Skip to content

feat(platform): unify canvas file viewers under one action card#2135

Merged
Israeltheminer merged 4 commits into
mainfrom
feat/canvas-viewer-unification
Jun 25, 2026
Merged

feat(platform): unify canvas file viewers under one action card#2135
Israeltheminer merged 4 commits into
mainfrom
feat/canvas-viewer-unification

Conversation

@Israeltheminer

Copy link
Copy Markdown
Collaborator

What & why

Unifies every canvas file viewer — code, markdown, html, svg, mermaid, image — around one shared control surface, replacing the inconsistent chrome (the code viewer used a full-width top strip; renderables used a floating card).

  • CanvasViewerFrame — hoists the floating bottom-right action card, the pb-14 content gutter, and the size label into one shell; each viewer passes its own buttons as actions.
  • CanvasPreferencesProvider — line-wrap and the per-file Source/Preview choice now live above the viewers, so they survive switching files and viewer kinds (previously a remount reset them and shifted the layout).
  • CodeViewer becomes a pure content renderer (no chrome); a new CodeFileViewer wraps it with the shared card.
  • download.ts — shared downloadTextFile / downloadUrlFile helpers replace the duplicated inline blob-download logic; per-viewer download replaces the canvas header button.
  • preloadHighlighter() (@tale/ui) — warmed on canvas mount so the first code file highlights without the lazy shiki cold-start flash.

Commits: feat(ui): add preloadHighlighter + feat(platform): unify canvas file viewers under one action card.

Verification

  • typecheck + lint (platform + ui) green against latest main
  • lint:sast (Opengrep) — 0 findings in changed files
  • ✅ i18n parity + usage enforce checks green
  • ✅ unit/component suites green — the docs deploy-sim and pii tokenizer failures seen during bun run check are pre-existing flakes under concurrent CPU load (both pass in isolation; neither file is touched here)
  • ⚠️ Authenticated in-browser walkthrough not run locally (no dev credential on the running instance); relying on CI e2e + reviewer check

Definition of Done

  • Translations — all base locales — en/de/fr: added canvas.copy / copied / toggleWrap / fileActionsAriaLabel, removed the now-unused canvas.viewToggleAriaLabel. de-CH falls back to de (no ß / Swiss-specific divergence).
  • Accessibility — action buttons carry title/aria-label; the frame is role="group" labelled by canvas.fileActionsAriaLabel; the size label keeps canvas.fileSizeAriaLabel.
  • Tests — typecheck + existing test:ui green; this is a refactor that preserves the behaviour of already-covered viewers. No new e2e spec (no new user-facing behaviour; CI e2e covers the canvas).
  • Docs — N/A (canvas viewer internals; no user-visible/config/API surface).
  • Migrations — N/A (no data-model change).
  • Storybook — N/A (feature components under services/platform, not packages/ui primitives).
  • Instructions — N/A (no documented path/command/pattern changed).

Israeltheminer and others added 4 commits June 24, 2026 23:42
The highlighter (engine + themes + eager grammars) inits lazily on the
first highlightCode call, so the first code file a surface opens flashes
un-highlighted while the dynamic imports resolve. Expose a
fire-and-forget preloadHighlighter() that warms the cached singleton
ahead of first use; idempotent and safe to call on mount.

Translations: N/A (no user-facing strings)
Docs: N/A | Migrations: N/A | a11y: N/A | Storybook: N/A
Tests: covered by existing shiki usage + typecheck
Hoist the floating bottom-right action card out of renderable-file-viewer
into a shared CanvasViewerFrame, so the code/markdown/html/svg/mermaid/
image viewers all present one identical control surface (the code viewer
previously used a full-width top strip). Wrap and the per-file Source/
Preview choice move into a CanvasPreferencesProvider mounted above the
viewers, so they survive switching files and viewer kinds. CodeViewer
becomes a pure content renderer; a new CodeFileViewer wraps it with the
shared card. Per-viewer download (shared download.ts helpers) replaces the
canvas header download button. Shiki is preloaded on canvas mount so the
first file highlights without the lazy cold-start.

Translations: en/de/fr - added canvas.copy/copied/toggleWrap/
fileActionsAriaLabel; removed the now-unused viewToggleAriaLabel
Docs: N/A (no user-facing docs for canvas internals)
Migrations: N/A (no data-model change)
a11y: action buttons carry title/aria-label; frame is role="group" with
canvas.fileActionsAriaLabel; size keeps canvas.fileSizeAriaLabel
Storybook: N/A (feature components, not ui primitives)
Tests: typecheck + existing platform test:ui green; refactor preserves
already-covered viewer behavior
Pre-existing oxfmt breakage on main (merged via #2122) that fails the
repo-wide Format CI check; unrelated to this PR but blocks its gate.
Pure formatting, no content change.
@Israeltheminer Israeltheminer merged commit 9dcd0b7 into main Jun 25, 2026
31 checks passed
@Israeltheminer Israeltheminer deleted the feat/canvas-viewer-unification branch June 25, 2026 08:01
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