@fuzdev/fuz_ui 0.206.8 → 0.207.0

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 (46) hide show
  1. package/dist/DeclarationDetail.svelte +55 -20
  2. package/dist/DeclarationDetail.svelte.d.ts +1 -1
  3. package/dist/DeclarationDetail.svelte.d.ts.map +1 -1
  4. package/dist/ProjectActivityChart.svelte +137 -0
  5. package/dist/ProjectActivityChart.svelte.d.ts +30 -0
  6. package/dist/ProjectActivityChart.svelte.d.ts.map +1 -0
  7. package/dist/ProjectLinks.svelte +31 -46
  8. package/dist/ProjectLinks.svelte.d.ts.map +1 -1
  9. package/dist/Sparkline.svelte +131 -0
  10. package/dist/Sparkline.svelte.d.ts +42 -0
  11. package/dist/Sparkline.svelte.d.ts.map +1 -0
  12. package/dist/TypeJsonView.svelte +90 -0
  13. package/dist/TypeJsonView.svelte.d.ts +26 -0
  14. package/dist/TypeJsonView.svelte.d.ts.map +1 -0
  15. package/dist/TypeLink.svelte +17 -1
  16. package/dist/TypeLink.svelte.d.ts +10 -0
  17. package/dist/TypeLink.svelte.d.ts.map +1 -1
  18. package/dist/declaration.svelte.d.ts +25 -5
  19. package/dist/declaration.svelte.d.ts.map +1 -1
  20. package/dist/declaration.svelte.js +31 -5
  21. package/dist/project_stats.d.ts +121 -0
  22. package/dist/project_stats.d.ts.map +1 -0
  23. package/dist/project_stats.js +153 -0
  24. package/dist/project_stats_data.d.ts +3 -0
  25. package/dist/project_stats_data.d.ts.map +1 -0
  26. package/dist/project_stats_data.js +469 -0
  27. package/dist/project_stats_update.task.d.ts +4 -0
  28. package/dist/project_stats_update.task.d.ts.map +1 -0
  29. package/dist/project_stats_update.task.js +50 -0
  30. package/dist/projects.d.ts +17 -0
  31. package/dist/projects.d.ts.map +1 -0
  32. package/dist/projects.js +20 -0
  33. package/dist/publish.task.d.ts +3 -0
  34. package/dist/publish.task.d.ts.map +1 -0
  35. package/dist/publish.task.js +23 -0
  36. package/dist/sparkline.d.ts +102 -0
  37. package/dist/sparkline.d.ts.map +1 -0
  38. package/dist/sparkline.js +63 -0
  39. package/package.json +2 -2
  40. package/src/lib/declaration.svelte.ts +37 -7
  41. package/src/lib/project_stats.ts +220 -0
  42. package/src/lib/project_stats_data.ts +472 -0
  43. package/src/lib/project_stats_update.task.ts +53 -0
  44. package/src/lib/projects.ts +49 -0
  45. package/src/lib/publish.task.ts +22 -0
  46. package/src/lib/sparkline.ts +173 -0
@@ -4,7 +4,7 @@
4
4
  Renders the full detail view for an exported declaration.
5
5
  Handles all svelte-docinfo declaration kinds (function, class, interface,
6
6
  type, variable, enum, component, snippet) and their kind-specific fields
7
- including parameters, props, members, overloads, intersects, and more.
7
+ including parameters, props, members, overloads, external types, and more.
8
8
 
9
9
  @see `declaration.svelte.ts` for the `Declaration` wrapper class
