99 lines
3.6 KiB
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>
|