Files
summercms/admin/src/components/shell/SectionPanel.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>