Skip to content

Commit bb24e81

Browse files
olafkfreundclaude
andauthored
fix(splashboard): redesign project dashboards + dedup contributors (#523)
The bundled project dashboard was rendering as a stack of look-alike rounded boxes with a broken `font = "standard"` figlet banner, and the Top Contributors bar chart was showing the same user twice ("23 | 23 ola | ola") because four git identities had never been collapsed. Bundled `home/shell/splashboard/project.dashboard.toml` rewrite: - Banner switches to `font = "ansi_shadow"` with `color = "panel_title"` - 3-pill status badge strip (git_age / git_status / git_stash_count) replaces the old Status + Age 2-column row - Full-width 12-month commit heatmap (border = "thick") as the centerpiece - `chart_pie` for LOC by language (vs yet another bar chart) - `list_ranking` of largest files alongside the pie - `list_timeline` for recent commits with bullets and relative time column - Horizontal `chart_bar` for contributors at 2/5 width so names fit - Mixed border hierarchy (thick → rounded → top → rounded) for rhythm Per-repo `.splashboard/dashboard.toml` for this nixos repo: - Same hero band + badge strip vocabulary - GitHub-mirrored 12-month contributions heatmap as the centerpiece - `github_languages` rendered as `chart_pie` (vs the previous bar chart) - New `code_largest_files` ranking with medal glyphs (🥇🥈🥉) - `github_recent_releases` as `list_timeline` (date column + bullet) - `github_contributors_monthly` as `list_ranking` with medals — different vocabulary from the bundled default's bar chart `home/shell/splashboard/home.dashboard.toml` minor tune-up: hero date recolored `panel_title` → `accent` so home and project have distinct identities; fortune footer gets `border = "top"` for a closing seam. `.mailmap` (new) collapses four committer identities (olafkfreund / Olaf K-Freund / Olaf Krasicki-Freund across three emails) into one canonical `Olaf Krasicki-Freund <olaf@freundcloud.com>`. `git shortlog -sne` now reports 1908 commits under one author; `git_contributors` honors this via gix, so the duplicate bars in the chart collapse to a single full-height bar. `_typos.toml`: add `ratatui` to the allowlist — it's the actual Rust TUI library splashboard is built on, not a misspelling of `ratatouille`. Verification: - All three TOML files parse via python tomllib - Every widget's fetcher / render shape combo verified against `splashboard catalog renderer` - `just test-host p620` succeeds; new home-manager-files derivation contains the new TOMLs Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent ffd45ba commit bb24e81

5 files changed

Lines changed: 290 additions & 125 deletions

File tree

.mailmap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Olaf Krasicki-Freund <olaf@freundcloud.com> olafkfreund <olaf.loken@gmail.com>
2+
Olaf Krasicki-Freund <olaf@freundcloud.com> Olaf K-Freund <olaf.loken@google.com>
3+
Olaf Krasicki-Freund <olaf@freundcloud.com> Olaf Krasicki-Freund <olaf.freund@r3.com>
4+
Olaf Krasicki-Freund <olaf@freundcloud.com> Olaf Krasicki-Freund <olaf.loken@gmail.com>

.splashboard/dashboard.toml

Lines changed: 142 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,28 @@
1-
# project_github — per-repo preset. Hero is the repo name as a figlet banner
2-
# (fetched dynamically via `git_repo_name` → git remote origin), subtitle shows the repo
3-
# slug / description / license. Header band sits on `bg = "subtle"` so it reads as a
4-
# distinct panel; body pairs languages / releases, PRs / issues, commits / contributors
5-
# into 2-column rows so the dashboard reads as a tight grid rather than a tall stack.
1+
# Per-repo dashboard for this nixos config repo. Overrides the bundled
2+
# project.dashboard.toml from ~/.splashboard/project.dashboard.toml when
3+
# splashboard runs inside this directory.
64
#
7-
# Drop this file in as `./.splashboard/dashboard.toml` at a repo root. Nothing here is
8-
# repo-specific — every widget discovers the repo at fetch time, so the same template
9-
# produces a tailored dashboard for whichever project the user cd's into.
5+
# Schema: https://splashboard.unhappychoice.com/guides/configuration/
106
#
11-
# Source: https://splashboard.unhappychoice.com/guides/presets/#project_github--repo-hero--activity-grid
7+
# Tuned for an infrastructure-as-code repo:
8+
# • Hero band on `bg = "subtle"` with the repo name in `ansi_shadow` figlet
9+
# • Subtitle: slug / description / license from github_repo
10+
# • Inline stats table (stars / forks / watchers / issues) — kept as
11+
# grid_table since github_repo_stars emits `entries`, not `badge`
12+
# • Status badges row underneath: age, working-tree state, stash count
13+
# • Full-width 12-month GitHub contributions heatmap (border = "thick")
14+
# • Codebase split: github_languages as a pie chart | largest files ranking
15+
# • GitHub work split: open PRs | open issues (border = "top")
16+
# • Closer: releases timeline | monthly contributors ranking
1217
#
13-
# Trust: on first cd into the repo, splashboard will prompt to trust this file
14-
# (or `splashboard trust` ahead of time). The hash is stored in ~/.splashboard/trust.toml.
15-
# Editing this file invalidates the entry — re-run `splashboard trust`.
18+
# Trust: this dashboard wires Network-class widgets (github_*). On first
19+
# `cd` into the repo splashboard prompts for trust; run `splashboard trust`
20+
# ahead of time to skip the prompt. The hash is stored in
21+
# ~/.splashboard/trust.toml; editing this file invalidates the entry.
22+
#
23+
# Contributor dedup is handled at the git layer via ./.mailmap, which
24+
# collapses four committer identities into one canonical author before
25+
# `git_contributors` ever sees them.
1626

1727
# ── Widgets ────────────────────────────────────────────────────────
1828

@@ -21,66 +31,106 @@ id = "hero"
2131
fetcher = "git_repo_name"
2232
render = { type = "text_ascii", style = "figlet", font = "ansi_shadow", color = "panel_title", align = "center" }
2333

24-
# Subtitle: `github_repo` emits TextBlock (slug / description / license on their own rows).
25-
# `list_plain` renders via ratatui's `Paragraph` which centers each line individually,
26-
# so short lines like "ISC" still sit under the hero centreline instead of hugging the
27-
# block's left edge.
34+
# Subtitle — slug / description / license, three stacked lines via the
35+
# `text_block` shape that github_repo emits.
2836
[[widget]]
2937
id = "subtitle"
3038
fetcher = "github_repo"
3139
render = { type = "list_plain", align = "center" }
3240

41+
# Inline repo stats — stars / forks / watchers / open issues, all on one row.
3342
[[widget]]
3443
id = "repo_stats"
3544
fetcher = "github_repo_stars"
3645
render = { type = "grid_table", layout = "inline", align = "center" }
3746

47+
# Status badges — three pills mirroring the bundled project dashboard so
48+
# both layouts share visual vocabulary.
3849
[[widget]]
39-
id = "repo_prs"
40-
fetcher = "github_repo_prs"
41-
render = { type = "list_links", max_items = 5 }
50+
id = "badge_age"
51+
fetcher = "git_age"
52+
render = { type = "status_badge", shape = "rounded", align = "center" }
4253

4354
[[widget]]
44-
id = "repo_issues"
45-
fetcher = "github_repo_issues"
46-
render = { type = "list_links", max_items = 5 }
55+
id = "badge_status"
56+
fetcher = "git_status"
57+
render = { type = "status_badge", shape = "rounded", align = "center" }
4758

4859
[[widget]]
49-
id = "commits_heatmap"
50-
fetcher = "git_commits_activity"
51-
render = "grid_heatmap"
52-
60+
id = "badge_stash"
61+
fetcher = "git_stash_count"
62+
render = { type = "status_badge", shape = "rounded", align = "center" }
63+
64+
# Centerpiece — 12-month GitHub contributions heatmap. Uses the
65+
# GitHub-mirrored view (one square per day, normalized contributor list)
66+
# rather than the local git_commits_activity so the heatmap reads as
67+
# "what does this project look like on GitHub" rather than "what's in my
68+
# local mirror".
5369
[[widget]]
54-
id = "top_contributors"
55-
fetcher = "git_contributors"
56-
render = { type = "chart_bar", max_bars = 5 }
70+
id = "contributions"
71+
fetcher = "github_contributions"
72+
render = { type = "grid_heatmap", align = "center" }
5773

74+
# Codebase — languages as a pie, largest files as a numbered ranking with
75+
# medal glyphs on the top three.
5876
[[widget]]
5977
id = "languages"
6078
fetcher = "github_languages"
61-
render = { type = "chart_bar", horizontal = true }
79+
render = { type = "chart_pie", legend = "right" }
80+
81+
[[widget]]
82+
id = "largest_files"
83+
fetcher = "code_largest_files"
84+
render = { type = "list_ranking", style = "medal" }
85+
[widget.options]
86+
limit = 6
6287

88+
# GitHub work — open PRs and open issues for this repo.
89+
[[widget]]
90+
id = "repo_prs"
91+
fetcher = "github_repo_prs"
92+
render = { type = "list_links", max_items = 5 }
93+
94+
[[widget]]
95+
id = "repo_issues"
96+
fetcher = "github_repo_issues"
97+
render = { type = "list_links", max_items = 5 }
98+
99+
# Closer — releases as a timeline (date column + title), monthly
100+
# contributors as a ranking. Using github_contributors_monthly (which
101+
# honors GitHub's normalized contributor identities) for the closer
102+
# instead of git_contributors so the two contributor visualisations
103+
# bring different vocabularies — bars on the bundled default, ranking
104+
# here.
63105
[[widget]]
64106
id = "releases"
65107
fetcher = "github_recent_releases"
66-
render = { type = "list_links", max_items = 3 }
108+
render = { type = "list_timeline", bullet = "", max_items = 5, date_format = "relative" }
109+
110+
[[widget]]
111+
id = "monthly_contributors"
112+
fetcher = "github_contributors_monthly"
113+
render = { type = "list_ranking", style = "medal" }
114+
[widget.options]
115+
limit = 6
67116

68-
# ── Layout ─────────────────────────────────────────────────────────
117+
# ── Layout ─────────────────────────────────────────────────────────
69118

119+
# Hero band — figlet repo name lifted on `bg = "subtle"`. Spacer row above
120+
# the figlet so the banner breathes inside the band.
70121
[[row]]
71122
height = { length = 1 }
72123
bg = "subtle"
73124

74-
# Hero gets the full band width — `ansi_shadow` figlet is 7 rows tall, with the
75-
# inner `align = "center"` in the render options recentring the glyphs.
76125
[[row]]
77126
height = { length = 7 }
78127
bg = "subtle"
79128
[[row.child]]
80129
widget = "hero"
130+
width = { fill = 1 }
81131

82-
# Subtitle: 3 stacked lines (slug / description / license) via github_repo's TextBlock
83-
# shape. Centered on a 70-cell column inside the band.
132+
# Subtitleslug / description / license, centered on a 70-cell column
133+
# so short lines like "ISC" sit under the hero centreline.
84134
[[row]]
85135
height = { length = 3 }
86136
bg = "subtle"
@@ -89,6 +139,7 @@ flex = "center"
89139
widget = "subtitle"
90140
width = { length = 70 }
91141

142+
# Inline stats — stars / forks / watchers / issues table.
92143
[[row]]
93144
height = { length = 1 }
94145
bg = "subtle"
@@ -97,71 +148,98 @@ flex = "center"
97148
widget = "repo_stats"
98149
width = { length = 70 }
99150

151+
# Status badges row — still on the hero band, three pills flex-centered.
100152
[[row]]
101153
height = { length = 1 }
102154
bg = "subtle"
155+
flex = "center"
156+
gap = 2
157+
[[row.child]]
158+
widget = "badge_age"
159+
width = { length = 22 }
160+
[[row.child]]
161+
widget = "badge_status"
162+
width = { length = 28 }
163+
[[row.child]]
164+
widget = "badge_stash"
165+
width = { length = 18 }
103166

104167
[[row]]
105168
height = { length = 1 }
169+
bg = "subtle"
106170

107-
# Row 1: languages horizontal bar chart | releases timeline.
171+
# Break out of the hero band.
108172
[[row]]
109-
height = { length = 6 }
110-
flex = "center"
173+
height = { length = 1 }
174+
175+
# Centerpiece — GitHub contributions heatmap, full width, thick border.
176+
[[row]]
177+
height = { length = 7 }
178+
[[row.child]]
179+
widget = "contributions"
180+
width = { fill = 1 }
181+
border = "thick"
182+
title = " 12 months of commits "
183+
title_align = "center"
184+
185+
[[row]]
186+
height = { length = 1 }
187+
188+
# Codebase split — languages pie | largest files ranking.
189+
[[row]]
190+
height = { length = 8 }
111191
gap = 2
112192
[[row.child]]
113193
widget = "languages"
114-
width = { length = 34 }
115-
border = "top"
194+
width = { fill = 1 }
195+
border = "rounded"
116196
title = " languages "
117197
title_align = "center"
118198
[[row.child]]
119-
widget = "releases"
120-
width = { length = 34 }
121-
border = "top"
122-
title = " released "
199+
widget = "largest_files"
200+
width = { fill = 1 }
201+
border = "rounded"
202+
title = " largest files "
123203
title_align = "center"
124204

125205
[[row]]
126206
height = { length = 1 }
127207

128-
# Row 2: PRs | issues — two list_plain columns.
208+
# GitHub work — open PRs | open issues. Top border (lighter than rounded)
209+
# marks this as the most heavily-loaded data row visually.
129210
[[row]]
130211
height = { length = 9 }
131-
flex = "center"
132212
gap = 2
133213
[[row.child]]
134214
widget = "repo_prs"
135-
width = { length = 34 }
215+
width = { fill = 1 }
136216
border = "top"
137-
title = " PRs "
217+
title = " open PRs "
138218
title_align = "center"
139219
[[row.child]]
140220
widget = "repo_issues"
141-
width = { length = 34 }
221+
width = { fill = 1 }
142222
border = "top"
143-
title = " issues "
223+
title = " open issues "
144224
title_align = "center"
145225

146226
[[row]]
147227
height = { length = 1 }
148228

149-
# Row 3: commits heatmap | top contributors. Heatmap shows the 52-week contribution
150-
# grid (repo-level, not viewer-level). Top contributors is a horizontal bar chart
151-
# capped at 5.
229+
# Closer — releases timeline | monthly contributors ranking. Rounded
230+
# borders mirror the codebase split so the bottom echoes the middle.
152231
[[row]]
153-
height = { length = 10 }
154-
flex = "center"
232+
height = { length = 9 }
155233
gap = 2
156234
[[row.child]]
157-
widget = "commits_heatmap"
158-
width = { length = 34 }
159-
border = "top"
160-
title = " commits "
235+
widget = "releases"
236+
width = { fill = 1 }
237+
border = "rounded"
238+
title = " recent releases "
161239
title_align = "center"
162240
[[row.child]]
163-
widget = "top_contributors"
164-
width = { length = 34 }
165-
border = "top"
166-
title = " top contributors "
241+
widget = "monthly_contributors"
242+
width = { fill = 1 }
243+
border = "rounded"
244+
title = " monthly contributors "
167245
title_align = "center"

_typos.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ nd = "nd"
5151
# AER is the PCIe Advanced Error Reporting acronym
5252
AER = "AER"
5353

54+
# ratatui is the Rust TUI library splashboard is built on
55+
ratatui = "ratatui"
56+
5457
[default.extend-identifiers]
5558
# Santa Claus - not "Clause"
5659
Claus = "Claus"

home/shell/splashboard/home.dashboard.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
id = "hero_date"
2020
fetcher = "clock"
2121
format = "%a %e %b"
22-
render = { type = "text_ascii", style = "blocks", pixel_size = "quadrant", color = "panel_title", align = "center" }
22+
render = { type = "text_ascii", style = "blocks", pixel_size = "quadrant", color = "accent", align = "center" }
2323

2424
# Footer flourish — daily fortune. `length = "auto"` row sizes itself to whatever cookie was
2525
# drawn so 1-line fortunes hug the closing line and 4-line ones get the room they need.
@@ -272,11 +272,14 @@ height = { length = 1 }
272272
[[row]]
273273
# `height = "auto"` — text_plain's `natural_height` returns the TextBlock line count, so
274274
# 1-line fortunes hug the closing line and multi-line cookies get the room they need.
275+
# `border = "top"` adds a closing seam under the body grid so the fortune reads as a
276+
# deliberate footer flourish rather than a stray line of text.
275277
height = "auto"
276278
flex = "center"
277279
[[row.child]]
278280
widget = "fortune"
279281
width = { length = 80 }
282+
border = "top"
280283

281284
[[row]]
282285
height = { length = 1 }

0 commit comments

Comments
 (0)