모바일 새로고침 시 좌측 사이드바 열림→닫힘 애니메이션 문제 수정
- useMenuState에 menuMounted 추가, 모바일은 항상 닫힘 상태로 시작 - 좌측 사이드바 모바일 오버레이·백드롭을 마운트 이후에만 열리도록 게이팅 - 데스크톱 기본 열림·저장 설정은 그대로 유지 - v1.10.30 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -5,6 +5,10 @@ defineProps({
|
|||||||
menuOpen: {
|
menuOpen: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
menuMounted: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -229,9 +233,14 @@ onMounted(() => {
|
|||||||
<aside
|
<aside
|
||||||
id="menu"
|
id="menu"
|
||||||
class="left-sidebar site-sidebar flex flex-col overflow-hidden border-r border-[var(--site-line)] transition-[width,opacity,transform,border-color] duration-300 ease-out max-lg:fixed max-lg:left-0 max-lg:top-[57px] max-lg:z-[60] max-lg:h-[calc(100dvh-57px)] max-lg:max-h-[calc(100dvh-57px)] max-lg:w-[min(287px,calc(100vw-24px))] max-lg:shadow-[0_16px_48px_rgba(0,0,0,0.18)] lg:sticky lg:top-[57px] lg:z-10 lg:h-[calc(100vh-57px)] lg:max-h-[calc(100vh-57px)] lg:self-start"
|
class="left-sidebar site-sidebar flex flex-col overflow-hidden border-r border-[var(--site-line)] transition-[width,opacity,transform,border-color] duration-300 ease-out max-lg:fixed max-lg:left-0 max-lg:top-[57px] max-lg:z-[60] max-lg:h-[calc(100dvh-57px)] max-lg:max-h-[calc(100dvh-57px)] max-lg:w-[min(287px,calc(100vw-24px))] max-lg:shadow-[0_16px_48px_rgba(0,0,0,0.18)] lg:sticky lg:top-[57px] lg:z-10 lg:h-[calc(100vh-57px)] lg:max-h-[calc(100vh-57px)] lg:self-start"
|
||||||
:class="menuOpen
|
:class="[
|
||||||
? 'max-lg:translate-x-0 max-lg:pointer-events-auto lg:w-[287px] lg:opacity-100'
|
menuOpen
|
||||||
: 'max-lg:-translate-x-full max-lg:pointer-events-none lg:w-0 lg:opacity-0 lg:border-transparent'"
|
? 'lg:w-[287px] lg:opacity-100'
|
||||||
|
: 'lg:w-0 lg:opacity-0 lg:border-transparent',
|
||||||
|
menuOpen && menuMounted
|
||||||
|
? 'max-lg:translate-x-0 max-lg:pointer-events-auto'
|
||||||
|
: 'max-lg:-translate-x-full max-lg:pointer-events-none'
|
||||||
|
]"
|
||||||
>
|
>
|
||||||
<div class="left-sidebar__scroll site-sidebar-scroll min-h-0 flex-1">
|
<div class="left-sidebar__scroll site-sidebar-scroll min-h-0 flex-1">
|
||||||
<div class="left-sidebar__block site-sidebar-section py-3 pl-4 pr-3 sm:pl-5 xl:pl-0">
|
<div class="left-sidebar__block site-sidebar-section py-3 pl-4 pr-3 sm:pl-5 xl:pl-0">
|
||||||
|
|||||||
@@ -6,13 +6,26 @@ const menuStorageKey = 'MENU_STATE'
|
|||||||
*/
|
*/
|
||||||
export const useMenuState = () => {
|
export const useMenuState = () => {
|
||||||
const menuOpen = useState('site-menu-open', () => true)
|
const menuOpen = useState('site-menu-open', () => true)
|
||||||
|
const menuMounted = useState('site-menu-mounted', () => false)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const savedState = localStorage.getItem(menuStorageKey)
|
if (menuMounted.value) {
|
||||||
|
return
|
||||||
if (savedState) {
|
|
||||||
menuOpen.value = savedState === 'open'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isNarrow = window.matchMedia('(max-width: 1023px)').matches
|
||||||
|
|
||||||
|
if (isNarrow) {
|
||||||
|
// 모바일은 항상 닫힌 상태로 시작한다(데스크톱 저장 설정은 보존).
|
||||||
|
menuOpen.value = false
|
||||||
|
} else {
|
||||||
|
const savedState = localStorage.getItem(menuStorageKey)
|
||||||
|
if (savedState) {
|
||||||
|
menuOpen.value = savedState === 'open'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
menuMounted.value = true
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,6 +51,7 @@ export const useMenuState = () => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
menuOpen,
|
menuOpen,
|
||||||
|
menuMounted,
|
||||||
toggleMenu,
|
toggleMenu,
|
||||||
closeMenu
|
closeMenu
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -412,7 +412,7 @@
|
|||||||
| nuxt.config.js | Nuxt 앱 설정, `tailwindcss.cssPath`로 `main.css` 단일 엔트리, Tailwind 모듈, 관리자 QA를 위한 개발 도구 비활성화, 회원 썸네일 최소/최대 해상도·품질 런타임 설정 |
|
| nuxt.config.js | Nuxt 앱 설정, `tailwindcss.cssPath`로 `main.css` 단일 엔트리, Tailwind 모듈, 관리자 QA를 위한 개발 도구 비활성화, 회원 썸네일 최소/최대 해상도·품질 런타임 설정 |
|
||||||
| tailwind.config.js | Tailwind 테마 설정 |
|
| tailwind.config.js | Tailwind 테마 설정 |
|
||||||
| assets/css/main.css | 전역 스타일, 공개 배경·사이드바 배경 통일 기준, 관리자 라이트 테마 격리(`admin-layout`), 좌측 사이드바/그리드 전환 애니메이션, 네비게이션 세로 바 hover 효과 |
|
| assets/css/main.css | 전역 스타일, 공개 배경·사이드바 배경 통일 기준, 관리자 라이트 테마 격리(`admin-layout`), 좌측 사이드바/그리드 전환 애니메이션, 네비게이션 세로 바 hover 효과 |
|
||||||
| composables/useMenuState.js | 좌측 메뉴 열림 상태·`closeMenu`(모바일 백드롭 등) |
|
| composables/useMenuState.js | 좌측 메뉴 열림 상태·`closeMenu`(모바일 백드롭 등), 모바일은 마운트 시 항상 닫힘 시작·`menuMounted`로 첫 페인트 슬라이드 플래시 방지 |
|
||||||
| composables/useThemeMode.js | 사용자 화면 라이트/다크 테마 상태 관리 |
|
| composables/useThemeMode.js | 사용자 화면 라이트/다크 테마 상태 관리 |
|
||||||
| middleware/admin-auth.global.js | 관리자 페이지 접근 인증 |
|
| middleware/admin-auth.global.js | 관리자 페이지 접근 인증 |
|
||||||
| scripts/dev-server.js | 로컬 개발 서버 링크 요약 출력 |
|
| scripts/dev-server.js | 로컬 개발 서버 링크 요약 출력 |
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
# 업데이트 이력
|
# 업데이트 이력
|
||||||
|
|
||||||
|
## v1.10.30
|
||||||
|
|
||||||
|
- 모바일에서 새로고침 시 좌측 사이드바가 열렸다 닫히는 애니메이션 문제 수정.
|
||||||
|
- `useMenuState`에 `menuMounted` 상태 추가, 모바일은 항상 닫힌 상태로 시작(데스크톱 저장 설정은 보존)하도록 수정.
|
||||||
|
- 좌측 사이드바 모바일 슬라이드 오버레이·백드롭이 마운트 이후에만 열리도록 게이팅해 첫 페인트 플래시·슬라이드 재생 제거.
|
||||||
|
|
||||||
## v1.10.29
|
## v1.10.29
|
||||||
|
|
||||||
- 한글 IME 조합 중(`compositionupdate`)에도 검색이 즉시 반영되는 공통 컴포저블 `useImeSearchInput` 추가(NFC 정규화·선택적 디바운스).
|
- 한글 IME 조합 중(`compositionupdate`)에도 검색이 즉시 반영되는 공통 컴포저블 `useImeSearchInput` 추가(NFC 정규화·선택적 디바운스).
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
const { menuOpen, closeMenu } = useMenuState()
|
const { menuOpen, menuMounted, closeMenu } = useMenuState()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 모바일에서 좌측 슬라이드 메뉴가 열려 있을 때 문서 스크롤을 잠근다.
|
* 모바일에서 좌측 슬라이드 메뉴가 열려 있을 때 문서 스크롤을 잠근다.
|
||||||
@@ -40,7 +40,7 @@ onBeforeUnmount(() => {
|
|||||||
leave-to-class="opacity-0"
|
leave-to-class="opacity-0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-show="menuOpen"
|
v-show="menuOpen && menuMounted"
|
||||||
class="public-layout__nav-backdrop fixed inset-x-0 bottom-0 z-40 bg-black/35 backdrop-blur-[2px] lg:hidden"
|
class="public-layout__nav-backdrop fixed inset-x-0 bottom-0 z-40 bg-black/35 backdrop-blur-[2px] lg:hidden"
|
||||||
style="top: var(--site-top-chrome-height, 57px)"
|
style="top: var(--site-top-chrome-height, 57px)"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
@@ -60,7 +60,7 @@ onBeforeUnmount(() => {
|
|||||||
<div class="public-layout__right-column lg:col-start-3 lg:row-start-1 lg:self-stretch lg:border-l lg:border-[var(--site-line)]">
|
<div class="public-layout__right-column lg:col-start-3 lg:row-start-1 lg:self-stretch lg:border-l lg:border-[var(--site-line)]">
|
||||||
<RightSidebar />
|
<RightSidebar />
|
||||||
</div>
|
</div>
|
||||||
<LeftSidebar :menu-open="menuOpen" class="lg:col-start-1 lg:row-start-1" />
|
<LeftSidebar :menu-open="menuOpen" :menu-mounted="menuMounted" class="lg:col-start-1 lg:row-start-1" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
const { menuOpen, closeMenu } = useMenuState()
|
const { menuOpen, menuMounted, closeMenu } = useMenuState()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 모바일에서 좌측 슬라이드 메뉴가 열려 있을 때 문서 스크롤을 잠근다.
|
* 모바일에서 좌측 슬라이드 메뉴가 열려 있을 때 문서 스크롤을 잠근다.
|
||||||
@@ -40,7 +40,7 @@ onBeforeUnmount(() => {
|
|||||||
leave-to-class="opacity-0"
|
leave-to-class="opacity-0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-show="menuOpen"
|
v-show="menuOpen && menuMounted"
|
||||||
class="post-layout__nav-backdrop fixed inset-x-0 bottom-0 z-40 bg-black/35 backdrop-blur-[2px] lg:hidden"
|
class="post-layout__nav-backdrop fixed inset-x-0 bottom-0 z-40 bg-black/35 backdrop-blur-[2px] lg:hidden"
|
||||||
style="top: var(--site-top-chrome-height, 57px)"
|
style="top: var(--site-top-chrome-height, 57px)"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
@@ -60,7 +60,7 @@ onBeforeUnmount(() => {
|
|||||||
<div class="post-layout__right-column lg:col-start-3 lg:row-start-1 lg:self-stretch lg:border-l lg:border-[var(--site-line)]">
|
<div class="post-layout__right-column lg:col-start-3 lg:row-start-1 lg:self-stretch lg:border-l lg:border-[var(--site-line)]">
|
||||||
<RightSidebar />
|
<RightSidebar />
|
||||||
</div>
|
</div>
|
||||||
<LeftSidebar :menu-open="menuOpen" class="lg:col-start-1 lg:row-start-1" />
|
<LeftSidebar :menu-open="menuOpen" :menu-mounted="menuMounted" class="lg:col-start-1 lg:row-start-1" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sori.studio",
|
"name": "sori.studio",
|
||||||
"version": "1.10.29",
|
"version": "1.10.30",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"imports": {
|
"imports": {
|
||||||
|
|||||||
@@ -321,7 +321,7 @@ const goPreviousStep = () => {
|
|||||||
{{ errors.emailOtp }}
|
{{ errors.emailOtp }}
|
||||||
</p>
|
</p>
|
||||||
<p class="text-xs text-[#8c95a3]">
|
<p class="text-xs text-[#8c95a3]">
|
||||||
Resend로 발송됩니다. 메일이 보이지 않으면 스팸함을 확인해 주세요.
|
메일이 보이지 않으면 스팸함을 확인해 주세요.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user