From 540b1c032c4817a49da106c0ea00207692e37c69 Mon Sep 17 00:00:00 2001 From: Joshua Lau Date: Mon, 1 Dec 2025 11:31:16 -0500 Subject: [PATCH 1/9] Theme settings panel --- .../lib/components/general/AppHeader.svelte | 3 +- .../lib/components/general/ModalLib.svelte | 7 +- .../general/style/ThemePanel.svelte | 191 ++++++++++++++++++ .../src/lib/components/ui/SidePanel.svelte | 75 +++++++ apps/web/src/lib/stores/panel.ts | 19 ++ apps/web/src/routes/(apps)/+layout.svelte | 2 + 6 files changed, 290 insertions(+), 7 deletions(-) create mode 100644 apps/web/src/lib/components/general/style/ThemePanel.svelte create mode 100644 apps/web/src/lib/components/ui/SidePanel.svelte create mode 100644 apps/web/src/lib/stores/panel.ts diff --git a/apps/web/src/lib/components/general/AppHeader.svelte b/apps/web/src/lib/components/general/AppHeader.svelte index 500541f4..141d637b 100644 --- a/apps/web/src/lib/components/general/AppHeader.svelte +++ b/apps/web/src/lib/components/general/AppHeader.svelte @@ -1,6 +1,7 @@ + + panelStore.close()}> +
+ +
+
+ {#if $darkTheme} + + + + {:else} + + + + {/if} + Dark Mode +
+ +
+ + +
+

+ Preset Themes +

+
+ {#each Object.entries(colorPalettes) as [name, colors]} + + {/each} +
+
+ + +
+

+ Custom Colors +

+
+ {#each Object.keys($calColors) as colorKey} +
+ updateColor(colorKey, e.currentTarget.value)} + class="w-12 h-8 rounded cursor-pointer + border border-zinc-300 dark:border-zinc-600" + /> + + {getColorLabel(colorKey)} + +
+ {/each} +
+
+ + + +
+
+ + diff --git a/apps/web/src/lib/components/ui/SidePanel.svelte b/apps/web/src/lib/components/ui/SidePanel.svelte new file mode 100644 index 00000000..eeef9a2d --- /dev/null +++ b/apps/web/src/lib/components/ui/SidePanel.svelte @@ -0,0 +1,75 @@ + + +{#if open} + + +
+ + +
+ +
+

{title}

+ +
+ + +
+ +
+
+{/if} diff --git a/apps/web/src/lib/stores/panel.ts b/apps/web/src/lib/stores/panel.ts new file mode 100644 index 00000000..f9aa1f88 --- /dev/null +++ b/apps/web/src/lib/stores/panel.ts @@ -0,0 +1,19 @@ +/** + * @file Store for managing side panel state + */ + +import { writable } from "svelte/store"; + +export type PanelType = "theme" | null; + +function createPanelStore() { + const { subscribe, set } = writable(null); + + return { + subscribe, + open: (panel: PanelType) => set(panel), + close: () => set(null) + }; +} + +export const panelStore = createPanelStore(); diff --git a/apps/web/src/routes/(apps)/+layout.svelte b/apps/web/src/routes/(apps)/+layout.svelte index 5a2f743d..b1bb5124 100644 --- a/apps/web/src/routes/(apps)/+layout.svelte +++ b/apps/web/src/routes/(apps)/+layout.svelte @@ -1,6 +1,7 @@ +
From 53a710282620aaacbd475bda5f8e4c2ca855c330 Mon Sep 17 00:00:00 2001 From: Joshua Lau Date: Mon, 1 Dec 2025 11:35:55 -0500 Subject: [PATCH 2/9] Spinning theme change and theme reset --- .../lib/components/general/AppHeader.svelte | 30 +++++++- .../general/style/ThemePanel.svelte | 76 +++++++++++++++---- 2 files changed, 90 insertions(+), 16 deletions(-) diff --git a/apps/web/src/lib/components/general/AppHeader.svelte b/apps/web/src/lib/components/general/AppHeader.svelte index 141d637b..8b6db1f0 100644 --- a/apps/web/src/lib/components/general/AppHeader.svelte +++ b/apps/web/src/lib/components/general/AppHeader.svelte @@ -14,6 +14,17 @@ }; $: cssVarStyles = getStyles("0"); + + // Spinning animation state for theme toggle + let spinning = false; + + const toggleTheme = () => { + spinning = true; + darkTheme.set(!$darkTheme); + setTimeout(() => { + spinning = false; + }, 500); + };
- - + +
+ {#if lastSelectedTheme} + + {/if} + +
@@ -188,4 +225,17 @@ hover:border-zinc-400 dark:hover:border-zinc-500 transition-colors cursor-pointer; } + + .spin { + animation: spin 0.5s ease-in-out; + } + + @keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } + } From fd52cc2bcad663a14325811cb2ee7d705c39071c Mon Sep 17 00:00:00 2001 From: Joshua Lau Date: Mon, 1 Dec 2025 11:39:12 -0500 Subject: [PATCH 3/9] Neon --- apps/web/src/lib/scripts/ReCal+/palettes.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/web/src/lib/scripts/ReCal+/palettes.ts b/apps/web/src/lib/scripts/ReCal+/palettes.ts index b2a79d87..f4199ca1 100644 --- a/apps/web/src/lib/scripts/ReCal+/palettes.ts +++ b/apps/web/src/lib/scripts/ReCal+/palettes.ts @@ -136,6 +136,17 @@ export const colorPalettes: Record = { "6": "#b61f4c", "E": "#2e0812" }, + Neon: { + "-1": "#A8A8A8", + "0": "#8a004d", + "1": "#99005c", + "2": "#a3005c", + "3": "#8a0052", + "4": "#005c99", + "5": "#00668a", + "6": "#007099", + "E": "#1a1a2e" + }, Midnight: { "-1": "#A8A8A8", "0": "#295270", From 473d3e08f800c7ab53eecdc77161ec29ecae071e Mon Sep 17 00:00:00 2001 From: Joshua Lau Date: Mon, 1 Dec 2025 11:43:52 -0500 Subject: [PATCH 4/9] Fix custom color selection --- .../general/style/ThemePanel.svelte | 62 ++++++++++++++----- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/apps/web/src/lib/components/general/style/ThemePanel.svelte b/apps/web/src/lib/components/general/style/ThemePanel.svelte index 0a8ea367..15401883 100644 --- a/apps/web/src/lib/components/general/style/ThemePanel.svelte +++ b/apps/web/src/lib/components/general/style/ThemePanel.svelte @@ -19,7 +19,7 @@ }; // Dark palettes that should auto-enable dark mode - const DARK_PALETTES = ["Midnight", "Cobalt", "Shadow", "Crimson", "Aurora"]; + const DARK_PALETTES = ["Midnight", "Cobalt", "Shadow", "Crimson", "Aurora", "Neon"]; // Track the last selected theme for "Reset to Theme" functionality let lastSelectedTheme: { name: string; colors: CalColors } | null = null; @@ -68,6 +68,7 @@ */ const resetToDefault = () => { calColors.set(DEFAULT_RCARD_COLORS); + darkTheme.set(false); lastSelectedTheme = null; }; @@ -173,23 +174,34 @@
-

