Files
Virtnet.bond/themes/lucentui/views/components/navigation/index.blade.php

206 lines
11 KiB
PHP

<script data-navigate-track>
// Apply lazy loading to images - runs on initial load and Livewire navigation
(function() {
const applyLazyLoading = () => {
document.querySelectorAll('img:not([loading])')
.forEach(img => img.loading = 'lazy');
};
// Run immediately if DOM is ready, otherwise wait
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', applyLazyLoading);
} else {
applyLazyLoading();
}
// Also run on Livewire navigation
document.addEventListener('livewire:navigated', applyLazyLoading);
})();
</script>
<style>
.text-flow-effect {
background: linear-gradient(75deg,
hsl(178, 46.40%, 11.00%) 0%,
hsl(211, 57.80%, 17.60%) 30%,
hsl(220, 98%, 61%) 45%,
hsl(207, 53.00%, 50.80%) 55%,
hsl(214, 82.50%, 31.40%) 70%,
hsl(222, 47%, 11%) 100%);
background-size: 400% auto;
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
animation: textFlowAnimation 8s linear infinite;
}
@keyframes textFlowAnimation {
to {
background-position: 400% center;
}
}
</style>
<nav x-data="{ scrolled: false, slideOverOpen: false }"
x-init="
window.addEventListener('scroll', () => { scrolled = window.scrollY > 20 });
$watch('slideOverOpen', value => { document.documentElement.style.overflow = value ? 'hidden' : '' });
"
:class="{
'shadow-lg shadow-black/10 border-neutral/80': scrolled,
'border-neutral': !scrolled
}"
class="w-full px-4 lg:px-8 bg-background-secondary border-b flex flex-col lg:flex-row justify-between fixed top-0 z-20 h-auto transition-all duration-300">
<div class="relative z-50 w-full h-auto">
<div class="flex flex-row items-center justify-between w-full h-16">
<!-- Logo -->
<div class="flex flex-row items-center">
<a href="{{ route('home') }}" class="flex items-center h-10 gap-2" wire:navigate>
<x-logo class="h-10" />
<span class="text-xl font-bold leading-none flex items-center text-flow-effect">{{ config('app.name') }}</span>
</a>
<!-- Desktop menu: lg and above -->
<div class="hidden lg:flex flex-row ml-7">
@foreach (\App\Classes\Navigation::getLinks() as $nav)
@if (isset($nav['children']) && count($nav['children']) > 0)
<div class="relative">
<x-dropdown>
<x-slot:trigger>
<span class="flex flex-row items-center p-3 text-sm font-semibold whitespace-nowrap text-base hover:text-base/80">{{ $nav['name'] }}</span>
</x-slot:trigger>
<x-slot:content>
@foreach ($nav['children'] as $child)
<x-navigation.link :href="route($child['route'], $child['params'] ?? null)"
:spa="isset($child['spa']) ? $nav['spa'] : true">
{{ $child['name'] }}
</x-navigation.link>
@endforeach
</x-slot:content>
</x-dropdown>
</div>
@else
<x-navigation.link :href="route($nav['route'], $nav['params'] ?? null)"
:spa="isset($nav['spa']) ? $nav['spa'] : true"
class="flex items-center px-4 py-2">
{{ $nav['name'] }}
</x-navigation.link>
@endif
@endforeach
</div>
</div>
<!-- Right-side controls -->
<div class="flex items-center gap-3">
<!-- Desktop-only: md/lg controls -->
<!--<div class="hidden lg:flex items-center gap-2">
<x-dropdown>
<x-slot:trigger>
<span class="text-sm font-semibold">{{ strtoupper(app()->getLocale()) }} <span class="text-base/50">|</span> {{ session('currency', config('settings.default_currency')) }}</span>
</x-slot:trigger>
<x-slot:content>
<strong class="block p-2 text-xs font-semibold uppercase text-base/50">Language</strong>
<livewire:components.language-switch />
<livewire:components.currency-switch />
</x-slot:content>
</x-dropdown>
<x-theme-toggle />
</div>-->
<livewire:components.cart />
<!-- User account dropdown (desktop) -->
@if(auth()->check())
<div class="hidden lg:block">
<x-dropdown>
<x-slot:trigger>
<div class="flex items-center gap-3">
<img src="{{ auth()->user()->avatar }}" class="w-8 h-8 rounded-full border-2 border-background-secondary" alt="avatar" />
<span class="text-sm font-bold">{{ Auth::user()->first_name }}</span>
</div>
</x-slot:trigger>
<x-slot:content>
@foreach (\App\Classes\Navigation::getAccountDropdownLinks() as $nav)
<x-navigation.link :href="route($nav['route'], $nav['params'] ?? null)" :spa="isset($nav['spa']) ? $nav['spa'] : true">
{{ $nav['name'] }}
</x-navigation.link>
@endforeach
<div class="border-t border-neutral/50 mt-1 pt-1">
<livewire:auth.logout />
</div>
</x-slot:content>
</x-dropdown>
</div>
@else
<div class="hidden lg:flex items-center gap-3">
<a href="{{ route('login') }}" wire:navigate>
<button class="px-4 py-2 text-sm font-medium text-base border border-neutral hover:text-white hover:bg-primary rounded-lg transition-all duration-200">
{{ __('navigation.login') }}
</button>
</a>
@if(!config('settings.registration_disabled', false))
<a href="{{ route('register') }}" wire:navigate>
<button class="px-4 py-2 text-sm font-medium text-white bg-gradient-to-r from-primary to-secondary hover:from-primary/50 hover:to-secondary/50 rounded-lg transition-all duration-200 shadow-lg hover:shadow-xl transform hover:scale-105">
{{ __('navigation.register') }}
</button>
</a>
@endif
</div>
@endif
<!-- Mobile menu toggle -->
<button @click="slideOverOpen = !slideOverOpen" class="relative w-12 h-12 flex lg:hidden items-center justify-center rounded-xl bg-background hover:bg-neutral/50 transition-all duration-300 group" aria-label="Toggle Menu">
<span x-show="!slideOverOpen" x-transition.opacity class="absolute inset-0 flex items-center justify-center">
<x-ri-menu-fill class="size-6 text-base/80 group-hover:text-foreground transition-colors duration-200" />
</span>
<span x-show="slideOverOpen" x-transition.opacity class="absolute inset-0 flex items-center justify-center">
<x-ri-close-fill class="size-6 text-base/80 group-hover:text-foreground transition-colors duration-200" />
</span>
</button>
</div>
</div>
<!-- Mobile slide-over menu (<1024px) -->
<template x-teleport="body">
<div x-show="slideOverOpen" @keydown.window.escape="slideOverOpen=false" x-cloak class="fixed inset-0 z-[99]" aria-modal="true">
{{-- Backdrop with blur and fade --}}
<div x-show="slideOverOpen"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
@click="slideOverOpen = false"
class="absolute inset-0 bg-black/40 backdrop-blur-sm"></div>
{{-- Slide-over panel --}}
<div x-show="slideOverOpen"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-full"
x-transition:enter-end="opacity-100 translate-y-0"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0"
x-transition:leave-end="opacity-0 translate-y-full"
@click.stop
class="absolute left-0 right-0 top-16 bg-background-secondary/95 backdrop-blur-xl border-t border-neutral/50 shadow-2xl overflow-y-auto flex flex-col rounded-t-3xl"
style="height:calc(100dvh - 4rem);">
<div class="flex flex-col h-full p-6">
{{-- Swipe handle indicator --}}
<div class="flex justify-center mb-4">
<div class="w-12 h-1.5 bg-neutral/50 rounded-full"></div>
</div>
<div class="flex-1 min-h-0 overflow-y-auto">
<x-navigation.sidebar-links />
</div>
</div>
</div>
</div>
</template>
</div>
</nav>