breadman UI refresh #3

Closed
opened 2026-09-05 02:19:37 +08:00 by Breadway · 7 comments
Owner

breadman needs a UI overhaul before the release of BOS 0.6.2.

Rebuilt as a Tauri 2 + Svelte app (course change from the earlier native-GTK4 direction, decided with the reporter). The Rust core (breadpad-shared: storage, scheduler, parser, classifier) does not move; breadman/src/ is a thin #[tauri::command] layer over it. Design target: the mockup at https://claude.ai/code/artifact/f5330ab1-b681-40ae-9565-9a58d55f8d65

PR: #7

breadman needs a UI overhaul before the release of BOS 0.6.2. Rebuilt as a Tauri 2 + Svelte app (course change from the earlier native-GTK4 direction, decided with the reporter). The Rust core (breadpad-shared: storage, scheduler, parser, classifier) does not move; breadman/src/ is a thin #[tauri::command] layer over it. Design target: the mockup at https://claude.ai/code/artifact/f5330ab1-b681-40ae-9565-9a58d55f8d65 PR: https://git.breadway.dev/Breadway/breadpad/pulls/7
Author
Owner

Needs direction before implementation.

This is an open-ended UI redesign with no concrete spec, so I have not opened a branch. What I found in the repo:

  • breadman/src/main.rs (803 lines) builds the main window as a plain gtk4::ApplicationWindow + gtk4::Stack, hand-rolled, no libadwaita layout and no CSS file in the crate.
  • breadman/src/editor.rs already uses libadwaita (Dialog, HeaderBar, ToolbarView, PreferencesGroup, ActionRow/EntryRow), so the app is half-adwaita, half-bespoke.
  • Theming already goes through bread_theme::adw::init().
  • bos-settings is a Tauri/Svelte webview app, not GTK, so "in line with bos-settings" can only mean matching its visual language (ViewScaffold + Group + Row structure, the plain-CSS row design), not sharing code. Per prior notes, bos-settings deliberately avoids libadwaita PreferencesRow because those rows can't be width-constrained from outside.

Questions before this can be built:

  1. Which screens are in scope? The note list, the note editor, the settings view, all of them?
  2. "More in line with bos-settings" concretely: adopt a ViewScaffold-style header + scrollable content + grouped rows layout? A specific accent/spacing/typography from the bread design system?
  3. Is the target native GTK4 + a hand-written CSS sheet (mirroring bos-settings' plain-CSS rows), or a full libadwaita NavigationSplitView/PreferencesPage conversion?
  4. What is actually wrong with the current UI that the refresh must fix (density, navigation, inconsistency with the rest of BOS)? A screenshot or two of the pain points would pin this down.

Happy to take it as soon as there is a concrete target. Leaving in todo.

Needs direction before implementation. This is an open-ended UI redesign with no concrete spec, so I have not opened a branch. What I found in the repo: - `breadman/src/main.rs` (803 lines) builds the main window as a plain `gtk4::ApplicationWindow` + `gtk4::Stack`, hand-rolled, no libadwaita layout and no CSS file in the crate. - `breadman/src/editor.rs` already uses libadwaita (`Dialog`, `HeaderBar`, `ToolbarView`, `PreferencesGroup`, `ActionRow`/`EntryRow`), so the app is half-adwaita, half-bespoke. - Theming already goes through `bread_theme::adw::init()`. - bos-settings is a Tauri/Svelte webview app, not GTK, so "in line with bos-settings" can only mean matching its visual language (ViewScaffold + Group + Row structure, the plain-CSS row design), not sharing code. Per prior notes, bos-settings deliberately avoids libadwaita `PreferencesRow` because those rows can't be width-constrained from outside. Questions before this can be built: 1. Which screens are in scope? The note list, the note editor, the settings view, all of them? 2. "More in line with bos-settings" concretely: adopt a ViewScaffold-style header + scrollable content + grouped rows layout? A specific accent/spacing/typography from the bread design system? 3. Is the target native GTK4 + a hand-written CSS sheet (mirroring bos-settings' plain-CSS rows), or a full libadwaita `NavigationSplitView`/`PreferencesPage` conversion? 4. What is actually wrong with the current UI that the refresh must fix (density, navigation, inconsistency with the rest of BOS)? A screenshot or two of the pain points would pin this down. Happy to take it as soon as there is a concrete target. Leaving in todo.
Author
Owner

Direction (decided after reviewing the codebase + bos-settings + the bread design system):

Scope: a native GTK4 shell refresh of main.rs. Not a Tauri rewrite. A Tauri migration of breadman stays a separate future epic; it is out of scope for 0.6.2, and the GTK app has to keep working until that ships anyway, so this refresh is not throwaway. Three of the four surfaces (settings, note rows, editor) have already been brought in line with bos-settings incrementally; this finishes the pattern on the last un-refreshed surface.

In scope:

  1. Main window chrome: gtk4::ApplicationWindow -> adw::ApplicationWindow + an adw::NavigationSplitView (or OverlaySplitView) for the sidebar/content split, with adw::HeaderBars. Drop the raw Box + Separator sidebar layout.
  2. Sidebar: adw navigation-sidebar styling, keep the existing VIEWS / TYPES / MORE sections and the symbolic-icon rows that are already there.
  3. Per-view treatment: match bos-settings' tokens and family resemblance (Varela Round, 14/12px, 4px spacing scale, 8px card radius, group cards), not necessarily its literal ViewScaffold. The list views (All / Upcoming / per-type / Archive) are note inboxes, not settings forms - give them a light treatment: HeaderBar with the view name + search moved into the header (adw::HeaderBar toggle + adw::SearchBar), then the shared row.rs list. Reserve the full width-capped title+lede+grouped-content ViewScaffold layout for breadman's own Settings view (which settings.rs already approximates).
  4. Fold the bespoke show_add_note_window "New Note" gtk4::Window in main.rs into the same AdwDialog editor surface as editor.rs. The two currently teach different input languages for the same fields - this is a real bug already flagged in the code comments and is the highest-value piece of this ticket.

