refresh top bar (design tokens + adaptive overflow menu) and tile chrome#151
Merged
korbinian90 merged 10 commits intoJun 13, 2026
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Introduces a design-token-based styling layer for niivue-react, focusing on the top menu bar and volume tile chrome, and exposes tokens to Tailwind utilities.
Changes:
- Added
tokens.css(CSS variables) and extended Tailwind theme (colors/fonts/radii) to enablebg-bg-*,text-fg-*,text-accent,font-ui, etc. - Replaced Tailwind utility styling in top bar/menu and volume tile chrome with
nv-*classnames backed by new CSS files. - Added
@fontsource/interand@fontsource/jetbrains-monodependencies and imported font CSS in the VS Code build entry.
Reviewed changes
Copilot reviewed 10 out of 11 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm-lock.yaml | Locks new @fontsource/* dependencies. |
| packages/niivue-react/package.json | Adds font dependencies (also triggers changeset requirement). |
| packages/niivue-react/tailwind.config.js | Extends Tailwind theme with token-backed colors/fonts/radii. |
| packages/niivue-react/src/styles/tokens.css | Defines global design token CSS variables and density presets. |
| packages/niivue-react/src/index.css | Imports tokens + new chrome CSS and Tailwind layers. |
| packages/niivue-react/src/main.tsx | Imports font CSS assets for the VS Code build entry. |
| packages/niivue-react/src/components/Menu.tsx | Refactors top bar structure and applies new nv-* chrome classes. |
| packages/niivue-react/src/components/MenuElements.tsx | Updates menu element classes to nv-* primitives and menu panel wrapper. |
| packages/niivue-react/src/components/Menu.module.css | Adds CSS definitions for top bar + menu primitives (intended global). |
| packages/niivue-react/src/components/Volume.tsx | Updates tile chrome markup/classes and close button accessibility label. |
| packages/niivue-react/src/components/Volume.module.css | Adds CSS definitions for viewport tile chrome (intended global). |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
Comment on lines
+1
to
+3
| /* Top bar + menu primitives — source: prototype styles.css lines 83–143, 605–624. | ||
| Imported globally from index.css; classes are plain (not CSS-Module-scoped). | ||
| The `nv-` prefix provides the scoping. */ |
Comment on lines
+1
to
+3
| /* Viewport tile chrome — source: prototype styles.css lines 206–280. | ||
| Imported globally from index.css; classes are plain (not CSS-Module-scoped). */ | ||
|
|
| import './index.css' | ||
| import '@fontsource/inter/400.css' | ||
| import '@fontsource/inter/500.css' | ||
| import '@fontsource/inter/600.css' |
Comment on lines
64
to
69
| "dependencies": { | ||
| "@fontsource/inter": "^5.0.0", | ||
| "@fontsource/jetbrains-mono": "^5.0.0", | ||
| "@niivue/dcm2niix": "^1.2.0", | ||
| "@niivue/minc-loader": "^1.0.0" | ||
| }, |
Comment on lines
+1
to
+3
| @import './styles/tokens.css'; | ||
| @import './components/Menu.module.css'; | ||
| @import './components/Volume.module.css'; |
Comment on lines
1
to
7
| @import './styles/tokens.css'; | ||
| @import './components/Menu.module.css'; | ||
| @import './components/Volume.module.css'; | ||
|
|
||
| @tailwind base; | ||
| @tailwind components; | ||
| @tailwind utilities; |
| @@ -0,0 +1,57 @@ | |||
| /* Design tokens — source: /tmp/design-project/niivue-vscode/project/styles.css (lines 6–52, 668–679). | |||
Introduce a token-driven visual layer scoped to the top menu bar and volume tile chrome. Tokens live in a new tokens.css (verbatim from the design prototype), are exposed to Tailwind via theme.extend so the rest of the codebase can use bg-bg-3 / text-fg-1 / text-accent / font-ui utilities, and the complex chrome (nv-topbar, nv-pane, nv-pane-label, nv-readout, nv-menu-panel) stays as plain CSS in per-component .module.css files — color-mix, backdrop-filter and gradient backgrounds are kept readable rather than shoved into arbitrary-value utility strings. Status bar, left rail, panels, and command palette are untouched; existing gray-* utilities continue to work. https://claude.ai/code/session_01MZgGydjXWry6uru8UGNstP
- rename Menu.module.css / Volume.module.css to plain .css. They are global stylesheets; the .module.css suffix suggested CSS-Modules scoping, even though the @import path sidesteps Vite's module transform. - reorder index.css so component CSS is imported with layer(components) between @tailwind components and @tailwind utilities. Tailwind's preflight base layer now comes before the component rules, so element-default resets (e.g. button background/cursor) can't stomp .nv-topbtn / .nv-menu-item / etc. - drop font-weight: 700 from .nv-brand-mark (600 is the heaviest Inter weight imported; 600 looks the same at 14px and avoids a synthesized bold). - strip /tmp/design-project paths from header comments; they only made sense in the authoring environment. - add a Changeset entry so @niivue/react gets a patch release note. https://claude.ai/code/session_01MZgGydjXWry6uru8UGNstP
MCP tools in this sandbox are scoped to korbinian90/niivue-vscode; upstream reviews live on niivue/niivue-vscode. Record the curl endpoints for fetching PR/review/comment data so future sessions don't re-derive them. https://claude.ai/code/session_01MZgGydjXWry6uru8UGNstP
The volume tile close glyph changed from "X" to "×" (U+00D7) as part of
the visual refresh, breaking `hasText: 'X'` / `:has-text("X")` selectors
in two Playwright specs. Switch both to `getByRole('button', { name:
'Close' })` — semantic and stable against glyph tweaks.
https://claude.ai/code/session_01MZgGydjXWry6uru8UGNstP
26e6f9b to
5b5d746
Compare
probe-mhd-streamlit-shape.spec.ts asserted the legacy single-line
"{location}: {intensity}" readout. The visual refresh splits it into a
structured POS / VAL pair inside .nv-readout, so the concatenated
"32 x 32 x 32: 255" substring never appears. Assert each fragment
separately and require the "VAL" prefix before the intensity value to
keep the match unambiguous.
https://claude.ai/code/session_01MZgGydjXWry6uru8UGNstP
Contributor
Coverage ReportOverall line coverage: 36.8% (+1.3) vs
|
Contributor
🚀 PWA Preview DeploymentYour PWA preview has been deployed! Preview URL: https://niivue.github.io/niivue-vscode/pr-151/ This preview will be updated automatically when you push new commits to this PR. |
Comment on lines
+30
to
+32
| sm: 'var(--radius-sm)', | ||
| DEFAULT: 'var(--radius)', | ||
| lg: 'var(--radius-lg)', |
Comment on lines
+7
to
+24
| extend: { | ||
| colors: { | ||
| 'bg-0': 'var(--bg-0)', | ||
| 'bg-1': 'var(--bg-1)', | ||
| 'bg-2': 'var(--bg-2)', | ||
| 'bg-3': 'var(--bg-3)', | ||
| 'bg-4': 'var(--bg-4)', | ||
| 'bg-5': 'var(--bg-5)', | ||
| 'fg-0': 'var(--fg-0)', | ||
| 'fg-1': 'var(--fg-1)', | ||
| 'fg-2': 'var(--fg-2)', | ||
| 'fg-3': 'var(--fg-3)', | ||
| 'fg-4': 'var(--fg-4)', | ||
| accent: 'var(--accent)', | ||
| line: 'var(--line)', | ||
| 'line-2': 'var(--line-2)', | ||
| 'line-3': 'var(--line-3)', | ||
| }, |
Comment on lines
+6
to
+9
| import '@fontsource/inter/400.css' | ||
| import '@fontsource/inter/500.css' | ||
| import '@fontsource/inter/600.css' | ||
| import '@fontsource/jetbrains-mono/400.css' |
| </div> | ||
| </div> | ||
| <p className="pl-2">{displayInfo.value}</p> | ||
| <p className="pl-2 text-fg-2">{displayInfo.value}</p> |
| margin-left: 16px; | ||
| font-family: var(--font-mono); | ||
| } | ||
| .nv-menu-div, |
| @@ -0,0 +1,5 @@ | |||
| --- | |||
| "@niivue/react": patch | |||
4 tasks
korbinian90
added a commit
that referenced
this pull request
May 18, 2026
… tests (#175) * test(coverage): easy wins — jupyter download fix + vscode/shared-core tests Three coverage easy wins, all surfaced from the published coverage table on PR #151 (https://niivue.github.io/niivue-vscode/coverage/pr-151/) which showed jupyter as null and vscode at 7.8%. 1) ci.yml — fix jupyter coverage download path Aggregator scans `*/coverage/**/*.json` for `coverage-final.json`. apps/jupyter's CI step uploaded coverage as a single-path artifact (which strips the parent path) and then downloaded with `path: .`, landing files at the repo root with no `coverage/` segment — invisible to the aggregator. Same pattern as VS Code's existing fix: download under `apps/jupyter/coverage/unit/` to restore the path segment. Bumps jupyter from `null` to a real number on the dashboard. 2) apps/vscode tests — three new spec files, 41 new tests - test/dispose.test.ts (9 tests) — disposeAll + Disposable LIFO/idempotency - test/html.test.ts (6 tests) — CSP locked-down, nonce uniqueness, asWebviewUri wiring, no wildcard sources (security guardrail) - test/HoverProvider.test.ts (26 tests) — regex link detection across all 17 supported extensions, command URI shape, case-insensitivity, negative cases test/vscode-mock.ts extended with Hover, MarkdownString, Position, Range, EventEmitter, Disposable to support the new tests. Coverage: HoverProvider 100%, dispose 100%, html 100%. Overall apps/vscode: 7.8% → ~34% statements. 3) packages/niivue-react tests — three new spec files, 53 new tests - test/utility.test.ts (35 tests) — isImageType extension matrix, getMetadataString empty/3D/4D/sub-mm voxel formatting, getNumberOfPoints, getNames duplicate-name resolution with overlay/layer fallbacks - test/keyboardShortcuts.test.ts (12 tests) — matchesShortcut over bare keys / ctrl / shift / alt / meta-as-ctrl / case-insensitivity - test/readyState.test.ts (6 tests) — ReadyStateManager state machine (dom + listener → single send; idempotency; no-window safety) Coverage on the tested files: utility 68%, readyState 100%, settings 100%, keyboardShortcuts 100%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(jupyter): cover remaining url-utils exports Adds tests for the five exports the original url-utils.test.ts didn't cover: getJupyterUrl — URLExt.join wrapper around PageConfig getMhdPairedRawBasename — parses ElementDataFile field; handles LOCAL, missing field, quoted values, subdir-rejection, case insensitivity getMhdPairedRawPath — sibling path computation fetchArrayBuffer — happy path, network failure, HTTP error with body detail, text() throws, text/html auth-redirect detection fetchJson — happy path, HTTP error, generic typing ServerConnection.makeRequest is mocked via vi.spyOn so we exercise fetchArrayBuffer/fetchJson without a real HTTP roundtrip. The error messages tested ("Unexpected HTML response (likely auth redirect)", HTTP-status-with-truncated-body) are the ones JupyterHub users see in auth misfires — pinning their shape protects against silent regressions of user-facing error UX. Result: url-utils.ts coverage 16% → 100% statements / 86% branches. Overall apps/jupyter 1.6% → 10.1% (LOC ceiling — viewer.ts and index.ts together are 77% of source and need JupyterLab test harness to exercise). +25 tests, 39 total in the file. * review: tighten test assertions + add changeset Address all seven Copilot review points on #175. 1) Missing changeset for packages/ + apps/ changes. Add .changeset/test-coverage-easy-wins.md with empty frontmatter (tests-only — no version bump). 2) HoverProvider getText stub ignored the range, returning the whole line regardless. That meant a regression where the provider passed the wrong range to getText() would still pass the tests. Fix: slice the line by the range's character offsets. 3) Loose command-URI assertion (`/command:niiVue\.openLink\?/` matched even though the stubbed Uri.parse mangled the URI). Improve the Uri mock to handle opaque-scheme URIs (command:, mailto:, data:) per real vscode.Uri behavior, distinguishing hierarchical schemes (file, http, https, vscode-remote) from opaque ones via a private _hierarchical flag set at parse time. Then assert the parsed scheme, command path, and decoded args structure explicitly. Adds an extra test pinning that surrounding text never leaks into the args. 4) tryHover swallowed every rejection/exception. Replace with a guard that only swallows the implementation's `reject()` (which rejects with undefined) and re-throws anything else, so unexpected crashes fail loudly. 5) readyState comment had backwards logic ("would still hand us a fresh state machine"). Rewrite to describe what resetModules actually does — clears the module cache so the next import re-evaluates the module and constructs a fresh singleton. 6) isImageType tests only asserted truthiness. Switch to it.each tuples that assert the exact returned extension string, so a regression that says "yes, supported" but returns the wrong extension still fails. 7) CSP wildcard guard regex was too narrow (`(\s|=)\*(\s|;|$)` would miss `https://*` or `*.example.com`). Replace with a strict `not.toContain('*')` — current CSP contains none; any future addition should require explicit reasoning. * review: fix lint — curly braces + prettier formatting on url-utils.test.ts ESLint `curly` rule rejected the single-line `if (opts.textThrows) throw new Error('reader closed')` inside the mockResponse helper. Adding braces fixes that. Prettier then reflowed some adjacent lines. * review: position-aware hover mock, real JupyterHub baseUrl test, empty-changeset detection, fix it.each title order Four points raised on the most recent review pass: 1) HoverProvider mock was position-blind — `getWordRangeAtPosition` returned the first regex match regardless of the cursor position, so a buggy provider that asked about a position outside any link could still pass these tests. Mock now respects the position the same way the real VS Code API does. `tryHover` now defaults the cursor to the middle of the line; the positive tests construct their lines so the link straddles the middle. Added a new "cursor sits outside the link" negative test that pins down the new behavior explicitly (cursor at 0 → no hover, cursor inside the URL → hover). 2) getJupyterUrl tests didn't actually exercise the JupyterHub prefix-preserving behavior the function exists for. The assertions only checked the URL suffix while relying on the default PageConfig root; an implementation that ignored the configured base URL would have passed them. Replaced with tests that explicitly set `PageConfig.setOption('baseUrl', 'http://hub. example.com/user/johndoe/')` (with and without trailing slash) and assert the full URL — the JupyterHub prefix must appear. Restores the original baseUrl in afterEach. 3) Empty-frontmatter changeset would still be counted by `.github/workflows/prerelease.yml`, triggering a no-op prerelease on merge. Updated the Detect step to skip changesets whose frontmatter has no package bumps. Verified locally: with the current `.changeset/` it counts `streamlit-perf-followup.md` (1) and skips `test-coverage-easy-wins.md` (empty). Future test-only PRs benefit from the same treatment. 4) it.each placeholder order on isImageType read as "returns scan.nii for .nii" — the input/expected were reversed in the title even though the assertion was correct. Changed title to "given %s, returns %s" so cases read naturally as "given scan.nii, returns .nii". --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bring the design-token visual refresh up to date with main. Key conflict reconciliations: - index.css: main migrated to Tailwind v4 (@import 'tailwindcss' + @config). Re-add the token + component-CSS imports on top, keeping Menu.css / Volume.css in layer(components) so Tailwind utilities still override them. - Volume.tsx: main added drag-and-drop reordering (drag handle, drop zones, insert bars). Keep all of it and apply the nv-pane chrome + nv-iconbtn close button (x glyph, aria-label "Close") from the refresh. - pnpm-lock.yaml regenerated for the @fontsource/* deps alongside main's dependency bumps. Verified: @niivue/react type-check, build, and 71 unit tests all pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…n prod Top bar: replace the flex-wrap second-line behaviour with an adaptive "priority+" overflow. A new MenuBar measures the available width with a ResizeObserver and keeps as many top-level menus inline as fit; the rest collapse into a trailing "More" button. Overflowed dropdowns expand inline (accordion) inside the popover, which stays robust on the narrow VS Code / Streamlit widths where overflow actually happens (a side flyout would clip there). Top-level items are now expressed as a data array so each renders either inline or in the overflow menu; the existing menu primitives (MenuItem / MenuButton / MenuToggle / MenuEntry) are reused unchanged, and a hidden measurer mirrors their widths. Fix: the refreshed chrome (design tokens, top bar, tile chrome) rendered in dev but not in production builds. The package declares "sideEffects": false, so the bare side-effect "import './index.css'" in the package entry was tree-shaken out of consumers' production bundles, dropping every nv- rule and token. Co-locate the CSS with the components that use it (Menu.tsx, Volume.tsx) and mark "*.css" as side-effectful, so the styles ship reliably in dev, app production builds, and the library build. Verified: type-check, lint, 71 unit tests; PWA and library production builds now contain the nv- styles and tokens; full PWA e2e suite (50 tests) plus a fresh-production Menu e2e run all pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Three Playwright cases in real Chrome (where ResizeObserver fires on viewport changes, unlike the headless preview): - wide viewport keeps all top-level menus inline (no More button) - narrow viewport collapses overflow into More, and a collapsed dropdown expands inline (View -> Axial) inside the popover - loading the example image reveals ColorScale/Overlay/Header/Navigation, which then collapse into More at a constrained width instead of wrapping Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
korbinian90
added a commit
to korbinian90/niivue-vscode
that referenced
this pull request
Jun 13, 2026
Brings the PWA icon-generator work up to date with main (top bar refresh niivue#151, vite 8 / vitest 4 upgrades, tauri app, coverage tooling). Conflict resolution: - apps/pwa/package.json: kept the PR's @vite-pwa/assets-generator ^1.0.2 and vite-plugin-pwa ^1.3.0; adopted main's newer vite ^8, vitest ^4, @types/* and vite-plugin-virtual ^0.5.0. - pnpm-lock.yaml: took main's lockfile and reran pnpm install --lockfile-only so vite-plugin-pwa/@vite-pwa/assets-generator resolve against vite@8. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
korbinian90
added a commit
to korbinian90/niivue-vscode
that referenced
this pull request
Jun 13, 2026
The niivue#151 top bar shipped a placeholder 'N' glyph as the brand mark. Swap it for the canonical neon brain logo so the same icon this PR rolls out to the favicon, PWA, VS Code and JupyterLab also appears in-app. - New master: packages/niivue-react/src/assets/niivue-logo.png, a 96x96 256-color-palette downscale (Lanczos) of apps/pwa/public/logo.png, ~3.3 KB. Being under Vite's 4096-byte assetsInlineLimit, it inlines as a base64 data URI in every consumer (PWA builds @niivue/react from source; VS Code and JupyterLab consume the built lib). Verified: the lib build embeds one data:image/png URI and emits no separate file, so the webview needs no extra asset request or CSP allowance. - Menu.tsx: the brand <div>N</div> becomes <img class=nv-brand-mark>. alt='' since the adjacent 'niivue' wordmark already names the brand. - Menu.css: .nv-brand-mark restyled from an accent tile + centered glyph to an image tile (object-fit: cover, dark #0a0e13 fallback, kept the inset hairline ring; softened the accent glow). Changeset bumps @niivue/react alongside the existing icon work. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
korbinian90
added a commit
to korbinian90/niivue-vscode
that referenced
this pull request
Jun 13, 2026
The niivue#151 top bar shipped a placeholder 'N' glyph as the brand mark. Swap it for the canonical neon brain logo so the same icon this PR rolls out to the favicon, PWA, VS Code and JupyterLab also appears in-app. - New module: packages/niivue-react/src/assets/niivue-logo.ts exports the logo as a base64 data URI (a 96x96 256-color-palette downscale of apps/pwa/public/logo.png, ~3.3 KB). Embedded as a string rather than imported as a *.png on purpose: the PWA and the Streamlit frontend type-check @niivue/react *from source* and don't all provide an ambient '*.png' module declaration, so a *.png import breaks their type-check. A plain string sidesteps that and still inlines (verified: the lib build embeds one data:image/png URI and emits no asset file, so the VS Code webview needs no extra request or CSP allowance). - Menu.tsx: the brand <div>N</div> becomes <img class=nv-brand-mark>. alt='' since the adjacent 'niivue' wordmark already names the brand. - Menu.css: .nv-brand-mark restyled from an accent tile + centered glyph to an image tile (object-fit: cover, dark #0a0e13 fallback, kept the inset hairline ring; softened the accent glow). Changeset bumps @niivue/react alongside the existing icon work. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
korbinian90
added a commit
that referenced
this pull request
Jun 13, 2026
…169) * fix(pwa): modernize icon generation with @vite-pwa/assets-generator Replaces the legacy 200x200 grayscale brain master with the canonical 512x512 neon brand icon (downscaled via Lanczos3 from the 1024x1024 upstream at niivue/niivue, sha 97875774f13d), and switches PWA icon generation to vite-plugin-pwa's integrated pwaAssets option. Generated PNGs use 256-color palette mode (Sharp's quantize-per-output), so a full icon set (favicon.ico + pwa-64/192/512 + maskable-512 + apple-touch-180) totals ~89 KB on disk instead of the inflated PNGs the old pipeline shipped. Per-purpose icons replace the incorrect 'purpose: "any maskable"' on an unpadded transparent icon: the maskable variant has the icon's own dark background filling the safe-zone, and the apple-touch variant is pre-rendered at 180x180 instead of being a mis-labelled 200x200 PNG. - new pwa-assets.config.ts with palette PNG output options - VitePWA gets pwaAssets: { config: true, overrideManifestIcons: true } and the manifest icons[] array is removed (auto-injected) - index.html: favicon now has sizes="any", apple-touch-icon points at the generated 180x180 file - copy-assets.mjs removed: nothing left to copy, all assets generated - .gitignore: keep apps/pwa/public/logo.png, ignore generated icons - bump vite-plugin-pwa ^1.1.0 -> ^1.3.0 Replaces #108. Targets main directly (the old PR was on the abandoned ci_working branch). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(pwa): drop deleted copy-assets.mjs from playwright webServer + align workbox peer deps Three follow-ups after the icon-generator refresh: 1. apps/pwa/playwright.config.ts webServer.command still invoked `node copy-assets.mjs && vite build ...`, which silently killed webServer startup on CI now that copy-assets.mjs is gone. Result: playwright collected 0 tests and exited 1. Drop the node prefix. 2. apps/pwa/tests/global-teardown.ts tried to rmdir public/, which would always fail now that public/logo.png is a tracked file. The fs.unlink loop above already removes test fixtures; nothing else to clean. Drop the rmdir. 3. vite-plugin-pwa@1.3.0 declares workbox-build/workbox-window peer deps as ^7.4.1, but apps/pwa/package.json pinned ^7.3.0 — peer warning during install and a real risk of subtle incompat. Bump both to ^7.4.1. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * icons: roll out master logo to vscode + jupyter, drop legacy duplicates PR #169 modernised the PWA icon pipeline but left the vscode and jupyter extensions on the legacy 200×200 PNGs (plus stray duplicates under packages/niivue-react/public/). Extend the cleanup: - apps/vscode/icon.png (128×128) — marketplace icon, downsized from apps/pwa/public/logo.png. Replaces niivue_icon.png. - apps/vscode/language-icon.png (32×32, transparent) — file-type icon for .nii/.dcm/etc., downsized from the existing niivue_icon_transparent_contrast.png. Replaces both light/dark references in package.json. - apps/jupyter/style/niivue-icon.png (32×32, transparent) — .jp-NiivueFileIcon background-image now points at this co-located PNG instead of the static/niivue/* rsync output. Decouples the JupyterLab file icon from build:assets. Resized via sharp (already a transitive dep of @vite-pwa/assets-generator in PR #169) with the same palette/quality settings as pwa-assets.config.ts: node -e 'const s=require("sharp"); const png={quality:80, compressionLevel:9,palette:true,colors:256}; (async()=>{await s("apps/pwa/public/logo.png").resize(128,128).png(png).toFile("apps/vscode/icon.png"); await s("apps/vscode/niivue_icon_transparent_contrast.png").resize(32,32).png(png).toFile("apps/vscode/language-icon.png"); await s("apps/vscode/niivue_icon_transparent_contrast.png").resize(32,32).png(png).toFile("apps/jupyter/style/niivue-icon.png");})()' Deleted: - apps/vscode/niivue_icon.png - apps/vscode/niivue_icon_transparent_contrast.png - apps/jupyter/niivue_icon_transparent_contrast.png (unreferenced) - packages/niivue-react/public/niivue_icon.png (orphan after #169) - packages/niivue-react/public/niivue_icon_transparent_contrast.png - packages/niivue-react/public/favicon.ico (#169 generates a new one from apps/pwa/public/logo.png) Also drop the now-inert "niivue/niivue_icon*.png" rules from apps/vscode/.vscodeignore — the source files they shielded against no longer exist in packages/niivue-react/public/. The PWA build was re-verified end-to-end (manifest icons[] now lists pwa-64/192/512 + maskable-512; build/ contains apple-touch-180, favicon.ico generated at 48×48); the vscode extension package builds cleanly with the new icon references; the jupyter CSS reference was verified locally (full labextension build needs jupyter CLI not present in this sandbox — CI will exercise it). Changeset extended to also bump 'niivue' and '@niivue/jupyter' patch. https://claude.ai/code/session_01MZgGydjXWry6uru8UGNstP * feat(react): use the neon brain logo as the top-bar brand mark The #151 top bar shipped a placeholder 'N' glyph as the brand mark. Swap it for the canonical neon brain logo so the same icon this PR rolls out to the favicon, PWA, VS Code and JupyterLab also appears in-app. - New module: packages/niivue-react/src/assets/niivue-logo.ts exports the logo as a base64 data URI (a 96x96 256-color-palette downscale of apps/pwa/public/logo.png, ~3.3 KB). Embedded as a string rather than imported as a *.png on purpose: the PWA and the Streamlit frontend type-check @niivue/react *from source* and don't all provide an ambient '*.png' module declaration, so a *.png import breaks their type-check. A plain string sidesteps that and still inlines (verified: the lib build embeds one data:image/png URI and emits no asset file, so the VS Code webview needs no extra request or CSP allowance). - Menu.tsx: the brand <div>N</div> becomes <img class=nv-brand-mark>. alt='' since the adjacent 'niivue' wordmark already names the brand. - Menu.css: .nv-brand-mark restyled from an accent tile + centered glyph to an image tile (object-fit: cover, dark #0a0e13 fallback, kept the inset hairline ring; softened the accent glow). Changeset bumps @niivue/react alongside the existing icon work. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
korbinian90
added a commit
that referenced
this pull request
Jun 13, 2026
Re-applies the .nvd 'Save Scene' action as a BarItem in the new data-driven MenuBar (the old MenuButton render path was rewritten upstream), keeping the viewer-protocol import and the saveScene handler. type-check, lint, build, and 80 unit tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Introduce a token-driven visual layer scoped to the top menu bar and volume tile chrome. Tokens live in a new
tokens.css, are exposed to Tailwind viatheme.extend(so the rest of the codebase can usebg-bg-3/text-fg-1/text-accent/font-ui), and the complex chrome (nv-topbar,nv-pane,nv-pane-label,nv-readout,nv-menu-panel) stays as plain CSS in per-component stylesheets. Status bar, left rail, panels, and command palette are untouched; existinggray-*utilities continue to work.https://claude.ai/code/session_01MZgGydjXWry6uru8UGNstP
Update (2026-06-13): rebased onto main + adaptive top bar
Rebased onto current
main, which had since moved to Tailwind v4, added the Tauri desktop app, and added drag-and-drop image reordering. Conflicts resolved inindex.css(v3@tailwinddirectives reconciled with v4@import 'tailwindcss'+@config) andVolume.tsx(kept both main's drag-and-drop machinery and the new tile chrome +xclose button).Adaptive top bar. The menu bar no longer wraps to a second line when horizontal space runs out. A new
MenuBarmeasures the available width with aResizeObserverand keeps as many top-level menus inline as fit; the rest collapse into a trailing "More" overflow button. A collapsed dropdown expands inline (accordion) inside the popover, which stays robust on the narrow VS Code / Streamlit widths where overflow actually happens. Top-level items are now expressed as a data array so each renders either inline or in the overflow menu; the existing menu primitives (MenuItem/MenuButton/MenuToggle/MenuEntry) are reused unchanged.Fix: component CSS now ships in production. The refreshed chrome rendered in dev but not in production builds. The package declared
"sideEffects": false, so the bare side-effectimport './index.css'in the package entry was tree-shaken out of consumers' production bundles, dropping everynv-rule and token. The CSS is now co-located with the components that use it (Menu.tsx,Volume.tsx) and*.cssis marked side-effectful, so the chrome ships in dev, app production builds, and the library build.Verification.
type-check,lint, and 71 unit tests pass; PWA and library production builds now contain thenv-styles and tokens; the full PWA e2e suite (50 tests) plus a newMenuOverflow.spec.ts(wide / narrow / after-loading-an-image) all pass on a fresh production build.🤖 Generated with Claude Code