Fix headers on mobile with cool dropdown menu.
This commit is contained in:
parent
86c2ff4605
commit
393a4962c9
|
@ -6,40 +6,83 @@ import { useUser } from '../hooks/use-user'
|
|||
import { formatMoney } from '../lib/util/format'
|
||||
import { Row } from './layout/row'
|
||||
import { firebaseLogin, User } from '../lib/firebase/users'
|
||||
import { MenuButton } from './menu'
|
||||
|
||||
const hoverClasses =
|
||||
'hover:underline hover:decoration-indigo-400 hover:decoration-2'
|
||||
|
||||
const mobileNavigation = [
|
||||
{
|
||||
name: 'Home',
|
||||
href: '/',
|
||||
},
|
||||
{
|
||||
name: 'Account',
|
||||
href: '/account',
|
||||
},
|
||||
{
|
||||
name: 'Your bets',
|
||||
href: '/bets',
|
||||
},
|
||||
{
|
||||
name: 'Create a market',
|
||||
href: '/create',
|
||||
},
|
||||
]
|
||||
|
||||
function ProfileSummary(props: { user: User }) {
|
||||
const { user } = props
|
||||
return (
|
||||
<Row className="avatar items-center">
|
||||
<div className="rounded-full w-10 h-10 mr-4">
|
||||
<Image src={user.avatarUrl} width={40} height={40} />
|
||||
</div>
|
||||
<div className="truncate" style={{ maxWidth: 175 }}>
|
||||
{user.name}
|
||||
<div className="text-gray-700 text-sm">{formatMoney(user.balance)}</div>
|
||||
</div>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
|
||||
function SignedInHeaders(props: { user: User; themeClasses?: string }) {
|
||||
const { user, themeClasses } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
<Link href="/create">
|
||||
<a className={clsx('text-base font-medium', themeClasses)}>
|
||||
<a
|
||||
className={clsx(
|
||||
'text-base font-medium hidden md:block',
|
||||
themeClasses
|
||||
)}
|
||||
>
|
||||
Create a market
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
<Link href="/bets">
|
||||
<a className={clsx('text-base font-medium', themeClasses)}>Your bets</a>
|
||||
<a
|
||||
className={clsx(
|
||||
'text-base font-medium hidden md:block',
|
||||
themeClasses
|
||||
)}
|
||||
>
|
||||
Your bets
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
<Link href="/account">
|
||||
<a className={clsx('text-base font-medium', themeClasses)}>
|
||||
<Row className="avatar items-center">
|
||||
<div className="rounded-full w-10 h-10 mr-4">
|
||||
<Image src={user.avatarUrl} width={40} height={40} />
|
||||
</div>
|
||||
<div>
|
||||
{user.name}
|
||||
<div className="text-gray-700 text-sm">
|
||||
{formatMoney(user.balance)}
|
||||
</div>
|
||||
</div>
|
||||
</Row>
|
||||
<a className={clsx('text-base font-medium hidden md:block')}>
|
||||
<ProfileSummary user={user} />
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
<MenuButton
|
||||
className="md:hidden"
|
||||
menuItems={mobileNavigation}
|
||||
buttonContent={<ProfileSummary user={user} />}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -68,12 +111,12 @@ export function Header(props: { darkBackground?: boolean; children?: any }) {
|
|||
|
||||
return (
|
||||
<nav
|
||||
className="max-w-7xl w-full flex flex-row mx-auto pt-5 px-4 sm:px-6"
|
||||
className="max-w-7xl w-full flex flex-row justify-between md:justify-start mx-auto pt-5 px-4 sm:px-6"
|
||||
aria-label="Global"
|
||||
>
|
||||
<Link href="/">
|
||||
<a className="flex flex-row gap-3">
|
||||
<Image
|
||||
<img
|
||||
className="sm:h-10 sm:w-10 hover:rotate-12 transition-all"
|
||||
src="/logo-icon.svg"
|
||||
width={40}
|
||||
|
@ -81,7 +124,7 @@ export function Header(props: { darkBackground?: boolean; children?: any }) {
|
|||
/>
|
||||
<div
|
||||
className={clsx(
|
||||
'font-major-mono lowercase mt-1 hidden sm:block sm:text-2xl',
|
||||
'font-major-mono lowercase mt-1 sm:text-2xl',
|
||||
darkBackground && 'text-white'
|
||||
)}
|
||||
>
|
||||
|
@ -90,7 +133,7 @@ export function Header(props: { darkBackground?: boolean; children?: any }) {
|
|||
</a>
|
||||
</Link>
|
||||
|
||||
<Row className="gap-8 mt-1 md:ml-16 mr-8">
|
||||
<Row className="gap-8 mt-1 md:ml-16">
|
||||
{children}
|
||||
|
||||
{user ? (
|
||||
|
|
51
web/components/menu.tsx
Normal file
51
web/components/menu.tsx
Normal file
|
@ -0,0 +1,51 @@
|
|||
import { Fragment } from 'react'
|
||||
import { Menu, Transition } from '@headlessui/react'
|
||||
import clsx from 'clsx'
|
||||
|
||||
export function MenuButton(props: {
|
||||
buttonContent: any
|
||||
menuItems: { name: string; href: string }[]
|
||||
className?: string
|
||||
}) {
|
||||
const { buttonContent, menuItems, className } = props
|
||||
return (
|
||||
<Menu
|
||||
as="div"
|
||||
className={clsx('flex-shrink-0 relative ml-4 z-10', className)}
|
||||
>
|
||||
<div>
|
||||
<Menu.Button className="rounded-full flex">
|
||||
<span className="sr-only">Open user menu</span>
|
||||
{buttonContent}
|
||||
</Menu.Button>
|
||||
</div>
|
||||
<Transition
|
||||
as={Fragment}
|
||||
enter="transition ease-out duration-100"
|
||||
enterFrom="transform opacity-0 scale-95"
|
||||
enterTo="transform opacity-100 scale-100"
|
||||
leave="transition ease-in duration-75"
|
||||
leaveFrom="transform opacity-100 scale-100"
|
||||
leaveTo="transform opacity-0 scale-95"
|
||||
>
|
||||
<Menu.Items className="origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 py-1 focus:outline-none">
|
||||
{menuItems.map((item) => (
|
||||
<Menu.Item key={item.name}>
|
||||
{({ active }) => (
|
||||
<a
|
||||
href={item.href}
|
||||
className={clsx(
|
||||
active ? 'bg-gray-100' : '',
|
||||
'block py-2 px-4 text-sm text-gray-700'
|
||||
)}
|
||||
>
|
||||
{item.name}
|
||||
</a>
|
||||
)}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu.Items>
|
||||
</Transition>
|
||||
</Menu>
|
||||
)
|
||||
}
|
19
web/package-lock.json
generated
19
web/package-lock.json
generated
|
@ -6,6 +6,7 @@
|
|||
"": {
|
||||
"name": "mantic",
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^1.4.2",
|
||||
"@heroicons/react": "^1.0.5",
|
||||
"@nivo/core": "0.74.0",
|
||||
"@nivo/line": "0.74.0",
|
||||
|
@ -1586,6 +1587,18 @@
|
|||
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz",
|
||||
"integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw=="
|
||||
},
|
||||
"node_modules/@headlessui/react": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.4.2.tgz",
|
||||
"integrity": "sha512-N8tv7kLhg9qGKBkVdtg572BvKvWhmiudmeEpOCyNwzOsZHCXBtl8AazGikIfUS+vBoub20Fse3BjawXDVPPdug==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16 || ^17 || ^18",
|
||||
"react-dom": "^16 || ^17 || ^18"
|
||||
}
|
||||
},
|
||||
"node_modules/@heroicons/react": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@heroicons/react/-/react-1.0.5.tgz",
|
||||
|
@ -9448,6 +9461,12 @@
|
|||
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz",
|
||||
"integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw=="
|
||||
},
|
||||
"@headlessui/react": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.4.2.tgz",
|
||||
"integrity": "sha512-N8tv7kLhg9qGKBkVdtg572BvKvWhmiudmeEpOCyNwzOsZHCXBtl8AazGikIfUS+vBoub20Fse3BjawXDVPPdug==",
|
||||
"requires": {}
|
||||
},
|
||||
"@heroicons/react": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@heroicons/react/-/react-1.0.5.tgz",
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
"prepare": "cd .. && husky install web/.husky"
|
||||
},
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^1.4.2",
|
||||
"@heroicons/react": "^1.0.5",
|
||||
"@nivo/core": "0.74.0",
|
||||
"@nivo/line": "0.74.0",
|
||||
|
|
Loading…
Reference in New Issue
Block a user