Add placeholder images, enhance alert styles, and implement theme toggle component with dark mode support

This commit is contained in:
pacnpal
2025-02-23 22:12:26 -05:00
parent 27e584f427
commit 0ba7add72f
44 changed files with 2188 additions and 227 deletions

View File

@@ -0,0 +1,176 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="csrf-token" content="{{ csrf_token() }}" />
<title>@yield('title', 'ThrillWiki')</title>
<!-- Google Fonts -->
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<!-- Prevent flash of wrong theme -->
<script>
let theme = localStorage.getItem("theme");
if (!theme) {
theme = window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
localStorage.setItem("theme", theme);
}
if (theme === "dark") {
document.documentElement.classList.add("dark");
}
</script>
<!-- HTMX -->
<script src="https://unpkg.com/htmx.org@1.9.6"></script>
<!-- Scripts and Styles (loaded via Vite) -->
@vite(['resources/js/app.js', 'resources/css/app.css'])
<!-- Font Awesome -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"
/>
<style>
.dropdown-menu {
position: absolute;
right: 0;
margin-top: 0.5rem;
width: 12rem;
border-radius: 0.375rem;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
0 4px 6px -2px rgba(0, 0, 0, 0.05);
z-index: 50;
overflow: hidden;
}
.htmx-indicator {
display: none;
}
.htmx-request .htmx-indicator {
display: block;
}
.htmx-request.htmx-indicator {
display: block;
}
</style>
@stack('styles')
</head>
<body
class="flex flex-col min-h-screen text-gray-900 bg-gradient-to-br from-white via-blue-50 to-indigo-50 dark:from-gray-950 dark:via-indigo-950 dark:to-purple-950 dark:text-white"
>
<!-- Header -->
<header
class="sticky top-0 z-40 border-b shadow-lg bg-white/90 dark:bg-gray-800/90 backdrop-blur-lg border-gray-200/50 dark:border-gray-700/50"
>
<nav class="container mx-auto nav-container">
<div class="flex items-center justify-between">
<!-- Logo -->
<div class="flex items-center">
<a
href="{{ route('home') }}"
class="font-bold text-transparent transition-transform site-logo bg-gradient-to-r from-primary to-secondary bg-clip-text hover:scale-105"
>
ThrillWiki
</a>
</div>
<!-- Navigation Links (Always Visible) -->
<div class="flex items-center space-x-2 sm:space-x-4">
<a href="{{ route('parks.index') }}" class="nav-link">
<i class="fas fa-map-marker-alt"></i>
<span>Parks</span>
</a>
<a href="{{ route('rides.index') }}" class="nav-link">
<i class="fas fa-rocket"></i>
<span>Rides</span>
</a>
</div>
<!-- Search Bar -->
<div class="flex-1 hidden max-w-md mx-8 lg:flex">
<form action="{{ route('search') }}" method="get" class="w-full">
<div class="relative">
<input
type="text"
name="q"
placeholder="Search parks and rides..."
class="form-input"
/>
</div>
</form>
</div>
<!-- Right Side Menu -->
<div class="flex items-center space-x-2 sm:space-x-6">
<!-- Theme Toggle -->
<livewire:theme-toggle-component />
<!-- User Menu -->
@auth
@if(auth()->user()->can('access-moderation'))
<a href="{{ route('moderation.dashboard') }}" class="nav-link">
<i class="fas fa-shield-alt"></i>
<span>Moderation</span>
</a>
@endif
<livewire:user-menu-component />
@else
<!-- Generic Profile Icon for Unauthenticated Users -->
<livewire:auth-menu-component />
@endauth
<!-- Mobile Menu -->
<livewire:mobile-menu-component />
</div>
</div>
</nav>
</header>
<!-- Flash Messages -->
@if (session('status'))
<div class="fixed top-0 right-0 z-50 p-4 space-y-4">
<div class="alert alert-success">
{{ session('status') }}
</div>
</div>
@endif
<!-- Main Content -->
<main class="container flex-grow px-6 py-8 mx-auto">
{{ $slot }}
</main>
<!-- Footer -->
<footer
class="mt-auto border-t bg-white/90 dark:bg-gray-800/90 backdrop-blur-lg border-gray-200/50 dark:border-gray-700/50"
>
<div class="container px-6 py-6 mx-auto">
<div class="flex items-center justify-between">
<div class="text-gray-600 dark:text-gray-400">
<p>&copy; {{ date('Y') }} ThrillWiki. All rights reserved.</p>
</div>
<div class="space-x-4">
<a
href="{{ route('terms') }}"
class="text-gray-600 transition-colors hover:text-primary dark:text-gray-400 dark:hover:text-primary"
>Terms</a>
<a
href="{{ route('privacy') }}"
class="text-gray-600 transition-colors hover:text-primary dark:text-gray-400 dark:hover:text-primary"
>Privacy</a>
</div>
</div>
</div>
</footer>
@stack('scripts')
</body>
</html>

View File

