Files
oikos/web/src/lib/desktop-patterns.ts
dtoro 873b00ac42
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
ci / web (push) Has been cancelled
Desktop App / Build Linux (amd64) (push) Has been cancelled
Desktop App / Attach to Release (push) Has been cancelled
style(web): fix prettier config, format entire web/ tree
.prettierrc.json was missing "semi": false, so prettier wanted to add
semicolons to a codebase written without them (763 semicolon-free
statements vs. 150 with, in hand-written .ts; zero hand-written .svelte
files use them at all). That's why prettier --check failed on 249 files
— not because the code was unformatted, but because the config didn't
match the actual house style. Added "semi": false; left printWidth/etc
as configured (printWidth barely moves the failure count: 218/213/212
files at 100/120/140).

Ran `prettier --write .` with the corrected config. Verified
semantics-preserving before and after:
- eslint: 142 problems both before and after, byte-identical
- build passes, 38/38 tests pass
- token-stream diff (whitespace/semicolons/quotes normalized) on all
  218 changed files: only 52 had any remaining token change, all either
  trailing-comma removal (matching trailingComma: "none") or import/
  ternary reflow — no semantic changes
- live smoke test: Knowledge, Tasks, Fleet map, and a chat window
  (AgentTrace, markdown, Scope graph, activity rail) all render
  correctly, no console errors

Most of the diff is shadcn/ui vendor files (lib/components/ui/) moving
from the CLI's own style (double quotes, tabs, semicolons) to house
style; re-running `shadcn-svelte add` on a component will need a
follow-up format pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 12:56:07 +02:00

85 lines
3.8 KiB
TypeScript

// 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)
}