feat: Implement Phase 4 - Application Architecture & Routing
Phase 4 establishes the core application structure with SvelteKit routing, data loading, error handling, and state management. ## Routing & Data Loading - Created root layout load function (+layout.ts) with app version and feature flags - Implemented comprehensive error boundary (+error.svelte) with status-based messages - Added page loaders for homepage, matches, players, and about routes - Homepage loader fetches featured matches via API with error fallback - Matches loader supports URL query parameters (map, player_id, limit) ## State Management (Svelte Stores) - preferences.ts: User settings with localStorage persistence * Theme selection (cs2dark, cs2light, auto) * Favorite players tracking * Advanced stats toggle, date format preferences - search.ts: Search state with recent searches (localStorage) - toast.ts: Toast notification system with auto-dismiss * Success, error, warning, info types * Configurable duration and dismissibility ## UI Components - Toast.svelte: Individual notification with Lucide icons - ToastContainer.svelte: Fixed top-right toast display - Integrated ToastContainer into root layout ## Fixes - Fixed Svelte 5 deprecation warnings (removed <svelte:component> in runes mode) - Updated homepage to use PageData from loader - Added proper type safety across all load functions ## Testing - Type check: 0 errors, 0 warnings - Production build: Successful - All Phase 4 core objectives completed 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
49
src/lib/components/ui/Toast.svelte
Normal file
49
src/lib/components/ui/Toast.svelte
Normal file
@@ -0,0 +1,49 @@
|
||||
<script lang="ts">
|
||||
import { fly } from 'svelte/transition';
|
||||
import { CheckCircle, XCircle, AlertTriangle, Info, X } from 'lucide-svelte';
|
||||
import type { Toast } from '$lib/stores';
|
||||
|
||||
interface Props {
|
||||
toast: Toast;
|
||||
onDismiss: (id: string) => void;
|
||||
}
|
||||
|
||||
let { toast, onDismiss }: Props = $props();
|
||||
|
||||
// Icon mapping
|
||||
const icons = {
|
||||
success: CheckCircle,
|
||||
error: XCircle,
|
||||
warning: AlertTriangle,
|
||||
info: Info
|
||||
};
|
||||
|
||||
// Color mapping for DaisyUI
|
||||
const alertClasses = {
|
||||
success: 'alert-success',
|
||||
error: 'alert-error',
|
||||
warning: 'alert-warning',
|
||||
info: 'alert-info'
|
||||
};
|
||||
|
||||
const IconComponent = icons[toast.type];
|
||||
</script>
|
||||
|
||||
<div
|
||||
role="alert"
|
||||
class="alert {alertClasses[toast.type]} shadow-lg"
|
||||
transition:fly={{ y: -20, duration: 300 }}
|
||||
>
|
||||
<IconComponent class="h-6 w-6" />
|
||||
<span>{toast.message}</span>
|
||||
|
||||
{#if toast.dismissible}
|
||||
<button
|
||||
class="btn btn-circle btn-ghost btn-sm"
|
||||
onclick={() => onDismiss(toast.id)}
|
||||
aria-label="Dismiss notification"
|
||||
>
|
||||
<X class="h-4 w-4" />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
Reference in New Issue
Block a user