- Layer/page rows use the unified accent selection, 5px radius, airier 1.5 padding, and 11px labels - Panel headers (Layers, Assets, Pages) drop the uppercase tracked style for a single 11px/semibold/surface dialect matching section headers - Segmented control md size uses 11px to match the rest of the panel
86 lines
2.6 KiB
Vue
86 lines
2.6 KiB
Vue
<script setup lang="ts">
|
|
import { computed, ref } from 'vue'
|
|
import { SplitterGroup, SplitterPanel, SplitterResizeHandle } from 'reka-ui'
|
|
|
|
import { useI18n } from '@open-pencil/vue'
|
|
|
|
import AppMenu from '@/components/Shell/AppMenu.vue'
|
|
import SegmentedControl from '@/components/ui/SegmentedControl.vue'
|
|
import AssetsPanel from './AssetsPanel.vue'
|
|
import LayerTree from './LayerTree/LayerTree.vue'
|
|
import PagesPanel from './PagesPanel.vue'
|
|
|
|
const { menu, panels } = useI18n()
|
|
const activePanel = ref<'file' | 'assets'>('file')
|
|
const panelModel = computed({
|
|
get: () => activePanel.value,
|
|
set: (value: string) => {
|
|
if (value === 'file' || value === 'assets') activePanel.value = value
|
|
}
|
|
})
|
|
const panelOptions = computed(() => [
|
|
{ value: 'file', label: menu.value.file },
|
|
{ value: 'assets', label: panels.value.assets }
|
|
])
|
|
const panelTabsUI = { root: 'w-full' }
|
|
</script>
|
|
|
|
<template>
|
|
<aside
|
|
data-test-id="layers-panel"
|
|
class="flex min-w-0 flex-1 flex-col overflow-hidden border-r border-border bg-panel"
|
|
style="contain: paint layout style"
|
|
>
|
|
<AppMenu />
|
|
<div class="shrink-0 border-b border-border px-2 py-1.5">
|
|
<SegmentedControl
|
|
v-model="panelModel"
|
|
:options="panelOptions"
|
|
:label="panels.layers"
|
|
:ui="panelTabsUI"
|
|
>
|
|
<template #option="{ option }">
|
|
<span
|
|
:data-test-id="
|
|
option.value === 'file' ? 'left-panel-layers-tab' : 'left-panel-assets-tab'
|
|
"
|
|
class="truncate"
|
|
>
|
|
{{ option.label }}
|
|
</span>
|
|
</template>
|
|
</SegmentedControl>
|
|
</div>
|
|
<AssetsPanel v-if="activePanel === 'assets'" />
|
|
<SplitterGroup
|
|
v-else
|
|
direction="vertical"
|
|
auto-save-id="layers-layout"
|
|
class="flex-1 overflow-hidden"
|
|
>
|
|
<SplitterPanel
|
|
:default-size="30"
|
|
:min-size="10"
|
|
:max-size="60"
|
|
class="flex flex-col overflow-hidden"
|
|
>
|
|
<PagesPanel />
|
|
</SplitterPanel>
|
|
<SplitterResizeHandle class="group relative z-10 -my-1 h-2 cursor-row-resize">
|
|
<div
|
|
class="pointer-events-none absolute inset-x-0 top-1/2 h-px -translate-y-1/2 bg-border"
|
|
/>
|
|
</SplitterResizeHandle>
|
|
<SplitterPanel :default-size="70" :min-size="20" class="flex flex-col overflow-hidden">
|
|
<header
|
|
data-test-id="layers-header"
|
|
class="shrink-0 px-3 py-2 text-[11px] font-semibold text-surface"
|
|
>
|
|
{{ panels.layers }}
|
|
</header>
|
|
<LayerTree data-test-id="layers-tree" />
|
|
</SplitterPanel>
|
|
</SplitterGroup>
|
|
</aside>
|
|
</template>
|