Skip to content

Refactor dashboard charts into per-chart cards and refresh the header#10

Merged
tyom merged 18 commits into
mainfrom
dev
May 23, 2026
Merged

Refactor dashboard charts into per-chart cards and refresh the header#10
tyom merged 18 commits into
mainfrom
dev

Conversation

@tyom
Copy link
Copy Markdown
Owner

@tyom tyom commented May 23, 2026

Summary

A dashboard-focused pass over the web/ Svelte app: the monolithic OverallCharts is broken into per-chart cards, charts are recast for clarity, and shared chart/legend logic is extracted into reusable helpers. Also adds a header refresh, language-treemap GitHub links, a self-contained favicon, and a tag-sync caveat in the README.

Charts & components

  • Split OverallCharts into per-chart cardsChurnCard, CommitShareCard, CommitStyleCard, LanguagesCard, LargestFilesCard, WeeklyCommitsCard, drops OverallCharts from ~770 lines to a thin shell.
  • Replaced ECharts legends with HTML legends carrying author popovers, backed by a shared ChartLegend component and a chart-legend.svelte.ts selection-state factory.
  • Recast charts: churn as diverging bars with author labels; net-lines-per-commit as a commit-style scatter with a balanced axis; commit share as a labelled pie (skipping bot profile lookups).
  • Moved contributor commit share into the author popover; centralized the bot-filter rule into humanContribRows.

Header & UI polish

  • Enriched the header with repo links, merge count, timestamps, and social counts; hardened header and tooltip rendering and fixed the merge count under active filters.
  • Grouped co-located tags in the timeline hover tooltip; labelled the largest-files title with its active scope; widened the technologies grid gap; dimmed punch-card row separators.

Data & build

  • Classified .po as Gettext Catalog and linked the language treemap to GitHub.
  • Inlined the favicon as a base64 data URI (inlineFavicon() in vite.config.ts) so single-file dashboards render it over file://.
  • Documented the tag-sync caveat (force-moved floating vX tag) and added a git gc make target.

Test plan

  • make build regenerates dist/repo-intel (committed).
  • bun run check in web/ passes.

Summary by CodeRabbit

  • New Features

    • Five new visualization cards: churn distribution, commit-share pie, commit-style scatter, language treemap, and largest-files treemap.
    • Header shows merge-aware commit totals, GitHub social counts, and last-commit timestamp.
    • Author popovers now display commit-share percentages and timeline tag groups.
    • Interactive chart legends, hover popovers, and improved chart interactions.
    • Added Gettext Catalog support for .po/.pot files.
    • Single-file build now inlines the favicon.
  • Documentation

    • Added instructions to resync local git tags after the release workflow.
  • Chores

    • New Makefile target to repack repository history (gc).

Review Change Stack

tyom added 17 commits May 23, 2026 12:34
- Link the commits/contributors/branches counts to their GitHub pages
  (text-colour, underlined, no underline on hover).