+

Custom Colors

-
- {#each Object.keys($calColors) as colorKey} -
- updateColor(colorKey, e.currentTarget.value)} - class="w-12 h-8 rounded cursor-pointer - border border-zinc-300 dark:border-zinc-600" - /> - +
+ {#each Object.keys($calColors).sort((a, b) => { + if (a === "E") return 1; + if (b === "E") return 1; + if (a === "-1") return 1; + if (b === "-1") return -1; + return parseInt(a) - parseInt(b); + }) as colorKey} + {/each}
@@ -226,6 +238,28 @@ transition-colors cursor-pointer; } + .color-swatch { + @apply flex flex-col items-center gap-0.5 cursor-pointer; + } + + .color-input-wrapper { + @apply relative w-10 h-10; + } + + .color-input { + @apply absolute inset-0 w-full h-full opacity-0 cursor-pointer; + } + + .color-display { + @apply w-10 h-10 rounded-md shadow-sm + border border-zinc-400/50 + transition-all pointer-events-none; + } + + .color-swatch:hover .color-display { + @apply scale-105 border-zinc-500; + } + .spin { animation: spin 0.5s ease-in-out; } From fc4ff7e82899c65c12e06b2febe456677d91565f Mon Sep 17 00:00:00 2001 From: Joshua Lau Date: Mon, 1 Dec 2025 11:48:01 -0500 Subject: [PATCH 5/9] improve themes --- .../general/style/ThemePanel.svelte | 91 ++++++++++++------- apps/web/src/lib/scripts/ReCal+/palettes.ts | 28 +++--- 2 files changed, 71 insertions(+), 48 deletions(-) diff --git a/apps/web/src/lib/components/general/style/ThemePanel.svelte b/apps/web/src/lib/components/general/style/ThemePanel.svelte index 15401883..6d6c672c 100644 --- a/apps/web/src/lib/components/general/style/ThemePanel.svelte +++ b/apps/web/src/lib/components/general/style/ThemePanel.svelte @@ -1,7 +1,12 @@ - panelStore.close()}> + panelStore.close()}>
@@ -107,13 +123,13 @@ viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" - class="w-5 h-5 dark:text-zinc-100 {spinning ? 'spin' : ''}" - > + class="w-5 h-5 dark:text-zinc-100 {spinning + ? 'spin' + : ''}"> + d="M21.752 15.002A9.718 9.718 0 0118 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 003 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 009.002-5.998z" /> {:else} + class="w-5 h-5 dark:text-zinc-100 {spinning + ? 'spin' + : ''}"> + d="M12 3v2.25m6.364.386l-1.591 1.591M21 12h-2.25m-.386 6.364l-1.591-1.591M12 18.75V21m-4.773-4.227l-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0z" /> {/if} Dark Mode @@ -136,35 +152,37 @@
-

