Unify workspace dropdowns; Update layouts (#458)

Unified Account and Workspace drop-downs; Layout updates, now header lives within the PageBody component; Sidebars now use floating variant
This commit is contained in:
Giancarlo Buomprisco
2026-03-11 14:45:42 +08:00
committed by GitHub
parent ca585e09be
commit 4bc8448a1d
530 changed files with 14398 additions and 11198 deletions

View File

@@ -7,9 +7,17 @@ import { useTheme } from 'next-themes';
import { cn } from '../lib/utils';
import { Button } from '../shadcn/button';
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '../shadcn/card';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSub,
@@ -36,13 +44,13 @@ export function ModeToggle(props: { className?: string }) {
key={mode}
onClick={() => {
setTheme(mode);
setCookieTheme(mode);
setCookeTheme(mode);
}}
>
<Icon theme={mode} />
<span>
<Trans i18nKey={`common:${mode}Theme`} />
<Trans i18nKey={`common.${mode}Theme`} />
</span>
</DropdownMenuItem>
);
@@ -51,12 +59,14 @@ export function ModeToggle(props: { className?: string }) {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className={props.className}>
<Sun className="h-[0.9rem] w-[0.9rem] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" />
<Moon className="absolute h-[0.9rem] w-[0.9rem] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" />
<span className="sr-only">Toggle theme</span>
</Button>
<DropdownMenuTrigger
render={
<Button variant="ghost" size="icon" className={props.className} />
}
>
<Sun className="h-[0.9rem] w-[0.9rem] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" />
<Moon className="absolute h-[0.9rem] w-[0.9rem] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" />
<span className="sr-only">Toggle theme</span>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">{Items}</DropdownMenuContent>
@@ -74,20 +84,18 @@ export function SubMenuModeToggle() {
return (
<DropdownMenuItem
className={cn('flex cursor-pointer items-center space-x-2', {
className={cn('flex cursor-pointer items-center gap-x-2', {
'bg-muted': isSelected,
})}
key={mode}
onClick={() => {
setTheme(mode);
setCookieTheme(mode);
setCookeTheme(mode);
}}
>
<Icon theme={mode} />
<span>
<Trans i18nKey={`common:${mode}Theme`} />
</span>
<Trans i18nKey={`common.${mode}Theme`} />
</DropdownMenuItem>
);
}),
@@ -95,20 +103,16 @@ export function SubMenuModeToggle() {
);
return (
<>
<DropdownMenuGroup>
<DropdownMenuSub>
<DropdownMenuSubTrigger
className={
'hidden w-full items-center justify-between gap-x-3 lg:flex'
'hidden w-full items-center justify-between gap-x-2 lg:flex'
}
>
<span className={'flex space-x-2'}>
<Icon theme={resolvedTheme} />
<Icon theme={resolvedTheme} />
<span>
<Trans i18nKey={'common:theme'} />
</span>
</span>
<Trans i18nKey={'common.theme'} />
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>{MenuItems}</DropdownMenuSubContent>
@@ -116,19 +120,17 @@ export function SubMenuModeToggle() {
<div className={'lg:hidden'}>
<DropdownMenuLabel>
<Trans i18nKey={'common:theme'} />
<Trans i18nKey={'common.theme'} />
</DropdownMenuLabel>
{MenuItems}
</div>
</>
</DropdownMenuGroup>
);
}
function setCookieTheme(theme: string) {
const secure =
typeof window !== 'undefined' && window.location.protocol === 'https:';
document.cookie = `theme=${theme}; path=/; max-age=31536000; SameSite=Lax${secure ? '; Secure' : ''}`;
function setCookeTheme(theme: string) {
document.cookie = `theme=${theme}; path=/; max-age=31536000`;
}
function Icon({ theme }: { theme: string | undefined }) {
@@ -141,3 +143,53 @@ function Icon({ theme }: { theme: string | undefined }) {
return <Computer className="h-4" />;
}
}
export function ThemePreferenceCard({
currentTheme,
}: {
currentTheme: string;
}) {
const { setTheme, theme = currentTheme } = useTheme();
return (
<Card>
<CardHeader>
<CardTitle>
<Trans i18nKey="common.theme" />
</CardTitle>
<CardDescription>
<Trans i18nKey="common.themeDescription" />
</CardDescription>
</CardHeader>
<CardContent>
<div className="grid grid-cols-3 gap-3">
{MODES.map((mode) => {
const isSelected = theme === mode;
return (
<Button
key={mode}
variant={isSelected ? 'default' : 'outline'}
className={'flex items-center justify-center gap-2'}
onClick={() => {
setTheme(mode);
setCookeTheme(mode);
}}
>
{mode === 'light' && <Sun className="size-4" />}
{mode === 'dark' && <Moon className="size-4" />}
{mode === 'system' && <Computer className="size-4" />}
<span className="text-sm">
<Trans i18nKey={`common.${mode}Theme`} />
</span>
</Button>
);
})}
</div>
</CardContent>
</Card>
);
}