From 3bc3fb1f90bf94096526cef97d691d8799a5c25b Mon Sep 17 00:00:00 2001 From: Parminder Klair Date: Thu, 13 Aug 2026 11:48:06 +0100 Subject: [PATCH] Fix the mini player's crushed layout, square its artwork, add a mini button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mini window's cover sleeve was a , which stretches to fill its row: it took 240x120 of a 420-wide row, leaving the metadata column 24px wide. The title rendered one letter per line and the artist text overflowed to 373px inside a 102px row. Swap it for a hugging explicitly-sized art, the way the LIVE stage's sleeve does, and give the metadata column min-width 0. The three metadata lines had no wrap/overflow rules, so the artist line still wrapped past the row once it had width. They elide now. That cost the title's bold weight and the artist/album ink-vs-muted split: both came from , and the SDK rejects wrap/overflow on a span paragraph because inline spans always word-wrap and the paragraph reserves the wrapped height. In a window fixed at 168pt, a deterministic single line beats the styling — size carries the hierarchy instead. The drag strip padded only its leading edge. Per the both-edges rule in CLAUDE.md the window-control cluster trails on Windows, so EXPAND needed the {chrome_trailing} spacer too; it is zero on macOS. Also, per review: - Artwork is , not — avatar renders a disc, and a record sleeve is square. Same has_cover / initials-tile fallback as the stage. - Sleeve padding and corner radius come down on both players (stage 12 -> 5, mini 6 -> 3, both radius -> sm) so the frame reads as a hairline. - New masthead button toggles mini mode, using a new app:mini picture-in-picture glyph; the builtin icon set has nothing for it. - The back panel's gear becomes panel-right: `settings` read as preferences-only, but the panel is SHOWS/TIMELINE/BOOTH/REQUEST as well, and it opens as a right-hand column. The masthead button makes the "shortcut is the only way into mini mode" comment in main.zig and the README's mini bullet stale; both updated. native test passes; both windows verified against the running app. --- README.md | 5 +++-- src/icons/mini.svg | 1 + src/main.zig | 7 ++++-- src/views/mini.native | 40 +++++++++++++++++++++++++++++------ src/views/player-stage.native | 2 +- src/views/player-top.native | 9 +++++++- 6 files changed, 51 insertions(+), 13 deletions(-) create mode 100644 src/icons/mini.svg diff --git a/README.md b/README.md index 8a2a08f..734e9c8 100644 --- a/README.md +++ b/README.md @@ -50,8 +50,9 @@ bottom.](docs/images/player-booth.png) optional signed name + status polling). - **Signal + sleep** — timed `/api/health` probe → latency readout while playing; sleep timer (15–90 min) from the tray or the back panel. -- **Mini player** — a compact secondary window (420×168) toggled from the tray - or Cmd/Ctrl+Shift+M. One player surface at a time: opening it minimizes the +- **Mini player** — a compact secondary window (420×168) toggled from the + masthead button, the tray, or Cmd/Ctrl+Shift+M. One player surface at a + time: opening it minimizes the full player, and EXPAND — or closing the mini window — brings the full player back. - **Menu-bar extra** — macOS `NSStatusItem` and the Windows tray (the GTK host diff --git a/src/icons/mini.svg b/src/icons/mini.svg new file mode 100644 index 0000000..1e57452 --- /dev/null +++ b/src/icons/mini.svg @@ -0,0 +1 @@ + diff --git a/src/main.zig b/src/main.zig index 32c1308..ca0d171 100644 --- a/src/main.zig +++ b/src/main.zig @@ -40,6 +40,7 @@ const disc_icon = canvas.svg_icon.parseComptime(@embedFile("icons/disc.svg")); const heart_icon = canvas.svg_icon.parseComptime(@embedFile("icons/heart.svg")); const heart_fill_icon = canvas.svg_icon.parseComptime(@embedFile("icons/heart-fill.svg")); const logo_icon = canvas.svg_icon.parseComptime(@embedFile("icons/logo.svg")); +const mini_icon = canvas.svg_icon.parseComptime(@embedFile("icons/mini.svg")); const power_icon = canvas.svg_icon.parseComptime(@embedFile("icons/power.svg")); const radio_icon = canvas.svg_icon.parseComptime(@embedFile("icons/radio.svg")); const spark_icon = canvas.svg_icon.parseComptime(@embedFile("icons/spark.svg")); @@ -49,6 +50,7 @@ pub const app_icons = [_]canvas.icons.Entry{ .{ .name = "heart", .icon = &heart_icon }, .{ .name = "heart-fill", .icon = &heart_fill_icon }, .{ .name = "logo", .icon = &logo_icon }, + .{ .name = "mini", .icon = &mini_icon }, .{ .name = "power", .icon = &power_icon }, .{ .name = "radio", .icon = &radio_icon }, .{ .name = "spark", .icon = &spark_icon }, @@ -59,8 +61,9 @@ pub const app_icons = [_]canvas.icons.Entry{ // (typing in the request/station fields is never stolen). Space = tune toggle, // arrows = volume, M = mute, cmd/ctrl+K = stations, cmd/ctrl+shift+M = mini // player (plain cmd+M is the macOS system minimize), Esc = back to LIVE, -// 1–5 = dial stops. The shortcut is also the only way into mini mode on -// Linux, where the GTK host has no tray to offer the menu item. +// 1–5 = dial stops. The masthead's mini button and the tray item reach mini +// mode too; on Linux the button and the shortcut are the only routes, since +// the GTK host has no tray to offer the menu item. fn onKey(keyboard: canvas.WidgetKeyboardEvent) ?Msg { if (keyboard.phase != .key_down) return null; const mods = keyboard.modifiers; diff --git a/src/views/mini.native b/src/views/mini.native index 42d384f..0699206 100644 --- a/src/views/mini.native +++ b/src/views/mini.native @@ -12,15 +12,41 @@ + + - - {initials} - - - {title} - {artist}{album_line} - {np_head} + + + + + + + + + + {initials} + + + + + + + + {title} + {artist}{album_line} + {np_head} diff --git a/src/views/player-stage.native b/src/views/player-stage.native index 1d16ebe..97acedf 100644 --- a/src/views/player-stage.native +++ b/src/views/player-stage.native @@ -8,7 +8,7 @@ - + +