218 lines
10 KiB
Vue
218 lines
10 KiB
Vue
<script setup lang="ts">
|
||
import AppLogo from '@/components/AppLogo.vue';
|
||
import AppLogoIcon from '@/components/AppLogoIcon.vue';
|
||
import Breadcrumbs from '@/components/Breadcrumbs.vue';
|
||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||
import { Button } from '@/components/ui/button';
|
||
import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
|
||
import { NavigationMenu, NavigationMenuItem, NavigationMenuList, navigationMenuTriggerStyle } from '@/components/ui/navigation-menu';
|
||
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '@/components/ui/sheet';
|
||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
|
||
import UserMenuContent from '@/components/UserMenuContent.vue';
|
||
import { getInitials } from '@/composables/useInitials';
|
||
import type { BreadcrumbItem, NavItem } from '@/types';
|
||
import { InertiaLinkProps, Link, usePage } from '@inertiajs/vue3';
|
||
import { BookOpen, Folder } from 'lucide-vue-next';
|
||
import { computed } from 'vue';
|
||
|
||
interface Props {
|
||
breadcrumbs?: BreadcrumbItem[];
|
||
}
|
||
|
||
const props = withDefaults(defineProps<Props>(), {
|
||
breadcrumbs: () => [],
|
||
});
|
||
|
||
const page = usePage();
|
||
const auth = computed(() => page.props.auth);
|
||
|
||
const isCurrentRoute = computed(() => (url: NonNullable<InertiaLinkProps['href']>) => page.url === (typeof url === 'string' ? url : url.url));
|
||
|
||
const activeItemStyles = computed(
|
||
() => (url: NonNullable<InertiaLinkProps['href']>) =>
|
||
isCurrentRoute.value(typeof url === 'string' ? url : url.url)
|
||
? 'text-primary dark:bg-card dark:text-primary-foreground'
|
||
: 'text-foreground hover:bg-muted',
|
||
);
|
||
|
||
const mainNavItems: NavItem[] = [
|
||
{
|
||
title: 'Accueil',
|
||
href: '/', // Example route
|
||
},
|
||
{
|
||
title: 'Tirage d’oracle',
|
||
href: '/oracle-draw', // Example route
|
||
},
|
||
{
|
||
title: 'Consultations',
|
||
href: '/consultations', // Example route
|
||
},
|
||
{
|
||
title: 'Services',
|
||
href: '/services', // Example route
|
||
},
|
||
{
|
||
title: 'Contact',
|
||
href: '/contact', // Example route
|
||
},
|
||
];
|
||
|
||
const rightNavItems: NavItem[] = [
|
||
{
|
||
title: 'Repository',
|
||
href: 'https://github.com/your-repo',
|
||
icon: Folder,
|
||
},
|
||
{
|
||
title: 'Documentation',
|
||
href: 'https://your-docs.com',
|
||
icon: BookOpen,
|
||
},
|
||
];
|
||
</script>
|
||
|
||
<template>
|
||
<div>
|
||
<div class="border-b border-border/80">
|
||
<div class="mx-auto flex h-16 items-center px-4 md:max-w-7xl">
|
||
<div class="lg:hidden">
|
||
<Sheet>
|
||
<SheetTrigger :as-child="true">
|
||
<Button variant="ghost" size="icon" class="mr-2 h-9 w-9">
|
||
<Menu class="h-5 w-5" />
|
||
</Button>
|
||
</SheetTrigger>
|
||
<SheetContent side="left" class="w-[300px] bg-background p-6">
|
||
<SheetTitle class="sr-only">Navigation Menu</SheetTitle>
|
||
<SheetHeader class="flex justify-start text-left">
|
||
<AppLogoIcon class="size-6 fill-current text-primary dark:text-primary" />
|
||
</SheetHeader>
|
||
<div class="flex h-full flex-1 flex-col justify-between space-y-4 py-6">
|
||
<nav class="-mx-3 space-y-1">
|
||
<Link
|
||
v-for="item in mainNavItems"
|
||
:key="item.title"
|
||
:href="item.href"
|
||
class="flex items-center gap-x-3 rounded-lg px-3 py-2 font-body text-sm hover:bg-muted"
|
||
:class="isCurrentRoute(item.href) ? 'font-semibold text-primary' : 'text-foreground'"
|
||
>
|
||
{{ item.title }}
|
||
</Link>
|
||
</nav>
|
||
<div class="flex flex-col space-y-4">
|
||
<a
|
||
v-for="item in rightNavItems"
|
||
:key="item.title"
|
||
:href="typeof item.href === 'string' ? item.href : item.href?.url"
|
||
target="_blank"
|
||
rel="noopener noreferrer"
|
||
class="flex items-center space-x-2 font-body text-sm text-foreground"
|
||
>
|
||
<component v-if="item.icon" :is="item.icon" class="h-5 w-5" />
|
||
<span>{{ item.title }}</span>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</SheetContent>
|
||
</Sheet>
|
||
</div>
|
||
|
||
<Link href="/" class="flex items-center gap-x-2">
|
||
<AppLogo />
|
||
</Link>
|
||
|
||
<div class="hidden h-full lg:flex lg:flex-1">
|
||
<NavigationMenu class="ml-10 flex h-full items-stretch">
|
||
<NavigationMenuList class="flex h-full items-stretch space-x-2">
|
||
<NavigationMenuItem v-for="(item, index) in mainNavItems" :key="index" class="relative flex h-full items-center">
|
||
<Link
|
||
:class="[navigationMenuTriggerStyle(), activeItemStyles(item.href), 'h-9 cursor-pointer px-3 font-body']"
|
||
:href="item.href"
|
||
>
|
||
{{ item.title }}
|
||
</Link>
|
||
<div
|
||
v-if="isCurrentRoute(item.href)"
|
||
class="bg-subtle-gold dark:bg-subtle-gold absolute bottom-0 left-0 h-0.5 w-full translate-y-px"
|
||
></div>
|
||
</NavigationMenuItem>
|
||
</NavigationMenuList>
|
||
</NavigationMenu>
|
||
</div>
|
||
|
||
<div class="ml-auto flex items-center space-x-2">
|
||
<div class="relative flex items-center space-x-1">
|
||
<TooltipProvider :delay-duration="0">
|
||
<Tooltip>
|
||
<TooltipTrigger>
|
||
<Button variant="ghost" size="icon" as-child class="group h-9 w-9 cursor-pointer">
|
||
<a href="#" class="flex items-center justify-center">
|
||
<span class="sr-only">Rechercher</span>
|
||
<Search class="size-5 opacity-80 group-hover:opacity-100" />
|
||
</a>
|
||
</Button>
|
||
</TooltipTrigger>
|
||
<TooltipContent>
|
||
<p>Rechercher</p>
|
||
</TooltipContent>
|
||
</Tooltip>
|
||
</TooltipProvider>
|
||
|
||
<div class="hidden space-x-1 lg:flex">
|
||
<template v-for="item in rightNavItems" :key="item.title">
|
||
<TooltipProvider :delay-duration="0">
|
||
<Tooltip>
|
||
<TooltipTrigger>
|
||
<Button variant="ghost" size="icon" as-child class="group h-9 w-9 cursor-pointer">
|
||
<a
|
||
:href="typeof item.href === 'string' ? item.href : item.href?.url"
|
||
target="_blank"
|
||
rel="noopener noreferrer"
|
||
>
|
||
<span class="sr-only">{{ item.title }}</span>
|
||
<component :is="item.icon" class="size-5 opacity-80 group-hover:opacity-100" />
|
||
</a>
|
||
</Button>
|
||
</TooltipTrigger>
|
||
<TooltipContent>
|
||
<p>{{ item.title }}</p>
|
||
</TooltipContent>
|
||
</Tooltip>
|
||
</TooltipProvider>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
|
||
<DropdownMenu>
|
||
<DropdownMenuTrigger :as-child="true">
|
||
<Button
|
||
variant="ghost"
|
||
size="icon"
|
||
class="focus-within:ring-subtle-gold relative size-10 w-auto rounded-full p-1 focus-within:ring-2"
|
||
>
|
||
<Avatar class="size-8 overflow-hidden rounded-full">
|
||
<AvatarImage v-if="auth.user.avatar" :src="auth.user.avatar" :alt="auth.user.name" />
|
||
<AvatarFallback
|
||
class="bg-linen dark:bg-spiritual-earth dark:text-pure-white rounded-lg font-semibold text-foreground"
|
||
>
|
||
{{ getInitials(auth.user?.name) }}
|
||
</AvatarFallback>
|
||
</Avatar>
|
||
</Button>
|
||
</DropdownMenuTrigger>
|
||
<DropdownMenuContent align="end" class="w-56">
|
||
<UserMenuContent :user="auth.user" />
|
||
</DropdownMenuContent>
|
||
</DropdownMenu>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div v-if="props.breadcrumbs.length > 1" class="flex w-full border-b border-border/70">
|
||
<div class="mx-auto flex h-12 w-full items-center justify-start px-4 text-muted-foreground md:max-w-7xl">
|
||
<Breadcrumbs :breadcrumbs="breadcrumbs" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|