@@ -0,0 +1,34 @@
<div class="relative">
<div
wire:click="toggle"
class="flex items-center justify-center w-8 h-8 text-gray-500 transition-transform rounded-full cursor-pointer hover:text-primary dark:text-gray-400 dark:hover:text-primary hover:scale-105"
>
<i class="text-xl fas fa-user"></i>
</div>
<!-- Auth Menu -->
<div
wire:model="isOpen"
class="bg-white dropdown-menu dark:bg-gray-800"
style="display: {{ $isOpen ? 'block' : 'none' }}"
>
<div
hx-get="{{ route('login') }}"
hx-target="body"
hx-swap="beforeend"
class="cursor-pointer menu-item"
>
<i class="w-5 fas fa-sign-in-alt"></i>
<span>Login</span>
</div>
<div
hx-get="{{ route('register') }}"
hx-target="body"
hx-swap="beforeend"
class="cursor-pointer menu-item"
>
<i class="w-5 fas fa-user-plus"></i>
<span>Register</span>
</div>
</div>
</div>

View File

@@ -1,7 +1,8 @@
<div>
<h1>{{ $count }}</h1>
<button wire:click="increment">+</button>
<button wire:click="decrement">-</button>
<div class="flex flex-col items-center justify-center p-6 space-y-4">
<h1 class="text-4xl font-bold">{{ $count }}</h1>
<div class="flex space-x-4">
<button wire:click="increment" class="px-4 py-2 text-white bg-blue-500 rounded hover:bg-blue-600">+</button>
<button wire:click="decrement" class="px-4 py-2 text-white bg-red-500 rounded hover:bg-red-600">-</button>
</div>
</div>

View File

@@ -0,0 +1,39 @@
<div>
<button
wire:click="toggle"
class="p-2 text-gray-500 rounded-lg lg:hidden hover:bg-gray-100 dark:hover:bg-gray-700 dark:text-gray-400"
aria-label="Toggle mobile menu"
aria-expanded="{{ $isOpen }}"
>
<i class="text-2xl fas {{ $isOpen ? 'fa-times' : 'fa-bars' }}"></i>
</button>
<!-- Mobile Menu -->
<div
wire:model="isOpen"
class="absolute left-0 right-0 w-full p-4 mt-2 space-y-4 bg-white border-b dark:bg-gray-800 dark:border-gray-700"
style="display: {{ $isOpen ? 'block' : 'none' }}"
>
<!-- Search (Mobile) -->
<form action="{{ route('search') }}" method="get" class="mb-4">
<input
type="text"
name="q"
placeholder="Search parks and rides..."
class="form-input"
/>
</form>
<!-- Mobile Navigation Links -->
<nav class="space-y-2">
<a href="{{ route('parks.index') }}" class="block nav-link">
<i class="fas fa-map-marker-alt"></i>
<span>Parks</span>
</a>
<a href="{{ route('rides.index') }}" class="block nav-link">
<i class="fas fa-rocket"></i>
<span>Rides</span>
</a>
</nav>
</div>
</div>

View File

@@ -0,0 +1,28 @@
<label for="theme-toggle" class="cursor-pointer">
<input
type="checkbox"
id="theme-toggle"
class="hidden"
wire:model.live="isDark"
wire:change="toggleTheme"
>
<div
class="inline-flex items-center justify-center p-2 text-gray-500 transition-colors hover:text-primary dark:text-gray-400 dark:hover:text-primary theme-toggle-btn"
role="button"
aria-label="Toggle dark mode"
>
<i class="text-xl fas {{ $isDark ? 'fa-sun' : 'fa-moon' }}"></i>
</div>
</label>
<script>
document.addEventListener('livewire:init', () => {
Livewire.on('theme-changed', ({ theme }) => {
if (theme === 'dark') {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
});
});
</script>

View File

@@ -0,0 +1,47 @@
<div class="relative">
<!-- Profile Picture Button -->
@if(auth()->user()->profile?->avatar)
<img
wire:click="toggle"
src="{{ auth()->user()->profile->avatar }}"
alt="{{ auth()->user()->username }}"
class="w-8 h-8 transition-transform rounded-full cursor-pointer ring-2 ring-primary/20 hover:scale-105"
/>
@else
<div
wire:click="toggle"
class="flex items-center justify-center w-8 h-8 text-white transition-transform rounded-full cursor-pointer bg-gradient-to-br from-primary to-secondary hover:scale-105"
>
{{ ucfirst(auth()->user()->username[0]) }}
</div>
@endif
<!-- Dropdown Menu -->
<div
wire:model="isOpen"
class="bg-white dropdown-menu dark:bg-gray-800"
style="display: {{ $isOpen ? 'block' : 'none' }}"
>
<a href="{{ route('profile.show', auth()->user()->username) }}" class="menu-item">
<i class="w-5 fas fa-user"></i>
<span>Profile</span>
</a>
<a href="{{ route('settings') }}" class="menu-item">
<i class="w-5 fas fa-cog"></i>
<span>Settings</span>
</a>
@if(auth()->user()->can('access-admin'))
<a href="{{ route('admin.index') }}" class="menu-item">
<i class="w-5 fas fa-shield-alt"></i>
<span>Admin</span>
</a>
@endif
<form method="POST" action="{{ route('logout') }}">
@csrf
<button type="submit" class="w-full menu-item">
<i class="w-5 fas fa-sign-out-alt"></i>
<span>Logout</span>
</button>
</form>
</div>
</div>