Files
bili-sync-ai/web/src/lib/components/app-sidebar.svelte
2025-07-08 12:48:51 +08:00

145 lines
3.6 KiB
Svelte

<script lang="ts">
import DatabaseIcon from '@lucide/svelte/icons/database';
import FileVideoIcon from '@lucide/svelte/icons/file-video';
import BotIcon from '@lucide/svelte/icons/bot';
import ChartPieIcon from '@lucide/svelte/icons/chart-pie';
import HeartIcon from '@lucide/svelte/icons/heart';
import FolderIcon from '@lucide/svelte/icons/folder';
import UserIcon from '@lucide/svelte/icons/user';
import Settings2Icon from '@lucide/svelte/icons/settings-2';
import SquareTerminalIcon from '@lucide/svelte/icons/square-terminal';
import * as Sidebar from '$lib/components/ui/sidebar/index.js';
import type { ComponentProps } from 'svelte';
let { ref = $bindable(null), ...restProps }: ComponentProps<typeof Sidebar.Root> = $props();
const data = {
header: {
title: 'Bili Sync',
subtitle: '后台管理系统',
icon: BotIcon,
href: '/'
},
navMain: [
{
category: '总览',
items: [
{
title: '仪表盘',
icon: ChartPieIcon,
href: '/'
},
{
title: '日志',
icon: SquareTerminalIcon,
href: '/logs'
}
]
},
{
category: '内容管理',
items: [
{
title: '视频',
icon: FileVideoIcon,
href: '/videos'
},
{
title: '视频源',
icon: DatabaseIcon,
href: '/video-sources'
}
]
},
{
category: '快捷订阅',
items: [
{
title: '收藏夹',
icon: HeartIcon,
href: '/me/favorites'
},
{
title: '合集',
icon: FolderIcon,
href: '/me/collections'
},
{
title: 'up 主',
icon: UserIcon,
href: '/me/uppers'
}
]
}
],
footer: [
{
title: '设置',
icon: Settings2Icon,
href: '/settings'
}
]
};
</script>
<Sidebar.Root bind:ref variant="inset" {...restProps}>
<Sidebar.Header>
<Sidebar.Menu>
<Sidebar.MenuItem>
<Sidebar.MenuButton size="lg">
{#snippet child({ props })}
<a href={data.header.href} {...props}>
<div
class="bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg"
>
<data.header.icon class="size-4" />
</div>
<div class="grid flex-1 text-left text-sm leading-tight">
<span class="truncate font-medium">{data.header.title}</span>
<span class="truncate text-xs">{data.header.subtitle}</span>
</div>
</a>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
</Sidebar.Menu>
</Sidebar.Header>
<Sidebar.Content>
<Sidebar.Group>
{#each data.navMain as group (group.category)}
<Sidebar.GroupLabel class="h-10">{group.category}</Sidebar.GroupLabel>
<Sidebar.Menu>
{#each group.items as item (item.title)}
<Sidebar.MenuItem>
<Sidebar.MenuButton class="h-8">
{#snippet child({ props })}
<a href={item.href} {...props}>
<item.icon class="size-4" />
<span class="text-sm">{item.title}</span>
</a>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
{/each}
</Sidebar.Menu>
{/each}
</Sidebar.Group>
</Sidebar.Content>
<Sidebar.Footer>
<Sidebar.Separator />
<Sidebar.Menu>
{#each data.footer as item (item.title)}
<Sidebar.MenuItem>
<Sidebar.MenuButton class="h-8">
{#snippet child({ props })}
<a href={item.href} {...props}>
<item.icon class="size-4" />
<span class="text-sm">{item.title}</span>
</a>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
{/each}
</Sidebar.Menu>
</Sidebar.Footer>
</Sidebar.Root>