사이드바 메뉴 토글 추가
This commit is contained in:
@@ -61,6 +61,11 @@
|
||||
background: var(--site-bg);
|
||||
}
|
||||
|
||||
.site-content-grid--menu-closed {
|
||||
@apply lg:grid-cols-[minmax(0,720px)_287px];
|
||||
max-width: 1007px;
|
||||
}
|
||||
|
||||
.site-section {
|
||||
border-bottom: 1px solid var(--site-line);
|
||||
background: var(--site-bg);
|
||||
@@ -93,6 +98,10 @@
|
||||
background: var(--site-bg);
|
||||
}
|
||||
|
||||
.site-main--menu-closed {
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
.site-sidebar {
|
||||
min-height: calc(100vh - 57px);
|
||||
background: var(--site-panel);
|
||||
|
||||
@@ -1,8 +1,41 @@
|
||||
<script setup>
|
||||
const { menuOpen, toggleMenu } = useMenuState()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header class="site-header sticky top-0 z-20 backdrop-blur">
|
||||
<div class="site-header__inner mx-auto flex h-full max-w-[1294px] items-center justify-between px-4 lg:px-0">
|
||||
<NuxtLink class="site-header__brand flex items-center gap-2 text-[18px] font-semibold tracking-normal" to="/">
|
||||
<span class="site-header__brand-mark inline-block h-5 w-4 rounded-sm bg-[var(--site-text)]" />
|
||||
<button
|
||||
class="site-header__menu-toggle group flex h-7 w-7 items-center justify-center rounded-full transition-transform"
|
||||
type="button"
|
||||
data-menu-toggle
|
||||
aria-label="Menu toggle"
|
||||
aria-haspopup="true"
|
||||
aria-controls="menu"
|
||||
:aria-expanded="menuOpen.toString()"
|
||||
@click.prevent="toggleMenu"
|
||||
>
|
||||
<span v-if="menuOpen" class="site-header__menu-icon pointer-events-none">
|
||||
<svg class="block h-6 w-6 group-hover:hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
||||
<path d="M6 21a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h12a3 3 0 0 1 3 3v12a3 3 0 0 1-3 3H6Zm12-16h-8v14h8a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1Z" />
|
||||
</svg>
|
||||
<svg class="hidden h-6 w-6 group-hover:block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
||||
<path d="M18 3a3 3 0 0 1 3 3v12a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h12Zm0 2h-9v14h9a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1Zm-2.3 4.3a1 1 0 0 1 0 1.4L14.4 12l1.3 1.3a1 1 0 0 1-1.4 1.4l-2-2a1 1 0 0 1 0-1.4l2-2a1 1 0 0 1 1.4 0Z" />
|
||||
</svg>
|
||||
</span>
|
||||
<span v-else class="site-header__menu-icon pointer-events-none">
|
||||
<svg class="block h-6 w-6 group-hover:hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<path d="M4 6a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6Z" />
|
||||
<path d="M9 4v16" />
|
||||
</svg>
|
||||
<svg class="hidden h-6 w-6 group-hover:block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<path d="M4 6a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6Z" />
|
||||
<path d="M9 4v16" />
|
||||
<path d="m14 10 2 2-2 2" />
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
sori.studio
|
||||
</NuxtLink>
|
||||
<div class="site-header__search hidden h-9 w-[470px] items-center rounded-lg px-3 text-sm md:flex site-input">
|
||||
|
||||
31
composables/useMenuState.js
Normal file
31
composables/useMenuState.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const menuStorageKey = 'MENU_STATE'
|
||||
|
||||
/**
|
||||
* 좌측 메뉴 열림 상태 관리
|
||||
* @returns {{menuOpen: import('vue').Ref<boolean>, toggleMenu: Function}} 메뉴 상태와 토글 함수
|
||||
*/
|
||||
export const useMenuState = () => {
|
||||
const menuOpen = useState('site-menu-open', () => true)
|
||||
|
||||
onMounted(() => {
|
||||
const savedState = localStorage.getItem(menuStorageKey)
|
||||
|
||||
if (savedState) {
|
||||
menuOpen.value = savedState === 'open'
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 좌측 메뉴 열림 상태 토글
|
||||
* @returns {void}
|
||||
*/
|
||||
const toggleMenu = () => {
|
||||
menuOpen.value = !menuOpen.value
|
||||
localStorage.setItem(menuStorageKey, menuOpen.value ? 'open' : 'closed')
|
||||
}
|
||||
|
||||
return {
|
||||
menuOpen,
|
||||
toggleMenu
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
# 업데이트 요약
|
||||
|
||||
## v0.0.4
|
||||
|
||||
- 헤더 좌측 아이콘을 사이드바 메뉴 토글 버튼으로 수정.
|
||||
- 좌측 사이드바 열림 상태를 저장하고 복원하는 기능 추가.
|
||||
- Nuxt/Vue 방식으로 원본 테마의 Alpine식 메뉴 토글 동작을 구현.
|
||||
|
||||
## v0.0.3
|
||||
|
||||
- 공개 화면의 라이트/다크 색상 토큰을 추가.
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# 의사결정 이력
|
||||
|
||||
## 2026-04-29 v0.0.4
|
||||
|
||||
### 메뉴 토글 구현 방식 결정
|
||||
|
||||
원본 Ghost 테마는 Alpine 스타일의 `@click`, `:class`, `:aria-expanded` 바인딩으로 좌측 메뉴 상태를 제어한다. 이 프로젝트는 Nuxt/Vue 기반이므로 Alpine을 추가하지 않고 Vue 상태와 composable로 같은 기능을 구현한다.
|
||||
|
||||
메뉴 상태는 `useMenuState`에서 공유하고, 브라우저 `localStorage`의 `MENU_STATE`에 저장한다. 이렇게 하면 헤더 버튼, 공개 레이아웃, 게시물 레이아웃이 같은 상태를 사용하면서도 별도 프론트엔드 상태 라이브러리나 Alpine 의존성을 추가하지 않아도 된다.
|
||||
|
||||
## 2026-04-29 v0.0.3
|
||||
|
||||
### 공개 화면 테마와 패널 구조 보정
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
| nuxt.config.js | Nuxt 앱 설정 |
|
||||
| tailwind.config.js | Tailwind 테마 설정 |
|
||||
| assets/css/main.css | 전역 스타일 |
|
||||
| composables/useMenuState.js | 좌측 메뉴 열림 상태 관리 |
|
||||
| .env.example | 환경 변수 예시 |
|
||||
| Dockerfile | NAS 운영 이미지 빌드 |
|
||||
| docker-compose.yml | NAS 컨테이너 실행 초안 |
|
||||
|
||||
@@ -22,6 +22,13 @@
|
||||
| Main | 너비 720px, 패딩 32px 24px (헤더), 16px 24px (섹션) |
|
||||
| Right Aside | 너비 287px, 최소 높이 calc(100vh - 57px), 패딩 20px 0 20px 20px |
|
||||
|
||||
### 메뉴 토글
|
||||
|
||||
- 헤더 좌측 아이콘은 브랜드 마크가 아니라 왼쪽 사이드바 열기/닫기 버튼
|
||||
- 메뉴 상태는 Nuxt/Vue 상태로 관리
|
||||
- 브라우저에서는 `localStorage.MENU_STATE`에 `open` 또는 `closed` 저장
|
||||
- 닫힘 상태에서는 왼쪽 사이드바를 숨기고 중앙/오른쪽 컬럼만 표시
|
||||
|
||||
### 공개 화면 색상
|
||||
|
||||
- 라이트/다크 모드는 CSS 변수로 관리
|
||||
@@ -235,6 +242,6 @@ APP_PORT=43118
|
||||
|
||||
## 버전 관리
|
||||
|
||||
- 현재 버전: v0.0.3
|
||||
- 현재 버전: v0.0.4
|
||||
- 첫 커밋 이후 변경사항을 커밋할 때마다 패치 버전 증가
|
||||
- 메이저/마이너 버전은 구조 변경 또는 기능 묶음 단위로 결정
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
- [ ] 공개 화면 모바일 사이드바/네비게이션 방식 결정
|
||||
- [ ] Thred 참고 화면 기준 시각 QA
|
||||
- [ ] 사이드바 토글 애니메이션 세부 조정
|
||||
- [ ] 게시물 카드 실제 데이터 연동
|
||||
- [ ] 태그 페이지 실제 데이터 연동
|
||||
- [ ] 고정 페이지 실제 데이터 연동
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# 업데이트 이력
|
||||
|
||||
## v0.0.4
|
||||
|
||||
- 헤더 좌측 아이콘을 브랜드 마크에서 메뉴 토글 버튼으로 수정.
|
||||
- Vue/Nuxt 상태 기반 좌측 사이드바 열기/닫기 기능 추가.
|
||||
- 메뉴 열림 상태를 `localStorage`의 `MENU_STATE`에 저장하도록 추가.
|
||||
- 메뉴 닫힘 상태에서 공개 레이아웃 그리드가 좌측 사이드바 폭을 제거하도록 수정.
|
||||
|
||||
## v0.0.3
|
||||
|
||||
- Thred 참고 화면 기준 공개 레이아웃 색상 토큰 정리.
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
<script setup>
|
||||
const { menuOpen } = useMenuState()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="site-shell public-layout">
|
||||
<SiteHeader />
|
||||
<div class="site-content-grid public-layout__grid">
|
||||
<LeftSidebar />
|
||||
<main class="site-main w-full lg:w-[720px]">
|
||||
<div class="site-content-grid public-layout__grid" :class="{ 'site-content-grid--menu-closed': !menuOpen }">
|
||||
<LeftSidebar v-show="menuOpen" />
|
||||
<main class="site-main w-full lg:w-[720px]" :class="{ 'site-main--menu-closed': !menuOpen }">
|
||||
<slot />
|
||||
</main>
|
||||
<RightSidebar />
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
<script setup>
|
||||
const { menuOpen } = useMenuState()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="site-shell post-layout">
|
||||
<SiteHeader />
|
||||
<div class="site-content-grid post-layout__grid">
|
||||
<LeftSidebar />
|
||||
<main class="site-main post-main w-full px-5 py-8 lg:w-[720px]">
|
||||
<div class="site-content-grid post-layout__grid" :class="{ 'site-content-grid--menu-closed': !menuOpen }">
|
||||
<LeftSidebar v-show="menuOpen" />
|
||||
<main class="site-main post-main w-full px-5 py-8 lg:w-[720px]" :class="{ 'site-main--menu-closed': !menuOpen }">
|
||||
<slot />
|
||||
</main>
|
||||
<RightSidebar />
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "sori.studio",
|
||||
"version": "0.0.3",
|
||||
"version": "0.0.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "sori.studio",
|
||||
"version": "0.0.3",
|
||||
"version": "0.0.4",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@nuxtjs/tailwindcss": "^6.14.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sori.studio",
|
||||
"version": "0.0.3",
|
||||
"version": "0.0.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
Reference in New Issue
Block a user