feat(web): replace 3D graph with fleet map, add desktop background patterns, rename Knowledge Base to Fleet
- FleetMap: service-centric host -> container -> service graph replacing the WebGL 3D force graph, with health coloring, hover-to-trace blast radius, and click-to-open - Desktop background: configurable CSS pattern picker in Settings -> Appearance (8 patterns, color/fill/opacity/fade/size/rotation), replacing the hardcoded ambient graph background - Fix missing data-orientation/data-disabled Tailwind custom variants so the shadcn Slider's track actually renders - Rename "Knowledge Base" app to "Fleet"; scope its table to the same fleet entities as the graph (compute-entity descendants + service) instead of all entities - Remove dead code: EntityGraph, GraphBackground, categories.ts, MultiSelectFilter (all superseded by the above) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
82
web/src/lib/desktop-patterns.ts
Normal file
82
web/src/lib/desktop-patterns.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
// 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)
|
||||
}
|
||||
Reference in New Issue
Block a user