New mobile menu.

This commit is contained in:
Mike Cao 2025-10-14 21:57:31 -07:00
parent be5f0494cc
commit 10bc2895eb
6 changed files with 90 additions and 32 deletions

View file

@ -1,10 +1,10 @@
'use client'; 'use client';
import { Grid, Loading, Column, Row, List, ListItem } from '@umami/react-zen'; import { Grid, Loading, Column, Row } from '@umami/react-zen';
import Script from 'next/script'; import Script from 'next/script';
import { UpdateNotice } from './UpdateNotice'; import { UpdateNotice } from './UpdateNotice';
import { SideNav } from '@/app/(main)/SideNav'; import { SideNav } from '@/app/(main)/SideNav';
import { useLoginQuery, useConfig, useNavigation } from '@/components/hooks'; import { useLoginQuery, useConfig, useNavigation } from '@/components/hooks';
import { MobileMenuButton } from '@/components/input/MobileMenuButton'; import { MobileNav } from '@/app/(main)/MobileNav';
export function App({ children }) { export function App({ children }) {
const { user, isLoading, error } = useLoginQuery(); const { user, isLoading, error } = useLoginQuery();
@ -29,15 +29,9 @@ export function App({ children }) {
} }
return ( return (
<Grid columns={{ xs: '1fr', lg: 'auto 1fr' }} height="100vh" width="100%" backgroundColor="2"> <Grid columns={{ xs: '1fr', lg: 'auto 1fr' }} height="100vh" width="100%">
<Row display={{ xs: 'flex', lg: 'none' }} alignItems="center" gap padding> <Row display={{ xs: 'flex', lg: 'none' }} alignItems="center" gap padding="3">
<MobileMenuButton> <MobileNav />
<List>
<ListItem>Websites</ListItem>
<ListItem>Links</ListItem>
<ListItem>Pixels</ListItem>
</List>
</MobileMenuButton>
</Row> </Row>
<Column display={{ xs: 'none', lg: 'flex' }}> <Column display={{ xs: 'none', lg: 'flex' }}>
<SideNav /> <SideNav />

View file

@ -0,0 +1,77 @@
import {
Row,
Dialog,
DialogTrigger,
Button,
Icon,
Modal,
NavMenu,
NavMenuItem,
IconLabel,
Text,
Grid,
} from '@umami/react-zen';
import { Globe, Grid2x2, LinkIcon, Menu } from '@/components/icons';
import { useMessages, useNavigation } from '@/components/hooks';
import Link from 'next/link';
import { WebsiteNav } from '@/app/(main)/websites/[websiteId]/WebsiteNav';
import { Logo } from '@/components/svg';
export function MobileNav() {
const { formatMessage, labels } = useMessages();
const { websiteId } = useNavigation();
const links = [
{
id: 'websites',
label: formatMessage(labels.websites),
path: '/websites',
icon: <Globe />,
},
{
id: 'links',
label: formatMessage(labels.links),
path: '/links',
icon: <LinkIcon />,
},
{
id: 'pixels',
label: formatMessage(labels.pixels),
path: '/pixels',
icon: <Grid2x2 />,
},
];
return (
<Grid columns="auto 1fr" flexGrow={1}>
<DialogTrigger>
<Button>
<Icon>
<Menu />
</Icon>
</Button>
<Modal position="left" offset="80px">
<Dialog variant="sheet">
<NavMenu padding="3">
{links.map(link => {
return (
<Link key={link.id} href={link.path}>
<NavMenuItem>
<IconLabel icon={link.icon} label={link.label} />
</NavMenuItem>
</Link>
);
})}
</NavMenu>
{websiteId && <WebsiteNav websiteId={websiteId} />}
</Dialog>
</Modal>
</DialogTrigger>
<Row alignItems="center" justifyContent="center" flexGrow={1}>
<IconLabel icon={<Logo />} style={{ width: 'auto' }}>
<Text weight="bold">umami</Text>
</IconLabel>
</Row>
</Grid>
);
}

View file

@ -12,6 +12,7 @@ export function WebsiteLayout({ websiteId, children }: { websiteId: string; chil
<Grid columns={{ xs: '1fr', lg: 'auto 1fr' }} width="100%" height="100%"> <Grid columns={{ xs: '1fr', lg: 'auto 1fr' }} width="100%" height="100%">
<Column <Column
display={{ xs: 'none', lg: 'flex' }} display={{ xs: 'none', lg: 'flex' }}
width="240px"
height="100%" height="100%"
border="right" border="right"
backgroundColor backgroundColor

View file

@ -57,7 +57,6 @@ export function SideMenu({
<Column <Column
gap gap
padding padding
width="240px"
overflowY="auto" overflowY="auto"
justifyContent="space-between" justifyContent="space-between"
position="sticky" position="sticky"

View file

@ -1,18 +0,0 @@
import { Button, Icon, DialogTrigger, Dialog, Modal } from '@umami/react-zen';
import { Menu } from '@/components/icons';
import { ReactNode } from 'react';
export function MobileMenuButton({ children }: { children: ReactNode }) {
return (
<DialogTrigger>
<Button>
<Icon>
<Menu />
</Icon>
</Button>
<Modal position="left" offset="20px">
<Dialog variant="sheet">{children}</Dialog>
</Modal>
</DialogTrigger>
);
}

View file

@ -1,6 +1,11 @@
import { useState } from 'react'; import { useState } from 'react';
import { Select, SelectProps, ListItem, Text, Row } from '@umami/react-zen'; import { Select, SelectProps, ListItem, Text, Row } from '@umami/react-zen';
import { useUserWebsitesQuery, useMessages, useLoginQuery, useWebsite } from '@/components/hooks'; import {
useUserWebsitesQuery,
useMessages,
useLoginQuery,
useWebsiteQuery,
} from '@/components/hooks';
import { Empty } from '@/components/common/Empty'; import { Empty } from '@/components/common/Empty';
export function WebsiteSelect({ export function WebsiteSelect({
@ -15,7 +20,7 @@ export function WebsiteSelect({
includeTeams?: boolean; includeTeams?: boolean;
} & SelectProps) { } & SelectProps) {
const { formatMessage, messages } = useMessages(); const { formatMessage, messages } = useMessages();
const website = useWebsite(); const { data: website } = useWebsiteQuery(websiteId);
const [name, setName] = useState<string>(website?.name); const [name, setName] = useState<string>(website?.name);
const [search, setSearch] = useState(''); const [search, setSearch] = useState('');
const { user } = useLoginQuery(); const { user } = useLoginQuery();