190 lines
6.3 KiB
Vue
190 lines
6.3 KiB
Vue
<template>
|
|
<header class="relative isolate z-10 bg-white dark:bg-gray-900 shadow-sm">
|
|
<nav
|
|
class="mx-auto flex max-w-7xl min-h-20 lg:min-h-32 items-end justify-between p-6 lg:px-8"
|
|
aria-label="Global Navigation"
|
|
>
|
|
<!-- MobileSidebar Open Button -->
|
|
<div class="flex justify-start">
|
|
<button
|
|
type="button"
|
|
class="-m-2.5 inline-flex items-center justify-center rounded-md p-2.5 text-gray-700 dark:text-white"
|
|
@click="mobileMenuOpen = true"
|
|
aria-label="Open main menu"
|
|
>
|
|
<Bars3Icon class="size-6" aria-hidden="true" />
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Desktop Navigation -->
|
|
<!-- Logo -->
|
|
<div class="flex">
|
|
<NuxtLink to="/" class="-m-1.5 p-1.5" aria-label="Bobu Home">
|
|
<span class="sr-only">Bobu</span>
|
|
<img
|
|
class="h-14 w-auto block dark:hidden transition-all duration-300"
|
|
:src="LOGOS.Red"
|
|
alt="Bobu Logo Light"
|
|
/>
|
|
<img
|
|
class="h-14 w-auto hidden dark:block transition-all duration-300"
|
|
:src="LOGOS.White"
|
|
alt="Bobu Logo Dark"
|
|
/>
|
|
</NuxtLink>
|
|
</div>
|
|
<!-- <PopoverGroup class="hidden lg:flex lg:gap-x-12">
|
|
<NuxtLink
|
|
v-for="item in navItems"
|
|
:key="item.name"
|
|
:to="item.href"
|
|
class="text-sm font-semibold leading-6 text-gray-900 dark:text-white hover:text-gray-700 dark:hover:text-gray-300"
|
|
>
|
|
{{ item.name }}
|
|
</NuxtLink>
|
|
</PopoverGroup> -->
|
|
|
|
<!-- Desktop HeaderActions -->
|
|
<div class="flex justify-end">
|
|
<HeaderActions />
|
|
</div>
|
|
</nav>
|
|
<!-- MobileSidebar -->
|
|
|
|
<Dialog
|
|
as="div"
|
|
class=""
|
|
@close="mobileMenuOpen = false"
|
|
:open="mobileMenuOpen"
|
|
>
|
|
<!-- Backdrop -->
|
|
<div
|
|
class="fixed inset-0 z-10 bg-black/50 dark:bg-black/50"
|
|
aria-hidden="true"
|
|
/>
|
|
|
|
<!-- Panel -->
|
|
<DialogPanel
|
|
class="fixed inset-y-0 left-0 z-20 w-full overflow-y-auto bg-white dark:bg-gray-900 px-6 py-6 sm:max-w-sm sm:ring-1 sm:ring-gray-900/10 dark:sm:ring-white/10 flex flex-col"
|
|
>
|
|
<!-- Top: Logo + Close button -->
|
|
<div class="flex items-end justify-between">
|
|
<NuxtLink
|
|
to="/"
|
|
class="-m-1.5 p-1.5"
|
|
@click="mobileMenuOpen = false"
|
|
aria-label="BDBU Home"
|
|
>
|
|
<span class="sr-only">Bobu</span>
|
|
<img
|
|
class="h-6 w-auto block dark:hidden"
|
|
:src="LOGOS.RedGaro"
|
|
alt="Bobu Logo Light"
|
|
/>
|
|
<img
|
|
class="h-6 w-auto hidden dark:block"
|
|
:src="LOGOS.WhiteGaro"
|
|
alt="Bobu Logo Dark"
|
|
/>
|
|
</NuxtLink>
|
|
<button
|
|
type="button"
|
|
class="-m-2.5 rounded-md p-2.5 text-gray-700 dark:text-white"
|
|
@click="mobileMenuOpen = false"
|
|
aria-label="Close menu"
|
|
>
|
|
<XMarkIcon class="size-6" aria-hidden="true" />
|
|
</button>
|
|
</div>
|
|
<!-- Middle: navItems + HeaderActions -->
|
|
<div class="mt-12 flow-root">
|
|
<div class="-my-6 divide-y divide-gray-500/10 dark:divide-gray-700">
|
|
<div class="space-y-2 py-6">
|
|
<NuxtLink
|
|
v-for="item in navItems"
|
|
:key="item.name"
|
|
:to="item.href"
|
|
@click="mobileMenuOpen = false"
|
|
class="-mx-3 flex items-center gap-x-4 rounded-lg px-3 py-2 text-base font-semibold leading-7 text-gray-900 dark:text-white hover:bg-gray-50 dark:hover:bg-gray-800"
|
|
>
|
|
<font-awesome-icon
|
|
:icon="item.icon"
|
|
class="h-4 w-4"
|
|
:style="item.color ? { color: item.color } : {}"
|
|
/>
|
|
{{ item.name }}
|
|
</NuxtLink>
|
|
</div>
|
|
|
|
<div class="py-6 space-y-2">
|
|
<!-- Not logged in: show 로그인/회원가입 -->
|
|
<NuxtLink
|
|
v-if="!userStore.userLoggedIn"
|
|
to="/login"
|
|
class="-mx-3 block rounded-lg px-3 py-2 text-base font-semibold leading-7 text-gray-900 dark:text-white hover:bg-gray-50 dark:hover:bg-gray-800"
|
|
>
|
|
로그인 / 회원가입
|
|
</NuxtLink>
|
|
|
|
<!-- If logged in: show 마이페이지 -->
|
|
<NuxtLink
|
|
v-else
|
|
to="/mypage"
|
|
class="-mx-3 block rounded-lg px-3 py-2 text-base font-semibold leading-7 text-gray-900 dark:text-white hover:bg-gray-50 dark:hover:bg-gray-800"
|
|
>
|
|
마이페이지
|
|
</NuxtLink>
|
|
|
|
<!-- Always show Cart when logged in -->
|
|
<NuxtLink
|
|
v-if="userStore.userLoggedIn"
|
|
to="/shop"
|
|
class="-mx-3 block rounded-lg px-3 py-2 text-base font-semibold leading-7 text-gray-900 dark:text-white hover:bg-gray-50 dark:hover:bg-gray-800"
|
|
>
|
|
장바구니
|
|
</NuxtLink>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Spacer -->
|
|
<div class="flex-grow"></div>
|
|
|
|
<!-- Bottom -->
|
|
<div class="mt-6 flex items-end justify-between">
|
|
<app-select-language />
|
|
<ColorModeSelector />
|
|
</div>
|
|
</DialogPanel>
|
|
</Dialog>
|
|
</header>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref } from 'vue';
|
|
import { Dialog, DialogPanel, PopoverGroup } from '@headlessui/vue';
|
|
import { Bars3Icon, XMarkIcon } from '@heroicons/vue/24/outline';
|
|
import { LOGOS } from '@/data/assets';
|
|
import useUserStore from '@/stores/user';
|
|
import HeaderActions from './header/HeaderAction.vue';
|
|
import AppSelectLanguage from './SelectLanguage.vue';
|
|
import { BASE_NAV_ITEMS } from '@/data/config';
|
|
|
|
const mobileMenuOpen = ref(false);
|
|
const userStore = useUserStore();
|
|
|
|
// Navigation items definition
|
|
const navItems = computed(() => {
|
|
// Get the user role, default to 0 if logged out or role is undefined/null
|
|
const currentRole = userStore.userRole || 0;
|
|
|
|
return BASE_NAV_ITEMS.filter((item) => {
|
|
return !item.requiredRole || currentRole >= item.requiredRole;
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* Add any component-specific styles here if needed, beyond Tailwind */
|
|
</style>
|