diff --git a/docs/history.md b/docs/history.md index cfb3bee..e54eec0 100644 --- a/docs/history.md +++ b/docs/history.md @@ -1,5 +1,9 @@ # 의사결정 이력 +## 2026-04-03 v1.4.76 +- 프리뷰용 `viewerSidebar__section`은 데스크톱 오른쪽 레일에서 하단 액션 카드처럼 보이게 하려고 `margin-top: auto`를 갖고 있었지만, 모바일 전체 화면 overlay에서는 이 규칙이 카드를 바닥으로 밀어 과도하게 붙은 인상을 만들 수 있다고 판단했다. +- 게다가 `localRightRailRoot`가 최소 높이 100%를 유지한 채 상위 콘텐츠 컨테이너도 flex 남은 높이를 채우면, 하단 footer 영역과 Teleport 콘텐츠의 시각적 쌓임이 어색해질 수 있으므로 모바일 overlay에서는 콘텐츠 컨테이너를 내용 높이 기준으로 풀어 footer가 자연스럽게 아래로 따라오게 정리했다. + ## 2026-04-03 v1.4.75 - 데스크톱/태블릿에서는 오른쪽 레일을 폭이 정해진 서랍 패널처럼 여는 게 맞지만, 모바일에서는 같은 폭 규칙을 유지하면 오히려 “오른쪽에서 덜 열린 반쪽 패널”처럼 보여 하단 공간까지 어색해질 수 있다고 판단했다. - 그래서 모바일 한정으로 오른쪽 레일 overlay를 전체 화면 패널로 바꾸고, 공유/복사 같은 하단 액션이 기기 하단 UI나 safe-area에 붙어 잘리지 않도록 내부 바디 패딩을 더 넉넉하게 두는 쪽으로 정리했다. diff --git a/docs/update.md b/docs/update.md index 6013259..efffe99 100644 --- a/docs/update.md +++ b/docs/update.md @@ -1,5 +1,11 @@ # 업데이트 로그 +## 2026-04-03 v1.4.76 +- 모바일 티어표 프리뷰에서 오른쪽 레일의 `VIEWER MODE` 카드가 패널 바닥에 딱 붙고, 카피라이트 문구가 카드 뒤쪽 중간 높이에 겹쳐 보일 수 있던 배치를 보정했다. +- 모바일 오른쪽 overlay 레일에서는 `rightRail__content`가 남는 높이를 억지로 채우지 않도록 `flex: 0 0 auto`로 풀고, `localRightRailRoot`의 최소 높이도 `auto`로 낮춰 footer와 콘텐츠가 자연스럽게 순서대로 쌓이게 했다. +- 프리뷰 전용 `viewerSidebar__section`의 `margin-top: auto`는 모바일에서만 끄고, 광고 아래에 바로 카드가 이어지도록 조정했다. +- 프런트 프로덕션 빌드(`npm run build`) 통과를 확인했다. + ## 2026-04-03 v1.4.75 - 모바일에서 오른쪽 레일을 열었을 때 패널이 `calc(100vw - 20px)` 폭의 좁은 서랍처럼 떠서 화면 전체를 채우지 못하고, 아래쪽도 어색하게 비어 보이던 부분을 조정했다. - 모바일 오른쪽 레일 overlay는 `inset: 0`, `width: 100vw`, `height: 100dvh`로 화면 전체를 덮는 패널처럼 열리게 바꾸고, 하단 액션/공유 버튼이 바닥에 붙거나 잘려 보이지 않도록 내부 패딩을 `32px + safe-area`까지 늘렸다. diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 8047962..86baaab 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -146,6 +146,7 @@ const showSettingsThemePanel = computed(() => route.name === 'profile') const showTopicViewToggle = computed(() => route.name === 'topicHub') 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) const leftBottomPrimaryAction = computed(() => { if (!authReady.value) return null if (route.name === 'home' && auth.user) { @@ -296,6 +297,11 @@ function toggleTheme() { applyTheme(isLightTheme.value ? 'dark' : 'light') } +function syncRightRailBodyScrollLock(shouldLock) { + if (typeof document === 'undefined') return + document.body.style.overflow = shouldLock ? 'hidden' : '' +} + onMounted(async () => { if (typeof window !== 'undefined') { const savedTheme = window.localStorage.getItem('tier-maker:theme') @@ -338,6 +344,7 @@ onBeforeUnmount(() => { window.removeEventListener('resize', syncViewportWidth) window.removeEventListener('keydown', handleGlobalKeydown) } + syncRightRailBodyScrollLock(false) }) watch( @@ -383,6 +390,14 @@ watch( { immediate: true } ) +watch( + shouldLockRightRailBodyScroll, + (shouldLock) => { + syncRightRailBodyScrollLock(shouldLock) + }, + { immediate: true } +) + function isRouteActive(path) { if (path === '/') return route.path === '/' return route.path.startsWith(path) @@ -2186,6 +2201,15 @@ function reloadApp() { padding: 14px 20px calc(32px + env(safe-area-inset-bottom)); } + .rightRail--overlay .rightRail__content { + flex: 0 0 auto; + overflow: visible; + } + + .rightRail--overlay .localRightRailRoot { + min-height: auto; + } + .collapsedSearchModal { padding: 72px 16px 16px; } diff --git a/frontend/src/views/TierEditorView.vue b/frontend/src/views/TierEditorView.vue index 2036457..ea91875 100644 --- a/frontend/src/views/TierEditorView.vue +++ b/frontend/src/views/TierEditorView.vue @@ -3198,6 +3198,9 @@ onUnmounted(() => { .previewOnly { padding: 14px; } + .viewerSidebar__section { + margin-top: 0; + } .pool { grid-template-columns: repeat(4, minmax(0, 1fr)); }