mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-11 17:34:00 +01:00
Some checks are pending
crdt_sync_dart tests / test (push) Waiting to run
crdt_sync_flutter tests / test (push) Waiting to run
crdt-sync pre-commit / pre-commit (push) Waiting to run
crdt-sync tests / test (push) Waiting to run
dependency freshness / dependencies on newest stable (push) Waiting to run
design_system tests / test (push) Waiting to run
file length / file-length (push) Waiting to run
freedays pre-commit / pre-commit (push) Waiting to run
freedays tests / test (push) Waiting to run
gatelock pre-commit / pre-commit (push) Waiting to run
gatelock tests / test (push) Waiting to run
github_device_auth tests / test (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
music_theory tests / test (push) Waiting to run
palette drift / palette (push) Waiting to run
shared gate tests / gate unit tests (push) Waiting to run
sync_settings_ui tests / test (push) Waiting to run
web_ui tests / test (push) Waiting to run
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AwtowrowDXx6ccmWVPkCaF
155 lines
7.3 KiB
Markdown
155 lines
7.3 KiB
Markdown
# Nielsen coverage audit
|
||
|
||
Jakob Nielsen's ["10 GUI Design Elements Build Every User
|
||
Interface"](https://jakobnielsenphd.substack.com/p/gui-widgets) argues that
|
||
essentially every UI is assembled from ~10 standardized elements, and that the
|
||
value comes from *reusing* those conventions rather than re-inventing them.
|
||
Re-implementing the same button in eight repos is the private version of the
|
||
convention erosion he describes.
|
||
|
||
This file is the **audit grid**, not a build list. Shipping a widget nobody
|
||
imports is the failure mode to avoid — 183 imported agent definitions were
|
||
invoked zero times in 432 sessions. A component gets built only where **two or
|
||
more repos already contain a structurally similar implementation**.
|
||
|
||
Written 2026-08-14, alongside `design_system` v0.1.0.
|
||
|
||
**Phase 3 (web, `@kuhyx/web-ui`) is recorded in `phase3-record.md`** — including
|
||
why `FilterBar` was *not* extracted (structurally disjoint despite the shared
|
||
name) and the new categorical ramp. Read it before re-proposing any web
|
||
component.
|
||
|
||
## Scope
|
||
|
||
Fourteen Flutter repos, seven web repos, four Python/Tk guard apps. Out of
|
||
scope, verified rather than assumed: Unity (zero `.uxml`/`.uss` files exist
|
||
anywhere), games (their repeated identifiers are game constants like
|
||
`FORGE_MAX_C`, not UI), and the locker gate windows (their X-grab/input-hijack
|
||
invariants make the *window* non-reusable, though its leaf widgets are fair
|
||
game).
|
||
|
||
`~/src/testsAndMisc/pomodoro_app` and `horatio` no longer exist. **`workout_app`
|
||
does not exist either** — it is named in the source plan and in several skill
|
||
docs, but no directory under `~` matches `*workout*`. Anything citing it as a
|
||
consumer is stale.
|
||
|
||
## The grid
|
||
|
||
| # | Nielsen element | Flutter | Web | Python/Tk |
|
||
|---|---|---|---|---|
|
||
| 1 | Buttons | ⚠️ themed only | ❌ 7 vocabularies | ⚠️ 4 factories, see Phase 2 |
|
||
| 2 | Input fields / forms | ✅ `inputDecorationTheme` | ❌ | ⚠️ |
|
||
| 3 | Menus | ❌ not specced | ❌ | ❌ |
|
||
| 4 | Links | ❌ not specced | ❌ | n/a |
|
||
| 5 | Dialogs | ✅ `confirmDestructive()` | ❌ | ⚠️ |
|
||
| 6 | Alerts / notifications | ✅ `showToast`/`showError` | ❌ | ❌ |
|
||
| 7 | Icons | ❌ not specced | ❌ | ❌ |
|
||
| 8 | Checkboxes / radio buttons | ⚠️ themed only | ❌ | ❌ |
|
||
| 9 | Tabs | ❌ not specced | ❌ | ❌ |
|
||
| 10 | Search | ❌ not specced | ⚠️ `FilterBar` ×2 | n/a |
|
||
|
||
`components.html` specs 9 components but says nothing about **menus, links,
|
||
icons, radio buttons, tabs, or search** — six of Nielsen's ten. That is the
|
||
documentation gap; whether any of them deserves *code* still depends on the
|
||
two-repo extraction criterion, which most of them currently fail.
|
||
|
||
## What v0.1.0 closed
|
||
|
||
| Export | Replaced |
|
||
|---|---|
|
||
| `AppPalette` + scales | 10 divergent `theme.dart` copies; ~318 raw color literals |
|
||
| `buildLightTheme` / `buildDarkTheme` | the same, per repo |
|
||
| `AppStatusColors` | 4 hand-rolled `ThemeExtension`s with inconsistent fields |
|
||
| `confirmDestructive()` | ~35 inlined `AlertDialog`s |
|
||
| `showToast` / `showError` | ~38 raw `SnackBar` sites, zero helpers |
|
||
| `EmptyState` | 4 variants, one reusable |
|
||
| `SectionHeader` | 3 near-identical private widgets |
|
||
|
||
Proof consumers `todo` and `untools` are migrated, verified and pushed.
|
||
|
||
### Which exports have a live consumer
|
||
|
||
An extracted component with no importer is the failure mode this audit
|
||
exists to prevent, so the honest status per export:
|
||
|
||
| Export | Live consumers |
|
||
|---|---|
|
||
| tokens, palette, themes | todo, untools |
|
||
| `confirmDestructive` | todo (2 sites) |
|
||
| `showToast` / `showError` | todo (3 sites) |
|
||
| `SectionHeader` | untools (2 sites) |
|
||
| `EmptyState` | **none yet** — donor is home_inventory (3 sites), unmigrated |
|
||
| `AppStatusColors` | **none yet** — 4 donors, all unmigrated |
|
||
|
||
Palette/token consumers beyond the two proof apps, added the same day:
|
||
`focus_owner`, `kuhylog`, `epopeja_karta` (tokens only) and `billsplit`.
|
||
|
||
The last two ship ahead of their consumers. That is defensible (both have
|
||
real donors waiting, and `AppStatusColors` must exist for `showError` to read
|
||
the danger hue off the theme) but it is not *validated*, and it should be
|
||
called that way until home_inventory or one of the status-color donors
|
||
migrates.
|
||
|
||
### Corrections to the original plan, found by measuring
|
||
|
||
The plan's figures were mostly right but three were not, and the difference
|
||
changes what is worth doing next:
|
||
|
||
- **The "343 raw literals" are not spread through call sites.** They are
|
||
concentrated in the hand-copied theme files. todo had 35, *all 35* inside
|
||
`theme.dart`; untools had 36, of which 35 were in `theme.dart` and the last
|
||
was `Colors.transparent` in `keyboard.dart` — a sentinel, not a palette
|
||
value. Deleting the theme file removes essentially all of them. There was no
|
||
call-site sweep to do in either proof consumer, and the same is true of
|
||
home_inventory, habit_stack, diet-guard, wake-alarm, macro-cam and kuhylog,
|
||
which all have **zero** literals outside their token file. The repos with
|
||
genuine call-site leakage are `billsplit` (16, all ad hoc `Colors.red`/
|
||
`teal`/`black54`), `epopeja_karta` (14, palette inlined in `app.dart`) and
|
||
`focus_owner` (8).
|
||
- **There are 4 `AppStatusColors`, not 5**, and they disagree about their own
|
||
shape: home_inventory and diet-guard have `success` + `warning`, habit_stack
|
||
has `success` only, wake-alarm has both; home_inventory and habit_stack ship
|
||
`light` *and* `dark` statics, the other two `dark` only. The package's
|
||
version is a superset (`success`/`warning`/`danger`/`info`/`onStatus`), so
|
||
every consumer can adopt it without losing a field.
|
||
- **There are 3 section headers, not 5**, and no `_SectionLabel` exists. Two
|
||
agreed on `titleMedium` and were reconciled into `SectionHeader`;
|
||
`epopeja_karta`'s is a *different element* — `labelSmall` + primary color +
|
||
letter-spacing, i.e. an eyebrow, not a section title. It was deliberately
|
||
not folded in.
|
||
|
||
## Deferred clusters
|
||
|
||
Actionable later; each line is repo + path + size, so none of this needs
|
||
rediscovering.
|
||
|
||
### Flutter — large reconciliations
|
||
|
||
| Cluster | Where | Size |
|
||
|---|---|---|
|
||
| `GitHubMirrorScreen` ×5 | todo, diet-guard, +3 | ~1551 lines, 586 differing between two copies |
|
||
| `SettingsScreen` ×6 | fleet-wide | — |
|
||
| List tiles | ~20 classes fleet-wide | — |
|
||
| Filter sheets | todo, dufs-cloud, +1 | **name collision, not duplicates** — dufs-cloud's uses no chips at all; judge structurally |
|
||
| Steppers, badges | fleet-wide | — |
|
||
|
||
The five `GitHubMirrorScreen` copies each carry a near-verbatim "kept
|
||
app-local rather than folded into `sync_settings_ui`" comment. That decision
|
||
deserves revisiting **on its own**, not smuggled into a component extraction.
|
||
|
||
### Shipped work
|
||
|
||
Palette drift, Phase 2 (Python/Tk) and Phase 3 (TypeScript) are all done. The
|
||
decisions behind them — including two deliberate exceptions that must not be
|
||
"corrected" back, and the remaining Flutter adopters — are in
|
||
[`shipped-record.md`](shipped-record.md).
|
||
|
||
## Standing risks
|
||
|
||
- **Version churn.** Each new tag needs a `pubspec.yaml` bump in every
|
||
consumer. `habit_stack` is already **7 minor versions stale** on `crdt_sync`
|
||
(v0.3.0 vs v0.10.0); the same drift will hit this package.
|
||
- **Reconciliation is judgement.** Where copies diverged, a "best-of" choice
|
||
can regress a consumer that depended on its local variant. Migrating proof
|
||
consumers first exists to surface that early.
|