Spotlight phase 1: auto-hiding pill with workspace modes and widget slots #27

Closed
opened 2026-09-26 13:34:56 +08:00 by Breadway · 9 comments
Owner

Phase 1 of BAR-26. Implement the spotlight pill to match the approved mockup (https://claude.ai/artifact/49uF81wgNZi9pqDFoA2Xif).

Scope:

  • Pill: floating top-centre, 30px tall, fully rounded, no exclusive zone. Contents in order: workspaces, divider, left widget slot, time (display face), right widget slot, low-battery flag, unread dot.
  • Workspaces display option: none / current (just the active number) / all (occupied plus active, numbered, active lit, clickable), configured from the theme.
  • Widget slots either side of the time (widget:left_of_clock / widget:right_of_clock); empty slots collapse, widgets on/off.
  • Auto-hide option: tucked above the top edge with a small lip; drops on top-middle hover (hot zone), Super+Space / a toggle command, a new notification, a volume/brightness change, a workspace switch; re-tucks about 0.6s after the pointer leaves; stays down while the battery is low. Auto-hide off means always visible.
  • Palette and type from the mockup mapped to palette tokens (no raw hex).

Verification: screenshots from bread-capture's isolated compositor (or a nested session), never the live desktop. States: tucked, shown, widgets on/off, each workspace mode.

Out of scope: the stage, results, surtitles and in-pill levels (later phases).

Phase 1 of BAR-26. Implement the spotlight pill to match the approved mockup (https://claude.ai/artifact/49uF81wgNZi9pqDFoA2Xif). Scope: - Pill: floating top-centre, 30px tall, fully rounded, no exclusive zone. Contents in order: workspaces, divider, left widget slot, time (display face), right widget slot, low-battery flag, unread dot. - Workspaces display option: none / current (just the active number) / all (occupied plus active, numbered, active lit, clickable), configured from the theme. - Widget slots either side of the time (widget:left_of_clock / widget:right_of_clock); empty slots collapse, widgets on/off. - Auto-hide option: tucked above the top edge with a small lip; drops on top-middle hover (hot zone), Super+Space / a toggle command, a new notification, a volume/brightness change, a workspace switch; re-tucks about 0.6s after the pointer leaves; stays down while the battery is low. Auto-hide off means always visible. - Palette and type from the mockup mapped to palette tokens (no raw hex). Verification: screenshots from bread-capture's isolated compositor (or a nested session), never the live desktop. States: tucked, shown, widgets on/off, each workspace mode. Out of scope: the stage, results, surtitles and in-pill levels (later phases).
Author
Owner

Progress: bread-theme schema landed on feature/spotlight-pill (bread-ecosystem worktree, commit 25be473).

Added modules.workspaces.display (none/current/all, defaults to all so every other theme is unaffected), a bar.autohide table (off by default, on for spotlight with the mockup's own timings: 420x14 hot zone, 600ms retuck, 3800/1400/1200ms peeks), and sep/flag/unread as new builtin bar modules. Rewrote spotlight/theme.toml as a 30px fully rounded, content-hugging, top-anchored pill with no exclusive zone, one flat slot row (workspaces, sep, widget:left_of_clock, clock, widget:right_of_clock, flag, unread), pill style workspaces, and plain clock. Appended pill CSS primitives to the shared base.css template (confirmed inert/dead CSS for the other 4 builtins via re-blessed golden snapshots).

cargo test -p bread-theme: 119 passed. cargo clippy: clean. Old spotlight tests describing the previous capsule-launcher design were rewritten to match the new pill.

Next: breadbar side (pill widget assembly, workspace display filter, auto-hide state machine, hot-zone/lip surface, CLI toggle, screenshots).

Progress: bread-theme schema landed on feature/spotlight-pill (bread-ecosystem worktree, commit 25be473). Added modules.workspaces.display (none/current/all, defaults to all so every other theme is unaffected), a bar.autohide table (off by default, on for spotlight with the mockup's own timings: 420x14 hot zone, 600ms retuck, 3800/1400/1200ms peeks), and sep/flag/unread as new builtin bar modules. Rewrote spotlight/theme.toml as a 30px fully rounded, content-hugging, top-anchored pill with no exclusive zone, one flat slot row (workspaces, sep, widget:left_of_clock, clock, widget:right_of_clock, flag, unread), pill style workspaces, and plain clock. Appended pill CSS primitives to the shared base.css template (confirmed inert/dead CSS for the other 4 builtins via re-blessed golden snapshots). cargo test -p bread-theme: 119 passed. cargo clippy: clean. Old spotlight tests describing the previous capsule-launcher design were rewritten to match the new pill. Next: breadbar side (pill widget assembly, workspace display filter, auto-hide state machine, hot-zone/lip surface, CLI toggle, screenshots).
Author
Owner

Progress: pill rendering and auto-hide landed on feature/spotlight-pill (breadbar worktree, commit a3f94a0).

Renders the pill per the mockup: workspaces, a collapsing divider, widget:left_of_clock/right_of_clock slots, the plain clock, a low-battery flag, and an unread dot, all as regular bar modules the existing [bar.slots] system places. Workspace display (none/current/all) is a pure, unit-tested filter layered on top of the existing style/show_empty logic. Auto-hide is a pure, unit-tested decision function driving a layer-shell margin spring animation, with a separate hot-zone/lip satellite window for hover-while-tucked. Peeks wired from notifications, volume/brightness OSD events, and workspace switches; low battery keeps it down. Added breadbar --pill toggle|show over the existing dev.breadway.Bar D-Bus surface.

cargo test: 64 passed (14 new). cargo clippy: clean. cargo fmt: no new diffs versus baseline (repo already has pre-existing drift elsewhere).

Next: bread-capture screenshot views, visual verification, and final report.

Progress: pill rendering and auto-hide landed on feature/spotlight-pill (breadbar worktree, commit a3f94a0). Renders the pill per the mockup: workspaces, a collapsing divider, widget:left_of_clock/right_of_clock slots, the plain clock, a low-battery flag, and an unread dot, all as regular bar modules the existing [bar.slots] system places. Workspace display (none/current/all) is a pure, unit-tested filter layered on top of the existing style/show_empty logic. Auto-hide is a pure, unit-tested decision function driving a layer-shell margin spring animation, with a separate hot-zone/lip satellite window for hover-while-tucked. Peeks wired from notifications, volume/brightness OSD events, and workspace switches; low battery keeps it down. Added breadbar --pill toggle|show over the existing dev.breadway.Bar D-Bus surface. cargo test: 64 passed (14 new). cargo clippy: clean. cargo fmt: no new diffs versus baseline (repo already has pre-existing drift elsewhere). Next: bread-capture screenshot views, visual verification, and final report.
Author
Owner

Phase 1 complete on feature/spotlight-pill in both worktrees (breadbar 4ce67a3, bread-ecosystem 829f405).

Screenshots taken via bread-capture's isolated Sway session for all required states: pill shown/tucked/hover, widgets on/off, all three workspace display modes, and low battery. Two capture-only bugs found and fixed along the way: the hot-zone/lip satellite window needed an explicit transparent background (it painted as an opaque black bar over the whole hot-zone footprint), and three of the mocked screenshot states (widgets-on, low-battery, workspace modes) were racing real data sources reachable from the isolated session (a real bread daemon, a real battery, Hyprland IPC absence) that clobbered the forced capture state; each now skips starting its one real source for its own view.

Final: cargo test/clippy/fmt clean in both repos (bread-theme 119 tests, breadbar 64 tests, no new fmt diffs versus baseline). Full report going to the user now. Leaving this in doing per instructions.

Phase 1 complete on feature/spotlight-pill in both worktrees (breadbar 4ce67a3, bread-ecosystem 829f405). Screenshots taken via bread-capture's isolated Sway session for all required states: pill shown/tucked/hover, widgets on/off, all three workspace display modes, and low battery. Two capture-only bugs found and fixed along the way: the hot-zone/lip satellite window needed an explicit transparent background (it painted as an opaque black bar over the whole hot-zone footprint), and three of the mocked screenshot states (widgets-on, low-battery, workspace modes) were racing real data sources reachable from the isolated session (a real bread daemon, a real battery, Hyprland IPC absence) that clobbered the forced capture state; each now skips starting its one real source for its own view. Final: cargo test/clippy/fmt clean in both repos (bread-theme 119 tests, breadbar 64 tests, no new fmt diffs versus baseline). Full report going to the user now. Leaving this in doing per instructions.
Author
Owner

Review of phase 1 (breadbar feature/spotlight-pill after b51845d, bread-ecosystem feature/spotlight-pill after 5b0626b).

Verdict: PASS, with fixes applied. The architecture holds up (pure auto-hide decision function, generation-debounced hover, the peek hold is extend-only, animations are cancelled before a new one starts, all new options default to off/All so the other four themes are untouched). Tests: bread-theme 119 passed, breadbar 64 passed, clippy clean. I re-captured every pill-* view plus glass-workbench and liquid-motion bar in bread-capture's isolated sway.

Blocking issues found and fixed:

  1. The pill did not hug its content. The bar row is a GtkCenterBox, whose natural width is centre + 2 * max(left, right). With the whole row in the LEFT slot the pill measured twice its content and drew the content in its left half, with dead space on the right, in every capture. Fixed by moving the row to the centre slot (bread-ecosystem aa26d23; also corrects a comment about a .pill-item rule that does not exist).
  2. needs_restart ignored [bar.autohide]. autohide_cfg and the hot-zone window are init-only, so a live reload that only changed that table did nothing. Fixed (breadbar 6569c40).
  3. A live theme reload while tucked dropped the pill back into view: apply_window_spec resets the top margin, pill_shown stayed false, and pill_margin went stale. Fixed by snapping to the shown/tucked margin after apply_window_spec, via a shared pill_margins helper (breadbar 5877782).
  4. The flag and unread dots drew as tall capsules because they had no valign. The divider also started visible before any workspace sync. Both fixed (breadbar 55ff646).
  5. Under display = "none" the empty workspace module kept 12px of box spacing, so the clock sat off-centre. The module is now hidden in that mode only (breadbar d1b30fa).

Non-blocking, for later:

  • The hot zone (420x14, Layer::Top) catches input for its whole footprint, including while the pill is shown, so clicks in that strip never reach windows underneath. That is inherent to the mockup's design. Consider a thinner input region (2 to 4px) while tucked, and an empty input region while shown.
  • Colours: the active workspace chip and the WS number use @accent (a pywal hue), where the mockup uses warm-white --light. The unread dot is @yellow where the mockup uses brass. The flag has no glow. The pill has no hover shade.
  • Spacing: items are 12px apart (the centre container's spacing) against the mockup's 10px, and the flag/unread get a further 10px chip_gap margin on top of that.
  • The on_show/on_change peek callbacks are passed for every theme, not only when autohide is enabled as the doc comments say. This is harmless because update_pill returns early, but each call still schedules a timer.
  • Super+Space is not bound anywhere yet. Only breadbar --pill toggle|show exists, so a Hyprland bind is needed in BOS.
  • Known deviations accepted: peeks only reach the primary monitor, the WS label is a real label, the lip toggles visibility instead of fading.
Review of phase 1 (breadbar feature/spotlight-pill after b51845d, bread-ecosystem feature/spotlight-pill after 5b0626b). Verdict: PASS, with fixes applied. The architecture holds up (pure auto-hide decision function, generation-debounced hover, the peek hold is extend-only, animations are cancelled before a new one starts, all new options default to off/All so the other four themes are untouched). Tests: bread-theme 119 passed, breadbar 64 passed, clippy clean. I re-captured every pill-* view plus glass-workbench and liquid-motion `bar` in bread-capture's isolated sway. Blocking issues found and fixed: 1. The pill did not hug its content. The bar row is a GtkCenterBox, whose natural width is centre + 2 * max(left, right). With the whole row in the LEFT slot the pill measured twice its content and drew the content in its left half, with dead space on the right, in every capture. Fixed by moving the row to the centre slot (bread-ecosystem aa26d23; also corrects a comment about a .pill-item rule that does not exist). 2. needs_restart ignored [bar.autohide]. autohide_cfg and the hot-zone window are init-only, so a live reload that only changed that table did nothing. Fixed (breadbar 6569c40). 3. A live theme reload while tucked dropped the pill back into view: apply_window_spec resets the top margin, pill_shown stayed false, and pill_margin went stale. Fixed by snapping to the shown/tucked margin after apply_window_spec, via a shared pill_margins helper (breadbar 5877782). 4. The flag and unread dots drew as tall capsules because they had no valign. The divider also started visible before any workspace sync. Both fixed (breadbar 55ff646). 5. Under display = "none" the empty workspace module kept 12px of box spacing, so the clock sat off-centre. The module is now hidden in that mode only (breadbar d1b30fa). Non-blocking, for later: - The hot zone (420x14, Layer::Top) catches input for its whole footprint, including while the pill is shown, so clicks in that strip never reach windows underneath. That is inherent to the mockup's design. Consider a thinner input region (2 to 4px) while tucked, and an empty input region while shown. - Colours: the active workspace chip and the WS number use @accent (a pywal hue), where the mockup uses warm-white --light. The unread dot is @yellow where the mockup uses brass. The flag has no glow. The pill has no hover shade. - Spacing: items are 12px apart (the centre container's spacing) against the mockup's 10px, and the flag/unread get a further 10px chip_gap margin on top of that. - The on_show/on_change peek callbacks are passed for every theme, not only when autohide is enabled as the doc comments say. This is harmless because update_pill returns early, but each call still schedules a timer. - Super+Space is not bound anywhere yet. Only `breadbar --pill toggle|show` exists, so a Hyprland bind is needed in BOS. - Known deviations accepted: peeks only reach the primary monitor, the WS label is a real label, the lip toggles visibility instead of fading.
Author
Owner

No Forgejo PR or remote work branch is available for review. The issue comments point to local-only feature/spotlight-pill worktrees (breadbar fc078d4, bread-ecosystem b249b33), both ahead of origin/main, but neither branch exists on Forgejo and there is no open PR. I cannot publish or push a branch as reviewer. Please publish the existing branch(es) and link the PRs; leaving BAR-27 in review.

No Forgejo PR or remote work branch is available for review. The issue comments point to local-only `feature/spotlight-pill` worktrees (breadbar `fc078d4`, bread-ecosystem `b249b33`), both ahead of `origin/main`, but neither branch exists on Forgejo and there is no open PR. I cannot publish or push a branch as reviewer. Please publish the existing branch(es) and link the PRs; leaving BAR-27 in review.
Author
Owner

Dependency PR: Breadway/bread-ecosystem#45 adds the bread-theme schema, styles, and bread-capture changes required by this spotlight work. Merge it before the breadbar PR, which will follow on feature/spotlight-pill. Headless Sway captures passed for pill shown/tucked, stage idle/results, critical surtitle, and in-pill levels.

Dependency PR: https://git.breadway.dev/Breadway/bread-ecosystem/pulls/45 adds the bread-theme schema, styles, and bread-capture changes required by this spotlight work. Merge it before the breadbar PR, which will follow on feature/spotlight-pill. Headless Sway captures passed for pill shown/tucked, stage idle/results, critical surtitle, and in-pill levels.
Author
Owner

Breadbar implementation PR: #37. Dependency: merge bread-ecosystem PR #45 first, which provides the theme API and CSS. Headless Sway smoke captures passed for the shown/tucked pill, stage idle/results, critical surtitle, and in-pill level.

Breadbar implementation PR: https://git.breadway.dev/Breadway/breadbar/pulls/37. Dependency: merge bread-ecosystem PR #45 first, which provides the theme API and CSS. Headless Sway smoke captures passed for the shown/tucked pill, stage idle/results, critical surtitle, and in-pill level.
Author
Owner

PR #37 check / check (push) is currently failing. The implementation depends on bread-ecosystem PR #45, which has passed CI but is not merged yet. I am moving this card to TODO as requested for REVIEW items with failing CI. Recheck the breadbar CI after #45 merges; then send it back through review.

PR #37 check / check (push) is currently failing. The implementation depends on bread-ecosystem PR #45, which has passed CI but is not merged yet. I am moving this card to TODO as requested for REVIEW items with failing CI. Recheck the breadbar CI after #45 merges; then send it back through review.
Author
Owner

PR #37 now passes fresh check / check (push) on 0fd9f05 (5m17s). The merged bread-ecosystem #45 dependency is resolved through the existing PR-check scripts/dev-deps.sh workflow, which records bread-ecosystem d9ab179 in the generated dev-deps lock; Cargo.toml and the committed release-tag Cargo.lock remain unchanged. Local clippy, build, and all 120 tests pass against that same dependency commit. Ready for independent review: #37

PR #37 now passes fresh `check / check (push)` on 0fd9f05 (5m17s). The merged bread-ecosystem #45 dependency is resolved through the existing PR-check `scripts/dev-deps.sh` workflow, which records bread-ecosystem d9ab179 in the generated dev-deps lock; Cargo.toml and the committed release-tag Cargo.lock remain unchanged. Local clippy, build, and all 120 tests pass against that same dependency commit. Ready for independent review: https://git.breadway.dev/Breadway/breadbar/pulls/37
Sign in to join this conversation.
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/breadbar#27
No description provided.