Files
money.sori.studio/layouts/default.vue

99 lines
3.6 KiB
Vue

<template>
<div class="min-h-dvh bg-paper text-ink">
<aside
v-if="showNav"
class="fixed inset-y-0 left-0 z-20 hidden w-64 border-r border-line bg-white md:block"
>
<div class="flex h-16 items-center gap-3 border-b border-line px-5">
<div class="flex h-9 w-9 items-center justify-center rounded-md bg-red-500 text-lg font-bold text-white">M</div>
<strong>Money 가계부</strong>
</div>
<nav class="px-3 py-5">
<NuxtLink
v-for="item in items"
:key="item.to"
:to="item.to"
class="mb-2 flex min-h-12 items-center gap-3 rounded-md px-4 text-sm font-semibold"
:class="isActive(item.to) ? 'bg-red-50 text-red-600' : 'text-muted hover:bg-paper'"
>
<span
class="flex h-8 w-8 items-center justify-center rounded-md"
:class="isActive(item.to) ? 'bg-red-100' : ''"
aria-hidden="true"
>
<span class="nav-icon h-6 w-6" v-html="item.icon" />
</span>
<span>{{ item.label }}</span>
</NuxtLink>
</nav>
</aside>
<main class="min-h-dvh w-full bg-white md:bg-paper" :class="showNav ? 'pb-20 md:pb-0 md:pl-64' : ''">
<div class="mx-auto min-h-dvh w-full md:max-w-7xl md:bg-transparent">
<slot />
</div>
</main>
<nav
v-if="showNav"
class="fixed inset-x-0 bottom-0 z-20 border-t border-line bg-white/95 backdrop-blur md:hidden"
>
<div class="mx-auto grid max-w-lg grid-cols-4">
<NuxtLink
v-for="item in items"
:key="item.to"
:to="item.to"
class="flex min-h-14 flex-col items-center justify-center gap-0.5 text-[11px] font-bold"
:class="isActive(item.to) ? 'text-red-600' : 'text-muted'"
>
<span
class="flex h-7 w-7 items-center justify-center rounded-md"
:class="isActive(item.to) ? 'bg-red-50' : ''"
aria-hidden="true"
>
<span class="nav-icon h-5 w-5" v-html="item.icon" />
</span>
<span>{{ item.label }}</span>
</NuxtLink>
</div>
</nav>
<NuxtLink
v-if="showFab"
to="/add"
class="fixed bottom-20 right-4 z-30 flex h-14 w-14 items-center justify-center rounded-full bg-red-500 text-white shadow-soft active:scale-95 md:bottom-10 md:right-10"
aria-label="거래 추가"
>
<span class="nav-icon h-7 w-7" v-html="addIcon" />
</NuxtLink>
</div>
</template>
<script setup lang="ts">
import addIconRaw from '~/assets/icons/add.svg?raw'
import assetIconRaw from '~/assets/icons/account_balance_wallet.svg?raw'
import reportIconRaw from '~/assets/icons/bar_chart.svg?raw'
import receiptIconRaw from '~/assets/icons/receipt_long.svg?raw'
import settingsIconRaw from '~/assets/icons/settings.svg?raw'
const route = useRoute()
const navIcon = (icon: string) => icon
.replace(/fill="[^"]*"/g, 'fill="currentColor"')
.replace(/height="[^"]*"/, 'height="100%"')
.replace(/width="[^"]*"/, 'width="100%"')
const items = [
{ to: '/', label: '내역', icon: navIcon(receiptIconRaw) },
{ to: '/stats', label: '통계', icon: navIcon(reportIconRaw) },
{ to: '/assets', label: '자산', icon: navIcon(assetIconRaw) },
{ to: '/settings', label: '설정', icon: navIcon(settingsIconRaw) }
]
const addIcon = navIcon(addIconRaw)
const showNav = computed(() => route.path !== '/login')
const showFab = computed(() => showNav.value && route.path !== '/add' && !route.path.startsWith('/transactions/'))
function isActive(to: string) {
return to === '/' ? route.path === '/' : route.path.startsWith(to)
}
</script>