diff --git a/docs/history.md b/docs/history.md index f8ea1c7..dbbc34d 100644 --- a/docs/history.md +++ b/docs/history.md @@ -1,5 +1,10 @@ # 의사결정 이력 +## 2026-03-30 v1.2.22 +- 왼쪽 레일은 홈/목록/에디터 어디서든 “사라지는 패널”보다 “축소된 내비 레일”로 읽히는 편이 구조적으로 더 일관되므로, 완전 숨김 대신 아이콘 중심 축소 상태를 유지하기로 했다. +- 좌우 패널 토글은 상태마다 다른 아이콘이 바뀌기보다 방향만 고정하는 편이 덜 혼란스러우므로, 우측은 `dock_to_left`, 좌측은 `dock_to_right` 하나로 통일하기로 정리했다. +- 좌측 검색도 임시 선형 SVG보다 실제 에셋을 쓰는 편이 전체 레일 완성도가 높으므로, 사용자가 추가한 `search.svg`를 우선 적용하기로 했다. + ## 2026-03-30 v1.2.21 - 티어표 목록 카드는 페이지마다 다른 메타 구성을 두기보다, `제목+좋아요 / 작성자+최종 수정일` 두 줄 문법으로 통일하는 편이 시안과 사용성 모두에 더 맞다고 정리했다. - `내 즐겨찾기` 화면에서 “즐겨찾기한 날짜”는 컬렉션 내부 정보일 뿐 카드 핵심 정보는 아니므로, 정렬은 유지하되 카드에는 마지막 수정일만 보여주는 편이 더 읽기 쉽다고 판단했다. diff --git a/docs/map.md b/docs/map.md index a872806..daa609f 100644 --- a/docs/map.md +++ b/docs/map.md @@ -48,7 +48,7 @@ ## 공통 레이아웃 - 앱 셸 파일: `frontend/src/App.vue` - 역할: 좌측 내비게이션, 중앙 워크스페이스, 우측 컨텍스트 패널로 구성된 공통 앱 셸 렌더링, 로그인 상태 반영, 최근 즐겨찾기 바로가기와 전역 검색 입력, 관리자 메뉴 노출 제어, 실제 SVG 에셋과 선형 SVG 아이콘이 혼합된 레일 UI, 전역 우측 상단 토스트 렌더링 -- 세부: 좌측 패널은 `248px`, 우측 패널은 `320px` 기준 폭을 사용하며, 세 컬럼 모두 상단에 높이 `56px`의 헤더 블록을 유지한다. 중앙 헤더에는 고정 브랜드 `Tier Maker by zenn`이 표시되고, 우측 패널 토글은 닫혀 있을 때 중앙 헤더, 열려 있을 때 우측 헤더에 아이콘만 표시된다. +- 세부: 좌측 패널은 `248px` 기준 폭을 사용하되 축소 시 아이콘 중심의 좁은 레일로 전환하고, 우측 패널은 `320px` 기준 폭을 사용한다. 세 컬럼 모두 상단에 높이 `56px`의 헤더 블록을 유지한다. 중앙 헤더에는 고정 브랜드 `Tier Maker by zenn`이 표시되고, 우측 패널 토글은 닫혀 있을 때 중앙 헤더, 열려 있을 때 우측 헤더에 아이콘만 표시된다. ## 백엔드 진입점 - 서버 엔트리: `backend/index.js` diff --git a/docs/spec.md b/docs/spec.md index cbcb8a9..7d3c2f3 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -11,6 +11,7 @@ - 프런트 파비콘은 운영 정적 파일 차단 영향을 줄이기 위해 `index.html`의 인라인 데이터 URL로 제공한다. - 프런트 앱 셸은 `좌측 내비게이션 / 중앙 워크스페이스 / 우측 컨텍스트 패널` 3단 구조로 재정의되었고, preview 모드에서는 이 셸을 숨기고 콘텐츠만 렌더링한다. - 좌측 패널은 `248px`, 우측 패널은 `320px` 기준 폭을 사용하며, 우측 패널은 상단 토글 버튼으로 접고 펼칠 수 있다. +- 좌측 패널은 필요 시 축소형 레일로 접을 수 있으며, 접힌 상태에서는 아이콘 중심 내비게이션과 축약된 바로가기만 유지한다. - 이 3단 셸 구조는 홈, 게임 허브, 에디터, 관리자 등 일반 페이지 전반의 공통 뼈대로 유지하고, 페이지별 차이는 중앙/우측에 어떤 콘텐츠를 넣는지만 달라지도록 관리한다. - 비로그인 상태의 로그인 유도는 좌측 하단 버튼으로만 노출하고, 좌측 상단 사용자 카드 영역에는 별도 게스트 안내 카드를 렌더링하지 않는다. - 공통 셸의 좌측 내비, 우측 패널, 빠른 점프 버튼은 간단한 선형 SVG 아이콘과 두꺼운 카드형 버튼 문법을 공유한다. @@ -27,6 +28,7 @@ ## 화면 구조 - 좌측 패널 - 사용자 요약, 전체 공개 티어표 검색 입력, 주요 라우트 내비게이션, 최근 즐겨찾기 티어표 바로가기, 관리자 진입 버튼을 배치한다. + - 상단 토글 버튼은 항상 고정되어 있고, 패널을 축소하면 텍스트를 숨기고 아이콘 중심 레일로 전환한다. - `Settings`는 별도 메뉴 항목으로만 진입하며, 사용자 카드 자체는 정보 표시 용도로만 사용한다. - 사용자 아바타는 원형 보더 스타일을 유지하고, `Favorites` 영역은 최근 즐겨찾기 티어표 최대 10개를 메인 메뉴보다 작은 밀도의 바로가기 목록으로 보여준 뒤 하단 `즐겨찾기 더 보기` 링크로 전체 즐겨찾기 화면에 연결한다. - 중앙 워크스페이스 @@ -38,6 +40,7 @@ - 현재 화면 문맥에 맞는 설명, 빠른 액션, 계정 상태 같은 보조 정보를 배치한다. - 에디터/관리자 세부 옵션은 후속 단계에서 이 패널로 점진 이관한다. - 공통 토글 버튼은 패널이 닫혀 있을 때 중앙 헤더, 열려 있을 때 우측 헤더에 각각 아이콘만 표시하는 방식으로 동작한다. + - 오른쪽 패널 토글은 열기/닫기 모두 `dock_to_left`, 왼쪽 패널 토글은 `dock_to_right` 아이콘으로 통일한다. - 홈 화면 기준 우측 패널은 임시 정보 카드 여러 개보다 핵심 CTA 하나만 남겨, 시안처럼 단순한 보조 레일 역할을 우선 유지한다. - 티어표 편집 화면 - 공통 우측 패널 대신 전용 로컬 편집 패널을 사용한다. diff --git a/docs/todo.md b/docs/todo.md index c472869..1385d9e 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -14,6 +14,7 @@ - 에디터 우측 패널 외곽 래퍼는 제거했으므로, 다음 단계는 공통 오른쪽 컬럼 안에서 입력/버튼/구분선 간격을 시안처럼 더 정교하게 다듬는 작업이다. - 공통 56px 셸 헤더는 반영했으므로, 다음 단계는 좌/중앙/우 헤더 안에 실제 아이콘/상태 요소를 시안 순서에 맞게 하나씩 채워 넣는 작업이다. - 좌측 레일은 최근 즐겨찾기와 전역 검색까지 붙었으므로, 다음 단계는 검색 자동완성이나 즐겨찾기 썸네일 품질 같은 디테일을 더 다듬는 작업이다. +- 좌측 레일 축소형은 반영했으므로, 다음 단계는 축소 상태에서 관리자/로그인 진입점과 hover 툴팁 같은 보조 UX를 더 다듬는 작업이다. - 카드 목록은 4열 기준과 메타 줄 구성까지 통일했으므로, 다음 단계는 필터 상태 배지나 hover·selection 강조 같은 상호작용 디테일을 더 다듬는 작업이다. - 검색 결과 화면은 좌측 전역 검색 입력만 쓰도록 정리됐으므로, 다음 단계는 결과 필터/정렬 여부를 검토하는 식으로 확장하면 된다. - 공통 3단 셸 구조는 고정했지만, 관리자/에디터 우측 패널 내부에 아직 바디에 남아 있는 제어 요소를 더 옮겨야 한다. diff --git a/docs/update.md b/docs/update.md index ddf5b1b..654fca7 100644 --- a/docs/update.md +++ b/docs/update.md @@ -1,5 +1,10 @@ # 업데이트 로그 +## 2026-03-30 v1.2.22 +- **왼쪽 사이드 축소/확대 추가**: 좌측 레일을 완전히 숨기지 않고 축소형 내비로 접었다 펼 수 있게 바꾸고, 접힌 상태에서는 아이콘 중심으로만 보이도록 레이아웃을 정리 +- **좌우 패널 토글 아이콘 통일**: 오른쪽 패널 열기/닫기는 모두 `dock_to_left`, 왼쪽 패널 토글은 `dock_to_right` 아이콘만 사용하도록 통일 +- **전역 검색 아이콘 교체**: 좌측 전역 검색 입력에 사용자가 추가한 `search.svg`를 실제 아이콘으로 연결 + ## 2026-03-30 v1.2.21 - **티어표 카드 문법 통일**: 게임 허브, 검색 결과, 내 티어표, 즐겨찾기 목록의 카드 레이아웃을 `상단 썸네일 / 제목+좋아요 / 작성자+최종 수정일` 2줄 메타 구조로 통일하고, 데스크톱 기준 한 줄 4개 카드가 보이도록 재배치 - **즐겨찾기 화면 날짜 기준 단순화**: `내 즐겨찾기` 화면은 더 이상 즐겨찾기한 시각을 표시하지 않고, 정렬 기준과 무관하게 덱의 마지막 수정일만 카드에 노출하도록 정리 diff --git a/frontend/src/App.vue b/frontend/src/App.vue index ed0cb7e..54b99d3 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -10,6 +10,7 @@ import iconDockToRight from './assets/icons/dock_to_right.svg' import iconGridView from './assets/icons/grid_view.svg' import iconLists from './assets/icons/lists.svg' import iconMore from './assets/icons/more.svg' +import iconSearch from './assets/icons/search.svg' import iconSettings from './assets/icons/settings.svg' const route = useRoute() @@ -17,6 +18,7 @@ const router = useRouter() const auth = useAuthStore() const { toasts, dismissToast } = useToast() +const leftRailCollapsed = ref(false) const rightRailOpen = ref(true) const searchQuery = ref('') const favoriteShortcuts = ref([]) @@ -35,6 +37,10 @@ const accountName = computed(() => { return 'Guest' }) const accountEmail = computed(() => (auth.user?.email || '').trim() || '로그인 후 개인 메뉴를 사용할 수 있어요.') +const shellStyle = computed(() => ({ + '--left-rail-width': leftRailCollapsed.value ? '76px' : '248px', + '--right-rail-width': rightRailOpen.value ? '320px' : '0px', +})) const leftNavItems = computed(() => { const items = [ { key: 'home', label: 'Games', path: '/', iconSrc: iconGridView }, @@ -139,16 +145,12 @@ const routeMeta = computed(() => { action: () => router.push('/'), } }) -function railGlyph(type) { - if (type === 'menu') return 'M4 6.5h16M4 12h16M4 17.5h16' - if (type === 'search') return 'M10.2 6.2a4 4 0 1 1 0 8 4 4 0 0 1 0-8z M13.6 13.6l3.2 3.2' - if (type === 'link') return 'M8 12h8 M12 8l4 4-4 4' - return 'M4 12h16' -} onMounted(async () => { await auth.refresh() if (typeof window !== 'undefined') { + const leftSaved = window.localStorage.getItem('tier-maker:left-rail-collapsed') + if (leftSaved === '1') leftRailCollapsed.value = true const saved = window.localStorage.getItem('tier-maker:right-rail-open') if (saved === '0') rightRailOpen.value = false } @@ -168,6 +170,13 @@ function isRouteActive(path) { return route.path.startsWith(path) } +function toggleLeftRail() { + leftRailCollapsed.value = !leftRailCollapsed.value + if (typeof window !== 'undefined') { + window.localStorage.setItem('tier-maker:left-rail-collapsed', leftRailCollapsed.value ? '1' : '0') + } +} + function toggleRightRail() { rightRailOpen.value = !rightRailOpen.value if (typeof window !== 'undefined') { @@ -218,8 +227,10 @@ watch( class="appShell" :class="{ 'appShell--preview': isPreviewMode, + 'appShell--leftCollapsed': leftRailCollapsed, 'appShell--rightClosed': !rightRailOpen, }" + :style="shellStyle" >