1 commit: 1 rewritten.
@@ site/assets/ui.ts
+ const words = (d: string): string => `${MONTHS[Number(d.slice(5, 7)) - 1]} ${Number(d.slice(8))}, ${d.slice(0, 4)}`;
+ const plural = (n: number, w: string): string => `${n.toLocaleString('en-US')} ${w}${n === 1 ? '' : 's'}`;
+ const level = (n: number, max: number): number => (n <= 0 || max <= 0 ? 0 : Math.min(4, Math.ceil((4 * n) / max)));
++ // A repo's events carry their times, so their days are the reader's,
++ // as their times are; the page without JS has UTC days.
++ const localDay = (ms: number): string => {
++ const t = new Date(ms);
++ return `${t.getFullYear()}-${two(t.getMonth() + 1)}-${two(t.getDate())}`;
++ };
+ const esc = (v: unknown): string => String(v).replace(/[&<>"']/g, (c) => `&#${c.charCodeAt(0)};`);
+ type Days = Record<string, Record<string, number>>;
+ type Ev = [number, string, string, string];
@@ site/assets/ui.ts
+ if (events) {
+ const counts: Record<string, number> = {};
+ for (const e of events) {
-+ const d = new Date(e[0]).toISOString().slice(0, 10);
++ const d = localDay(e[0]);
+ counts[d] = (counts[d] ?? 0) + 1;
+ }
+ paint(g, counts);
@@ site/assets/ui.ts
+ list.querySelector<HTMLElement>('.list-head')!.hidden = !!pick.day;
+ head.hidden = !pick.day;
+ if (!pick.day && !events) return;
-+ const day = pick.day ? (events ?? []).filter((e) => new Date(e[0]).toISOString().slice(0, 10) === pick.day) : events!.slice(0, 20);
++ const day = pick.day ? (events ?? []).filter((e) => localDay(e[0]) === pick.day) : events!.slice(0, 20);
+ head.querySelector('.day-title')!.textContent = pick.day ? words(pick.day) : '';
+ head.querySelector('.day-note')!.textContent = pick.day ? (events ? plural(day.length, 'event') : lost ? "couldn't load the day's events" : 'loading') : '';
+ list.querySelector('ul')!.innerHTML = day.map((e) => evRow(g.dataset.base ?? '', e)).join('');
@@ test/activity-fixture.sh (new)
+export FORGE_STRICT=1
+build
+ ## test/lib.sh ##
+@@ test/lib.sh: if [ -n "${FORGE_TEST_NODE:-}" ]; then
+ PATH=$T/node:$PATH
+ fi
+
++# Days and times in UTC, whatever the machine's zone: the activity grid
++# puts a repo's events on the reader's local day (site/assets/ui.ts).
++export TZ=UTC
+ export FORGE_ROOT=$T/root
+ export FORGE_WWW=$FORGE_ROOT/.forge/www
+ export FORGE_SSH=git@forge.test
+
## test/page.ts ##
// attributes, descendants and lists.