릴리스: v1.2.22 좌측 레일 축소형 토글 추가

This commit is contained in:
2026-03-30 18:27:52 +09:00
parent 1a7ec50a93
commit 876c13d99b
7 changed files with 119 additions and 19 deletions

View File

@@ -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"
>
<template v-if="isPreviewMode">
<main class="appMain appMain--preview">
@@ -229,8 +240,8 @@ watch(
<template v-else>
<aside class="leftRail">
<div class="leftRail__top railHeader">
<button class="ghostIcon ghostIcon--iconOnly" type="button" aria-label="메뉴">
<svg viewBox="0 0 24 24" aria-hidden="true"><path :d="railGlyph('menu')" /></svg>
<button class="ghostIcon ghostIcon--iconOnly" type="button" aria-label="왼쪽 패널 토글" @click="toggleLeftRail">
<img :src="iconDockToRight" alt="" />
</button>
</div>
@@ -248,9 +259,9 @@ watch(
<form class="searchStub" @submit.prevent="submitGlobalSearch">
<span class="searchStub__icon">
<svg viewBox="0 0 24 24" aria-hidden="true"><path :d="railGlyph('search')" /></svg>
<img :src="iconSearch" alt="" />
</span>
<input v-model="searchQuery" class="searchStub__input" type="search" placeholder="전체 티어표 검색" />
<input v-model="searchQuery" class="searchStub__input" type="search" :placeholder="leftRailCollapsed ? '' : '전체 티어표 검색'" />
</form>
<nav class="leftNav">
@@ -265,7 +276,7 @@ watch(
<img v-if="item.iconSrc" :src="item.iconSrc" alt="" />
<svg v-else viewBox="0 0 24 24" aria-hidden="true"><path :d="item.icon" /></svg>
</span>
<span>{{ item.label }}</span>
<span class="leftNav__label">{{ item.label }}</span>
</RouterLink>
</nav>
@@ -323,7 +334,7 @@ watch(
<aside class="rightRail" :class="{ 'rightRail--closed': !rightRailOpen }" :aria-hidden="!rightRailOpen">
<div class="rightRail__top railHeader">
<button v-if="rightRailOpen" class="ghostIcon ghostIcon--iconOnly" type="button" aria-label="패널 닫기" @click="toggleRightRail">
<img :src="iconDockToRight" alt="" />
<img :src="iconDockToLeft" alt="" />
</button>
</div>
<div class="rightRail__body">
@@ -355,7 +366,7 @@ watch(
.appShell {
min-height: 100vh;
display: grid;
grid-template-columns: 248px minmax(0, 1fr) 320px;
grid-template-columns: var(--left-rail-width, 248px) minmax(0, 1fr) var(--right-rail-width, 320px);
background:
radial-gradient(circle at top left, rgba(255, 255, 255, 0.04), transparent 28%),
linear-gradient(180deg, #1a1a1a 0%, #121212 100%);
@@ -376,6 +387,7 @@ watch(
min-width: 0;
display: flex;
flex-direction: column;
overflow: hidden;
}
.rightRail {
@@ -388,10 +400,6 @@ watch(
border-color 220ms ease;
}
.appShell--rightClosed {
grid-template-columns: 248px minmax(0, 1fr) 0px;
}
.appShell--rightClosed .rightRail {
opacity: 0;
transform: translateX(18px);
@@ -417,6 +425,10 @@ watch(
gap: 12px;
}
.leftRail__top {
justify-content: flex-start;
}
.rightRail__top {
justify-content: flex-end;
}
@@ -458,7 +470,9 @@ watch(
}
.ghostIcon img,
.leftNav__glyph img {
.leftNav__glyph img,
.searchStub__icon img,
.favoriteMoreLink__icon img {
width: 16px;
height: 16px;
display: block;
@@ -475,6 +489,7 @@ watch(
position: relative;
margin-bottom: 14px;
min-height: 58px;
transition: margin 220ms ease;
}
.appUserCard__button,
@@ -491,6 +506,7 @@ watch(
text-align: left;
cursor: default;
box-sizing: border-box;
transition: padding 220ms ease, justify-content 220ms ease;
}
.appUserCard__avatar {
@@ -514,6 +530,7 @@ watch(
min-width: 0;
display: grid;
gap: 4px;
transition: opacity 180ms ease;
}
.appUserCard__name {
@@ -541,6 +558,7 @@ watch(
color: rgba(255, 255, 255, 0.62);
margin-bottom: 14px;
box-sizing: border-box;
transition: padding 220ms ease, justify-content 220ms ease;
}
.searchStub__input {
@@ -551,6 +569,7 @@ watch(
color: rgba(255, 255, 255, 0.92);
outline: none;
font: inherit;
transition: opacity 180ms ease, width 180ms ease;
}
.searchStub__input::placeholder {
@@ -581,6 +600,11 @@ watch(
transition: background 180ms ease, color 180ms ease, transform 180ms ease;
}
.leftNav__label {
min-width: 0;
white-space: nowrap;
}
.leftNav__item--active,
.leftNav__item.router-link-active {
background: rgba(255, 255, 255, 0.1);
@@ -601,6 +625,7 @@ watch(
margin-top: 22px;
display: grid;
gap: 8px;
transition: margin 220ms ease;
}
.leftRail__sectionTitle {
@@ -687,6 +712,66 @@ watch(
opacity: 0.56;
}
.appShell--leftCollapsed .leftRail__body {
padding-left: 10px;
padding-right: 10px;
}
.appShell--leftCollapsed .appUserCard {
margin-bottom: 10px;
}
.appShell--leftCollapsed .appUserCard__button,
.appShell--leftCollapsed .appUserCard__guest {
justify-content: center;
padding-left: 8px;
padding-right: 8px;
}
.appShell--leftCollapsed .appUserCard__meta,
.appShell--leftCollapsed .searchStub__input,
.appShell--leftCollapsed .leftNav__label,
.appShell--leftCollapsed .leftRail__sectionTitle,
.appShell--leftCollapsed .favoriteShortcut__label,
.appShell--leftCollapsed .favoriteMoreLink span:not(.favoriteMoreLink__icon),
.appShell--leftCollapsed .favoriteEmpty {
display: none;
}
.appShell--leftCollapsed .searchStub {
justify-content: center;
padding-left: 8px;
padding-right: 8px;
}
.appShell--leftCollapsed .leftNav {
gap: 10px;
}
.appShell--leftCollapsed .leftNav__item {
justify-content: center;
padding-left: 8px;
padding-right: 8px;
}
.appShell--leftCollapsed .leftRail__section {
margin-top: 18px;
}
.appShell--leftCollapsed .favoriteShortcut {
grid-template-columns: 1fr;
justify-items: center;
padding: 2px 0;
}
.appShell--leftCollapsed .favoriteMoreLink {
justify-content: center;
}
.appShell--leftCollapsed .leftRail__bottom {
display: none;
}
.leftRail__bottom {
margin-top: auto;
padding-top: 20px;

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="ffffff"><path d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z"/></svg>

After

Width:  |  Height:  |  Size: 375 B