사이드바 메뉴 토글 추가

This commit is contained in:
2026-04-29 15:08:04 +09:00
parent a3acd9320a
commit cbf5ed6c8c
13 changed files with 122 additions and 11 deletions

View File

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

View File

@@ -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">

View 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
}
}

View File

@@ -1,5 +1,11 @@
# 업데이트 요약
## v0.0.4
- 헤더 좌측 아이콘을 사이드바 메뉴 토글 버튼으로 수정.
- 좌측 사이드바 열림 상태를 저장하고 복원하는 기능 추가.
- Nuxt/Vue 방식으로 원본 테마의 Alpine식 메뉴 토글 동작을 구현.
## v0.0.3
- 공개 화면의 라이트/다크 색상 토큰을 추가.

View File

@@ -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
### 공개 화면 테마와 패널 구조 보정

View File

@@ -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 컨테이너 실행 초안 |

View File

@@ -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
- 첫 커밋 이후 변경사항을 커밋할 때마다 패치 버전 증가
- 메이저/마이너 버전은 구조 변경 또는 기능 묶음 단위로 결정

View File

@@ -28,6 +28,7 @@
- [ ] 공개 화면 모바일 사이드바/네비게이션 방식 결정
- [ ] Thred 참고 화면 기준 시각 QA
- [ ] 사이드바 토글 애니메이션 세부 조정
- [ ] 게시물 카드 실제 데이터 연동
- [ ] 태그 페이지 실제 데이터 연동
- [ ] 고정 페이지 실제 데이터 연동

View File

@@ -1,5 +1,12 @@
# 업데이트 이력
## v0.0.4
- 헤더 좌측 아이콘을 브랜드 마크에서 메뉴 토글 버튼으로 수정.
- Vue/Nuxt 상태 기반 좌측 사이드바 열기/닫기 기능 추가.
- 메뉴 열림 상태를 `localStorage``MENU_STATE`에 저장하도록 추가.
- 메뉴 닫힘 상태에서 공개 레이아웃 그리드가 좌측 사이드바 폭을 제거하도록 수정.
## v0.0.3
- Thred 참고 화면 기준 공개 레이아웃 색상 토큰 정리.

View File

@@ -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 />

View File

@@ -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
View File

@@ -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",

View File

@@ -1,6 +1,6 @@
{
"name": "sori.studio",
"version": "0.0.3",
"version": "0.0.4",
"private": true,
"type": "module",
"scripts": {