Initial commit

This commit is contained in:
2026-02-06 15:28:27 -03:00
commit 4bc96abf4a
116 changed files with 13806 additions and 0 deletions

View File

@@ -0,0 +1,157 @@
<script lang="ts">
import { onMount } from 'svelte';
import { Moon, SunMoon, Sun } from '@lucide/svelte';
import { getStoredTheme, setTheme } from '$lib/theme';
import type { ThemeMode } from '$lib/theme';
const SLOT_WIDTH = 48;
const GAP = 8;
/** When collapsed, track translateX so the active option is in the 48px viewport (left=Light, middle=Dark, right=Auto). */
const OFFSETS: Record<ThemeMode, number> = {
light: 0,
dark: -(SLOT_WIDTH + GAP),
auto: -(SLOT_WIDTH + GAP) * 2,
};
let current = $state<ThemeMode>('auto');
let expanded = $state(false);
const themeOffset = $derived(OFFSETS[current]);
onMount(() => {
current = getStoredTheme();
});
function choose(mode: ThemeMode) {
setTheme(mode);
current = mode;
}
function handleClick(mode: ThemeMode) {
if (expanded) {
choose(mode);
expanded = false;
} else {
expanded = true;
}
}
</script>
{#if expanded}
<!-- Click outside to collapse -->
<button
type="button"
class="theme-toggle-backdrop"
aria-label="Close theme menu"
tabindex="-1"
onclick={() => (expanded = false)}
></button>
{/if}
<div
class="theme-toggle"
class:expanded
role="group"
aria-label="Color theme"
style="--theme-offset: {themeOffset}px;"
>
<div class="theme-toggle-track">
<button
type="button"
class="action theme-option"
class:active={expanded && current === 'light'}
aria-label="Light"
aria-current={current === 'light' ? 'true' : undefined}
title="Light"
onclick={() => handleClick('light')}
>
<Sun size={24} />
</button>
<button
type="button"
class="action theme-option"
class:active={expanded && current === 'dark'}
aria-label="Dark"
aria-current={current === 'dark' ? 'true' : undefined}
title="Dark"
onclick={() => handleClick('dark')}
>
<Moon size={24} />
</button>
<button
type="button"
class="action theme-option"
class:active={expanded && current === 'auto'}
aria-label="Auto (system)"
aria-current={current === 'auto' ? 'true' : undefined}
title="Auto (system)"
onclick={() => handleClick('auto')}
>
<SunMoon size={24} />
</button>
</div>
</div>
<style>
.theme-toggle-backdrop {
position: fixed;
inset: 0;
z-index: 99;
padding: 0;
border: none;
background: transparent;
cursor: default;
}
/* Collapsed: match hero-action (other header buttons); expanded: glass panel */
.theme-toggle {
position: relative;
z-index: 100;
display: inline-block;
width: 48px;
padding: 0;
overflow: hidden;
border-radius: 50%;
border: none;
transition:
width 0.22s ease-out,
padding 0.22s ease-out,
border-radius 0.22s ease-out,
background 0.22s ease-out,
box-shadow 0.22s ease-out,
backdrop-filter 0.22s ease-out;
background: var(--color-surface-elevated);
box-shadow: 0 2px 8px rgb(0 0 0 / 15%);
}
.theme-toggle.expanded {
width: 176px;
padding: 0.5rem;
border-radius: 1rem;
border: 1px solid color-mix(in srgb, var(--color-border) 60%, transparent);
background: color-mix(in srgb, var(--color-surface-elevated) 52%, transparent);
backdrop-filter: blur(20px) saturate(1.2);
-webkit-backdrop-filter: blur(20px) saturate(1.2);
box-shadow:
0 0 0 1px color-mix(in srgb, white 12%, transparent) inset,
0 4px 24px rgba(0, 0, 0, 0.12),
0 2px 8px rgba(0, 0, 0, 0.08);
}
.theme-toggle-track {
display: flex;
gap: 0.5rem;
width: 160px;
transform: translateX(var(--theme-offset));
transition: transform 0.22s ease-out;
}
.theme-toggle.expanded .theme-toggle-track {
transform: translateX(0);
}
.theme-option.active {
background: var(--color-primary);
color: var(--color-bg);
}
</style>