설정과 모바일 동선 정리

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));
}

View File

@@ -71,7 +71,7 @@ watch(() => route.query.q, loadHomeFeed)
<div class="pageHead__main">
<div class="pageHead__eyebrow">Feed</div>
<h1 class="pageHead__title"></h1>
<div class="pageHead__desc">사용자 공개한 티어표를 최신순으로 살펴보고, 추천 티어표는 상단에서 바로 어요.</div>
<div class="pageHead__desc">다른 사용자들이 공개한 티어표를 살펴 습니다.</div>
<div v-if="query" class="pageHead__searchState">"{{ query }}" 맞는 공개 티어표만 보고 있어요.</div>
</div>
</section>

View File

@@ -80,7 +80,7 @@ function openList(t) {
<div class="pageHead__main">
<div class="pageHead__eyebrow">Tier Lists</div>
<h2 class="pageHead__title">나의 티어표</h2>
<div class="pageHead__desc">직접 저장한 티어표를 같은 카드 레이아웃으로 다시 열고 정리할 있어요.</div>
<div class="pageHead__desc">직접 저장한 티어표를 관리할 있는 페이지입니다.</div>
</div>
</section>

View File

@@ -308,7 +308,7 @@ async function logout() {
<div class="pageHead__main">
<div class="pageHead__eyebrow">Account</div>
<h2 class="pageHead__title">설정</h2>
<div class="pageHead__desc">수시로 바꾸지 않는 정보는 요약해서 보여주고, 필요할 때만 모달로 열어 바꾸는 흐름으로 정리했어.</div>
<div class="pageHead__desc">닉네임은 변경은 쿨타임이 있으니 신중하게 설정해주세.</div>
</div>
</header>
@@ -368,12 +368,10 @@ async function logout() {
</div>
<div class="settingsSummaryItem">
<div class="settingsSummaryItem__label">이메일</div>
<div class="settingsSummaryItem__label">ID (이메일)</div>
<div class="settingsSummaryItem__valueRow">
<div class="settingsSummaryItem__value">{{ authEmail }}</div>
<span class="settingsSummaryItem__status">읽기 전용</span>
</div>
<div class="settingsSummaryItem__meta">현재 로그인에 사용하는 계정 이메일이며, 설정 화면에서는 변경할 없습니다.</div>
</div>
</div>
@@ -381,7 +379,7 @@ async function logout() {
</div>
</article>
<article class="settingsThemeCard">
<article class="settingsThemeCard settingsThemeCard--compact">
<div class="settingsThemeCard__eyebrow">Security</div>
<div class="settingsThemeCard__title">보안 설정</div>
<div class="settingsCompactRow">
@@ -395,7 +393,7 @@ async function logout() {
</div>
</article>
<article class="settingsThemeCard">
<article class="settingsThemeCard settingsThemeCard--compact">
<div class="settingsThemeCard__eyebrow">Session</div>
<div class="settingsThemeCard__title">계정 상태</div>
<div class="settingsCompactList">
@@ -537,6 +535,10 @@ async function logout() {
grid-column: 1 / -1;
}
.settingsThemeCard--compact {
grid-template-rows: auto auto minmax(0, 1fr);
}
.settingsThemeCard__eyebrow {
font-size: 11px;
letter-spacing: 0.12em;
@@ -691,17 +693,6 @@ async function logout() {
line-height: 1.6;
}
.settingsSummaryItem__status {
flex-shrink: 0;
padding: 6px 10px;
border-radius: 999px;
border: 1px solid var(--theme-border);
background: var(--theme-pill-bg);
color: var(--theme-text-soft);
font-size: 12px;
font-weight: 700;
}
.settingsActionRow {
display: flex;
flex-wrap: wrap;
@@ -712,6 +703,7 @@ async function logout() {
.settingsCompactList {
display: grid;
gap: 10px;
height: 100%;
}
.settingsCompactRow {
@@ -719,6 +711,7 @@ async function logout() {
justify-content: space-between;
gap: 16px;
align-items: center;
min-height: 100%;
padding: 16px 18px;
border-radius: 18px;
border: 1px solid var(--theme-border);

View File

@@ -83,7 +83,7 @@ function templateThumbUrl(template) {
<div class="pageHead__main">
<div class="pageHead__eyebrow">Topic</div>
<h1 class="pageHead__title">템플릿</h1>
<p class="pageHead__desc">자주 쓰는 주제 템플릿을 빠르게 고르고, 필요하면 바로 커스텀 티어표를 시작할 어요.</p>
<p class="pageHead__desc">미리 설정된 템플릿을 이용하여 쉽고 빠르게 만들 습니다.</p>
<p v-if="query" class="pageHead__searchState">"{{ query }}" 맞는 주제 템플릿만 보고 있어요.</p>
</div>
</section>

View File

@@ -367,11 +367,6 @@ function closeItemContextMenu() {
}
}
function scrollWorkspaceBodyToTop() {
const workspaceBody = document.querySelector('.workspaceBody')
workspaceBody?.scrollIntoView({ behavior: 'smooth', block: 'start' })
}
function updateEditorSidebarMaxHeight() {
if (typeof window === 'undefined' || !sidebarEl.value) return
const bottomGap = 14
@@ -1104,6 +1099,11 @@ function confirmNavigationDiscard() {
router.push(nextPath)
}
function openTemplateTopic() {
if (!templateId.value) return
requestEditorNavigation(topicPath(templateId.value))
}
function openSourceTierList() {
if (!sourceTierListId.value) return
requestEditorNavigation(editorPath(templateId.value, sourceTierListId.value))
@@ -1535,7 +1535,7 @@ onUnmounted(() => {
<div v-if="isNavigationConfirmModalOpen" class="modalOverlay" @click.self="closeNavigationConfirmModal">
<div class="modalCard" role="dialog" aria-modal="true" aria-labelledby="navigationConfirmTitle">
<div id="navigationConfirmTitle" class="modalCard__title">원본 티어표 이동</div>
<div id="navigationConfirmTitle" class="modalCard__title">다른 화면으 이동</div>
<div class="modalCard__desc">
아직 저장하지 않은 수정 내용이 있어요. 이대로 이동하면 현재 변경 내용은 사라집니다.
</div>
@@ -1656,9 +1656,9 @@ onUnmounted(() => {
<button
class="editorMain__title editorMain__titleButton"
type="button"
title="본문을 화면로 이동"
@click="scrollWorkspaceBodyToTop"
@keydown.space.prevent="scrollWorkspaceBodyToTop"
title="이 템플릿 화면로 이동"
@click="openTemplateTopic"
@keydown.space.prevent="openTemplateTopic"
>
{{ templateName || templateId }}
</button>