// Desktop background patterns — CSS-only (no images), in the spirit of // magicpattern.design's "CSS backgrounds" gallery. Each pattern is written // with a single foreground color against `transparent` gaps rather than a // baked-in second color, so it composes correctly over the app's own // terracotta/carbon theme background (and follows the theme swap for free) // instead of needing its own light/dark variant. A separate, optional fill // color (see background.svelte.ts) sits underneath as `background-color`, // showing through the transparent gaps when the user wants one. export type BackgroundPatternId = 'none' | 'dots' | 'bubbles' | 'grid' | 'stripes' | 'checks' | 'zigzag' | 'rings' export interface PatternDef { id: BackgroundPatternId label: string // Returns a CSS declaration string (background-image/-size/-position/ // -repeat) for the given foreground color and size multiplier (1 = the // pattern's natural/default tile size). Empty string = no pattern. css: (color: string, scale: number) => string } // Rounds to 1 decimal — enough precision for a smooth size slider without // producing long floating-point tails in the generated CSS. function px(base: number, scale: number): string { return `${Math.round(Math.max(0.5, base * scale) * 10) / 10}px` } export const PATTERNS: PatternDef[] = [ { id: 'none', label: 'None', css: () => '' }, { id: 'dots', label: 'Dots', css: (c, s) => `background-image: radial-gradient(${c} ${px(1.6, s)}, transparent ${px(1.6, s)}); background-size: ${px(18, s)} ${px(18, s)};` }, { id: 'bubbles', label: 'Bubbles', css: (c, s) => `background-image: radial-gradient(${c} 17%, transparent 18% 35%, transparent 36.5%), radial-gradient(${c} 17%, transparent 18% 35%, transparent 36.5%), radial-gradient(transparent 34%, ${c} 36% 68%, transparent 70%), repeating-linear-gradient(45deg, ${c} -12.5% 12.5%, transparent 0 37.5%); background-position: -${px(20, s)} -${px(20, s)}, ${px(20, s)} ${px(20, s)}, 0 0, 0 0; background-size: ${px(80, s)} ${px(80, s)}, ${px(80, s)} ${px(80, s)}, ${px(40, s)} ${px(40, s)}, ${px(80, s)} ${px(80, s)};` }, { id: 'grid', label: 'Grid', css: (c, s) => `background-image: linear-gradient(${c} 1px, transparent 1px), linear-gradient(90deg, ${c} 1px, transparent 1px); background-size: ${px(24, s)} ${px(24, s)};` }, { id: 'stripes', label: 'Stripes', css: (c, s) => `background-image: repeating-linear-gradient(45deg, ${c} 0 ${px(2, s)}, transparent ${px(2, s)} ${px(14, s)});` }, { id: 'checks', label: 'Checks', css: (c, s) => `background-image: conic-gradient(${c} 90deg, transparent 90deg 180deg, ${c} 180deg 270deg, transparent 270deg); background-size: ${px(24, s)} ${px(24, s)};` }, { id: 'zigzag', label: 'Zigzag', css: (c, s) => `background-image: linear-gradient(135deg, ${c} 25%, transparent 25%), linear-gradient(225deg, ${c} 25%, transparent 25%), linear-gradient(45deg, ${c} 25%, transparent 25%), linear-gradient(315deg, ${c} 25%, transparent 25%); background-position: ${px(20, s)} 0, ${px(20, s)} 0, 0 0, 0 0; background-size: ${px(40, s)} ${px(40, s)}; background-repeat: repeat;` }, { id: 'rings', label: 'Rings', css: (c, s) => `background-image: repeating-radial-gradient(circle at 50% 50%, ${c} 0, ${c} ${px(1, s)}, transparent ${px(1, s)}, transparent ${px(14, s)});` } ] const byId = new Map(PATTERNS.map((p) => [p.id, p])) export function patternDef(id: BackgroundPatternId): PatternDef { return byId.get(id) ?? PATTERNS[0] } // Full inline-style CSS text for a pattern + color + size, ready to drop // into a `style` attribute. Empty string for 'none' (or unknown ids). export function patternCss(id: BackgroundPatternId, color: string, scale = 1): string { return patternDef(id).css(color, scale) }