Files
bobu/bobu/app/components/MainHeader.vue
2025-06-03 21:13:56 +09:00

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>