10
10
  @see {@link https://github.com/ryanatkn/svelte-docinfo svelte-docinfo} for the analysis library
@@ -22,11 +22,24 @@ including parameters, props, members, overloads, intersects, and more.
22
22
 
23
23
  import type { Declaration } from './declaration.svelte.js';
24
24
  import TypeLink from './TypeLink.svelte';
25
+ import TypeJsonView from './TypeJsonView.svelte';
25
26
  import ModuleLink from './ModuleLink.svelte';
26
27
  import DocsLink from './DocsLink.svelte';
27
28
 
28
29
  const { declaration }: { declaration: Declaration } = $props();
29
30
 
31
+ // external types not already shown in the inheritance section — on direct
32
+ // heritage (`interface Props extends HTMLButtonAttributes`) the producer
33
+ // deliberately records the same name in both fields, so the external-types
34
+ // section keeps only what heritage doesn't already display
35
+ const external_types_not_inherited = $derived.by(() => {
36
+ const external_types = declaration.external_types;
37
+ if (!external_types?.length) return undefined;
38
+ const heritage = (declaration.extends_types ?? []).concat(declaration.implements_types ?? []);
39
+ const filtered = external_types.filter((t) => !heritage.includes(t));
40
+ return filtered.length ? filtered : undefined;
41
+ });
42
+
30
43
  // render mdz inline `code` as API-linking `DocsLink` and fenced blocks as syntax-highlighted
31
44
  // `Code`, matching the rest of the docs — the injection mdz core leaves open
32
45
  mdz_set_context_with_fallback(mdz_code_context, () => DocsLink);
@@ -57,7 +70,7 @@ including parameters, props, members, overloads, intersects, and more.
57
70
  {/if}
58
71
  <div class="row gap_md mb_sm">
59
72
  <strong>type</strong>
60
- <TypeLink type={param.type} />
73
+ <TypeLink type={param.type} type_info={param.typeInfo} />
61
74
  </div>
62
75
  {#if param.optional || param.defaultValue}
63
76
  <div class="row gap_md">
@@ -79,7 +92,7 @@ including parameters, props, members, overloads, intersects, and more.
79
92
  <code>
80
93
  {param.name}{#if param.optional}?{/if}
81
94
  </code>
82
- <TypeLink type={param.type} />
95
+ <TypeLink type={param.type} type_info={param.typeInfo} />
83
96
  </div>
84
97
  {/snippet}
85
98
 
@@ -125,7 +138,7 @@ including parameters, props, members, overloads, intersects, and more.
125
138
  {/if}
126
139
  {/snippet}
127
140
 
128
- <!-- A comma-separated inline list of type links (extends, implements, intersects are rarely more than one). -->
141
+ <!-- A comma-separated inline list of type links (extends, implements, external types are rarely more than one). -->
129
142
  {#snippet type_list(types: Array<string>)}
130
143
  {#each types as type, i (type)}
131
144
  {#if i > 0}
@@ -194,6 +207,23 @@ including parameters, props, members, overloads, intersects, and more.
194
207
  <Code lang="ts" content={declaration.type_signature} />
195
208
  {/if}
196
209
 
210
+ <!-- structured type (variables and type aliases; carries what the flat
211
+ signature lost — union members, recovered alias names — with links) -->
212
+ {#if declaration.type_info}
213
+ <p class="row gap_md">
214
+ <strong>type</strong>
215
+ <TypeJsonView type_info={declaration.type_info} title={declaration.type_signature} />
216
+ </p>
217
+ {/if}
218
+
219
+ <!-- default (top-level variables; params, props, and members render theirs inline) -->
220
+ {#if declaration.default_value}
221
+ <p class="row gap_md">
222
+ <strong>default</strong>
223
+ <Code lang="ts" content={declaration.default_value} />
224
+ </p>
225
+ {/if}
226
+
197
227
  <!-- import statement -->
198
228
  <Code lang="ts" content={declaration.import_statement} />
199
229
 
@@ -226,7 +256,7 @@ including parameters, props, members, overloads, intersects, and more.
226
256
  {/if}
227
257
  <div class="row gap_md mb_sm">
228
258
  <strong>type</strong>
229
- <TypeLink type={prop.type} />
259
+ <TypeLink type={prop.type} type_info={prop.typeInfo} />
230
260
  </div>
231
261
  {#if prop.optional || prop.bindable || prop.defaultValue}
232
262
  <div class="row gap_md">
@@ -274,7 +304,7 @@ including parameters, props, members, overloads, intersects, and more.
274
304
  {#if overload.returnType}
275
305
  <div class="row gap_md">
276
306
  <strong>returns</strong>
277
- <TypeLink type={overload.returnType} />
307
+ <TypeLink type={overload.returnType} type_info={overload.returnTypeInfo} />
278
308
  </div>
279
309
  {#if overload.returnDescription}
280
310
  <Mdz content={overload.returnDescription} />
@@ -285,12 +315,13 @@ including parameters, props, members, overloads, intersects, and more.
285
315
  </section>
286
316
  {/if}
287
317
 
288
- <!-- intersects (component/type intersection types) -->
289
- {#if declaration.intersects?.length}
318
+ <!-- external types whose contributions are filtered out of (or, on
319
+ interfaces/classes, never enumerated in) props/members -->
320
+ {#if external_types_not_inherited}
290
321
  <section>
291
- <h4>intersects</h4>
322
+ <h4>external types</h4>
292
323
  <div class="row gap_md flex-wrap:wrap">
293
- {@render type_list(declaration.intersects)}
324
+ {@render type_list(external_types_not_inherited)}
294
325
  </div>
295
326
  </section>
296
327
  {/if}
@@ -299,7 +330,14 @@ including parameters, props, members, overloads, intersects, and more.
299
330
  {#if declaration.return_type}
300
331
  <section>
301
332
  <h4>returns</h4>
302
- <Code lang="ts" content={declaration.return_type} />
333
+ {#if declaration.return_type_info}
334
+ <!-- the flat expansion stays visible in the type signature above -->
335
+ <p>
336
+ <TypeJsonView type_info={declaration.return_type_info} title={declaration.return_type} />
337
+ </p>
338
+ {:else}
339
+ <Code lang="ts" content={declaration.return_type} />
340
+ {/if}
303
341
  {#if declaration.return_description}
304
342
  <Mdz content={declaration.return_description} />
305
343
  {/if}
@@ -334,17 +372,13 @@ including parameters, props, members, overloads, intersects, and more.
334
372
  {/if}
335
373
 
336
374
  <!-- Extends/Implements -->
337
- {#if declaration.extends_type || declaration.implements_types?.length}
375
+ {#if declaration.extends_types?.length || declaration.implements_types?.length}
338
376
  <section>
339
377
  <h4>inheritance</h4>
340
- {#if declaration.extends_type}
378
+ {#if declaration.extends_types?.length}
341
379
  <div class="row gap_md flex-wrap:wrap">
342
380
  <strong>extends:</strong>
343
- {@render type_list(
344
- Array.isArray(declaration.extends_type)
345
- ? declaration.extends_type
346
- : [declaration.extends_type]
347
- )}
381
+ {@render type_list(declaration.extends_types)}
348
382
  </div>
349
383
  {/if}
350
384
  {#if declaration.implements_types?.length}
@@ -440,6 +474,7 @@ including parameters, props, members, overloads, intersects, and more.
440
474
  type={member.kind === 'constructor'
441
475
  ? `new ${member.typeSignature}`
442
476
  : member.typeSignature}
477
+ type_info={member.kind === 'variable' ? member.typeInfo : undefined}
443
478
  />
444
479
  </p>
445
480
  {/if}
@@ -455,7 +490,7 @@ including parameters, props, members, overloads, intersects, and more.
455
490
  {/if}
456
491
  </div>
457
492
  {/if}
458
- {#if member.kind === 'variable' && member.defaultValue}
493
+ {#if (member.kind === 'variable' || member.kind === 'function') && member.defaultValue}
459
494
  <div class="row gap_md">
460
495
  <strong>default</strong>
461
496
  <Code lang="ts" content={member.defaultValue} />
@@ -475,7 +510,7 @@ including parameters, props, members, overloads, intersects, and more.
475
510
  {#if member.kind === 'function' && member.returnType}
476
511
  <div class="row gap_md">
477
512
  <strong>returns</strong>
478
- <TypeLink type={member.returnType} />
513
+ <TypeLink type={member.returnType} type_info={member.returnTypeInfo} />
479
514
  </div>
480
515
  {#if member.returnDescription}
481
516
  <Mdz content={member.returnDescription} />
@@ -6,7 +6,7 @@ type $$ComponentProps = {
6
6
  * Renders the full detail view for an exported declaration.
7
7
  * Handles all svelte-docinfo declaration kinds (function, class, interface,
8
8
  * type, variable, enum, component, snippet) and their kind-specific fields
9
- * including parameters, props, members, overloads, intersects, and more.
9
+ * including parameters, props, members, overloads, external types, and more.
10
10
  *
11
11
  * @see `declaration.svelte.ts` for the `Declaration` wrapper class
12
12
  * @see {@link https://github.com/ryanatkn/svelte-docinfo svelte-docinfo} for the analysis library
@@ -1 +1 @@
1
- {"version":3,"file":"DeclarationDetail.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/DeclarationDetail.svelte"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAgB1D,KAAK,gBAAgB,GAAI;IAAE,WAAW,EAAE,WAAW,CAAA;CAAE,CAAC;AA+cvD;;;;;;;;GAQG;AACH,QAAA,MAAM,iBAAiB,sDAAwC,CAAC;AAChE,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC9D,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"DeclarationDetail.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/DeclarationDetail.svelte"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAiB1D,KAAK,gBAAgB,GAAI;IAAE,WAAW,EAAE,WAAW,CAAA;CAAE,CAAC;AA+evD;;;;;;;;GAQG;AACH,QAAA,MAAM,iBAAiB,sDAAwC,CAAC;AAChE,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC9D,eAAe,iBAAiB,CAAC"}
@@ -0,0 +1,137 @@
1
+ <script lang="ts">
2
+ import type { OmitStrict } from '@fuzdev/fuz_util/types.ts';
3
+ import type { SvelteHTMLElements } from 'svelte/elements';
4
+
5
+ import { project_items } from './projects.js';
6
+ import { project_stats_data } from './project_stats_data.js';
7
+ import { project_stats_label, project_stats_to_weekly_series } from './project_stats.js';
8
+ import { sparkline_geometry, type SparklineScale } from './sparkline.js';
9
+
10
+ /**
11
+ * A large line chart of weekly commit activity with every fuz.dev project
12
+ * drawn over one another, sharing one time window and one scale.
13
+ *
14
+ * Each project's line uses its `color_class` from `project_items` (the
15
+ * `ProjectLinks` grid doubles as the legend), with the same per-point alpha
16
+ * fade and end dot as `Sparkline`. Hovering a line shows the project's
17
+ * stats via a native `title`. The svg scales to its container's width.
18
+ *
19
+ * The background is a light wash of `currentColor` (the inherited text
20
+ * color), overridable with the `--sparkline_bg` custom property.
21
+ *
22
+ * @module
23
+ */
24
+
25
+ const {
26
+ width = 800,
27
+ height = 160,
28
+ scale = 1 / 3,
29
+ stroke_width = 2,
30
+ alpha_floor = 0.4,
31
+ label = 'weekly commit activity for all projects, drawn over one another at a shared scale',
32
+ ...rest
33
+ }: OmitStrict<SvelteHTMLElements['svg'], 'width' | 'height' | 'scale'> & {
34
+ /**
35
+ * Width of the svg's coordinate space in px; rendering stretches to the container.
36
+ */
37
+ width?: number;
38
+ /**
39
+ * Height of the svg's coordinate space in px.
40
+ */
41
+ height?: number;
42
+ /**
43
+ * Vertical scale for the lines' geometry — see `SparklineScale`.
44
+ */
45
+ scale?: SparklineScale;
46
+ stroke_width?: number;
47
+ /**
48
+ * Stroke alpha at a value of 0, scaling linearly to 1 at the shared max.
49
+ */
50
+ alpha_floor?: number;
51
+ /**
52
+ * Accessible label for the chart.
53
+ */
54
+ label?: string;
55
+ } = $props();
56
+
57
+ const chart_id = $props.id();
58
+
59
+ const { series, max } = project_stats_to_weekly_series(project_stats_data);
60
+ const color_class_by_name = new Map(project_items.map((p) => [p.name, p.color_class]));
61
+ const label_by_name = new Map(
62
+ project_stats_data.projects.map((p) => [p.name, project_stats_label(p)])
63
+ );
64
+
65
+ const lines = $derived(
66
+ series.flatMap(({ name, counts }) => {
67
+ const geometry = sparkline_geometry(counts, {
68
+ width,
69
+ height,
70
+ max,
71
+ scale,
72
+ stroke_width,
73
+ alpha_floor,
74
+ end_dot: true
75
+ });
76
+ return geometry
77
+ ? [
78
+ {
79
+ name,
80
+ geometry,
81
+ color_class: color_class_by_name.get(name),
82
+ title: label_by_name.get(name)
83
+ }
84
+ ]
85
+ : [];
86
+ })
87
+ );
88
+ </script>
89
+
90
+ <svg {...rest} viewBox="0 0 {width} {height}" role="img" aria-label={label}>
91
+ <defs>
92
+ {#each lines as line, index (line.name)}
93
+ <linearGradient
94
+ id="{chart_id}-{index}"
95
+ class={line.color_class}
96
+ gradientUnits="userSpaceOnUse"
97
+ x1="0"
98
+ y1="0"
99
+ x2={width}
100
+ y2="0"
101
+ >
102
+ {#each line.geometry.stops as stop, stop_index (stop_index)}
103
+ <stop offset={stop.offset} stop-color="currentColor" stop-opacity={stop.opacity} />
104
+ {/each}
105
+ </linearGradient>
106
+ {/each}
107
+ </defs>
108
+ {#each lines as line, index (line.name)}
109
+ <g class={line.color_class}>
110
+ <title>{line.title}</title>
111
+ <polyline
112
+ points={line.geometry.points}
113
+ fill="none"
114
+ stroke="url(#{chart_id}-{index})"
115
+ stroke-width={stroke_width}
116
+ stroke-linejoin="round"
117
+ stroke-linecap="round"
118
+ />
119
+ <circle
120
+ cx={line.geometry.end_x}
121
+ cy={line.geometry.end_y}
122
+ r={line.geometry.dot_radius}
123
+ fill="currentColor"
124
+ fill-opacity={line.geometry.end_alpha}
125
+ />
126
+ </g>
127
+ {/each}
128
+ </svg>
129
+
130
+ <style>
131
+ svg {
132
+ width: 100%;
133
+ height: auto;
134
+ background: var(--sparkline_bg, color-mix(in hsl, currentColor 8%, transparent));
135
+ border-radius: var(--border_radius_xs);
136
+ }
137
+ </style>
@@ -0,0 +1,30 @@
1
+ import type { OmitStrict } from '@fuzdev/fuz_util/types.ts';
2
+ import type { SvelteHTMLElements } from 'svelte/elements';
3
+ import { type SparklineScale } from './sparkline.js';
4
+ type $$ComponentProps = OmitStrict<SvelteHTMLElements['svg'], 'width' | 'height' | 'scale'> & {
5
+ /**
6
+ * Width of the svg's coordinate space in px; rendering stretches to the container.
7
+ */
8
+ width?: number;
9
+ /**
10
+ * Height of the svg's coordinate space in px.
11
+ */
12
+ height?: number;
13
+ /**
14
+ * Vertical scale for the lines' geometry — see `SparklineScale`.
15
+ */
16
+ scale?: SparklineScale;
17
+ stroke_width?: number;
18
+ /**
19
+ * Stroke alpha at a value of 0, scaling linearly to 1 at the shared max.
20
+ */
21
+ alpha_floor?: number;
22
+ /**
23
+ * Accessible label for the chart.
24
+ */
25
+ label?: string;
26
+ };
27
+ declare const ProjectActivityChart: import("svelte").Component<$$ComponentProps, {}, "">;
28
+ type ProjectActivityChart = ReturnType<typeof ProjectActivityChart>;
29
+ export default ProjectActivityChart;
30
+ //# sourceMappingURL=ProjectActivityChart.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProjectActivityChart.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/ProjectActivityChart.svelte"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAK1D,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAExE,KAAK,gBAAgB,GAAI,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC,GAAG;IAC9F;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AA2FH,QAAA,MAAM,oBAAoB,sDAAwC,CAAC;AACnE,KAAK,oBAAoB,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;AACpE,eAAe,oBAAoB,CAAC"}
@@ -1,49 +1,15 @@
1
1
  <script lang="ts">
2
2
  import Svg from './Svg.svelte';
3
- import type { SvgData } from './svg.js';
4
- import {
5
- // TODO when fuz.dev is ready
6
- // logo_fuz,
7
- logo_fuz_ui,
8
- logo_fuz_code,
9
- logo_fuz_blog,
10
- logo_fuz_mastodon,
11
- logo_fuz_gitops,
12
- logo_fuz_template,
13
- logo_fuz_css,
14
- logo_fuz_util,
15
- logo_gro,
16
- logo_svelte_docinfo,
17
- logo_fuz_app,
18
- logo_tsv
19
- } from './logos.js';
3
+ import Sparkline from './Sparkline.svelte';
4
+ import { project_items, type ProjectItem } from './projects.js';
5
+ import { project_stats_data } from './project_stats_data.js';
6
+ import { project_stats_label, project_stats_to_monthly_series } from './project_stats.js';
20
7
 
21
- // TODO refactor
22
- interface ProjectItem {
23
- name: string;
24
- url: string;
25
- logo: SvgData;
26
- description: string;
27
- glyph: string;
28
- color_class: string;
29
- }
30
-
31
- // TODO ideally this wouldn't duplicate metadata like descriptions, but adding fuz_gitops to this repo is heavy
32
- // prettier-ignore
33
- const project_items: Array<ProjectItem> = [
34
- {name: 'fuz_app', url: 'https://app.fuz.dev/', logo: logo_fuz_app, description: '[pre-alpha] fullstack app library', glyph: '🗝', color_class: 'color_j_50'},
35
- {name: 'fuz_css', url: 'https://css.fuz.dev/', logo: logo_fuz_css, description: 'semantic-first CSS framework and design system', glyph: '🌿', color_class: 'color_b_50'},
36
- {name: 'fuz_ui', url: 'https://ui.fuz.dev/', logo: logo_fuz_ui, description: 'Svelte UI library', glyph: '🧶', color_class: 'color_c_50'},
37
- {name: 'fuz_template', url: 'https://template.fuz.dev/', logo: logo_fuz_template, description: 'a static web app and Node library template with TypeScript, Svelte, SvelteKit, Vite, esbuild, Gro, and Fuz', glyph: '❄', color_class: 'color_h_50'},
38
- {name: 'fuz_blog', url: 'https://blog.fuz.dev/', logo: logo_fuz_blog, description: 'blog software from scratch with SvelteKit', glyph: '🖊️', color_class: 'color_e_50'},
39
- {name: 'fuz_code', url: 'https://code.fuz.dev/', logo: logo_fuz_code, description: 'syntax styling utilities and components for TypeScript, Svelte, Markdown, and more', glyph: '🎨', color_class: 'color_g_50'},
40
- {name: 'fuz_mastodon', url: 'https://mastodon.fuz.dev/', logo: logo_fuz_mastodon, description: 'Mastodon components and helpers for Svelte, SvelteKit, and Fuz', glyph: '🦣', color_class: 'color_d_50'},
41
- {name: 'fuz_gitops', url: 'https://gitops.fuz.dev/', logo: logo_fuz_gitops, description: 'a tool for managing many repos', glyph: '🪄', color_class: 'color_a_50'},
42
- {name: 'svelte-docinfo', url: 'https://svelte-docinfo.fuz.dev/', logo: logo_svelte_docinfo, description: 'static analysis for TypeScript and Svelte', glyph: '📜', color_class: 'color_i_50'},
43
- {name: 'fuz_util', url: 'https://util.fuz.dev/', logo: logo_fuz_util, description: 'utility belt for JS', glyph: '🦕', color_class: 'color_f_50'},
44
- {name: 'gro', url: 'https://github.com/fuzdev/gro', logo: logo_gro, description: 'task runner and toolkit extending SvelteKit', glyph: '🌰', color_class: 'color_f_50'},
45
- {name: 'tsv', url: 'https://tsv.fuz.dev/', logo: logo_tsv, description: 'precise language tools for TypeScript/JS, CSS, and Svelte in Rust', glyph: '🪶', color_class: 'color_h_50'},
46
- ];
8
+ const { series, max } = project_stats_to_monthly_series(project_stats_data);
9
+ const series_by_name = new Map(series.map((s) => [s.name, s.counts]));
10
+ const label_by_name = new Map(
11
+ project_stats_data.projects.map((p) => [p.name, project_stats_label(p)])
12
+ );
47
13
  </script>
48
14
 
49
15
  <h2 class="mt_0 mb_xl2">Packages</h2>
@@ -52,19 +18,35 @@
52
18
  {@render package_thumbnail(project_item)}
53
19
  {/each}
54
20
  </menu>
21
+ <small class="display:block text-align:right">
22
+ the charts show public commit activity<br />since Gro planted on August 7, 2019
23
+ </small>
55
24
 
56
25
  {#snippet package_thumbnail(project_item: ProjectItem)}
57
- <!-- eslint-disable-next-line svelte/no-navigation-without-resolve -->
58
- <a class="thumbnail row shade_00 px_md py_xs border_radius_sm mb_lg" href={project_item.url}>
26
+ {@const counts = series_by_name.get(project_item.name)}
27
+ <!-- eslint-disable svelte/no-navigation-without-resolve -->
28
+ <a
29
+ class="thumbnail row align-items:start shade_00 px_md py_xs border_radius_sm mb_lg"
30
+ href={project_item.url}
31
+ >
59
32
  <Svg shrink={false} data={project_item.logo} size="var(--icon_size_lg)" />
60
33
  <div class="pl_lg width_atmost_sm">
61
- <div class="thumbnail-name {project_item.color_class}">{project_item.name}</div>
34
+ <div class="thumbnail-name row {project_item.color_class}">
35
+ {project_item.name}
36
+ {#if counts}
37
+ {@const stats_label = label_by_name.get(project_item.name)}
38
+ <div class="thumbnail-sparkline pl_md {project_item.color_class}" title={stats_label}>
39
+ <Sparkline values={counts} {max} scale={1 / 3} end_dot label={stats_label} />
40
+ </div>
41
+ {/if}
42
+ </div>
62
43
  <div class="thumbnail-description font_size_md text_70 font-weight:500">
63
44
  {project_item.description}
64
45
  {project_item.glyph}
65
46
  </div>
66
47
  </div>
67
48
  </a>
49
+ <!-- eslint-enable svelte/no-navigation-without-resolve -->
68
50
  {/snippet}
69
51
 
70
52
  <style>
@@ -101,4 +83,7 @@
101
83
  transparent
102
84
  );
103
85
  }
86
+ .thumbnail-sparkline {
87
+ margin-left: auto;
88
+ }
104
89
  </style>
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectLinks.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/ProjectLinks.svelte"],"names":[],"mappings":"AAgFA,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IACtG,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,YAAY;;kBAA+E,CAAC;AAChF,KAAK,YAAY,GAAG,YAAY,CAAC,OAAO,YAAY,CAAC,CAAC;AACxD,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"ProjectLinks.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/ProjectLinks.svelte"],"names":[],"mappings":"AA6DA,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IACtG,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,YAAY;;kBAA+E,CAAC;AAChF,KAAK,YAAY,GAAG,YAAY,CAAC,OAAO,YAAY,CAAC,CAAC;AACxD,eAAe,YAAY,CAAC"}
@@ -0,0 +1,131 @@
1
+ <script lang="ts">
2
+ import type { OmitStrict } from '@fuzdev/fuz_util/types.ts';
3
+ import type { SvelteHTMLElements } from 'svelte/elements';
4
+
5
+ import { sparkline_geometry, type SparklineScale } from './sparkline.js';
6
+
7
+ /**
8
+ * Renders values as a small inline SVG line graph.
9
+ *
10
+ * Designed for comparable small multiples: pass a shared `max` so a set of
11
+ * sparklines renders at the same vertical scale instead of each stretching
12
+ * to fit. The stroke uses `currentColor`, so color it by setting `color` on
13
+ * the component or a parent (e.g. a fuz_css `color_*` class). Each point's
14
+ * stroke alpha scales with its value, from `alpha_floor` at 0 up to 1 at
15
+ * `max`, de-emphasizing quiet stretches.
16
+ *
17
+ * `scale` controls only the geometry: the nonlinear options compress the
18
+ * top of the range so small values stay legible under a large shared
19
+ * `max`, while the alpha fade keeps tracking the linear ratio so it still
20
+ * encodes true magnitude.
21
+ *
22
+ * The background is a light wash of `currentColor`, overridable with the
23
+ * `--sparkline_bg` custom property.
24
+ *
25
+ * @module
26
+ */
27
+
28
+ const {
29
+ values,
30
+ max,
31
+ scale = 'linear',
32
+ width = 100,
33
+ height = 24,
34
+ stroke_width = 2,
35
+ alpha_floor = 0.4,
36
+ end_dot = false,
37
+ label,
38
+ ...rest
39
+ }: OmitStrict<SvelteHTMLElements['svg'], 'values' | 'width' | 'height' | 'scale'> & {
40
+ values: Array<number>;
41
+ /**
42
+ * The value rendered at full height and full alpha.
43
+ * Pass a shared max across sparklines for comparable scales.
44
+ * Defaults to the local max of `values`.
45
+ */
46
+ max?: number;
47
+ /**
48
+ * Vertical scale for the line's geometry — see `SparklineScale`.
49
+ * The alpha fade always tracks the linear ratio regardless of `scale`.
50
+ */
51
+ scale?: SparklineScale;
52
+ /**
53
+ * Width of the svg in px.
54
+ */
55
+ width?: number;
56
+ /**
57
+ * Height of the svg in px.
58
+ */
59
+ height?: number;
60
+ stroke_width?: number;
61
+ /**
62
+ * Stroke alpha at a value of 0, scaling linearly to 1 at `max`.
63
+ */
64
+ alpha_floor?: number;
65
+ /**
66
+ * Renders a dot at the final point, anchoring the "now" end of the line.
67
+ */
68
+ end_dot?: boolean;
69
+ /**
70
+ * Accessible label. When omitted the svg is `aria-hidden`.
71
+ */
72
+ label?: string;
73
+ } = $props();
74
+
75
+ const gradient_id = $props.id();
76
+
77
+ const geometry = $derived(
78
+ sparkline_geometry(values, { width, height, max, scale, stroke_width, alpha_floor, end_dot })
79
+ );
80
+ </script>
81
+
82
+ <svg
83
+ {...rest}
84
+ {width}
85
+ {height}
86
+ viewBox="0 0 {width} {height}"
87
+ role={label ? 'img' : undefined}
88
+ aria-label={label}
89
+ aria-hidden={label ? undefined : true}
90
+ >
91
+ {#if geometry}
92
+ <defs>
93
+ <linearGradient
94
+ id={gradient_id}
95
+ gradientUnits="userSpaceOnUse"
96
+ x1="0"
97
+ y1="0"
98
+ x2={width}
99
+ y2="0"
100
+ >
101
+ {#each geometry.stops as stop, index (index)}
102
+ <stop offset={stop.offset} stop-color="currentColor" stop-opacity={stop.opacity} />
103
+ {/each}
104
+ </linearGradient>
105
+ </defs>
106
+ <polyline
107
+ points={geometry.points}
108
+ fill="none"
109
+ stroke="url(#{gradient_id})"
110
+ stroke-width={stroke_width}
111
+ stroke-linejoin="round"
112
+ stroke-linecap="round"
113
+ />
114
+ {#if end_dot}
115
+ <circle
116
+ cx={geometry.end_x}
117
+ cy={geometry.end_y}
118
+ r={geometry.dot_radius}
119
+ fill="currentColor"
120
+ fill-opacity={geometry.end_alpha}
121
+ />
122
+ {/if}
123
+ {/if}
124
+ </svg>
125
+
126
+ <style>
127
+ svg {
128
+ background: var(--sparkline_bg, color-mix(in hsl, currentColor 8%, transparent));
129
+ border-radius: var(--border_radius_xs);
130
+ }
131
+ </style>
@@ -0,0 +1,42 @@
1
+ import type { OmitStrict } from '@fuzdev/fuz_util/types.ts';
2
+ import type { SvelteHTMLElements } from 'svelte/elements';
3
+ import { type SparklineScale } from './sparkline.js';
4
+ type $$ComponentProps = OmitStrict<SvelteHTMLElements['svg'], 'values' | 'width' | 'height' | 'scale'> & {
5
+ values: Array<number>;
6
+ /**
7
+ * The value rendered at full height and full alpha.
8
+ * Pass a shared max across sparklines for comparable scales.
9
+ * Defaults to the local max of `values`.
10
+ */
11
+ max?: number;
12
+ /**
13
+ * Vertical scale for the line's geometry — see `SparklineScale`.
14
+ * The alpha fade always tracks the linear ratio regardless of `scale`.
15
+ */
16
+ scale?: SparklineScale;
17
+ /**
18
+ * Width of the svg in px.
19
+ */
20
+ width?: number;
21
+ /**
22
+ * Height of the svg in px.
23
+ */
24
+ height?: number;
25
+ stroke_width?: number;
26
+ /**
27
+ * Stroke alpha at a value of 0, scaling linearly to 1 at `max`.
28
+ */
29
+ alpha_floor?: number;
30
+ /**
31
+ * Renders a dot at the final point, anchoring the "now" end of the line.
32
+ */
33
+ end_dot?: boolean;
34
+ /**
35
+ * Accessible label. When omitted the svg is `aria-hidden`.
36
+ */
37
+ label?: string;
38
+ };
39
+ declare const Sparkline: import("svelte").Component<$$ComponentProps, {}, "">;
40
+ type Sparkline = ReturnType<typeof Sparkline>;
41
+ export default Sparkline;
42
+ //# sourceMappingURL=Sparkline.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sparkline.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/Sparkline.svelte"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAExE,KAAK,gBAAgB,GAAI,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC,GAAG;IACzG,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACtB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAoEH,QAAA,MAAM,SAAS,sDAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}