frontend: make the logo block exactly as wide as the second-level menu

The logo block stopped wherever its text happened to end (~140px) while the
rail below it is 208px, so the left edge was a step rather than a column.

Both now read `asideWidth()` from src/layout.ts, so they cannot drift apart,
and collapsing the rail narrows the logo block with it — the wordmark is
dropped and the mark centres in the 56px strip. The block also carries the
rail's separator up through the header, so the column reads as one piece.

The header's own 20px padding had to go for this to work: the logo block has
to start at x=0 to be flush with the rail, so the nav and the right-hand mark
now own their insets. The mark's inset comes from the same `ASIDE_INSET` as
the rail's section title, so the two line up.

A side effect worth keeping: the rail is 208px and the top nav's first item
and .el-main are each inset a further 20px by their own Element Plus defaults,
so the nav text, the page body and the page header all start on one vertical
line.

The widths live in a module rather than CSS custom properties because el-aside
takes its width through a prop and would otherwise fight an inline style.
This commit is contained in:
2026-09-18 16:43:30 +08:00
parent 4b826567b8
commit 0d0aa20be2
4 changed files with 123 additions and 12 deletions
+13 -2
View File
@@ -11,6 +11,7 @@ import { computed, type Component } from 'vue'
import { useRoute } from 'vue-router'
import { Document, Expand, Files, Fold, Setting } from '@element-plus/icons-vue'
import { ASIDE_INSET, asideWidth } from '@/layout'
import { useAppStore } from '@/stores/app'
interface AsideItem {
@@ -46,13 +47,21 @@ const MENUS: Record<string, AsideMenu> = {
const menu = computed<AsideMenu | null>(() => MENUS[props.section] ?? null)
const collapsed = computed(() => appStore.asideCollapsed)
/**
* The rail's width, from the one place the header's logo block reads too, so
* the two cannot drift apart.
*/
const width = computed(() => asideWidth(collapsed.value))
const inset = ASIDE_INSET
</script>
<template>
<el-aside
v-if="menu"
class="app-aside"
:width="collapsed ? '56px' : '208px'"
:width="width"
:style="{ '--aside-inset': inset }"
>
<div class="aside-head" :class="{ 'is-collapsed': collapsed }">
<span v-if="!collapsed" class="aside-title">{{ menu.title }}</span>
@@ -107,7 +116,9 @@ const collapsed = computed(() => appStore.asideCollapsed)
justify-content: space-between;
gap: 8px;
height: 48px;
padding: 0 8px 0 16px;
/* Left inset comes from the shared metric so the section title lines up with
the mark in the header above it. */
padding: 0 8px 0 var(--aside-inset);
border-bottom: 1px solid var(--el-border-color-lighter);
flex: 0 0 auto;
}