207 lines
5.7 KiB
Svelte
207 lines
5.7 KiB
Svelte
<script lang="ts" module>
|
|
import ChartNoAxesColumn from 'lucide-svelte/icons/chart-no-axes-column';
|
|
import ChevronsUpDown from 'lucide-svelte/icons/chevrons-up-down';
|
|
import CircleHelp from 'lucide-svelte/icons/circle-help';
|
|
import Code from 'lucide-svelte/icons/code';
|
|
import GitBranch from 'lucide-svelte/icons/git-branch';
|
|
import LayoutDashboard from 'lucide-svelte/icons/layout-dashboard';
|
|
import LogOut from 'lucide-svelte/icons/log-out';
|
|
import Radio from 'lucide-svelte/icons/radio';
|
|
import ScrollText from 'lucide-svelte/icons/scroll-text';
|
|
import Settings from 'lucide-svelte/icons/settings';
|
|
|
|
let navigation = $state([
|
|
{
|
|
title: null,
|
|
isAdmin: false,
|
|
items: [
|
|
{
|
|
title: 'Dashboard',
|
|
url: '/',
|
|
icon: LayoutDashboard
|
|
},
|
|
{
|
|
title: 'Classement',
|
|
url: '/leaderboard',
|
|
icon: ChartNoAxesColumn
|
|
},
|
|
{
|
|
title: 'Chapitres',
|
|
url: '/chapters',
|
|
icon: Code
|
|
}
|
|
]
|
|
},
|
|
{
|
|
title: 'Documentation',
|
|
isAdmin: false,
|
|
items: [
|
|
{
|
|
title: 'Git',
|
|
url: 'https://git.peerat.dev',
|
|
icon: GitBranch
|
|
},
|
|
{
|
|
title: 'Discord',
|
|
url: 'https://discord.gg/72vuHcwUkE',
|
|
icon: CircleHelp
|
|
}
|
|
]
|
|
},
|
|
{
|
|
title: 'Administration',
|
|
isAdmin: true,
|
|
items: [
|
|
{
|
|
title: 'Logs',
|
|
url: '/admin/logs',
|
|
icon: ScrollText
|
|
},
|
|
{
|
|
title: 'Puzzles',
|
|
url: '/admin/puzzles',
|
|
icon: Code
|
|
}
|
|
,
|
|
{
|
|
title: 'Broadcast',
|
|
url: '/admin/broadcast',
|
|
icon: Radio
|
|
}
|
|
]
|
|
}
|
|
]);
|
|
</script>
|
|
|
|
<script lang="ts">
|
|
import { afterNavigate, goto } from '$app/navigation';
|
|
import { page } from '$app/state';
|
|
import type { ComponentProps } from 'svelte';
|
|
|
|
import * as Avatar from '$lib/components/ui/avatar';
|
|
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
|
|
import * as Sidebar from '$lib/components/ui/sidebar';
|
|
import { useSidebar } from '$lib/components/ui/sidebar';
|
|
|
|
let {
|
|
ref = $bindable(null),
|
|
collapsible = 'icon',
|
|
...restProps
|
|
}: ComponentProps<typeof Sidebar.Root> = $props();
|
|
|
|
const sidebar = useSidebar();
|
|
|
|
navigation = navigation.filter(
|
|
(nav) => !nav.isAdmin || page.data.user?.email.endsWith('@peerat.dev')
|
|
);
|
|
|
|
afterNavigate(() => {
|
|
if (sidebar.isMobile) {
|
|
sidebar.setOpenMobile(false);
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<Sidebar.Root bind:ref {collapsible} {...restProps}>
|
|
<Sidebar.Header>
|
|
<Sidebar.Menu>
|
|
<a href="/">
|
|
<Sidebar.MenuItem>
|
|
<Sidebar.MenuButton
|
|
size="lg"
|
|
class="rounded data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
|
|
>
|
|
<div class="flex aspect-square size-8 items-center justify-center rounded">
|
|
<img src="/favicon.ico" alt="Peer-at Code" class="size-6" />
|
|
</div>
|
|
<div class="grid flex-1 text-left text-sm leading-tight">
|
|
<span class="truncate font-semibold"> Peer-at Code </span>
|
|
</div>
|
|
</Sidebar.MenuButton>
|
|
</Sidebar.MenuItem>
|
|
</a>
|
|
</Sidebar.Menu>
|
|
</Sidebar.Header>
|
|
<Sidebar.Content>
|
|
{#each navigation as navigation}
|
|
<Sidebar.Group>
|
|
{#if navigation.title}
|
|
<Sidebar.GroupLabel>{navigation.title}</Sidebar.GroupLabel>
|
|
{/if}
|
|
<Sidebar.Menu>
|
|
{#each navigation.items as item (item.title)}
|
|
<Sidebar.MenuItem>
|
|
<Sidebar.MenuButton class="rounded" isActive={page.url.pathname === item.url}>
|
|
{#snippet child({ props })}
|
|
<a href={item.url} {...props}>
|
|
<item.icon />
|
|
<span>{item.title}</span>
|
|
</a>
|
|
{/snippet}
|
|
</Sidebar.MenuButton>
|
|
</Sidebar.MenuItem>
|
|
{/each}
|
|
</Sidebar.Menu>
|
|
</Sidebar.Group>
|
|
{/each}
|
|
</Sidebar.Content>
|
|
<Sidebar.Footer>
|
|
<Sidebar.Menu>
|
|
<Sidebar.MenuItem>
|
|
<DropdownMenu.Root>
|
|
<DropdownMenu.Trigger>
|
|
{#snippet child({ props })}
|
|
<Sidebar.MenuButton
|
|
size="lg"
|
|
class="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
|
|
{...props}
|
|
>
|
|
<Avatar.Root class="h-8 w-8 rounded">
|
|
<Avatar.Image src={page.data.user?.avatar} alt={page.data.user?.pseudo} />
|
|
<Avatar.Fallback class="rounded">CN</Avatar.Fallback>
|
|
</Avatar.Root>
|
|
<div class="grid flex-1 text-left text-sm leading-tight">
|
|
<span class="truncate font-semibold">{page.data.user?.pseudo}</span>
|
|
<span class="truncate text-xs">{page.data.user?.email}</span>
|
|
</div>
|
|
<ChevronsUpDown class="ml-auto size-4" />
|
|
</Sidebar.MenuButton>
|
|
{/snippet}
|
|
</DropdownMenu.Trigger>
|
|
<DropdownMenu.Content
|
|
class="w-[--bits-dropdown-menu-anchor-width] min-w-56 rounded"
|
|
side={sidebar.isMobile ? 'bottom' : 'right'}
|
|
align="end"
|
|
sideOffset={4}
|
|
>
|
|
<DropdownMenu.Label class="p-0 font-normal">
|
|
<div class="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
|
|
<Avatar.Root class="h-8 w-8 rounded">
|
|
<Avatar.Image src={page.data.user?.avatar} alt={page.data.user?.pseudo} />
|
|
<Avatar.Fallback class="rounded">CN</Avatar.Fallback>
|
|
</Avatar.Root>
|
|
<div class="grid flex-1 text-left text-sm leading-tight">
|
|
<span class="truncate font-semibold">{page.data.user?.pseudo}</span>
|
|
<span class="truncate text-xs">{page.data.user?.email}</span>
|
|
</div>
|
|
</div>
|
|
</DropdownMenu.Label>
|
|
<DropdownMenu.Separator />
|
|
<DropdownMenu.Group>
|
|
<DropdownMenu.Item disabled>
|
|
<Settings />
|
|
Paramètres
|
|
</DropdownMenu.Item>
|
|
</DropdownMenu.Group>
|
|
<DropdownMenu.Separator />
|
|
<DropdownMenu.Item onclick={() => goto('/logout')}>
|
|
<LogOut />
|
|
Se déconnecter
|
|
</DropdownMenu.Item>
|
|
</DropdownMenu.Content>
|
|
</DropdownMenu.Root>
|
|
</Sidebar.MenuItem>
|
|
</Sidebar.Menu>
|
|
</Sidebar.Footer>
|
|
<Sidebar.Rail />
|
|
</Sidebar.Root>
|