fix(admin): unify sidebar collapse motion
This commit is contained in:
@@ -125,6 +125,7 @@ const filteredImages = computed(() => {
|
||||
const selectedManagedCount = computed(() => selectedImageIds.value.size)
|
||||
const displayUsername = computed(() => authStore.profile?.username || authStore.user?.email || '管理员')
|
||||
const userEmail = computed(() => authStore.user?.email || '未绑定邮箱')
|
||||
const displayInitial = computed(() => displayUsername.value.slice(0, 1).toUpperCase())
|
||||
|
||||
watch(imageFilter, () => {
|
||||
setSelectedImageIds([])
|
||||
@@ -491,56 +492,54 @@ onMounted(loadAdminData)
|
||||
<template>
|
||||
<div class="min-h-screen bg-[linear-gradient(180deg,#f8fafc_0%,#eef6ff_55%,#f8fafc_100%)]">
|
||||
<div
|
||||
class="min-h-screen w-full transition-[grid-template-columns] duration-200 lg:grid"
|
||||
class="min-h-screen w-full transition-[grid-template-columns] duration-200 ease-out lg:grid"
|
||||
:class="sidebarCollapsed
|
||||
? 'lg:grid-cols-[88px_minmax(0,1fr)]'
|
||||
: 'lg:grid-cols-[280px_minmax(0,1fr)]'"
|
||||
>
|
||||
<aside
|
||||
class="border-b border-slate-200 bg-white/90 px-4 py-4 backdrop-blur lg:sticky lg:top-0 lg:flex lg:h-screen lg:flex-col lg:border-b-0 lg:border-r lg:py-5"
|
||||
:class="sidebarCollapsed ? 'lg:px-3' : 'lg:px-5'"
|
||||
class="relative border-b border-slate-200 bg-white/90 px-4 py-4 backdrop-blur lg:sticky lg:top-0 lg:flex lg:h-screen lg:flex-col lg:border-b-0 lg:border-r lg:px-5 lg:py-5"
|
||||
>
|
||||
<div
|
||||
class="flex items-start justify-between gap-3"
|
||||
:class="sidebarCollapsed ? 'lg:flex-col lg:items-center' : 'lg:items-center'"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<div class="flex min-w-0 items-center gap-3">
|
||||
<span class="flex h-10 w-10 shrink-0 items-center justify-center border border-sky-200 bg-sky-50 text-sky-800 shadow-[3px_3px_0_0_rgba(14,165,233,0.12)]">
|
||||
<NIcon size="22"><Shield /></NIcon>
|
||||
</span>
|
||||
<span class="min-w-0" :class="sidebarCollapsed ? 'lg:hidden' : ''">
|
||||
<span class="block text-xs font-semibold uppercase tracking-[0.2em] text-sky-700">Admin Console</span>
|
||||
<span class="mt-1 block truncate text-lg font-bold text-slate-950">管理工作台</span>
|
||||
<span
|
||||
class="min-w-0 overflow-hidden whitespace-nowrap transition-[max-width,opacity] duration-200 ease-out"
|
||||
:class="sidebarCollapsed
|
||||
? 'lg:max-w-0 lg:opacity-0'
|
||||
: 'lg:max-w-[168px] lg:opacity-100'"
|
||||
>
|
||||
<span class="block whitespace-nowrap text-xs font-semibold uppercase tracking-[0.2em] text-sky-700">Admin Console</span>
|
||||
<span class="mt-1 block whitespace-nowrap text-lg font-bold text-slate-950">管理工作台</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="hidden h-9 w-9 shrink-0 items-center justify-center border border-slate-200 bg-white text-slate-500 transition-colors hover:border-teal-200 hover:bg-teal-50 hover:text-teal-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-teal-600 lg:flex"
|
||||
:aria-label="sidebarCollapsed ? '展开侧边栏' : '折叠侧边栏'"
|
||||
:aria-expanded="!sidebarCollapsed"
|
||||
:title="sidebarCollapsed ? '展开侧边栏' : '折叠侧边栏'"
|
||||
@click="toggleSidebar"
|
||||
>
|
||||
<NIcon size="20">
|
||||
<LayoutSidebarLeftExpand v-if="sidebarCollapsed" />
|
||||
<LayoutSidebarLeftCollapse v-else />
|
||||
</NIcon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="hidden h-8 w-8 items-center justify-center border border-slate-200 bg-white text-slate-500 shadow-[3px_3px_0_0_rgba(15,23,42,0.06)] transition-colors hover:border-teal-200 hover:bg-teal-50 hover:text-teal-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-teal-600 lg:absolute lg:-right-4 lg:top-6 lg:z-20 lg:flex"
|
||||
:aria-label="sidebarCollapsed ? '展开侧边栏' : '折叠侧边栏'"
|
||||
:aria-expanded="!sidebarCollapsed"
|
||||
:title="sidebarCollapsed ? '展开侧边栏' : '折叠侧边栏'"
|
||||
@click="toggleSidebar"
|
||||
>
|
||||
<NIcon size="18">
|
||||
<LayoutSidebarLeftExpand v-if="sidebarCollapsed" />
|
||||
<LayoutSidebarLeftCollapse v-else />
|
||||
</NIcon>
|
||||
</button>
|
||||
|
||||
<nav aria-label="后台管理分区" class="mt-4 flex gap-2 overflow-x-auto pb-1 lg:mt-7 lg:block lg:space-y-2 lg:overflow-visible lg:pb-0">
|
||||
<button
|
||||
v-for="tab in tabs"
|
||||
:key="tab.key"
|
||||
type="button"
|
||||
class="group relative flex min-w-[150px] items-center gap-3 border px-3 py-3 text-left transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-teal-600 focus-visible:ring-offset-2 lg:w-full lg:min-w-0"
|
||||
:class="[
|
||||
activeTab === tab.key
|
||||
? 'border-teal-200 bg-teal-50 text-teal-900 shadow-[3px_3px_0_0_rgba(20,184,166,0.14)]'
|
||||
: 'border-transparent bg-white text-slate-600 hover:border-slate-200 hover:bg-slate-50 hover:text-slate-950',
|
||||
sidebarCollapsed ? 'lg:justify-center lg:px-0' : '',
|
||||
]"
|
||||
class="group relative flex min-w-[150px] items-center gap-3 overflow-hidden border px-3 py-3 text-left transition-[background-color,border-color,color,box-shadow] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-teal-600 focus-visible:ring-offset-2 lg:w-full lg:min-w-0"
|
||||
:class="activeTab === tab.key
|
||||
? 'border-teal-200 bg-teal-50 text-teal-900 shadow-[3px_3px_0_0_rgba(20,184,166,0.14)]'
|
||||
: 'border-transparent bg-white text-slate-600 hover:border-slate-200 hover:bg-slate-50 hover:text-slate-950'"
|
||||
:aria-current="activeTab === tab.key ? 'page' : undefined"
|
||||
:aria-label="tab.label"
|
||||
:title="sidebarCollapsed ? tab.label : undefined"
|
||||
@@ -549,8 +548,13 @@ onMounted(loadAdminData)
|
||||
<NIcon size="22" class="shrink-0">
|
||||
<component :is="tab.icon" />
|
||||
</NIcon>
|
||||
<span class="min-w-0 flex-1" :class="sidebarCollapsed ? 'lg:hidden' : ''">
|
||||
<span class="block text-sm font-semibold">{{ tab.label }}</span>
|
||||
<span
|
||||
class="min-w-0 flex-1 overflow-hidden whitespace-nowrap transition-[max-width,opacity] duration-200 ease-out"
|
||||
:class="sidebarCollapsed
|
||||
? 'lg:max-w-0 lg:opacity-0'
|
||||
: 'lg:max-w-[190px] lg:opacity-100'"
|
||||
>
|
||||
<span class="block whitespace-nowrap text-sm font-semibold">{{ tab.label }}</span>
|
||||
<span class="mt-0.5 hidden truncate text-xs text-slate-500 lg:block">{{ tab.description }}</span>
|
||||
</span>
|
||||
<span
|
||||
@@ -574,31 +578,35 @@ onMounted(loadAdminData)
|
||||
<template #trigger>
|
||||
<button
|
||||
type="button"
|
||||
class="flex min-h-[46px] min-w-0 flex-1 items-center gap-3 border px-3 py-2 text-left transition-[background-color,border-color,color,box-shadow] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-teal-600 lg:w-full"
|
||||
:class="[
|
||||
accountMenuOpen
|
||||
? 'border-teal-200 bg-teal-50 text-teal-800 shadow-[3px_3px_0_0_rgba(20,184,166,0.12)]'
|
||||
: 'border-slate-200 bg-slate-50 text-slate-700 hover:border-teal-200 hover:bg-teal-50 hover:text-teal-800',
|
||||
sidebarCollapsed ? 'lg:justify-center lg:px-0' : '',
|
||||
]"
|
||||
class="flex h-14 min-w-0 flex-1 items-center gap-3 overflow-hidden border px-3 py-2 text-left transition-[background-color,border-color,color,box-shadow] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-teal-600 lg:w-full"
|
||||
:class="accountMenuOpen
|
||||
? 'border-teal-200 bg-teal-50 text-teal-800 shadow-[3px_3px_0_0_rgba(20,184,166,0.12)]'
|
||||
: 'border-slate-200 bg-slate-50 text-slate-700 hover:border-teal-200 hover:bg-teal-50 hover:text-teal-800'"
|
||||
aria-label="打开管理员账户菜单"
|
||||
aria-haspopup="menu"
|
||||
:aria-expanded="accountMenuOpen"
|
||||
:title="sidebarCollapsed ? displayUsername : undefined"
|
||||
>
|
||||
<NIcon size="22" class="shrink-0"><UserCircle /></NIcon>
|
||||
<span class="min-w-0 flex-1" :class="sidebarCollapsed ? 'lg:hidden' : ''">
|
||||
<span
|
||||
class="min-w-0 flex-1 overflow-hidden whitespace-nowrap transition-[max-width,opacity] duration-200 ease-out"
|
||||
:class="sidebarCollapsed
|
||||
? 'lg:max-w-0 lg:opacity-0'
|
||||
: 'lg:max-w-[145px] lg:opacity-100'"
|
||||
>
|
||||
<span class="block truncate text-sm font-semibold text-slate-900">{{ displayUsername }}</span>
|
||||
<span class="mt-0.5 block text-xs text-slate-500">管理员账户</span>
|
||||
</span>
|
||||
<NIcon
|
||||
v-if="!sidebarCollapsed"
|
||||
size="16"
|
||||
class="shrink-0 transition-transform"
|
||||
:class="accountMenuOpen ? 'rotate-180' : ''"
|
||||
<span
|
||||
class="overflow-hidden transition-[max-width,opacity] duration-200 ease-out"
|
||||
:class="sidebarCollapsed
|
||||
? 'lg:max-w-0 lg:opacity-0'
|
||||
: 'lg:max-w-4 lg:opacity-100'"
|
||||
>
|
||||
<ChevronUp />
|
||||
</NIcon>
|
||||
<NIcon size="16" class="shrink-0 transition-transform" :class="accountMenuOpen ? 'rotate-180' : ''">
|
||||
<ChevronUp />
|
||||
</NIcon>
|
||||
</span>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
@@ -607,10 +615,16 @@ onMounted(loadAdminData)
|
||||
role="menu"
|
||||
aria-label="管理员账户"
|
||||
>
|
||||
<div class="border-b border-slate-200 bg-[linear-gradient(180deg,#f0fdfa_0%,#ffffff_100%)] px-4 py-3">
|
||||
<p class="text-[11px] font-semibold uppercase tracking-[0.18em] text-teal-700">Administrator</p>
|
||||
<p class="mt-2 truncate text-sm font-semibold text-slate-950">@{{ displayUsername }}</p>
|
||||
<p class="mt-1 truncate text-xs text-slate-500">{{ userEmail }}</p>
|
||||
<div class="border-b border-slate-200 bg-[linear-gradient(180deg,#f0fdfa_0%,#ffffff_100%)] px-4 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex h-11 w-11 shrink-0 items-center justify-center border border-teal-200 bg-[linear-gradient(135deg,#ecfeff_0%,#ccfbf1_100%)] text-lg font-bold text-teal-800">
|
||||
{{ displayInitial }}
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
<p class="truncate text-sm font-semibold text-slate-950">@{{ displayUsername }}</p>
|
||||
<p class="mt-1 truncate text-xs text-slate-500">{{ userEmail }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="py-2">
|
||||
@@ -649,12 +663,18 @@ onMounted(loadAdminData)
|
||||
</NPopover>
|
||||
<RouterLink
|
||||
to="/"
|
||||
class="flex h-[46px] shrink-0 items-center justify-center gap-3 border border-slate-200 bg-white px-3 text-sm font-semibold text-slate-700 shadow-[3px_3px_0_0_rgba(15,23,42,0.06)] transition-colors hover:border-sky-200 hover:bg-sky-50 hover:text-sky-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sky-600"
|
||||
:class="sidebarCollapsed ? 'lg:px-0' : 'lg:w-full'"
|
||||
class="flex h-[46px] shrink-0 items-center justify-start gap-3 overflow-hidden border border-slate-200 bg-white px-3 text-sm font-semibold text-slate-700 shadow-[3px_3px_0_0_rgba(15,23,42,0.06)] transition-colors hover:border-sky-200 hover:bg-sky-50 hover:text-sky-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sky-600 lg:w-full"
|
||||
title="返回主页"
|
||||
>
|
||||
<NIcon size="20" class="shrink-0"><Home /></NIcon>
|
||||
<span :class="sidebarCollapsed ? 'lg:hidden' : ''">返回主页</span>
|
||||
<span
|
||||
class="overflow-hidden whitespace-nowrap transition-[max-width,opacity] duration-200 ease-out"
|
||||
:class="sidebarCollapsed
|
||||
? 'lg:max-w-0 lg:opacity-0'
|
||||
: 'lg:max-w-[100px] lg:opacity-100'"
|
||||
>
|
||||
返回主页
|
||||
</span>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
Reference in New Issue
Block a user