mirror of
https://github.com/umami-software/umami.git
synced 2026-02-14 09:35:36 +01:00
Move settings nav into SideNav, matching WebsiteNav pattern
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
04c7216928
commit
08e4da27c1
4 changed files with 79 additions and 29 deletions
|
|
@ -10,6 +10,7 @@ import {
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from '@umami/react-zen';
|
} from '@umami/react-zen';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
import { SettingsNav } from '@/app/(main)/settings/SettingsNav';
|
||||||
import { WebsiteNav } from '@/app/(main)/websites/[websiteId]/WebsiteNav';
|
import { WebsiteNav } from '@/app/(main)/websites/[websiteId]/WebsiteNav';
|
||||||
import { IconLabel } from '@/components/common/IconLabel';
|
import { IconLabel } from '@/components/common/IconLabel';
|
||||||
import { useGlobalState, useMessages, useNavigation } from '@/components/hooks';
|
import { useGlobalState, useMessages, useNavigation } from '@/components/hooks';
|
||||||
|
|
@ -83,6 +84,8 @@ export function SideNav(props: any) {
|
||||||
</Row>
|
</Row>
|
||||||
{websiteId ? (
|
{websiteId ? (
|
||||||
<WebsiteNav websiteId={websiteId} isCollapsed={isCollapsed} />
|
<WebsiteNav websiteId={websiteId} isCollapsed={isCollapsed} />
|
||||||
|
) : pathname.includes('/settings') ? (
|
||||||
|
<SettingsNav isCollapsed={isCollapsed} />
|
||||||
) : (
|
) : (
|
||||||
<Column gap="2">
|
<Column gap="2">
|
||||||
{links.map(({ id, path, label, icon }) => {
|
{links.map(({ id, path, label, icon }) => {
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,12 @@
|
||||||
'use client';
|
'use client';
|
||||||
import { Column, Grid } from '@umami/react-zen';
|
import { Column } from '@umami/react-zen';
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
import { PageBody } from '@/components/common/PageBody';
|
import { PageBody } from '@/components/common/PageBody';
|
||||||
import { SettingsNav } from './SettingsNav';
|
|
||||||
|
|
||||||
export function SettingsLayout({ children }: { children: ReactNode }) {
|
export function SettingsLayout({ children }: { children: ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<Grid columns={{ base: '1fr', lg: 'auto 1fr' }} width="100%" height="100%">
|
<Column gap="6" margin="2" width="100%">
|
||||||
<Column
|
<PageBody>{children}</PageBody>
|
||||||
display={{ base: 'none', lg: 'flex' }}
|
</Column>
|
||||||
width="240px"
|
|
||||||
height="100%"
|
|
||||||
border="right"
|
|
||||||
marginRight="2"
|
|
||||||
padding="3"
|
|
||||||
>
|
|
||||||
<SettingsNav />
|
|
||||||
</Column>
|
|
||||||
<Column gap="6" margin="2">
|
|
||||||
<PageBody>{children}</PageBody>
|
|
||||||
</Column>
|
|
||||||
</Grid>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,16 @@
|
||||||
import { NavMenu } from '@/components/common/NavMenu';
|
import { Column, Focusable, Row, Text, Tooltip, TooltipTrigger } from '@umami/react-zen';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { IconLabel } from '@/components/common/IconLabel';
|
||||||
import { useMessages, useNavigation } from '@/components/hooks';
|
import { useMessages, useNavigation } from '@/components/hooks';
|
||||||
import { Settings2, UserCircle, Users } from '@/components/icons';
|
import { ArrowLeft, Settings2, UserCircle, Users } from '@/components/icons';
|
||||||
|
|
||||||
export function SettingsNav({ onItemClick }: { onItemClick?: () => void }) {
|
export function SettingsNav({
|
||||||
|
isCollapsed,
|
||||||
|
onItemClick,
|
||||||
|
}: {
|
||||||
|
isCollapsed?: boolean;
|
||||||
|
onItemClick?: () => void;
|
||||||
|
}) {
|
||||||
const { t, labels } = useMessages();
|
const { t, labels } = useMessages();
|
||||||
const { renderUrl, pathname } = useNavigation();
|
const { renderUrl, pathname } = useNavigation();
|
||||||
|
|
||||||
|
|
@ -42,12 +50,57 @@ export function SettingsNav({ onItemClick }: { onItemClick?: () => void }) {
|
||||||
.find(({ path }) => path && pathname.includes(path.split('?')[0]))?.id;
|
.find(({ path }) => path && pathname.includes(path.split('?')[0]))?.id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavMenu
|
<Column gap="2">
|
||||||
items={items}
|
<Link href={renderUrl('/boards', false)} role="button" onClick={onItemClick}>
|
||||||
title={t(labels.settings)}
|
<TooltipTrigger isDisabled={!isCollapsed} delay={0}>
|
||||||
selectedKey={selectedKey}
|
<Focusable>
|
||||||
allowMinimize={false}
|
<Row
|
||||||
onItemClick={onItemClick}
|
alignItems="center"
|
||||||
/>
|
hover={{ backgroundColor: 'surface-sunken' }}
|
||||||
|
borderRadius
|
||||||
|
minHeight="40px"
|
||||||
|
>
|
||||||
|
<IconLabel icon={<ArrowLeft />} label={isCollapsed ? '' : t(labels.back)} padding />
|
||||||
|
</Row>
|
||||||
|
</Focusable>
|
||||||
|
<Tooltip placement="right">{t(labels.back)}</Tooltip>
|
||||||
|
</TooltipTrigger>
|
||||||
|
</Link>
|
||||||
|
{items.map(({ label: sectionLabel, items: sectionItems }, index) => (
|
||||||
|
<Column key={`${sectionLabel}${index}`} gap="1" marginBottom="1">
|
||||||
|
{!isCollapsed && (
|
||||||
|
<Row padding>
|
||||||
|
<Text weight="bold">{sectionLabel}</Text>
|
||||||
|
</Row>
|
||||||
|
)}
|
||||||
|
{sectionItems.map(({ id, path, label, icon }) => {
|
||||||
|
const isSelected = selectedKey === id;
|
||||||
|
return (
|
||||||
|
<Link key={id} href={path} role="button" onClick={onItemClick}>
|
||||||
|
<TooltipTrigger isDisabled={!isCollapsed} delay={0}>
|
||||||
|
<Focusable>
|
||||||
|
<Row
|
||||||
|
alignItems="center"
|
||||||
|
hover={{ backgroundColor: 'surface-sunken' }}
|
||||||
|
backgroundColor={isSelected ? 'surface-sunken' : undefined}
|
||||||
|
borderRadius
|
||||||
|
minHeight="40px"
|
||||||
|
>
|
||||||
|
<IconLabel
|
||||||
|
icon={icon}
|
||||||
|
label={isCollapsed ? '' : label}
|
||||||
|
weight={isSelected ? 'bold' : undefined}
|
||||||
|
padding
|
||||||
|
/>
|
||||||
|
</Row>
|
||||||
|
</Focusable>
|
||||||
|
<Tooltip placement="right">{label}</Tooltip>
|
||||||
|
</TooltipTrigger>
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Column>
|
||||||
|
))}
|
||||||
|
</Column>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,9 +47,16 @@ export function TeamsButton() {
|
||||||
return (
|
return (
|
||||||
<MenuTrigger>
|
<MenuTrigger>
|
||||||
<Button variant="quiet">
|
<Button variant="quiet">
|
||||||
<Row alignItems="center" position="relative" gap maxHeight="40px">
|
<Row
|
||||||
|
alignItems="center"
|
||||||
|
position="relative"
|
||||||
|
gap
|
||||||
|
maxHeight="40px"
|
||||||
|
minWidth="200px"
|
||||||
|
maxWidth="200px"
|
||||||
|
>
|
||||||
<Icon>{teamId ? <Users /> : <User />}</Icon>
|
<Icon>{teamId ? <Users /> : <User />}</Icon>
|
||||||
<Text>{label}</Text>
|
<Text truncate>{label}</Text>
|
||||||
</Row>
|
</Row>
|
||||||
<Icon rotate={90} size="sm">
|
<Icon rotate={90} size="sm">
|
||||||
<ChevronRight />
|
<ChevronRight />
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue