From 7c6ff9458f77355cd8bbf7ddbdfc4fff50dbb717 Mon Sep 17 00:00:00 2001 From: rasmusq Date: Fri, 28 Nov 2025 00:26:43 +0100 Subject: [PATCH] wip: not loading themes until reload, missing in dashboard, bad alignment and scaling --- .../components/dashboard/WishlistCard.svelte | 10 ++- .../dashboard/WishlistSection.svelte | 1 + .../components/layout/DashboardHeader.svelte | 33 ++++++++- .../components/layout/PageContainer.svelte | 18 ++++- .../components/themes/ThemeBackground.svelte | 37 ++++++++++ src/lib/components/themes/ThemeCard.svelte | 23 +++++++ .../themes/svgs/BottomPattern.svelte | 38 +++++++++++ .../components/themes/svgs/CardPattern.svelte | 38 +++++++++++ .../components/themes/svgs/TopPattern.svelte | 38 +++++++++++ src/lib/components/ui/theme-picker.svelte | 68 +++++++++++++++++++ .../wishlist/EditableItemsList.svelte | 6 +- .../components/wishlist/WishlistHeader.svelte | 17 ++++- .../components/wishlist/WishlistItem.svelte | 8 ++- src/lib/server/schema.ts | 4 +- src/lib/utils/themes.ts | 51 ++++++++++++++ src/lib/utils/wishlistUpdates.ts | 4 ++ src/routes/dashboard/+page.server.ts | 22 +++++- src/routes/dashboard/+page.svelte | 8 ++- src/routes/wishlist/[token]/+page.svelte | 4 +- .../wishlist/[token]/edit/+page.server.ts | 5 ++ src/routes/wishlist/[token]/edit/+page.svelte | 4 +- 21 files changed, 417 insertions(+), 20 deletions(-) create mode 100644 src/lib/components/themes/ThemeBackground.svelte create mode 100644 src/lib/components/themes/ThemeCard.svelte create mode 100644 src/lib/components/themes/svgs/BottomPattern.svelte create mode 100644 src/lib/components/themes/svgs/CardPattern.svelte create mode 100644 src/lib/components/themes/svgs/TopPattern.svelte create mode 100644 src/lib/components/ui/theme-picker.svelte create mode 100644 src/lib/utils/themes.ts diff --git a/src/lib/components/dashboard/WishlistCard.svelte b/src/lib/components/dashboard/WishlistCard.svelte index b74e0e5..3d94650 100644 --- a/src/lib/components/dashboard/WishlistCard.svelte +++ b/src/lib/components/dashboard/WishlistCard.svelte @@ -3,26 +3,30 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '$lib/components/ui/card'; import type { Snippet } from 'svelte'; import { getCardStyle } from '$lib/utils/colors'; + import ThemeCard from '$lib/components/themes/ThemeCard.svelte'; let { title, description, itemCount, color = null, + theme = null, children }: { title: string; description?: string | null; itemCount: number; color?: string | null; + theme?: string | null; children?: Snippet; } = $props(); const cardStyle = $derived(getCardStyle(color)); - - + + +
{title} @@ -35,7 +39,7 @@ {description} {/if} - + {#if children}
{@render children()} diff --git a/src/lib/components/dashboard/WishlistSection.svelte b/src/lib/components/dashboard/WishlistSection.svelte index 396d3d4..53c664e 100644 --- a/src/lib/components/dashboard/WishlistSection.svelte +++ b/src/lib/components/dashboard/WishlistSection.svelte @@ -149,6 +149,7 @@ description={getWishlistDescription(item)} itemCount={wishlist.items?.length || 0} color={wishlist.color} + theme={wishlist.theme} > {@render actions(item, unlocked)} diff --git a/src/lib/components/layout/DashboardHeader.svelte b/src/lib/components/layout/DashboardHeader.svelte index 83b8943..7d06297 100644 --- a/src/lib/components/layout/DashboardHeader.svelte +++ b/src/lib/components/layout/DashboardHeader.svelte @@ -2,13 +2,41 @@ import { Button } from '$lib/components/ui/button'; import { ThemeToggle } from '$lib/components/ui/theme-toggle'; import { LanguageToggle } from '$lib/components/ui/language-toggle'; + import ThemePicker from '$lib/components/ui/theme-picker.svelte'; import { signOut } from '@auth/sveltekit/client'; import { languageStore } from '$lib/stores/language.svelte'; + import { enhance } from '$app/forms'; - let { userName, userEmail }: { userName?: string | null; userEmail?: string | null } = $props(); + let { + userName, + userEmail, + dashboardTheme = 'none' + }: { + userName?: string | null; + userEmail?: string | null; + dashboardTheme?: string; + } = $props(); const t = $derived(languageStore.t); const isAuthenticated = $derived(!!userName || !!userEmail); + + let currentTheme = $state(dashboardTheme); + + async function handleThemeChange(theme: string) { + currentTheme = theme; + + // Submit form to update theme + const formData = new FormData(); + formData.append('theme', theme); + + await fetch('?/updateDashboardTheme', { + method: 'POST', + body: formData + }); + + // Reload to apply new theme + window.location.reload(); + }
@@ -21,6 +49,9 @@ {/if}
+ {#if isAuthenticated} + + {/if} {#if isAuthenticated} diff --git a/src/lib/components/layout/PageContainer.svelte b/src/lib/components/layout/PageContainer.svelte index 844e8d0..135bd8c 100644 --- a/src/lib/components/layout/PageContainer.svelte +++ b/src/lib/components/layout/PageContainer.svelte @@ -1,11 +1,23 @@ -
-
+
+ +
{@render children()}
diff --git a/src/lib/components/themes/ThemeBackground.svelte b/src/lib/components/themes/ThemeBackground.svelte new file mode 100644 index 0000000..f983a58 --- /dev/null +++ b/src/lib/components/themes/ThemeBackground.svelte @@ -0,0 +1,37 @@ + + +{#if theme.pattern !== 'none'} + {#if showTop} + + {/if} + {#if showBottom} + + {/if} +{/if} diff --git a/src/lib/components/themes/ThemeCard.svelte b/src/lib/components/themes/ThemeCard.svelte new file mode 100644 index 0000000..0a3c685 --- /dev/null +++ b/src/lib/components/themes/ThemeCard.svelte @@ -0,0 +1,23 @@ + + +{#if theme.pattern !== 'none'} + +{/if} diff --git a/src/lib/components/themes/svgs/BottomPattern.svelte b/src/lib/components/themes/svgs/BottomPattern.svelte new file mode 100644 index 0000000..1e696d7 --- /dev/null +++ b/src/lib/components/themes/svgs/BottomPattern.svelte @@ -0,0 +1,38 @@ + + +
+ {#if pattern === 'waves'} + + + + {:else if pattern === 'geometric'} + + + + {:else if pattern === 'dots'} + + + + + + + + + {/if} +
diff --git a/src/lib/components/themes/svgs/CardPattern.svelte b/src/lib/components/themes/svgs/CardPattern.svelte new file mode 100644 index 0000000..6c00a8c --- /dev/null +++ b/src/lib/components/themes/svgs/CardPattern.svelte @@ -0,0 +1,38 @@ + + +
+ {#if pattern === 'waves'} + + + + {:else if pattern === 'geometric'} + + + + {:else if pattern === 'dots'} + + + + + + + + + {/if} +
diff --git a/src/lib/components/themes/svgs/TopPattern.svelte b/src/lib/components/themes/svgs/TopPattern.svelte new file mode 100644 index 0000000..3aa0247 --- /dev/null +++ b/src/lib/components/themes/svgs/TopPattern.svelte @@ -0,0 +1,38 @@ + + +
+ {#if pattern === 'waves'} + + + + {:else if pattern === 'geometric'} + + + + {:else if pattern === 'dots'} + + + + + + + + + {/if} +
diff --git a/src/lib/components/ui/theme-picker.svelte b/src/lib/components/ui/theme-picker.svelte new file mode 100644 index 0000000..4f93363 --- /dev/null +++ b/src/lib/components/ui/theme-picker.svelte @@ -0,0 +1,68 @@ + + +
+ + + {#if showMenu} +
+
+ {#each Object.entries(AVAILABLE_THEMES) as [key, theme]} + + {/each} +
+
+ {/if} +
diff --git a/src/lib/components/wishlist/EditableItemsList.svelte b/src/lib/components/wishlist/EditableItemsList.svelte index 1ef8374..dbdc6fc 100644 --- a/src/lib/components/wishlist/EditableItemsList.svelte +++ b/src/lib/components/wishlist/EditableItemsList.svelte @@ -12,12 +12,14 @@ items = $bindable([]), rearranging, onStartEditing, - onReorder + onReorder, + theme = null }: { items: Item[]; rearranging: boolean; onStartEditing: (item: Item) => void; onReorder: (items: Item[]) => Promise; + theme?: string | null; } = $props(); const t = $derived(languageStore.t); @@ -28,7 +30,7 @@
{#each items as item (item.id)}
- +
-
+
+ { + wishlistTheme = theme; + await onThemeUpdate(theme); + // Force reactivity by updating the wishlist object + wishlist.theme = theme; + }} + /> onColorUpdate(wishlistColor)} diff --git a/src/lib/components/wishlist/WishlistItem.svelte b/src/lib/components/wishlist/WishlistItem.svelte index ed22299..b4e0461 100644 --- a/src/lib/components/wishlist/WishlistItem.svelte +++ b/src/lib/components/wishlist/WishlistItem.svelte @@ -5,12 +5,14 @@ import { getCardStyle } from '$lib/utils/colors'; import { Button } from "$lib/components/ui/button"; import { languageStore } from '$lib/stores/language.svelte'; + import ThemeCard from '$lib/components/themes/ThemeCard.svelte'; interface Props { item: Item; showImage?: boolean; children?: any; showDragHandle?: boolean; + theme?: string | null; } let { @@ -18,6 +20,7 @@ showImage = true, children, showDragHandle = false, + theme = null }: Props = $props(); const t = $derived(languageStore.t); @@ -51,8 +54,9 @@ const cardStyle = $derived(getCardStyle(item.color)); - - + + +
{#if showDragHandle}
= { + none: { + name: 'None', + pattern: 'none', + opacity: 0 + }, + waves: { + name: 'Waves', + pattern: 'waves', + opacity: 0.1 + }, + geometric: { + name: 'Geometric', + pattern: 'geometric', + opacity: 0.1 + }, + dots: { + name: 'Dots', + pattern: 'dots', + opacity: 0.15 + } +}; + +export const DEFAULT_THEME = 'none'; + +export function getTheme(themeName?: string | null): Theme { + if (!themeName || !AVAILABLE_THEMES[themeName]) { + return AVAILABLE_THEMES[DEFAULT_THEME]; + } + return AVAILABLE_THEMES[themeName]; +} + +/** + * Get color from a CSS color string or class + * For now, we'll use currentColor which inherits from the parent + */ +export function getThemeColor(color?: string | null): string { + return color || 'currentColor'; +} diff --git a/src/lib/utils/wishlistUpdates.ts b/src/lib/utils/wishlistUpdates.ts index bd0f9d2..184ffd9 100644 --- a/src/lib/utils/wishlistUpdates.ts +++ b/src/lib/utils/wishlistUpdates.ts @@ -38,6 +38,10 @@ export async function updateEndDate(endDate: string | null): Promise { return updateWishlist({ endDate: endDate || "" }); } +export async function updateTheme(theme: string | null): Promise { + return updateWishlist({ theme: theme || "none" }); +} + export async function reorderItems(items: Array<{ id: string; order: number }>): Promise { const response = await fetch("?/reorderItems", { method: "POST", diff --git a/src/routes/dashboard/+page.server.ts b/src/routes/dashboard/+page.server.ts index 0e2bb3c..358e14e 100644 --- a/src/routes/dashboard/+page.server.ts +++ b/src/routes/dashboard/+page.server.ts @@ -1,7 +1,7 @@ import { redirect } from '@sveltejs/kit'; import type { PageServerLoad, Actions } from './$types'; import { db } from '$lib/server/db'; -import { wishlists, savedWishlists } from '$lib/server/schema'; +import { wishlists, savedWishlists, users } from '$lib/server/schema'; import { eq, and } from 'drizzle-orm'; export const load: PageServerLoad = async (event) => { @@ -149,6 +149,26 @@ export const actions: Actions = { eq(wishlists.userId, session.user.id) )); + return { success: true }; + }, + + updateDashboardTheme: async ({ request, locals }) => { + const session = await locals.auth(); + if (!session?.user?.id) { + throw redirect(303, '/signin'); + } + + const formData = await request.formData(); + const theme = formData.get('theme') as string; + + if (!theme) { + return { success: false, error: 'Theme is required' }; + } + + await db.update(users) + .set({ dashboardTheme: theme }) + .where(eq(users.id, session.user.id)); + return { success: true }; } }; diff --git a/src/routes/dashboard/+page.svelte b/src/routes/dashboard/+page.svelte index 4ecbc3c..3eba68c 100644 --- a/src/routes/dashboard/+page.svelte +++ b/src/routes/dashboard/+page.svelte @@ -34,8 +34,12 @@ }); - - + + diff --git a/src/routes/wishlist/[token]/+page.svelte b/src/routes/wishlist/[token]/+page.svelte index 81199df..da74e6a 100644 --- a/src/routes/wishlist/[token]/+page.svelte +++ b/src/routes/wishlist/[token]/+page.svelte @@ -35,7 +35,7 @@ ); - + {#if filteredItems.length > 0} {#each filteredItems as item} - + - +