From 733d123edc24377f701640a0ee7dfe937300062b Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Thu, 28 May 2026 08:59:40 -0400 Subject: [PATCH] Top-right action strip: pin undo/redo + canvas-size readouts under Nostr widget MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The undo/redo pair and the trim/sheet canvas-size pills lived inside .topbar's flex row, which wraps at narrow widths. Adam wanted them in a permanent, predictable place so muscle memory works regardless of editor mode or sidebar state. Changes: - .status is now `position: fixed; top: var(--top-strip-height); right: 0; flex-wrap: nowrap` with the same panel/border styling as the Nostr widget — a second strip directly below it. - Reordered the markup so the canvas-size pills come first and the undo/redo group last, so undo/redo end up hugging the viewport edge and the pills sit to their left (matching the requested layout). - Dropped the `body.app-designer .status` override (full-width left-aligned), since the new positioning is universal across modes. - updateNostrWidgetSpace() now measures the wider of the Nostr widget or the new strip and reserves topbar right padding accordingly, so the project title can't slide under the strip. Verified via CDP at 1440px (cover, customart, pixelart modes) and at 900px narrow — strip stays pinned top-right with undo/redo on the outside edge in every case. Co-Authored-By: Claude Opus 4.7 --- TODO.md | 17 +++++++++++++++-- src/index.html | 40 +++++++++++++++++++++++++++++----------- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/TODO.md b/TODO.md index 20fd090..0e0fabd 100644 --- a/TODO.md +++ b/TODO.md @@ -5,8 +5,12 @@ Running list of deferred work. Detailed specs for the larger items live in ## Adam's working list -_(Empty — see "Shipped (recent)" below for the items that just -landed. Drop new items in here as they come up.)_ +- **Pixel canvas size dropdown — fix sidebar clipping.** When the + sidebar is open and the canvas size row wraps to a second line on + the left, the pixel-art canvas-size dropdown is clipped by the + sidebar. Easiest fix is probably "always right-align when wrapped" + so the dropdown opens away from the sidebar; or move the dropdown + to a placement that can't collide with the sidebar. ## QR code layer — remaining phases @@ -84,6 +88,15 @@ Each has a full spec in `docs/`. ## Shipped (recent) +- **Top-right action strip — permanent, never wraps.** Pulled the + canvas-size readouts and the undo / redo pair out of the topbar's + flex flow and pinned them in a fixed strip directly under the Nostr + widget, right-anchored, with `flex-wrap: nowrap`. Order: canvas-size + pills on the left, undo / redo on the right (so undo / redo hug the + viewport edge). The topbar's right padding now tracks the wider of + the Nostr widget or the strip via the existing + `--nostr-widget-space` var, so the project title never slides under + it. - **Click canvas background → deselect.** The existing #sheet click handler missed clicks in the gutter between sheet edge and previewShell edge; added a #previewShell handler. diff --git a/src/index.html b/src/index.html index bb898c1..082ee32 100644 --- a/src/index.html +++ b/src/index.html @@ -992,20 +992,30 @@ padding: 22px var(--nostr-widget-space, 210px) 14px 26px; } + /* Permanent top-right action strip — pinned directly under the Nostr + widget so the undo/redo controls and the canvas-size readouts always + live in the same place regardless of editor mode, sidebar state, or + window width. Never wraps. */ .status { + position: fixed; + top: var(--top-strip-height, 34px); + right: 0; + z-index: 90; display: flex; flex-wrap: nowrap; - gap: 10px; + gap: 8px; align-items: center; color: var(--muted); font-size: .86rem; min-width: 0; + background: var(--panel); + border-left: 1px solid var(--line); + border-bottom: 1px solid var(--line); + padding: 4px 10px 4px 14px; + box-sizing: border-box; } - - body.app-designer .status { - flex-basis: 100%; - justify-content: flex-start; - } + body.dark .status { color: var(--muted); } + @media print { .status { display: none !important; } } .pill { border: 1px solid var(--line); @@ -3517,12 +3527,12 @@

Left-to-right layout is back cover, spine, front cover.

+ +
- -
@@ -18350,10 +18360,16 @@ } function updateNostrWidgetSpace() { + // Reserve right-edge padding on the topbar for whichever fixed strip + // is wider: the Nostr widget itself, or the action strip below it + // (canvas-size pills + undo/redo). Without this, a narrow topbar + // would let the project title slide under the action strip. const widget = $('nostrWidget'); - if (!widget) return; - const rect = widget.getBoundingClientRect(); - const space = Math.ceil(rect.width || 0) + 18; + const statusStrip = document.querySelector('.topbar > .status'); + let widest = 0; + if (widget) widest = Math.max(widest, widget.getBoundingClientRect().width || 0); + if (statusStrip) widest = Math.max(widest, statusStrip.getBoundingClientRect().width || 0); + const space = Math.ceil(widest) + 18; document.documentElement.style.setProperty('--nostr-widget-space', `${space}px`); } @@ -18364,6 +18380,8 @@ if (typeof ResizeObserver === 'function') { const observer = new ResizeObserver(updateNostrWidgetSpace); observer.observe(widget); + const statusStrip = document.querySelector('.topbar > .status'); + if (statusStrip) observer.observe(statusStrip); } window.addEventListener('resize', updateNostrWidgetSpace); }