Rewrite website as a Hyprland desktop

This commit is contained in:
SirBlob committed 2026-10-26 14:33:05 -04:00
1 parent 7c52779cf6
commit 3065ad6092
197 files changed
+5609 -17779

No files matched your search

+30
View File
@@ -0,0 +1,30 @@
import { themes, type Theme } from './themes';
function toCssName(key: string): string {
return `--${key.replaceAll('_', '-')}`;
}
function themeVariables(theme: Theme): string {
const colorVariables = Object.entries(theme.colors).map(
([key, value]) => `${toCssName(key)}: ${value};`
);
const [borderStart, borderEnd] = theme.activeBorder ?? [theme.colors.accent, theme.colors.accent];
const wallpaper = theme.wallpaper ? `url('${theme.wallpaper}')` : 'none';
return [
...colorVariables,
`--border-active: linear-gradient(45deg, ${borderStart}, ${borderEnd});`,
`--border-active-solid: ${borderStart};`,
`--wallpaper: ${wallpaper};`,
`color-scheme: ${theme.mode};`
].join(' ');
}
export function buildThemeStylesheet(defaultThemeId: string): string {
const defaultTheme = themes.find((theme) => theme.id === defaultThemeId) ?? themes[0];
const defaultRule = `:root { ${themeVariables(defaultTheme)} }`;
const themeRules = themes.map(
(theme) => `:root[data-theme='${theme.id}'] { ${themeVariables(theme)} }`
);
return [defaultRule, ...themeRules].join('\n');
}
+48
View File
@@ -0,0 +1,48 @@
import { desktop } from '#lib/content';
import { findTheme, themes, type Theme } from './themes';
export const themeStorageKey = 'theme';
function readStoredThemeId(): string | null {
try {
return localStorage.getItem(themeStorageKey);
} catch {
return null;
}
}
function storeThemeId(themeId: string) {
try {
localStorage.setItem(themeStorageKey, themeId);
} catch {}
}
class ThemeState {
currentId = $state(desktop.defaultTheme);
get current(): Theme {
return findTheme(this.currentId) ?? themes[0];
}
restore() {
const storedTheme = findTheme(readStoredThemeId());
if (storedTheme) this.currentId = storedTheme.id;
}
set(themeId: string): boolean {
const theme = findTheme(themeId);
if (!theme) return false;
this.currentId = theme.id;
document.documentElement.dataset.theme = theme.id;
storeThemeId(theme.id);
return true;
}
cycle(step: number) {
const index = themes.findIndex((theme) => theme.id === this.currentId);
const nextIndex = (index + step + themes.length) % themes.length;
this.set(themes[nextIndex].id);
}
}
export const themeState = new ThemeState();
+321
View File
@@ -0,0 +1,321 @@
export interface ThemePalette {
accent: string;
selection: string;
muted: string;
background: string;
dark_background: string;
lighter_background: string;
foreground: string;
red: string;
yellow: string;
orange: string;
green: string;
cyan: string;
blue: string;
magenta: string;
}
export interface Theme {
id: string;
name: string;
mode: 'dark' | 'light';
wallpaper?: string;
activeBorder?: [string, string];
colors: ThemePalette;
}
export const themes: Theme[] = [
{
id: 'flats',
name: 'Flats',
mode: 'dark',
wallpaper: '/wallpapers/pastel-car.jpg',
colors: {
accent: '#5fa3e8',
selection: '#1e2228',
muted: '#78828c',
background: '#0f1012',
dark_background: '#0a0b0c',
lighter_background: '#191c20',
foreground: '#cbd2d9',
red: '#d53838',
yellow: '#d58638',
orange: '#d56338',
green: '#38d586',
cyan: '#38d4d5',
blue: '#3886d5',
magenta: '#d53886'
}
},
{
id: 'retro-82',
name: 'Retro 82',
mode: 'dark',
wallpaper: '/wallpapers/pixel-city.png',
activeBorder: ['#faa968', '#f85525'],
colors: {
accent: '#faa968',
selection: '#134e5a',
muted: '#3f8f8a',
background: '#05182e',
dark_background: '#031222',
lighter_background: '#0a2540',
foreground: '#f6dcac',
red: '#f85525',
yellow: '#e97b3c',
orange: '#faa968',
green: '#028391',
cyan: '#8cbfb8',
blue: '#3f8f8a',
magenta: '#a7c9c6'
}
},
{
id: 'tokyo-night',
name: 'Tokyo Night',
mode: 'dark',
wallpaper: '/wallpapers/home127-dark.jpg',
colors: {
accent: '#7aa2f7',
selection: '#292e42',
muted: '#565f89',
background: '#1a1b26',
dark_background: '#13141c',
lighter_background: '#24283b',
foreground: '#a9b1d6',
red: '#f7768e',
yellow: '#e0af68',
orange: '#eb927b',
green: '#9ece6a',
cyan: '#449dab',
blue: '#7aa2f7',
magenta: '#ad8ee6'
}
},
{
id: 'catppuccin',
name: 'Catppuccin',
mode: 'dark',
wallpaper: '/wallpapers/cat.jpg',
colors: {
accent: '#89b4fa',
selection: '#45475a',
muted: '#6c7086',
background: '#1e1e2e',
dark_background: '#161622',
lighter_background: '#313244',
foreground: '#cdd6f4',
red: '#f38ba8',
yellow: '#f9e2af',
orange: '#fab387',
green: '#a6e3a1',
cyan: '#94e2d5',
blue: '#89b4fa',
magenta: '#cba6f7'
}
},
{
id: 'arch',
name: 'Arch Linux',
mode: 'dark',
wallpaper: '/wallpapers/pacman-black.png',
activeBorder: ['#33ccff', '#00ff99'],
colors: {
accent: '#1793d1',
selection: '#21262d',
muted: '#8b949e',
background: '#0d1117',
dark_background: '#090c10',
lighter_background: '#161b22',
foreground: '#c9d1d9',
red: '#ff7b72',
yellow: '#d29922',
orange: '#ffa657',
green: '#3fb950',
cyan: '#39c5cf',
blue: '#58a6ff',
magenta: '#bc8cff'
}
},
{
id: 'gruvbox',
name: 'Gruvbox',
mode: 'dark',
wallpaper: '/wallpapers/deer-forest.jpg',
colors: {
accent: '#7daea3',
selection: '#504945',
muted: '#928374',
background: '#282828',
dark_background: '#1e1e1e',
lighter_background: '#3c3836',
foreground: '#d4be98',
red: '#ea6962',
yellow: '#d8a657',
orange: '#e1875c',
green: '#a9b665',
cyan: '#89b482',
blue: '#7daea3',
magenta: '#d3869b'
}
},
{
id: 'nord',
name: 'Nord',
mode: 'dark',
wallpaper: '/wallpapers/nord_minimal_cat.png',
colors: {
accent: '#81a1c1',
selection: '#434c5e',
muted: '#7b88a1',
background: '#2e3440',
dark_background: '#222730',
lighter_background: '#3b4252',
foreground: '#d8dee9',
red: '#bf616a',
yellow: '#ebcb8b',
orange: '#d5967a',
green: '#a3be8c',
cyan: '#88c0d0',
blue: '#81a1c1',
magenta: '#b48ead'
}
},
{
id: 'kanagawa',
name: 'Kanagawa',
mode: 'dark',
wallpaper: '/wallpapers/pixel-earth.png',
colors: {
accent: '#dcd7ba',
selection: '#363646',
muted: '#727169',
background: '#1f1f28',
dark_background: '#17171e',
lighter_background: '#2a2a37',
foreground: '#dcd7ba',
red: '#c34043',
yellow: '#c0a36e',
orange: '#c17158',
green: '#76946a',
cyan: '#6a9589',
blue: '#7e9cd8',
magenta: '#957fb8'
}
},
{
id: 'wintry',
name: 'Wintry',
mode: 'dark',
wallpaper: '/wallpapers/pixel-earth.png',
colors: {
accent: '#7dd3fc',
selection: '#334155',
muted: '#94a3b8',
background: '#0f172a',
dark_background: '#0a1020',
lighter_background: '#1e293b',
foreground: '#f1f5f9',
red: '#f43f5e',
yellow: '#fde047',
orange: '#fb923c',
green: '#4ade80',
cyan: '#67e8f9',
blue: '#60a5fa',
magenta: '#c084fc'
}
},
{
id: 'rose',
name: 'Rose',
mode: 'dark',
wallpaper: '/wallpapers/cat.jpg',
colors: {
accent: '#fb7185',
selection: '#5f484f',
muted: '#c48b95',
background: '#1f181b',
dark_background: '#171214',
lighter_background: '#2e2327',
foreground: '#ffe4e6',
red: '#f43f5e',
yellow: '#fde047',
orange: '#fb923c',
green: '#34d399',
cyan: '#67e8f9',
blue: '#60a5fa',
magenta: '#e879f9'
}
},
{
id: 'cerberus',
name: 'Cerberus',
mode: 'dark',
wallpaper: '/wallpapers/home127-dark.jpg',
activeBorder: ['#818cf8', '#e879f9'],
colors: {
accent: '#818cf8',
selection: '#404040',
muted: '#a3a3a3',
background: '#171717',
dark_background: '#0f0f0f',
lighter_background: '#262626',
foreground: '#f5f5f5',
red: '#ef4444',
yellow: '#fbbf24',
orange: '#fb923c',
green: '#2dd4bf',
cyan: '#67e8f9',
blue: '#818cf8',
magenta: '#e879f9'
}
},
{
id: 'catppuccin-latte',
name: 'Catppuccin Latte',
mode: 'light',
wallpaper: '/wallpapers/yosemite-color-block.jpg',
colors: {
accent: '#1e66f5',
selection: '#ccd0da',
muted: '#8c8fa1',
background: '#eff1f5',
dark_background: '#e3e4e8',
lighter_background: '#dce0e8',
foreground: '#4c4f69',
red: '#d20f39',
yellow: '#df8e1d',
orange: '#d84e2b',
green: '#40a02b',
cyan: '#179299',
blue: '#1e66f5',
magenta: '#ea76cb'
}
},
{
id: 'rose-pine',
name: 'Rose Pine Dawn',
mode: 'light',
wallpaper: '/wallpapers/material-pastel.jpg',
colors: {
accent: '#56949f',
selection: '#dfdad9',
muted: '#9893a5',
background: '#faf4ed',
dark_background: '#ede7e1',
lighter_background: '#f2e9e1',
foreground: '#575279',
red: '#b4637a',
yellow: '#ea9d34',
orange: '#cf8057',
green: '#286983',
cyan: '#d7827e',
blue: '#56949f',
magenta: '#907aa9'
}
}
];
export function findTheme(id: string | null | undefined): Theme | undefined {
return themes.find((theme) => theme.id === id);
}