New website layout.

This commit is contained in:
Mike Cao 2025-05-18 03:34:37 -07:00
parent c5086be6eb
commit 6e41ba2e2c
7 changed files with 355 additions and 125 deletions

View file

@ -78,7 +78,7 @@
"@react-spring/web": "^9.7.3", "@react-spring/web": "^9.7.3",
"@svgr/cli": "^8.1.0", "@svgr/cli": "^8.1.0",
"@tanstack/react-query": "^5.28.6", "@tanstack/react-query": "^5.28.6",
"@umami/react-zen": "^0.97.0", "@umami/react-zen": "^0.108.0",
"@umami/redis-client": "^0.27.0", "@umami/redis-client": "^0.27.0",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"chalk": "^4.1.1", "chalk": "^4.1.1",

416
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,7 @@ import { Grid, Loading, Column } from '@umami/react-zen';
import Script from 'next/script'; import Script from 'next/script';
import { usePathname } from 'next/navigation'; import { usePathname } from 'next/navigation';
import { UpdateNotice } from './UpdateNotice'; import { UpdateNotice } from './UpdateNotice';
import { Nav } from '@/app/(main)/Nav'; import { SideNav } from '@/app/(main)/SideNav';
import { MenuBar } from '@/app/(main)/MenuBar'; import { MenuBar } from '@/app/(main)/MenuBar';
import { Page } from '@/components/common/Page'; import { Page } from '@/components/common/Page';
import { useLoginQuery, useConfig } from '@/components/hooks'; import { useLoginQuery, useConfig } from '@/components/hooks';
@ -32,7 +32,7 @@ export function App({ children }) {
return ( return (
<Grid height="100vh" width="100%" columns="auto 1fr" rows="auto 1fr"> <Grid height="100vh" width="100%" columns="auto 1fr" rows="auto 1fr">
<Nav gridColumn="1 / 2" gridRow="1 / 3" /> <SideNav gridColumn="1 / 2" gridRow="1 / 3" />
<MenuBar gridColumn="2 / 3" gridRow="1 / 2" /> <MenuBar gridColumn="2 / 3" gridRow="1 / 2" />
<Column <Column
gridColumn="2 / 3" gridColumn="2 / 3"

View file

@ -1,10 +1,10 @@
import Link from 'next/link'; import Link from 'next/link';
import { SideNav, SideNavHeader, SideNavSection, SideNavItem } from '@umami/react-zen'; import { Sidebar, SidebarHeader, SidebarSection, SidebarItem } from '@umami/react-zen';
import { Lucide, Icons } from '@/components/icons'; import { Lucide, Icons } from '@/components/icons';
import { useMessages, useNavigation } from '@/components/hooks'; import { useMessages, useNavigation } from '@/components/hooks';
import useGlobalState from '@/components/hooks/useGlobalState'; import useGlobalState from '@/components/hooks/useGlobalState';
export function Nav(props: any) { export function SideNav(props: any) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { renderTeamUrl, pathname } = useNavigation(); const { renderTeamUrl, pathname } = useNavigation();
const [isCollapsed] = useGlobalState('sidenav-collapsed'); const [isCollapsed] = useGlobalState('sidenav-collapsed');
@ -38,20 +38,20 @@ export function Nav(props: any) {
].filter(n => n); ].filter(n => n);
return ( return (
<SideNav {...props} isCollapsed={isCollapsed} variant="2" showBorder={true}> <Sidebar {...props} isCollapsed={isCollapsed} variant="0" showBorder={true}>
<SideNavSection> <SidebarSection>
<SideNavHeader label="umami" icon={<Icons.Logo />} /> <SidebarHeader label="umami" icon={<Icons.Logo />} />
</SideNavSection> </SidebarSection>
<SideNavSection> <SidebarSection>
{links.map(({ href, label, icon }) => { {links.map(({ href, label, icon }) => {
return ( return (
<Link key={href} href={href} role="button"> <Link key={href} href={href} role="button">
<SideNavItem label={label} icon={icon} isSelected={pathname.startsWith(href)} /> <SidebarItem label={label} icon={icon} isSelected={pathname.startsWith(href)} />
</Link> </Link>
); );
})} })}
</SideNavSection> </SidebarSection>
<SideNavSection alignSelf="end">{``}</SideNavSection> <SidebarSection alignSelf="end">{``}</SidebarSection>
</SideNav> </Sidebar>
); );
} }

View file

@ -1,7 +1,6 @@
import { Column, Row, Heading } from '@umami/react-zen'; import { Column, Row, Heading } from '@umami/react-zen';
import { Favicon } from '@/components/common/Favicon'; import { Favicon } from '@/components/common/Favicon';
import { ActiveUsers } from '@/components/metrics/ActiveUsers'; import { ActiveUsers } from '@/components/metrics/ActiveUsers';
import { WebsiteTabs } from '@/app/(main)/websites/[websiteId]/WebsiteTabs';
import { useWebsite } from '@/components/hooks/useWebsite'; import { useWebsite } from '@/components/hooks/useWebsite';
import { WebsiteFilterButton } from '@/app/(main)/websites/[websiteId]/WebsiteFilterButton'; import { WebsiteFilterButton } from '@/app/(main)/websites/[websiteId]/WebsiteFilterButton';
import { WebsiteDateFilter } from '@/components/input/WebsiteDateFilter'; import { WebsiteDateFilter } from '@/components/input/WebsiteDateFilter';
@ -35,7 +34,6 @@ export function WebsiteHeader({
</Row> </Row>
</Row> </Row>
<FilterBar websiteId={websiteId} /> <FilterBar websiteId={websiteId} />
<WebsiteTabs websiteId={websiteId} />
</Column> </Column>
); );
} }