+

Preset Themes

{#each Object.entries(colorPalettes) as [name, colors]} @@ -174,10 +192,12 @@
-

+

Custom Colors

-
+
{#each Object.keys($calColors).sort((a, b) => { if (a === "E") return 1; if (b === "E") return 1; @@ -190,15 +210,20 @@ updateColor(colorKey, e.currentTarget.value)} - class="color-input" - /> + on:input={e => + updateColor( + colorKey, + e.currentTarget.value + )} + class="color-input" />
+ style="background-color: {hslToRGB( + $calColors[colorKey] + )}" />
- + {getColorLabel(colorKey)} @@ -213,8 +238,7 @@ on:click={resetToTheme} class="flex-1 py-2 px-3 rounded-lg text-sm font-medium bg-zinc-100 dark:bg-zinc-800 text-zinc-700 dark:text-zinc-300 - hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors" - > + hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors"> Reset to {lastSelectedTheme.name} {/if} @@ -222,8 +246,7 @@ on:click={resetToDefault} class="flex-1 py-2 px-3 rounded-lg text-sm font-medium bg-zinc-100 dark:bg-zinc-800 text-zinc-700 dark:text-zinc-300 - hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors" - > + hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors"> Reset to Default
diff --git a/apps/web/src/lib/scripts/ReCal+/palettes.ts b/apps/web/src/lib/scripts/ReCal+/palettes.ts index f4199ca1..c912eb2c 100644 --- a/apps/web/src/lib/scripts/ReCal+/palettes.ts +++ b/apps/web/src/lib/scripts/ReCal+/palettes.ts @@ -136,26 +136,26 @@ export const colorPalettes: Record = { "6": "#b61f4c", "E": "#2e0812" }, - Neon: { + Pixel: { "-1": "#A8A8A8", "0": "#8a004d", - "1": "#99005c", - "2": "#a3005c", - "3": "#8a0052", - "4": "#005c99", - "5": "#00668a", - "6": "#007099", + "1": "#005c99", + "2": "#007040", + "3": "#99005c", + "4": "#00668a", + "5": "#008050", + "6": "#a3005c", "E": "#1a1a2e" }, Midnight: { "-1": "#A8A8A8", - "0": "#295270", - "1": "#304f71", - "2": "#374c72", - "3": "#3e4a73", - "4": "#444773", - "5": "#4b4474", - "6": "#524175", + "0": "#1a5568", + "1": "#1a4a5a", + "2": "#255060", + "3": "#2a4578", + "4": "#3a3a72", + "5": "#453580", + "6": "#503570", "E": "#1a3246" }, Cobalt: { From e805474ac4acfa47c66858c7da02de5a1279db39 Mon Sep 17 00:00:00 2001 From: Joshua Lau Date: Mon, 1 Dec 2025 11:51:53 -0500 Subject: [PATCH 6/9] fix weird handlebar behavior --- .../components/recal/left/Handlebar.svelte | 24 +++++++++++++++---- .../src/lib/components/ui/SidePanel.svelte | 18 ++++++-------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/apps/web/src/lib/components/recal/left/Handlebar.svelte b/apps/web/src/lib/components/recal/left/Handlebar.svelte index fddbae5a..cda5db41 100644 --- a/apps/web/src/lib/components/recal/left/Handlebar.svelte +++ b/apps/web/src/lib/components/recal/left/Handlebar.svelte @@ -16,6 +16,11 @@ handlebarEl.setPointerCapture(e.pointerId); document.body.style.cursor = "row-resize"; document.body.style.userSelect = "none"; + + // Add window-level listeners to ensure cleanup even if pointer leaves element/window + window.addEventListener("pointermove", handlePointerMove); + window.addEventListener("pointerup", handlePointerUp); + window.addEventListener("pointercancel", handlePointerUp); } function handlePointerMove(e: PointerEvent) { @@ -38,7 +43,21 @@ function handlePointerUp(e: PointerEvent) { if (!isDragging) return; isDragging = false; - handlebarEl.releasePointerCapture(e.pointerId); + + // Clean up window-level listeners + window.removeEventListener("pointermove", handlePointerMove); + window.removeEventListener("pointerup", handlePointerUp); + window.removeEventListener("pointercancel", handlePointerUp); + + // Release pointer capture if we still have it + if (handlebarEl && e.pointerId !== undefined) { + try { + handlebarEl.releasePointerCapture(e.pointerId); + } catch { + // Pointer capture may already be released + } + } + document.body.style.cursor = ""; document.body.style.userSelect = ""; } @@ -57,9 +76,6 @@ if (!isDragging) isHovering = false; }} on:pointerdown={handlePointerDown} - on:pointermove={handlePointerMove} - on:pointerup={handlePointerUp} - on:pointercancel={handlePointerUp} on:dblclick={handleDoubleClick}>
diff --git a/apps/web/src/lib/components/ui/SidePanel.svelte b/apps/web/src/lib/components/ui/SidePanel.svelte index eeef9a2d..53527fe6 100644 --- a/apps/web/src/lib/components/ui/SidePanel.svelte +++ b/apps/web/src/lib/components/ui/SidePanel.svelte @@ -30,8 +30,7 @@
+ on:click={close} />
+ transition:fly={{ x: 320, duration: 200, opacity: 1 }}> -

{title}

From 33814ec1a730fe4de3d0092f992649c31c16f751 Mon Sep 17 00:00:00 2001 From: Joshua Lau Date: Mon, 1 Dec 2025 11:52:08 -0500 Subject: [PATCH 7/9] fmt --- apps/web/src/lib/components/general/AppHeader.svelte | 4 +--- apps/web/src/lib/components/recal/calendar/CalBox.svelte | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/web/src/lib/components/general/AppHeader.svelte b/apps/web/src/lib/components/general/AppHeader.svelte index 8b6db1f0..a6c0fa86 100644 --- a/apps/web/src/lib/components/general/AppHeader.svelte +++ b/apps/web/src/lib/components/general/AppHeader.svelte @@ -43,9 +43,7 @@ dark:border-zinc-700 border-zinc-200"