diff --git a/dashboard/package-lock.json b/dashboard/package-lock.json index 1b24bf152e..da02b12dcb 100644 --- a/dashboard/package-lock.json +++ b/dashboard/package-lock.json @@ -9,6 +9,8 @@ "version": "0.1.0", "dependencies": { "@preact/signals-core": "^1.8.0", + "@types/dompurify": "^3.0.5", + "dompurify": "^3.4.13", "lit": "^3.2.1", "workbox-window": "^7.4.0" }, @@ -2529,6 +2531,15 @@ "sourcemap-codec": "^1.4.8" } }, + "node_modules/@types/dompurify": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz", + "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==", + "license": "MIT", + "dependencies": { + "@types/trusted-types": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -3212,6 +3223,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/dompurify": { + "version": "3.4.13", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.13.tgz", + "integrity": "sha512-2vmYIoqjze2d+kakP8S/nS5shfsl587kzwEjcGlTdiksUVgFHnFCsLYDVj/JNqJVOQZGSYBTmuycv0PodwmnMQ==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", diff --git a/dashboard/package.json b/dashboard/package.json index e99f9ae45e..c9f61076e7 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -16,6 +16,8 @@ }, "dependencies": { "@preact/signals-core": "^1.8.0", + "@types/dompurify": "^3.0.5", + "dompurify": "^3.4.13", "lit": "^3.2.1", "workbox-window": "^7.4.0" }, diff --git a/dashboard/src/components/nv-app-store.ts b/dashboard/src/components/nv-app-store.ts index f6b90f9bc7..e50dbfb285 100644 --- a/dashboard/src/components/nv-app-store.ts +++ b/dashboard/src/components/nv-app-store.ts @@ -97,7 +97,7 @@ export class NvAppStore extends LitElement { .chip .swatch { width: 7px; height: 7px; border-radius: 50%; } - .chip .count { color: var(--ink-3); font-size: 10px; } + .chip .count { color: var(--ink-2); font-size: 10px; } .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); @@ -139,7 +139,7 @@ export class NvAppStore extends LitElement { } .badge { padding: 1px 6px; border-radius: 4px; - background: var(--bg-3); color: var(--ink-3); + background: var(--bg-3); color: var(--ink-2); border: 1px solid var(--line); } .badge.cat { color: var(--accent); border-color: oklch(0.78 0.14 70 / 0.3); } @@ -149,7 +149,7 @@ export class NvAppStore extends LitElement { .badge.budget { color: var(--accent-2); border-color: oklch(0.78 0.12 195 / 0.3); } .badge.rt-running { color: var(--ok); border-color: oklch(0.78 0.14 145 / 0.5); background: oklch(0.78 0.14 145 / 0.08); } .badge.rt-simulated { color: var(--accent); border-color: oklch(0.78 0.14 70 / 0.5); background: oklch(0.78 0.14 70 / 0.08); } - .badge.rt-mesh-only { color: var(--ink-3); border-color: var(--line); } + .badge.rt-mesh-only { color: var(--ink-2); border-color: var(--line); } .events-feed { background: var(--bg-2); border: 1px solid var(--line); @@ -389,7 +389,7 @@ export class NvAppStore extends LitElement { ${app.crate} ${evCount > 0 ? html`⚡ ${evCount} ev` : ''} this.toggle(app)}> diff --git a/dashboard/src/components/nv-console.ts b/dashboard/src/components/nv-console.ts index 1888ece742..6b791a4297 100644 --- a/dashboard/src/components/nv-console.ts +++ b/dashboard/src/components/nv-console.ts @@ -66,7 +66,7 @@ export class NvConsole extends LitElement { border-left: 2px solid transparent; } .line:hover { background: var(--bg-1); } - .ts { color: var(--ink-4); font-size: 10.5px; padding-top: 1px; } + .ts { color: var(--ink-2); font-size: 10.5px; padding-top: 1px; } .lvl { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; padding-top: 1px; diff --git a/dashboard/src/components/nv-ghost-murmur.ts b/dashboard/src/components/nv-ghost-murmur.ts index aebf31cdaf..78e0b1296b 100644 --- a/dashboard/src/components/nv-ghost-murmur.ts +++ b/dashboard/src/components/nv-ghost-murmur.ts @@ -394,7 +394,7 @@ export class NvGhostMurmur extends LitElement { Distance from sensor ${this.formatDistance(this.distanceM)} - { this.distanceM = Math.pow(10, +(e.target as HTMLInputElement).value); }} /> @@ -407,7 +407,7 @@ export class NvGhostMurmur extends LitElement { Heart dipole moment ${m.toExponential(2)} A·m² - { this.momentLog10 = +(e.target as HTMLInputElement).value; }} /> @@ -536,7 +536,7 @@ export class NvGhostMurmur extends LitElement {

RuView's three-tier mesh — what is actually buildable

-
┌──────────────────────────┐ +
┌──────────────────────────┐ │ Tier 3 — NV-diamond │ Range: 0.1–2 m (lab) │ magnetometer ring │ Status: nvsim simulator only │ (close-confirm) │ Hardware: $$$ (≥$8k DNV-B1) diff --git a/dashboard/src/components/nv-inspector.ts b/dashboard/src/components/nv-inspector.ts index a0d7495426..342ca7e882 100644 --- a/dashboard/src/components/nv-inspector.ts +++ b/dashboard/src/components/nv-inspector.ts @@ -423,7 +423,7 @@ export class NvInspector extends LitElement { role="tab" aria-selected=${this.tab === 'witness'} @click=${() => this.tab = 'witness'}>Witness
-
+
${this.renderHeader()} ${this.tab === 'signal' ? this.renderSignalTab() : this.tab === 'frame' ? this.renderFrameTab() diff --git a/dashboard/src/components/nv-modal.ts b/dashboard/src/components/nv-modal.ts index 23b4c65750..cc2edcf038 100644 --- a/dashboard/src/components/nv-modal.ts +++ b/dashboard/src/components/nv-modal.ts @@ -1,6 +1,7 @@ /* Modal dialog — opened via window.dispatchEvent('nv-modal', { title, body, buttons }). */ import { LitElement, html, css } from 'lit'; import { customElement, state } from 'lit/decorators.js'; +import DOMPurify from 'dompurify'; interface ModalButton { label: string; @@ -137,7 +138,7 @@ export class NvModal extends LitElement {
${this.mTitle}
-
+
${this.buttons.map((b) => html` diff --git a/dashboard/src/components/nv-onboarding.ts b/dashboard/src/components/nv-onboarding.ts index 29e9cb1ca7..04440d3268 100644 --- a/dashboard/src/components/nv-onboarding.ts +++ b/dashboard/src/components/nv-onboarding.ts @@ -33,7 +33,7 @@ const STEPS: TourStep[] = [ This 60-second tour walks you through the four panels, the App Store, the Ghost Murmur research view, and the determinism contract that makes nvsim distinctive.

-

+

Press Esc any time to skip. You can replay this tour from Settings → Help.

`, cta: { label: 'Start the tour →' }, @@ -224,7 +224,7 @@ export class NvOnboarding extends LitElement { .h .step-label { font-family: var(--mono); font-size: 10.5px; - color: var(--ink-3); + color: var(--ink-2); margin-top: 4px; text-transform: uppercase; letter-spacing: 0.06em; @@ -299,7 +299,7 @@ export class NvOnboarding extends LitElement { .progress-label { font-family: var(--mono); font-size: 10px; - color: var(--ink-3); + color: var(--ink-2); } button.primary, button.ghost { padding: 9px 16px; diff --git a/dashboard/src/components/nv-settings-drawer.ts b/dashboard/src/components/nv-settings-drawer.ts index 92544147cc..85b69d3477 100644 --- a/dashboard/src/components/nv-settings-drawer.ts +++ b/dashboard/src/components/nv-settings-drawer.ts @@ -172,7 +172,7 @@ export class NvSettingsDrawer extends LitElement {
Stops the rotating diamond, animated field lines, and chart easing. Auto-on if your system has the prefers-reduced-motion preference set.
motionReduced.value = !motionReduced.value}>
@@ -185,7 +185,7 @@ export class NvSettingsDrawer extends LitElement {
When you change a Tunables slider or load a new scene, push the change to the worker without a manual restart.
autoUpdate.value = !autoUpdate.value}>