View file

@ -1,13 +1,20 @@
'use client'; 'use client';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { Grid, Column, Box } from '@umami/react-zen';
import { WebsiteProvider } from './WebsiteProvider'; import { WebsiteProvider } from './WebsiteProvider';
import { WebsiteHeader } from '@/app/(main)/websites/[websiteId]/WebsiteHeader'; import { WebsiteHeader } from '@/app/(main)/websites/[websiteId]/WebsiteHeader';
import { WebsiteTabs } from '@/app/(main)/websites/[websiteId]/WebsiteTabs';
export function WebsiteLayout({ websiteId, children }: { websiteId: string; children: ReactNode }) { export function WebsiteLayout({ websiteId, children }: { websiteId: string; children: ReactNode }) {
return ( return (
<WebsiteProvider websiteId={websiteId}> <WebsiteProvider websiteId={websiteId}>
<WebsiteHeader websiteId={websiteId} /> <WebsiteHeader websiteId={websiteId} />
{children} <Grid columns="170px 1140px" justifyContent="center" gap>
<Box position="sticky" top="20px" alignSelf="flex-start">
<WebsiteTabs websiteId={websiteId} />
</Box>
<Column>{children}</Column>
</Grid>
</WebsiteProvider> </WebsiteProvider>
); );
} }

View file

@ -1,4 +1,4 @@
import { Column, Icon, Text, Row } from '@umami/react-zen'; import { Icon, Text, Row, NavMenu, NavMenuItem } from '@umami/react-zen';
import { Icons } from '@/components/icons'; import { Icons } from '@/components/icons';
import { useMessages, useNavigation } from '@/components/hooks'; import { useMessages, useNavigation } from '@/components/hooks';
import Link from 'next/link'; import Link from 'next/link';
@ -91,24 +91,21 @@ export function WebsiteTabs({ websiteId }: { websiteId: string }) {
const selected = links.find(({ path }) => path && pathname.endsWith(path))?.id || 'overview'; const selected = links.find(({ path }) => path && pathname.endsWith(path))?.id || 'overview';
return ( return (
<Column gap="2" position="absolute" padding="4" style={{ top: 0, left: 0, bottom: 0 }}> <NavMenu highlightColor="3">
{links.map(({ id, label, icon, path }) => { {links.map(({ id, label, icon, path }) => {
const isSelected = selected === id;
return ( return (
<Link key={id} href={renderTeamUrl(`/websites/${websiteId}${path}`)}> <Link key={id} href={renderTeamUrl(`/websites/${websiteId}${path}`)}>
<Row <NavMenuItem highlightColor="5" isSelected={isSelected}>
alignItems="center" <Row alignItems="center" gap>
padding <Icon style={{ fill: 'currentcolor' }}>{icon}</Icon>
gap <Text>{label}</Text>
hoverBackgroundColor="3" </Row>
borderRadius </NavMenuItem>
width="160px"
>
<Icon fillColor="currentColor">{icon}</Icon>
<Text weight={selected === id ? 'bold' : undefined}>{label}</Text>
</Row>
</Link> </Link>
); );
})} })}
</Column> </NavMenu>
); );
} }