Out of scope / do not touch:

  • Do not re-architect AppState / rebuild_stack / the note-loading path. This is a chrome + dialog-unification pass, not a logic rewrite - that internal structure is exactly what a future Tauri port would discard, so keep investment there at zero.
  • Do not regress the plain-CSS rows to AdwPreferencesRow / AdwActionRow / AdwSpinRow. settings.rs deliberately avoids that family (they run tall and can't be width-constrained from outside); keep the established field-row design.

Must still work after the restructure:

  • --screenshot <view> mode (screenshot.rs) - it is used to generate docs/breadhelp imagery. Verify explicitly.
  • Theme live-reload via breadpad_shared::theme::apply_live() / bread_theme::adw::init().

Moving to doing.

Direction (decided after reviewing the codebase + bos-settings + the bread design system): **Scope: a native GTK4 shell refresh of `main.rs`. Not a Tauri rewrite.** A Tauri migration of breadman stays a separate future epic; it is out of scope for 0.6.2, and the GTK app has to keep working until that ships anyway, so this refresh is not throwaway. Three of the four surfaces (settings, note rows, editor) have already been brought in line with bos-settings incrementally; this finishes the pattern on the last un-refreshed surface. **In scope:** 1. Main window chrome: `gtk4::ApplicationWindow` -> `adw::ApplicationWindow` + an `adw::NavigationSplitView` (or `OverlaySplitView`) for the sidebar/content split, with `adw::HeaderBar`s. Drop the raw `Box` + `Separator` sidebar layout. 2. Sidebar: adw navigation-sidebar styling, keep the existing VIEWS / TYPES / MORE sections and the symbolic-icon rows that are already there. 3. Per-view treatment: match bos-settings' *tokens and family resemblance* (Varela Round, 14/12px, 4px spacing scale, 8px card radius, group cards), not necessarily its literal `ViewScaffold`. The list views (All / Upcoming / per-type / Archive) are note inboxes, not settings forms - give them a light treatment: HeaderBar with the view name + search moved into the header (`adw::HeaderBar` toggle + `adw::SearchBar`), then the shared `row.rs` list. Reserve the full width-capped title+lede+grouped-content `ViewScaffold` layout for breadman's own Settings view (which `settings.rs` already approximates). 4. Fold the bespoke `show_add_note_window` "New Note" `gtk4::Window` in `main.rs` into the same `AdwDialog` editor surface as `editor.rs`. The two currently teach different input languages for the same fields - this is a real bug already flagged in the code comments and is the highest-value piece of this ticket. **Out of scope / do not touch:** - Do not re-architect `AppState` / `rebuild_stack` / the note-loading path. This is a chrome + dialog-unification pass, not a logic rewrite - that internal structure is exactly what a future Tauri port would discard, so keep investment there at zero. - Do not regress the plain-CSS rows to `AdwPreferencesRow` / `AdwActionRow` / `AdwSpinRow`. `settings.rs` deliberately avoids that family (they run tall and can't be width-constrained from outside); keep the established `field-row` design. **Must still work after the restructure:** - `--screenshot <view>` mode (`screenshot.rs`) - it is used to generate docs/breadhelp imagery. Verify explicitly. - Theme live-reload via `breadpad_shared::theme::apply_live()` / `bread_theme::adw::init()`. Moving to doing.
Author
Owner

PR: #6

Done (direction point 4, the "highest-value piece"): New Note and Edit Note are now one surface. editor.rs gains a shared build_fields() used by open_editor and a new open_new_note; both render the same AdwDialog + AdwHeaderBar + AdwPreferencesGroup + chip type-picker. show_add_note_window in main.rs is now a thin wrapper (the bespoke gtk4::Window with plain entries is deleted, -250 lines). spawn_bg consolidated from 3 copies to 1. Create-time semantics (rule-based body parse, explicit type overrides parser, save_note + schedule) preserved.

Verified: cargo clippy --workspace --all-targets --locked -- -D warnings clean, cargo test --workspace all pass, breadman --screenshot {new-note,editor,all} all exit 0 against a live compositor (New Note dialog now visually matches the editor).

Deferred (direction points 1-3): the adw::ApplicationWindow + NavigationSplitView + header-search chrome conversion. Reason: there is no reference GTK NavigationSplitView implementation anywhere in the ecosystem (breadhelp, the only other adw app, is a plain gtk4::ApplicationWindow + stack + tab switcher; bos-settings is Tauri). A blind split-view conversion of the 200-line build_app_window needs iterative visual verification I can't do headless, and per the run's rules I shouldn't open a speculative PR for it. Recommend it be done by someone who can run the app and screenshot each state, or as a follow-up PR on this same key with before/after captures.

Moving to review for PR #6. If you'd rather the whole ticket land as one PR, bounce it back to todo and pair the chrome work with a live-run session.

PR: https://git.breadway.dev/Breadway/breadpad/pulls/6 **Done (direction point 4, the "highest-value piece"):** New Note and Edit Note are now one surface. `editor.rs` gains a shared `build_fields()` used by `open_editor` and a new `open_new_note`; both render the same `AdwDialog` + `AdwHeaderBar` + `AdwPreferencesGroup` + chip type-picker. `show_add_note_window` in `main.rs` is now a thin wrapper (the bespoke `gtk4::Window` with plain entries is deleted, -250 lines). `spawn_bg` consolidated from 3 copies to 1. Create-time semantics (rule-based body parse, explicit type overrides parser, `save_note` + schedule) preserved. Verified: `cargo clippy --workspace --all-targets --locked -- -D warnings` clean, `cargo test --workspace` all pass, `breadman --screenshot {new-note,editor,all}` all exit 0 against a live compositor (New Note dialog now visually matches the editor). **Deferred (direction points 1-3):** the `adw::ApplicationWindow` + `NavigationSplitView` + header-search chrome conversion. Reason: there is no reference GTK `NavigationSplitView` implementation anywhere in the ecosystem (breadhelp, the only other adw app, is a plain `gtk4::ApplicationWindow` + stack + tab switcher; bos-settings is Tauri). A blind split-view conversion of the 200-line `build_app_window` needs iterative visual verification I can't do headless, and per the run's rules I shouldn't open a speculative PR for it. Recommend it be done by someone who can run the app and screenshot each state, or as a follow-up PR on this same key with before/after captures. Moving to review for PR #6. If you'd rather the whole ticket land as one PR, bounce it back to todo and pair the chrome work with a live-run session.
Author
Owner

Decision on the deferred chrome pass (points 1-3): do it now, interactively, before BOS 0.6.2 - not split into its own ticket.

PAD-3 stays open (moved back to doing). PR #6 (the New Note / editor unification) is good work but should not be merged standalone - it lands as part of the complete refresh once the adw::ApplicationWindow + NavigationSplitView + header-search chrome is done in a session where the app can be launched and each view state screenshotted. Holding #6 until then.

Next step is a live-run session on feature/pad-3-unify-new-note-editor (or a branch stacked on it): convert build_app_window, iterate on the split-view / sidebar / header-search visually with before/after captures, then the single PR covers the whole ticket.

Decision on the deferred chrome pass (points 1-3): **do it now, interactively, before BOS 0.6.2 - not split into its own ticket.** PAD-3 stays open (moved back to doing). PR #6 (the New Note / editor unification) is good work but should **not** be merged standalone - it lands as part of the complete refresh once the `adw::ApplicationWindow` + `NavigationSplitView` + header-search chrome is done in a session where the app can be launched and each view state screenshotted. Holding #6 until then. Next step is a live-run session on `feature/pad-3-unify-new-note-editor` (or a branch stacked on it): convert `build_app_window`, iterate on the split-view / sidebar / header-search visually with before/after captures, then the single PR covers the whole ticket.
Author
Owner

Course change (decided with the reporter): PAD-3 becomes the Tauri 2 + Svelte rebuild, not the native GTK4 adw::ApplicationWindow + NavigationSplitView chrome pass described in the earlier direction comment. The Rust core (breadpad-shared: store, scheduler, parser, config, types) does not move; only the breadman binary's surface does, becoming a Tauri app with a Svelte frontend and a thin src-tauri command layer over breadpad-shared.

Consequence for the deferred GTK chrome work: dropped. PR #6 (feature/pad-3-unify-new-note-editor, the GTK AdwDialog New Note / editor unification) is GTK-specific and will be superseded by the Svelte editor; it should be closed rather than merged. The "one editor surface for New Note and Edit Note" requirement carries over to the Svelte implementation.

Visual target mockup: https://claude.ai/code/artifact/f5330ab1-b681-40ae-9565-9a58d55f8d65

It covers the main window (sidebar with VIEWS / TYPES / MORE, header search, the shared dense single-line row template), the unified editor dialog, the settings rows, the five-type accent system carried from sidebar dot to row chip, and the three-tier classification surface. Built on the Bread design system tokens (Varela Round, 14/12px, 4px spacing scale, 8px radius, fixed BOS dark base with pywal accent). Real breadman vocabulary and example notes throughout. That is the layout, density and colour target for the Svelte build.

Must still work after the rebuild: --screenshot <view> mode (used for docs/breadhelp imagery), theme live-reload from the pywal palette, and the existing notes.jsonl / archive.jsonl storage format unchanged.

Staying in doing. Building on feature/pad-3-tauri-svelte, iterated in a nested Wayland session.

Course change (decided with the reporter): **PAD-3 becomes the Tauri 2 + Svelte rebuild**, not the native GTK4 `adw::ApplicationWindow` + `NavigationSplitView` chrome pass described in the earlier direction comment. The Rust core (`breadpad-shared`: store, scheduler, parser, config, types) does not move; only the `breadman` binary's surface does, becoming a Tauri app with a Svelte frontend and a thin `src-tauri` command layer over `breadpad-shared`. Consequence for the deferred GTK chrome work: dropped. PR #6 (`feature/pad-3-unify-new-note-editor`, the GTK `AdwDialog` New Note / editor unification) is GTK-specific and will be superseded by the Svelte editor; it should be closed rather than merged. The "one editor surface for New Note and Edit Note" requirement carries over to the Svelte implementation. Visual target mockup: https://claude.ai/code/artifact/f5330ab1-b681-40ae-9565-9a58d55f8d65 It covers the main window (sidebar with VIEWS / TYPES / MORE, header search, the shared dense single-line row template), the unified editor dialog, the settings rows, the five-type accent system carried from sidebar dot to row chip, and the three-tier classification surface. Built on the Bread design system tokens (Varela Round, 14/12px, 4px spacing scale, 8px radius, fixed BOS dark base with pywal accent). Real breadman vocabulary and example notes throughout. That is the layout, density and colour target for the Svelte build. Must still work after the rebuild: `--screenshot <view>` mode (used for docs/breadhelp imagery), theme live-reload from the pywal palette, and the existing `notes.jsonl` / `archive.jsonl` storage format unchanged. Staying in doing. Building on `feature/pad-3-tauri-svelte`, iterated in a nested Wayland session.
Author
Owner

Built on feature/pad-3-tauri-svelte, PR #7 (#7). Moved to review.

Done:

  • Backend: lib.rs / state.rs / commands.rs / theme.rs. GTK main.rs / editor.rs / screenshot.rs / views/ removed; main.rs keeps the headless CLI (done <id>, upcoming --plain, --view <name>, plus --view editor).
  • Frontend breadman/ui/ (Svelte 5 + Vite): sidebar (VIEWS / TYPES / MORE + per-type accent dots), the shared dense single-line row across All / Upcoming / per-type / Archive, one editor modal for New note and Edit note with a live Tier-1 classification readout, width-capped Settings on plain token rows, Errors.
  • Theme bridge: live pywal palette to CSS custom properties via bread-theme, re-emitted on filesystem change (no restart).
  • build.rs builds ui/dist; ci/deps.txt adds webkit2gtk-4.1 + node + pnpm; release workflows build with --features breadman/custom-protocol; bakery.toml gains webkit2gtk-4.1.
  • Verified in a nested headless compositor: every view renders and functions (create / edit / done / delete / search / settings save / classify preview). cargo build --locked, cargo clippy -p breadman, svelte-check all clean.

Consequence for PR #6: the GTK AdwDialog editor unification is superseded by the Svelte editor. PR #6 should be closed rather than merged.

Open before this can land:

  • CI on the real self-hosted runner is unverified (container image rebuild with the new deps.txt, in-container pnpm install). First check.yml run on this branch is the test.
  • --screenshot <view> capture mode not ported (webview needs a compositor-side capture path); breadman --screenshot exits with a message for now. Affects the docs/breadhelp imagery pipeline.
  • Real-desktop check of font rendering (nested WebKitGTK fell back from Varela Round / IBM Plex Mono to a default sans; both are installed and wired through --font-family).
  • Placeholder app icons in breadman/icons/.
Built on `feature/pad-3-tauri-svelte`, PR #7 (https://git.breadway.dev/Breadway/breadpad/pulls/7). Moved to review. **Done:** - Backend: `lib.rs` / `state.rs` / `commands.rs` / `theme.rs`. GTK `main.rs` / `editor.rs` / `screenshot.rs` / `views/` removed; `main.rs` keeps the headless CLI (`done <id>`, `upcoming --plain`, `--view <name>`, plus `--view editor`). - Frontend `breadman/ui/` (Svelte 5 + Vite): sidebar (VIEWS / TYPES / MORE + per-type accent dots), the shared dense single-line row across All / Upcoming / per-type / Archive, one editor modal for New note and Edit note with a live Tier-1 classification readout, width-capped Settings on plain token rows, Errors. - Theme bridge: live pywal palette to CSS custom properties via `bread-theme`, re-emitted on filesystem change (no restart). - `build.rs` builds `ui/dist`; `ci/deps.txt` adds `webkit2gtk-4.1` + node + pnpm; release workflows build with `--features breadman/custom-protocol`; `bakery.toml` gains `webkit2gtk-4.1`. - Verified in a nested headless compositor: every view renders and functions (create / edit / done / delete / search / settings save / classify preview). `cargo build --locked`, `cargo clippy -p breadman`, `svelte-check` all clean. **Consequence for PR #6:** the GTK `AdwDialog` editor unification is superseded by the Svelte editor. PR #6 should be closed rather than merged. **Open before this can land:** - CI on the real self-hosted runner is unverified (container image rebuild with the new `deps.txt`, in-container `pnpm install`). First `check.yml` run on this branch is the test. - `--screenshot <view>` capture mode not ported (webview needs a compositor-side capture path); `breadman --screenshot` exits with a message for now. Affects the docs/breadhelp imagery pipeline. - Real-desktop check of font rendering (nested WebKitGTK fell back from Varela Round / IBM Plex Mono to a default sans; both are installed and wired through `--font-family`). - Placeholder app icons in `breadman/icons/`.
Author
Owner

Not merged: CI is red on PR #7 (check / check (push) failed after 13 seconds on commit 1b246f2, breadpad repo). That alone blocks a merge regardless of anything else. A 13-second failure this early is consistent with the CI image not yet having the new ci/deps.txt packages (webkit2gtk-4.1, libsoup3, nodejs, pnpm) built in; worth checking the actual job log before assuming the code itself is at fault.

Beyond CI, one acceptance-criteria gap worth flagging before this lands even once CI is green: the direction comment (id 154) explicitly listed "--screenshot mode (used for docs/breadhelp imagery)" as something that "must still work after the rebuild." The PR itself says this now "exits with a message" instead of capturing, i.e. it's a known regression against a stated must-still-work requirement, not just an unverified nice-to-have. The PR body is upfront about this and about the other open items (CI unverified on the real runner, WebKitGTK font fallback not confirmed on a real desktop, placeholder icons), so nothing here is hidden, but "must still work" was not optional in the direction comment.

Also worth noting for your own tracking, not something I'm acting on: PR #6 (feature/pad-3-unify-new-note-editor) is still open on this repo and is superseded by PR #7 per the issue's own comment 154 ("should be closed rather than merged"). I have not touched it; closing PRs isn't something I do, just flagging it's still sitting open.

Leaving PAD-3 in review rather than todo, since this is a CI-block, not a content verdict beyond the screenshot-mode gap noted above.

Not merged: CI is red on PR #7 (check / check (push) failed after 13 seconds on commit 1b246f2, breadpad repo). That alone blocks a merge regardless of anything else. A 13-second failure this early is consistent with the CI image not yet having the new ci/deps.txt packages (webkit2gtk-4.1, libsoup3, nodejs, pnpm) built in; worth checking the actual job log before assuming the code itself is at fault. Beyond CI, one acceptance-criteria gap worth flagging before this lands even once CI is green: the direction comment (id 154) explicitly listed "--screenshot mode (used for docs/breadhelp imagery)" as something that "must still work after the rebuild." The PR itself says this now "exits with a message" instead of capturing, i.e. it's a known regression against a stated must-still-work requirement, not just an unverified nice-to-have. The PR body is upfront about this and about the other open items (CI unverified on the real runner, WebKitGTK font fallback not confirmed on a real desktop, placeholder icons), so nothing here is hidden, but "must still work" was not optional in the direction comment. Also worth noting for your own tracking, not something I'm acting on: PR #6 (feature/pad-3-unify-new-note-editor) is still open on this repo and is superseded by PR #7 per the issue's own comment 154 ("should be closed rather than merged"). I have not touched it; closing PRs isn't something I do, just flagging it's still sitting open. Leaving PAD-3 in review rather than todo, since this is a CI-block, not a content verdict beyond the screenshot-mode gap noted above.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Breadway/breadpad#3
No description provided.