refactor: improve layout navbar
This commit is contained in:
parent
3bb2cc8715
commit
6fbf316c5d
@ -1,22 +1,36 @@
|
||||
import * as React from "react"
|
||||
import * as AvatarPrimitive from "@radix-ui/react-avatar"
|
||||
import * as React from 'react';
|
||||
import * as AvatarPrimitive from '@radix-ui/react-avatar';
|
||||
|
||||
import { cn } from "@/utils/style"
|
||||
import { cn } from '@/utils/style';
|
||||
import { VariantProps, cva } from 'class-variance-authority';
|
||||
|
||||
const avatarVariants = cva(
|
||||
'relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full',
|
||||
{
|
||||
variants: {
|
||||
size: {
|
||||
default: 'h-10 w-10',
|
||||
sm: 'h-8 w-8',
|
||||
lg: 'h-12 w-12',
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
interface AvatarProps
|
||||
extends React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>,
|
||||
VariantProps<typeof avatarVariants> {}
|
||||
const Avatar = React.forwardRef<
|
||||
React.ElementRef<typeof AvatarPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
|
||||
>(({ className, ...props }, ref) => (
|
||||
AvatarProps
|
||||
>(({ className, size, ...props }, ref) => (
|
||||
<AvatarPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
|
||||
className
|
||||
)}
|
||||
className={cn(avatarVariants({ size, className }))}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Avatar.displayName = AvatarPrimitive.Root.displayName
|
||||
));
|
||||
Avatar.displayName = AvatarPrimitive.Root.displayName;
|
||||
|
||||
const AvatarImage = React.forwardRef<
|
||||
React.ElementRef<typeof AvatarPrimitive.Image>,
|
||||
@ -24,11 +38,11 @@ const AvatarImage = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AvatarPrimitive.Image
|
||||
ref={ref}
|
||||
className={cn("aspect-square h-full w-full", className)}
|
||||
className={cn('aspect-square h-full w-full', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AvatarImage.displayName = AvatarPrimitive.Image.displayName
|
||||
));
|
||||
AvatarImage.displayName = AvatarPrimitive.Image.displayName;
|
||||
|
||||
const AvatarFallback = React.forwardRef<
|
||||
React.ElementRef<typeof AvatarPrimitive.Fallback>,
|
||||
@ -37,12 +51,12 @@ const AvatarFallback = React.forwardRef<
|
||||
<AvatarPrimitive.Fallback
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-full w-full items-center justify-center rounded-full bg-muted",
|
||||
'bg-muted flex h-full w-full items-center justify-center rounded-full',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
|
||||
));
|
||||
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
|
||||
|
||||
export { Avatar, AvatarImage, AvatarFallback }
|
||||
export { Avatar, AvatarImage, AvatarFallback };
|
||||
|
@ -12,6 +12,8 @@ import {
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuLabel,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { useEvent } from '@/hooks/useEvent';
|
||||
import { useSettingsStore } from '@/store/settings';
|
||||
@ -19,6 +21,7 @@ import { useUserInfo } from '@/store/user';
|
||||
import { languages } from '@/utils/constants';
|
||||
import { useTranslation, setLanguage } from '@i18next-toolkit/react';
|
||||
import { useNavigate } from '@tanstack/react-router';
|
||||
import { version } from '@tianji/shared';
|
||||
import React from 'react';
|
||||
import { LuMoreVertical } from 'react-icons/lu';
|
||||
|
||||
@ -38,7 +41,7 @@ export const UserConfig: React.FC<UserConfigProps> = React.memo((props) => {
|
||||
});
|
||||
|
||||
const avatar = (
|
||||
<Avatar>
|
||||
<Avatar size={props.isCollapsed ? 'sm' : 'default'}>
|
||||
<AvatarFallback>
|
||||
{(userInfo?.username ?? '').substring(0, 2).toUpperCase()}
|
||||
</AvatarFallback>
|
||||
@ -134,6 +137,31 @@ export const UserConfig: React.FC<UserConfigProps> = React.memo((props) => {
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuPortal>
|
||||
</DropdownMenuSub>
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>{t('Community')}</DropdownMenuSubTrigger>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuItem
|
||||
onClick={() => window.open('https://discord.gg/8Vv47wAEej')}
|
||||
>
|
||||
{t('Join Discord')}
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem
|
||||
onClick={() => window.open('https://twitter.com/moonrailgun')}
|
||||
>
|
||||
{t('Follow Twitter')}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuPortal>
|
||||
</DropdownMenuSub>
|
||||
|
||||
<DropdownMenuLabel className="text-muted">
|
||||
v{version}
|
||||
</DropdownMenuLabel>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
|
@ -20,7 +20,7 @@ import { WorkspaceSwitcher } from '@/components/WorkspaceSwitcher';
|
||||
import { UserConfig } from './Layout/UserConfig';
|
||||
import { Outlet } from '@tanstack/react-router';
|
||||
import { trpc } from '@/api/trpc';
|
||||
import { useCurrentWorkspaceId, useUserStore } from '@/store/user';
|
||||
import { useUserStore } from '@/store/user';
|
||||
|
||||
const defaultLayout: [number, number, number] = [265, 440, 655];
|
||||
|
||||
@ -48,6 +48,62 @@ export const LayoutV2: React.FC<LayoutProps> = React.memo((props) => {
|
||||
}
|
||||
);
|
||||
|
||||
const navbar = (
|
||||
<>
|
||||
<div
|
||||
className={cn(
|
||||
'flex h-[52px] items-center justify-center',
|
||||
isCollapsed ? 'h-[52px]' : 'px-2'
|
||||
)}
|
||||
>
|
||||
<WorkspaceSwitcher isCollapsed={isCollapsed} />
|
||||
</div>
|
||||
<Separator />
|
||||
<Nav
|
||||
isCollapsed={isCollapsed}
|
||||
links={[
|
||||
{
|
||||
title: 'Website',
|
||||
label: String(serviceCount?.website ?? ''),
|
||||
icon: LuAreaChart,
|
||||
to: '/website',
|
||||
},
|
||||
{
|
||||
title: 'Monitor',
|
||||
label: String(serviceCount?.monitor ?? ''),
|
||||
icon: LuMonitorDot,
|
||||
to: '/monitor',
|
||||
},
|
||||
{
|
||||
title: 'Servers',
|
||||
label: '',
|
||||
icon: LuServer,
|
||||
to: '/server',
|
||||
},
|
||||
{
|
||||
title: 'Telemetry',
|
||||
label: String(serviceCount?.telemetry ?? ''),
|
||||
icon: LuWifi,
|
||||
to: '/telemetry',
|
||||
},
|
||||
{
|
||||
title: 'Pages',
|
||||
label: String(serviceCount?.page ?? ''),
|
||||
icon: LuFilePieChart,
|
||||
to: '/page',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Separator />
|
||||
<div className="flex-1" />
|
||||
<Separator />
|
||||
|
||||
<div className={cn(isCollapsed && 'm-auto')}>
|
||||
<UserConfig isCollapsed={isCollapsed} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<TooltipProvider delayDuration={0}>
|
||||
<ResizablePanelGroup
|
||||
@ -65,9 +121,9 @@ export const LayoutV2: React.FC<LayoutProps> = React.memo((props) => {
|
||||
>
|
||||
<ResizablePanel
|
||||
defaultSize={layout[0]}
|
||||
collapsedSize={4}
|
||||
collapsedSize={1}
|
||||
collapsible={true}
|
||||
minSize={15}
|
||||
minSize={10}
|
||||
maxSize={20}
|
||||
onCollapse={() => {
|
||||
setIsCollapsed(true);
|
||||
@ -81,55 +137,7 @@ export const LayoutV2: React.FC<LayoutProps> = React.memo((props) => {
|
||||
'min-w-[50px] transition-all duration-300 ease-in-out'
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'flex h-[52px] items-center justify-center',
|
||||
isCollapsed ? 'h-[52px]' : 'px-2'
|
||||
)}
|
||||
>
|
||||
<WorkspaceSwitcher isCollapsed={isCollapsed} />
|
||||
</div>
|
||||
<Separator />
|
||||
<Nav
|
||||
isCollapsed={isCollapsed}
|
||||
links={[
|
||||
{
|
||||
title: 'Website',
|
||||
label: String(serviceCount?.website ?? ''),
|
||||
icon: LuAreaChart,
|
||||
to: '/website',
|
||||
},
|
||||
{
|
||||
title: 'Monitor',
|
||||
label: String(serviceCount?.monitor ?? ''),
|
||||
icon: LuMonitorDot,
|
||||
to: '/monitor',
|
||||
},
|
||||
{
|
||||
title: 'Servers',
|
||||
label: '',
|
||||
icon: LuServer,
|
||||
to: '/server',
|
||||
},
|
||||
{
|
||||
title: 'Telemetry',
|
||||
label: String(serviceCount?.telemetry ?? ''),
|
||||
icon: LuWifi,
|
||||
to: '/telemetry',
|
||||
},
|
||||
{
|
||||
title: 'Pages',
|
||||
label: String(serviceCount?.page ?? ''),
|
||||
icon: LuFilePieChart,
|
||||
to: '/page',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Separator />
|
||||
<div className="flex-1" />
|
||||
<Separator />
|
||||
|
||||
<UserConfig isCollapsed={isCollapsed} />
|
||||
{navbar}
|
||||
</ResizablePanel>
|
||||
|
||||
{props.list && (
|
||||
|
Loading…
Reference in New Issue
Block a user