Files
thrillwiki_django_no_react/templates/components/layout/enhanced_header.html
pac7 f2fccdf190 Improve icon sizes for better visual consistency across devices
Update Tailwind CSS with new height and width utilities for icons and adjust icon sizes in the enhanced header component for improved responsiveness.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 9ac4060c-9ba6-40b4-b325-c945a385dd39
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
2025-09-23 21:15:44 +00:00

473 lines
23 KiB
HTML

{% comment %}
Enhanced Header Component - Matches React Frontend Design
Includes: Browse menu, advanced search, theme toggle, user dropdown, mobile menu
{% endcomment %}
{% load static %}
<header class="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<div class="flex items-center h-14 px-4 gap-3 md:gap-4">
<!-- Logo and Browse Menu -->
<div class="flex items-center gap-4 shrink-0">
<!-- Logo -->
<a href="{% url 'home' %}" class="flex items-center space-x-2 flex-shrink-0">
<div class="w-6 h-6 bg-purple-600 rounded flex items-center justify-center">
<span class="text-white text-xs font-bold">TW</span>
</div>
<span class="font-bold text-lg whitespace-nowrap">ThrillWiki</span>
</a>
<!-- Browse Menu (Desktop) -->
<div class="hidden md:block">
<div
x-data="{ open: false }"
@mouseenter="open = true"
@mouseleave="open = false"
class="relative"
>
<button
class="flex items-center gap-2 px-3 py-1.5 text-sm font-medium rounded-md hover:bg-accent transition-colors"
@click="open = !open"
>
<i class="fas fa-compass w-4 h-4"></i>
Browse
<i class="fas fa-chevron-down w-3 h-3 transition-transform duration-200" :class="{ 'rotate-180': open }"></i>
</button>
<!-- Browse Dropdown -->
<div
x-show="open"
x-transition:enter="transition ease-out duration-100"
x-transition:enter-start="transform opacity-0 scale-95"
x-transition:enter-end="transform opacity-100 scale-100"
x-transition:leave="transition ease-in duration-75"
x-transition:leave-start="transform opacity-100 scale-100"
x-transition:leave-end="transform opacity-0 scale-95"
x-cloak
class="absolute left-0 mt-1 w-auto max-w-4xl p-6 bg-background border rounded-lg shadow-lg z-50"
>
<div class="flex gap-8">
<!-- Left Column -->
<div class="flex-1 space-y-4 min-w-0">
<a
href="{% url 'parks:park_list' %}"
class="flex items-start gap-3 p-3 rounded-md hover:bg-accent transition-colors group"
@click="open = false"
>
<i class="fas fa-map-marker-alt w-4 h-4 mt-0.5 text-muted-foreground group-hover:text-foreground flex-shrink-0"></i>
<div class="min-w-0 flex-1">
<h3 class="font-medium text-sm mb-1 leading-tight">Parks</h3>
<p class="text-xs text-muted-foreground leading-relaxed">Explore theme parks worldwide</p>
</div>
</a>
<a
href="{% url 'rides:manufacturer_list' %}"
class="flex items-start gap-3 p-3 rounded-md hover:bg-accent transition-colors group"
@click="open = false"
>
<i class="fas fa-wrench w-4 h-4 mt-0.5 text-muted-foreground group-hover:text-foreground flex-shrink-0"></i>
<div class="min-w-0 flex-1">
<h3 class="font-medium text-sm mb-1 leading-tight">Manufacturers</h3>
<p class="text-xs text-muted-foreground leading-relaxed">Ride and attraction manufacturers</p>
</div>
</a>
<a
href="{% url 'parks:operator_list' %}"
class="flex items-start gap-3 p-3 rounded-md hover:bg-accent transition-colors group"
@click="open = false"
>
<i class="fas fa-users w-4 h-4 mt-0.5 text-muted-foreground group-hover:text-foreground flex-shrink-0"></i>
<div class="min-w-0 flex-1">
<h3 class="font-medium text-sm mb-1 leading-tight">Operators</h3>
<p class="text-xs text-muted-foreground leading-relaxed">Theme park operating companies</p>
</div>
</a>
</div>
<!-- Right Column -->
<div class="flex-1 space-y-4 min-w-0">
<a
href="{% url 'rides:global_ride_list' %}"
class="flex items-start gap-3 p-3 rounded-md hover:bg-accent transition-colors group"
@click="open = false"
>
<i class="fas fa-rocket w-4 h-4 mt-0.5 text-muted-foreground group-hover:text-foreground flex-shrink-0"></i>
<div class="min-w-0 flex-1">
<h3 class="font-medium text-sm mb-1 leading-tight">Rides</h3>
<p class="text-xs text-muted-foreground leading-relaxed">Discover rides and attractions</p>
</div>
</a>
<a
href="{% url 'rides:designer_list' %}"
class="flex items-start gap-3 p-3 rounded-md hover:bg-accent transition-colors group"
@click="open = false"
>
<i class="fas fa-drafting-compass w-4 h-4 mt-0.5 text-muted-foreground group-hover:text-foreground flex-shrink-0"></i>
<div class="min-w-0 flex-1">
<h3 class="font-medium text-sm mb-1 leading-tight">Designers</h3>
<p class="text-xs text-muted-foreground leading-relaxed">Ride designers and architects</p>
</div>
</a>
<a
href="#"
class="flex items-start gap-3 p-3 rounded-md hover:bg-accent transition-colors group"
@click="open = false"
>
<i class="fas fa-trophy w-4 h-4 mt-0.5 text-muted-foreground group-hover:text-foreground flex-shrink-0"></i>
<div class="min-w-0 flex-1">
<h3 class="font-medium text-sm mb-1 leading-tight">Top Lists</h3>
<p class="text-xs text-muted-foreground leading-relaxed">Community rankings and favorites</p>
</div>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Center Search Bar -->
<div class="hidden md:flex flex-1 min-w-0 justify-center">
<!-- Enhanced Search -->
<div class="relative w-full min-w-0 max-w-xl lg:max-w-2xl" x-data="searchComponent">
<div class="relative">
<i class="fas fa-search absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground"></i>
<input
type="search"
placeholder="Search parks, rides..."
class="w-full min-w-0 pl-10 pr-3 h-10 rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
x-model="query"
@input.debounce.300ms="search()"
hx-get="{% url 'search:search' %}"
hx-trigger="input changed delay:300ms"
hx-target="#search-results"
hx-include="this"
name="q"
/>
</div>
<!-- Search Results Dropdown -->
<div
id="search-results"
x-show="results.length > 0"
x-transition
x-cloak
class="absolute top-full left-0 right-0 mt-1 bg-background border rounded-md shadow-lg z-50 max-h-96 overflow-y-auto"
>
<!-- Search results will be populated by HTMX -->
</div>
</div>
</div>
<!-- Desktop Right Side -->
<div class="hidden md:flex items-center gap-4 shrink-0">
<!-- Search Button -->
<button
type="submit"
class="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4"
>
Search
</button>
<!-- Theme Toggle -->
<button
x-data="themeToggle"
@click="toggleTheme()"
class="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground h-12 w-12"
>
<i class="fas fa-sun h-6 w-6 md:h-7 md:w-7 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0"></i>
<i class="fas fa-moon absolute h-6 w-6 md:h-7 md:w-7 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"></i>
<span class="sr-only">Toggle theme</span>
</button>
<!-- User Icon -->
<div class="relative" x-data="{ open: false }" @click.outside="open = false">
<button
@click="open = !open"
class="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground h-12 w-12"
>
{% if user.is_authenticated %}
{% if user.profile.avatar %}
<img
src="{{ user.profile.avatar.url }}"
alt="{{ user.get_full_name|default:user.username }}"
class="h-8 w-8 rounded-full object-cover"
/>
{% else %}
<div class="h-8 w-8 rounded-full bg-primary flex items-center justify-center text-primary-foreground text-sm font-medium">
{{ user.get_full_name.0|default:user.username.0|upper }}
</div>
{% endif %}
{% else %}
<i class="fas fa-user h-6 w-6"></i>
{% endif %}
</button>
<!-- User Dropdown -->
<div
x-show="open"
x-transition:enter="transition ease-out duration-100"
x-transition:enter-start="transform opacity-0 scale-95"
x-transition:enter-end="transform opacity-100 scale-100"
x-transition:leave="transition ease-in duration-75"
x-transition:leave-start="transform opacity-100 scale-100"
x-transition:leave-end="transform opacity-0 scale-95"
x-cloak
class="absolute right-0 top-full mt-2 w-48 bg-background border rounded-md shadow-lg z-50"
>
{% if user.is_authenticated %}
<div class="flex items-center justify-start gap-2 p-3">
<div class="flex flex-col space-y-1 leading-none">
<p class="font-medium">{{ user.get_full_name|default:user.username }}</p>
<p class="w-[180px] truncate text-sm text-muted-foreground">{{ user.email }}</p>
</div>
</div>
<div class="border-t"></div>
<a href="{% url 'profile' user.username %}" class="flex items-center px-3 py-2 text-sm hover:bg-accent" @click="open = false">
<i class="fas fa-user mr-2 h-4 w-4"></i>
Profile
</a>
<a href="{% url 'settings' %}" class="flex items-center px-3 py-2 text-sm hover:bg-accent" @click="open = false">
<i class="fas fa-cog mr-2 h-4 w-4"></i>
Settings
</a>
{% if has_moderation_access %}
<a href="{% url 'moderation:dashboard' %}" class="flex items-center px-3 py-2 text-sm hover:bg-accent" @click="open = false">
<i class="fas fa-shield-alt mr-2 h-4 w-4"></i>
Moderation
</a>
{% endif %}
<div class="border-t"></div>
<form method="post" action="{% url 'account_logout' %}">
{% csrf_token %}
<button type="submit" class="flex items-center w-full px-3 py-2 text-sm text-red-600 hover:bg-accent">
<i class="fas fa-sign-out-alt mr-2 h-4 w-4"></i>
Log out
</button>
</form>
{% else %}
<div class="p-2">
<button
@click="window.authModal.show('login'); open = false"
class="flex items-center w-full px-3 py-2 text-sm hover:bg-accent rounded-md"
>
<i class="fas fa-sign-in-alt mr-2 h-4 w-4"></i>
Login
</button>
<button
@click="window.authModal.show('register'); open = false"
class="flex items-center w-full px-3 py-2 text-sm hover:bg-accent rounded-md"
>
<i class="fas fa-user-plus mr-2 h-4 w-4"></i>
Register
</button>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Mobile Menu -->
<div class="md:hidden flex items-center space-x-2 flex-shrink-0">
<!-- Theme Toggle (Mobile) -->
<div x-data="themeToggle">
<button
@click="toggleTheme()"
class="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground h-10 w-10"
>
<i class="fas fa-sun h-6 w-6 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0"></i>
<i class="fas fa-moon absolute h-6 w-6 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"></i>
</button>
</div>
<!-- Mobile User Menu -->
{% if user.is_authenticated %}
<div class="relative" x-data="{ open: false }" @click.outside="open = false">
<button @click="open = !open" class="relative h-8 w-8 rounded-full">
{% if user.profile.avatar %}
<img
src="{{ user.profile.avatar.url }}"
alt="{{ user.get_full_name|default:user.username }}"
class="h-8 w-8 rounded-full object-cover"
/>
{% else %}
<div class="h-8 w-8 rounded-full bg-primary flex items-center justify-center text-primary-foreground text-sm font-medium">
{{ user.get_full_name.0|default:user.username.0|upper }}
</div>
{% endif %}
</button>
<!-- Mobile User Dropdown -->
<div
x-show="open"
x-transition
x-cloak
class="absolute right-0 mt-2 w-56 bg-background border rounded-md shadow-lg z-50"
>
<div class="flex items-center justify-start gap-2 p-2">
<div class="flex flex-col space-y-1 leading-none">
<p class="font-medium">{{ user.get_full_name|default:user.username }}</p>
<p class="w-[200px] truncate text-sm text-muted-foreground">{{ user.email }}</p>
</div>
</div>
<div class="border-t"></div>
<form method="post" action="{% url 'account_logout' %}">
{% csrf_token %}
<button type="submit" class="flex items-center w-full px-2 py-2 text-sm text-red-600 hover:bg-accent">
<i class="fas fa-sign-out-alt mr-2 h-4 w-4"></i>
Log out
</button>
</form>
</div>
</div>
{% else %}
<div class="flex items-center gap-1">
<c-button
variant="outline"
size="default"
hx_get="{% url 'account_login' %}"
hx_target="body"
hx_swap="beforeend"
>
Login
</c-button>
<c-button
variant="default"
size="default"
hx_get="{% url 'account_signup' %}"
hx_target="body"
hx_swap="beforeend"
>
Join
</c-button>
</div>
{% endif %}
<!-- Mobile Menu Button -->
<div x-data="{ open: false }">
<button
@click="open = !open"
class="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground h-10 w-10"
>
<i class="fas fa-bars h-5 w-5"></i>
</button>
<!-- Mobile Menu Overlay -->
<div
x-show="open"
x-transition:enter="transition-opacity ease-linear duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition-opacity ease-linear duration-300"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
x-cloak
class="fixed inset-0 z-50 bg-background/80 backdrop-blur-sm"
@click="open = false"
>
<!-- Mobile Menu Panel -->
<div
x-show="open"
x-transition:enter="transition ease-in-out duration-300 transform"
x-transition:enter-start="translate-x-full"
x-transition:enter-end="translate-x-0"
x-transition:leave="transition ease-in-out duration-300 transform"
x-transition:leave-start="translate-x-0"
x-transition:leave-end="translate-x-full"
class="fixed right-0 top-0 h-full w-full sm:w-96 bg-background border-l shadow-lg"
@click.stop
>
<div class="flex flex-col h-full">
<!-- Mobile Menu Header -->
<div class="flex items-center justify-between p-4 border-b">
<div class="flex items-center space-x-2">
<div class="w-6 h-6 bg-purple-600 rounded flex items-center justify-center">
<span class="text-white text-xs font-bold">TW</span>
</div>
<span class="font-bold text-lg">ThrillWiki</span>
</div>
<button
@click="open = false"
class="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground h-10 w-10"
>
<i class="fas fa-times h-5 w-5"></i>
</button>
</div>
<!-- Mobile Menu Content -->
<div class="flex-1 overflow-y-auto p-4 space-y-6">
<p class="text-sm text-muted-foreground">
Navigate through the ultimate theme park database
</p>
<!-- Navigation Section -->
<div>
<h3 class="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-3">
NAVIGATION
</h3>
<div class="space-y-1">
<a href="{% url 'home' %}" class="flex items-center gap-3 px-3 py-2 rounded-md hover:bg-accent transition-colors" @click="open = false">
<i class="fas fa-home w-4 h-4"></i>
<span>Home</span>
</a>
<a href="{% url 'search:search' %}" class="flex items-center gap-3 px-3 py-2 rounded-md hover:bg-accent transition-colors" @click="open = false">
<i class="fas fa-search w-4 h-4"></i>
<span>Search</span>
</a>
<a href="{% url 'parks:park_list' %}" class="flex items-center gap-3 px-3 py-2 rounded-md hover:bg-accent transition-colors" @click="open = false">
<i class="fas fa-map-marker-alt w-4 h-4"></i>
<span>Parks</span>
</a>
<a href="{% url 'rides:global_ride_list' %}" class="flex items-center gap-3 px-3 py-2 rounded-md hover:bg-accent transition-colors" @click="open = false">
<i class="fas fa-rocket w-4 h-4"></i>
<span>Rides</span>
</a>
<a href="{% url 'rides:manufacturer_list' %}" class="flex items-center gap-3 px-3 py-2 rounded-md hover:bg-accent transition-colors" @click="open = false">
<i class="fas fa-wrench w-4 h-4"></i>
<span>Manufacturers</span>
</a>
<a href="{% url 'parks:operator_list' %}" class="flex items-center gap-3 px-3 py-2 rounded-md hover:bg-accent transition-colors" @click="open = false">
<i class="fas fa-building w-4 h-4"></i>
<span>Operators</span>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Mobile Search Bar -->
<div class="md:hidden border-t bg-background">
<div class="px-4 py-3">
<div class="flex items-center gap-2 w-full">
<div class="relative flex-1">
<i class="fas fa-search absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground"></i>
<input
type="search"
placeholder="Search parks, rides..."
class="w-full pl-10 pr-3 h-10 rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
hx-get="{% url 'search:search' %}"
hx-trigger="input changed delay:300ms"
hx-target="#mobile-search-results"
hx-include="this"
name="q"
/>
</div>
<button type="submit" class="flex-shrink-0 inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 w-10">
<i class="fas fa-search h-4 w-4"></i>
</button>
</div>
<div id="mobile-search-results" class="mt-2"></div>
</div>
</div>
</header>