lg 미만에서 좌측 내비를 오버레이 슬라이드로 전환하고, 본문 아래에 우측 사이드를 두며 헤더·패널 여백을 보정했다. Co-authored-by: Cursor <cursoragent@cursor.com>
117 lines
5.5 KiB
Vue
117 lines
5.5 KiB
Vue
<script setup>
|
|
defineProps({
|
|
menuOpen: {
|
|
type: Boolean,
|
|
required: true
|
|
}
|
|
})
|
|
|
|
const { isDarkMode, toggleTheme } = useThemeMode()
|
|
|
|
const { data: tags } = await useFetch('/api/tags', {
|
|
default: () => []
|
|
})
|
|
|
|
const { data: navigation } = await useFetch('/api/navigation', {
|
|
default: () => ({
|
|
primary: [],
|
|
footer: []
|
|
})
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<aside
|
|
id="menu"
|
|
class="left-sidebar site-sidebar flex flex-col overflow-hidden border-r border-[var(--site-line)] transition-[width,opacity,transform,border-color] duration-300 ease-out max-lg:fixed max-lg:left-0 max-lg:top-[57px] max-lg:z-[60] max-lg:h-[calc(100dvh-57px)] max-lg:max-h-[calc(100dvh-57px)] max-lg:w-[min(287px,calc(100vw-24px))] max-lg:shadow-[0_16px_48px_rgba(0,0,0,0.18)] lg:sticky lg:top-[57px] lg:z-10 lg:h-[calc(100vh-57px)] lg:max-h-[calc(100vh-57px)] lg:self-start"
|
|
:class="menuOpen
|
|
? 'max-lg:translate-x-0 max-lg:pointer-events-auto lg:w-[287px] lg:opacity-100'
|
|
: 'max-lg:-translate-x-full max-lg:pointer-events-none lg:w-0 lg:opacity-0 lg:border-transparent'"
|
|
>
|
|
<div class="left-sidebar__scroll site-sidebar-scroll min-h-0 flex-1">
|
|
<div class="left-sidebar__block site-sidebar-section py-3 pl-4 pr-3 sm:pl-5 xl:pl-0">
|
|
<nav class="left-sidebar__nav" data-nav="menu">
|
|
<ul class="flex flex-col gap-[3px] text-[15px] text-[var(--site-text)]">
|
|
<li
|
|
v-for="item in navigation.primary"
|
|
:key="item.id"
|
|
class="group relative flex w-full items-center"
|
|
>
|
|
<NuxtLink
|
|
class="left-sidebar__nav-link flex flex-1 items-center gap-2 rounded-[10px] py-1.5 pr-3 pl-0 leading-tight transition-[padding,background-color] duration-200 before:h-4 before:w-1 before:flex-none before:rounded-sm before:rounded-l-none before:bg-[var(--site-line)] before:transition-[width,height,border-radius,background-color] before:duration-200 hover:bg-[#f2f2f2] hover:px-3 hover:before:h-2 hover:before:w-2 hover:before:rounded-full hover:before:bg-[rgba(17,17,17,0.25)]"
|
|
:to="item.url"
|
|
>
|
|
<span class="left-sidebar__nav-link-label flex-1 transition-transform duration-200 group-hover:translate-x-[3px]">{{ item.label }}</span>
|
|
</NuxtLink>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
|
|
<div class="left-sidebar__block site-sidebar-section px-5 py-4 pr-3 xl:pl-0">
|
|
<div class="left-sidebar__section-title flex items-center justify-between pr-2 text-xs font-semibold uppercase tracking-[0.01em] site-muted">
|
|
<span>Categories</span>
|
|
<span class="text-sm">⌃</span>
|
|
</div>
|
|
<div class="left-sidebar__category-grid mt-1.5 grid grid-cols-2 gap-x-2 gap-y-[2px] text-[0.8rem] font-medium">
|
|
<NuxtLink
|
|
v-for="tag in tags"
|
|
:key="tag.id"
|
|
class="left-sidebar__category group flex items-center gap-2 rounded-[10px] py-2 pr-3 pl-0 leading-tight transition-[padding,background-color,color] duration-200 hover:bg-[#f2f2f2] hover:px-3"
|
|
:to="`/tag/${tag.slug}`"
|
|
>
|
|
<span class="left-sidebar__category-color h-4 w-1 rounded-sm rounded-l-none transition-all duration-200 group-hover:h-2 group-hover:w-2 group-hover:rounded-full" :style="{ backgroundColor: tag.color }" />
|
|
<span class="left-sidebar__category-name flex-1 truncate transition-transform duration-200 group-hover:translate-x-[3px]">{{ tag.name }}</span>
|
|
<span
|
|
v-if="tag.postCount"
|
|
class="left-sidebar__category-count invisible text-xs font-medium opacity-0 transition-opacity duration-200 group-hover:visible group-hover:opacity-100"
|
|
>
|
|
{{ tag.postCount }}
|
|
</span>
|
|
</NuxtLink>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="left-sidebar__block site-sidebar-section px-5 py-5 pr-3 xl:pl-0">
|
|
<div class="left-sidebar__section-title flex items-center justify-between text-xs font-semibold uppercase site-muted">
|
|
<span>Authors</span>
|
|
<span>⌃</span>
|
|
</div>
|
|
<div class="left-sidebar__authors mt-4 grid gap-4 text-sm">
|
|
<div class="left-sidebar__author flex items-center gap-3">
|
|
<span class="h-8 w-8 rounded-full bg-[#e7c49d]" />
|
|
<span><strong class="block">sori</strong><span class="site-soft">Editor</span></span>
|
|
</div>
|
|
<div class="left-sidebar__author flex items-center gap-3">
|
|
<span class="h-8 w-8 rounded-full bg-[#98b7d5]" />
|
|
<span><strong class="block">zenn</strong><span class="site-soft">Writer</span></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<footer class="left-sidebar__footer flex shrink-0 items-center justify-between px-1 py-4 text-xs">
|
|
<nav class="left-sidebar__footer-nav flex gap-4">
|
|
<NuxtLink
|
|
v-for="item in navigation.footer"
|
|
:key="item.id"
|
|
class="site-interactive"
|
|
:to="item.url"
|
|
>
|
|
{{ item.label }}
|
|
</NuxtLink>
|
|
</nav>
|
|
<button
|
|
class="left-sidebar__theme-dot site-panel-hover site-interactive grid h-7 w-7 place-items-center rounded-full"
|
|
type="button"
|
|
:aria-label="isDarkMode ? '라이트 모드로 전환' : '다크 모드로 전환'"
|
|
:title="isDarkMode ? '라이트 모드' : '다크 모드'"
|
|
@click="toggleTheme"
|
|
>
|
|
<span v-if="isDarkMode">☀</span>
|
|
<span v-else>☾</span>
|
|
</button>
|
|
</footer>
|
|
</aside>
|
|
</template>
|