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); }