Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@
<link rel="icon" type="image/png" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width" />
%sveltekit.head%
<script>
(function() {
const themes = {"black-white":{"background":"#000000","card":"#1a1a1a","border":"#333333","foreground":"#ffffff","muted":"#999999","primary":"#ffffff","secondary":"#cccccc","accent":"#666666","on-primary":"#000000","on-background":"#ffffff","hero-from":"#000000","hero-via":"#1a1a1a","hero-to":"#000000"},"blue":{"background":"#0b1220","card":"#0f172a","border":"#1e3a5f","foreground":"#e5e7eb","muted":"#94a3b8","primary":"#3b82f6","secondary":"#60a5fa","accent":"#2563eb","on-primary":"#ffffff","on-background":"#0f172a","hero-from":"#0b1220","hero-via":"#0f172a","hero-to":"#0b1220"},"red":{"background":"#1a0b0e","card":"#2d1417","border":"#5f1e2a","foreground":"#fce7f3","muted":"#fda4af","primary":"#ef4444","secondary":"#f87171","accent":"#dc2626","on-primary":"#ffffff","on-background":"#2d1417","hero-from":"#1a0b0e","hero-via":"#2d1417","hero-to":"#1a0b0e"},"green":{"background":"#0b1a14","card":"#0f2a1f","border":"#1e5f3a","foreground":"#e7fcf3","muted":"#86efac","primary":"#10b981","secondary":"#34d399","accent":"#059669","on-primary":"#ffffff","on-background":"#0f2a1f","hero-from":"#0b1a14","hero-via":"#0f2a1f","hero-to":"#0b1a14"},"orange":{"background":"#1a120b","card":"#2a1f0f","border":"#5f3a1e","foreground":"#fef3e7","muted":"#fdba74","primary":"#f97316","secondary":"#fb923c","accent":"#ea580c","on-primary":"#ffffff","on-background":"#2a1f0f","hero-from":"#1a120b","hero-via":"#2a1f0f","hero-to":"#1a120b"},"purple":{"background":"#150b1a","card":"#1f0f2a","border":"#3a1e5f","foreground":"#f3e7fc","muted":"#d8b4fe","primary":"#a855f7","secondary":"#c084fc","accent":"#9333ea","on-primary":"#ffffff","on-background":"#1f0f2a","hero-from":"#150b1a","hero-via":"#1f0f2a","hero-to":"#150b1a"},"cyan":{"background":"#0b1a1a","card":"#0f2a2a","border":"#1e5f5f","foreground":"#e7fcfc","muted":"#67e8f9","primary":"#06b6d4","secondary":"#22d3ee","accent":"#0891b2","on-primary":"#ffffff","on-background":"#0f2a2a","hero-from":"#0b1a1a","hero-via":"#0f2a2a","hero-to":"#0b1a1a"},"pink":{"background":"#1a0b15","card":"#2a0f1f","border":"#5f1e3a","foreground":"#fce7f3","muted":"#f9a8d4","primary":"#ec4899","secondary":"#f472b6","accent":"#db2777","on-primary":"#ffffff","on-background":"#2a0f1f","hero-from":"#1a0b15","hero-via":"#2a0f1f","hero-to":"#1a0b15"},"black-red":{"background":"#000000","card":"#1a0000","border":"#330000","foreground":"#ffffff","muted":"#999999","primary":"#dc2626","secondary":"#ef4444","accent":"#b91c1c","on-primary":"#ffffff","on-background":"#ffffff","hero-from":"#000000","hero-via":"#1a0000","hero-to":"#000000"},"charcoal":{"background":"#212121","card":"#303030","border":"#444444","foreground":"#f5f5f5","muted":"#a0a0a0","primary":"#ffffff","secondary":"#e0e0e0","accent":"#888888","on-primary":"#212121","on-background":"#f5f5f5","hero-from":"#212121","hero-via":"#2a2a2a","hero-to":"#212121"}};
Comment thread
VAIBHAVSING marked this conversation as resolved.
Outdated
const saved = localStorage.getItem('statue-theme');
if (saved && themes[saved]) {
const theme = themes[saved];
Object.entries(theme).forEach(([key, value]) => {
document.documentElement.style.setProperty('--color-' + key, value);
});
}
})();
</script>
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
Expand Down
107 changes: 107 additions & 0 deletions src/lib/components/ThemeSwitcher.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<script lang="ts">
import { themes, defaultTheme, type ThemeDefinition } from '$lib/themes/index.js';
import { onMount } from 'svelte';

