101 lines
6.5 KiB
Vue
101 lines
6.5 KiB
Vue
<template>
|
|
<div ref="container"></div>
|
|
<div ref="slotContainer"><slot></slot></div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { link, optionmenu } from '~/shared/components.util';
|
|
import { Content, iconByType } from '~/shared/content.util';
|
|
import { div, dom, icon, span, text } from '~/shared/dom.util';
|
|
import { popper, tooltip } from '~/shared/floating.util';
|
|
import { unifySlug } from '~/shared/general.util';
|
|
import { TreeDOM } from '~/shared/tree';
|
|
|
|
const container = useTemplateRef('container'), slots = useTemplateRef('slotContainer');
|
|
|
|
const open = ref(false);
|
|
const { loggedIn, user, clear: logout } = useUserSession();
|
|
const { fetch } = useContent();
|
|
|
|
await fetch(false);
|
|
|
|
const route = useRouter().currentRoute;
|
|
const path = computed(() => route.value.params.path ? decodeURIComponent(unifySlug(route.value.params.path)) : undefined);
|
|
|
|
await Content.init();
|
|
const tree = new TreeDOM((item, depth) => {
|
|
return dom('div', { class: 'group flex items-center ps-2 outline-none relative cursor-pointer', style: { 'padding-inline-start': `${depth / 1.5}em` } }, [dom('div', { class: ['flex flex-1 items-center hover:border-accent-blue hover:text-accent-purple max-w-full cursor-pointer font-medium'], attributes: { 'data-private': item.private } }, [
|
|
icon('radix-icons:chevron-right', { class: 'h-4 w-4 transition-transform absolute group-data-[state=open]:rotate-90', style: { 'left': `${depth / 1.5 - 1}em` } }),
|
|
dom('div', { class: 'pl-1.5 py-1.5 flex-1 truncate', text: item.title, attributes: { title: item.title } }),
|
|
item.private ? tooltip(icon('radix-icons:lock-closed', { class: 'mx-1' }), 'Privé', 'right') : undefined,
|
|
])]);
|
|
}, (item, depth) => {
|
|
return dom('div', { class: 'group flex items-center ps-2 outline-none relative cursor-pointer', style: { 'padding-inline-start': `${depth / 1.5}em` } }, [link([
|
|
icon(iconByType[item.type], { class: 'w-5 h-5', width: 20, height: 20 }),
|
|
dom('div', { class: 'pl-1.5 py-1.5 flex-1 truncate', text: item.title, attributes: { title: item.title } }),
|
|
item.private ? tooltip(icon('radix-icons:lock-closed', { class: 'mx-1' }), 'Privé', 'right') : undefined,
|
|
], { class: ['flex flex-1 items-center hover:border-accent-blue hover:text-accent-purple max-w-full'], attributes: { 'data-private': item.private }, active: 'text-accent-blue' }, item.path ? { name: 'explore-path', params: { path: item.path } } : undefined)]);
|
|
}, (item) => item.navigable);
|
|
const toggleByPath = (path: string | undefined) => (path?.split('/').map((e, i, a) => a.slice(0, i).join('/')) ?? []).forEach(e => tree.toggle(tree.tree.search('path', e)[0], true));
|
|
toggleByPath(path.value);
|
|
|
|
const unmount = useRouter().afterEach((to, from, failure) => {
|
|
if(failure)
|
|
return;
|
|
|
|
to.name === 'explore-path' && toggleByPath(unifySlug(to.params.path ?? ''));
|
|
});
|
|
|
|
watch(route, () => {
|
|
open.value = false;
|
|
});
|
|
|
|
const getUserDom = () => user.value ? [popper(link([ text(user.value.username), icon('radix-icons:caret-down', { width: 12, height: 12 }) ], { class: 'flex flex-row gap-2 items-center border-b-2 border-transparent hover:border-accent-blue py-4 select-none' }, { name: 'user-profile' }), {
|
|
placement: 'bottom', delay: 0, content: () => [div('flex flex-1 flex-col', [
|
|
dom('span', { class: 'hover:bg-light-30 dark:hover:bg-dark-30 px-4 py-2 cursor-pointer select-none', listeners: { click: logout } }, [ text('Se déconnecter') ], ),
|
|
])], class: 'bg-light-10 dark:bg-dark-10 border border-light-35 dark:border-dark-35 group-data-[pinned]:bg-light-15 dark:group-data-[pinned]:bg-dark-15 group-data-[pinned]:border-light-50 dark:group-data-[pinned]:border-dark-50 text-light-100 dark:text-dark-100 z-[45] relative group-data-[pinned]:h-full'
|
|
}).container] : [link([ text('S\'inscrire') ], { class: 'flex flex-row gap-2 items-center border-b-2 border-transparent hover:border-accent-blue py-4 select-none' }, { name: 'user-register' }), link([ text('Se connecter') ], { class: 'flex flex-row gap-2 items-center border-b-2 border-transparent hover:border-accent-blue py-4 select-none' }, { name: 'user-login' })];
|
|
|
|
const slotContainer = div('flex flex-1');
|
|
const content = () => div('flex flex-row w-full h-full', [
|
|
div('bg-light-0 dark:bg-dark-0 w-[300px] border-r border-light-30 dark:border-dark-30 flex flex-col gap-2', [
|
|
link([ dom('img', { attributes: { src: '/logo.dark.svg', width: 52, height: 41 } }), span('text-xl font-semibold group-hover:text-light-70 dark:group-hover:text-dark-70', 'd[any]') ], { class: 'flex flex-row items-center justify-center group gap-2 my-2' }, { name: 'index' }),
|
|
div('flex-1 px-2 max-w-full max-h-full overflow-y-auto overflow-x-hidden', [ tree.container ]),
|
|
div('flex flex-col my-4 items-center justify-center gap-1 text-xs text-light-60 dark:text-dark-60', [
|
|
link([ text('Mentions légales') ], { class: 'hover:underline' }, { name: 'legal' }),
|
|
link([ text('Conditions d\'utilisations') ], { class: 'hover:underline' }, { name: 'usage' }),
|
|
text('Copyright 2025 - Peaceultime & d[any]')
|
|
])
|
|
]),
|
|
div('flex flex-col flex-1 h-full', [
|
|
div('flex flex-row border-b border-light-30 dark:border-dark-30 justify-between px-8', [
|
|
div('flex flex-row gap-16 items-center', [
|
|
popper(link([ text('Personnages'), icon('radix-icons:caret-down', { width: 12, height: 12 }) ], { class: 'flex flex-row gap-2 items-center border-b-2 border-transparent hover:border-accent-blue py-4 select-none' }, { name: 'character' }), {
|
|
placement: 'bottom', delay: 0, content: () => [div('flex flex-1 flex-col', [
|
|
link([ text('Personnages publics') ], { class: 'hover:bg-light-30 dark:hover:bg-dark-30 px-4 py-2 select-none' }, { name: 'character-list' }),
|
|
link([ text('Nouveau personnage') ], { class: 'hover:bg-light-30 dark:hover:bg-dark-30 px-4 py-2 select-none' }, { name: 'character-id-edit', params: { id: 'new' } })
|
|
])], class: 'bg-light-10 dark:bg-dark-10 border border-light-35 dark:border-dark-35 group-data-[pinned]:bg-light-15 dark:group-data-[pinned]:bg-dark-15 group-data-[pinned]:border-light-50 dark:group-data-[pinned]:border-dark-50 text-light-100 dark:text-dark-100 z-[45] relative group-data-[pinned]:h-full'
|
|
}).container,
|
|
link([ text('Campagnes') ], { class: 'flex flex-row gap-2 items-center border-b-2 border-transparent hover:border-accent-blue py-4 select-none' }, { name: 'character' })
|
|
]),
|
|
div('flex flex-row gap-16 items-center', getUserDom())
|
|
]),
|
|
slotContainer,
|
|
])
|
|
]);
|
|
|
|
onMounted(() => {
|
|
if(container.value && slots.value)
|
|
{
|
|
slotContainer.replaceChildren(...slots.value.childNodes);
|
|
container.value!.replaceWith(content());
|
|
}
|
|
});
|
|
|
|
onUpdated(() => {
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
unmount();
|
|
});
|
|
</script> |