mirror of
https://github.com/umami-software/umami.git
synced 2026-02-04 04:37:11 +01:00
Add collapsible ShareNav sidebar
- Add collapse/expand button in header - When collapsed: hide menu items and logo, show only toggle button - Stack bottom icons vertically when collapsed - Adjust grid layout to match collapsed nav width (60px vs 240px) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
4e8be724ac
commit
482d6c1e47
2 changed files with 69 additions and 30 deletions
|
|
@ -1,12 +1,29 @@
|
||||||
import { Column, Icon, Row, Text, ThemeButton } from '@umami/react-zen';
|
import { Button, Column, Icon, Row, Text, ThemeButton } from '@umami/react-zen';
|
||||||
import { SideMenu } from '@/components/common/SideMenu';
|
import { SideMenu } from '@/components/common/SideMenu';
|
||||||
import { useMessages, useNavigation, useShare } from '@/components/hooks';
|
import { useMessages, useNavigation, useShare } from '@/components/hooks';
|
||||||
import { AlignEndHorizontal, Clock, Eye, Sheet, Tag, User } from '@/components/icons';
|
import {
|
||||||
|
AlignEndHorizontal,
|
||||||
|
Clock,
|
||||||
|
Eye,
|
||||||
|
PanelLeftClose,
|
||||||
|
PanelLeftOpen,
|
||||||
|
Sheet,
|
||||||
|
Tag,
|
||||||
|
User,
|
||||||
|
} from '@/components/icons';
|
||||||
import { LanguageButton } from '@/components/input/LanguageButton';
|
import { LanguageButton } from '@/components/input/LanguageButton';
|
||||||
import { PreferencesButton } from '@/components/input/PreferencesButton';
|
import { PreferencesButton } from '@/components/input/PreferencesButton';
|
||||||
import { Funnel, Lightning, Logo, Magnet, Money, Network, Path, Target } from '@/components/svg';
|
import { Funnel, Lightning, Logo, Magnet, Money, Network, Path, Target } from '@/components/svg';
|
||||||
|
|
||||||
export function ShareNav({ onItemClick }: { onItemClick?: () => void }) {
|
export function ShareNav({
|
||||||
|
collapsed,
|
||||||
|
onCollapse,
|
||||||
|
onItemClick,
|
||||||
|
}: {
|
||||||
|
collapsed?: boolean;
|
||||||
|
onCollapse?: (collapsed: boolean) => void;
|
||||||
|
onItemClick?: () => void;
|
||||||
|
}) {
|
||||||
const share = useShare();
|
const share = useShare();
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
const { pathname } = useNavigation();
|
const { pathname } = useNavigation();
|
||||||
|
|
@ -130,9 +147,24 @@ export function ShareNav({ onItemClick }: { onItemClick?: () => void }) {
|
||||||
.find(({ path }) => path && pathname.endsWith(path.split('?')[0]))?.id;
|
.find(({ path }) => path && pathname.endsWith(path.split('?')[0]))?.id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column position="fixed" padding="3" width="240px" maxHeight="100vh" height="100vh">
|
<Column
|
||||||
<Row as="header" gap alignItems="center" paddingY="3" marginLeft="3">
|
position="fixed"
|
||||||
<a href={logoUrl} target="_blank" rel="noopener">
|
padding="3"
|
||||||
|
width={collapsed ? '60px' : '240px'}
|
||||||
|
maxHeight="100vh"
|
||||||
|
height="100vh"
|
||||||
|
border="right"
|
||||||
|
borderColor="4"
|
||||||
|
>
|
||||||
|
<Row
|
||||||
|
as="header"
|
||||||
|
gap
|
||||||
|
alignItems="center"
|
||||||
|
paddingY="3"
|
||||||
|
justifyContent={collapsed ? 'center' : undefined}
|
||||||
|
>
|
||||||
|
{!collapsed && (
|
||||||
|
<a href={logoUrl} target="_blank" rel="noopener" style={{ marginLeft: 12 }}>
|
||||||
<Row alignItems="center" gap>
|
<Row alignItems="center" gap>
|
||||||
{logoImage ? (
|
{logoImage ? (
|
||||||
<img src={logoImage} alt={logoName} style={{ height: 24 }} />
|
<img src={logoImage} alt={logoName} style={{ height: 24 }} />
|
||||||
|
|
@ -144,7 +176,12 @@ export function ShareNav({ onItemClick }: { onItemClick?: () => void }) {
|
||||||
<Text weight="bold">{logoName}</Text>
|
<Text weight="bold">{logoName}</Text>
|
||||||
</Row>
|
</Row>
|
||||||
</a>
|
</a>
|
||||||
|
)}
|
||||||
|
<Button variant="quiet" onPress={() => onCollapse?.(!collapsed)}>
|
||||||
|
<Icon>{collapsed ? <PanelLeftOpen /> : <PanelLeftClose />}</Icon>
|
||||||
|
</Button>
|
||||||
</Row>
|
</Row>
|
||||||
|
{!collapsed && (
|
||||||
<Column>
|
<Column>
|
||||||
<SideMenu
|
<SideMenu
|
||||||
items={items}
|
items={items}
|
||||||
|
|
@ -153,12 +190,13 @@ export function ShareNav({ onItemClick }: { onItemClick?: () => void }) {
|
||||||
onItemClick={onItemClick}
|
onItemClick={onItemClick}
|
||||||
/>
|
/>
|
||||||
</Column>
|
</Column>
|
||||||
|
)}
|
||||||
<Column flexGrow={1} justifyContent="flex-end">
|
<Column flexGrow={1} justifyContent="flex-end">
|
||||||
<Row>
|
<Column gap="2">
|
||||||
<ThemeButton />
|
<ThemeButton />
|
||||||
<LanguageButton />
|
<LanguageButton />
|
||||||
<PreferencesButton />
|
<PreferencesButton />
|
||||||
</Row>
|
</Column>
|
||||||
</Column>
|
</Column>
|
||||||
</Column>
|
</Column>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
import { Column, Grid, Row, useTheme } from '@umami/react-zen';
|
import { Column, Grid, Row, useTheme } from '@umami/react-zen';
|
||||||
import { usePathname } from 'next/navigation';
|
import { usePathname } from 'next/navigation';
|
||||||
import { useEffect } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { AttributionPage } from '@/app/(main)/websites/[websiteId]/(reports)/attribution/AttributionPage';
|
import { AttributionPage } from '@/app/(main)/websites/[websiteId]/(reports)/attribution/AttributionPage';
|
||||||
import { BreakdownPage } from '@/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage';
|
import { BreakdownPage } from '@/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage';
|
||||||
import { FunnelsPage } from '@/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelsPage';
|
import { FunnelsPage } from '@/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelsPage';
|
||||||
|
|
@ -52,6 +52,7 @@ function getSharePath(pathname: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SharePage() {
|
export function SharePage() {
|
||||||
|
const [navCollapsed, setNavCollapsed] = useState(false);
|
||||||
const share = useShare();
|
const share = useShare();
|
||||||
const { setTheme } = useTheme();
|
const { setTheme } = useTheme();
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
|
|
@ -78,7 +79,7 @@ export function SharePage() {
|
||||||
const PageComponent = PAGE_COMPONENTS[pageKey] || WebsitePage;
|
const PageComponent = PAGE_COMPONENTS[pageKey] || WebsitePage;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid columns={{ xs: '1fr', lg: '240px 1fr' }} width="100%">
|
<Grid columns={{ xs: '1fr', lg: `${navCollapsed ? '60px' : '240px'} 1fr` }} width="100%">
|
||||||
<Row display={{ xs: 'flex', lg: 'none' }} alignItems="center" gap padding="3">
|
<Row display={{ xs: 'flex', lg: 'none' }} alignItems="center" gap padding="3">
|
||||||
<MobileMenuButton>
|
<MobileMenuButton>
|
||||||
{({ close }) => {
|
{({ close }) => {
|
||||||
|
|
@ -87,7 +88,7 @@ export function SharePage() {
|
||||||
</MobileMenuButton>
|
</MobileMenuButton>
|
||||||
</Row>
|
</Row>
|
||||||
<Column display={{ xs: 'none', lg: 'flex' }} marginRight="2">
|
<Column display={{ xs: 'none', lg: 'flex' }} marginRight="2">
|
||||||
<ShareNav />
|
<ShareNav collapsed={navCollapsed} onCollapse={setNavCollapsed} />
|
||||||
</Column>
|
</Column>
|
||||||
<PageBody gap>
|
<PageBody gap>
|
||||||
<WebsiteProvider websiteId={websiteId}>
|
<WebsiteProvider websiteId={websiteId}>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue