feat: add theme system, fonts, graph styling, rename Overview→Tasks
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
Desktop App / Build Linux (amd64) (push) Has been cancelled
Desktop App / Attach to Release (push) Has been cancelled

- Terracotta (light) and Carbon (dark) themes with toggle
- Inknut Antiqua headings, DM Sans body
- Dot grid background on EntityGraph and GraphBackground
- Theme-adaptive graph colors on EntityGraph
- Art Nouveau chat styling (borders, underlines, blockquote quotes)
- Bullet point styles in chat prose
- Task goal in header, rename Overview→Tasks, New Task labels
- Logo uses var(--primary) for theme awareness
This commit is contained in:
2026-07-15 00:14:31 +02:00
parent 49dfaa77e6
commit e8b30cddcf
12 changed files with 422 additions and 105 deletions

View File

@@ -437,10 +437,11 @@
{#if loading && !nodes.length}
<Skeleton class="h-full min-h-0" />
{:else}
<div class="relative h-full min-h-0 overflow-hidden rounded-lg border bg-[radial-gradient(ellipse_at_center,rgba(88,166,255,0.04),transparent_70%)]">
<div class="relative h-full min-h-0 overflow-hidden rounded-lg border">
<svg
bind:this={svgEl}
viewBox="0 0 {width} {height}"
preserveAspectRatio="xMidYMid slice"
class="h-full w-full touch-none {panState ? 'cursor-grabbing' : 'cursor-grab'}"
role="application"
aria-label="Entity graph"
@@ -451,12 +452,16 @@
onpointercancel={onPointerUp}
>
<defs>
<pattern id="dot-grid" width="12" height="12" patternUnits="userSpaceOnUse">
<circle cx="2" cy="2" r="0.8" fill="var(--border)" opacity="0.75" />
</pattern>
{#each allRelTypes as type}
<marker id={markerId(type)} viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto">
<path d="M0,-3.5L8,0L0,3.5" fill={relColor(type)} />
</marker>
{/each}
</defs>
<rect x="0" y="0" width={width} height={height} fill="url(#dot-grid)" />
<g transform="translate({view.x},{view.y}) scale({view.k})">
<g>
{#each links as link}
@@ -522,15 +527,15 @@
{#if isFocus || isMatch}
<circle r={r + 5} fill={nodeColor(node)} opacity="0.25" />
{/if}
<circle r={r} fill={nodeColor(node)} stroke={isFocus || isMatch ? '#e6edf3' : '#0d1117'} stroke-width={isFocus || isMatch ? 2 : 1.25} />
<circle r={r} fill={nodeColor(node)} stroke={isFocus || isMatch ? 'var(--foreground)' : 'var(--background)'} stroke-width={isFocus || isMatch ? 2 : 1.25} />
{#if view.k >= 0.8 || isFocus || isMatch || op === 1 && focusIds !== null}
<text
y={r + 12}
text-anchor="middle"
font-size={isFocus ? 12 / view.k : 10 / Math.max(view.k, 1)}
fill={isFocus ? '#e6edf3' : '#8b949e'}
fill={isFocus ? 'var(--foreground)' : 'var(--muted-foreground)'}
paint-order="stroke"
stroke="#0d1117"
stroke="var(--background)"
stroke-width={3 / view.k}
class="pointer-events-none select-none"
>