markgraphy 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/LICENSE.txt +21 -0
  2. package/README.md +154 -0
  3. package/dist/animated/GraphAgni.svelte +430 -0
  4. package/dist/animated/GraphAgni.svelte.d.ts +22 -0
  5. package/dist/animated/GraphAum.svelte +294 -0
  6. package/dist/animated/GraphAum.svelte.d.ts +20 -0
  7. package/dist/animated/GraphBoot.svelte +325 -0
  8. package/dist/animated/GraphBoot.svelte.d.ts +28 -0
  9. package/dist/animated/GraphCron.svelte +476 -0
  10. package/dist/animated/GraphCron.svelte.d.ts +42 -0
  11. package/dist/animated/GraphDamru.svelte +341 -0
  12. package/dist/animated/GraphDamru.svelte.d.ts +18 -0
  13. package/dist/animated/GraphDeps.svelte +245 -0
  14. package/dist/animated/GraphDeps.svelte.d.ts +29 -0
  15. package/dist/animated/GraphDiya.svelte +330 -0
  16. package/dist/animated/GraphDiya.svelte.d.ts +22 -0
  17. package/dist/animated/GraphFire.svelte +246 -0
  18. package/dist/animated/GraphFire.svelte.d.ts +22 -0
  19. package/dist/animated/GraphFlame.svelte +258 -0
  20. package/dist/animated/GraphFlame.svelte.d.ts +14 -0
  21. package/dist/animated/GraphFlowPlayer.svelte +346 -0
  22. package/dist/animated/GraphFlowPlayer.svelte.d.ts +27 -0
  23. package/dist/animated/GraphGanga.svelte +305 -0
  24. package/dist/animated/GraphGanga.svelte.d.ts +20 -0
  25. package/dist/animated/GraphHash.svelte +251 -0
  26. package/dist/animated/GraphHash.svelte.d.ts +20 -0
  27. package/dist/animated/GraphJapa.svelte +253 -0
  28. package/dist/animated/GraphJapa.svelte.d.ts +20 -0
  29. package/dist/animated/GraphLife.svelte +312 -0
  30. package/dist/animated/GraphLife.svelte.d.ts +27 -0
  31. package/dist/animated/GraphMandala.svelte +262 -0
  32. package/dist/animated/GraphMandala.svelte.d.ts +24 -0
  33. package/dist/animated/GraphMandel.svelte +290 -0
  34. package/dist/animated/GraphMandel.svelte.d.ts +27 -0
  35. package/dist/animated/GraphPulse.svelte +248 -0
  36. package/dist/animated/GraphPulse.svelte.d.ts +24 -0
  37. package/dist/animated/GraphRain.svelte +280 -0
  38. package/dist/animated/GraphRain.svelte.d.ts +22 -0
  39. package/dist/animated/GraphScatter.svelte +395 -0
  40. package/dist/animated/GraphScatter.svelte.d.ts +31 -0
  41. package/dist/animated/GraphScope.svelte +197 -0
  42. package/dist/animated/GraphScope.svelte.d.ts +22 -0
  43. package/dist/animated/GraphSequence.svelte +247 -0
  44. package/dist/animated/GraphSequence.svelte.d.ts +18 -0
  45. package/dist/animated/GraphSpinners.svelte +109 -0
  46. package/dist/animated/GraphSpinners.svelte.d.ts +22 -0
  47. package/dist/animated/GraphState.svelte +270 -0
  48. package/dist/animated/GraphState.svelte.d.ts +14 -0
  49. package/dist/animated/GraphStream.svelte +223 -0
  50. package/dist/animated/GraphStream.svelte.d.ts +24 -0
  51. package/dist/animated/GraphSurya.svelte +268 -0
  52. package/dist/animated/GraphSurya.svelte.d.ts +22 -0
  53. package/dist/animated/GraphTerminal.svelte +238 -0
  54. package/dist/animated/GraphTerminal.svelte.d.ts +28 -0
  55. package/dist/animated/GraphTicker.svelte +163 -0
  56. package/dist/animated/GraphTicker.svelte.d.ts +21 -0
  57. package/dist/animated/GraphTypewriter.svelte +130 -0
  58. package/dist/animated/GraphTypewriter.svelte.d.ts +22 -0
  59. package/dist/animated/GraphWorkflow.svelte +570 -0
  60. package/dist/animated/GraphWorkflow.svelte.d.ts +29 -0
  61. package/dist/assets/favicon.svg +21 -0
  62. package/dist/diagram/AmplifierDiagram.svelte +206 -0
  63. package/dist/diagram/AmplifierDiagram.svelte.d.ts +12 -0
  64. package/dist/diagram/AsciiDiagram.svelte +212 -0
  65. package/dist/diagram/AsciiDiagram.svelte.d.ts +24 -0
  66. package/dist/diagram/DiagramEditor.svelte +414 -0
  67. package/dist/diagram/DiagramEditor.svelte.d.ts +3 -0
  68. package/dist/diagram/MetricsTableDiagram.svelte +125 -0
  69. package/dist/diagram/MetricsTableDiagram.svelte.d.ts +18 -0
  70. package/dist/diagram/NestedRadiiDiagram.svelte +218 -0
  71. package/dist/diagram/NestedRadiiDiagram.svelte.d.ts +12 -0
  72. package/dist/diagram/PromptLoopDiagram.svelte +331 -0
  73. package/dist/diagram/PromptLoopDiagram.svelte.d.ts +12 -0
  74. package/dist/diagram/ascii.d.ts +35 -0
  75. package/dist/diagram/ascii.js +83 -0
  76. package/dist/diagram/parser.d.ts +16 -0
  77. package/dist/diagram/parser.js +71 -0
  78. package/dist/frame/Graph.svelte +141 -0
  79. package/dist/frame/Graph.svelte.d.ts +14 -0
  80. package/dist/frame/GraphArrow.svelte +49 -0
  81. package/dist/frame/GraphArrow.svelte.d.ts +9 -0
  82. package/dist/frame/GraphBody.svelte +39 -0
  83. package/dist/frame/GraphBody.svelte.d.ts +10 -0
  84. package/dist/frame/GraphRule.svelte +21 -0
  85. package/dist/frame/GraphRule.svelte.d.ts +6 -0
  86. package/dist/frame/GraphTick.svelte +23 -0
  87. package/dist/frame/GraphTick.svelte.d.ts +9 -0
  88. package/dist/frame/GraphTrack.svelte +29 -0
  89. package/dist/frame/GraphTrack.svelte.d.ts +14 -0
  90. package/dist/frame/clock.d.ts +10 -0
  91. package/dist/frame/clock.js +62 -0
  92. package/dist/frame/glyphs.d.ts +22 -0
  93. package/dist/frame/glyphs.js +53 -0
  94. package/dist/frame/motion.css +27 -0
  95. package/dist/frame/motion.d.ts +24 -0
  96. package/dist/frame/motion.js +47 -0
  97. package/dist/frame/tone.d.ts +11 -0
  98. package/dist/frame/tone.js +64 -0
  99. package/dist/graphs/GraphActivity.svelte +387 -0
  100. package/dist/graphs/GraphActivity.svelte.d.ts +22 -0
  101. package/dist/graphs/GraphBars.svelte +194 -0
  102. package/dist/graphs/GraphBars.svelte.d.ts +20 -0
  103. package/dist/graphs/GraphBullet.svelte +208 -0
  104. package/dist/graphs/GraphBullet.svelte.d.ts +22 -0
  105. package/dist/graphs/GraphCalendar.svelte +203 -0
  106. package/dist/graphs/GraphCalendar.svelte.d.ts +20 -0
  107. package/dist/graphs/GraphCells.svelte +181 -0
  108. package/dist/graphs/GraphCells.svelte.d.ts +18 -0
  109. package/dist/graphs/GraphCompare.svelte +192 -0
  110. package/dist/graphs/GraphCompare.svelte.d.ts +18 -0
  111. package/dist/graphs/GraphCountdown.svelte +96 -0
  112. package/dist/graphs/GraphCountdown.svelte.d.ts +14 -0
  113. package/dist/graphs/GraphDiff.svelte +181 -0
  114. package/dist/graphs/GraphDiff.svelte.d.ts +18 -0
  115. package/dist/graphs/GraphFlow.svelte +137 -0
  116. package/dist/graphs/GraphFlow.svelte.d.ts +21 -0
  117. package/dist/graphs/GraphFunnel.svelte +190 -0
  118. package/dist/graphs/GraphFunnel.svelte.d.ts +21 -0
  119. package/dist/graphs/GraphGantt.svelte +258 -0
  120. package/dist/graphs/GraphGantt.svelte.d.ts +25 -0
  121. package/dist/graphs/GraphHeatmap.svelte +287 -0
  122. package/dist/graphs/GraphHeatmap.svelte.d.ts +22 -0
  123. package/dist/graphs/GraphInvoice.svelte +294 -0
  124. package/dist/graphs/GraphInvoice.svelte.d.ts +34 -0
  125. package/dist/graphs/GraphKpi.svelte +166 -0
  126. package/dist/graphs/GraphKpi.svelte.d.ts +17 -0
  127. package/dist/graphs/GraphLatency.svelte +340 -0
  128. package/dist/graphs/GraphLatency.svelte.d.ts +28 -0
  129. package/dist/graphs/GraphMeter.svelte +121 -0
  130. package/dist/graphs/GraphMeter.svelte.d.ts +16 -0
  131. package/dist/graphs/GraphPlot.svelte +226 -0
  132. package/dist/graphs/GraphPlot.svelte.d.ts +18 -0
  133. package/dist/graphs/GraphQuota.svelte +303 -0
  134. package/dist/graphs/GraphQuota.svelte.d.ts +27 -0
  135. package/dist/graphs/GraphRank.svelte +141 -0
  136. package/dist/graphs/GraphRank.svelte.d.ts +21 -0
  137. package/dist/graphs/GraphSlo.svelte +325 -0
  138. package/dist/graphs/GraphSlo.svelte.d.ts +31 -0
  139. package/dist/graphs/GraphSlope.svelte +197 -0
  140. package/dist/graphs/GraphSlope.svelte.d.ts +19 -0
  141. package/dist/graphs/GraphSpark.svelte +125 -0
  142. package/dist/graphs/GraphSpark.svelte.d.ts +15 -0
  143. package/dist/graphs/GraphSpec.svelte +69 -0
  144. package/dist/graphs/GraphSpec.svelte.d.ts +14 -0
  145. package/dist/graphs/GraphStack.svelte +266 -0
  146. package/dist/graphs/GraphStack.svelte.d.ts +25 -0
  147. package/dist/graphs/GraphStat.svelte +103 -0
  148. package/dist/graphs/GraphStat.svelte.d.ts +16 -0
  149. package/dist/graphs/GraphTable.svelte +133 -0
  150. package/dist/graphs/GraphTable.svelte.d.ts +15 -0
  151. package/dist/graphs/GraphTimeline.svelte +164 -0
  152. package/dist/graphs/GraphTimeline.svelte.d.ts +18 -0
  153. package/dist/graphs/GraphTimer.svelte +117 -0
  154. package/dist/graphs/GraphTimer.svelte.d.ts +15 -0
  155. package/dist/graphs/GraphTree.svelte +147 -0
  156. package/dist/graphs/GraphTree.svelte.d.ts +16 -0
  157. package/dist/graphs/GraphUptime.svelte +210 -0
  158. package/dist/graphs/GraphUptime.svelte.d.ts +18 -0
  159. package/dist/graphs/GraphWaffle.svelte +131 -0
  160. package/dist/graphs/GraphWaffle.svelte.d.ts +17 -0
  161. package/dist/graphs/GraphWaterfall.svelte +258 -0
  162. package/dist/graphs/GraphWaterfall.svelte.d.ts +22 -0
  163. package/dist/index.d.ts +147 -0
  164. package/dist/index.js +87 -0
  165. package/dist/themes.css +54 -0
  166. package/package.json +67 -0