- Headline now matches GitHub's commit count: show authored + merge
  commits as "N commits (M merges)". totals.commits stays the merge-free
  authored count (= sum of contributors' commits, the share denominator);
  merges live in a sibling totals.merges composed in only at display time.
- Add "Generated N ago" (header, right) and "Last commit N ago"
  (Contributions section), both relative with the full timestamp on hover.
- Add GitHub stars/watchers/forks via REST (github.com only, 5s timeout,
  degrades to absent for non-GitHub or unreachable repos).
Tags on the same commit (shared oid) draw on one dot, so only the topmost
was discoverable. The tag tip now lists every tag at that commit as a
two-column table (names aligned, hairline row separators), with the shared
date and oid below.
The Sat/Sun grid line sits inside the weekend tint band, which amplified
it into the chart's boldest rule. Lower the uniform splitLine opacity so
it reads as a normal subdivision again. Tints unchanged.
The weekly-commits and commit-share charts aggregate contributors by
email, so one person committing under several addresses shows up as
several rows sharing a display name. ECharts keys legend selection by
series name, collapsing those into one toggle. Name the series/slices by
email instead, hide ECharts' own legend, and render HTML legends that
toggle selection and carry the same author popover the timeline lanes
use. Add matching name links + popovers to the contributor and pattern
cards, with aria-pressed on the legend toggles and non-navigating labels
on local-only repos.
Convert the commit-share donut to a larger solid pie with outside
name + share labels. minShowLabelAngle drops the label (and its leader
line) for sectors under ~4% of the circle; being angle-based, labels
reappear as the legend hides bigger slices and the survivors widen.
Hovering a legend row now highlights its slice, scaling it out a touch.

Also skip bot accounts (logins ending in [bot]) in the GraphQL profile
fetch — they're Bot nodes, not User nodes, so user(login:) only ever
returns NOT_FOUND. Benign NOT_FOUND errors are no longer warned about.
Replace the grouped added/deleted bars with horizontal diverging bars
(deleted left of zero, added right), sorted by total churn and filtered
of [bot] accounts so the human contributors keep the scale. The y-axis
labels carry the identity dot, name, and author popover used elsewhere,
and click through to the contributor's commits. The legend moves into
the title as colour squares, and the value labels drop their stroke.
The languages treemap header carried each contributor's commit share, but
the names truncate at narrow widths and re-anchoring the hover popover on
every mouseover (one per zrender sub-element of the header strip) made it
jerk. Drop the header percentage, key the popover on the contributor idx so
it anchors once per section, and surface the share on the popover's commit
line instead — shared across the table, timeline, churn axis, and treemap.
Addresses a code-review pass over the branch:

- repo-intel.py: the merge tally is whole-history (collected before
  filtering, and merges aren't in commits_meta to recount), so adding it
  to a date/subset-filtered authored total inflated the "N commits"
  headline. Drop it under any --since/--until/--commits filter so the
  headline reads as just the commits in range.
- OverallCharts.svelte: escape contributor names in the four tooltip
  formatters whose output is rendered as HTML (a name with markup would
  otherwise inject). Rich-text/canvas labels are left as-is.
- ContributorCard/PatternCard.svelte: gate target/rel on a real href so
  local-only repos (url "#") render a clean non-navigating label rather
  than dangling link attributes.
- Header.svelte: collapse the three repeated link-or-plaintext subtitle
  branches into a single `stat` snippet.

Rebuild dist/repo-intel.
OverallCharts.svelte (1212 lines) became a 28-line grid orchestrator;
each chart now lives in its own component following the
ContributorCard/PatternCard convention:

- WeeklyCommitsCard, CommitShareCard, ChurnCard, CommitStyleCard,
  LanguagesCard, LargestFilesCard (each owns its option + handlers)
- ChartLegend: shared HTML legend + Reset for the two legend-driven charts
- chart-helpers.ts: shared name/email/legend builders + tileInnerBorder

Languages and files cards self-guard their own visibility. Promoted the
cross-component layout primitives (.chart-card/.ec/.ec-tree/.span-2) into
app.css; per-card style overrides stay collocated.
- Classify .po/.pot as "Gettext Catalog" (gold #9e6a03, GitHub's
  attention fallback for colorless Linguist languages) instead of letting
  translation catalogs vanish into "Other". Pinned via gen_techdata.py's
  EXT_OVERRIDE + SYNTHETIC_COLORS (merge reordered before the override
  guard) so a `make techdata` regen reproduces it rather than dropping it.
- Fix langSearchUrl: emit a path-glob query for buckets GitHub can't
  resolve by language (Gettext Catalog -> path:*.po OR path:*.pot),
  suppress the unresolvable Tools link, and quote multi-word language
  names so `language:"Common Lisp"` parses.
- Link "Languages by contributor" treemap cells. GitHub code search has
  no author filter, so the two dimensions split across the cell: the
  header strip opens the author's commit log, each language tile opens a
  repo-wide code search for that language.
- Raise the language limit 6 -> 10 before collapsing into "Other".
WeeklyCommitsCard and CommitShareCard each carried an identical copy of
the hidden-legend plumbing (sel state, chart ref, onReady/toggle/reset,
plus highlight on the pie). Pull it into createLegendSelection() in a new
chart-legend.svelte.ts module (the popover-store.svelte.ts -module
convention), exposing selected via a getter so callers stay reactive.
ChurnCard and CommitStyleCard both open-coded the non-bot contributor
filter (map to {c, origIdx}, drop logins ending in [bot]). Pull it into
humanContribRows() in chart-helpers.ts so the bot-detection rule lives in
one place and the two charts can't drift on what counts as a bot.
The generated dashboard is a single HTML file opened over file:// from
/tmp, so a sibling or remote favicon never loads. vite-plugin-singlefile
only inlines JS/CSS, and public/ files are copied verbatim — so the icon
shipped as an unreachable ./favicon.png link.

Move the favicon out of public/ into src/assets so Vite tracks it as a
build asset, and add an inlineFavicon() plugin that reads its bytes from
the bundle and rewrites the <link> href to a data: URI (no node:fs, like
the existing abs() helper). One self-contained file, no emitted sibling.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b831f079-d1c9-4050-8fa5-94d04e9f9dbf

📥 Commits

Reviewing files that changed from the base of the PR and between 74c9142 and 09e3bde.

⛔ Files ignored due to path filters (1)
  • dist/repo-intel is excluded by !**/dist/**
📒 Files selected for processing (2)
  • web/src/lib/components/ChartLegend.svelte
  • web/src/lib/popover-store.svelte.ts

📝 Walkthrough

Walkthrough

This PR refactors the dashboard frontend into modular chart components while enhancing backend data collection. The backend now tracks merge commits, fetches GitHub social statistics, and adds Gettext Catalog language support. The frontend extracts six chart cards from a monolithic OverallCharts component, implements multi-tag timeline tooltips, and threads author popovers throughout the UI to show commit share and contributor details on hover.

Changes

Backend: Statistics and Language Support

Layer / File(s) Summary
Merge-aware commits and GitHub social stats
repo-intel.py
collect_local() now captures whole-repo merge count and latest commit timestamp. build_data() propagates these as totals.merges and lastCommit. New fetch_repo_social() fetches stars/watchers/forks from GitHub REST API (GitHub-only). render_markdown() and console output now report headline commit counts that include merges. Filters remove merge counts to avoid inflating filtered views. fetch_user_profiles() skips bot logins and treats GraphQL NOT_FOUND as non-actionable. top_languages() limit increased from 6 to 10.
Gettext Catalog language support
gen_techdata.py, techdata.json
EXT_OVERRIDE maps .po/.pot to "Gettext Catalog". SYNTHETIC_COLORS adds a color entry for "Gettext Catalog". build_language_tables() merges SYNTHETIC_COLORS before applying overrides so the .po/.pot mappings are included when "Gettext Catalog" is in the colored set. techdata.json updated with the new language color and extension mappings.

Frontend: Data, State, and Timeline

Layer / File(s) Summary
Type contracts and time formatting
web/src/types.ts, web/src/lib/format.ts
Totals adds optional merges field. RepoData adds lastCommit, generatedAt, and GitHub social counts (stars, watchers, forks). New relativeTime() and fmtDateTime() helpers format ISO timestamps as relative ("N ago") and full locale strings. langSearchUrl() updated to use SYNTHETIC_PATH_QUERY for Gettext Catalog and quote multi-word language names in search queries.
Popover state and author metadata
web/src/lib/popover-store.svelte.ts
authorMeta reactive state stores totalCommits for commit-share calculations. setAuthorTotalCommits() initializes from App.svelte. Timeline tooltip state transitions from single tag to grouped tags: Tag[]. setTagTip() accepts tag arrays and updates when the first OID or group size changes.
Timeline tooltip multi-tag rendering
web/src/lib/popovers.ts, web/src/lib/timeline.ts, web/src/lib/components/TimelineTooltip.svelte
TimelineTooltip.showTag() now accepts Tag[] instead of single tag. timeline.ts precomputes tagGroups keyed by commit OID, passing the full group to tooltip hover. TimelineTooltip component renders either single-tag layout or multi-tag CSS Grid layout with per-tag rows, messages, and grouped styling.

Frontend: Chart Architecture

Layer / File(s) Summary
Chart helpers and legend state management
web/src/lib/chart-helpers.ts, web/src/lib/chart-legend.svelte.ts
New chart-helpers module exports identity maps (buildNameByEmail, buildEmailToOrig), buildContribLegend for legend items, humanContribRows for bot-filtered contributors, and tileInnerBorder CSS constant. chart-legend.svelte.ts exports createLegendSelection() factory that synchronizes ECharts legend state via event handlers and action dispatchers (toggle, reset, highlight).
OverallCharts refactored to layout component
web/src/lib/components/OverallCharts.svelte
Extracted chart option construction, ECharts wiring, and drill-down behavior into six card components. Component now declares data and authorPopover props, imports card components, and renders a 2-column grid passing props through. All ECharts-heavy logic moved to individual cards.
Six chart cards: weekly, share, churn, style, languages, files
web/src/lib/components/WeeklyCommitsCard.svelte, CommitShareCard.svelte, ChurnCard.svelte, CommitStyleCard.svelte, LanguagesCard.svelte, LargestFilesCard.svelte
WeeklyCommitsCard: stacked area by contributor with custom legend. CommitShareCard: pie with "Others" slice and legend-driven selection. ChurnCard: diverging bars showing added vs deleted per contributor with author popover on hover. CommitStyleCard: log-scaled scatter with median churn vs commit count, symbol-sized by total touch. LanguagesCard: treemap grouped by contributor with language-colored tiles, URL navigation, and popover anchoring. LargestFilesCard: treemap with HEAD/history tab toggle, drill-down/up navigation, breadcrumb overlay, and remainder tile.
ChartLegend component
web/src/lib/components/ChartLegend.svelte
Interactive legend buttons drive ECharts selection state. Renders hide/show toggles, optional author popover on hover (when idx >= 0), and emphasis toggle. Reset button appears when items are hidden. Uses createLegendSelection() state and dispatches toggle/reset/highlight actions.

Frontend: Integration and Display

Layer / File(s) Summary
App.svelte initialization and header wiring
web/src/App.svelte, web/src/lib/components/Header.svelte
App.svelte imports setAuthorTotalCommits, calls it during onMount to initialize popover totals, and derives last-commit relative/full timestamps for the Contributions header. Header.svelte derives GitHub base URL and per-type URL builders, conditionally renders social counts and generated time blocks, and refactors subtitle rendering to switch between linkable and plain-text labels based on URL availability.
ContributorCard and PatternCard popovers
web/src/lib/components/ContributorCard.svelte, web/src/lib/components/PatternCard.svelte
ContributorCard converts contributor name to conditional link (navigates when not "#"), wires author popover on name hover, and adds link truncation/underline styling. PatternCard derives conditional href from url prop, replaces plain title with navigable anchor, wires author popover on title hover, and updates split-line axis styling to a uniform separator.
AuthorPopover commit share
web/src/lib/components/AuthorPopover.svelte
Computes commitShare percentage from author commits relative to authorMeta.totalCommits and conditionally renders it in parentheses. Added .lp-share styling for muted text color.

Frontend: Styling and Build

Layer / File(s) Summary
Chart card styling and favicon inlining
web/src/styles/app.css, web/src/lib/components/TechGrid.svelte, web/vite.config.ts, web/index.html
app.css adds shared .chart-card, .ec, .ec-tree, and .span-2 layout primitives for consistent chart sizing and grid positioning. .contributions-title flex layout for header with nested .last-commit styling. TechGrid.svelte updates gap to 48px default with 16px mobile override. vite.config.ts adds inlineFavicon() plugin to convert favicon to base64 data URI during bundle. index.html documents the inlining behavior.
Build and release documentation
Makefile, README.md
gc Make target added to report git pack sizes before/after git gc. README documents the vX tag syncing workflow after release cutover using git fetch --tags --force --prune origin.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • tyom/repo-intel#9: Related frontend chart/prop changes; overlaps in OverallCharts/PatternCard wiring.
  • tyom/repo-intel#6: Prior frontend migration touching popover/timeline/format modules and language query logic.

"🐰
Hooray — six cards in tidy rows,
Popovers bloom where the hover goes,
Merge counts and stars now softly gleam,
Tags grouped together, a reviewer’s dream,
The dashboard hops into a brighter stream."

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 65.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main refactoring work: splitting the monolithic OverallCharts component into per-chart cards and updating the header component.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
web/vite.config.ts (1)

50-51: ⚡ Quick win

Replace btoa with Buffer and make favicon href replacement deterministic

  • Line 50: btoa(binary) relies on legacy Node globals and requires an extra bytes→string loop; prefer Buffer.from(bytes).toString("base64").
  • Line 51: new RegExp(\\.?/${fav.fileName}`)interpolates an unescaped filename into a regex; use exact string replacements for./${fav.fileName}and/${fav.fileName}` (or escape regex metacharacters).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/vite.config.ts` around lines 50 - 51, Replace the legacy btoa-based
base64 conversion and the unsafe regex replacement: instead of using
btoa(binary) build the data URI with Buffer.from(binary).toString("base64") (use
Buffer.from to convert the bytes), and replace the html.source.replace(new
RegExp(...)) call with deterministic exact string replacements for both
`./${fav.fileName}` and `/${fav.fileName}` (or escape fav.fileName) so
html.source.replace targets the literal paths; update the code around dataUri,
btoa, html.source.replace, and fav.fileName accordingly.
web/src/lib/components/LargestFilesCard.svelte (1)

93-99: 💤 Low value

Potential Infinity/-Infinity when leafTotals is empty.

If payload.items contains only root-level files without fullPath set, or only the "N more files" remainder, leafTotals could be empty. Math.min(...[]) returns Infinity and Math.max(...[]) returns -Infinity, which would make lo > hi and cause grey() to always return t = 1.

In practice this is unlikely given the data shape, but a guard would be safer:

Suggested defensive guard
     const leafTotals: number[] = [];
     for (const n of nodes) {
       if (n.children) for (const c of n.children) leafTotals.push(c.total);
       else if (n.fullPath) leafTotals.push(n.total);
     }
+    if (leafTotals.length === 0) leafTotals.push(1); // fallback to avoid Infinity
     const lo = Math.log(Math.max(Math.min(...leafTotals), 1));
     const hi = Math.log(Math.max(...leafTotals, 1));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/lib/components/LargestFilesCard.svelte` around lines 93 - 99, The
code computes lo and hi from leafTotals but doesn't handle an empty leafTotals
array, causing Math.min(...leafTotals) to be Infinity and lo>hi; add a guard: if
leafTotals.length === 0 set safe defaults (e.g. lo = 0 and hi = 0 or hi = 1)
before computing logs, otherwise compute lo and hi as now; reference leafTotals,
lo, hi and ensure the grey() caller gets a sensible range (or clamp t) so it
won’t always return t = 1 when leafTotals is empty.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/src/lib/components/ChartLegend.svelte`:
- Line 72: The Reset button in ChartLegend.svelte remains focusable/accessible
when hidden because it only uses opacity; update the element so when hasHidden
is false it is removed from the accessibility tree and not focusable: modify the
<button class="chart-reset-btn" class:visible={hasHidden}
onclick={onReset}>Reset</button> to conditionally render or toggle attributes
(e.g., render only when hasHidden, or add aria-hidden="true" and tabindex="-1"
and pointer-events: none/visibility:hidden when not visible) so the button is
neither tabbable nor announced by screen readers when hidden; apply the same fix
to the other hidden controls referenced around lines 133-155.

In `@web/src/lib/popover-store.svelte.ts`:
- Around line 127-136: The identity check in setTagTip currently only compares
tags[0]?.oid and length, which fails for tag groups keyed by date (no oid) and
allows stale tooltips; update the condition in setTagTip to compare a stable key
for the group: if tags[0]?.oid exists use oid, otherwise compare the date (e.g.,
tags[0]?.date or equivalent timestamp) along with the length, so
timelineTipState.tags is updated when the date-keyed group changes; adjust the
branch that sets timelineTipState.kind and timelineTipState.tags accordingly.

---

Nitpick comments:
In `@web/src/lib/components/LargestFilesCard.svelte`:
- Around line 93-99: The code computes lo and hi from leafTotals but doesn't
handle an empty leafTotals array, causing Math.min(...leafTotals) to be Infinity
and lo>hi; add a guard: if leafTotals.length === 0 set safe defaults (e.g. lo =
0 and hi = 0 or hi = 1) before computing logs, otherwise compute lo and hi as
now; reference leafTotals, lo, hi and ensure the grey() caller gets a sensible
range (or clamp t) so it won’t always return t = 1 when leafTotals is empty.

In `@web/vite.config.ts`:
- Around line 50-51: Replace the legacy btoa-based base64 conversion and the
unsafe regex replacement: instead of using btoa(binary) build the data URI with
Buffer.from(binary).toString("base64") (use Buffer.from to convert the bytes),
and replace the html.source.replace(new RegExp(...)) call with deterministic
exact string replacements for both `./${fav.fileName}` and `/${fav.fileName}`
(or escape fav.fileName) so html.source.replace targets the literal paths;
update the code around dataUri, btoa, html.source.replace, and fav.fileName
accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0ad72c04-fc67-4d7f-97f7-9c663c9bda4e

📥 Commits

Reviewing files that changed from the base of the PR and between 4adf216 and 74c9142.

⛔ Files ignored due to path filters (2)
  • dist/repo-intel is excluded by !**/dist/**
  • web/src/assets/favicon.png is excluded by !**/*.png
📒 Files selected for processing (30)
  • Makefile
  • README.md
  • gen_techdata.py
  • repo-intel.py
  • techdata.json
  • web/index.html
  • web/src/App.svelte
  • web/src/lib/chart-helpers.ts
  • web/src/lib/chart-legend.svelte.ts
  • web/src/lib/components/AuthorPopover.svelte
  • web/src/lib/components/ChartLegend.svelte
  • web/src/lib/components/ChurnCard.svelte
  • web/src/lib/components/CommitShareCard.svelte
  • web/src/lib/components/CommitStyleCard.svelte
  • web/src/lib/components/ContributorCard.svelte
  • web/src/lib/components/Header.svelte
  • web/src/lib/components/LanguagesCard.svelte
  • web/src/lib/components/LargestFilesCard.svelte
  • web/src/lib/components/OverallCharts.svelte
  • web/src/lib/components/PatternCard.svelte
  • web/src/lib/components/TechGrid.svelte
  • web/src/lib/components/TimelineTooltip.svelte
  • web/src/lib/components/WeeklyCommitsCard.svelte
  • web/src/lib/format.ts
  • web/src/lib/popover-store.svelte.ts
  • web/src/lib/popovers.ts
  • web/src/lib/timeline.ts
  • web/src/styles/app.css
  • web/src/types.ts
  • web/vite.config.ts

Comment thread web/src/lib/components/ChartLegend.svelte Outdated
Comment thread web/src/lib/popover-store.svelte.ts
- ChartLegend: hide Reset from tab order/AT and make it click-inert
  when no series is hidden (was opacity-only, still focusable/clickable).
- setTagTip: key group identity on oid || date so lightweight tags
  (no oid) don't collide and stick a stale tooltip across date groups.
@tyom tyom merged commit b782157 into main May 23, 2026
2 checks passed
@tyom tyom deleted the dev branch May 23, 2026 18:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant