Skip to content

Feat/canvas preview overlay#66

Merged
u8array merged 4 commits into
mainfrom
feat/canvas-preview-overlay
May 15, 2026
Merged

Feat/canvas preview overlay#66
u8array merged 4 commits into
mainfrom
feat/canvas-preview-overlay

Conversation

@u8array
Copy link
Copy Markdown
Owner

@u8array u8array commented May 15, 2026

No description provided.

u8array added 4 commits May 15, 2026 10:24
Replaces the separate-window LabelPreviewModal with an in-canvas
overlay so the user can flip between the editor and the Labelary-
rendered output at the same scale, position and rotation as a true
1:1 comparison.

Store: `previewMode` is a state machine (idle, loading, active,
error) with `enterPreviewMode` (async; runs ZPL emit + Labelary
fetch) and `exitPreviewMode`. The fetched blob URL lives in the
active state and is revoked on exit. Persistence whitelist already
excludes `previewMode`, so reloading drops to idle.

Canvas: the rendered KImage swaps in for the editor leaves at the
same `labelOffset*` / `labelWidthPx`/`HeightPx` coordinates, which
means viewRotation and zoom apply naturally to both views. The
Transformer, lasso, guides, ghost-drop, rotation button and
visibleLeaves all skip when the overlay is on. Mouse handlers
(pan, lasso, stage click), keyboard handlers (delete, arrow keys,
all useGlobalShortcuts entries) and palette drop guard on
`selectPreviewLocksEditor` so the design cannot drift away from the
frozen snapshot under the user's hands. PaginationControl disables
its next/prev/delete for the same reason.

ZPLOutput: the existing "Preview" button is now a toggle. First-
press still flows through `LabelaryNoticeModal` for the privacy
acknowledgement; subsequent activations fetch directly. Error state
surfaces as an in-canvas amber banner with a close button (calls
`exitPreviewMode`).

Deletes `LabelPreview.tsx` — the modal had no remaining caller.
Swaps the label's default drop-shadow for a symmetric amber halo
while `previewMode` is locking the editor, so the mode signal sits
at the user's locus of attention (the paper) instead of only in the
toolbar button at the bottom of the screen. Replaces (not stacks
on) the existing shadow because layering an amber glow over the
dark drop-shadow reads as a passive theme drift rather than an
active mode change.

Amber matches the colour the app already uses for Labelary-related
warnings, so the colour language stays consistent. Glow is outward-
only with `shadowOffsetY: 0` so it does not bleed into the
preview image itself.
Two affordances for the editor-locked state introduced by the
preview overlay:

* Cursor shows `not-allowed` while `selectPreviewLocksEditor` holds.
  Signals the locked state at the user's locus of attention (the
  canvas) instead of leaving the toolbar button as the only state
  feedback, so an attempted edit no longer silent-fails.

* Escape key now exits the overlay. Bound globally so the user can
  return to the editor from anywhere; the existing useGlobalShortcuts
  guard already short-circuits other shortcut bindings while preview
  locks, so there is no collision.

Click-to-exit was deliberately not added — hidden affordance, risks
accidental exits, and removes the option to inspect the preview
without leaving the mode.
Until now the preview overlay's "freeze the editor" invariant was
enforced piecemeal at the UI surfaces: canvas mouse and keyboard
handlers, palette drop, useGlobalShortcuts and PaginationControl
each checked `selectPreviewLocksEditor` and short-circuited. The
gap: PropertiesPanel inputs, LayersPanel toggles, header undo/redo
and any future caller that goes straight to a store action could
still drift the design under the frozen Labelary snapshot.

Move the load-bearing guard to the store. Every design-mutating
action now checks the lock at entry; selection, view settings,
locale, theme and the preview controls themselves stay open. The
existing UI guards become defense-in-depth and keep their value for
the cursor / disabled-state UX they also provide.

Also wraps zundo's `useHistory` so undo and redo become no-ops while
locked — header buttons would otherwise rewind state without going
through the store mutator path.
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request replaces the previous modal-based Labelary preview with an integrated canvas overlay that locks the editor during active preview sessions. The implementation includes a new previewMode state in the store that prevents design mutations, disables keyboard shortcuts, and restricts pagination to ensure the preview remains in sync with the design. Visually, the canvas now displays a frozen Labelary snapshot with an amber glow and a "not-allowed" cursor to indicate the locked state. Review feedback focuses on optimizing the useHistory hook by memoizing its return value to maintain referential identity and avoid unnecessary re-renders while the editor is locked.

Comment thread src/store/labelStore.ts
Comment thread src/store/labelStore.ts
@u8array u8array merged commit 1f5faba into main May 15, 2026
2 checks passed
@u8array u8array deleted the feat/canvas-preview-overlay branch May 17, 2026 16:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant