Skip to content

feat(viewer): compact top bar, unified status strip, single-master icon pipeline#255

Merged
korbinian90 merged 3 commits into
mainfrom
claude/distracted-pike-0b6fb5
Jun 20, 2026
Merged

feat(viewer): compact top bar, unified status strip, single-master icon pipeline#255
korbinian90 merged 3 commits into
mainfrom
claude/distracted-pike-0b6fb5

Conversation

@korbinian90

Copy link
Copy Markdown
Collaborator

Summary

Two related improvements to the viewer chrome, plus the icon-pipeline modernization that motivated them. Addresses the VS Code feedback that the top bar took too much vertical space and the file-type / viewer icons were still on the old scheme.

Top bar and layout

  • Compact VS Code top bar. The .nv-form-vscode density tokens existed in tokens.css but were never applied, so the webview was stuck on the airy 48px :root value. This wires the class onto the webview root, dropping the bar to 36px. The 26px brand mark is unchanged; only the empty space above and below it shrinks.
  • One status strip. A new shared StatusBar (packages/niivue-react) merges the image-metadata line (matrix/voxel size, formerly under the bar) and the crosshair mm readout (formerly a standalone footer) into one slim bottom strip. Used by the VS Code, PWA, desktop, and Streamlit hosts; each keeps its existing hideUI gating.
  • Scrollbar fix. The canvas grid sized itself off window.onresize only, so a menu-bar reflow (overflow into "More", the status strip toggling) changed the available height with no resize event and left a stale, oversized canvas with scrollbars on both axes. It now observes its container with a ResizeObserver, and the container is flex-1 min-h-0 instead of flex-grow h-full.

Icons (one committed master, generate the rest)

  • Every app icon now derives from a single committed master, branding/niivue-icon.png, via scripts/generate-icons.mjs (pnpm generate:icons). The file-type icons (VS Code Explorer/tab, Jupyter) and the in-app viewer logo become a transparent neon mark (luminance-keyed, so the glow falls off cleanly); the marketplace and PWA icons stay opaque on the dark tile. Outputs are palette-quantized for size (the PWA logo.png dropped 265KB to 118KB).
  • Generated binaries are gitignored and rebuilt by each app's build (each regenerates only its own icons, so parallel turbo build does not race). Tauri's multi-format .icns/.ico are produced by the Tauri CLI in beforeBuildCommand.
  • The one committed generated file is niivue-logo.ts (imported from @niivue/react source, so gitignoring it would break tsc/vitest ordering). It is marked linguist-generated and stamps the master's sha256; CI fails if the master changes without pnpm generate:icons. That is a content check, not a byte-compare of the palette PNG, which is not reproducible across platforms.

Testing

  • @niivue/react type-check + lint clean; 142/142 unit tests pass.
  • pwa / vscode / tauri / streamlit type-check + lint clean.
  • Verified end-to-end by deleting the icons and running pnpm --filter niivue build and pnpm --filter @niivue/pwa build: both regenerate their icons from the master and compile (the PWA also regenerates all favicons / apple-touch / maskable via pwa-assets).
  • pnpm install --frozen-lockfile clean.

Notes for the reviewer

  • I could not run the Tauri (tauri build, needs Rust) or Jupyter (needs JupyterLab + Python) bundle builds locally. Their icon wiring follows the standard hook points (beforeBuildCommand, build:assets); please confirm a desktop bundle and a jupyter build on a machine with those toolchains.
  • Tauri dev is intentionally left without icon regeneration (it would re-run tauri icon on every start); run pnpm generate:icons:tauri once after a fresh clone if the dev window wants its icon.

🤖 Generated with Claude Code

Top bar + layout:
- Apply the dormant .nv-form-vscode density tokens to the VS Code webview so
  the bar is 36px instead of the 48px :root default; the brand mark keeps its
  size, only the space above/below it shrinks.
- New shared StatusBar merges the image-metadata line (was under the bar) and
  the crosshair mm readout (was a separate footer) into one slim bottom strip
  across the vscode/pwa/desktop/streamlit hosts.
- Size the canvas off a ResizeObserver on its container instead of only
  window.onresize, and use flex-1/min-h-0 (not h-full), so a menu-bar reflow
  no longer leaves a stale, oversized canvas with scrollbars on both axes.

Icons:
- One committed master, branding/niivue-icon.png, drives every app icon via
  scripts/generate-icons.mjs (pnpm generate:icons): transparent neon mark for
  the file-type and in-app viewer icons, opaque for marketplace/PWA.
- Generated binaries are gitignored and rebuilt by each app's build; the one
  committed generated file, niivue-logo.ts, stamps the master's sha256 so CI
  catches drift without a non-reproducible byte-compare.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

🚀 PWA Preview Deployment

Your PWA preview has been deployed!

Preview URL: https://niivue.github.io/niivue-vscode/pr-255/


This preview will be updated automatically when you push new commits to this PR.

github-actions Bot added a commit that referenced this pull request Jun 19, 2026
@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Coverage Report

coverage

Overall line coverage: 42.9% (+0.1) vs main

Package Statements Branches Functions Lines
Shared core (packages/niivue-react) 46.9% 48% (−0.1) 45.8% (+0.1) 47.5% (+0.1)
apps/pwa 28.3% 30% (−2.4) 52.9% 29.5%
apps/jupyter 14.4% 15.9% 14.9% 14.5%
apps/streamlit 17.9% (+0.1) 5.4% (+0.1) 18.5% 17.8% (+0.1)
apps/vscode 38.7% 39.6% 18.9% 38.1%
apps/desktop-tauri 81.8% 65% (+5.9) 78.9% 84.3%

📊 View full report →

…sBar

The global mm readout is owned by the first selected canvas. NiiVue's initial
onLocationChange can fire before a Menu effect initializes selection to [0],
which left the readout blank until the next crosshair move. Fall back to canvas
0 owning it when selection is empty so it populates immediately on load.

Add a StatusBar unit test covering mm reactivity and metadata rendering.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
github-actions Bot added a commit that referenced this pull request Jun 19, 2026
…llbars

The hidden width-measurement twin (.nv-bar-measure) is absolutely positioned and
holds every menu item at natural width. On viewports narrower than the full menu
it extended past the edge and inflated the document scroll area, producing page
scrollbars (a horizontal one that cascades to vertical via the root w-screen).

Cap its box to the bar and clip the overflow; the proxies keep flex-shrink:0 so
their measured widths stay natural and the adaptive overflow collapse is
unchanged. Verified in the PWA at a narrow viewport: document horizontal
overflow drops from 410px to 0 with the More menu still collapsing correctly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
github-actions Bot added a commit that referenced this pull request Jun 20, 2026
@korbinian90 korbinian90 merged commit 4ccaf11 into main Jun 20, 2026
12 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

🧹 PWA Preview Cleanup

The preview deployment for this PR has been removed.

github-actions Bot added a commit that referenced this pull request Jun 20, 2026
korbinian90 added a commit that referenced this pull request Jun 20, 2026
Reconcile #255 (compact top bar, unified StatusBar, single-master icon
pipeline) with the @niivue/niivue v1.0 core migration.

Resolution:
- Menu.tsx import conflict: #255 moved the image-metadata line out of the
  menu into the new shared StatusBar, dropping getMetadataString /
  getNumberOfPoints from Menu. The migration had separately changed the
  multi-echo check from the removed nv.volumes[0].getImageMetadata() method
  to the v1 utility getImageMetadata(vol). Resolved by keeping only the
  still-used getImageMetadata import.
- StatusBar (new in #255) calls getMetadataString(nv) / getNumberOfPoints(nv);
  both keep the same nv signature post-migration, now reading matrix/voxel
  size off the NIfTI header and mesh size off positions (v1) rather than the
  removed 0.x accessors. StatusBar wiring in App.tsx is unchanged from main.
- Container.tsx, Volume.tsx, the three app package.json, and pnpm-lock.yaml
  auto-merged cleanly.

Verified (forced, uncached): turbo type-check 8/8, turbo build 8/8,
@niivue/react 160 unit tests pass (incl. StatusBar 2/2). The streamlit
python test fails only on a missing local pytest (env, pre-existing).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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