mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 14:11:09 -05:00
436 lines
22 KiB
HTML
436 lines
22 KiB
HTML
{% load static %}
|
|
|
|
<!-- Enhanced Navigation Header -->
|
|
<header class="fixed top-0 left-0 right-0 z-50 transition-all duration-300"
|
|
x-data="{
|
|
isOpen: false,
|
|
isScrolled: false,
|
|
searchOpen: false,
|
|
userMenuOpen: false
|
|
}"
|
|
x-init="
|
|
window.addEventListener('scroll', () => {
|
|
isScrolled = window.scrollY > 20;
|
|
});
|
|
"
|
|
:class="isScrolled ? 'bg-white/95 dark:bg-neutral-900/95 backdrop-blur-xl shadow-xl border-b border-neutral-200/50 dark:border-neutral-700/50' : 'bg-transparent'">
|
|
|
|
<nav class="container mx-auto px-6 py-4" role="navigation" aria-label="Main navigation">
|
|
<div class="flex items-center justify-between">
|
|
|
|
<!-- Logo/Brand -->
|
|
<div class="flex items-center space-x-4">
|
|
<a href="{% url 'home' %}"
|
|
class="nav-brand text-2xl md:text-3xl font-bold transition-all duration-300 hover:scale-105"
|
|
aria-label="ThrillWiki Home">
|
|
<span class="bg-gradient-to-r from-thrill-primary via-purple-500 to-pink-500 bg-clip-text text-transparent">
|
|
ThrillWiki
|
|
</span>
|
|
</a>
|
|
|
|
<!-- Beta Badge -->
|
|
<div class="hidden sm:block">
|
|
<span class="badge badge-info text-xs pulse-glow">
|
|
<i class="fas fa-rocket mr-1"></i>
|
|
Beta
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Desktop Navigation -->
|
|
<div class="hidden lg:flex items-center space-x-8">
|
|
<!-- Main Navigation Links -->
|
|
<div class="flex items-center space-x-6">
|
|
<a href="{% url 'parks:park_list' %}"
|
|
class="nav-link group relative"
|
|
hx-get="{% url 'parks:park_list' %}"
|
|
hx-target="#main-content"
|
|
hx-swap="innerHTML transition:true">
|
|
<i class="fas fa-map-marked-alt mr-2 text-thrill-primary"></i>
|
|
Parks
|
|
<span class="absolute -bottom-1 left-0 w-0 h-0.5 bg-gradient-to-r from-thrill-primary to-purple-500 transition-all duration-300 group-hover:w-full"></span>
|
|
</a>
|
|
|
|
<a href="{% url 'rides:list' %}"
|
|
class="nav-link group relative"
|
|
hx-get="{% url 'rides:list' %}"
|
|
hx-target="#main-content"
|
|
hx-swap="innerHTML transition:true">
|
|
<i class="fas fa-rocket mr-2 text-thrill-secondary"></i>
|
|
Rides
|
|
<span class="absolute -bottom-1 left-0 w-0 h-0.5 bg-gradient-to-r from-thrill-secondary to-red-500 transition-all duration-300 group-hover:w-full"></span>
|
|
</a>
|
|
|
|
<div class="relative" x-data="{ open: false }" @mouseenter="open = true" @mouseleave="open = false">
|
|
<button class="nav-link group relative flex items-center"
|
|
@click="open = !open">
|
|
<i class="fas fa-compass mr-2 text-thrill-success"></i>
|
|
Explore
|
|
<i class="fas fa-chevron-down ml-2 text-xs transition-transform duration-200" :class="open ? 'rotate-180' : ''"></i>
|
|
<span class="absolute -bottom-1 left-0 w-0 h-0.5 bg-gradient-to-r from-thrill-success to-teal-500 transition-all duration-300 group-hover:w-full"></span>
|
|
</button>
|
|
|
|
<!-- Dropdown Menu -->
|
|
<div x-show="open"
|
|
x-transition:enter="transition ease-out duration-200"
|
|
x-transition:enter-start="opacity-0 transform scale-95"
|
|
x-transition:enter-end="opacity-100 transform scale-100"
|
|
x-transition:leave="transition ease-in duration-150"
|
|
x-transition:leave-start="opacity-100 transform scale-100"
|
|
x-transition:leave-end="opacity-0 transform scale-95"
|
|
class="absolute top-full left-0 mt-2 w-64 bg-white/95 dark:bg-neutral-800/95 backdrop-blur-xl rounded-2xl shadow-xl border border-neutral-200/50 dark:border-neutral-700/50 py-2"
|
|
@click.away="open = false">
|
|
|
|
<a href="{% url 'parks:trending' %}"
|
|
class="flex items-center px-4 py-3 text-sm hover:bg-neutral-100/50 dark:hover:bg-neutral-700/50 transition-colors">
|
|
<div class="w-8 h-8 bg-gradient-to-r from-thrill-primary to-purple-500 rounded-lg flex items-center justify-center mr-3">
|
|
<i class="fas fa-fire text-white text-xs"></i>
|
|
</div>
|
|
<div>
|
|
<div class="font-semibold">Trending Parks</div>
|
|
<div class="text-xs text-neutral-500">Most popular destinations</div>
|
|
</div>
|
|
</a>
|
|
|
|
<a href="{% url 'rides:new' %}"
|
|
class="flex items-center px-4 py-3 text-sm hover:bg-neutral-100/50 dark:hover:bg-neutral-700/50 transition-colors">
|
|
<div class="w-8 h-8 bg-gradient-to-r from-thrill-secondary to-red-500 rounded-lg flex items-center justify-center mr-3">
|
|
<i class="fas fa-plus text-white text-xs"></i>
|
|
</div>
|
|
<div>
|
|
<div class="font-semibold">New Attractions</div>
|
|
<div class="text-xs text-neutral-500">Latest additions</div>
|
|
</div>
|
|
</a>
|
|
|
|
<a href="{% url 'search:advanced' %}"
|
|
class="flex items-center px-4 py-3 text-sm hover:bg-neutral-100/50 dark:hover:bg-neutral-700/50 transition-colors">
|
|
<div class="w-8 h-8 bg-gradient-to-r from-thrill-success to-teal-500 rounded-lg flex items-center justify-center mr-3">
|
|
<i class="fas fa-search text-white text-xs"></i>
|
|
</div>
|
|
<div>
|
|
<div class="font-semibold">Advanced Search</div>
|
|
<div class="text-xs text-neutral-500">Find exactly what you want</div>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Search Bar -->
|
|
<div class="relative" x-data="searchComponent()">
|
|
<div class="relative">
|
|
<input type="text"
|
|
x-model="query"
|
|
@input="handleInput()"
|
|
placeholder="Search parks, rides, locations..."
|
|
class="w-80 pl-12 pr-4 py-3 bg-white/80 dark:bg-neutral-800/80 backdrop-blur-sm border border-neutral-300/50 dark:border-neutral-600/50 rounded-xl text-sm transition-all duration-300 focus:w-96 focus:bg-white dark:focus:bg-neutral-800 focus:border-thrill-primary focus:ring-2 focus:ring-thrill-primary/20 focus:shadow-lg"
|
|
hx-get="{% url 'parks:search_parks' %}"
|
|
hx-trigger="keyup changed delay:300ms"
|
|
hx-target="#search-results"
|
|
hx-include="this"
|
|
hx-vals='{"quick_search": "true"}'
|
|
name="search">
|
|
<div class="absolute left-4 top-1/2 transform -translate-y-1/2">
|
|
<i class="fas fa-search text-neutral-400 transition-colors duration-300"
|
|
:class="loading ? 'fa-spinner fa-spin text-thrill-primary' : 'text-thrill-primary'"></i>
|
|
</div>
|
|
<button x-show="query.length > 0"
|
|
@click="clearSearch()"
|
|
class="absolute right-4 top-1/2 transform -translate-y-1/2 text-neutral-400 hover:text-neutral-600 transition-colors">
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Search Results Dropdown -->
|
|
<div id="search-results"
|
|
x-show="showResults"
|
|
x-transition:enter="transition ease-out duration-200"
|
|
x-transition:enter-start="opacity-0 transform scale-95"
|
|
x-transition:enter-end="opacity-100 transform scale-100"
|
|
x-transition:leave="transition ease-in duration-150"
|
|
x-transition:leave-start="opacity-100 transform scale-100"
|
|
x-transition:leave-end="opacity-0 transform scale-95"
|
|
class="absolute top-full left-0 right-0 mt-2 bg-white/95 dark:bg-neutral-800/95 backdrop-blur-xl rounded-2xl shadow-xl border border-neutral-200/50 dark:border-neutral-700/50 max-h-96 overflow-y-auto z-50"
|
|
@click.away="showResults = false">
|
|
<!-- Dynamic search results will be loaded here via HTMX -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Action Buttons -->
|
|
<div class="flex items-center space-x-4">
|
|
<!-- Theme Toggle -->
|
|
<button class="p-2 rounded-lg hover:bg-neutral-100/50 dark:hover:bg-neutral-800/50 transition-colors"
|
|
onclick="toggleTheme()"
|
|
aria-label="Toggle theme">
|
|
<i class="fas fa-moon dark:hidden text-neutral-600"></i>
|
|
<i class="fas fa-sun hidden dark:block text-yellow-400"></i>
|
|
</button>
|
|
|
|
<!-- Notifications -->
|
|
<div class="relative" x-data="{ open: false }">
|
|
<button class="p-2 rounded-lg hover:bg-neutral-100/50 dark:hover:bg-neutral-800/50 transition-colors relative"
|
|
@click="open = !open"
|
|
aria-label="Notifications">
|
|
<i class="fas fa-bell text-neutral-600 dark:text-neutral-400"></i>
|
|
<span class="absolute -top-1 -right-1 w-3 h-3 bg-thrill-danger rounded-full animate-pulse"></span>
|
|
</button>
|
|
|
|
<!-- Notifications Dropdown -->
|
|
<div x-show="open"
|
|
x-transition:enter="transition ease-out duration-200"
|
|
x-transition:enter-start="opacity-0 transform scale-95"
|
|
x-transition:enter-end="opacity-100 transform scale-100"
|
|
x-transition:leave="transition ease-in duration-150"
|
|
x-transition:leave-start="opacity-100 transform scale-100"
|
|
x-transition:leave-end="opacity-0 transform scale-95"
|
|
class="absolute top-full right-0 mt-2 w-80 bg-white/95 dark:bg-neutral-800/95 backdrop-blur-xl rounded-2xl shadow-xl border border-neutral-200/50 dark:border-neutral-700/50 py-4"
|
|
@click.away="open = false">
|
|
|
|
<div class="px-4 pb-2 border-b border-neutral-200/50 dark:border-neutral-700/50">
|
|
<h3 class="font-semibold text-lg">Notifications</h3>
|
|
</div>
|
|
|
|
<div class="py-2 max-h-64 overflow-y-auto">
|
|
<div class="px-4 py-3 hover:bg-neutral-100/50 dark:hover:bg-neutral-700/50 transition-colors">
|
|
<div class="flex items-start space-x-3">
|
|
<div class="w-2 h-2 bg-thrill-primary rounded-full mt-2 flex-shrink-0"></div>
|
|
<div class="flex-1">
|
|
<p class="text-sm font-medium">New park added: Universal Epic Universe</p>
|
|
<p class="text-xs text-neutral-500 mt-1">2 hours ago</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="px-4 py-3 hover:bg-neutral-100/50 dark:hover:bg-neutral-700/50 transition-colors">
|
|
<div class="flex items-start space-x-3">
|
|
<div class="w-2 h-2 bg-thrill-secondary rounded-full mt-2 flex-shrink-0"></div>
|
|
<div class="flex-1">
|
|
<p class="text-sm font-medium">Ride update: Steel Vengeance reopened</p>
|
|
<p class="text-xs text-neutral-500 mt-1">1 day ago</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="px-4 pt-2 border-t border-neutral-200/50 dark:border-neutral-700/50">
|
|
<button class="text-sm text-thrill-primary hover:text-thrill-primary-dark transition-colors">
|
|
View all notifications
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- User Menu -->
|
|
{% if user.is_authenticated %}
|
|
<div class="relative" x-data="{ open: false }">
|
|
<button class="flex items-center space-x-2 p-2 rounded-lg hover:bg-neutral-100/50 dark:hover:bg-neutral-800/50 transition-colors"
|
|
@click="open = !open">
|
|
{% if user.avatar %}
|
|
<img src="{{ user.avatar.url }}" alt="{{ user.username }}" class="w-8 h-8 rounded-full object-cover">
|
|
{% else %}
|
|
<div class="w-8 h-8 bg-gradient-to-r from-thrill-primary to-purple-500 rounded-full flex items-center justify-center">
|
|
<span class="text-white text-sm font-semibold">{{ user.username|first|upper }}</span>
|
|
</div>
|
|
{% endif %}
|
|
<i class="fas fa-chevron-down text-xs transition-transform duration-200" :class="open ? 'rotate-180' : ''"></i>
|
|
</button>
|
|
|
|
<!-- User Dropdown -->
|
|
<div x-show="open"
|
|
x-transition:enter="transition ease-out duration-200"
|
|
x-transition:enter-start="opacity-0 transform scale-95"
|
|
x-transition:enter-end="opacity-100 transform scale-100"
|
|
x-transition:leave="transition ease-in duration-150"
|
|
x-transition:leave-start="opacity-100 transform scale-100"
|
|
x-transition:leave-end="opacity-0 transform scale-95"
|
|
class="absolute top-full right-0 mt-2 w-64 bg-white/95 dark:bg-neutral-800/95 backdrop-blur-xl rounded-2xl shadow-xl border border-neutral-200/50 dark:border-neutral-700/50 py-2"
|
|
@click.away="open = false">
|
|
|
|
<div class="px-4 py-3 border-b border-neutral-200/50 dark:border-neutral-700/50">
|
|
<p class="font-semibold">{{ user.get_full_name|default:user.username }}</p>
|
|
<p class="text-sm text-neutral-500">{{ user.email }}</p>
|
|
</div>
|
|
|
|
<a href="{% url 'accounts:profile' %}" class="flex items-center px-4 py-3 text-sm hover:bg-neutral-100/50 dark:hover:bg-neutral-700/50 transition-colors">
|
|
<i class="fas fa-user mr-3 text-thrill-primary"></i>
|
|
Profile
|
|
</a>
|
|
|
|
<a href="{% url 'accounts:settings' %}" class="flex items-center px-4 py-3 text-sm hover:bg-neutral-100/50 dark:hover:bg-neutral-700/50 transition-colors">
|
|
<i class="fas fa-cog mr-3 text-neutral-500"></i>
|
|
Settings
|
|
</a>
|
|
|
|
<a href="{% url 'accounts:favorites' %}" class="flex items-center px-4 py-3 text-sm hover:bg-neutral-100/50 dark:hover:bg-neutral-700/50 transition-colors">
|
|
<i class="fas fa-heart mr-3 text-red-500"></i>
|
|
Favorites
|
|
</a>
|
|
|
|
<div class="border-t border-neutral-200/50 dark:border-neutral-700/50 mt-2 pt-2">
|
|
<form method="post" action="{% url 'accounts:logout' %}">
|
|
{% csrf_token %}
|
|
<button type="submit" class="flex items-center w-full px-4 py-3 text-sm text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors">
|
|
<i class="fas fa-sign-out-alt mr-3"></i>
|
|
Sign Out
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<div class="flex items-center space-x-3">
|
|
<button class="btn-ghost btn-sm"
|
|
onclick="openAuthModal('login')">
|
|
Sign In
|
|
</button>
|
|
<button class="btn-primary btn-sm"
|
|
onclick="openAuthModal('register')">
|
|
Join Now
|
|
</button>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Mobile Menu Button -->
|
|
<button class="lg:hidden p-2 rounded-lg hover:bg-neutral-100/50 dark:hover:bg-neutral-800/50 transition-colors"
|
|
@click="isOpen = !isOpen"
|
|
aria-label="Toggle mobile menu">
|
|
<div class="w-6 h-6 relative">
|
|
<span class="absolute top-1 left-0 w-6 h-0.5 bg-current transition-all duration-300"
|
|
:class="isOpen ? 'rotate-45 top-2.5' : ''"></span>
|
|
<span class="absolute top-2.5 left-0 w-6 h-0.5 bg-current transition-all duration-300"
|
|
:class="isOpen ? 'opacity-0' : ''"></span>
|
|
<span class="absolute top-4 left-0 w-6 h-0.5 bg-current transition-all duration-300"
|
|
:class="isOpen ? '-rotate-45 top-2.5' : ''"></span>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Mobile Navigation Menu -->
|
|
<div x-show="isOpen"
|
|
x-transition:enter="transition ease-out duration-300"
|
|
x-transition:enter-start="opacity-0 transform -translate-y-4"
|
|
x-transition:enter-end="opacity-100 transform translate-y-0"
|
|
x-transition:leave="transition ease-in duration-200"
|
|
x-transition:leave-start="opacity-100 transform translate-y-0"
|
|
x-transition:leave-end="opacity-0 transform -translate-y-4"
|
|
class="lg:hidden mt-6 bg-white/95 dark:bg-neutral-800/95 backdrop-blur-xl rounded-2xl border border-neutral-200/50 dark:border-neutral-700/50 p-6">
|
|
|
|
<!-- Mobile Search -->
|
|
<div class="mb-6" x-data="searchComponent()">
|
|
<div class="relative">
|
|
<input type="text"
|
|
x-model="query"
|
|
@input="handleInput()"
|
|
placeholder="Search parks, rides, locations..."
|
|
class="w-full pl-12 pr-4 py-3 bg-neutral-100/50 dark:bg-neutral-700/50 border border-neutral-300/50 dark:border-neutral-600/50 rounded-xl text-sm"
|
|
hx-get="{% url 'parks:search_parks' %}"
|
|
hx-trigger="keyup changed delay:300ms"
|
|
hx-target="#mobile-search-results"
|
|
hx-include="this"
|
|
hx-vals='{"quick_search": "true"}'
|
|
name="search">
|
|
<div class="absolute left-4 top-1/2 transform -translate-y-1/2">
|
|
<i class="fas fa-search text-neutral-400 transition-colors duration-300"
|
|
:class="loading ? 'fa-spinner fa-spin text-thrill-primary' : ''"></i>
|
|
</div>
|
|
<button x-show="query.length > 0"
|
|
@click="clearSearch()"
|
|
class="absolute right-4 top-1/2 transform -translate-y-1/2 text-neutral-400 hover:text-neutral-600 transition-colors">
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Mobile Search Results -->
|
|
<div id="mobile-search-results"
|
|
x-show="showResults"
|
|
x-transition:enter="transition ease-out duration-200"
|
|
x-transition:enter-start="opacity-0 transform scale-95"
|
|
x-transition:enter-end="opacity-100 transform scale-100"
|
|
x-transition:leave="transition ease-in duration-150"
|
|
x-transition:leave-start="opacity-100 transform scale-100"
|
|
x-transition:leave-end="opacity-0 transform scale-95"
|
|
class="mt-2 bg-white/95 dark:bg-neutral-800/95 backdrop-blur-xl rounded-2xl shadow-xl border border-neutral-200/50 dark:border-neutral-700/50 max-h-64 overflow-y-auto"
|
|
@click.away="showResults = false">
|
|
<!-- Dynamic search results will be loaded here via HTMX -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Mobile Navigation Links -->
|
|
<div class="space-y-4">
|
|
<a href="{% url 'parks:park_list' %}"
|
|
class="flex items-center p-3 rounded-lg hover:bg-neutral-100/50 dark:hover:bg-neutral-700/50 transition-colors"
|
|
@click="isOpen = false">
|
|
<i class="fas fa-map-marked-alt mr-3 text-thrill-primary"></i>
|
|
<span class="font-medium">Parks</span>
|
|
</a>
|
|
|
|
<a href="{% url 'rides:ride_list' %}"
|
|
class="flex items-center p-3 rounded-lg hover:bg-neutral-100/50 dark:hover:bg-neutral-700/50 transition-colors"
|
|
@click="isOpen = false">
|
|
<i class="fas fa-rocket mr-3 text-thrill-secondary"></i>
|
|
<span class="font-medium">Rides</span>
|
|
</a>
|
|
|
|
<a href="{% url 'search:advanced' %}"
|
|
class="flex items-center p-3 rounded-lg hover:bg-neutral-100/50 dark:hover:bg-neutral-700/50 transition-colors"
|
|
@click="isOpen = false">
|
|
<i class="fas fa-search mr-3 text-thrill-success"></i>
|
|
<span class="font-medium">Advanced Search</span>
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Mobile User Actions -->
|
|
<div class="mt-6 pt-6 border-t border-neutral-200/50 dark:border-neutral-700/50">
|
|
{% if user.is_authenticated %}
|
|
<div class="flex items-center space-x-3 mb-4">
|
|
{% if user.avatar %}
|
|
<img src="{{ user.avatar.url }}" alt="{{ user.username }}" class="w-10 h-10 rounded-full object-cover">
|
|
{% else %}
|
|
<div class="w-10 h-10 bg-gradient-to-r from-thrill-primary to-purple-500 rounded-full flex items-center justify-center">
|
|
<span class="text-white font-semibold">{{ user.username|first|upper }}</span>
|
|
</div>
|
|
{% endif %}
|
|
<div>
|
|
<p class="font-semibold">{{ user.get_full_name|default:user.username }}</p>
|
|
<p class="text-sm text-neutral-500">{{ user.email }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-2">
|
|
<a href="{% url 'accounts:profile' %}" class="flex items-center p-2 rounded-lg hover:bg-neutral-100/50 dark:hover:bg-neutral-700/50 transition-colors">
|
|
<i class="fas fa-user mr-3 text-thrill-primary"></i>
|
|
Profile
|
|
</a>
|
|
<a href="{% url 'accounts:settings' %}" class="flex items-center p-2 rounded-lg hover:bg-neutral-100/50 dark:hover:bg-neutral-700/50 transition-colors">
|
|
<i class="fas fa-cog mr-3 text-neutral-500"></i>
|
|
Settings
|
|
</a>
|
|
<form method="post" action="{% url 'accounts:logout' %}">
|
|
{% csrf_token %}
|
|
<button type="submit" class="flex items-center w-full p-2 rounded-lg text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors">
|
|
<i class="fas fa-sign-out-alt mr-3"></i>
|
|
Sign Out
|
|
</button>
|
|
</form>
|
|
</div>
|
|
{% else %}
|
|
<div class="space-y-3">
|
|
<button class="btn-primary w-full" onclick="openAuthModal('register')">
|
|
Join ThrillWiki
|
|
</button>
|
|
<button class="btn-secondary w-full" onclick="openAuthModal('login')">
|
|
Sign In
|
|
</button>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
|
|
<!-- Spacer to prevent content from hiding behind fixed header -->
|
|
<div class="h-20"></div>
|