From 96e0aceb93a7eb1ad756e49c39ba08021379ee1e Mon Sep 17 00:00:00 2001 From: Till-JS <101404291+Till-JS@users.noreply.github.com> Date: Mon, 24 Nov 2025 21:51:24 +0100 Subject: [PATCH] feat: implement unified theme system across all web apps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SUMMARY: Create a unified theming architecture with two new shared packages (@manacore/shared-theme and @manacore/shared-theme-ui) that provides consistent theming across all 4 web applications while allowing app-specific primary color customization. NEW PACKAGES: @manacore/shared-theme: - Svelte 5 Runes-based theme store factory - 4 theme variants: Lume (Gold), Nature (Green), Stone (Blue Gray), Ocean (Blue) - 3 theme modes: Light, Dark, System (auto-detect) - HSL-based color system with 18 semantic tokens - localStorage persistence per app - System preference detection via matchMedia - Pre-defined configs for all apps (memoro, manacore, manadeck, maerchenzauber) @manacore/shared-theme-ui: - ThemeToggle: Light/dark mode toggle button - ThemeSelector: Visual theme variant selector with color dots - ThemeModeSelector: Segmented control for light/dark/system UPDATED PACKAGES: @manacore/shared-tailwind: - Converted from HEX to HSL-based CSS variables - Updated preset.js with hsl(var(--color-*)) syntax - themes.css now contains all 4 theme variants with light/dark modes APP MIGRATIONS: memoro/web: - Replaced 145 LOC theme store with 25 LOC shared implementation - Deleted local ThemeSelector.svelte and ThemeToggle.svelte - Primary color: Gold (47 95% 58%) manacore/web: - Replaced 80 LOC theme store with 25 LOC shared implementation - Deleted local ThemeToggle.svelte - Primary color: Indigo (239 84% 67%) manadeck/web: - Added new theme store using shared package - Primary color: Indigo (239 84% 67%) maerchenzauber/web: - Added new theme store using shared package - Primary color: Purple (280 60% 55%) All app layouts updated with theme.initialize() in onMount. BENEFITS: - ~225 LOC of app-specific code reduced to ~100 LOC total - Single source of truth for theme logic - Consistent theming experience across all apps - Easy to add new theme variants - App-specific primary colors preserved 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- SHARED_PACKAGES_ROADMAP.md | 4 +- .../apps/web/src/lib/stores/theme.ts | 25 + .../apps/web/src/routes/+layout.svelte | 7 + .../web/src/lib/components/ThemeToggle.svelte | 40 - manacore/apps/web/src/lib/stores/theme.ts | 100 +- manacore/apps/web/src/routes/+layout.svelte | 10 +- manadeck/apps/web/src/lib/stores/theme.ts | 25 + manadeck/apps/web/src/routes/+layout.svelte | 7 + .../src/lib/components/ThemeSelector.svelte | 233 ----- .../web/src/lib/components/ThemeToggle.svelte | 40 - memoro/apps/web/src/lib/stores/theme.ts | 165 +--- memoro/apps/web/src/routes/+layout.svelte | 34 - package.json | 5 +- packages/shared-tailwind/src/preset.js | 184 ++-- packages/shared-tailwind/src/themes.css | 641 ++++++++----- packages/shared-theme-ui/README.md | 170 ++++ packages/shared-theme-ui/package.json | 25 + .../src/ThemeModeSelector.svelte | 87 ++ .../shared-theme-ui/src/ThemeSelector.svelte | 125 +++ .../shared-theme-ui/src/ThemeToggle.svelte | 74 ++ packages/shared-theme-ui/src/index.ts | 4 + packages/shared-theme-ui/tsconfig.json | 15 + packages/shared-theme/README.md | 225 +++++ packages/shared-theme/package.json | 22 + packages/shared-theme/src/constants.ts | 244 +++++ packages/shared-theme/src/index.ts | 43 + packages/shared-theme/src/store.svelte.ts | 227 +++++ packages/shared-theme/src/types.ts | 133 +++ packages/shared-theme/src/utils.ts | 245 +++++ packages/shared-theme/tsconfig.json | 16 + pnpm-lock.yaml | 907 ++++++++++++++---- 31 files changed, 2993 insertions(+), 1089 deletions(-) create mode 100644 maerchenzauber/apps/web/src/lib/stores/theme.ts delete mode 100644 manacore/apps/web/src/lib/components/ThemeToggle.svelte create mode 100644 manadeck/apps/web/src/lib/stores/theme.ts delete mode 100644 memoro/apps/web/src/lib/components/ThemeSelector.svelte delete mode 100644 memoro/apps/web/src/lib/components/ThemeToggle.svelte create mode 100644 packages/shared-theme-ui/README.md create mode 100644 packages/shared-theme-ui/package.json create mode 100644 packages/shared-theme-ui/src/ThemeModeSelector.svelte create mode 100644 packages/shared-theme-ui/src/ThemeSelector.svelte create mode 100644 packages/shared-theme-ui/src/ThemeToggle.svelte create mode 100644 packages/shared-theme-ui/src/index.ts create mode 100644 packages/shared-theme-ui/tsconfig.json create mode 100644 packages/shared-theme/README.md create mode 100644 packages/shared-theme/package.json create mode 100644 packages/shared-theme/src/constants.ts create mode 100644 packages/shared-theme/src/index.ts create mode 100644 packages/shared-theme/src/store.svelte.ts create mode 100644 packages/shared-theme/src/types.ts create mode 100644 packages/shared-theme/src/utils.ts create mode 100644 packages/shared-theme/tsconfig.json diff --git a/SHARED_PACKAGES_ROADMAP.md b/SHARED_PACKAGES_ROADMAP.md index e17853bdf..205ee4c0d 100644 --- a/SHARED_PACKAGES_ROADMAP.md +++ b/SHARED_PACKAGES_ROADMAP.md @@ -8,7 +8,9 @@ This document outlines the plan to unify common code across all web apps in the - [x] `@manacore/shared-ui` - Unified UI Components (Text, Button, Badge, Toggle, Input, Modal) - [x] `@manacore/shared-auth` - Unified Auth Logic (Supabase client, token management) - [x] `@manacore/shared-auth-ui` - Unified Auth UI (LoginPage, RegisterPage, OAuth buttons) -- [x] `@manacore/shared-tailwind` - Unified Tailwind Config (4 themes, colors, preset) +- [x] `@manacore/shared-tailwind` - Unified Tailwind Config (HSL colors, preset, themes.css) +- [x] `@manacore/shared-theme` - **NEW** Unified Theme Store (Svelte 5, 4 variants, light/dark/system) +- [x] `@manacore/shared-theme-ui` - **NEW** Theme UI Components (ThemeToggle, ThemeSelector) - [x] `@manacore/shared-utils` - Unified Utilities (formatting, validation, async) - [x] `@manacore/shared-types` - Unified TypeScript Types - [x] `@manacore/shared-supabase` - Unified Supabase Client Factory diff --git a/maerchenzauber/apps/web/src/lib/stores/theme.ts b/maerchenzauber/apps/web/src/lib/stores/theme.ts new file mode 100644 index 000000000..5199b59aa --- /dev/null +++ b/maerchenzauber/apps/web/src/lib/stores/theme.ts @@ -0,0 +1,25 @@ +/** + * Maerchenzauber (Storyteller) Theme Store + * + * Uses the shared theme system with a magical purple primary color. + */ +import { createThemeStore } from '@manacore/shared-theme'; + +// Re-export types for convenience +export type { ThemeMode, ThemeVariant, EffectiveMode } from '@manacore/shared-theme'; + +/** + * Maerchenzauber theme store instance + * + * - Default variant: nature (green - enchanted forest feel) + * - Custom primary: Purple (magical storytelling) + * - All 4 theme variants available + */ +export const theme = createThemeStore({ + appId: 'maerchenzauber', + defaultVariant: 'nature', + primaryColor: { + light: '280 60% 55%', // Purple - magical/storytelling + dark: '280 60% 60%', + }, +}); diff --git a/maerchenzauber/apps/web/src/routes/+layout.svelte b/maerchenzauber/apps/web/src/routes/+layout.svelte index a50d72603..5067c4bbf 100644 --- a/maerchenzauber/apps/web/src/routes/+layout.svelte +++ b/maerchenzauber/apps/web/src/routes/+layout.svelte @@ -1,8 +1,15 @@ diff --git a/manacore/apps/web/src/lib/components/ThemeToggle.svelte b/manacore/apps/web/src/lib/components/ThemeToggle.svelte deleted file mode 100644 index 0039644f7..000000000 --- a/manacore/apps/web/src/lib/components/ThemeToggle.svelte +++ /dev/null @@ -1,40 +0,0 @@ - - - diff --git a/manacore/apps/web/src/lib/stores/theme.ts b/manacore/apps/web/src/lib/stores/theme.ts index 27c2fb90d..7f463e876 100644 --- a/manacore/apps/web/src/lib/stores/theme.ts +++ b/manacore/apps/web/src/lib/stores/theme.ts @@ -1,79 +1,25 @@ -import { writable, derived } from 'svelte/store'; -import { browser } from '$app/environment'; +/** + * ManaCore Theme Store + * + * Uses the shared theme system with ManaCore's indigo primary color. + */ +import { createThemeStore } from '@manacore/shared-theme'; -type ThemeMode = 'light' | 'dark' | 'system'; +// Re-export types for convenience +export type { ThemeMode, ThemeVariant, EffectiveMode } from '@manacore/shared-theme'; -interface ThemeState { - mode: ThemeMode; - effectiveMode: 'light' | 'dark'; -} - -function createThemeStore() { - const getInitialMode = (): ThemeMode => { - if (browser) { - const stored = localStorage.getItem('theme-mode'); - if (stored === 'light' || stored === 'dark' || stored === 'system') { - return stored; - } - } - return 'system'; - }; - - const getSystemPreference = (): 'light' | 'dark' => { - if (browser && window.matchMedia('(prefers-color-scheme: dark)').matches) { - return 'dark'; - } - return 'light'; - }; - - const mode = writable(getInitialMode()); - - const effectiveMode = derived(mode, ($mode) => { - if ($mode === 'system') { - return getSystemPreference(); - } - return $mode; - }); - - const state = derived([mode, effectiveMode], ([$mode, $effectiveMode]) => ({ - mode: $mode, - effectiveMode: $effectiveMode - })); - - // Apply theme to document - if (browser) { - effectiveMode.subscribe((effective) => { - if (effective === 'dark') { - document.documentElement.classList.add('dark'); - } else { - document.documentElement.classList.remove('dark'); - } - }); - - // Listen for system preference changes - window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { - mode.update((m) => m); // Trigger re-evaluation - }); - } - - return { - subscribe: state.subscribe, - setMode: (newMode: ThemeMode) => { - mode.set(newMode); - if (browser) { - localStorage.setItem('theme-mode', newMode); - } - }, - toggleMode: () => { - mode.update((current) => { - const newMode = current === 'light' ? 'dark' : current === 'dark' ? 'system' : 'light'; - if (browser) { - localStorage.setItem('theme-mode', newMode); - } - return newMode; - }); - } - }; -} - -export const theme = createThemeStore(); +/** + * ManaCore theme store instance + * + * - Default variant: ocean (blue) + * - Custom primary: Indigo (#6366f1) + * - All 4 theme variants available + */ +export const theme = createThemeStore({ + appId: 'manacore', + defaultVariant: 'ocean', + primaryColor: { + light: '239 84% 67%', // Indigo #6366f1 + dark: '239 84% 67%', + }, +}); diff --git a/manacore/apps/web/src/routes/+layout.svelte b/manacore/apps/web/src/routes/+layout.svelte index 8fd039713..85a61a32f 100644 --- a/manacore/apps/web/src/routes/+layout.svelte +++ b/manacore/apps/web/src/routes/+layout.svelte @@ -2,10 +2,15 @@ import '../app.css'; import { invalidate } from '$app/navigation'; import { onMount } from 'svelte'; + import { theme } from '$lib/stores/theme'; let { data, children } = $props(); onMount(() => { + // Initialize theme + const cleanupTheme = theme.initialize(); + + // Setup auth state change listener const { data: { subscription } } = data.supabase.auth.onAuthStateChange(async (event, session) => { @@ -16,7 +21,10 @@ } }); - return () => subscription.unsubscribe(); + return () => { + cleanupTheme(); + subscription.unsubscribe(); + }; }); diff --git a/manadeck/apps/web/src/lib/stores/theme.ts b/manadeck/apps/web/src/lib/stores/theme.ts new file mode 100644 index 000000000..403feefc3 --- /dev/null +++ b/manadeck/apps/web/src/lib/stores/theme.ts @@ -0,0 +1,25 @@ +/** + * ManaDeck Theme Store + * + * Uses the shared theme system with ManaDeck's indigo primary color. + */ +import { createThemeStore } from '@manacore/shared-theme'; + +// Re-export types for convenience +export type { ThemeMode, ThemeVariant, EffectiveMode } from '@manacore/shared-theme'; + +/** + * ManaDeck theme store instance + * + * - Default variant: ocean (blue) + * - Custom primary: Indigo (#6366f1) + * - All 4 theme variants available + */ +export const theme = createThemeStore({ + appId: 'manadeck', + defaultVariant: 'ocean', + primaryColor: { + light: '239 84% 67%', // Indigo #6366f1 + dark: '239 84% 67%', + }, +}); diff --git a/manadeck/apps/web/src/routes/+layout.svelte b/manadeck/apps/web/src/routes/+layout.svelte index a50d72603..5067c4bbf 100644 --- a/manadeck/apps/web/src/routes/+layout.svelte +++ b/manadeck/apps/web/src/routes/+layout.svelte @@ -1,8 +1,15 @@ diff --git a/memoro/apps/web/src/lib/components/ThemeSelector.svelte b/memoro/apps/web/src/lib/components/ThemeSelector.svelte deleted file mode 100644 index 07dc114f7..000000000 --- a/memoro/apps/web/src/lib/components/ThemeSelector.svelte +++ /dev/null @@ -1,233 +0,0 @@ - - -
- - - {#if isOpen} - - {/if} -
- - diff --git a/memoro/apps/web/src/lib/components/ThemeToggle.svelte b/memoro/apps/web/src/lib/components/ThemeToggle.svelte deleted file mode 100644 index ee67f2ce5..000000000 --- a/memoro/apps/web/src/lib/components/ThemeToggle.svelte +++ /dev/null @@ -1,40 +0,0 @@ - - - diff --git a/memoro/apps/web/src/lib/stores/theme.ts b/memoro/apps/web/src/lib/stores/theme.ts index 8c9af6817..ad6d936cc 100644 --- a/memoro/apps/web/src/lib/stores/theme.ts +++ b/memoro/apps/web/src/lib/stores/theme.ts @@ -1,144 +1,25 @@ -import { writable } from 'svelte/store'; -import { browser } from '$app/environment'; +/** + * Memoro Theme Store + * + * Uses the shared theme system with Memoro's gold primary color. + */ +import { createThemeStore } from '@manacore/shared-theme'; -export type ThemeMode = 'light' | 'dark' | 'system'; -export type ThemeVariant = 'lume' | 'nature' | 'ocean' | 'stone'; +// Re-export types for convenience +export type { ThemeMode, ThemeVariant, EffectiveMode } from '@manacore/shared-theme'; -interface ThemeState { - mode: ThemeMode; - variant: ThemeVariant; - // The actual rendered mode (light or dark), derived from mode and system preference - effectiveMode: 'light' | 'dark'; -} - -const THEME_STORAGE_KEY = 'memoro-theme'; - -// Get initial theme from localStorage or system preference -function getInitialTheme(): ThemeState { - if (!browser) { - return { mode: 'system', variant: 'lume', effectiveMode: 'light' }; - } - - const stored = localStorage.getItem(THEME_STORAGE_KEY); - let mode: ThemeMode = 'system'; - let variant: ThemeVariant = 'lume'; - - if (stored) { - try { - const parsed = JSON.parse(stored); - mode = parsed.mode || 'system'; - variant = parsed.variant || 'lume'; - } catch { - // Fall through to default - } - } - - // Calculate effective mode - const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; - const effectiveMode: 'light' | 'dark' = - mode === 'system' ? (prefersDark ? 'dark' : 'light') : mode === 'dark' ? 'dark' : 'light'; - - return { - mode, - variant, - effectiveMode - }; -} - -// Create the theme store -function createThemeStore() { - const { subscribe, set, update } = writable(getInitialTheme()); - - return { - subscribe, - setMode: (mode: ThemeMode) => { - update((state) => { - const prefersDark = browser - ? window.matchMedia('(prefers-color-scheme: dark)').matches - : false; - const effectiveMode: 'light' | 'dark' = - mode === 'system' - ? prefersDark - ? 'dark' - : 'light' - : mode === 'dark' - ? 'dark' - : 'light'; - - const newState = { ...state, mode, effectiveMode }; - if (browser) { - localStorage.setItem(THEME_STORAGE_KEY, JSON.stringify(newState)); - applyTheme(newState); - } - return newState; - }); - }, - setVariant: (variant: ThemeVariant) => { - update((state) => { - const newState = { ...state, variant }; - if (browser) { - localStorage.setItem(THEME_STORAGE_KEY, JSON.stringify(newState)); - applyTheme(newState); - } - return newState; - }); - }, - toggleMode: () => { - update((state) => { - // Toggle between light and dark (skip system) - const newMode: ThemeMode = state.effectiveMode === 'light' ? 'dark' : 'light'; - const newState = { ...state, mode: newMode, effectiveMode: newMode }; - if (browser) { - localStorage.setItem(THEME_STORAGE_KEY, JSON.stringify(newState)); - applyTheme(newState); - } - return newState; - }); - }, - initialize: () => { - if (browser) { - const state = getInitialTheme(); - set(state); - applyTheme(state); - - // Listen for system theme changes - const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); - const handleChange = (e: MediaQueryListEvent) => { - // Only update if mode is set to 'system' - update((state) => { - if (state.mode === 'system') { - const newEffectiveMode: 'light' | 'dark' = e.matches ? 'dark' : 'light'; - const newState = { ...state, effectiveMode: newEffectiveMode }; - applyTheme(newState); - return newState; - } - return state; - }); - }; - mediaQuery.addEventListener('change', handleChange); - - // Cleanup function - return () => mediaQuery.removeEventListener('change', handleChange); - } - } - }; -} - -// Apply theme to document -function applyTheme(state: ThemeState) { - if (!browser) return; - - const html = document.documentElement; - - // Apply dark mode class based on effectiveMode - if (state.effectiveMode === 'dark') { - html.classList.add('dark'); - } else { - html.classList.remove('dark'); - } - - // Apply theme variant as data attribute - html.setAttribute('data-theme', state.variant); -} - -export const theme = createThemeStore(); +/** + * Memoro theme store instance + * + * - Default variant: lume (gold) + * - Custom primary: Gold (#f8d62b) + * - All 4 theme variants available + */ +export const theme = createThemeStore({ + appId: 'memoro', + defaultVariant: 'lume', + primaryColor: { + light: '47 95% 58%', // Gold #f8d62b + dark: '47 95% 58%', + }, +}); diff --git a/memoro/apps/web/src/routes/+layout.svelte b/memoro/apps/web/src/routes/+layout.svelte index 179d2677f..a7302839a 100644 --- a/memoro/apps/web/src/routes/+layout.svelte +++ b/memoro/apps/web/src/routes/+layout.svelte @@ -9,45 +9,11 @@ let { children } = $props(); - let currentTheme = $derived($theme); - let isDark = $derived(currentTheme.effectiveMode === 'dark'); - - // Get page background based on theme variant - let pageBackground = $derived(() => { - const variant = currentTheme.variant; - if (isDark) { - const colors: Record = { - lume: '#101010', - nature: '#121212', - stone: '#121212', - ocean: '#121212' - }; - return colors[variant]; - } else { - const colors: Record = { - lume: '#dddddd', - nature: '#FBFDF8', - stone: '#F5F7F9', - ocean: '#F5FCFF' - }; - return colors[variant]; - } - }); - // Initialize theme on mount onMount(() => { const cleanup = theme.initialize(); return cleanup; }); - - // Update body and html background when theme changes - $effect(() => { - if (typeof document !== 'undefined') { - const bgColor = pageBackground(); - document.documentElement.style.backgroundColor = bgColor; - document.body.style.backgroundColor = bgColor; - } - }); {@render children?.()} diff --git a/package.json b/package.json index 24fdaa4f8..5baae7909 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,10 @@ "maerchenzauber:dev": "turbo run dev --filter=maerchenzauber...", "manacore:dev": "turbo run dev --filter=manacore...", "manadeck:dev": "turbo run dev --filter=manadeck...", - "memoro:dev": "turbo run dev --filter=memoro..." + "memoro:dev": "turbo run dev --filter=memoro...", + "dev:web": "turbo run dev --filter=@storyteller/web --filter=manacore-web --filter=web --filter=memoro-web", + "dev:landing": "turbo run dev --filter=@storyteller/landing --filter=manacore-landing --filter=landing --filter=memoro-landing", + "dev:mobile": "turbo run dev --filter=@storyteller/mobile --filter=manacore --filter=manadeck --filter=memoro" }, "devDependencies": { "prettier": "^3.3.3", diff --git a/packages/shared-tailwind/src/preset.js b/packages/shared-tailwind/src/preset.js index a6e38a98e..c8a12f2ee 100644 --- a/packages/shared-tailwind/src/preset.js +++ b/packages/shared-tailwind/src/preset.js @@ -1,107 +1,114 @@ /** * Shared Tailwind CSS preset for all ManaCore apps - * + * + * This preset uses HSL-based CSS variables for theming. + * Colors are defined as HSL values (e.g., "47 95% 58%") and + * wrapped with hsl() in the Tailwind config for flexibility. + * * Usage in tailwind.config.js: * ``` - * import sharedPreset from '@manacore/shared-tailwind/preset'; - * + * import preset from '@manacore/shared-tailwind/preset'; + * * export default { - * presets: [sharedPreset], + * presets: [preset], * content: ['./src/**\/*.{html,js,svelte,ts}'], * // app-specific overrides... * } * ``` */ -import { colors } from './colors.js'; - /** @type {import('tailwindcss').Config} */ const preset = { darkMode: 'class', theme: { extend: { colors: { - // Brand colors - mana: colors.mana, - - // Primary scale - primary: colors.primary, - - // Semantic colors using CSS custom properties - // These can be changed at runtime via themes.css - background: 'var(--color-background)', - foreground: 'var(--color-foreground)', - - // Content areas - content: { - DEFAULT: 'var(--color-content)', - hover: 'var(--color-content-hover)', - page: 'var(--color-content-page)', + // Brand color (consistent across all apps) + mana: '#4287f5', + + // ===== HSL-Based Semantic Colors ===== + // These use CSS variables set by @manacore/shared-theme + // Format: hsl(var(--color-name)) where --color-name is "H S% L%" + + // Page background + background: 'hsl(var(--color-background))', + + // Main text color + foreground: 'hsl(var(--color-foreground))', + + // Primary brand color (customizable per app) + primary: { + DEFAULT: 'hsl(var(--color-primary))', + foreground: 'hsl(var(--color-primary-foreground))', }, - - // Menu/sidebar - menu: { - DEFAULT: 'var(--color-menu)', - hover: 'var(--color-menu-hover)', + + // Secondary accent + secondary: { + DEFAULT: 'hsl(var(--color-secondary))', + foreground: 'hsl(var(--color-secondary-foreground))', }, - - // Text - theme: { - DEFAULT: 'var(--color-text)', - secondary: 'var(--color-text-secondary)', + + // Card/content surfaces + surface: { + DEFAULT: 'hsl(var(--color-surface))', + hover: 'hsl(var(--color-surface-hover))', + elevated: 'hsl(var(--color-surface-elevated))', }, - + + // Muted/disabled elements + muted: { + DEFAULT: 'hsl(var(--color-muted))', + foreground: 'hsl(var(--color-muted-foreground))', + }, + // Borders border: { - light: 'var(--color-border-light)', - DEFAULT: 'var(--color-border)', - strong: 'var(--color-border-strong)', + DEFAULT: 'hsl(var(--color-border))', + strong: 'hsl(var(--color-border-strong))', + }, + + // Semantic/feedback colors + error: 'hsl(var(--color-error))', + success: 'hsl(var(--color-success))', + warning: 'hsl(var(--color-warning))', + + // Form elements + input: 'hsl(var(--color-input))', + ring: 'hsl(var(--color-ring))', + + // ===== Legacy aliases (for backwards compatibility) ===== + content: { + DEFAULT: 'hsl(var(--color-surface))', + hover: 'hsl(var(--color-surface-hover))', + page: 'hsl(var(--color-background))', + }, + menu: { + DEFAULT: 'hsl(var(--color-muted))', + hover: 'hsl(var(--color-surface-hover))', + }, + theme: { + DEFAULT: 'hsl(var(--color-foreground))', + secondary: 'hsl(var(--color-muted-foreground))', }, - - // Buttons 'primary-btn': { - DEFAULT: 'var(--color-primary-button)', - text: 'var(--color-primary-button-text)', - }, - 'secondary-btn': 'var(--color-secondary-button)', - - // Feedback colors - error: 'var(--color-error)', - success: 'var(--color-success)', - warning: 'var(--color-warning)', - - // Direct theme colors (for apps that don't use CSS vars) - lume: { - ...colors.lume.light, - dark: colors.lume.dark, - }, - nature: { - ...colors.nature.light, - dark: colors.nature.dark, - }, - stone: { - ...colors.stone.light, - dark: colors.stone.dark, - }, - ocean: { - ...colors.ocean.light, - dark: colors.ocean.dark, + DEFAULT: 'hsl(var(--color-primary))', + text: 'hsl(var(--color-primary-foreground))', }, }, - - // Border radius tokens + + // Border radius tokens (CSS variable support) borderRadius: { 'none': '0', - 'sm': '0.25rem', - DEFAULT: '0.375rem', - 'md': '0.5rem', - 'lg': '0.75rem', - 'xl': '1rem', - '2xl': '1.5rem', - '3xl': '2rem', + 'sm': 'var(--radius-sm, 0.25rem)', + DEFAULT: 'var(--radius, 0.375rem)', + 'md': 'var(--radius-md, 0.5rem)', + 'lg': 'var(--radius-lg, 0.75rem)', + 'xl': 'var(--radius-xl, 1rem)', + '2xl': 'var(--radius-2xl, 1.5rem)', + '3xl': 'var(--radius-3xl, 2rem)', 'full': '9999px', }, - + // Box shadow tokens boxShadow: { 'sm': '0 1px 2px 0 rgb(0 0 0 / 0.05)', @@ -113,7 +120,7 @@ const preset = { 'inner': 'inset 0 2px 4px 0 rgb(0 0 0 / 0.05)', 'none': 'none', }, - + // Font family fontFamily: { sans: [ @@ -136,14 +143,37 @@ const preset = { 'monospace', ], }, - + // Animation animation: { 'spin-slow': 'spin 3s linear infinite', 'pulse-slow': 'pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite', 'bounce-slow': 'bounce 2s infinite', + 'fade-in': 'fadeIn 0.2s ease-out', + 'fade-out': 'fadeOut 0.2s ease-in', + 'slide-in': 'slideIn 0.2s ease-out', + 'slide-out': 'slideOut 0.2s ease-in', }, - + + keyframes: { + fadeIn: { + '0%': { opacity: '0' }, + '100%': { opacity: '1' }, + }, + fadeOut: { + '0%': { opacity: '1' }, + '100%': { opacity: '0' }, + }, + slideIn: { + '0%': { transform: 'translateY(-10px)', opacity: '0' }, + '100%': { transform: 'translateY(0)', opacity: '1' }, + }, + slideOut: { + '0%': { transform: 'translateY(0)', opacity: '1' }, + '100%': { transform: 'translateY(-10px)', opacity: '0' }, + }, + }, + // Transition transitionDuration: { '250': '250ms', diff --git a/packages/shared-tailwind/src/themes.css b/packages/shared-tailwind/src/themes.css index c06ad3c53..d5c1c356b 100644 --- a/packages/shared-tailwind/src/themes.css +++ b/packages/shared-tailwind/src/themes.css @@ -1,265 +1,434 @@ /** - * CSS Custom Properties for ManaCore themes - * - * Usage: - * 1. Import in your app.css: @import '@manacore/shared-tailwind/themes.css'; - * 2. Set theme with data-theme attribute: - * 3. Dark mode is automatic with .dark class or prefers-color-scheme + * Shared Theme CSS Variables (HSL-based) + * + * This file defines HSL-based CSS custom properties for all theme variants. + * Variables are set by @manacore/shared-theme's createThemeStore() at runtime, + * but this file provides sensible defaults for static rendering. + * + * Usage in app.css: + * ```css + * @import '@manacore/shared-tailwind/themes.css'; + * @tailwind base; + * @tailwind components; + * @tailwind utilities; + * ``` + * + * Color format: HSL values without hsl() wrapper + * Example: --color-primary: 47 95% 58%; + * Used as: hsl(var(--color-primary)) */ -/* Default: Lume Light Theme */ -:root, -[data-theme="lume"] { - --color-primary: #f8d62b; - --color-primary-button: #f8d62b; - --color-primary-button-text: #000000; - --color-secondary: #D4B200; - --color-secondary-button: #FFE9A3; - - --color-background: #dddddd; - --color-foreground: #2c2c2c; - --color-content: #ffffff; - --color-content-hover: #f5f5f5; - --color-content-page: #ffffff; - --color-menu: #dddddd; - --color-menu-hover: #cccccc; - - --color-text: #2c2c2c; - --color-text-secondary: #666666; - - --color-border-light: #f2f2f2; - --color-border: #e6e6e6; - --color-border-strong: #cccccc; - - --color-error: #e74c3c; - --color-success: #27ae60; - --color-warning: #f39c12; +/* ===== Default Theme (Lume Light) ===== */ +:root { + /* Primary brand color */ + --color-primary: 47 95% 58%; + --color-primary-foreground: 0 0% 0%; + + /* Secondary accent */ + --color-secondary: 47 100% 41%; + --color-secondary-foreground: 0 0% 0%; + + /* Page background */ + --color-background: 0 0% 87%; + + /* Main text color */ + --color-foreground: 0 0% 17%; + + /* Surfaces (cards, modals, etc.) */ + --color-surface: 0 0% 100%; + --color-surface-hover: 0 0% 96%; + --color-surface-elevated: 0 0% 100%; + + /* Muted/subtle elements */ + --color-muted: 0 0% 90%; + --color-muted-foreground: 0 0% 40%; + + /* Borders */ + --color-border: 0 0% 90%; + --color-border-strong: 0 0% 80%; + + /* Semantic colors */ + --color-error: 6 78% 57%; + --color-success: 145 63% 42%; + --color-warning: 36 100% 50%; + + /* Form elements */ + --color-input: 0 0% 100%; + --color-ring: 47 95% 58%; + + /* Border radius */ + --radius-sm: 0.25rem; + --radius: 0.375rem; + --radius-md: 0.5rem; + --radius-lg: 0.75rem; + --radius-xl: 1rem; + --radius-2xl: 1.5rem; + --radius-3xl: 2rem; } -/* Lume Dark */ +/* ===== Dark Mode ===== */ .dark, -[data-theme="lume"].dark, -[data-theme="lume"] .dark { - --color-primary: #f8d62b; - --color-primary-button: #7C6B16; - --color-primary-button-text: #ffffff; - --color-secondary: #D4B200; - --color-secondary-button: #1E1E1E; - - --color-background: #101010; - --color-foreground: #ffffff; - --color-content: #1E1E1E; - --color-content-hover: #333333; - --color-content-page: #121212; - --color-menu: #101010; - --color-menu-hover: #333333; - - --color-text: #ffffff; - --color-text-secondary: #a0a0a0; - - --color-border-light: #333333; - --color-border: #424242; - --color-border-strong: #616161; - - --color-error: #e74c3c; - --color-success: #2ecc71; - --color-warning: #f1c40f; +:root.dark { + --color-primary: 47 95% 58%; + --color-primary-foreground: 0 0% 0%; + + --color-secondary: 47 70% 29%; + --color-secondary-foreground: 0 0% 100%; + + --color-background: 0 0% 6%; + --color-foreground: 0 0% 100%; + + --color-surface: 0 0% 12%; + --color-surface-hover: 0 0% 16%; + --color-surface-elevated: 0 0% 14%; + + --color-muted: 0 0% 20%; + --color-muted-foreground: 0 0% 60%; + + --color-border: 0 0% 26%; + --color-border-strong: 0 0% 35%; + + --color-error: 6 78% 57%; + --color-success: 145 63% 49%; + --color-warning: 48 100% 50%; + + --color-input: 0 0% 14%; + --color-ring: 47 95% 58%; } -/* Nature Theme */ +/* ===== Lume Theme (Gold) ===== */ +[data-theme="lume"] { + --color-primary: 47 95% 58%; + --color-primary-foreground: 0 0% 0%; + --color-secondary: 47 100% 41%; + --color-secondary-foreground: 0 0% 0%; + --color-background: 0 0% 87%; + --color-foreground: 0 0% 17%; + --color-surface: 0 0% 100%; + --color-surface-hover: 0 0% 96%; + --color-surface-elevated: 0 0% 100%; + --color-muted: 0 0% 90%; + --color-muted-foreground: 0 0% 40%; + --color-border: 0 0% 90%; + --color-border-strong: 0 0% 80%; + --color-error: 6 78% 57%; + --color-success: 145 63% 42%; + --color-warning: 36 100% 50%; + --color-input: 0 0% 100%; + --color-ring: 47 95% 58%; +} + +[data-theme="lume"].dark, +.dark[data-theme="lume"] { + --color-primary: 47 95% 58%; + --color-primary-foreground: 0 0% 0%; + --color-secondary: 47 70% 29%; + --color-secondary-foreground: 0 0% 100%; + --color-background: 0 0% 6%; + --color-foreground: 0 0% 100%; + --color-surface: 0 0% 12%; + --color-surface-hover: 0 0% 16%; + --color-surface-elevated: 0 0% 14%; + --color-muted: 0 0% 20%; + --color-muted-foreground: 0 0% 60%; + --color-border: 0 0% 26%; + --color-border-strong: 0 0% 35%; + --color-error: 6 78% 57%; + --color-success: 145 63% 49%; + --color-warning: 48 100% 50%; + --color-input: 0 0% 14%; + --color-ring: 47 95% 58%; +} + +/* ===== Nature Theme (Green) ===== */ [data-theme="nature"] { - --color-primary: #4CAF50; - --color-primary-button: #A08500; - --color-primary-button-text: #ffffff; - --color-secondary: #81C784; - --color-secondary-button: #F1F8E9; - - --color-background: #FBFDF8; - --color-foreground: #1B5E20; - --color-content: #F1F8E9; - --color-content-hover: #E8F5E9; - --color-content-page: #ffffff; - --color-menu: #E8F5E9; - --color-menu-hover: #C8E6C9; - - --color-text: #1B5E20; - --color-text-secondary: #388E3C; - - --color-border-light: #E8F5E9; - --color-border: #C8E6C9; - --color-border-strong: #A5D6A7; - - --color-error: #E57373; - --color-success: #66BB6A; - --color-warning: #FFB74D; + --color-primary: 122 39% 49%; + --color-primary-foreground: 0 0% 100%; + --color-secondary: 122 38% 63%; + --color-secondary-foreground: 0 0% 0%; + --color-background: 80 33% 97%; + --color-foreground: 122 56% 24%; + --color-surface: 0 0% 100%; + --color-surface-hover: 120 25% 95%; + --color-surface-elevated: 0 0% 100%; + --color-muted: 120 25% 95%; + --color-muted-foreground: 122 20% 40%; + --color-border: 120 25% 91%; + --color-border-strong: 120 26% 79%; + --color-error: 0 65% 67%; + --color-success: 122 39% 49%; + --color-warning: 36 100% 50%; + --color-input: 0 0% 100%; + --color-ring: 122 39% 49%; } [data-theme="nature"].dark, -[data-theme="nature"] .dark { - --color-primary: #4CAF50; - --color-primary-button: #FF9500; - --color-primary-button-text: #000000; - --color-secondary: #81C784; - --color-secondary-button: #1E1E1E; - - --color-background: #121212; - --color-foreground: #FFFFFF; - --color-content: #1E1E1E; - --color-content-hover: #2E7D32; - --color-content-page: #121212; - --color-menu: #252525; - --color-menu-hover: #2E7D32; - - --color-text: #FFFFFF; - --color-text-secondary: #A5D6A7; - - --color-border-light: #1B5E20; - --color-border: #2E7D32; - --color-border-strong: #388E3C; - - --color-error: #CF6679; - --color-success: #81C784; - --color-warning: #FFD54F; +.dark[data-theme="nature"] { + --color-primary: 122 39% 49%; + --color-primary-foreground: 0 0% 100%; + --color-secondary: 122 30% 35%; + --color-secondary-foreground: 0 0% 100%; + --color-background: 0 0% 7%; + --color-foreground: 0 0% 100%; + --color-surface: 120 10% 12%; + --color-surface-hover: 120 10% 16%; + --color-surface-elevated: 120 10% 14%; + --color-muted: 120 10% 20%; + --color-muted-foreground: 120 10% 60%; + --color-border: 120 10% 25%; + --color-border-strong: 120 10% 35%; + --color-error: 0 65% 57%; + --color-success: 122 50% 55%; + --color-warning: 48 100% 50%; + --color-input: 120 10% 14%; + --color-ring: 122 39% 49%; } -/* Stone Theme */ +/* ===== Stone Theme (Blue Gray) ===== */ [data-theme="stone"] { - --color-primary: #607D8B; - --color-primary-button: #FF9500; - --color-primary-button-text: #000000; - --color-secondary: #90A4AE; - --color-secondary-button: #ECEFF1; - - --color-background: #F5F7F9; - --color-foreground: #263238; - --color-content: #ECEFF1; - --color-content-hover: #E0E6EA; - --color-content-page: #ffffff; - --color-menu: #E0E6EA; - --color-menu-hover: #CFD8DC; - - --color-text: #263238; - --color-text-secondary: #546E7A; - - --color-border-light: #ECEFF1; - --color-border: #CFD8DC; - --color-border-strong: #B0BEC5; - - --color-error: #EF5350; - --color-success: #66BB6A; - --color-warning: #FFA726; + --color-primary: 200 18% 46%; + --color-primary-foreground: 0 0% 100%; + --color-secondary: 200 15% 62%; + --color-secondary-foreground: 0 0% 0%; + --color-background: 210 17% 97%; + --color-foreground: 200 19% 18%; + --color-surface: 0 0% 100%; + --color-surface-hover: 200 10% 94%; + --color-surface-elevated: 0 0% 100%; + --color-muted: 200 10% 94%; + --color-muted-foreground: 200 10% 45%; + --color-border: 200 10% 88%; + --color-border-strong: 200 12% 75%; + --color-error: 4 90% 63%; + --color-success: 145 63% 42%; + --color-warning: 36 100% 50%; + --color-input: 0 0% 100%; + --color-ring: 200 18% 46%; } [data-theme="stone"].dark, -[data-theme="stone"] .dark { - --color-primary: #78909C; - --color-primary-button: #FF9500; - --color-primary-button-text: #000000; - --color-secondary: #90A4AE; - --color-secondary-button: #1E1E1E; - - --color-background: #121212; - --color-foreground: #FFFFFF; - --color-content: #1E1E1E; - --color-content-hover: #37474F; - --color-content-page: #121212; - --color-menu: #252525; - --color-menu-hover: #37474F; - - --color-text: #FFFFFF; - --color-text-secondary: #B0BEC5; - - --color-border-light: #37474F; - --color-border: #455A64; - --color-border-strong: #546E7A; - - --color-error: #CF6679; - --color-success: #81C784; - --color-warning: #FFD54F; +.dark[data-theme="stone"] { + --color-primary: 200 15% 52%; + --color-primary-foreground: 0 0% 0%; + --color-secondary: 200 12% 35%; + --color-secondary-foreground: 0 0% 100%; + --color-background: 0 0% 7%; + --color-foreground: 0 0% 100%; + --color-surface: 200 10% 12%; + --color-surface-hover: 200 10% 16%; + --color-surface-elevated: 200 10% 14%; + --color-muted: 200 10% 20%; + --color-muted-foreground: 200 10% 60%; + --color-border: 200 10% 25%; + --color-border-strong: 200 10% 35%; + --color-error: 4 90% 58%; + --color-success: 145 63% 49%; + --color-warning: 48 100% 50%; + --color-input: 200 10% 14%; + --color-ring: 200 15% 52%; } -/* Ocean Theme */ +/* ===== Ocean Theme (Blue) ===== */ [data-theme="ocean"] { - --color-primary: #039BE5; - --color-primary-button: #FF9500; - --color-primary-button-text: #000000; - --color-secondary: #4FC3F7; - --color-secondary-button: #E1F5FE; - - --color-background: #F5FCFF; - --color-foreground: #01579B; - --color-content: #E1F5FE; - --color-content-hover: #B3E5FC; - --color-content-page: #ffffff; - --color-menu: #E1F5FE; - --color-menu-hover: #B3E5FC; - - --color-text: #01579B; - --color-text-secondary: #0277BD; - - --color-border-light: #E1F5FE; - --color-border: #B3E5FC; - --color-border-strong: #81D4FA; - - --color-error: #EF5350; - --color-success: #66BB6A; - --color-warning: #FFA726; + --color-primary: 199 98% 45%; + --color-primary-foreground: 0 0% 100%; + --color-secondary: 199 92% 64%; + --color-secondary-foreground: 0 0% 0%; + --color-background: 199 100% 97%; + --color-foreground: 199 100% 18%; + --color-surface: 0 0% 100%; + --color-surface-hover: 199 100% 94%; + --color-surface-elevated: 0 0% 100%; + --color-muted: 199 100% 94%; + --color-muted-foreground: 199 50% 40%; + --color-border: 199 71% 87%; + --color-border-strong: 199 79% 76%; + --color-error: 4 90% 63%; + --color-success: 145 63% 42%; + --color-warning: 36 100% 50%; + --color-input: 0 0% 100%; + --color-ring: 199 98% 45%; } [data-theme="ocean"].dark, -[data-theme="ocean"] .dark { - --color-primary: #039BE5; - --color-primary-button: #FF9500; - --color-primary-button-text: #000000; - --color-secondary: #4FC3F7; - --color-secondary-button: #1E1E1E; - - --color-background: #121212; - --color-foreground: #FFFFFF; - --color-content: #1E1E1E; - --color-content-hover: #0277BD; - --color-content-page: #121212; - --color-menu: #252525; - --color-menu-hover: #0277BD; - - --color-text: #FFFFFF; - --color-text-secondary: #81D4FA; - - --color-border-light: #01579B; - --color-border: #0277BD; - --color-border-strong: #0288D1; - - --color-error: #CF6679; - --color-success: #81C784; - --color-warning: #FFD54F; +.dark[data-theme="ocean"] { + --color-primary: 199 98% 48%; + --color-primary-foreground: 0 0% 0%; + --color-secondary: 199 60% 35%; + --color-secondary-foreground: 0 0% 100%; + --color-background: 0 0% 7%; + --color-foreground: 0 0% 100%; + --color-surface: 199 30% 12%; + --color-surface-hover: 199 30% 16%; + --color-surface-elevated: 199 30% 14%; + --color-muted: 199 20% 20%; + --color-muted-foreground: 199 20% 60%; + --color-border: 199 20% 25%; + --color-border-strong: 199 20% 35%; + --color-error: 4 90% 58%; + --color-success: 145 63% 49%; + --color-warning: 48 100% 50%; + --color-input: 199 30% 14%; + --color-ring: 199 98% 48%; } -/* Dark mode via media query */ +/* ===== Dark mode via media query (fallback) ===== */ @media (prefers-color-scheme: dark) { - :root:not([data-theme]) { - --color-primary: #f8d62b; - --color-primary-button: #7C6B16; - --color-primary-button-text: #ffffff; - --color-secondary: #D4B200; - --color-secondary-button: #1E1E1E; - - --color-background: #101010; - --color-foreground: #ffffff; - --color-content: #1E1E1E; - --color-content-hover: #333333; - --color-content-page: #121212; - --color-menu: #101010; - --color-menu-hover: #333333; - - --color-text: #ffffff; - --color-text-secondary: #a0a0a0; - - --color-border-light: #333333; - --color-border: #424242; - --color-border-strong: #616161; - - --color-error: #e74c3c; - --color-success: #2ecc71; - --color-warning: #f1c40f; + :root:not(.dark):not([data-theme]) { + --color-primary: 47 95% 58%; + --color-primary-foreground: 0 0% 0%; + --color-secondary: 47 70% 29%; + --color-secondary-foreground: 0 0% 100%; + --color-background: 0 0% 6%; + --color-foreground: 0 0% 100%; + --color-surface: 0 0% 12%; + --color-surface-hover: 0 0% 16%; + --color-surface-elevated: 0 0% 14%; + --color-muted: 0 0% 20%; + --color-muted-foreground: 0 0% 60%; + --color-border: 0 0% 26%; + --color-border-strong: 0 0% 35%; + --color-error: 6 78% 57%; + --color-success: 145 63% 49%; + --color-warning: 48 100% 50%; + --color-input: 0 0% 14%; + --color-ring: 47 95% 58%; + } +} + +/* ===== Base Styles ===== */ +@layer base { + * { + border-color: hsl(var(--color-border)); + } + + body { + background-color: hsl(var(--color-background)); + color: hsl(var(--color-foreground)); + font-family: 'Inter', system-ui, -apple-system, sans-serif; + } + + /* Smooth color transitions for theme switching */ + html { + color-scheme: light; + } + + html.dark { + color-scheme: dark; + } +} + +/* ===== Component Utilities ===== */ +@layer components { + /* Primary Button */ + .btn-primary { + background-color: hsl(var(--color-primary)); + color: hsl(var(--color-primary-foreground)); + padding: 0.5rem 1rem; + border-radius: var(--radius-md); + font-weight: 500; + transition: all 0.2s ease; + } + + .btn-primary:hover { + filter: brightness(0.9); + } + + .btn-primary:focus-visible { + outline: 2px solid hsl(var(--color-ring)); + outline-offset: 2px; + } + + /* Secondary Button */ + .btn-secondary { + background-color: hsl(var(--color-secondary)); + color: hsl(var(--color-secondary-foreground)); + padding: 0.5rem 1rem; + border-radius: var(--radius-md); + font-weight: 500; + transition: all 0.2s ease; + } + + .btn-secondary:hover { + filter: brightness(0.95); + } + + /* Ghost Button */ + .btn-ghost { + background-color: transparent; + color: hsl(var(--color-foreground)); + padding: 0.5rem 1rem; + border-radius: var(--radius-md); + font-weight: 500; + transition: all 0.2s ease; + } + + .btn-ghost:hover { + background-color: hsl(var(--color-surface-hover)); + } + + /* Card */ + .card { + background-color: hsl(var(--color-surface)); + border: 1px solid hsl(var(--color-border)); + border-radius: var(--radius-lg); + padding: 1rem; + } + + .card-elevated { + background-color: hsl(var(--color-surface-elevated)); + box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + } + + /* Input */ + .input { + background-color: hsl(var(--color-input)); + border: 1px solid hsl(var(--color-border)); + border-radius: var(--radius-md); + padding: 0.5rem 0.75rem; + color: hsl(var(--color-foreground)); + transition: border-color 0.2s ease, box-shadow 0.2s ease; + } + + .input:focus { + border-color: hsl(var(--color-ring)); + box-shadow: 0 0 0 2px hsl(var(--color-ring) / 0.2); + outline: none; + } + + .input::placeholder { + color: hsl(var(--color-muted-foreground)); + } + + /* Badge */ + .badge { + display: inline-flex; + align-items: center; + padding: 0.25rem 0.5rem; + border-radius: var(--radius); + font-size: 0.75rem; + font-weight: 500; + background-color: hsl(var(--color-muted)); + color: hsl(var(--color-muted-foreground)); + } + + .badge-primary { + background-color: hsl(var(--color-primary) / 0.1); + color: hsl(var(--color-primary)); + } + + .badge-success { + background-color: hsl(var(--color-success) / 0.1); + color: hsl(var(--color-success)); + } + + .badge-error { + background-color: hsl(var(--color-error) / 0.1); + color: hsl(var(--color-error)); + } + + .badge-warning { + background-color: hsl(var(--color-warning) / 0.1); + color: hsl(var(--color-warning)); } } diff --git a/packages/shared-theme-ui/README.md b/packages/shared-theme-ui/README.md new file mode 100644 index 000000000..18bc07e67 --- /dev/null +++ b/packages/shared-theme-ui/README.md @@ -0,0 +1,170 @@ +# @manacore/shared-theme-ui + +Svelte UI components for theme switching. Works with `@manacore/shared-theme`. + +## Features + +- **ThemeToggle**: Simple light/dark mode toggle button +- **ThemeSelector**: Visual selector for theme variants +- **ThemeModeSelector**: Segmented control for light/dark/system + +## Installation + +```bash +pnpm add @manacore/shared-theme-ui +``` + +## Prerequisites + +- `@manacore/shared-theme` - Theme store +- `@manacore/shared-icons` - Icon components + +## Components + +### ThemeToggle + +A simple button that toggles between light and dark mode. + +```svelte + + + + + + +``` + +#### Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `theme` | `ThemeStore` | required | Theme store instance | +| `size` | `number` | `20` | Icon size in pixels | +| `showTooltip` | `boolean` | `false` | Show tooltip on hover | +| `class` | `string` | `''` | Additional CSS classes | + +### ThemeSelector + +A visual selector showing all theme variants with color dots. + +```svelte + + + + + + +``` + +#### Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `theme` | `ThemeStore` | required | Theme store instance | +| `showLabels` | `boolean` | `true` | Show variant labels | +| `showEmoji` | `boolean` | `true` | Show variant emojis | +| `compact` | `boolean` | `false` | Compact mode (smaller buttons) | +| `class` | `string` | `''` | Additional CSS classes | + +### ThemeModeSelector + +A segmented control for selecting light, dark, or system mode. + +```svelte + + + + + + +``` + +#### Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `theme` | `ThemeStore` | required | Theme store instance | +| `class` | `string` | `''` | Additional CSS classes | + +## Complete Example + +```svelte + + +
+

Appearance

+ + +
+ +
+ + +
+ + +
+ + +
+ + +
+
+``` + +## Styling + +All components use CSS variables from `@manacore/shared-tailwind/themes.css` and are fully theme-aware. They automatically adapt to the current theme variant and mode. + +### Custom Styling + +You can override styles using the `class` prop or by targeting the component classes: + +```css +/* Custom toggle button */ +.theme-toggle { + background-color: var(--my-custom-bg); +} + +/* Custom selector buttons */ +.variant-button.active { + box-shadow: 0 0 0 2px var(--my-custom-ring); +} +``` + +## Related Packages + +- `@manacore/shared-theme` - Theme store and utilities +- `@manacore/shared-tailwind` - Tailwind preset with theme CSS +- `@manacore/shared-icons` - Icon components diff --git a/packages/shared-theme-ui/package.json b/packages/shared-theme-ui/package.json new file mode 100644 index 000000000..f7f2e16cd --- /dev/null +++ b/packages/shared-theme-ui/package.json @@ -0,0 +1,25 @@ +{ + "name": "@manacore/shared-theme-ui", + "version": "0.1.0", + "private": true, + "type": "module", + "main": "./src/index.ts", + "types": "./src/index.ts", + "exports": { + ".": "./src/index.ts", + "./ThemeToggle.svelte": "./src/ThemeToggle.svelte", + "./ThemeSelector.svelte": "./src/ThemeSelector.svelte", + "./ThemeModeSelector.svelte": "./src/ThemeModeSelector.svelte" + }, + "peerDependencies": { + "svelte": "^5.0.0" + }, + "dependencies": { + "@manacore/shared-theme": "workspace:*", + "@manacore/shared-icons": "workspace:*" + }, + "devDependencies": { + "svelte": "^5.0.0", + "typescript": "^5.0.0" + } +} diff --git a/packages/shared-theme-ui/src/ThemeModeSelector.svelte b/packages/shared-theme-ui/src/ThemeModeSelector.svelte new file mode 100644 index 000000000..1f1de3f34 --- /dev/null +++ b/packages/shared-theme-ui/src/ThemeModeSelector.svelte @@ -0,0 +1,87 @@ + + +
+ {#each modes as { mode, icon, label }} + {@const isActive = theme.mode === mode} + + {/each} +
+ + diff --git a/packages/shared-theme-ui/src/ThemeSelector.svelte b/packages/shared-theme-ui/src/ThemeSelector.svelte new file mode 100644 index 000000000..072e0a32a --- /dev/null +++ b/packages/shared-theme-ui/src/ThemeSelector.svelte @@ -0,0 +1,125 @@ + + +
+ {#each theme.variants as variant} + {@const definition = THEME_DEFINITIONS[variant]} + {@const isActive = theme.variant === variant} + + {/each} +
+ + diff --git a/packages/shared-theme-ui/src/ThemeToggle.svelte b/packages/shared-theme-ui/src/ThemeToggle.svelte new file mode 100644 index 000000000..df1c332c5 --- /dev/null +++ b/packages/shared-theme-ui/src/ThemeToggle.svelte @@ -0,0 +1,74 @@ + + + + + diff --git a/packages/shared-theme-ui/src/index.ts b/packages/shared-theme-ui/src/index.ts new file mode 100644 index 000000000..80f09d003 --- /dev/null +++ b/packages/shared-theme-ui/src/index.ts @@ -0,0 +1,4 @@ +// Theme UI Components +export { default as ThemeToggle } from './ThemeToggle.svelte'; +export { default as ThemeSelector } from './ThemeSelector.svelte'; +export { default as ThemeModeSelector } from './ThemeModeSelector.svelte'; diff --git a/packages/shared-theme-ui/tsconfig.json b/packages/shared-theme-ui/tsconfig.json new file mode 100644 index 000000000..ce024e619 --- /dev/null +++ b/packages/shared-theme-ui/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "declaration": true, + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/shared-theme/README.md b/packages/shared-theme/README.md new file mode 100644 index 000000000..34a57fdbf --- /dev/null +++ b/packages/shared-theme/README.md @@ -0,0 +1,225 @@ +# @manacore/shared-theme + +Unified theme system for all ManaCore web applications. Provides a consistent theming experience with HSL-based colors, multiple theme variants, and light/dark mode support. + +## Features + +- **4 Theme Variants**: Lume (Gold), Nature (Green), Stone (Blue Gray), Ocean (Blue) +- **3 Theme Modes**: Light, Dark, System (auto-detect) +- **HSL-based Colors**: 18 semantic color tokens for flexible theming +- **App-specific Primary Colors**: Each app can override the primary color +- **Svelte 5 Runes**: Modern reactive state management +- **localStorage Persistence**: Theme preferences are saved per app +- **System Preference Detection**: Automatically follows OS dark mode setting + +## Installation + +```bash +pnpm add @manacore/shared-theme +``` + +## Quick Start + +### 1. Create a theme store for your app + +```typescript +// src/lib/stores/theme.ts +import { createThemeStore } from '@manacore/shared-theme'; + +export const theme = createThemeStore({ + appId: 'myapp', + defaultVariant: 'lume', + primaryColor: { + light: '47 95% 58%', // Gold + dark: '47 95% 58%', + }, +}); +``` + +### 2. Initialize in your layout + +```svelte + + + +{@render children()} +``` + +### 3. Import theme CSS + +```css +/* src/app.css */ +@import '@manacore/shared-tailwind/themes.css'; + +@tailwind base; +@tailwind components; +@tailwind utilities; +``` + +## API Reference + +### `createThemeStore(config)` + +Creates a theme store instance for your app. + +#### Config Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `appId` | `string` | required | Unique app identifier for localStorage | +| `defaultMode` | `'light' \| 'dark' \| 'system'` | `'system'` | Default theme mode | +| `defaultVariant` | `ThemeVariant` | `'lume'` | Default theme variant | +| `primaryColor` | `{ light: HSLValue; dark: HSLValue }` | - | App-specific primary color override | + +#### Store Properties + +| Property | Type | Description | +|----------|------|-------------| +| `mode` | `ThemeMode` | Current mode (light/dark/system) | +| `variant` | `ThemeVariant` | Current variant (lume/nature/stone/ocean) | +| `effectiveMode` | `'light' \| 'dark'` | Resolved mode (accounts for system preference) | +| `isDark` | `boolean` | Whether dark mode is active | +| `variants` | `ThemeVariant[]` | All available variants | + +#### Store Methods + +| Method | Description | +|--------|-------------| +| `initialize()` | Initialize theme, returns cleanup function | +| `setMode(mode)` | Set theme mode | +| `setVariant(variant)` | Set theme variant | +| `toggleMode()` | Toggle between light and dark | +| `cycleMode()` | Cycle through light → dark → system | + +## Theme Variants + +### Lume (Gold) ✨ +- Primary: `hsl(47 95% 58%)` - #f8d62b +- Warm, energetic feel +- Best for: Creative apps, productivity tools + +### Nature (Green) 🌿 +- Primary: `hsl(122 39% 49%)` - #4CAF50 +- Calm, organic feel +- Best for: Health apps, environmental themes + +### Stone (Blue Gray) 🪨 +- Primary: `hsl(200 18% 46%)` - #607D8B +- Professional, neutral feel +- Best for: Business apps, enterprise tools + +### Ocean (Blue) 🌊 +- Primary: `hsl(199 98% 45%)` - #039BE5 +- Fresh, trustworthy feel +- Best for: Tech apps, communication tools + +## Color Tokens + +The theme system provides 18 semantic color tokens: + +```css +/* Primary */ +--color-primary +--color-primary-foreground + +/* Secondary */ +--color-secondary +--color-secondary-foreground + +/* Backgrounds */ +--color-background +--color-foreground + +/* Surfaces */ +--color-surface +--color-surface-hover +--color-surface-elevated + +/* Muted */ +--color-muted +--color-muted-foreground + +/* Borders */ +--color-border +--color-border-strong + +/* Semantic */ +--color-error +--color-success +--color-warning + +/* Form */ +--color-input +--color-ring +``` + +## Usage with Tailwind + +The `@manacore/shared-tailwind` preset maps all CSS variables to Tailwind classes: + +```html + +
Page background
+
Card surface
+
Hover state
+ + +

Main text

+

Secondary text

+ + + + + +
Normal border
+
Strong border
+ + +Error message +Success message +``` + +## Pre-defined App Configs + +```typescript +import { APP_THEME_CONFIGS } from '@manacore/shared-theme'; + +// Use pre-defined config +export const theme = createThemeStore(APP_THEME_CONFIGS.memoro); + +// Available configs: +// - APP_THEME_CONFIGS.memoro (Gold) +// - APP_THEME_CONFIGS.manacore (Indigo) +// - APP_THEME_CONFIGS.manadeck (Indigo) +// - APP_THEME_CONFIGS.maerchenzauber (Purple) +``` + +## TypeScript Types + +```typescript +import type { + ThemeMode, // 'light' | 'dark' | 'system' + ThemeVariant, // 'lume' | 'nature' | 'stone' | 'ocean' + EffectiveMode, // 'light' | 'dark' + ThemeState, // Full theme state object + ThemeColors, // Color token definitions + AppThemeConfig, // Store configuration + ThemeStore, // Store interface + HSLValue, // HSL string format +} from '@manacore/shared-theme'; +``` + +## Related Packages + +- `@manacore/shared-tailwind` - Tailwind preset with theme CSS variables +- `@manacore/shared-theme-ui` - Theme toggle and selector components diff --git a/packages/shared-theme/package.json b/packages/shared-theme/package.json new file mode 100644 index 000000000..d6cf062d8 --- /dev/null +++ b/packages/shared-theme/package.json @@ -0,0 +1,22 @@ +{ + "name": "@manacore/shared-theme", + "version": "0.1.0", + "private": true, + "type": "module", + "main": "./src/index.ts", + "types": "./src/index.ts", + "exports": { + ".": "./src/index.ts", + "./store": "./src/store.svelte.ts", + "./types": "./src/types.ts", + "./constants": "./src/constants.ts", + "./utils": "./src/utils.ts" + }, + "peerDependencies": { + "svelte": "^5.0.0" + }, + "devDependencies": { + "svelte": "^5.0.0", + "typescript": "^5.0.0" + } +} diff --git a/packages/shared-theme/src/constants.ts b/packages/shared-theme/src/constants.ts new file mode 100644 index 000000000..e1c976cf4 --- /dev/null +++ b/packages/shared-theme/src/constants.ts @@ -0,0 +1,244 @@ +import type { ThemeVariant, ThemeVariantDefinition, ThemeColors } from './types'; + +/** + * All available theme variants + */ +export const THEME_VARIANTS: readonly ThemeVariant[] = ['lume', 'nature', 'stone', 'ocean'] as const; + +/** + * HSL Color Definitions for all theme variants + * + * Format: "H S% L%" (without hsl() wrapper for CSS variable compatibility) + * + * Color tokens: + * - primary: Main brand/accent color + * - secondary: Secondary accent + * - background: Page background + * - foreground: Main text color + * - surface: Card/content background + * - muted: Disabled/subtle elements + * - border: Border colors + * - error/success/warning: Semantic colors + */ + +const lumeLight: ThemeColors = { + primary: '47 95% 58%', // #f8d62b - Gold + primaryForeground: '0 0% 0%', // Black text on gold + secondary: '47 100% 41%', // #D4B200 - Darker gold + secondaryForeground: '0 0% 0%', + background: '0 0% 87%', // #dddddd - Light gray + foreground: '0 0% 17%', // #2c2c2c - Dark text + surface: '0 0% 100%', // #ffffff - White + surfaceHover: '0 0% 96%', // #f5f5f5 + surfaceElevated: '0 0% 100%', // #ffffff + muted: '0 0% 90%', // #e6e6e6 + mutedForeground: '0 0% 40%', // #666666 + border: '0 0% 90%', // #e6e6e6 + borderStrong: '0 0% 80%', // #cccccc + error: '6 78% 57%', // #e74c3c + success: '145 63% 42%', // #27ae60 + warning: '36 100% 50%', // #f39c12 + input: '0 0% 100%', // #ffffff + ring: '47 95% 58%', // Same as primary +}; + +const lumeDark: ThemeColors = { + primary: '47 95% 58%', // #f8d62b - Gold (same in dark) + primaryForeground: '0 0% 0%', // Black text on gold + secondary: '47 70% 29%', // #7C6B16 - Muted gold + secondaryForeground: '0 0% 100%', + background: '0 0% 6%', // #101010 - Very dark + foreground: '0 0% 100%', // #ffffff - White text + surface: '0 0% 12%', // #1E1E1E - Dark surface + surfaceHover: '0 0% 16%', // #292929 + surfaceElevated: '0 0% 14%', // #242424 + muted: '0 0% 20%', // #333333 + mutedForeground: '0 0% 60%', // #999999 + border: '0 0% 26%', // #424242 + borderStrong: '0 0% 35%', // #595959 + error: '6 78% 57%', // #e74c3c + success: '145 63% 49%', // #2ecc71 + warning: '48 100% 50%', // #f1c40f + input: '0 0% 14%', // #242424 + ring: '47 95% 58%', +}; + +const natureLight: ThemeColors = { + primary: '122 39% 49%', // #4CAF50 - Green + primaryForeground: '0 0% 100%', // White text on green + secondary: '122 38% 63%', // #81C784 - Light green + secondaryForeground: '0 0% 0%', + background: '80 33% 97%', // #FBFDF8 - Very light green tint + foreground: '122 56% 24%', // #1B5E20 - Dark green text + surface: '0 0% 100%', // #ffffff + surfaceHover: '120 25% 95%', // #F1F8E9 + surfaceElevated: '0 0% 100%', + muted: '120 25% 95%', // #F1F8E9 + mutedForeground: '122 20% 40%', + border: '120 25% 91%', // #E8F5E9 + borderStrong: '120 26% 79%', // #C8E6C9 + error: '0 65% 67%', // #E57373 + success: '122 39% 49%', // Same as primary + warning: '36 100% 50%', + input: '0 0% 100%', + ring: '122 39% 49%', +}; + +const natureDark: ThemeColors = { + primary: '122 39% 49%', // #4CAF50 + primaryForeground: '0 0% 100%', + secondary: '122 30% 35%', // Muted green + secondaryForeground: '0 0% 100%', + background: '0 0% 7%', // #121212 + foreground: '0 0% 100%', // White + surface: '120 10% 12%', // Slight green tint + surfaceHover: '120 10% 16%', + surfaceElevated: '120 10% 14%', + muted: '120 10% 20%', + mutedForeground: '120 10% 60%', + border: '120 10% 25%', + borderStrong: '120 10% 35%', + error: '0 65% 57%', + success: '122 50% 55%', + warning: '48 100% 50%', + input: '120 10% 14%', + ring: '122 39% 49%', +}; + +const stoneLight: ThemeColors = { + primary: '200 18% 46%', // #607D8B - Blue gray + primaryForeground: '0 0% 100%', + secondary: '200 15% 62%', // #90A4AE - Light slate + secondaryForeground: '0 0% 0%', + background: '210 17% 97%', // #F5F7F9 - Very light blue gray + foreground: '200 19% 18%', // #263238 - Dark slate + surface: '0 0% 100%', + surfaceHover: '200 10% 94%', // #ECEFF1 + surfaceElevated: '0 0% 100%', + muted: '200 10% 94%', // #ECEFF1 + mutedForeground: '200 10% 45%', + border: '200 10% 88%', // #CFD8DC + borderStrong: '200 12% 75%', // #B0BEC5 + error: '4 90% 63%', // #EF5350 + success: '145 63% 42%', + warning: '36 100% 50%', + input: '0 0% 100%', + ring: '200 18% 46%', +}; + +const stoneDark: ThemeColors = { + primary: '200 15% 52%', // #78909C - Lighter in dark mode + primaryForeground: '0 0% 0%', + secondary: '200 12% 35%', + secondaryForeground: '0 0% 100%', + background: '0 0% 7%', // #121212 + foreground: '0 0% 100%', + surface: '200 10% 12%', + surfaceHover: '200 10% 16%', + surfaceElevated: '200 10% 14%', + muted: '200 10% 20%', + mutedForeground: '200 10% 60%', + border: '200 10% 25%', + borderStrong: '200 10% 35%', + error: '4 90% 58%', + success: '145 63% 49%', + warning: '48 100% 50%', + input: '200 10% 14%', + ring: '200 15% 52%', +}; + +const oceanLight: ThemeColors = { + primary: '199 98% 45%', // #039BE5 - Bright blue + primaryForeground: '0 0% 100%', + secondary: '199 92% 64%', // #4FC3F7 - Light blue + secondaryForeground: '0 0% 0%', + background: '199 100% 97%', // #F5FCFF - Very light blue + foreground: '199 100% 18%', // #01579B - Dark blue + surface: '0 0% 100%', + surfaceHover: '199 100% 94%', // #E1F5FE + surfaceElevated: '0 0% 100%', + muted: '199 100% 94%', // #E1F5FE + mutedForeground: '199 50% 40%', + border: '199 71% 87%', // #B3E5FC + borderStrong: '199 79% 76%', // #81D4FA + error: '4 90% 63%', // #EF5350 + success: '145 63% 42%', + warning: '36 100% 50%', + input: '0 0% 100%', + ring: '199 98% 45%', +}; + +const oceanDark: ThemeColors = { + primary: '199 98% 48%', // Slightly brighter in dark + primaryForeground: '0 0% 0%', + secondary: '199 60% 35%', + secondaryForeground: '0 0% 100%', + background: '0 0% 7%', // #121212 + foreground: '0 0% 100%', + surface: '199 30% 12%', // Slight blue tint + surfaceHover: '199 30% 16%', + surfaceElevated: '199 30% 14%', + muted: '199 20% 20%', + mutedForeground: '199 20% 60%', + border: '199 20% 25%', + borderStrong: '199 20% 35%', + error: '4 90% 58%', + success: '145 63% 49%', + warning: '48 100% 50%', + input: '199 30% 14%', + ring: '199 98% 48%', +}; + +/** + * Complete theme variant definitions + */ +export const THEME_DEFINITIONS: Record = { + lume: { + name: 'lume', + label: 'Lume', + emoji: '✨', + hue: 47, + light: lumeLight, + dark: lumeDark, + }, + nature: { + name: 'nature', + label: 'Nature', + emoji: '🌿', + hue: 122, + light: natureLight, + dark: natureDark, + }, + stone: { + name: 'stone', + label: 'Stone', + emoji: '🪨', + hue: 200, + light: stoneLight, + dark: stoneDark, + }, + ocean: { + name: 'ocean', + label: 'Ocean', + emoji: '🌊', + hue: 199, + light: oceanLight, + dark: oceanDark, + }, +}; + +/** + * Default theme configuration + */ +export const DEFAULT_MODE = 'system' as const; +export const DEFAULT_VARIANT = 'lume' as const; + +/** + * CSS variable prefix + */ +export const CSS_VAR_PREFIX = '--color' as const; + +/** + * LocalStorage key suffix + */ +export const STORAGE_KEY_SUFFIX = '-theme' as const; diff --git a/packages/shared-theme/src/index.ts b/packages/shared-theme/src/index.ts new file mode 100644 index 000000000..70255736a --- /dev/null +++ b/packages/shared-theme/src/index.ts @@ -0,0 +1,43 @@ +// Types +export type { + ThemeMode, + ThemeVariant, + EffectiveMode, + ThemeState, + ThemeColors, + ThemeVariantDefinition, + AppThemeConfig, + ThemeStore, + HSLValue, +} from './types'; + +// Constants +export { + THEME_VARIANTS, + THEME_DEFINITIONS, + DEFAULT_MODE, + DEFAULT_VARIANT, + CSS_VAR_PREFIX, + STORAGE_KEY_SUFFIX, +} from './constants'; + +// Store +export { createThemeStore, APP_THEME_CONFIGS } from './store.svelte'; + +// Utils +export { + isBrowser, + getSystemPreference, + createSystemPreferenceListener, + getThemeColors, + colorsToCssVars, + applyThemeToDocument, + loadThemeFromStorage, + saveThemeToStorage, + parseHSL, + createHSL, + adjustLightness, + adjustSaturation, + getContrastColor, + generateThemeCSS, +} from './utils'; diff --git a/packages/shared-theme/src/store.svelte.ts b/packages/shared-theme/src/store.svelte.ts new file mode 100644 index 000000000..7b68e02c1 --- /dev/null +++ b/packages/shared-theme/src/store.svelte.ts @@ -0,0 +1,227 @@ +import type { + ThemeMode, + ThemeVariant, + EffectiveMode, + ThemeStore, + AppThemeConfig, + HSLValue, +} from './types'; +import { + THEME_VARIANTS, + DEFAULT_MODE, + DEFAULT_VARIANT, + STORAGE_KEY_SUFFIX, +} from './constants'; +import { + isBrowser, + getSystemPreference, + createSystemPreferenceListener, + applyThemeToDocument, + loadThemeFromStorage, + saveThemeToStorage, +} from './utils'; + +/** + * Create a theme store for your app + * + * @example + * ```typescript + * // Basic usage + * import { createThemeStore } from '@manacore/shared-theme'; + * + * export const theme = createThemeStore({ appId: 'myapp' }); + * + * // With custom primary color + * export const theme = createThemeStore({ + * appId: 'memoro', + * primaryColor: { + * light: '47 95% 58%', // Gold + * dark: '47 95% 58%', + * }, + * }); + * ``` + */ +export function createThemeStore(config: AppThemeConfig): ThemeStore { + const { + appId, + defaultMode = DEFAULT_MODE, + defaultVariant = DEFAULT_VARIANT, + primaryColor, + } = config; + + const storageKey = `${appId}${STORAGE_KEY_SUFFIX}`; + + // Svelte 5 runes state + let mode = $state(defaultMode); + let variant = $state(defaultVariant); + let effectiveMode = $state('light'); + + // Derived state + const isDark = $derived(effectiveMode === 'dark'); + + /** + * Calculate effective mode from current mode and system preference + */ + function calculateEffectiveMode(currentMode: ThemeMode): EffectiveMode { + if (currentMode === 'system') { + return getSystemPreference(); + } + return currentMode; + } + + /** + * Apply current theme to document and save to storage + */ + function applyTheme(): void { + const newEffectiveMode = calculateEffectiveMode(mode); + effectiveMode = newEffectiveMode; + + applyThemeToDocument(variant, newEffectiveMode, primaryColor); + saveThemeToStorage(storageKey, mode, variant); + } + + /** + * Set theme mode + */ + function setMode(newMode: ThemeMode): void { + if (newMode === mode) return; + mode = newMode; + applyTheme(); + } + + /** + * Set theme variant + */ + function setVariant(newVariant: ThemeVariant): void { + if (!THEME_VARIANTS.includes(newVariant)) { + console.warn(`Invalid theme variant: ${newVariant}`); + return; + } + if (newVariant === variant) return; + variant = newVariant; + applyTheme(); + } + + /** + * Toggle between light and dark mode + * If currently on system, switches to opposite of effective mode + */ + function toggleMode(): void { + if (mode === 'system') { + // Switch to opposite of current effective mode + setMode(effectiveMode === 'dark' ? 'light' : 'dark'); + } else { + setMode(mode === 'dark' ? 'light' : 'dark'); + } + } + + /** + * Cycle through modes: light → dark → system → light + */ + function cycleMode(): void { + const modes: ThemeMode[] = ['light', 'dark', 'system']; + const currentIndex = modes.indexOf(mode); + const nextIndex = (currentIndex + 1) % modes.length; + setMode(modes[nextIndex]); + } + + /** + * Initialize theme store + * - Loads saved preferences from localStorage + * - Sets up system preference listener + * - Applies initial theme + * + * @returns Cleanup function to remove listeners + */ + function initialize(): () => void { + if (!isBrowser()) { + return () => {}; + } + + // Load saved preferences + const saved = loadThemeFromStorage(storageKey); + if (saved) { + if (saved.mode && ['light', 'dark', 'system'].includes(saved.mode)) { + mode = saved.mode as ThemeMode; + } + if (saved.variant && THEME_VARIANTS.includes(saved.variant as ThemeVariant)) { + variant = saved.variant as ThemeVariant; + } + } + + // Apply initial theme + applyTheme(); + + // Listen for system preference changes + const cleanup = createSystemPreferenceListener((isDark) => { + if (mode === 'system') { + effectiveMode = isDark ? 'dark' : 'light'; + applyThemeToDocument(variant, effectiveMode, primaryColor); + } + }); + + return cleanup; + } + + return { + get mode() { + return mode; + }, + get variant() { + return variant; + }, + get effectiveMode() { + return effectiveMode; + }, + get isDark() { + return isDark; + }, + get variants() { + return THEME_VARIANTS; + }, + + setMode, + setVariant, + toggleMode, + cycleMode, + initialize, + }; +} + +/** + * Pre-defined app configurations for convenience + */ +export const APP_THEME_CONFIGS = { + memoro: { + appId: 'memoro', + defaultVariant: 'lume' as ThemeVariant, + primaryColor: { + light: '47 95% 58%' as HSLValue, // Gold #f8d62b + dark: '47 95% 58%' as HSLValue, + }, + }, + manacore: { + appId: 'manacore', + defaultVariant: 'ocean' as ThemeVariant, + primaryColor: { + light: '239 84% 67%' as HSLValue, // Indigo #6366f1 + dark: '239 84% 67%' as HSLValue, + }, + }, + manadeck: { + appId: 'manadeck', + defaultVariant: 'ocean' as ThemeVariant, + primaryColor: { + light: '239 84% 67%' as HSLValue, // Indigo #6366f1 + dark: '239 84% 67%' as HSLValue, + }, + }, + maerchenzauber: { + appId: 'maerchenzauber', + defaultVariant: 'nature' as ThemeVariant, + primaryColor: { + light: '280 60% 55%' as HSLValue, // Purple (storytelling magic) + dark: '280 60% 60%' as HSLValue, + }, + }, +} as const; diff --git a/packages/shared-theme/src/types.ts b/packages/shared-theme/src/types.ts new file mode 100644 index 000000000..25995a9e4 --- /dev/null +++ b/packages/shared-theme/src/types.ts @@ -0,0 +1,133 @@ +/** + * Theme mode - user preference for light/dark appearance + */ +export type ThemeMode = 'light' | 'dark' | 'system'; + +/** + * Theme variant - visual style/color scheme + * All apps share the same 4 variants + */ +export type ThemeVariant = 'lume' | 'nature' | 'stone' | 'ocean'; + +/** + * Effective mode - the actual rendered mode (resolved from system preference) + */ +export type EffectiveMode = 'light' | 'dark'; + +/** + * Complete theme state + */ +export interface ThemeState { + mode: ThemeMode; + variant: ThemeVariant; + effectiveMode: EffectiveMode; +} + +/** + * HSL color value (without hsl() wrapper) + * Format: "H S% L%" e.g. "47 95% 58%" + */ +export type HSLValue = string; + +/** + * Theme color definition using HSL values + */ +export interface ThemeColors { + /** Primary brand color */ + primary: HSLValue; + /** Primary color for text on primary background */ + primaryForeground: HSLValue; + /** Secondary accent color */ + secondary: HSLValue; + /** Secondary foreground */ + secondaryForeground: HSLValue; + /** Page background */ + background: HSLValue; + /** Main text color */ + foreground: HSLValue; + /** Card/content surface */ + surface: HSLValue; + /** Surface hover state */ + surfaceHover: HSLValue; + /** Elevated surface (modals, dropdowns) */ + surfaceElevated: HSLValue; + /** Muted/disabled elements */ + muted: HSLValue; + /** Muted text */ + mutedForeground: HSLValue; + /** Border color */ + border: HSLValue; + /** Strong border (focus, active) */ + borderStrong: HSLValue; + /** Error/destructive color */ + error: HSLValue; + /** Success color */ + success: HSLValue; + /** Warning color */ + warning: HSLValue; + /** Input background */ + input: HSLValue; + /** Focus ring color */ + ring: HSLValue; +} + +/** + * Theme variant definition with light and dark mode colors + */ +export interface ThemeVariantDefinition { + name: string; + label: string; + emoji: string; + /** The primary hue for this variant (used for accent colors) */ + hue: number; + light: ThemeColors; + dark: ThemeColors; +} + +/** + * App-specific theme configuration + */ +export interface AppThemeConfig { + /** App identifier for localStorage key */ + appId: string; + /** Default theme mode */ + defaultMode?: ThemeMode; + /** Default theme variant */ + defaultVariant?: ThemeVariant; + /** + * App-specific primary color override (HSL value) + * This allows each app to have its own brand color + * while sharing the same theme variants + */ + primaryColor?: { + light: HSLValue; + dark: HSLValue; + }; +} + +/** + * Theme store interface + */ +export interface ThemeStore { + /** Current theme mode (user preference) */ + readonly mode: ThemeMode; + /** Current theme variant */ + readonly variant: ThemeVariant; + /** Effective mode (resolved from system) */ + readonly effectiveMode: EffectiveMode; + /** Whether dark mode is active */ + readonly isDark: boolean; + /** All available variants */ + readonly variants: readonly ThemeVariant[]; + + /** Set theme mode */ + setMode: (mode: ThemeMode) => void; + /** Set theme variant */ + setVariant: (variant: ThemeVariant) => void; + /** Toggle between light and dark mode */ + toggleMode: () => void; + /** Cycle through modes: light → dark → system → light */ + cycleMode: () => void; + /** Initialize theme (call on mount) */ + initialize: () => () => void; +} diff --git a/packages/shared-theme/src/utils.ts b/packages/shared-theme/src/utils.ts new file mode 100644 index 000000000..b30751b33 --- /dev/null +++ b/packages/shared-theme/src/utils.ts @@ -0,0 +1,245 @@ +import type { ThemeColors, ThemeVariant, EffectiveMode, HSLValue } from './types'; +import { THEME_DEFINITIONS, CSS_VAR_PREFIX } from './constants'; + +/** + * Check if code is running in browser + */ +export function isBrowser(): boolean { + return typeof window !== 'undefined' && typeof document !== 'undefined'; +} + +/** + * Get system color scheme preference + */ +export function getSystemPreference(): EffectiveMode { + if (!isBrowser()) return 'light'; + return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; +} + +/** + * Create a media query listener for system preference changes + */ +export function createSystemPreferenceListener(callback: (isDark: boolean) => void): () => void { + if (!isBrowser()) return () => {}; + + const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); + + const handler = (e: MediaQueryListEvent) => callback(e.matches); + + // Modern browsers + if (mediaQuery.addEventListener) { + mediaQuery.addEventListener('change', handler); + return () => mediaQuery.removeEventListener('change', handler); + } + + // Legacy browsers + mediaQuery.addListener(handler); + return () => mediaQuery.removeListener(handler); +} + +/** + * Get colors for a specific variant and mode + */ +export function getThemeColors( + variant: ThemeVariant, + mode: EffectiveMode, + primaryOverride?: { light: HSLValue; dark: HSLValue } +): ThemeColors { + const definition = THEME_DEFINITIONS[variant]; + const colors = mode === 'dark' ? { ...definition.dark } : { ...definition.light }; + + // Apply app-specific primary color override + if (primaryOverride) { + const overrideColor = mode === 'dark' ? primaryOverride.dark : primaryOverride.light; + colors.primary = overrideColor; + colors.ring = overrideColor; + } + + return colors; +} + +/** + * Convert ThemeColors to CSS variables object + */ +export function colorsToCssVars(colors: ThemeColors): Record { + return { + [`${CSS_VAR_PREFIX}-primary`]: colors.primary, + [`${CSS_VAR_PREFIX}-primary-foreground`]: colors.primaryForeground, + [`${CSS_VAR_PREFIX}-secondary`]: colors.secondary, + [`${CSS_VAR_PREFIX}-secondary-foreground`]: colors.secondaryForeground, + [`${CSS_VAR_PREFIX}-background`]: colors.background, + [`${CSS_VAR_PREFIX}-foreground`]: colors.foreground, + [`${CSS_VAR_PREFIX}-surface`]: colors.surface, + [`${CSS_VAR_PREFIX}-surface-hover`]: colors.surfaceHover, + [`${CSS_VAR_PREFIX}-surface-elevated`]: colors.surfaceElevated, + [`${CSS_VAR_PREFIX}-muted`]: colors.muted, + [`${CSS_VAR_PREFIX}-muted-foreground`]: colors.mutedForeground, + [`${CSS_VAR_PREFIX}-border`]: colors.border, + [`${CSS_VAR_PREFIX}-border-strong`]: colors.borderStrong, + [`${CSS_VAR_PREFIX}-error`]: colors.error, + [`${CSS_VAR_PREFIX}-success`]: colors.success, + [`${CSS_VAR_PREFIX}-warning`]: colors.warning, + [`${CSS_VAR_PREFIX}-input`]: colors.input, + [`${CSS_VAR_PREFIX}-ring`]: colors.ring, + }; +} + +/** + * Apply theme to document + */ +export function applyThemeToDocument( + variant: ThemeVariant, + effectiveMode: EffectiveMode, + primaryOverride?: { light: HSLValue; dark: HSLValue } +): void { + if (!isBrowser()) return; + + const root = document.documentElement; + const colors = getThemeColors(variant, effectiveMode, primaryOverride); + const cssVars = colorsToCssVars(colors); + + // Set CSS variables + Object.entries(cssVars).forEach(([key, value]) => { + root.style.setProperty(key, value); + }); + + // Set data-theme attribute + root.setAttribute('data-theme', variant); + + // Set dark class + if (effectiveMode === 'dark') { + root.classList.add('dark'); + } else { + root.classList.remove('dark'); + } + + // Update color-scheme for native elements + root.style.colorScheme = effectiveMode; +} + +/** + * Load theme from localStorage + */ +export function loadThemeFromStorage(storageKey: string): { mode?: string; variant?: string } | null { + if (!isBrowser()) return null; + + try { + const stored = localStorage.getItem(storageKey); + if (stored) { + return JSON.parse(stored); + } + } catch (e) { + console.warn('Failed to load theme from storage:', e); + } + + return null; +} + +/** + * Save theme to localStorage + */ +export function saveThemeToStorage( + storageKey: string, + mode: string, + variant: string +): void { + if (!isBrowser()) return; + + try { + localStorage.setItem(storageKey, JSON.stringify({ mode, variant })); + } catch (e) { + console.warn('Failed to save theme to storage:', e); + } +} + +/** + * Parse HSL string to components + * Input: "47 95% 58%" -> { h: 47, s: 95, l: 58 } + */ +export function parseHSL(hsl: HSLValue): { h: number; s: number; l: number } { + const parts = hsl.split(' '); + return { + h: parseFloat(parts[0]), + s: parseFloat(parts[1]), + l: parseFloat(parts[2]), + }; +} + +/** + * Create HSL string from components + */ +export function createHSL(h: number, s: number, l: number): HSLValue { + return `${h} ${s}% ${l}%`; +} + +/** + * Adjust lightness of an HSL color + */ +export function adjustLightness(hsl: HSLValue, amount: number): HSLValue { + const { h, s, l } = parseHSL(hsl); + const newL = Math.max(0, Math.min(100, l + amount)); + return createHSL(h, s, newL); +} + +/** + * Adjust saturation of an HSL color + */ +export function adjustSaturation(hsl: HSLValue, amount: number): HSLValue { + const { h, s, l } = parseHSL(hsl); + const newS = Math.max(0, Math.min(100, s + amount)); + return createHSL(h, newS, l); +} + +/** + * Get contrasting text color (black or white) for a background + */ +export function getContrastColor(backgroundHSL: HSLValue): HSLValue { + const { l } = parseHSL(backgroundHSL); + // Use white text for dark backgrounds, black for light + return l > 55 ? '0 0% 0%' : '0 0% 100%'; +} + +/** + * Generate CSS string for all theme variants + * Useful for generating static CSS files + */ +export function generateThemeCSS( + primaryOverrides?: Record +): string { + let css = ''; + + // Root (default Lume light) + const defaultColors = getThemeColors('lume', 'light', primaryOverrides?.['lume']); + const defaultVars = colorsToCssVars(defaultColors); + css += ':root {\n'; + Object.entries(defaultVars).forEach(([key, value]) => { + css += ` ${key}: ${value};\n`; + }); + css += '}\n\n'; + + // Each variant + for (const [variantName, definition] of Object.entries(THEME_DEFINITIONS)) { + const variant = variantName as ThemeVariant; + const override = primaryOverrides?.[variant]; + + // Light mode + const lightColors = getThemeColors(variant, 'light', override); + const lightVars = colorsToCssVars(lightColors); + css += `[data-theme="${variant}"] {\n`; + Object.entries(lightVars).forEach(([key, value]) => { + css += ` ${key}: ${value};\n`; + }); + css += '}\n\n'; + + // Dark mode + const darkColors = getThemeColors(variant, 'dark', override); + const darkVars = colorsToCssVars(darkColors); + css += `[data-theme="${variant}"].dark,\n.dark[data-theme="${variant}"] {\n`; + Object.entries(darkVars).forEach(([key, value]) => { + css += ` ${key}: ${value};\n`; + }); + css += '}\n\n'; + } + + return css; +} diff --git a/packages/shared-theme/tsconfig.json b/packages/shared-theme/tsconfig.json new file mode 100644 index 000000000..cc6bd8b1d --- /dev/null +++ b/packages/shared-theme/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "declaration": true, + "declarationMap": true, + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1b3a43168..6a0072205 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -309,7 +309,7 @@ importers: version: 17.0.7(expo@54.0.25)(react@19.1.0) expo-router: specifier: ~6.0.14 - version: 6.0.15(evxcyavfmgswt4zg3ii4wlqsdm) + version: 6.0.15(ja35odoob22us44jnpjqapckaa) expo-secure-store: specifier: ~15.0.7 version: 15.0.7(expo@54.0.25) @@ -412,7 +412,7 @@ importers: version: 7.28.5 '@testing-library/react-native': specifier: ^13.3.3 - version: 13.3.3(jest@29.5.0)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react-test-renderer@19.1.0(react@19.1.0))(react@19.1.0) + version: 13.3.3(jest@29.5.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react-test-renderer@19.1.0(react@19.1.0))(react@19.1.0) '@types/jest': specifier: ^29.5.12 version: 29.5.14 @@ -430,10 +430,10 @@ importers: version: 10.0.0 jest: specifier: ^29.2.1 - version: 29.5.0(@types/node@18.15.11)(ts-node@10.9.2(@types/node@18.15.11)(typescript@5.9.3)) + version: 29.5.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) jest-expo: specifier: ~54.0.13 - version: 54.0.13(@babel/core@7.28.5)(expo@54.0.25)(jest@29.5.0)(react-dom@19.1.0(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(webpack@5.100.2) + version: 54.0.13(@babel/core@7.28.5)(expo@54.0.25)(jest@29.5.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)))(react-dom@19.1.0(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(webpack@5.100.2) patch-package: specifier: ^8.0.0 version: 8.0.1 @@ -461,12 +461,24 @@ importers: '@manacore/shared-icons': specifier: workspace:* version: link:../../../packages/shared-icons + '@manacore/shared-subscription-types': + specifier: workspace:* + version: link:../../../packages/shared-subscription-types + '@manacore/shared-subscription-ui': + specifier: workspace:* + version: link:../../../packages/shared-subscription-ui '@manacore/shared-supabase': specifier: workspace:* version: link:../../../packages/shared-supabase '@manacore/shared-tailwind': specifier: workspace:* version: link:../../../packages/shared-tailwind + '@manacore/shared-theme': + specifier: workspace:* + version: link:../../../packages/shared-theme + '@manacore/shared-theme-ui': + specifier: workspace:* + version: link:../../../packages/shared-theme-ui '@manacore/shared-types': specifier: workspace:* version: link:../../../packages/shared-types @@ -482,13 +494,16 @@ importers: devDependencies: '@sveltejs/adapter-auto': specifier: ^7.0.0 - version: 7.0.0(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))) + version: 7.0.0(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))) '@sveltejs/kit': specifier: ^2.47.1 - version: 2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + version: 2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) '@sveltejs/vite-plugin-svelte': specifier: ^6.2.1 - version: 6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + version: 6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + '@tailwindcss/postcss': + specifier: ^4.1.17 + version: 4.1.17 autoprefixer: specifier: ^10.4.22 version: 10.4.22(postcss@8.5.6) @@ -509,7 +524,7 @@ importers: version: 5.9.3 vite: specifier: ^7.1.10 - version: 7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + version: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) maerchenzauber/packages/shared-types: {} @@ -520,7 +535,7 @@ importers: version: 3.6.3(@types/node@24.10.1)(@types/react-dom@19.2.3(@types/react@18.3.27))(@types/react@18.3.27)(lightningcss@1.30.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(terser@5.44.1) '@astrojs/tailwind': specifier: ^5.1.0 - version: 5.1.5(astro@5.16.0(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) + version: 5.1.5(astro@5.16.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) '@iconify-json/heroicons': specifier: ^1.2.2 version: 1.2.3 @@ -532,7 +547,7 @@ importers: version: 1.2.23 astro: specifier: ^5.16.0 - version: 5.16.0(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) + version: 5.16.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) astro-icon: specifier: ^1.1.5 version: 1.1.5 @@ -679,12 +694,24 @@ importers: '@manacore/shared-icons': specifier: workspace:* version: link:../../../packages/shared-icons + '@manacore/shared-subscription-types': + specifier: workspace:* + version: link:../../../packages/shared-subscription-types + '@manacore/shared-subscription-ui': + specifier: workspace:* + version: link:../../../packages/shared-subscription-ui '@manacore/shared-supabase': specifier: workspace:* version: link:../../../packages/shared-supabase '@manacore/shared-tailwind': specifier: workspace:* version: link:../../../packages/shared-tailwind + '@manacore/shared-theme': + specifier: workspace:* + version: link:../../../packages/shared-theme + '@manacore/shared-theme-ui': + specifier: workspace:* + version: link:../../../packages/shared-theme-ui '@manacore/shared-types': specifier: workspace:* version: link:../../../packages/shared-types @@ -706,16 +733,19 @@ importers: version: 1.56.1 '@sveltejs/adapter-auto': specifier: ^7.0.0 - version: 7.0.0(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))) + version: 7.0.0(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))) '@sveltejs/adapter-netlify': specifier: ^5.2.4 - version: 5.2.4(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))) + version: 5.2.4(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))) '@sveltejs/kit': specifier: ^2.15.7 - version: 2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + version: 2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) '@sveltejs/vite-plugin-svelte': specifier: ^5.0.4 - version: 5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + version: 5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + '@tailwindcss/postcss': + specifier: ^4.1.17 + version: 4.1.17 '@types/node': specifier: ^22.10.5 version: 22.19.1 @@ -754,10 +784,10 @@ importers: version: 5.9.3 vite: specifier: ^6.0.7 - version: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + version: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) vitest: specifier: ^3.2.4 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.1)(@vitest/ui@3.2.4)(jiti@1.21.7)(jsdom@20.0.3)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.1)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@20.0.3)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) manadeck/apps/mobile: dependencies: @@ -905,13 +935,13 @@ importers: version: 8.17.1 eslint: specifier: ^9.25.1 - version: 9.39.1(jiti@1.21.7) + version: 9.39.1(jiti@2.6.1) eslint-config-expo: specifier: ~10.0.0 - version: 10.0.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) + version: 10.0.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) eslint-config-prettier: specifier: ^10.1.2 - version: 10.1.8(eslint@9.39.1(jiti@1.21.7)) + version: 10.1.8(eslint@9.39.1(jiti@2.6.1)) prettier: specifier: ^3.2.5 version: 3.6.2 @@ -942,12 +972,24 @@ importers: '@manacore/shared-icons': specifier: workspace:* version: link:../../../packages/shared-icons + '@manacore/shared-subscription-types': + specifier: workspace:* + version: link:../../../packages/shared-subscription-types + '@manacore/shared-subscription-ui': + specifier: workspace:* + version: link:../../../packages/shared-subscription-ui '@manacore/shared-supabase': specifier: workspace:* version: link:../../../packages/shared-supabase '@manacore/shared-tailwind': specifier: workspace:* version: link:../../../packages/shared-tailwind + '@manacore/shared-theme': + specifier: workspace:* + version: link:../../../packages/shared-theme + '@manacore/shared-theme-ui': + specifier: workspace:* + version: link:../../../packages/shared-theme-ui '@manacore/shared-types': specifier: workspace:* version: link:../../../packages/shared-types @@ -963,13 +1005,16 @@ importers: devDependencies: '@sveltejs/adapter-auto': specifier: ^7.0.0 - version: 7.0.0(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))) + version: 7.0.0(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))) '@sveltejs/kit': specifier: ^2.47.1 - version: 2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + version: 2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) '@sveltejs/vite-plugin-svelte': specifier: ^6.2.1 - version: 6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + version: 6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + '@tailwindcss/postcss': + specifier: ^4.1.17 + version: 4.1.17 '@tailwindcss/typography': specifier: ^0.5.19 version: 0.5.19(tailwindcss@4.1.17) @@ -993,7 +1038,7 @@ importers: version: 5.9.3 vite: specifier: ^7.1.10 - version: 7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + version: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) manadeck/backend: dependencies: @@ -1072,13 +1117,13 @@ importers: version: 6.0.3 eslint: specifier: ^9.18.0 - version: 9.39.1(jiti@1.21.7) + version: 9.39.1(jiti@2.6.1) eslint-config-prettier: specifier: ^10.0.1 - version: 10.1.8(eslint@9.39.1(jiti@1.21.7)) + version: 10.1.8(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.2 - version: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.1(jiti@1.21.7)))(eslint@9.39.1(jiti@1.21.7))(prettier@3.6.2) + version: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))(prettier@3.6.2) globals: specifier: ^16.0.0 version: 16.5.0 @@ -1111,7 +1156,7 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.20.0 - version: 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) + version: 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) memoro/apps/landing: dependencies: @@ -1120,7 +1165,7 @@ importers: version: 0.9.5(prettier@3.6.2)(typescript@5.9.3) '@astrojs/mdx': specifier: ^4.0.8 - version: 4.3.12(astro@5.16.0(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)) + version: 4.3.12(astro@5.16.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)) '@astrojs/rss': specifier: ^4.0.12 version: 4.0.14 @@ -1132,7 +1177,7 @@ importers: version: 1.2.3 astro: specifier: ^5.3.0 - version: 5.16.0(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) + version: 5.16.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) astro-icon: specifier: ^1.1.5 version: 1.1.5 @@ -1148,7 +1193,7 @@ importers: devDependencies: '@astrojs/tailwind': specifier: ^6.0.0 - version: 6.0.2(astro@5.16.0(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) + version: 6.0.2(astro@5.16.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) '@tailwindcss/typography': specifier: ^0.5.16 version: 0.5.19(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1)) @@ -1365,25 +1410,25 @@ importers: version: 19.1.17 '@typescript-eslint/eslint-plugin': specifier: ^8.44.1 - version: 8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) + version: 8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.44.1 - version: 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) + version: 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.36.0 - version: 9.39.1(jiti@1.21.7) + version: 9.39.1(jiti@2.6.1) eslint-config-universe: specifier: ^15.0.3 - version: 15.0.3(@types/eslint@9.6.1)(eslint@9.39.1(jiti@1.21.7))(prettier@3.6.2)(typescript@5.9.3) + version: 15.0.3(@types/eslint@9.6.1)(eslint@9.39.1(jiti@2.6.1))(prettier@3.6.2)(typescript@5.9.3) eslint-plugin-react: specifier: ^7.37.5 - version: 7.37.5(eslint@9.39.1(jiti@1.21.7)) + version: 7.37.5(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-react-hooks: specifier: ^5.2.0 - version: 5.2.0(eslint@9.39.1(jiti@1.21.7)) + version: 5.2.0(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-unused-imports: specifier: ^4.2.0 - version: 4.3.0(@typescript-eslint/eslint-plugin@8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.1(jiti@1.21.7)) + version: 4.3.0(@typescript-eslint/eslint-plugin@8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)) patch-package: specifier: ^8.0.0 version: 8.0.1 @@ -1420,12 +1465,24 @@ importers: '@manacore/shared-icons': specifier: workspace:* version: link:../../../packages/shared-icons + '@manacore/shared-subscription-types': + specifier: workspace:* + version: link:../../../packages/shared-subscription-types + '@manacore/shared-subscription-ui': + specifier: workspace:* + version: link:../../../packages/shared-subscription-ui '@manacore/shared-supabase': specifier: workspace:* version: link:../../../packages/shared-supabase '@manacore/shared-tailwind': specifier: workspace:* version: link:../../../packages/shared-tailwind + '@manacore/shared-theme': + specifier: workspace:* + version: link:../../../packages/shared-theme + '@manacore/shared-theme-ui': + specifier: workspace:* + version: link:../../../packages/shared-theme-ui '@manacore/shared-types': specifier: workspace:* version: link:../../../packages/shared-types @@ -1456,16 +1513,19 @@ importers: devDependencies: '@sveltejs/adapter-netlify': specifier: ^5.2.4 - version: 5.2.4(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))) + version: 5.2.4(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))) '@sveltejs/adapter-static': specifier: ^3.0.10 - version: 3.0.10(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))) + version: 3.0.10(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))) '@sveltejs/kit': specifier: ^2.43.2 - version: 2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + version: 2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) '@sveltejs/vite-plugin-svelte': specifier: ^6.2.0 - version: 6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + version: 6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + '@tailwindcss/postcss': + specifier: ^4.1.17 + version: 4.1.17 autoprefixer: specifier: ^10.4.21 version: 10.4.22(postcss@8.5.6) @@ -1486,7 +1546,7 @@ importers: version: 5.9.3 vite: specifier: ^7.1.7 - version: 7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + version: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) packages/shared-auth: dependencies: @@ -1587,6 +1647,31 @@ importers: specifier: ^0.5.19 version: 0.5.19(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1)) + packages/shared-theme: + devDependencies: + svelte: + specifier: ^5.0.0 + version: 5.43.14 + typescript: + specifier: ^5.0.0 + version: 5.9.3 + + packages/shared-theme-ui: + dependencies: + '@manacore/shared-icons': + specifier: workspace:* + version: link:../shared-icons + '@manacore/shared-theme': + specifier: workspace:* + version: link:../shared-theme + devDependencies: + svelte: + specifier: ^5.0.0 + version: 5.43.14 + typescript: + specifier: ^5.0.0 + version: 5.9.3 + packages/shared-types: devDependencies: typescript: @@ -4881,6 +4966,94 @@ packages: '@swc/helpers@0.5.17': resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} + '@tailwindcss/node@4.1.17': + resolution: {integrity: sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==} + + '@tailwindcss/oxide-android-arm64@4.1.17': + resolution: {integrity: sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.17': + resolution: {integrity: sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.17': + resolution: {integrity: sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.17': + resolution: {integrity: sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17': + resolution: {integrity: sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.17': + resolution: {integrity: sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.17': + resolution: {integrity: sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.17': + resolution: {integrity: sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.17': + resolution: {integrity: sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.17': + resolution: {integrity: sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.17': + resolution: {integrity: sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.17': + resolution: {integrity: sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.17': + resolution: {integrity: sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==} + engines: {node: '>= 10'} + + '@tailwindcss/postcss@4.1.17': + resolution: {integrity: sha512-+nKl9N9mN5uJ+M7dBOOCzINw94MPstNR/GtIhz1fpZysxL/4a+No64jCBD6CPN+bIHWFx3KWuu8XJRrj/572Dw==} + '@tailwindcss/typography@0.5.19': resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==} peerDependencies: @@ -8945,6 +9118,10 @@ packages: resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + joi@17.13.3: resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} @@ -13342,12 +13519,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@astrojs/mdx@4.3.12(astro@5.16.0(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))': + '@astrojs/mdx@4.3.12(astro@5.16.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))': dependencies: '@astrojs/markdown-remark': 6.3.9 '@mdx-js/mdx': 3.1.1 acorn: 8.15.0 - astro: 5.16.0(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) + astro: 5.16.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) es-module-lexer: 1.7.0 estree-util-visit: 2.0.0 hast-util-to-html: 9.0.5 @@ -13419,9 +13596,9 @@ snapshots: stream-replace-string: 2.0.0 zod: 3.25.76 - '@astrojs/tailwind@5.1.5(astro@5.16.0(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))': + '@astrojs/tailwind@5.1.5(astro@5.16.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))': dependencies: - astro: 5.16.0(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) + astro: 5.16.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) autoprefixer: 10.4.22(postcss@8.5.6) postcss: 8.5.6 postcss-load-config: 4.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) @@ -13439,6 +13616,16 @@ snapshots: transitivePeerDependencies: - ts-node + '@astrojs/tailwind@6.0.2(astro@5.16.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))': + dependencies: + astro: 5.16.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) + autoprefixer: 10.4.22(postcss@8.5.6) + postcss: 8.5.6 + postcss-load-config: 4.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) + tailwindcss: 3.4.18(tsx@4.20.6)(yaml@2.8.1) + transitivePeerDependencies: + - ts-node + '@astrojs/telemetry@3.3.0': dependencies: ci-info: 4.3.1 @@ -14344,9 +14531,9 @@ snapshots: eslint: 8.57.1 eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1(jiti@1.21.7))': + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1(jiti@2.6.1))': dependencies: - eslint: 9.39.1(jiti@1.21.7) + eslint: 9.39.1(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} @@ -15595,6 +15782,41 @@ snapshots: - supports-color - ts-node + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3))': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.19.1 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + '@jest/core@30.2.0(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3))': dependencies: '@jest/console': 30.2.0 @@ -17349,37 +17571,37 @@ snapshots: dependencies: acorn: 8.15.0 - '@sveltejs/adapter-auto@7.0.0(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))': + '@sveltejs/adapter-auto@7.0.0(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))': dependencies: - '@sveltejs/kit': 2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + '@sveltejs/kit': 2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) - '@sveltejs/adapter-auto@7.0.0(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))': + '@sveltejs/adapter-auto@7.0.0(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))': dependencies: - '@sveltejs/kit': 2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + '@sveltejs/kit': 2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) - '@sveltejs/adapter-netlify@5.2.4(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))': + '@sveltejs/adapter-netlify@5.2.4(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))': dependencies: '@iarna/toml': 2.2.5 - '@sveltejs/kit': 2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + '@sveltejs/kit': 2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) esbuild: 0.25.12 set-cookie-parser: 2.7.2 - '@sveltejs/adapter-netlify@5.2.4(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))': + '@sveltejs/adapter-netlify@5.2.4(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))': dependencies: '@iarna/toml': 2.2.5 - '@sveltejs/kit': 2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + '@sveltejs/kit': 2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) esbuild: 0.25.12 set-cookie-parser: 2.7.2 - '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))': + '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))': dependencies: - '@sveltejs/kit': 2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + '@sveltejs/kit': 2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) - '@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))': + '@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))': dependencies: '@standard-schema/spec': 1.0.0 '@sveltejs/acorn-typescript': 1.0.7(acorn@8.15.0) - '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) '@types/cookie': 0.6.0 acorn: 8.15.0 cookie: 0.6.0 @@ -17392,13 +17614,13 @@ snapshots: set-cookie-parser: 2.7.2 sirv: 3.0.2 svelte: 5.43.14 - vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) - '@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))': + '@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))': dependencies: '@standard-schema/spec': 1.0.0 '@sveltejs/acorn-typescript': 1.0.7(acorn@8.15.0) - '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) '@types/cookie': 0.6.0 acorn: 8.15.0 cookie: 0.6.0 @@ -17411,48 +17633,48 @@ snapshots: set-cookie-parser: 2.7.2 sirv: 3.0.2 svelte: 5.43.14 - vite: 7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) - '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))': + '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))': dependencies: - '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) debug: 4.4.3 svelte: 5.43.14 - vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte-inspector@5.0.1(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))': + '@sveltejs/vite-plugin-svelte-inspector@5.0.1(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))': dependencies: - '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) debug: 4.4.3 svelte: 5.43.14 - vite: 7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))': + '@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) debug: 4.4.3 deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.21 svelte: 5.43.14 - vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) - vitefu: 1.1.1(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + vitefu: 1.1.1(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))': + '@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 5.0.1(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + '@sveltejs/vite-plugin-svelte-inspector': 5.0.1(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)))(svelte@5.43.14)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) debug: 4.4.3 deepmerge: 4.3.1 magic-string: 0.30.21 svelte: 5.43.14 - vite: 7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) - vitefu: 1.1.1(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + vite: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + vitefu: 1.1.1(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) transitivePeerDependencies: - supports-color @@ -17539,6 +17761,75 @@ snapshots: dependencies: tslib: 2.8.1 + '@tailwindcss/node@4.1.17': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.1.17 + + '@tailwindcss/oxide-android-arm64@4.1.17': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.17': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.17': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.17': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.17': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.17': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.17': + optional: true + + '@tailwindcss/oxide@4.1.17': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.17 + '@tailwindcss/oxide-darwin-arm64': 4.1.17 + '@tailwindcss/oxide-darwin-x64': 4.1.17 + '@tailwindcss/oxide-freebsd-x64': 4.1.17 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.17 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.17 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.17 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.17 + '@tailwindcss/oxide-linux-x64-musl': 4.1.17 + '@tailwindcss/oxide-wasm32-wasi': 4.1.17 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.17 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.17 + + '@tailwindcss/postcss@4.1.17': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.1.17 + '@tailwindcss/oxide': 4.1.17 + postcss: 8.5.6 + tailwindcss: 4.1.17 + '@tailwindcss/typography@0.5.19(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))': dependencies: postcss-selector-parser: 6.0.10 @@ -17549,7 +17840,7 @@ snapshots: postcss-selector-parser: 6.0.10 tailwindcss: 4.1.17 - '@testing-library/react-native@13.3.3(jest@29.5.0)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react-test-renderer@19.1.0(react@19.1.0))(react@19.1.0)': + '@testing-library/react-native@13.3.3(jest@29.5.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react-test-renderer@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: jest-matcher-utils: 30.2.0 picocolors: 1.1.1 @@ -17559,7 +17850,7 @@ snapshots: react-test-renderer: 19.1.0(react@19.1.0) redent: 3.0.0 optionalDependencies: - jest: 29.5.0(@types/node@18.15.11)(ts-node@10.9.2(@types/node@18.15.11)(typescript@5.9.3)) + jest: 29.5.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) '@testing-library/react-native@13.3.3(jest@30.2.0)(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react-test-renderer@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: @@ -17984,15 +18275,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.47.0 - '@typescript-eslint/type-utils': 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.47.0 - eslint: 9.39.1(jiti@1.21.7) + eslint: 9.39.1(jiti@2.6.1) graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 @@ -18039,14 +18330,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.47.0 '@typescript-eslint/types': 8.47.0 '@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.47.0 debug: 4.4.3 - eslint: 9.39.1(jiti@1.21.7) + eslint: 9.39.1(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -18120,13 +18411,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.47.0 '@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3 - eslint: 9.39.1(jiti@1.21.7) + eslint: 9.39.1(jiti@2.6.1) ts-api-utils: 2.1.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: @@ -18240,13 +18531,13 @@ snapshots: - supports-color - typescript - '@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) '@typescript-eslint/scope-manager': 8.47.0 '@typescript-eslint/types': 8.47.0 '@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3) - eslint: 9.39.1(jiti@1.21.7) + eslint: 9.39.1(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -18376,13 +18667,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@7.2.4(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))': + '@vitest/mocker@3.2.4(vite@7.2.4(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.2.4(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.2.4(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) '@vitest/pretty-format@3.2.4': dependencies: @@ -18413,7 +18704,7 @@ snapshots: sirv: 3.0.2 tinyglobby: 0.2.15 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.1)(@vitest/ui@3.2.4)(jiti@1.21.7)(jsdom@20.0.3)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.1)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@20.0.3)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) '@vitest/utils@3.2.4': dependencies: @@ -18915,6 +19206,108 @@ snapshots: - uploadthing - yaml + astro@5.16.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1): + dependencies: + '@astrojs/compiler': 2.13.0 + '@astrojs/internal-helpers': 0.7.5 + '@astrojs/markdown-remark': 6.3.9 + '@astrojs/telemetry': 3.3.0 + '@capsizecss/unpack': 3.0.1 + '@oslojs/encoding': 1.1.0 + '@rollup/pluginutils': 5.3.0(rollup@4.53.3) + acorn: 8.15.0 + aria-query: 5.3.2 + axobject-query: 4.1.0 + boxen: 8.0.1 + ci-info: 4.3.1 + clsx: 2.1.1 + common-ancestor-path: 1.0.1 + cookie: 1.0.2 + cssesc: 3.0.0 + debug: 4.4.3 + deterministic-object-hash: 2.0.2 + devalue: 5.5.0 + diff: 5.2.0 + dlv: 1.1.3 + dset: 3.1.4 + es-module-lexer: 1.7.0 + esbuild: 0.25.12 + estree-walker: 3.0.3 + flattie: 1.1.1 + fontace: 0.3.1 + github-slugger: 2.0.0 + html-escaper: 3.0.3 + http-cache-semantics: 4.2.0 + import-meta-resolve: 4.2.0 + js-yaml: 4.1.1 + magic-string: 0.30.21 + magicast: 0.5.1 + mrmime: 2.0.1 + neotraverse: 0.6.18 + p-limit: 6.2.0 + p-queue: 8.1.1 + package-manager-detector: 1.5.0 + piccolore: 0.1.3 + picomatch: 4.0.3 + prompts: 2.4.2 + rehype: 13.0.2 + semver: 7.7.3 + shiki: 3.15.0 + smol-toml: 1.5.2 + svgo: 4.0.0 + tinyexec: 1.0.2 + tinyglobby: 0.2.15 + tsconfck: 3.1.6(typescript@5.9.3) + ultrahtml: 1.6.0 + unifont: 0.6.0 + unist-util-visit: 5.0.0 + unstorage: 1.17.3 + vfile: 6.0.3 + vite: 6.4.1(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + vitefu: 1.1.1(vite@6.4.1(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + xxhash-wasm: 1.1.0 + yargs-parser: 21.1.1 + yocto-spinner: 0.2.3 + zod: 3.25.76 + zod-to-json-schema: 3.25.0(zod@3.25.76) + zod-to-ts: 1.2.0(typescript@5.9.3)(zod@3.25.76) + optionalDependencies: + sharp: 0.34.5 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@types/node' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - idb-keyval + - ioredis + - jiti + - less + - lightningcss + - rollup + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - typescript + - uploadthing + - yaml + async-function@1.0.0: {} async-limiter@1.0.1: {} @@ -19708,6 +20101,21 @@ snapshots: - supports-color - ts-node + create-jest@29.7.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + create-require@1.1.1: {} cross-fetch@3.2.0: @@ -20282,21 +20690,21 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-compat-utils@0.5.1(eslint@9.39.1(jiti@1.21.7)): + eslint-compat-utils@0.5.1(eslint@9.39.1(jiti@2.6.1)): dependencies: - eslint: 9.39.1(jiti@1.21.7) + eslint: 9.39.1(jiti@2.6.1) semver: 7.7.3 - eslint-config-expo@10.0.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3): + eslint-config-expo@10.0.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) - eslint: 9.39.1(jiti@1.21.7) - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.1(jiti@1.21.7)))(eslint@9.39.1(jiti@1.21.7)) - eslint-plugin-expo: 1.0.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@1.21.7)) - eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@1.21.7)) - eslint-plugin-react-hooks: 5.2.0(eslint@9.39.1(jiti@1.21.7)) + '@typescript-eslint/eslint-plugin': 8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.1(jiti@2.6.1) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-expo: 1.0.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-react-hooks: 5.2.0(eslint@9.39.1(jiti@2.6.1)) globals: 16.5.0 transitivePeerDependencies: - eslint-import-resolver-webpack @@ -20304,17 +20712,17 @@ snapshots: - supports-color - typescript - eslint-config-prettier@10.1.8(eslint@9.39.1(jiti@1.21.7)): + eslint-config-prettier@10.1.8(eslint@9.39.1(jiti@2.6.1)): dependencies: - eslint: 9.39.1(jiti@1.21.7) + eslint: 9.39.1(jiti@2.6.1) eslint-config-prettier@8.10.2(eslint@8.57.1): dependencies: eslint: 8.57.1 - eslint-config-prettier@9.1.2(eslint@9.39.1(jiti@1.21.7)): + eslint-config-prettier@9.1.2(eslint@9.39.1(jiti@2.6.1)): dependencies: - eslint: 9.39.1(jiti@1.21.7) + eslint: 9.39.1(jiti@2.6.1) eslint-config-universe@12.1.0(@types/eslint@9.6.1)(eslint@8.57.1)(prettier@3.6.2)(typescript@5.9.3): dependencies: @@ -20336,18 +20744,18 @@ snapshots: - supports-color - typescript - eslint-config-universe@15.0.3(@types/eslint@9.6.1)(eslint@9.39.1(jiti@1.21.7))(prettier@3.6.2)(typescript@5.9.3): + eslint-config-universe@15.0.3(@types/eslint@9.6.1)(eslint@9.39.1(jiti@2.6.1))(prettier@3.6.2)(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) - eslint: 9.39.1(jiti@1.21.7) - eslint-config-prettier: 9.1.2(eslint@9.39.1(jiti@1.21.7)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@1.21.7)) - eslint-plugin-n: 17.23.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) - eslint-plugin-node: 11.1.0(eslint@9.39.1(jiti@1.21.7)) - eslint-plugin-prettier: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@9.1.2(eslint@9.39.1(jiti@1.21.7)))(eslint@9.39.1(jiti@1.21.7))(prettier@3.6.2) - eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@1.21.7)) - eslint-plugin-react-hooks: 5.2.0(eslint@9.39.1(jiti@1.21.7)) + '@typescript-eslint/eslint-plugin': 8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.1(jiti@2.6.1) + eslint-config-prettier: 9.1.2(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-n: 17.23.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-node: 11.1.0(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-prettier: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@9.1.2(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))(prettier@3.6.2) + eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-react-hooks: 5.2.0(eslint@9.39.1(jiti@2.6.1)) globals: 16.5.0 optionalDependencies: prettier: 3.6.2 @@ -20366,18 +20774,18 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.1(jiti@1.21.7)))(eslint@9.39.1(jiti@1.21.7)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.3 - eslint: 9.39.1(jiti@1.21.7) + eslint: 9.39.1(jiti@2.6.1) get-tsconfig: 4.13.0 is-bun-module: 2.0.0 stable-hash: 0.0.5 tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@1.21.7)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -20391,23 +20799,23 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.1(jiti@1.21.7)))(eslint@9.39.1(jiti@1.21.7)))(eslint@9.39.1(jiti@1.21.7)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) - eslint: 9.39.1(jiti@1.21.7) + '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.1(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.1(jiti@1.21.7)))(eslint@9.39.1(jiti@1.21.7)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-plugin-es-x@7.8.0(eslint@9.39.1(jiti@1.21.7)): + eslint-plugin-es-x@7.8.0(eslint@9.39.1(jiti@2.6.1)): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 - eslint: 9.39.1(jiti@1.21.7) - eslint-compat-utils: 0.5.1(eslint@9.39.1(jiti@1.21.7)) + eslint: 9.39.1(jiti@2.6.1) + eslint-compat-utils: 0.5.1(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-es@3.0.1(eslint@8.57.1): dependencies: @@ -20415,17 +20823,17 @@ snapshots: eslint-utils: 2.1.0 regexpp: 3.2.0 - eslint-plugin-es@3.0.1(eslint@9.39.1(jiti@1.21.7)): + eslint-plugin-es@3.0.1(eslint@9.39.1(jiti@2.6.1)): dependencies: - eslint: 9.39.1(jiti@1.21.7) + eslint: 9.39.1(jiti@2.6.1) eslint-utils: 2.1.0 regexpp: 3.2.0 - eslint-plugin-expo@1.0.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3): + eslint-plugin-expo@1.0.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): dependencies: '@typescript-eslint/types': 8.47.0 - '@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) - eslint: 9.39.1(jiti@1.21.7) + '@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.1(jiti@2.6.1) transitivePeerDependencies: - supports-color - typescript @@ -20459,7 +20867,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@1.21.7)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -20468,9 +20876,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.39.1(jiti@1.21.7) + eslint: 9.39.1(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.1(jiti@1.21.7)))(eslint@9.39.1(jiti@1.21.7)))(eslint@9.39.1(jiti@1.21.7)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -20482,18 +20890,18 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-n@17.23.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3): + eslint-plugin-n@17.23.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) enhanced-resolve: 5.18.3 - eslint: 9.39.1(jiti@1.21.7) - eslint-plugin-es-x: 7.8.0(eslint@9.39.1(jiti@1.21.7)) + eslint: 9.39.1(jiti@2.6.1) + eslint-plugin-es-x: 7.8.0(eslint@9.39.1(jiti@2.6.1)) get-tsconfig: 4.13.0 globals: 15.15.0 globrex: 0.1.2 @@ -20513,10 +20921,10 @@ snapshots: resolve: 1.22.11 semver: 6.3.1 - eslint-plugin-node@11.1.0(eslint@9.39.1(jiti@1.21.7)): + eslint-plugin-node@11.1.0(eslint@9.39.1(jiti@2.6.1)): dependencies: - eslint: 9.39.1(jiti@1.21.7) - eslint-plugin-es: 3.0.1(eslint@9.39.1(jiti@1.21.7)) + eslint: 9.39.1(jiti@2.6.1) + eslint-plugin-es: 3.0.1(eslint@9.39.1(jiti@2.6.1)) eslint-utils: 2.1.0 ignore: 5.3.2 minimatch: 3.1.2 @@ -20531,15 +20939,15 @@ snapshots: optionalDependencies: eslint-config-prettier: 8.10.2(eslint@8.57.1) - eslint-plugin-prettier@5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.1(jiti@1.21.7)))(eslint@9.39.1(jiti@1.21.7))(prettier@3.6.2): + eslint-plugin-prettier@5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))(prettier@3.6.2): dependencies: - eslint: 9.39.1(jiti@1.21.7) + eslint: 9.39.1(jiti@2.6.1) prettier: 3.6.2 prettier-linter-helpers: 1.0.0 synckit: 0.11.11 optionalDependencies: '@types/eslint': 9.6.1 - eslint-config-prettier: 10.1.8(eslint@9.39.1(jiti@1.21.7)) + eslint-config-prettier: 10.1.8(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-prettier@5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@8.10.2(eslint@8.57.1))(eslint@8.57.1)(prettier@3.6.2): dependencies: @@ -20551,23 +20959,23 @@ snapshots: '@types/eslint': 9.6.1 eslint-config-prettier: 8.10.2(eslint@8.57.1) - eslint-plugin-prettier@5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@9.1.2(eslint@9.39.1(jiti@1.21.7)))(eslint@9.39.1(jiti@1.21.7))(prettier@3.6.2): + eslint-plugin-prettier@5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@9.1.2(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))(prettier@3.6.2): dependencies: - eslint: 9.39.1(jiti@1.21.7) + eslint: 9.39.1(jiti@2.6.1) prettier: 3.6.2 prettier-linter-helpers: 1.0.0 synckit: 0.11.11 optionalDependencies: '@types/eslint': 9.6.1 - eslint-config-prettier: 9.1.2(eslint@9.39.1(jiti@1.21.7)) + eslint-config-prettier: 9.1.2(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-react-hooks@4.6.2(eslint@8.57.1): dependencies: eslint: 8.57.1 - eslint-plugin-react-hooks@5.2.0(eslint@9.39.1(jiti@1.21.7)): + eslint-plugin-react-hooks@5.2.0(eslint@9.39.1(jiti@2.6.1)): dependencies: - eslint: 9.39.1(jiti@1.21.7) + eslint: 9.39.1(jiti@2.6.1) eslint-plugin-react@7.37.5(eslint@8.57.1): dependencies: @@ -20591,7 +20999,7 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 - eslint-plugin-react@7.37.5(eslint@9.39.1(jiti@1.21.7)): + eslint-plugin-react@7.37.5(eslint@9.39.1(jiti@2.6.1)): dependencies: array-includes: 3.1.9 array.prototype.findlast: 1.2.5 @@ -20599,7 +21007,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.2.1 - eslint: 9.39.1(jiti@1.21.7) + eslint: 9.39.1(jiti@2.6.1) estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -20613,11 +21021,11 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 - eslint-plugin-unused-imports@4.3.0(@typescript-eslint/eslint-plugin@8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.1(jiti@1.21.7)): + eslint-plugin-unused-imports@4.3.0(@typescript-eslint/eslint-plugin@8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)): dependencies: - eslint: 9.39.1(jiti@1.21.7) + eslint: 9.39.1(jiti@2.6.1) optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) eslint-scope@5.1.1: dependencies: @@ -20687,9 +21095,9 @@ snapshots: transitivePeerDependencies: - supports-color - eslint@9.39.1(jiti@1.21.7): + eslint@9.39.1(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.21.1 '@eslint/config-helpers': 0.4.2 @@ -20724,7 +21132,7 @@ snapshots: natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: - jiti: 1.21.7 + jiti: 2.6.1 transitivePeerDependencies: - supports-color @@ -21314,7 +21722,7 @@ snapshots: - '@types/react-dom' - supports-color - expo-router@6.0.15(evxcyavfmgswt4zg3ii4wlqsdm): + expo-router@6.0.15(ja35odoob22us44jnpjqapckaa): dependencies: '@expo/metro-runtime': 6.1.2(expo@54.0.25)(react-dom@19.1.0(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) '@expo/schema-utils': 0.1.7 @@ -21348,7 +21756,7 @@ snapshots: vaul: 1.1.2(@types/react-dom@18.3.7(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) optionalDependencies: '@react-navigation/drawer': 7.7.4(@react-navigation/native@7.1.21(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-gesture-handler@2.28.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@0.5.1(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) - '@testing-library/react-native': 13.3.3(jest@29.5.0)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react-test-renderer@19.1.0(react@19.1.0))(react@19.1.0) + '@testing-library/react-native': 13.3.3(jest@29.5.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react-test-renderer@19.1.0(react@19.1.0))(react@19.1.0) react-dom: 19.1.0(react@19.1.0) react-native-gesture-handler: 2.28.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) react-native-reanimated: 4.1.5(@babel/core@7.28.5)(react-native-worklets@0.5.1(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) @@ -23078,6 +23486,25 @@ snapshots: - supports-color - ts-node + jest-cli@29.7.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jest-cli@30.2.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)): dependencies: '@jest/core': 30.2.0(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) @@ -23159,6 +23586,37 @@ snapshots: - babel-plugin-macros - supports-color + jest-config@29.7.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)): + dependencies: + '@babel/core': 7.28.5 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.28.5) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 22.19.1 + ts-node: 10.9.2(@types/node@22.19.1)(typescript@5.9.3) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + jest-config@30.2.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)): dependencies: '@babel/core': 7.28.5 @@ -23264,7 +23722,7 @@ snapshots: jest-util: 30.2.0 jest-validate: 30.2.0 - jest-expo@54.0.13(@babel/core@7.28.5)(expo@54.0.25)(jest@29.5.0)(react-dom@19.1.0(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(webpack@5.100.2): + jest-expo@54.0.13(@babel/core@7.28.5)(expo@54.0.25)(jest@29.5.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)))(react-dom@19.1.0(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(webpack@5.100.2): dependencies: '@expo/config': 12.0.10 '@expo/json-file': 10.0.7 @@ -23275,7 +23733,7 @@ snapshots: jest-environment-jsdom: 29.7.0 jest-snapshot: 29.7.0 jest-watch-select-projects: 2.0.0 - jest-watch-typeahead: 2.2.1(jest@29.5.0) + jest-watch-typeahead: 2.2.1(jest@29.5.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3))) json5: 2.2.3 lodash: 4.17.21 react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0) @@ -23636,11 +24094,11 @@ snapshots: chalk: 3.0.0 prompts: 2.4.2 - jest-watch-typeahead@2.2.1(jest@29.5.0): + jest-watch-typeahead@2.2.1(jest@29.5.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3))): dependencies: ansi-escapes: 6.2.1 chalk: 4.1.2 - jest: 29.5.0(@types/node@18.15.11)(ts-node@10.9.2(@types/node@18.15.11)(typescript@5.9.3)) + jest: 29.5.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) jest-regex-util: 29.6.3 jest-watcher: 29.7.0 slash: 5.1.0 @@ -23702,6 +24160,18 @@ snapshots: - supports-color - ts-node + jest@29.5.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jest@30.2.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)): dependencies: '@jest/core': 30.2.0(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)) @@ -23719,6 +24189,8 @@ snapshots: jiti@1.21.7: {} + jiti@2.6.1: {} + joi@17.13.3: dependencies: '@hapi/hoek': 9.3.0 @@ -28024,13 +28496,13 @@ snapshots: dependencies: semver: 7.7.3 - typescript-eslint@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3): + typescript-eslint@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3) - eslint: 9.39.1(jiti@1.21.7) + '@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.1(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -28306,13 +28778,13 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite-node@3.2.4(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1): + vite-node@3.2.4(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.2.4(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.2.4(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) transitivePeerDependencies: - '@types/node' - jiti @@ -28338,7 +28810,7 @@ snapshots: lightningcss: 1.30.2 terser: 5.44.1 - vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1): + vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) @@ -28349,7 +28821,7 @@ snapshots: optionalDependencies: '@types/node': 22.19.1 fsevents: 2.3.3 - jiti: 1.21.7 + jiti: 2.6.1 lightningcss: 1.30.2 terser: 5.44.1 tsx: 4.20.6 @@ -28372,24 +28844,7 @@ snapshots: tsx: 4.20.6 yaml: 2.8.1 - vite@7.2.4(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1): - dependencies: - esbuild: 0.25.12 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.53.3 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 22.19.1 - fsevents: 2.3.3 - jiti: 1.21.7 - lightningcss: 1.30.2 - terser: 5.44.1 - tsx: 4.20.6 - yaml: 2.8.1 - - vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1): + vite@6.4.1(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) @@ -28400,29 +28855,67 @@ snapshots: optionalDependencies: '@types/node': 24.10.1 fsevents: 2.3.3 - jiti: 1.21.7 + jiti: 2.6.1 lightningcss: 1.30.2 terser: 5.44.1 tsx: 4.20.6 yaml: 2.8.1 - vitefu@1.1.1(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)): + vite@7.2.4(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1): + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.53.3 + tinyglobby: 0.2.15 optionalDependencies: - vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + '@types/node': 22.19.1 + fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + terser: 5.44.1 + tsx: 4.20.6 + yaml: 2.8.1 + + vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1): + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.53.3 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 24.10.1 + fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + terser: 5.44.1 + tsx: 4.20.6 + yaml: 2.8.1 + + vitefu@1.1.1(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)): + optionalDependencies: + vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) vitefu@1.1.1(vite@6.4.1(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)): optionalDependencies: vite: 6.4.1(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) - vitefu@1.1.1(vite@7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)): + vitefu@1.1.1(vite@6.4.1(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)): optionalDependencies: - vite: 7.2.4(@types/node@24.10.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + vite: 6.4.1(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) - vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.1)(@vitest/ui@3.2.4)(jiti@1.21.7)(jsdom@20.0.3)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1): + vitefu@1.1.1(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)): + optionalDependencies: + vite: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + + vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.1)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@20.0.3)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.2.4(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) + '@vitest/mocker': 3.2.4(vite@7.2.4(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -28440,8 +28933,8 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.2.4(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) - vite-node: 3.2.4(@types/node@22.19.1)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.2.4(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) + vite-node: 3.2.4(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1) why-is-node-running: 2.3.0 optionalDependencies: '@types/debug': 4.1.12