67 lines
2.5 KiB
Vue
67 lines
2.5 KiB
Vue
<script setup lang="ts">
|
|
import { computed, nextTick } from 'vue'
|
|
import { PanelLeftClose } from '@lucide/vue'
|
|
import { RouterLink, useRoute } from 'vue-router'
|
|
import type { NavigationEntry } from '../../api/types'
|
|
import { controllerIdFromPath, controllerPath } from '../../app/controllerRoutes'
|
|
import { iconFor } from '../../app/icons'
|
|
import { t } from '../../app/i18n'
|
|
import { setCollapsed } from '../../state/useSidebar'
|
|
|
|
// Section panel (design: Navigation shell, level 2): the active plugin's
|
|
// permitted side menu, 224px, with the plugin label and a "Zwiń menu" button
|
|
// in its header. Collapsing hides it and leaves only the rail (D-06).
|
|
|
|
const props = defineProps<{ entry: NavigationEntry }>()
|
|
const route = useRoute()
|
|
|
|
const currentController = computed(() => controllerIdFromPath(route.path))
|
|
|
|
const items = computed(() =>
|
|
props.entry.sideMenu.flatMap((item) => {
|
|
const to = controllerPath(item.controller)
|
|
if (!to) {
|
|
return []
|
|
}
|
|
return [{ item, to, icon: iconFor(item.icon), current: currentController.value === item.controller }]
|
|
}),
|
|
)
|
|
|
|
function collapse(): void {
|
|
setCollapsed(true)
|
|
void nextTick(() => document.querySelector<HTMLElement>('[data-sidebar-expand]')?.focus())
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<aside
|
|
:aria-label="t('backend::lang.nav.sections')"
|
|
class="sticky top-0 flex h-screen w-panel shrink-0 flex-col gap-0.5 self-start overflow-y-auto border-r border-border bg-surface px-3 py-3.5"
|
|
>
|
|
<div class="mb-3.5 flex h-10 items-center justify-between gap-2 pl-2">
|
|
<span class="truncate text-[16px] font-bold">{{ entry.label }}</span>
|
|
<button
|
|
type="button"
|
|
data-sidebar-collapse
|
|
:aria-label="t('backend::lang.nav.collapse')"
|
|
:title="t('backend::lang.nav.collapse')"
|
|
class="flex size-[30px] shrink-0 items-center justify-center rounded-tab text-muted transition-colors duration-150 ease-out hover:bg-hover hover:text-text"
|
|
@click="collapse"
|
|
>
|
|
<PanelLeftClose :size="18" aria-hidden="true" />
|
|
</button>
|
|
</div>
|
|
<RouterLink
|
|
v-for="link in items"
|
|
:key="link.item.code"
|
|
:to="link.to"
|
|
:aria-current="link.current ? 'page' : undefined"
|
|
:class="link.current ? 'bg-sel font-semibold text-text' : 'font-medium text-muted hover:bg-hover hover:text-text'"
|
|
class="flex h-nav items-center gap-3 rounded-control px-3 no-underline transition-colors duration-150 ease-out"
|
|
>
|
|
<component :is="link.icon" :size="18" aria-hidden="true" />
|
|
<span>{{ link.item.label }}</span>
|
|
</RouterLink>
|
|
</aside>
|
|
</template>
|