236 lines
5.1 KiB
Svelte
236 lines
5.1 KiB
Svelte
<script lang="ts">
|
|
import * as Sidebar from '$lib/components/ui/sidebar/index';
|
|
import { onDestroy, type ComponentProps } from 'svelte';
|
|
import { asset } from '$app/paths';
|
|
import AppAccountSelect from './app-account-select.svelte';
|
|
import { needPermission } from '$lib/core/handlers/permissionHandler';
|
|
import {
|
|
Code,
|
|
LayoutDashboard,
|
|
LucideEye,
|
|
CherryIcon,
|
|
DiamondIcon,
|
|
BugIcon,
|
|
CupSodaIcon,
|
|
Shield,
|
|
FileSpreadsheet
|
|
} from '@lucide/svelte/icons';
|
|
import TaobinLogo from '$lib/assets/logo.svelte';
|
|
import { goto } from '$app/navigation';
|
|
import Button from '$lib/components/ui/button/button.svelte';
|
|
import { sidebarStore } from '$lib/core/stores/sidebar';
|
|
import { auth } from '$lib/core/stores/auth';
|
|
import { isUserAdmin } from '$lib/core/admin/adminService';
|
|
import { referenceFromPage } from '$lib/core/stores/recipeStore';
|
|
|
|
let sideBar: HTMLElement | null = $state(null);
|
|
let isSideBarOpen: boolean = $state(true);
|
|
let isAdmin: boolean = $state(false);
|
|
|
|
const data = {
|
|
navMain: [
|
|
{
|
|
title: 'Home',
|
|
items: [
|
|
{
|
|
title: 'Dashboard',
|
|
url: '/dashboard',
|
|
icon: LayoutDashboard,
|
|
requirePerm: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
title: 'Recipe',
|
|
items: [
|
|
{
|
|
title: 'Overview',
|
|
url: '/recipe/overview',
|
|
icon: LucideEye,
|
|
requirePerm: ''
|
|
},
|
|
{
|
|
title: 'Topping',
|
|
url: '/recipe/topping',
|
|
icon: CherryIcon,
|
|
requirePerm: ''
|
|
},
|
|
{
|
|
title: 'Material',
|
|
url: '/recipe/material',
|
|
icon: DiamondIcon,
|
|
requirePerm: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
title: 'Tools',
|
|
items: [
|
|
{
|
|
title: 'Brew',
|
|
url: '/tools/brew',
|
|
icon: CupSodaIcon,
|
|
requirePerm: ''
|
|
},
|
|
{
|
|
title: 'Debug',
|
|
url: '/tools/debug',
|
|
icon: BugIcon,
|
|
requirePerm: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
title: 'Sheet',
|
|
items: [
|
|
{
|
|
title: 'Overview',
|
|
url: '/departments',
|
|
icon: FileSpreadsheet,
|
|
requirePerm: 'document.write.*'
|
|
}
|
|
]
|
|
}
|
|
]
|
|
};
|
|
|
|
const adminNav = {
|
|
title: 'Admin',
|
|
items: [
|
|
{
|
|
title: 'Permissions',
|
|
url: '/admin/users',
|
|
icon: Shield
|
|
}
|
|
]
|
|
};
|
|
|
|
$effect(() => {
|
|
const currentUser = $auth;
|
|
if (currentUser) {
|
|
isUserAdmin(currentUser.uid)
|
|
.then((result) => {
|
|
isAdmin = result;
|
|
})
|
|
.catch((e) => {
|
|
console.error('Error checking admin status:', e);
|
|
isAdmin = false;
|
|
});
|
|
} else {
|
|
isAdmin = false;
|
|
}
|
|
});
|
|
|
|
function onClickLogoIcon() {
|
|
goto('/departments');
|
|
}
|
|
|
|
let unsubSidebar = sidebarStore.subscribe((state) => {
|
|
isSideBarOpen = state;
|
|
});
|
|
|
|
onDestroy(() => {
|
|
unsubSidebar();
|
|
});
|
|
|
|
let authorizedNavMain = $derived(
|
|
data.navMain.map(nav => {
|
|
const filteredItems = nav.items.filter(item => {
|
|
if (!item.requirePerm) return true;
|
|
|
|
return needPermission(item.requirePerm);
|
|
});
|
|
|
|
return { ...nav, items: filteredItems };
|
|
|
|
}).filter(nav => nav.items.length > 0)
|
|
);
|
|
|
|
let {
|
|
ref = sideBar,
|
|
collapsible = 'icon',
|
|
...restProps
|
|
}: ComponentProps<typeof Sidebar.Root> = $props();
|
|
</script>
|
|
|
|
<Sidebar.Root {collapsible} {...restProps}>
|
|
<Sidebar.Header>
|
|
<div class="flex items-center justify-center">
|
|
<button class="hover:cursor-pointer" onclick={onClickLogoIcon}>
|
|
<TaobinLogo size={isSideBarOpen ? 96 : 24} fillColor={'#FFFFFF'} />
|
|
</button>
|
|
</div>
|
|
</Sidebar.Header>
|
|
<Sidebar.Content>
|
|
{#each authorizedNavMain as nav}
|
|
<Sidebar.Group>
|
|
<Sidebar.GroupLabel>{nav.title}</Sidebar.GroupLabel>
|
|
<Sidebar.GroupContent>
|
|
<Sidebar.Menu>
|
|
{#each nav.items as sub}
|
|
<Sidebar.MenuItem>
|
|
<Sidebar.MenuButton>
|
|
{#snippet child({ props })}
|
|
<a
|
|
href={sub.url}
|
|
{...props}
|
|
onclick={(e) => {
|
|
if (nav.title === 'Sheet') {
|
|
e.preventDefault();
|
|
referenceFromPage.set('sheet');
|
|
goto(sub.url);
|
|
}
|
|
}}
|
|
>
|
|
{#if sub.icon}
|
|
<sub.icon />
|
|
{/if}
|
|
<span>{sub.title}</span>
|
|
</a>
|
|
{/snippet}
|
|
</Sidebar.MenuButton>
|
|
</Sidebar.MenuItem>
|
|
{/each}
|
|
</Sidebar.Menu>
|
|
</Sidebar.GroupContent>
|
|
</Sidebar.Group>
|
|
{/each}
|
|
|
|
{#if isAdmin}
|
|
<Sidebar.Group>
|
|
<Sidebar.GroupLabel>{adminNav.title}</Sidebar.GroupLabel>
|
|
<Sidebar.GroupContent>
|
|
<Sidebar.Menu>
|
|
{#each adminNav.items as sub}
|
|
<Sidebar.MenuItem>
|
|
<Sidebar.MenuButton>
|
|
{#snippet child({ props })}
|
|
<a
|
|
href={sub.url}
|
|
{...props}
|
|
onclick={(e) => {
|
|
if (nav.title === 'Sheet') {
|
|
e.preventDefault();
|
|
referenceFromPage.set('sheet');
|
|
goto(sub.url);
|
|
}
|
|
}}
|
|
>
|
|
{#if sub.icon}
|
|
<sub.icon />
|
|
{/if}
|
|
<span>{sub.title}</span>
|
|
</a>
|
|
{/snippet}
|
|
</Sidebar.MenuButton>
|
|
</Sidebar.MenuItem>
|
|
{/each}
|
|
</Sidebar.Menu>
|
|
</Sidebar.GroupContent>
|
|
</Sidebar.Group>
|
|
{/if}
|
|
</Sidebar.Content>
|
|
<Sidebar.Footer>
|
|
<AppAccountSelect />
|
|
</Sidebar.Footer>
|
|
</Sidebar.Root>
|