설정과 모바일 동선 정리

This commit is contained in:
2026-04-07 16:19:01 +09:00
parent 3163a671de
commit 76de4b940a
13 changed files with 91 additions and 75 deletions

View File

@@ -166,7 +166,7 @@ const isGuideNextDisabled = computed(() => guideStepIndex.value >= guideSteps.le
const isLightTheme = computed(() => themeMode.value === 'light')
const themeToggleLabel = computed(() => (isLightTheme.value ? '다크 모드' : '라이트 모드'))
const showSettingsThemePanel = computed(() => route.name === 'profile')
const showTopicViewToggle = computed(() => ['home', 'templates', 'topicHub', 'me', 'favorites', 'followingFeed'].includes(String(route.name || '')))
const showTopicViewToggle = computed(() => !isMobileLayout.value && ['home', 'templates', 'topicHub', 'me', 'favorites', 'followingFeed'].includes(String(route.name || '')))
const topicViewMode = computed(() => (route.query.view === 'list' ? 'list' : 'grid'))
const showBackendFallback = computed(() => !isPreviewMode.value && ['maintenance', 'offline'].includes(backendState.value))
const shouldLockRightRailBodyScroll = computed(() => isRightRailOverlay.value && rightRailOpen.value && !showBackendFallback.value)
@@ -692,9 +692,11 @@ function reloadApp() {
</main>
</template>
<template v-else>
<aside class="leftRail">
<button v-if="isMobileLayout && mobileLeftNavOpen" class="leftRailBackdrop" type="button" aria-label="왼쪽 패널 닫기" @click="toggleLeftRail"></button>
<aside class="leftRail" :class="{ 'leftRail--overlay': isMobileLayout }" :aria-hidden="isMobileLayout && !mobileLeftNavOpen">
<div class="leftRail__top railHeader">
<button v-if="!isMobileLayout" class="ghostIcon ghostIcon--iconOnly" type="button" aria-label="왼쪽 패널 토글" @click="toggleLeftRail">
<button class="ghostIcon ghostIcon--iconOnly" type="button" :aria-label="isMobileLayout ? '왼쪽 패널 닫기' : '왼쪽 패널 토글'" @click="toggleLeftRail">
<SvgIcon :src="iconDockToRight" :size="24" />
</button>
</div>
@@ -709,16 +711,6 @@ function reloadApp() {
<div class="appUserCard__name">{{ accountName }}</div>
<div class="appUserCard__email" :class="{ 'appUserCard__email--hint': isAccountEmailHint }">{{ accountEmail }}</div>
</div>
<button
v-if="isMobileLayout"
class="appUserCard__navToggle"
type="button"
:aria-label="mobileLeftNavOpen ? '네비게이션 메뉴 닫기' : '네비게이션 메뉴 열기'"
:aria-expanded="mobileLeftNavOpen"
@click="toggleLeftRail"
>
<SvgIcon :src="mobileLeftNavOpen ? iconDockToLeft : iconDockToRight" :size="24" />
</button>
</div>
</div>
@@ -794,9 +786,15 @@ function reloadApp() {
<SvgIcon :src="iconLists" :size="24" />
</button>
</div>
<button v-if="isMobileLayout" class="ghostIcon ghostIcon--iconOnly" type="button" aria-label="왼쪽 패널 열기" @click="toggleLeftRail">
<SvgIcon :src="iconDockToRight" :size="24" />
</button>
<button v-if="!rightRailOpen" class="ghostIcon ghostIcon--iconOnly" type="button" aria-label="패널 열기" @click="toggleRightRail">
<SvgIcon :src="iconDockToLeft" :size="24" />
</button>
<button v-else-if="isMobileLayout" class="ghostIcon ghostIcon--iconOnly" type="button" aria-label="오른쪽 패널 닫기" @click="toggleRightRail">
<SvgIcon :src="iconDockToLeft" :size="24" />
</button>
</div>
</header>
<div class="workspaceBody" :class="{ 'workspaceBody--localRail': usesLocalRightRail }">
@@ -2151,10 +2149,10 @@ function reloadApp() {
grid-template-columns: var(--left-rail-width, 248px) minmax(0, 1fr);
}
.rightRailBackdrop {
position: fixed;
inset: 0;
display: block;
.rightRailBackdrop {
position: fixed;
inset: 0;
display: block;
border: 0;
background: rgba(0, 0, 0, 0.4);
z-index: 29;
@@ -2263,19 +2261,49 @@ function reloadApp() {
}
.leftRail {
min-height: auto;
height: auto;
min-height: 100dvh;
border-right: 0;
border-bottom: 1px solid var(--theme-border);
border-bottom: 0;
}
.leftRailBackdrop {
position: fixed;
inset: 0;
display: block;
border: 0;
background: rgba(0, 0, 0, 0.4);
z-index: 29;
}
.leftRail--overlay {
position: fixed;
top: 0;
left: 0;
width: min(340px, calc(100vw - 20px));
height: 100dvh;
z-index: 30;
background: var(--theme-shell-bg);
border-right: 1px solid var(--theme-border);
box-shadow: 18px 0 36px rgba(0, 0, 0, 0.34);
transition:
transform 220ms ease,
opacity 220ms ease;
}
.appShell--mobileNavClosed .leftRail--overlay {
transform: translateX(calc(-100% - 24px));
opacity: 0;
pointer-events: none;
}
.leftRail__top {
display: none;
display: flex;
justify-content: flex-end;
}
.leftRail__body {
max-height: none;
padding: 12px 14px;
padding: 12px 14px calc(18px + env(safe-area-inset-bottom));
}
.appUserCard {
@@ -2290,10 +2318,6 @@ function reloadApp() {
max-width: none;
}
.appUserCard__navToggle {
display: inline-flex;
}
.workspaceHead .ghostIcon--iconOnly,
.rightRail__top .ghostIcon--iconOnly {
width: 42px;
@@ -2392,18 +2416,6 @@ function reloadApp() {
margin: 14px 14px 0;
}
.appShell--mobileNavClosed .leftRail__mobileMenu {
max-height: 0;
margin-top: -8px;
opacity: 0;
transform: translateY(-8px);
pointer-events: none;
}
.appShell--mobileNavClosed .leftRail__bottom {
display: none;
}
.rightRail--overlay .rightRail__body {
padding: 14px 20px calc(32px + env(safe-area-inset-bottom));
}