릴리스: v1.3.29 가이드 진입점과 인증 초기화 안정화

This commit is contained in:
2026-04-01 15:07:58 +09:00
parent 3a64dc44c8
commit cf96e931e9
5 changed files with 92 additions and 32 deletions

View File

@@ -31,7 +31,8 @@ const viewportWidth = ref(typeof window !== 'undefined' ? window.innerWidth : 14
provide('rightRailOpen', rightRailOpen)
provide('localRightRailTarget', '#local-right-rail-root')
const isAdmin = computed(() => !!auth.user?.isAdmin)
const authReady = computed(() => auth.hydrated)
const isAdmin = computed(() => authReady.value && !!auth.user?.isAdmin)
const isPreviewMode = computed(() => route.query.preview === '1')
const usesLocalRightRail = computed(() => ['editEditor', 'newEditor', 'admin'].includes(String(route.name || '')))
const isRightRailOverlay = computed(() => viewportWidth.value <= 1200)
@@ -44,7 +45,10 @@ const accountName = computed(() => {
if (email) return email.split('@')[0] || email
return 'Guest'
})
const accountEmail = computed(() => (auth.user?.email || '').trim() || '로그인 후 개인 메뉴를 사용할 수 있어요.')
const accountEmail = computed(() => {
if (!authReady.value) return '계정 상태를 확인하고 있어요.'
return (auth.user?.email || '').trim() || '로그인 후 개인 메뉴를 사용할 수 있어요.'
})
const shellStyle = computed(() => ({
'--left-rail-width': leftRailCollapsed.value ? '76px' : '248px',
'--right-rail-width': !isRightRailOverlay.value && rightRailOpen.value ? '325px' : '0px',
@@ -56,9 +60,10 @@ const leftNavItems = computed(() => {
{ key: 'favorites', label: 'Favorites', path: '/favorites', iconSrc: iconFavorite, requiresAuth: true },
{ key: 'profile', label: 'Settings', path: '/profile', iconSrc: iconSettings, requiresAuth: true },
]
return items.filter((item) => !item.requiresAuth || auth.user)
return items.filter((item) => !item.requiresAuth || (authReady.value && auth.user))
})
const showRightRailAction = computed(() => false)
const showSettingsGuideButton = computed(() => route.name === 'profile')
const guideSteps = [
{
id: 'select-game',
@@ -123,6 +128,7 @@ const isGuideNextDisabled = computed(() => guideStepIndex.value >= guideSteps.le
const showGameHubViewToggle = computed(() => route.name === 'gameHub')
const gameHubViewMode = computed(() => (route.query.view === 'list' ? 'list' : 'grid'))
const leftBottomPrimaryAction = computed(() => {
if (!authReady.value) return null
if (route.name === 'home' && auth.user) {
return { label: '커스텀 티어표 만들기', to: '/editor/freeform/new' }
}
@@ -401,7 +407,7 @@ function submitGlobalSearch() {
<div class="leftRail__body">
<div class="leftRail__content">
<div v-if="auth.user" class="appUserCard">
<div v-if="authReady && auth.user" class="appUserCard">
<div class="appUserCard__button">
<img v-if="avatarUrl" :src="avatarUrl" class="appUserCard__avatar" alt="avatar" />
<div v-else class="appUserCard__avatar appUserCard__avatar--fallback">{{ accountName[0]?.toUpperCase() || 'U' }}</div>
@@ -442,8 +448,12 @@ function submitGlobalSearch() {
</div>
<div class="leftRail__bottom">
<RouterLink v-if="leftBottomPrimaryAction" :to="leftBottomPrimaryAction.to" class="adminButton">{{ leftBottomPrimaryAction.label }}</RouterLink>
<RouterLink v-if="isAdmin" to="/admin" class="adminButton">관리자 메뉴</RouterLink>
<RouterLink v-else-if="!auth.user" to="/login" class="adminButton">로그인</RouterLink>
<button v-if="showSettingsGuideButton" class="adminButton adminButton--icon" type="button" @click="openGuideModal()">
<SvgIcon :src="iconMenuBook" :size="18" class="adminButton__icon" />
<span>가이드 보기</span>
</button>
<RouterLink v-if="authReady && isAdmin" to="/admin" class="adminButton">관리자 메뉴</RouterLink>
<RouterLink v-else-if="authReady && !auth.user" to="/login" class="adminButton">로그인</RouterLink>
</div>
</div>
</aside>
@@ -567,9 +577,6 @@ function submitGlobalSearch() {
</button>
</section>
</template>
<button class="guideDockButton" type="button" aria-label="사용법 열기" @click="openGuideModal()">
<SvgIcon :src="iconMenuBook" :size="22" />
</button>
</div>
</div>
</aside>
@@ -960,6 +967,7 @@ function submitGlobalSearch() {
display: inline-flex;
justify-content: center;
align-items: center;
gap: 8px;
padding: 12px 14px;
border-radius: 14px;
border: 1px solid rgba(255, 255, 255, 0.12);
@@ -970,6 +978,14 @@ function submitGlobalSearch() {
font-weight: 800;
}
.adminButton--icon {
text-align: center;
}
.adminButton__icon {
flex: 0 0 auto;
}
.appMain {
min-width: 0;
min-height: 0;
@@ -1084,25 +1100,6 @@ function submitGlobalSearch() {
padding-top: 12px;
}
.guideDockButton {
width: 42px;
height: 42px;
border-radius: 14px;
border: 1px solid rgba(255, 255, 255, 0.08);
background: rgba(255, 255, 255, 0.04);
color: rgba(255, 255, 255, 0.78);
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
flex: 0 0 auto;
}
.guideDockButton:hover {
background: rgba(255, 255, 255, 0.08);
color: rgba(255, 255, 255, 0.96);
}
.rightRailAction__button {
width: 100%;
padding: 12px 14px;