@fuzdev/fuz_ui 0.206.8 → 0.206.9
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.
- package/dist/ProjectActivityChart.svelte +137 -0
- package/dist/ProjectActivityChart.svelte.d.ts +30 -0
- package/dist/ProjectActivityChart.svelte.d.ts.map +1 -0
- package/dist/ProjectLinks.svelte +25 -44
- package/dist/ProjectLinks.svelte.d.ts.map +1 -1
- package/dist/Sparkline.svelte +131 -0
- package/dist/Sparkline.svelte.d.ts +42 -0
- package/dist/Sparkline.svelte.d.ts.map +1 -0
- package/dist/project_stats.d.ts +121 -0
- package/dist/project_stats.d.ts.map +1 -0
- package/dist/project_stats.js +153 -0
- package/dist/project_stats_data.d.ts +3 -0
- package/dist/project_stats_data.d.ts.map +1 -0
- package/dist/project_stats_data.js +469 -0
- package/dist/project_stats_update.task.d.ts +4 -0
- package/dist/project_stats_update.task.d.ts.map +1 -0
- package/dist/project_stats_update.task.js +50 -0
- package/dist/projects.d.ts +17 -0
- package/dist/projects.d.ts.map +1 -0
- package/dist/projects.js +20 -0
- package/dist/publish.task.d.ts +3 -0
- package/dist/publish.task.d.ts.map +1 -0
- package/dist/publish.task.js +23 -0
- package/dist/sparkline.d.ts +102 -0
- package/dist/sparkline.d.ts.map +1 -0
- package/dist/sparkline.js +63 -0
- package/package.json +1 -1
- package/src/lib/project_stats.ts +220 -0
- package/src/lib/project_stats_data.ts +472 -0
- package/src/lib/project_stats_update.task.ts +53 -0
- package/src/lib/projects.ts +49 -0
- package/src/lib/publish.task.ts +22 -0
- package/src/lib/sparkline.ts +173 -0
|
@@ -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"}
|
package/dist/ProjectLinks.svelte
CHANGED
|
@@ -1,49 +1,15 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import Svg from './Svg.svelte';
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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,13 +18,25 @@
|
|
|
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)}
|
|
26
|
+
{@const counts = series_by_name.get(project_item.name)}
|
|
57
27
|
<!-- eslint-disable-next-line svelte/no-navigation-without-resolve -->
|
|
58
28
|
<a class="thumbnail row shade_00 px_md py_xs border_radius_sm mb_lg" href={project_item.url}>
|
|
59
29
|
<Svg shrink={false} data={project_item.logo} size="var(--icon_size_lg)" />
|
|
60
30
|
<div class="pl_lg width_atmost_sm">
|
|
61
|
-
<div class="thumbnail-name {project_item.color_class}">
|
|
31
|
+
<div class="thumbnail-name row align-items:start {project_item.color_class}">
|
|
32
|
+
{project_item.name}
|
|
33
|
+
{#if counts}
|
|
34
|
+
{@const stats_label = label_by_name.get(project_item.name)}
|
|
35
|
+
<div class="thumbnail-sparkline pl_md {project_item.color_class}" title={stats_label}>
|
|
36
|
+
<Sparkline values={counts} {max} scale={1 / 3} end_dot label={stats_label} />
|
|
37
|
+
</div>
|
|
38
|
+
{/if}
|
|
39
|
+
</div>
|
|
62
40
|
<div class="thumbnail-description font_size_md text_70 font-weight:500">
|
|
63
41
|
{project_item.description}
|
|
64
42
|
{project_item.glyph}
|
|
@@ -101,4 +79,7 @@
|
|
|
101
79
|
transparent
|
|
102
80
|
);
|
|
103
81
|
}
|
|
82
|
+
.thumbnail-sparkline {
|
|
83
|
+
margin-left: auto;
|
|
84
|
+
}
|
|
104
85
|
</style>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectLinks.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/ProjectLinks.svelte"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ProjectLinks.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/ProjectLinks.svelte"],"names":[],"mappings":"AA4DA,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"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types and pure helpers for project commit-activity stats.
|
|
3
|
+
*
|
|
4
|
+
* The committed dataset (`project_stats_data.ts`, written by the
|
|
5
|
+
* `project_stats_update` task) stores daily commit counts per project as the
|
|
6
|
+
* master granularity; coarser scopes like monthly are derived at runtime by
|
|
7
|
+
* rebucketing. All date handling is UTC — `YYYY-MM-DD` strings and "epoch
|
|
8
|
+
* days" (days since the Unix epoch) — so results are deterministic across
|
|
9
|
+
* machines.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Daily commit counts for one project.
|
|
15
|
+
*/
|
|
16
|
+
export interface ProjectCommitStats {
|
|
17
|
+
/**
|
|
18
|
+
* Project name, matching `project_items`.
|
|
19
|
+
*/
|
|
20
|
+
name: string;
|
|
21
|
+
/**
|
|
22
|
+
* UTC date (`YYYY-MM-DD`) of the first day bucket, the day of the first commit.
|
|
23
|
+
*/
|
|
24
|
+
start_date: string;
|
|
25
|
+
/**
|
|
26
|
+
* Commits per UTC day from `start_date` through the snapshot's `end_date`, inclusive.
|
|
27
|
+
*/
|
|
28
|
+
daily_counts: Array<number>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* A snapshot of commit stats across projects, sharing a single `end_date`.
|
|
32
|
+
*/
|
|
33
|
+
export interface ProjectStatsSnapshot {
|
|
34
|
+
/**
|
|
35
|
+
* ISO datetime when the snapshot was collected.
|
|
36
|
+
*/
|
|
37
|
+
generated_at: string;
|
|
38
|
+
/**
|
|
39
|
+
* UTC date (`YYYY-MM-DD`) of the final day bucket, shared by every project.
|
|
40
|
+
*/
|
|
41
|
+
end_date: string;
|
|
42
|
+
projects: Array<ProjectCommitStats>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A derived series of bucketed counts for one project.
|
|
46
|
+
*/
|
|
47
|
+
export interface ProjectStatsSeries {
|
|
48
|
+
name: string;
|
|
49
|
+
counts: Array<number>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Converts a UTC `YYYY-MM-DD` date to days since the Unix epoch.
|
|
53
|
+
*/
|
|
54
|
+
export declare const epoch_day_from_date: (date: string) => number;
|
|
55
|
+
/**
|
|
56
|
+
* Converts days since the Unix epoch to a UTC `YYYY-MM-DD` date.
|
|
57
|
+
*/
|
|
58
|
+
export declare const date_from_epoch_day: (epoch_day: number) => string;
|
|
59
|
+
/**
|
|
60
|
+
* Buckets commit timestamps into daily counts from the earliest commit's UTC
|
|
61
|
+
* day through `end_date`, inclusive.
|
|
62
|
+
*
|
|
63
|
+
* @param timestamps - commit times as Unix epoch seconds
|
|
64
|
+
* @param end_date - UTC date (`YYYY-MM-DD`) of the final bucket; later timestamps clamp into it
|
|
65
|
+
* @returns the start date and daily counts, or `null` if `timestamps` is empty
|
|
66
|
+
*/
|
|
67
|
+
export declare const daily_counts_from_timestamps: (timestamps: Array<number>, end_date: string) => {
|
|
68
|
+
start_date: string;
|
|
69
|
+
daily_counts: Array<number>;
|
|
70
|
+
} | null;
|
|
71
|
+
/**
|
|
72
|
+
* Pads `daily_counts` with leading zeros so the series starts at
|
|
73
|
+
* `padded_start_date` instead of `start_date`.
|
|
74
|
+
*
|
|
75
|
+
* Returns the input array unchanged when `padded_start_date` is not earlier
|
|
76
|
+
* than `start_date`.
|
|
77
|
+
*/
|
|
78
|
+
export declare const daily_counts_pad_start: (daily_counts: Array<number>, start_date: string, padded_start_date: string) => Array<number>;
|
|
79
|
+
/**
|
|
80
|
+
* Rebuckets daily counts into calendar-month (UTC) counts.
|
|
81
|
+
*
|
|
82
|
+
* The first and last buckets may cover partial months.
|
|
83
|
+
*/
|
|
84
|
+
export declare const monthly_counts_from_daily: (daily_counts: Array<number>, start_date: string) => Array<number>;
|
|
85
|
+
/**
|
|
86
|
+
* Rebuckets daily counts into 7-day counts, anchored at the end of the series
|
|
87
|
+
* so the newest bucket always covers a full 7 days.
|
|
88
|
+
*
|
|
89
|
+
* The first bucket may cover fewer days when the length isn't a multiple of 7.
|
|
90
|
+
*/
|
|
91
|
+
export declare const weekly_counts_from_daily: (daily_counts: Array<number>) => Array<number>;
|
|
92
|
+
/**
|
|
93
|
+
* Derives aligned monthly series for every project in `snapshot`, sharing one
|
|
94
|
+
* time window and one scale.
|
|
95
|
+
*
|
|
96
|
+
* Each series spans from the earliest project's `start_date` through the
|
|
97
|
+
* snapshot's `end_date` (younger projects are zero-padded at the front), so
|
|
98
|
+
* all series have the same length and bucket boundaries. `max` is the largest
|
|
99
|
+
* monthly count across all projects, for rendering every series at the same
|
|
100
|
+
* vertical scale.
|
|
101
|
+
*/
|
|
102
|
+
export declare const project_stats_to_monthly_series: (snapshot: ProjectStatsSnapshot) => {
|
|
103
|
+
series: Array<ProjectStatsSeries>;
|
|
104
|
+
max: number;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Derives aligned weekly series for every project in `snapshot`, sharing one
|
|
108
|
+
* time window and one scale — the weekly sibling of
|
|
109
|
+
* `project_stats_to_monthly_series`.
|
|
110
|
+
*/
|
|
111
|
+
export declare const project_stats_to_weekly_series: (snapshot: ProjectStatsSnapshot) => {
|
|
112
|
+
series: Array<ProjectStatsSeries>;
|
|
113
|
+
max: number;
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Formats a one-line human-readable summary of a project's commit stats,
|
|
117
|
+
* e.g. `"gro — 2,386 commits since August 7, 2019"`. Used for accessible
|
|
118
|
+
* labels and tooltips.
|
|
119
|
+
*/
|
|
120
|
+
export declare const project_stats_label: (project: ProjectCommitStats) => string;
|
|
121
|
+
//# sourceMappingURL=project_stats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project_stats.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/project_stats.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,YAAY,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,KAAK,CAAC,kBAAkB,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACtB;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,KAAG,MAGlD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAAI,WAAW,MAAM,KAAG,MACA,CAAC;AAEzD;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,GACxC,YAAY,KAAK,CAAC,MAAM,CAAC,EACzB,UAAU,MAAM,KACd;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;CAAE,GAAG,IAaxD,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,GAClC,cAAc,KAAK,CAAC,MAAM,CAAC,EAC3B,YAAY,MAAM,EAClB,mBAAmB,MAAM,KACvB,KAAK,CAAC,MAAM,CAId,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,GACrC,cAAc,KAAK,CAAC,MAAM,CAAC,EAC3B,YAAY,MAAM,KAChB,KAAK,CAAC,MAAM,CAcd,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,GAAI,cAAc,KAAK,CAAC,MAAM,CAAC,KAAG,KAAK,CAAC,MAAM,CAUlF,CAAC;AAuBF;;;;;;;;;GASG;AACH,eAAO,MAAM,+BAA+B,GAC3C,UAAU,oBAAoB,KAC5B;IAAE,MAAM,EAAE,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CACI,CAAC;AAExD;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,GAC1C,UAAU,oBAAoB,KAC5B;IAAE,MAAM,EAAE,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CACG,CAAC;AASvD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAS,kBAAkB,KAAG,MAMjE,CAAC"}
|