let currentTheme = $state(defaultTheme);
let isOpen = $state(false);

function applyTheme(theme: ThemeDefinition) {
Object.entries(theme.colors).forEach(([key, value]) => {
document.documentElement.style.setProperty(`--color-${key}`, value);
});
}

function setTheme(themeId: string) {
const theme = themes.find((t) => t.id === themeId);
if (theme) {
currentTheme = themeId;
applyTheme(theme);
localStorage.setItem('statue-theme', themeId);
isOpen = false;
}
}

onMount(() => {
const saved = localStorage.getItem('statue-theme');
if (saved && themes.find((t) => t.id === saved)) {
currentTheme = saved;
const theme = themes.find((t) => t.id === saved);
if (theme) applyTheme(theme);
}
});

function toggleDropdown() {
isOpen = !isOpen;
}

function closeDropdown() {
isOpen = false;
}
</script>

<svelte:window onclick={closeDropdown} />

<div class="relative">
<button
onclick={(e) => {
e.stopPropagation();
toggleDropdown();
}}
class="flex items-center gap-2 px-3 py-2 rounded-lg bg-[var(--color-card)] border border-[var(--color-border)] text-[var(--color-foreground)] hover:bg-[var(--color-primary)] hover:text-[var(--color-on-primary)] transition-colors"
aria-label="Switch theme"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 2.69l5.66 5.66a8 8 0 1 1-11.31 0z" />
</svg>
<span class="text-sm">{themes.find((t) => t.id === currentTheme)?.name}</span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="12"
height="12"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="transition-transform {isOpen ? 'rotate-180' : ''}"
>
<polyline points="6 9 12 15 18 9" />
</svg>
</button>

{#if isOpen}
<div
class="absolute right-0 mt-2 w-48 rounded-lg bg-[var(--color-card)] border border-[var(--color-border)] shadow-lg z-50"
onclick={(e) => e.stopPropagation()}
>
<div class="py-1">
{#each themes as theme}
<button
onclick={() => setTheme(theme.id)}
class="w-full flex items-center gap-3 px-4 py-2 text-left text-sm hover:bg-[var(--color-primary)] hover:text-[var(--color-on-primary)] transition-colors {currentTheme ===
theme.id
? 'bg-[var(--color-primary)] text-[var(--color-on-primary)]'
: 'text-[var(--color-foreground)]'}"
>
<span
class="w-4 h-4 rounded-full border border-[var(--color-border)]"
style="background-color: {theme.colors.primary}"
></span>
<span>{theme.name}</span>
</button>
{/each}
</div>
</div>
{/if}
</div>
6 changes: 5 additions & 1 deletion src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,8 @@ export { default as NotificationBanner } from './components/NotificationBanner.s
export { default as PricingSection } from './components/PricingSection.svelte';
export { default as ScrollingLogos } from './components/ScrollingLogos.svelte';
export { default as SlidingComparison } from './components/SlidingComparison.svelte';
export { default as SlidingTestimonial } from './components/SlidingTestimonial.svelte';
export { default as SlidingTestimonial } from './components/SlidingTestimonial.svelte';

// Theme components
export { default as ThemeSwitcher } from './components/ThemeSwitcher.svelte';
export { themes, defaultTheme, type ThemeDefinition } from './themes/index.js';
214 changes: 214 additions & 0 deletions src/lib/themes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
export interface ThemeDefinition {
id: string;
name: string;
colors: {
background: string;
card: string;
border: string;
foreground: string;
muted: string;
primary: string;
secondary: string;
accent: string;
'on-primary': string;
'on-background': string;
'hero-from': string;
'hero-via': string;
'hero-to': string;
};
}

export const themes: ThemeDefinition[] = [
{
id: 'black-white',
name: 'Black & White',
colors: {
background: '#000000',
card: '#1a1a1a',
border: '#333333',
foreground: '#ffffff',
muted: '#999999',
primary: '#ffffff',
secondary: '#cccccc',
accent: '#666666',
'on-primary': '#000000',
'on-background': '#ffffff',
'hero-from': '#000000',
'hero-via': '#1a1a1a',
'hero-to': '#000000'
}
},
{
id: 'blue',
name: 'Blue',
colors: {
background: '#0b1220',
card: '#0f172a',
border: '#1e3a5f',
foreground: '#e5e7eb',
muted: '#94a3b8',
primary: '#3b82f6',
secondary: '#60a5fa',
accent: '#2563eb',
'on-primary': '#ffffff',
'on-background': '#0f172a',
'hero-from': '#0b1220',
'hero-via': '#0f172a',
'hero-to': '#0b1220'
}
},
{
id: 'red',
name: 'Red',
colors: {
background: '#1a0b0e',
card: '#2d1417',
border: '#5f1e2a',
foreground: '#fce7f3',
muted: '#fda4af',
primary: '#ef4444',
secondary: '#f87171',
accent: '#dc2626',
'on-primary': '#ffffff',
'on-background': '#2d1417',
'hero-from': '#1a0b0e',
'hero-via': '#2d1417',
'hero-to': '#1a0b0e'
}
},
{
id: 'green',
name: 'Green',
colors: {
background: '#0b1a14',
card: '#0f2a1f',
border: '#1e5f3a',
foreground: '#e7fcf3',
muted: '#86efac',
primary: '#10b981',
secondary: '#34d399',
accent: '#059669',
'on-primary': '#ffffff',
'on-background': '#0f2a1f',
'hero-from': '#0b1a14',
'hero-via': '#0f2a1f',
'hero-to': '#0b1a14'
}
},
{
id: 'orange',
name: 'Orange',
colors: {
background: '#1a120b',
card: '#2a1f0f',
border: '#5f3a1e',
foreground: '#fef3e7',
muted: '#fdba74',
primary: '#f97316',
secondary: '#fb923c',
accent: '#ea580c',
'on-primary': '#ffffff',
'on-background': '#2a1f0f',
'hero-from': '#1a120b',
'hero-via': '#2a1f0f',
'hero-to': '#1a120b'
}
},
{
id: 'purple',
name: 'Purple',
colors: {
background: '#150b1a',
card: '#1f0f2a',
border: '#3a1e5f',
foreground: '#f3e7fc',
muted: '#d8b4fe',
primary: '#a855f7',
secondary: '#c084fc',
accent: '#9333ea',
'on-primary': '#ffffff',
'on-background': '#1f0f2a',
'hero-from': '#150b1a',
'hero-via': '#1f0f2a',
'hero-to': '#150b1a'
}
},
{
id: 'cyan',
name: 'Cyan',
colors: {
background: '#0b1a1a',
card: '#0f2a2a',
border: '#1e5f5f',
foreground: '#e7fcfc',
muted: '#67e8f9',
primary: '#06b6d4',
secondary: '#22d3ee',
accent: '#0891b2',
'on-primary': '#ffffff',
'on-background': '#0f2a2a',
'hero-from': '#0b1a1a',
'hero-via': '#0f2a2a',
'hero-to': '#0b1a1a'
}
},
{
id: 'pink',
name: 'Pink',
colors: {
background: '#1a0b15',
card: '#2a0f1f',
border: '#5f1e3a',
foreground: '#fce7f3',
muted: '#f9a8d4',
primary: '#ec4899',
secondary: '#f472b6',
accent: '#db2777',
'on-primary': '#ffffff',
'on-background': '#2a0f1f',
'hero-from': '#1a0b15',
'hero-via': '#2a0f1f',
'hero-to': '#1a0b15'
}
},
{
id: 'black-red',
name: 'Black & Red',
colors: {
background: '#000000',
card: '#1a0000',
border: '#330000',
foreground: '#ffffff',
muted: '#999999',
primary: '#dc2626',
secondary: '#ef4444',
accent: '#b91c1c',
'on-primary': '#ffffff',
'on-background': '#ffffff',
'hero-from': '#000000',
'hero-via': '#1a0000',
'hero-to': '#000000'
}
},
{
id: 'charcoal',
name: 'Charcoal',
colors: {
background: '#212121',
card: '#303030',
border: '#444444',
foreground: '#f5f5f5',
muted: '#a0a0a0',
primary: '#ffffff',
secondary: '#e0e0e0',
accent: '#888888',
'on-primary': '#212121',
'on-background': '#f5f5f5',
'hero-from': '#212121',
'hero-via': '#2a2a2a',
'hero-to': '#212121'
}
}
];

export const defaultTheme = 'black-white';
Loading