feat: 收口移动端侧栏与创作拆解页布局

This commit is contained in:
GJ
2026-09-04 19:41:17 +08:00
parent c483b1912e
commit 542ec296c7
12 changed files with 250 additions and 49 deletions
+45 -26
View File
@@ -38,10 +38,12 @@ const NARROW_NAV = '(max-width: 800px)'
const SIDER_COLLAPSED_WIDTH = 64
/** 展开侧栏宽度,窄屏裁切动画以内层保持该宽度。 */
const SIDER_EXPANDED_WIDTH = 208
/** 窄屏折叠侧栏宽度,给正文多留空间,仍覆盖 44px 点击区。 */
const SIDER_COLLAPSED_WIDTH_NARROW = 48
/** 窄屏展开侧栏宽度。 */
const SIDER_EXPANDED_WIDTH_NARROW = 168
/** 菜单图标尺寸,折叠/展开共用,避免切换时缩放。 */
const NAV_ICON_SIZE = 20
/** 折叠与展开共用的图标左偏移,避免切换时图标跳动。 */
const NAV_ICON_INDENT = SIDER_COLLAPSED_WIDTH / 2 - NAV_ICON_SIZE / 2
/** 应用外壳固定在视口内,业务数据仍由各工作区自行加载。 */
const route = useRoute()
@@ -51,6 +53,12 @@ const collapsed = ref(narrow.value)
const settingsOpen = ref(false)
/** 窄屏折叠只裁切文字,不把菜单收成图标,避免推挤动画时错位。 */
const menuCollapsed = computed(() => !narrow.value && collapsed.value)
/** 当前视口下的折叠侧栏宽度。 */
const siderCollapsedWidth = computed(() => (narrow.value ? SIDER_COLLAPSED_WIDTH_NARROW : SIDER_COLLAPSED_WIDTH))
/** 当前视口下的展开侧栏宽度。 */
const siderExpandedWidth = computed(() => (narrow.value ? SIDER_EXPANDED_WIDTH_NARROW : SIDER_EXPANDED_WIDTH))
/** 折叠与展开共用的图标左偏移,避免切换时图标跳动。 */
const navIconIndent = computed(() => siderCollapsedWidth.value / 2 - NAV_ICON_SIZE / 2)
/** 视口跨过断点时:进入窄屏收回侧栏。 */
function syncNarrow(event: MediaQueryListEvent) {
@@ -144,19 +152,25 @@ const menuOptions = computed<MenuOption[]>(() => [
<div
class="admin-layout"
:style="{
'--admin-sider-collapsed': SIDER_COLLAPSED_WIDTH + 'px',
'--admin-sider-expanded': SIDER_EXPANDED_WIDTH + 'px'
'--admin-sider-collapsed': siderCollapsedWidth + 'px',
'--admin-sider-expanded': siderExpandedWidth + 'px'
}"
>
<!-- 以下是主导航侧栏宽屏与窄屏共用同一份 -->
<aside
class="admin-sider"
:class="{ 'is-collapsed': collapsed }"
:style="{ width: (collapsed ? SIDER_COLLAPSED_WIDTH : SIDER_EXPANDED_WIDTH) + 'px' }"
:style="{ width: (collapsed ? siderCollapsedWidth : siderExpandedWidth) + 'px' }"
aria-label="主导航"
>
<RouterLink to="/projects" class="admin-brand" aria-label="短剧工作台首页">
<Clapperboard :size="24" /><span v-if="!menuCollapsed"
<!-- 以下是侧栏品牌折叠仅图标展开图标加文字 -->
<RouterLink
to="/projects"
class="admin-brand"
:class="{ 'is-collapsed': collapsed }"
aria-label="短剧工作台首页"
>
<Clapperboard :size="narrow ? NAV_ICON_SIZE : 24" /><span v-if="!collapsed"
>短剧工作台<small>SHORT DRAMA STUDIO</small></span
>
</RouterLink>
@@ -165,13 +179,14 @@ const menuOptions = computed<MenuOption[]>(() => [
:value="route.path"
:options="menuOptions"
:collapsed="menuCollapsed"
:collapsed-width="SIDER_COLLAPSED_WIDTH"
:collapsed-width="siderCollapsedWidth"
:icon-size="NAV_ICON_SIZE"
:collapsed-icon-size="NAV_ICON_SIZE"
:indent="NAV_ICON_INDENT"
:root-indent="NAV_ICON_INDENT"
:indent="navIconIndent"
:root-indent="navIconIndent"
/>
</NScrollbar>
<!-- 以下是侧栏底部后端连接折叠仅图标展开图标加文字 -->
<footer class="admin-sider-footer">
<NTooltip placement="right" :disabled="!collapsed">
<template #trigger>
@@ -179,12 +194,12 @@ const menuOptions = computed<MenuOption[]>(() => [
quaternary
block
class="admin-settings-button"
:class="{ 'is-collapsed': menuCollapsed }"
:class="{ 'is-collapsed': collapsed }"
aria-label="后端连接"
@click="openSettings"
>
<template #icon><Settings2 :size="18" /></template>
<span v-if="!menuCollapsed">后端连接</span>
<span v-if="!collapsed">后端连接</span>
</NButton>
</template>
后端连接
@@ -265,11 +280,14 @@ const menuOptions = computed<MenuOption[]>(() => [
@apply flex-1 min-h-0;
}
.admin-sider-footer {
@apply shrink-0;
@apply w-full shrink-0 overflow-hidden;
padding-block: 8px max(8px, env(safe-area-inset-bottom));
}
.n-button.admin-settings-button {
@apply justify-start h-11 px-5;
@apply justify-start h-11 w-full px-5;
}
.n-button.admin-settings-button.is-collapsed {
@apply justify-center px-0;
}
.admin-sider .n-menu .n-menu-item-content::before {
@apply left-0 right-0 rounded-none;
@@ -277,6 +295,9 @@ const menuOptions = computed<MenuOption[]>(() => [
.admin-brand {
@apply flex shrink-0 items-center gap-3 h-[74px] py-0 px-5 text-ink whitespace-nowrap;
}
.admin-brand.is-collapsed {
@apply justify-center px-0;
}
.admin-brand > svg {
@apply shrink-0;
}
@@ -307,20 +328,20 @@ const menuOptions = computed<MenuOption[]>(() => [
min-width: calc(100% - var(--admin-sider-collapsed));
max-width: calc(100% - var(--admin-sider-collapsed));
}
.admin-brand,
.admin-nav-scroll.n-scrollbar,
.admin-sider-footer {
.admin-nav-scroll.n-scrollbar {
min-width: var(--admin-sider-expanded);
}
.admin-brand span,
.admin-sider .n-menu-item-content-header,
.admin-settings-button span {
.admin-brand {
@apply h-12 w-full overflow-hidden;
}
.admin-sider:not(.is-collapsed) .admin-brand {
@apply justify-start px-3.5;
}
.admin-sider .n-menu-item-content-header {
opacity: 1;
transition: opacity 0.2s ease;
}
.admin-sider.is-collapsed .admin-brand span,
.admin-sider.is-collapsed .n-menu-item-content-header,
.admin-sider.is-collapsed .admin-settings-button span {
.admin-sider.is-collapsed .n-menu-item-content-header {
opacity: 0;
}
.admin-topbar {
@@ -329,9 +350,7 @@ const menuOptions = computed<MenuOption[]>(() => [
}
@media (prefers-reduced-motion: reduce) {
.admin-sider,
.admin-brand span,
.admin-sider .n-menu-item-content-header,
.admin-settings-button span {
.admin-sider .n-menu-item-content-header {
transition: none;
}
}