@@ -0,0 +1,15 @@
1
+ import type { Glyphs } from '../frame/glyphs';
2
+ import type { GraphPalette } from '../frame/tone';
3
+ /** Packed 1ch sparkline, centered with a small gap. Never stretched. */
4
+ export interface GraphSparkProps {
5
+ title: string;
6
+ data: number[];
7
+ caption?: string;
8
+ glyphs?: Glyphs;
9
+ palette?: GraphPalette;
10
+ corner?: string;
11
+ class?: string;
12
+ }
13
+ declare const GraphSpark: import("svelte").Component<GraphSparkProps, {}, "">;
14
+ type GraphSpark = ReturnType<typeof GraphSpark>;
15
+ export default GraphSpark;
@@ -0,0 +1,69 @@
1
+ <script module lang="ts">
2
+ export interface SpecRow {
3
+ label: string;
4
+ value: string;
5
+ accent?: boolean;
6
+ }
7
+
8
+ export interface GraphSpecProps {
9
+ title: string;
10
+ rows: SpecRow[];
11
+ corner?: string;
12
+ class?: string;
13
+ }
14
+ </script>
15
+
16
+ <script lang="ts">
17
+ import Graph from '../frame/Graph.svelte';
18
+ import GraphBody from '../frame/GraphBody.svelte';
19
+ import { reveal, stagger } from '../frame/motion';
20
+
21
+ let {
22
+ title,
23
+ rows,
24
+ corner,
25
+ class: className = ''
26
+ }: GraphSpecProps = $props();
27
+ </script>
28
+
29
+ <Graph {title} {corner} class={className}>
30
+ <GraphBody>
31
+ <dl class="rows">
32
+ {#each rows as row, i (row.label)}
33
+ <div class="row" use:reveal={{ delay: stagger(i, 40), amount: 0.5 }}>
34
+ <dt class="muted">{row.label}</dt>
35
+ <dd class="value" class:accent={row.accent}>{row.value}</dd>
36
+ </div>
37
+ {/each}
38
+ </dl>
39
+ </GraphBody>
40
+ </Graph>
41
+
42
+ <style>
43
+ .rows {
44
+ display: flex;
45
+ flex-direction: column;
46
+ gap: 0.75rem;
47
+ margin: 0;
48
+ }
49
+
50
+ .row {
51
+ display: grid;
52
+ grid-template-columns: minmax(7rem, 11rem) minmax(0, 1fr);
53
+ align-items: baseline;
54
+ column-gap: 1.5rem;
55
+ }
56
+
57
+ .muted {
58
+ margin: 0;
59
+ color: var(--graph-muted, oklch(0.62 0 0));
60
+ }
61
+
62
+ .value {
63
+ margin: 0;
64
+ }
65
+
66
+ .value.accent {
67
+ color: var(--graph-accent, oklch(0.78 0.17 155));
68
+ }
69
+ </style>
@@ -0,0 +1,14 @@
1
+ export interface SpecRow {
2
+ label: string;
3
+ value: string;
4
+ accent?: boolean;
5
+ }
6
+ export interface GraphSpecProps {
7
+ title: string;
8
+ rows: SpecRow[];
9
+ corner?: string;
10
+ class?: string;
11
+ }
12
+ declare const GraphSpec: import("svelte").Component<GraphSpecProps, {}, "">;
13
+ type GraphSpec = ReturnType<typeof GraphSpec>;
14
+ export default GraphSpec;
@@ -0,0 +1,266 @@
1
+ <script module lang="ts">
2
+ import type { Glyphs } from '../frame/glyphs';
3
+ import type { GraphPalette } from '../frame/tone';
4
+
5
+ /** One part of a whole. */
6
+ export interface StackSegment {
7
+ label: string;
8
+ value: number;
9
+ }
10
+
11
+ /** One stacked track made of segments. */
12
+ export interface StackRow {
13
+ label: string;
14
+ segments: StackSegment[];
15
+ }
16
+
17
+ export interface GraphStackProps {
18
+ title: string;
19
+ rows: StackRow[];
20
+ accent?: string;
21
+ ticks?: number;
22
+ glyphs?: Glyphs;
23
+ palette?: GraphPalette;
24
+ corner?: string;
25
+ class?: string;
26
+ }
27
+ </script>
28
+
29
+ <script lang="ts">
30
+ import Graph from '../frame/Graph.svelte';
31
+ import GraphBody from '../frame/GraphBody.svelte';
32
+ import GraphTrack from '../frame/GraphTrack.svelte';
33
+ import GraphTick from '../frame/GraphTick.svelte';
34
+ import { resolveGlyphs } from '../frame/glyphs';
35
+ import { isDim, isMonoPalette, seriesRole, type ToneRole } from '../frame/tone';
36
+ import { reveal, stagger } from '../frame/motion';
37
+
38
+ let {
39
+ title,
40
+ rows,
41
+ accent,
42
+ ticks = 24,
43
+ glyphs,
44
+ palette,
45
+ corner,
46
+ class: className = ''
47
+ }: GraphStackProps = $props();
48
+
49
+ const DEFAULT_GLYPHS = ['█', '▓', '▒', '░', '#', '=', '+', '-'];
50
+
51
+ interface Piece {
52
+ label: string;
53
+ glyph: string;
54
+ count: number;
55
+ highlighted: boolean;
56
+ }
57
+
58
+ function paintRow(
59
+ segments: StackSegment[],
60
+ tickCount: number,
61
+ set: readonly string[],
62
+ accentLabel?: string
63
+ ): Piece[] {
64
+ const total = segments.reduce((sum, segment) => sum + segment.value, 0) || 1;
65
+ let left = tickCount;
66
+
67
+ return segments.map((segment, index) => {
68
+ const raw = Math.round((segment.value / total) * tickCount);
69
+ const count =
70
+ index === segments.length - 1
71
+ ? Math.max(0, left)
72
+ : Math.min(Math.max(0, raw), left);
73
+ left -= count;
74
+ const highlighted = accentLabel
75
+ ? segment.label === accentLabel
76
+ : index === 0;
77
+
78
+ return {
79
+ label: segment.label,
80
+ glyph: set[index % set.length] ?? '█',
81
+ count,
82
+ highlighted
83
+ };
84
+ });
85
+ }
86
+
87
+ const mono = $derived(isMonoPalette(palette));
88
+ const set = $derived(glyphs == null ? DEFAULT_GLYPHS : resolveGlyphs(glyphs));
89
+
90
+ const legend = $derived.by(() => {
91
+ const names: string[] = [];
92
+
93
+ for (const row of rows) {
94
+ for (const segment of row.segments) {
95
+ if (!names.includes(segment.label)) {
96
+ names.push(segment.label);
97
+ }
98
+ }
99
+ }
100
+
101
+ return names.map((label, index) => {
102
+ const highlighted = mono ? (accent ? label === accent : index === 0) : true;
103
+
104
+ return {
105
+ label,
106
+ glyph: set[index % set.length] ?? '█',
107
+ role: seriesRole(palette, index),
108
+ dim: isDim(palette, highlighted),
109
+ highlighted
110
+ };
111
+ });
112
+ });
113
+
114
+ const view = $derived.by(() =>
115
+ rows.map((row) => {
116
+ const painted = paintRow(row.segments, ticks, set, accent);
117
+ const pieces = painted.flatMap((piece) => {
118
+ const role: ToneRole = seriesRole(palette, legend.findIndex((l) => l.label === piece.label));
119
+ const dim = isDim(palette, mono ? piece.highlighted : true);
120
+
121
+ return Array.from({ length: piece.count }, () => ({
122
+ glyph: piece.glyph,
123
+ role,
124
+ dim
125
+ }));
126
+ });
127
+
128
+ return {
129
+ label: row.label,
130
+ spoken: `${row.label}: ${row.segments
131
+ .map((segment) => `${segment.label} ${segment.value}`)
132
+ .join(', ')}`,
133
+ pieces
134
+ };
135
+ })
136
+ );
137
+ </script>
138
+
139
+ <Graph {title} {corner} class={className}>
140
+ <GraphBody>
141
+ <div class="col">
142
+ <ul class="tracks" role="list">
143
+ {#each view as row, i (row.label)}
144
+ <li
145
+ class="track-row"
146
+ aria-label={row.spoken}
147
+ use:reveal={{ delay: stagger(i, 40), amount: 0.4 }}
148
+ >
149
+ <span class="label">{row.label}</span>
150
+ <GraphTrack>
151
+ {#each row.pieces as piece}
152
+ <GraphTick>
153
+ <span
154
+ class="g"
155
+ class:c-accent={piece.role === 'accent'}
156
+ class:c-accent2={piece.role === 'accent2'}
157
+ class:c-accent3={piece.role === 'accent3'}
158
+ class:c-fg={piece.role === 'foreground'}
159
+ class:dim={piece.dim}
160
+ >
161
+ {piece.glyph}
162
+ </span>
163
+ </GraphTick>
164
+ {/each}
165
+ </GraphTrack>
166
+ </li>
167
+ {/each}
168
+ </ul>
169
+ <ul class="legend" role="list">
170
+ {#each legend as entry (entry.label)}
171
+ <li class="key" class:dim={entry.dim}>
172
+ <span
173
+ class="g"
174
+ aria-hidden="true"
175
+ class:c-accent={entry.role === 'accent'}
176
+ class:c-accent2={entry.role === 'accent2'}
177
+ class:c-accent3={entry.role === 'accent3'}
178
+ class:c-fg={entry.role === 'foreground'}
179
+ >
180
+ {entry.glyph}
181
+ </span>
182
+ <span class:c-fg={entry.highlighted} class:c-muted={!entry.highlighted}>
183
+ {entry.label}
184
+ </span>
185
+ </li>
186
+ {/each}
187
+ </ul>
188
+ </div>
189
+ </GraphBody>
190
+ </Graph>
191
+
192
+ <style>
193
+ .col {
194
+ display: flex;
195
+ flex-direction: column;
196
+ gap: 1.5rem;
197
+ }
198
+
199
+ .tracks {
200
+ margin: 0;
201
+ padding: 0;
202
+ list-style: none;
203
+ display: flex;
204
+ flex-direction: column;
205
+ gap: 0.75rem;
206
+ }
207
+
208
+ .track-row {
209
+ display: grid;
210
+ grid-template-columns: 7rem minmax(0, 1fr);
211
+ column-gap: 1rem;
212
+ align-items: center;
213
+ }
214
+
215
+ .label {
216
+ min-width: 0;
217
+ overflow: hidden;
218
+ text-overflow: ellipsis;
219
+ white-space: nowrap;
220
+ color: var(--graph-foreground, oklch(0.93 0 0));
221
+ }
222
+
223
+ .legend {
224
+ margin: 0;
225
+ padding: 0;
226
+ list-style: none;
227
+ display: flex;
228
+ flex-wrap: wrap;
229
+ column-gap: 1rem;
230
+ row-gap: 0.25rem;
231
+ }
232
+
233
+ .key {
234
+ display: flex;
235
+ align-items: center;
236
+ gap: 0.5rem;
237
+ }
238
+
239
+ .g {
240
+ display: block;
241
+ }
242
+
243
+ .c-accent {
244
+ color: var(--graph-accent, oklch(0.78 0.17 155));
245
+ }
246
+
247
+ .c-accent2 {
248
+ color: var(--graph-accent-2, oklch(0.78 0.12 70));
249
+ }
250
+
251
+ .c-accent3 {
252
+ color: var(--graph-accent-3, oklch(0.75 0.1 200));
253
+ }
254
+
255
+ .c-muted {
256
+ color: var(--graph-muted, oklch(0.62 0 0));
257
+ }
258
+
259
+ .c-fg {
260
+ color: var(--graph-foreground, oklch(0.93 0 0));
261
+ }
262
+
263
+ .dim {
264
+ opacity: 0.4;
265
+ }
266
+ </style>
@@ -0,0 +1,25 @@
1
+ import type { Glyphs } from '../frame/glyphs';
2
+ import type { GraphPalette } from '../frame/tone';
3
+ /** One part of a whole. */
4
+ export interface StackSegment {
5
+ label: string;
6
+ value: number;
7
+ }
8
+ /** One stacked track made of segments. */
9
+ export interface StackRow {
10
+ label: string;
11
+ segments: StackSegment[];
12
+ }
13
+ export interface GraphStackProps {
14
+ title: string;
15
+ rows: StackRow[];
16
+ accent?: string;
17
+ ticks?: number;
18
+ glyphs?: Glyphs;
19
+ palette?: GraphPalette;
20
+ corner?: string;
21
+ class?: string;
22
+ }
23
+ declare const GraphStack: import("svelte").Component<GraphStackProps, {}, "">;
24
+ type GraphStack = ReturnType<typeof GraphStack>;
25
+ export default GraphStack;
@@ -0,0 +1,103 @@
1
+ <script module lang="ts">
2
+ /** Large figures with labels. Two to four numbers, no trend. */
3
+ export interface StatItem {
4
+ value: string;
5
+ label: string;
6
+ hint?: string;
7
+ accent?: boolean;
8
+ }
9
+
10
+ export interface GraphStatProps {
11
+ title: string;
12
+ items: StatItem[];
13
+ corner?: string;
14
+ class?: string;
15
+ }
16
+ </script>
17
+
18
+ <script lang="ts">
19
+ import Graph from '../frame/Graph.svelte';
20
+ import GraphBody from '../frame/GraphBody.svelte';
21
+ import { reveal, stagger } from '../frame/motion';
22
+
23
+ let {
24
+ title,
25
+ items,
26
+ corner,
27
+ class: className = ''
28
+ }: GraphStatProps = $props();
29
+
30
+ const columns = $derived(Math.min(items.length, 4));
31
+ </script>
32
+
33
+ <Graph {title} {corner} class={className}>
34
+ <GraphBody>
35
+ <ul
36
+ class="stats"
37
+ class:cols2={columns === 2}
38
+ class:cols3={columns === 3}
39
+ class:cols4={columns === 4}
40
+ role="list"
41
+ >
42
+ {#each items as item, i (item.label)}
43
+ <li class="stat" class:accent={item.accent} use:reveal={{ delay: stagger(i, 60) }}>
44
+ <p class="value">{item.value}</p>
45
+ <p class="muted">{item.label}</p>
46
+ {#if item.hint}
47
+ <p class="muted">{item.hint}</p>
48
+ {/if}
49
+ </li>
50
+ {/each}
51
+ </ul>
52
+ </GraphBody>
53
+ </Graph>
54
+
55
+ <style>
56
+ .stats {
57
+ display: grid;
58
+ grid-template-columns: 1fr;
59
+ gap: 2rem;
60
+ }
61
+
62
+ @media (min-width: 640px) {
63
+ .cols2 {
64
+ grid-template-columns: repeat(2, minmax(0, 1fr));
65
+ }
66
+
67
+ .cols3 {
68
+ grid-template-columns: repeat(3, minmax(0, 1fr));
69
+ }
70
+
71
+ .cols4 {
72
+ grid-template-columns: repeat(4, minmax(0, 1fr));
73
+ }
74
+ }
75
+
76
+ .stat {
77
+ display: flex;
78
+ flex-direction: column;
79
+ gap: 0.5rem;
80
+ }
81
+
82
+ .value {
83
+ margin: 0;
84
+ font-size: 1.875rem;
85
+ line-height: 1.2;
86
+ letter-spacing: -0.025em;
87
+ }
88
+
89
+ @media (min-width: 640px) {
90
+ .value {
91
+ font-size: 2.25rem;
92
+ }
93
+ }
94
+
95
+ .muted {
96
+ margin: 0;
97
+ color: var(--graph-muted, oklch(0.62 0 0));
98
+ }
99
+
100
+ .stat.accent .value {
101
+ color: var(--graph-accent, oklch(0.78 0.17 155));
102
+ }
103
+ </style>
@@ -0,0 +1,16 @@
1
+ /** Large figures with labels. Two to four numbers, no trend. */
2
+ export interface StatItem {
3
+ value: string;
4
+ label: string;
5
+ hint?: string;
6
+ accent?: boolean;
7
+ }
8
+ export interface GraphStatProps {
9
+ title: string;
10
+ items: StatItem[];
11
+ corner?: string;
12
+ class?: string;
13
+ }
14
+ declare const GraphStat: import("svelte").Component<GraphStatProps, {}, "">;
15
+ type GraphStat = ReturnType<typeof GraphStat>;
16
+ export default GraphStat;
@@ -0,0 +1,133 @@
1
+ <script module lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ /** Framed data table with an optional footer row for totals. */
5
+ export type Cell = Snippet | string | number;
6
+
7
+ export interface GraphTableProps {
8
+ title: string;
9
+ headers: string[];
10
+ rows: Cell[][];
11
+ footer?: Cell[];
12
+ align?: ('left' | 'right')[];
13
+ corner?: string;
14
+ class?: string;
15
+ }
16
+ </script>
17
+
18
+ <script lang="ts">
19
+ import Graph from '../frame/Graph.svelte';
20
+ import GraphBody from '../frame/GraphBody.svelte';
21
+ import GraphRule from '../frame/GraphRule.svelte';
22
+ import { reveal, stagger } from '../frame/motion';
23
+
24
+ let {
25
+ title,
26
+ headers,
27
+ rows,
28
+ footer,
29
+ align,
30
+ corner,
31
+ class: className = ''
32
+ }: GraphTableProps = $props();
33
+
34
+ function isSnippet(cell: Cell): cell is Snippet {
35
+ return typeof cell === 'function';
36
+ }
37
+
38
+ function alignOf(index: number): 'left' | 'right' {
39
+ return align?.[index] ?? (index === 0 ? 'left' : 'right');
40
+ }
41
+ </script>
42
+
43
+ <Graph {title} {corner} class={className}>
44
+ <GraphBody tight>
45
+ <div class="scroll">
46
+ <table class="table">
47
+ <thead>
48
+ <tr>
49
+ {#each headers as header, i (header)}
50
+ <th scope="col" class="cell head" class:right={alignOf(i) === 'right'}>
51
+ {header}
52
+ </th>
53
+ {/each}
54
+ </tr>
55
+ <tr>
56
+ <th class="rulecell" colspan={headers.length}>
57
+ <GraphRule />
58
+ </th>
59
+ </tr>
60
+ </thead>
61
+ <tbody>
62
+ {#each rows as row, r}
63
+ <tr use:reveal={{ delay: stagger(r, 40), amount: 0.4 }}>
64
+ {#each row as cell, c}
65
+ <td class="cell" class:right={alignOf(c) === 'right'}>
66
+ {#if isSnippet(cell)}{@render cell()}{:else}{cell}{/if}
67
+ </td>
68
+ {/each}
69
+ </tr>
70
+ {/each}
71
+ </tbody>
72
+ {#if footer}
73
+ <tfoot>
74
+ <tr>
75
+ <td class="rulecell pad" colspan={headers.length}>
76
+ <GraphRule />
77
+ </td>
78
+ </tr>
79
+ <tr>
80
+ {#each footer as cell, c}
81
+ <td class="cell foot" class:right={alignOf(c) === 'right'}>
82
+ {#if isSnippet(cell)}{@render cell()}{:else}{cell}{/if}
83
+ </td>
84
+ {/each}
85
+ </tr>
86
+ </tfoot>
87
+ {/if}
88
+ </table>
89
+ </div>
90
+ </GraphBody>
91
+ </Graph>
92
+
93
+ <style>
94
+ .scroll {
95
+ overflow-x: auto;
96
+ }
97
+
98
+ .table {
99
+ font-size: 0.875rem;
100
+ width: 100%;
101
+ min-width: 32rem;
102
+ border-collapse: separate;
103
+ border-spacing: 0;
104
+ }
105
+
106
+ .cell {
107
+ padding: 0.625rem 0.75rem;
108
+ white-space: nowrap;
109
+ text-align: left;
110
+ }
111
+
112
+ .cell.right {
113
+ text-align: right;
114
+ }
115
+
116
+ .cell.head {
117
+ padding-bottom: 0.75rem;
118
+ font-weight: 400;
119
+ }
120
+
121
+ .cell.foot {
122
+ padding-top: 0.25rem;
123
+ }
124
+
125
+ .rulecell {
126
+ padding: 0;
127
+ }
128
+
129
+ .rulecell.pad {
130
+ padding-top: 0.5rem;
131
+ padding-bottom: 0.75rem;
132
+ }
133
+ </style>
@@ -0,0 +1,15 @@
1
+ import type { Snippet } from 'svelte';
2
+ /** Framed data table with an optional footer row for totals. */
3
+ export type Cell = Snippet | string | number;
4
+ export interface GraphTableProps {
5
+ title: string;
6
+ headers: string[];
7
+ rows: Cell[][];
8
+ footer?: Cell[];
9
+ align?: ('left' | 'right')[];
10
+ corner?: string;
11
+ class?: string;
12
+ }
13
+ declare const GraphTable: import("svelte").Component<GraphTableProps, {}, "">;
14
+ type GraphTable = ReturnType<typeof GraphTable>;
15
+ export default GraphTable;