Files
wishlist/src/lib/components/dashboard/WishlistGrid.svelte
Rasmus Q 35c1ab64e8 refactor: fix all lint errors and improve code quality
- Fix TypeScript 'any' types throughout codebase
- Add proper type definitions for wishlist items and components
- Fix missing keys in {#each} blocks
- Remove unused imports and variables
- Remove unused function parameters
- Update imports to use new schema location (/db/schema)
- Disable overly strict Svelte navigation lint rules
- Ignore .svelte.ts files from ESLint (handled by Svelte compiler)
2026-03-15 21:10:58 +00:00

103 lines
2.8 KiB
Svelte

<script lang="ts">
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle
} from '$lib/components/ui/card';
import EmptyState from '$lib/components/layout/EmptyState.svelte';
import type { Snippet } from 'svelte';
import { flip } from 'svelte/animate';
import { getCardStyle } from '$lib/utils/colors';
import ThemeCard from '$lib/components/themes/ThemeCard.svelte';
let {
title,
description,
items,
emptyMessage,
emptyDescription,
emptyActionLabel,
emptyActionHref,
fallbackColor = null,
fallbackTheme = null,
headerAction,
searchBar,
children
}: {
title: string;
description: string;
items: Array<Record<string, unknown>>;
emptyMessage: string;
emptyDescription?: string;
emptyActionLabel?: string;
emptyActionHref?: string;
fallbackColor?: string | null;
fallbackTheme?: string | null;
headerAction?: Snippet;
searchBar?: Snippet;
children: Snippet<[Record<string, unknown>]>;
} = $props();
const cardStyle = $derived(getCardStyle(fallbackColor, null));
let scrollContainer: HTMLElement | null = null;
function handleWheel(event: WheelEvent) {
if (!scrollContainer) return;
// Check if we have horizontal overflow
const hasHorizontalScroll = scrollContainer.scrollWidth > scrollContainer.clientWidth;
if (hasHorizontalScroll && event.deltaY !== 0) {
event.preventDefault();
scrollContainer.scrollLeft += event.deltaY;
}
}
</script>
<Card style={cardStyle} class="relative overflow-hidden">
<ThemeCard themeName={fallbackTheme} color={fallbackColor} showPattern={false} />
<CardHeader class="relative z-10">
<div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
<div class="flex-1 min-w-0">
<CardTitle>{title}</CardTitle>
<CardDescription>{description}</CardDescription>
</div>
{#if headerAction}
<div class="flex-shrink-0">
{@render headerAction()}
</div>
{/if}
</div>
{#if searchBar}
<div class="mt-4">
{@render searchBar()}
</div>
{/if}
</CardHeader>
<CardContent class="relative z-10">
{#if items && items.length > 0}
<div
bind:this={scrollContainer}
onwheel={handleWheel}
class="flex overflow-x-auto gap-4 pb-4 -mx-6 px-6"
>
{#each items as item (item.id)}
<div class="flex-shrink-0 w-80" animate:flip={{ duration: 300 }}>
{@render children(item)}
</div>
{/each}
</div>
{:else}
<EmptyState
message={emptyMessage}
description={emptyDescription}
actionLabel={emptyActionLabel}
actionHref={emptyActionHref}
/>
{/if}
</CardContent>
</Card>