@ashlr/hub 3.5.0 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +160 -0
- package/README.md +3 -0
- package/dist/build-identity.json +2 -2
- package/dist/cli/activation.d.ts +41 -0
- package/dist/cli/activation.js +485 -0
- package/dist/cli/activation.js.map +1 -0
- package/dist/core/daemon/cutoff-checkpoint-scheduler.js +7 -0
- package/dist/core/daemon/cutoff-checkpoint-scheduler.js.map +1 -1
- package/dist/core/daemon/loop.d.ts +19 -0
- package/dist/core/daemon/loop.js +235 -5
- package/dist/core/daemon/loop.js.map +1 -1
- package/dist/core/daemon/overnight-status.d.ts +152 -0
- package/dist/core/daemon/overnight-status.js +275 -0
- package/dist/core/daemon/overnight-status.js.map +1 -0
- package/dist/core/daemon/post-merge-halt.d.ts +212 -0
- package/dist/core/daemon/post-merge-halt.js +503 -0
- package/dist/core/daemon/post-merge-halt.js.map +1 -0
- package/dist/core/daemon/run-window.d.ts +218 -0
- package/dist/core/daemon/run-window.js +420 -0
- package/dist/core/daemon/run-window.js.map +1 -0
- package/dist/core/fleet/external-skill-audit.js +1 -1
- package/dist/core/fleet/external-skill-audit.js.map +1 -1
- package/dist/core/fleet/generated-repair-resolution.d.ts +36 -0
- package/dist/core/fleet/generated-repair-resolution.js +245 -0
- package/dist/core/fleet/generated-repair-resolution.js.map +1 -0
- package/dist/core/local-runtime/llama/config.d.ts +28 -6
- package/dist/core/local-runtime/llama/config.js +28 -6
- package/dist/core/local-runtime/llama/config.js.map +1 -1
- package/dist/core/local-runtime/llama/port.d.ts +17 -0
- package/dist/core/local-runtime/llama/port.js +47 -0
- package/dist/core/local-runtime/llama/port.js.map +1 -0
- package/dist/core/local-runtime/llama/proxy-host.d.ts +54 -0
- package/dist/core/local-runtime/llama/proxy-host.js +159 -0
- package/dist/core/local-runtime/llama/proxy-host.js.map +1 -0
- package/dist/core/local-runtime/llama/proxy-process.d.ts +148 -0
- package/dist/core/local-runtime/llama/proxy-process.js +250 -0
- package/dist/core/local-runtime/llama/proxy-process.js.map +1 -0
- package/dist/core/local-runtime/llama/proxy-record.d.ts +40 -0
- package/dist/core/local-runtime/llama/proxy-record.js +133 -0
- package/dist/core/local-runtime/llama/proxy-record.js.map +1 -0
- package/dist/core/local-runtime/llama/proxy-supervisor.d.ts +118 -0
- package/dist/core/local-runtime/llama/proxy-supervisor.js +511 -0
- package/dist/core/local-runtime/llama/proxy-supervisor.js.map +1 -0
- package/dist/core/web/public/next/assets/App-Cgi6j1Gk.css +1 -0
- package/dist/core/web/public/next/assets/App-vtaHB9mp.js +7 -0
- package/dist/core/web/public/next/assets/App-vtaHB9mp.js.map +1 -0
- package/dist/core/web/public/next/assets/ApprovalsSection-B-bFJ0I9.js +2 -0
- package/dist/core/web/public/next/assets/ApprovalsSection-B-bFJ0I9.js.map +1 -0
- package/dist/core/web/public/next/assets/ApprovalsSection-Su-NUTis.css +1 -0
- package/dist/core/web/public/next/assets/AutonomySection-CHjxJt2z.css +1 -0
- package/dist/core/web/public/next/assets/AutonomySection-DoqmsCjw.js +2 -0
- package/dist/core/web/public/next/assets/AutonomySection-DoqmsCjw.js.map +1 -0
- package/dist/core/web/public/next/assets/ChatSection-BfnLe5dT.css +1 -0
- package/dist/core/web/public/next/assets/ChatSection-vNPIJffd.js +80 -0
- package/dist/core/web/public/next/assets/ChatSection-vNPIJffd.js.map +1 -0
- package/dist/core/web/public/next/assets/ConfirmDialog-Dd2APQhB.js +2 -0
- package/dist/core/web/public/next/assets/ConfirmDialog-Dd2APQhB.js.map +1 -0
- package/dist/core/web/public/next/assets/{ConfirmDialog-cYuivhCX.css → ConfirmDialog-Dx15x0Ho.css} +1 -1
- package/dist/core/web/public/next/assets/Dialog-CPM9JxBc.js +2 -0
- package/dist/core/web/public/next/assets/Dialog-CPM9JxBc.js.map +1 -0
- package/dist/core/web/public/next/assets/Dialog-tQ8kFulD.css +1 -0
- package/dist/core/web/public/next/assets/DiffViewer-B84qVef9.js +7 -0
- package/dist/core/web/public/next/assets/DiffViewer-B84qVef9.js.map +1 -0
- package/dist/core/web/public/next/assets/DiffViewer-C8HHTnVE.css +1 -0
- package/dist/core/web/public/next/assets/McpSection-CEUpV_5X.js +2 -0
- package/dist/core/web/public/next/assets/McpSection-CEUpV_5X.js.map +1 -0
- package/dist/core/web/public/next/assets/McpSection-D88QlDpG.css +1 -0
- package/dist/core/web/public/next/assets/Meter--h3MmZS-.js +2 -0
- package/dist/core/web/public/next/assets/Meter--h3MmZS-.js.map +1 -0
- package/dist/core/web/public/next/assets/Meter-CLcr-4wS.css +1 -0
- package/dist/core/web/public/next/assets/{MutationTokenDialog-jWLLCxWn.css → MutationTokenDialog-CrfJ0PdD.css} +1 -1
- package/dist/core/web/public/next/assets/MutationTokenDialog-DA8t97XT.js +2 -0
- package/dist/core/web/public/next/assets/MutationTokenDialog-DA8t97XT.js.map +1 -0
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-Bq7Vyud0.js +7 -0
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-Bq7Vyud0.js.map +1 -0
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-CM_8pJs6.css +1 -0
- package/dist/core/web/public/next/assets/RouteErrorBoundary-Badio_uO.js +2 -0
- package/dist/core/web/public/next/assets/RouteErrorBoundary-Badio_uO.js.map +1 -0
- package/dist/core/web/public/next/assets/RouteErrorBoundary-ekyMXAK8.css +1 -0
- package/dist/core/web/public/next/assets/SettingsSection-BII7TTSD.css +1 -0
- package/dist/core/web/public/next/assets/SettingsSection-BwrpQlpP.js +2 -0
- package/dist/core/web/public/next/assets/SettingsSection-BwrpQlpP.js.map +1 -0
- package/dist/core/web/public/next/assets/UniverseConsoleApp-Dh7A-hLD.css +1 -0
- package/dist/core/web/public/next/assets/UniverseConsoleApp-_FSohAdN.js +2 -0
- package/dist/core/web/public/next/assets/UniverseConsoleApp-_FSohAdN.js.map +1 -0
- package/dist/core/web/public/next/assets/UniverseView-Bqa8DH57.css +1 -0
- package/dist/core/web/public/next/assets/UniverseView-DqcXbed4.js +9 -0
- package/dist/core/web/public/next/assets/UniverseView-DqcXbed4.js.map +1 -0
- package/dist/core/web/public/next/assets/UsageSection-Bq6Daaby.js +2 -0
- package/dist/core/web/public/next/assets/UsageSection-Bq6Daaby.js.map +1 -0
- package/dist/core/web/public/next/assets/UsageSection-DwgNOYvi.css +1 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-CMkCizvL.css +1 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-CsIQv9id.js +3 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-CsIQv9id.js.map +1 -0
- package/dist/core/web/public/next/assets/charts-CTZJ-JrH.js +2 -0
- package/dist/core/web/public/next/assets/charts-CTZJ-JrH.js.map +1 -0
- package/dist/core/web/public/next/assets/charts-CsrtT4rk.css +1 -0
- package/dist/core/web/public/next/assets/fleet-model-ClBbQ0Uj.js +2 -0
- package/dist/core/web/public/next/assets/fleet-model-ClBbQ0Uj.js.map +1 -0
- package/dist/core/web/public/next/assets/format-BNYWGJat.js +2 -0
- package/dist/core/web/public/next/assets/format-BNYWGJat.js.map +1 -0
- package/dist/core/web/public/next/assets/global-D6bTxIRn.js +2 -0
- package/dist/core/web/public/next/assets/global-D6bTxIRn.js.map +1 -0
- package/dist/core/web/public/next/assets/global-z-JfD3ow.css +1 -0
- package/dist/core/web/public/next/assets/icons-D9vlf85u.js +2 -0
- package/dist/core/web/public/next/assets/icons-D9vlf85u.js.map +1 -0
- package/dist/core/web/public/next/assets/index-CZamKRUg.js +11 -0
- package/dist/core/web/public/next/assets/index-CZamKRUg.js.map +1 -0
- package/dist/core/web/public/next/assets/queries-B8eBnFox.js +2 -0
- package/dist/core/web/public/next/assets/queries-B8eBnFox.js.map +1 -0
- package/dist/core/web/public/next/assets/use-guarded-action-bzrVVAYq.js +2 -0
- package/dist/core/web/public/next/assets/use-guarded-action-bzrVVAYq.js.map +1 -0
- package/dist/core/web/public/next/assets/verse-model-CvtK6vP6.js +2 -0
- package/dist/core/web/public/next/assets/verse-model-CvtK6vP6.js.map +1 -0
- package/dist/core/web/public/next/assets/workspace-model-v0a1gl-C.js +2 -0
- package/dist/core/web/public/next/assets/workspace-model-v0a1gl-C.js.map +1 -0
- package/dist/core/web/public/next/index.html +1 -1
- package/dist/release-dependency-inventory.json +1 -1
- package/node_modules/marked/README.md +8 -0
- package/node_modules/marked/bin/main.js +12 -11
- package/node_modules/marked/lib/marked.d.ts +88 -25
- package/node_modules/marked/lib/marked.esm.js +50 -44
- package/node_modules/marked/lib/marked.esm.js.map +3 -3
- package/node_modules/marked/lib/marked.umd.js +50 -44
- package/node_modules/marked/lib/marked.umd.js.map +3 -3
- package/node_modules/marked/man/marked.1 +1 -1
- package/node_modules/marked/package.json +21 -21
- package/package.json +13 -8
- package/dist/core/web/public/next/assets/App-BCKqSppK.css +0 -1
- package/dist/core/web/public/next/assets/App-CsbPYQqy.js +0 -16
- package/dist/core/web/public/next/assets/App-CsbPYQqy.js.map +0 -1
- package/dist/core/web/public/next/assets/ApprovalsSection-CBZquyLK.js +0 -2
- package/dist/core/web/public/next/assets/ApprovalsSection-CBZquyLK.js.map +0 -1
- package/dist/core/web/public/next/assets/ApprovalsSection-CRP59wSb.css +0 -1
- package/dist/core/web/public/next/assets/AutonomySection-CQVpEdCE.js +0 -2
- package/dist/core/web/public/next/assets/AutonomySection-CQVpEdCE.js.map +0 -1
- package/dist/core/web/public/next/assets/AutonomySection-DTN6m6QE.css +0 -1
- package/dist/core/web/public/next/assets/ChatSection-DiRvNX3Q.css +0 -1
- package/dist/core/web/public/next/assets/ChatSection-DmE9K0Tg.js +0 -77
- package/dist/core/web/public/next/assets/ChatSection-DmE9K0Tg.js.map +0 -1
- package/dist/core/web/public/next/assets/ConfirmDialog-deO0C0iY.js +0 -2
- package/dist/core/web/public/next/assets/ConfirmDialog-deO0C0iY.js.map +0 -1
- package/dist/core/web/public/next/assets/Dialog-CNd7q89m.js +0 -2
- package/dist/core/web/public/next/assets/Dialog-CNd7q89m.js.map +0 -1
- package/dist/core/web/public/next/assets/Dialog-DxN7RgB5.css +0 -1
- package/dist/core/web/public/next/assets/DiffViewer-DTO0KRuG.js +0 -7
- package/dist/core/web/public/next/assets/DiffViewer-DTO0KRuG.js.map +0 -1
- package/dist/core/web/public/next/assets/DiffViewer-hN7X6wGT.css +0 -1
- package/dist/core/web/public/next/assets/Epistemic-53PikaUI.js +0 -2
- package/dist/core/web/public/next/assets/Epistemic-53PikaUI.js.map +0 -1
- package/dist/core/web/public/next/assets/Epistemic-DiyMyeaN.css +0 -1
- package/dist/core/web/public/next/assets/Meter-CGBsbXUX.css +0 -1
- package/dist/core/web/public/next/assets/Meter-DRWZQgr1.js +0 -2
- package/dist/core/web/public/next/assets/Meter-DRWZQgr1.js.map +0 -1
- package/dist/core/web/public/next/assets/MutationTokenDialog-DYF8n_RD.js +0 -2
- package/dist/core/web/public/next/assets/MutationTokenDialog-DYF8n_RD.js.map +0 -1
- package/dist/core/web/public/next/assets/RefreshIndicator-DXJQXKyA.js +0 -2
- package/dist/core/web/public/next/assets/RefreshIndicator-DXJQXKyA.js.map +0 -1
- package/dist/core/web/public/next/assets/RefreshIndicator-O7jUBOmX.css +0 -1
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-DLl4DbGG.css +0 -1
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-hDSEFdLU.js +0 -7
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-hDSEFdLU.js.map +0 -1
- package/dist/core/web/public/next/assets/RouteErrorBoundary-BIpdnxp-.css +0 -1
- package/dist/core/web/public/next/assets/RouteErrorBoundary-CZd7ln8v.js +0 -2
- package/dist/core/web/public/next/assets/RouteErrorBoundary-CZd7ln8v.js.map +0 -1
- package/dist/core/web/public/next/assets/SettingsSection-C9Qs9JWW.js +0 -2
- package/dist/core/web/public/next/assets/SettingsSection-C9Qs9JWW.js.map +0 -1
- package/dist/core/web/public/next/assets/SettingsSection-DGJMdUh2.css +0 -1
- package/dist/core/web/public/next/assets/Skeleton-D2JaTXyv.css +0 -1
- package/dist/core/web/public/next/assets/Skeleton-YkcOpgFb.js +0 -2
- package/dist/core/web/public/next/assets/Skeleton-YkcOpgFb.js.map +0 -1
- package/dist/core/web/public/next/assets/StatusBadge-DJw0LSPg.js +0 -2
- package/dist/core/web/public/next/assets/StatusBadge-DJw0LSPg.js.map +0 -1
- package/dist/core/web/public/next/assets/StatusBadge-TpDqZf6K.css +0 -1
- package/dist/core/web/public/next/assets/TableView-Bj-w1O6o.js +0 -2
- package/dist/core/web/public/next/assets/TableView-Bj-w1O6o.js.map +0 -1
- package/dist/core/web/public/next/assets/TableView-R6Yeztp1.css +0 -1
- package/dist/core/web/public/next/assets/UniverseConsoleApp-Bs2fxaen.js +0 -2
- package/dist/core/web/public/next/assets/UniverseConsoleApp-Bs2fxaen.js.map +0 -1
- package/dist/core/web/public/next/assets/UniverseConsoleApp-CiZZxRPV.css +0 -1
- package/dist/core/web/public/next/assets/UniverseView-B6b2hw-8.js +0 -9
- package/dist/core/web/public/next/assets/UniverseView-B6b2hw-8.js.map +0 -1
- package/dist/core/web/public/next/assets/UniverseView-gBxl6yum.css +0 -1
- package/dist/core/web/public/next/assets/UsageSection-C__ziNkV.js +0 -2
- package/dist/core/web/public/next/assets/UsageSection-C__ziNkV.js.map +0 -1
- package/dist/core/web/public/next/assets/UsageSection-UUYDidOg.css +0 -1
- package/dist/core/web/public/next/assets/VerseConsoleApp-Cu5aG6J6.js +0 -3
- package/dist/core/web/public/next/assets/VerseConsoleApp-Cu5aG6J6.js.map +0 -1
- package/dist/core/web/public/next/assets/VerseConsoleApp-mOAXvWa6.css +0 -1
- package/dist/core/web/public/next/assets/fleet-model-DXCfVtNW.js +0 -2
- package/dist/core/web/public/next/assets/fleet-model-DXCfVtNW.js.map +0 -1
- package/dist/core/web/public/next/assets/format-fggwu_Rs.js +0 -2
- package/dist/core/web/public/next/assets/format-fggwu_Rs.js.map +0 -1
- package/dist/core/web/public/next/assets/global-BHjd6fVZ.js +0 -2
- package/dist/core/web/public/next/assets/global-BHjd6fVZ.js.map +0 -1
- package/dist/core/web/public/next/assets/global-BeRYd1Bu.css +0 -1
- package/dist/core/web/public/next/assets/index-CJ-e8YA9.js +0 -2
- package/dist/core/web/public/next/assets/index-CJ-e8YA9.js.map +0 -1
- package/dist/core/web/public/next/assets/index-CpgkRaTi.js +0 -51
- package/dist/core/web/public/next/assets/index-CpgkRaTi.js.map +0 -1
- package/dist/core/web/public/next/assets/queries-856qUN3Y.js +0 -2
- package/dist/core/web/public/next/assets/queries-856qUN3Y.js.map +0 -1
- package/dist/core/web/public/next/assets/use-guarded-action-Bqa2v0a-.css +0 -1
- package/dist/core/web/public/next/assets/use-guarded-action-DwaESKVy.js +0 -2
- package/dist/core/web/public/next/assets/use-guarded-action-DwaESKVy.js.map +0 -1
- package/dist/core/web/public/next/assets/verse-model-Dllo8rRt.js +0 -2
- package/dist/core/web/public/next/assets/verse-model-Dllo8rRt.js.map +0 -1
- package/dist/core/web/public/next/assets/workspace-model-JgmWDKt4.js +0 -2
- package/dist/core/web/public/next/assets/workspace-model-JgmWDKt4.js.map +0 -1
- /package/node_modules/marked/{LICENSE.md → LICENSE} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
._region_1818x_1{position:fixed;bottom:var(--space-6);right:var(--space-6);display:flex;flex-direction:column;gap:var(--space-2);z-index:var(--z-toast);max-width:360px}._toast_1818x_12{display:flex;align-items:center;justify-content:space-between;gap:var(--space-3);padding:var(--space-3) var(--space-4);border-radius:var(--radius-md);box-shadow:var(--shadow-toast);font-size:var(--text-sm-size);animation:_slide-in_1818x_1 var(--duration-base) var(--ease-decelerate);border:1px solid var(--border-default);background:var(--bg-surface-raised);color:var(--text-primary)}._success_1818x_27{border-color:var(--status-success-solid)}._danger_1818x_30{border-color:var(--status-danger-solid)}._dismiss_1818x_34{color:var(--text-tertiary);border-radius:var(--radius-xs);font-size:var(--text-lg-size);line-height:1;padding:var(--space-1)}._dismiss_1818x_34{transition:color var(--duration-fast) var(--ease-standard),background var(--duration-fast) var(--ease-standard)}._dismiss_1818x_34:hover{color:var(--text-primary);background:var(--bg-hover)}._dismiss_1818x_34:active{background:var(--bg-active)}@keyframes _slide-in_1818x_1{0%{opacity:0;transform:translateY(8px)}}@media(prefers-reduced-motion:reduce){:root:not([data-motion=full]) ._toast_1818x_12{animation:none}}:root[data-motion=reduce] ._toast_1818x_12{animation:none}._wrap_1759l_1{display:flex;flex-direction:column;align-items:flex-start;gap:var(--space-3);max-width:640px;margin:var(--space-8) auto;padding:var(--space-6);border:1px solid var(--status-danger-solid);border-radius:var(--radius-lg);background:var(--status-danger-bg)}._title_1759l_14{font-size:var(--text-md-size);line-height:var(--text-md-line);font-weight:var(--font-weight-semibold);color:var(--status-danger-fg)}._detail_1759l_21{font-size:var(--text-sm-size);line-height:var(--text-sm-line);color:var(--text-secondary)}._retry_1759l_27{padding:var(--space-2) var(--space-4);border:1px solid var(--status-danger-solid);border-radius:var(--radius-sm);background:var(--bg-surface);color:var(--status-danger-fg);font-size:var(--text-sm-size);font-weight:var(--font-weight-medium);cursor:pointer}._retry_1759l_27:hover{background:var(--bg-hover)}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{r as t,j as s}from"./index-CpgkRaTi.js";const x="_region_1818x_1",w="_toast_1818x_12",v="_success_1818x_27",y="_danger_1818x_30",g="_dismiss_1818x_34",a={region:x,toast:w,"slide-in":"_slide-in_1818x_1",success:v,danger:y,dismiss:g},_=t.createContext(null);function k(){const o=t.useContext(_);if(!o)throw new Error("useToast() called outside <ToastProvider>");return o}const j=5e3;function N({children:o}){const[r,n]=t.useState([]),h=t.useRef(0),c=t.useCallback(e=>{n(d=>d.filter(i=>i.id!==e))},[]),u=t.useCallback((e,d="neutral")=>{const i=h.current++;n(p=>[...p,{id:i,message:e,tone:d}]),setTimeout(()=>c(i),j)},[c]),m=t.useMemo(()=>({show:u}),[u]);return s.jsxs(_.Provider,{value:m,children:[o,s.jsx("div",{className:a.region,role:"status","aria-live":"polite",children:r.map(e=>s.jsxs("div",{className:`${a.toast} ${a[e.tone]}`,children:[s.jsx("span",{children:e.message}),s.jsx("button",{type:"button",className:a.dismiss,onClick:()=>c(e.id),"aria-label":"Dismiss",children:"×"})]},e.id))})]})}const f="_wrap_1759l_1",T="_title_1759l_14",C="_detail_1759l_21",S="_retry_1759l_27",l={wrap:f,title:T,detail:C,retry:S};class D extends t.Component{state={error:null};static getDerivedStateFromError(r){return{error:r}}componentDidCatch(r,n){console.error("[ashlr] view crashed while rendering",r,n.componentStack)}componentDidUpdate(r){this.state.error&&r.resetKey!==this.props.resetKey&&this.setState({error:null})}render(){return this.state.error?s.jsxs("div",{className:l.wrap,role:"alert",children:[s.jsx("p",{className:l.title,children:"This view hit an error and couldn't render."}),s.jsxs("p",{className:l.detail,children:[this.state.error.message||"Unknown error."," — the rest of ashlr is still working; pick another view from the sidebar, or retry this one."]}),s.jsx("button",{type:"button",className:l.retry,onClick:()=>this.setState({error:null}),children:"Retry this view"})]}):this.props.children}}export{D as R,N as T,k as u};
|
|
2
|
-
//# sourceMappingURL=RouteErrorBoundary-CZd7ln8v.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"RouteErrorBoundary-CZd7ln8v.js","sources":["../../../../../../src/web-ui/components/primitives/Toast.tsx","../../../../../../src/web-ui/components/primitives/RouteErrorBoundary.tsx"],"sourcesContent":["/**\n * components/primitives/Toast.tsx — app-wide notifications. A single\n * aria-live region so screen readers announce toasts once, not per-toast\n * duplicate regions.\n */\nimport { createContext, useCallback, useContext, useMemo, useRef, useState, type ReactNode } from 'react';\nimport styles from './Toast.module.css';\n\nexport type ToastTone = 'neutral' | 'success' | 'danger';\n\ninterface ToastItem {\n id: number;\n message: string;\n tone: ToastTone;\n}\n\ninterface ToastContextValue {\n show: (message: string, tone?: ToastTone) => void;\n}\n\nconst ToastContext = createContext<ToastContextValue | null>(null);\n\nexport function useToast(): ToastContextValue {\n const ctx = useContext(ToastContext);\n if (!ctx) throw new Error('useToast() called outside <ToastProvider>');\n return ctx;\n}\n\nconst AUTO_DISMISS_MS = 5000;\n\nexport function ToastProvider({ children }: { children: ReactNode }) {\n const [toasts, setToasts] = useState<ToastItem[]>([]);\n const nextId = useRef(0);\n\n const dismiss = useCallback((id: number) => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, []);\n\n const show = useCallback(\n (message: string, tone: ToastTone = 'neutral') => {\n const id = nextId.current++;\n setToasts((prev) => [...prev, { id, message, tone }]);\n setTimeout(() => dismiss(id), AUTO_DISMISS_MS);\n },\n [dismiss],\n );\n\n const value = useMemo(() => ({ show }), [show]);\n\n return (\n <ToastContext.Provider value={value}>\n {children}\n <div className={styles.region} role=\"status\" aria-live=\"polite\">\n {toasts.map((t) => (\n <div key={t.id} className={`${styles.toast} ${styles[t.tone]}`}>\n <span>{t.message}</span>\n <button type=\"button\" className={styles.dismiss} onClick={() => dismiss(t.id)} aria-label=\"Dismiss\">\n ×\n </button>\n </div>\n ))}\n </div>\n </ToastContext.Provider>\n );\n}\n","/**\n * components/primitives/RouteErrorBoundary.tsx — the last line of defense\n * against a view crashing on real-world data that doesn't match its\n * expected shape (see SwarmsView.tsx's `plan?.tasks` guard for a concrete\n * example: 2 of 80 real swarm records on this machine predate the `plan`\n * field entirely).\n *\n * React error boundaries can only be class components — there is no hook\n * equivalent. Wraps `<Outlet/>` in Shell.tsx, not the whole app: if one\n * routed view throws during render, the sidebar/topbar/command palette\n * survive and the operator can navigate to a working view instead of being\n * stuck on a permanently blank screen (DESIGN.md §11 point 4 — \"never a\n * full-page error, the shell stays usable\" — extended here to cover\n * uncaught render exceptions, not just query-status `'error'`).\n */\nimport { Component, type ErrorInfo, type ReactNode } from 'react';\nimport styles from './RouteErrorBoundary.module.css';\n\ninterface Props {\n children: ReactNode;\n /** Identity that, when changed, resets the boundary — pass the route pathname. */\n resetKey: string;\n}\n\ninterface State {\n error: Error | null;\n}\n\nexport class RouteErrorBoundary extends Component<Props, State> {\n override state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n override componentDidCatch(error: Error, info: ErrorInfo) {\n console.error('[ashlr] view crashed while rendering', error, info.componentStack);\n }\n\n override componentDidUpdate(prevProps: Props) {\n if (this.state.error && prevProps.resetKey !== this.props.resetKey) {\n this.setState({ error: null });\n }\n }\n\n override render() {\n if (this.state.error) {\n return (\n <div className={styles.wrap} role=\"alert\">\n <p className={styles.title}>This view hit an error and couldn't render.</p>\n <p className={styles.detail}>\n {this.state.error.message || 'Unknown error.'} — the rest of ashlr is still working; pick another view\n from the sidebar, or retry this one.\n </p>\n <button type=\"button\" className={styles.retry} onClick={() => this.setState({ error: null })}>\n Retry this view\n </button>\n </div>\n );\n }\n return this.props.children;\n }\n}\n"],"names":["ToastContext","createContext","useToast","ctx","useContext","AUTO_DISMISS_MS","ToastProvider","children","toasts","setToasts","useState","nextId","useRef","dismiss","useCallback","id","prev","t","show","message","tone","value","useMemo","jsxs","jsx","styles","RouteErrorBoundary","Component","error","info","prevProps"],"mappings":"+OAoBMA,EAAeC,EAAAA,cAAwC,IAAI,EAE1D,SAASC,GAA8B,CAC5C,MAAMC,EAAMC,EAAAA,WAAWJ,CAAY,EACnC,GAAI,CAACG,EAAK,MAAM,IAAI,MAAM,2CAA2C,EACrE,OAAOA,CACT,CAEA,MAAME,EAAkB,IAEjB,SAASC,EAAc,CAAE,SAAAC,GAAqC,CACnE,KAAM,CAACC,EAAQC,CAAS,EAAIC,EAAAA,SAAsB,CAAA,CAAE,EAC9CC,EAASC,EAAAA,OAAO,CAAC,EAEjBC,EAAUC,cAAaC,GAAe,CAC1CN,EAAWO,GAASA,EAAK,OAAQC,GAAMA,EAAE,KAAOF,CAAE,CAAC,CACrD,EAAG,CAAA,CAAE,EAECG,EAAOJ,EAAAA,YACX,CAACK,EAAiBC,EAAkB,YAAc,CAChD,MAAML,EAAKJ,EAAO,UAClBF,EAAWO,GAAS,CAAC,GAAGA,EAAM,CAAE,GAAAD,EAAI,QAAAI,EAAS,KAAAC,CAAA,CAAM,CAAC,EACpD,WAAW,IAAMP,EAAQE,CAAE,EAAGV,CAAe,CAC/C,EACA,CAACQ,CAAO,CAAA,EAGJQ,EAAQC,EAAAA,QAAQ,KAAO,CAAE,KAAAJ,IAAS,CAACA,CAAI,CAAC,EAE9C,OACEK,EAAAA,KAACvB,EAAa,SAAb,CAAsB,MAAAqB,EACpB,SAAA,CAAAd,EACDiB,EAAAA,IAAC,MAAA,CAAI,UAAWC,EAAO,OAAQ,KAAK,SAAS,YAAU,SACpD,SAAAjB,EAAO,IAAKS,GACXM,EAAAA,KAAC,MAAA,CAAe,UAAW,GAAGE,EAAO,KAAK,IAAIA,EAAOR,EAAE,IAAI,CAAC,GAC1D,SAAA,CAAAO,EAAAA,IAAC,OAAA,CAAM,WAAE,OAAA,CAAQ,EACjBA,EAAAA,IAAC,SAAA,CAAO,KAAK,SAAS,UAAWC,EAAO,QAAS,QAAS,IAAMZ,EAAQI,EAAE,EAAE,EAAG,aAAW,UAAU,SAAA,GAAA,CAEpG,CAAA,GAJQA,EAAE,EAKZ,CACD,CAAA,CACH,CAAA,EACF,CAEJ,0HCpCO,MAAMS,UAA2BC,EAAAA,SAAwB,CACrD,MAAe,CAAE,MAAO,IAAA,EAEjC,OAAO,yBAAyBC,EAAqB,CACnD,MAAO,CAAE,MAAAA,CAAA,CACX,CAES,kBAAkBA,EAAcC,EAAiB,CACxD,QAAQ,MAAM,uCAAwCD,EAAOC,EAAK,cAAc,CAClF,CAES,mBAAmBC,EAAkB,CACxC,KAAK,MAAM,OAASA,EAAU,WAAa,KAAK,MAAM,UACxD,KAAK,SAAS,CAAE,MAAO,IAAA,CAAM,CAEjC,CAES,QAAS,CAChB,OAAI,KAAK,MAAM,aAEV,MAAA,CAAI,UAAWL,EAAO,KAAM,KAAK,QAChC,SAAA,CAAAD,EAAAA,IAAC,IAAA,CAAE,UAAWC,EAAO,MAAO,SAAA,8CAAgD,EAC5EF,EAAAA,KAAC,IAAA,CAAE,UAAWE,EAAO,OAClB,SAAA,CAAA,KAAK,MAAM,MAAM,SAAW,iBAAiB,+FAAA,EAEhD,QACC,SAAA,CAAO,KAAK,SAAS,UAAWA,EAAO,MAAO,QAAS,IAAM,KAAK,SAAS,CAAE,MAAO,IAAA,CAAM,EAAG,SAAA,iBAAA,CAE9F,CAAA,EACF,EAGG,KAAK,MAAM,QACpB,CACF"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{r as v,j as e}from"./index-CpgkRaTi.js";import{H as B,I as L,J as A,K as z,h as W,u as K,c as U,n as G,L as V}from"./global-BHjd6fVZ.js";import{B as Y,D as f,E as J,F as T,G as Q,H as X,J as Z,K as ee,L as ne,M as te,N as se,O as ae,Q as ie}from"./VerseConsoleApp-Cu5aG6J6.js";import"./index-CJ-e8YA9.js";import{u as re}from"./RouteErrorBoundary-CZd7ln8v.js";import{M as oe}from"./Meter-DRWZQgr1.js";import{S as q}from"./StatusBadge-DJw0LSPg.js";import{D as le}from"./Dialog-CNd7q89m.js";import"./queries-856qUN3Y.js";const ce="_field_ki2n9_1",de="_label_ki2n9_8",ue="_shell_ki2n9_15",he="_sm_ki2n9_29",pe="_input_ki2n9_33",me="_invalid_ki2n9_50",be="_mono_ki2n9_80",_e="_prefix_ki2n9_85",fe="_hint_ki2n9_91",xe="_error_ki2n9_97",x={field:ce,label:de,shell:ue,sm:he,input:pe,invalid:me,mono:be,prefix:_e,hint:fe,error:xe};function O({label:n,hint:t,error:s,size:i="md",mono:r=!1,prefix:o,className:d,id:c,...h}){const p=v.useId(),a=c??p,u=`${a}-hint`,m=`${a}-error`,_=[h["aria-describedby"],t?u:null,s?m:null].filter(Boolean).join(" ");return e.jsxs("div",{className:`${x.field} ${d??""}`,children:[n?e.jsx("label",{className:x.label,htmlFor:a,children:n}):null,e.jsxs("div",{className:`${x.shell} ${x[i]} ${s?x.invalid:""}`,children:[o?e.jsx("span",{className:x.prefix,children:o}):null,e.jsx("input",{...h,id:a,className:`${x.input} ${r?x.mono:""}`,"aria-invalid":s?!0:h["aria-invalid"],"aria-describedby":_||void 0})]}),t?e.jsx("p",{id:u,className:x.hint,children:t}):null,s?e.jsx("p",{id:m,className:x.error,role:"alert",children:s}):null]})}const ge="_group_15ia8_1",ve="_block_15ia8_11",je="_option_15ia8_16",we="_sm_15ia8_45",ke="_glyph_15ia8_72",w={group:ge,block:ve,option:je,sm:we,glyph:ke};function S({options:n,value:t,onChange:s,size:i="md",block:r=!1,className:o,...d}){const c=v.useRef(null);function h(p){const a=n.filter(_=>!_.disabled);if(a.length===0)return;const u=a.findIndex(_=>_.value===t),m=a[((u+p)%a.length+a.length)%a.length];s(m.value),requestAnimationFrame(()=>{c.current?.querySelector(`[data-value="${m.value}"]`)?.focus()})}return e.jsx("div",{ref:c,role:"radiogroup",className:`${w.group} ${w[i]} ${r?w.block:""} ${o??""}`,...d,children:n.map(p=>{const a=p.value===t;return e.jsxs("button",{type:"button",role:"radio","aria-checked":a,"aria-label":p.ariaLabel,"data-value":p.value,tabIndex:a?0:-1,disabled:p.disabled,className:w.option,onClick:()=>s(p.value),onKeyDown:u=>{u.key==="ArrowRight"||u.key==="ArrowDown"?(u.preventDefault(),h(1)):(u.key==="ArrowLeft"||u.key==="ArrowUp")&&(u.preventDefault(),h(-1))},children:[p.icon?e.jsx("span",{className:w.glyph,children:p.icon}):null,p.label]},p.value)})})}const ye="_field_228wn_1",Ne="_label_228wn_8",Se="_row_228wn_15",$e="_value_228wn_22",Ie="_input_228wn_32",k={field:ye,label:Ne,row:Se,value:$e,input:Ie};function C({label:n,value:t,min:s=0,max:i=100,valueLabel:r,valueText:o,trackImage:d,className:c,id:h,...p}){const a=v.useId(),u=h??a,m=Math.max(1,i-s),_=Math.round((t-s)/m*100);return e.jsxs("div",{className:`${k.field} ${c??""}`,children:[n?e.jsx("label",{className:k.label,htmlFor:u,children:n}):null,e.jsxs("div",{className:k.row,children:[e.jsx("input",{...p,id:u,type:"range",className:k.input,value:t,min:s,max:i,"aria-valuetext":o,style:{"--slider-fill":`${_}%`,...d?{"--slider-track-image":d}:{}},"data-custom-track":d?"true":void 0}),r!==void 0?e.jsx("span",{className:k.value,children:r}):null]})]})}const Ce="_wrapper_1xq82_1",Te="_label_1xq82_8",qe="_track_1xq82_13",Re="_knob_1xq82_44",$={wrapper:Ce,label:Te,track:qe,knob:Re};function Le({checked:n,onChange:t,label:s,disabled:i=!1,id:r,className:o,...d}){const c=e.jsx("button",{type:"button",id:r,role:"switch","aria-checked":n,disabled:i,className:$.track,onClick:()=>t(!n),...d,children:e.jsx("span",{className:$.knob,"aria-hidden":"true"})});return s?e.jsxs("label",{className:`${$.wrapper} ${o??""}`,children:[c,e.jsx("span",{className:$.label,children:s})]}):e.jsx("span",{className:o,children:c})}const Ae="_section_3qpbp_5",Me="_strip_3qpbp_13",De="_stripTitle_3qpbp_25",He="_scroll_3qpbp_32",Ee="_column_3qpbp_38",Pe="_panel_3qpbp_51",Oe="_panelHead_3qpbp_56",Fe="_panelTitle_3qpbp_64",Be="_panelBody_3qpbp_74",ze="_row_3qpbp_81",We="_rowStacked_3qpbp_90",Ke="_rowText_3qpbp_95",Ue="_rowLabel_3qpbp_99",Ge="_rowDescription_3qpbp_107",Ve="_rowControl_3qpbp_114",Ye="_swatches_3qpbp_140",Je="_swatch_3qpbp_140",Qe="_swatchCheck_3qpbp_165",Xe="_sliderStack_3qpbp_173",Ze="_contrastWarning_3qpbp_180",en="_preview_3qpbp_197",nn="_previewRow_3qpbp_207",tn="_previewHeading_3qpbp_214",sn="_previewBody_3qpbp_222",an="_previewNumerals_3qpbp_228",rn="_origin_3qpbp_238",on="_note_3qpbp_242",ln="_noteIcon_3qpbp_258",cn="_code_3qpbp_249",dn="_shortcuts_3qpbp_278",un="_shortcut_3qpbp_278",hn="_keys_3qpbp_294",pn="_key_3qpbp_294",mn="_about_3qpbp_315",bn="_aboutLine_3qpbp_321",_n="_aboutName_3qpbp_329",fn="_link_3qpbp_338",l={section:Ae,strip:Me,stripTitle:De,scroll:He,column:Ee,panel:Pe,panelHead:Oe,panelTitle:Fe,panelBody:Be,row:ze,rowStacked:We,rowText:Ke,rowLabel:Ue,rowDescription:Ge,rowControl:Ve,swatches:Ye,swatch:Je,swatchCheck:Qe,sliderStack:Xe,contrastWarning:Ze,preview:en,previewRow:nn,previewHeading:tn,previewBody:sn,previewNumerals:an,origin:rn,note:on,noteIcon:ln,code:cn,shortcuts:dn,shortcut:un,keys:hn,key:pn,about:mn,aboutLine:bn,aboutName:_n,link:fn};function N({title:n,action:t,children:s}){return e.jsxs("section",{className:l.panel,children:[e.jsxs("div",{className:l.panelHead,children:[e.jsx("h3",{className:l.panelTitle,children:n}),t]}),e.jsx("div",{className:l.panelBody,children:s})]})}function b({label:n,description:t,htmlFor:s,labelId:i,stacked:r=!1,children:o}){const d=e.jsxs(e.Fragment,{children:[e.jsx("span",{className:l.rowLabel,id:i,children:n}),t?e.jsx("span",{className:l.rowDescription,children:t}):null]});return e.jsxs("div",{className:`${l.row} ${r?l.rowStacked:""}`,children:[e.jsx("div",{className:l.rowText,children:s?e.jsx("label",{htmlFor:s,className:l.rowText,children:d}):d}),e.jsx("div",{className:l.rowControl,children:o})]})}function xn(n,t){return n?`Last completed ${new Date(n).toLocaleDateString()}.`:t?"Skipped. Nothing was missed — it is all reachable from the sections themselves.":"Not seen yet."}function gn(){const{completedAt:n,dismissedAt:t,open:s}=Y();return e.jsx(N,{title:"Onboarding",children:e.jsx(b,{label:"Replay the first-run tour",description:`Your connected seats, whether a local runtime is available, and what each of the three stop controls really halts. ${xn(n,t)}`,children:e.jsx(f,{variant:"subtle",size:"sm",onClick:J,disabled:s,children:s?"Showing":"Replay"})})})}const vn="3.5.0",jn=vn,wn="Ashlr Verse";function kn(){return e.jsx(N,{title:"About",children:e.jsx("div",{className:`${l.row} ${l.rowStacked}`,children:e.jsxs("div",{className:l.about,children:[e.jsx("p",{className:l.aboutName,children:wn}),e.jsxs("p",{className:l.aboutLine,children:[e.jsxs(T,{mono:!0,children:["v",jn]}),e.jsx("span",{children:"ashlr-hub — local-first command center for agentic engineers."})]}),e.jsx("p",{className:l.aboutLine,children:"Every session, token and artifact stays on this machine. The console talks to one local server and no third-party service."}),e.jsx("p",{className:l.aboutLine,children:e.jsxs("a",{className:l.link,href:"https://github.com/ashlrai/ashlr-hub",target:"_blank",rel:"noreferrer noopener",children:["Source and changelog",e.jsx(Q,{size:12})]})})]})})})}const yn=/^#([0-9a-f]{3,8})$/i,Nn=/^(rgba?|hsla?)\(([^)]*)\)$/i;function g(n,t,s){return Math.min(s,Math.max(t,n))}function j(n,t){const s=n.trim();return s.endsWith("%")?Number.parseFloat(s)/100*t:Number.parseFloat(s)}function F(n,t,s){const i=(n%360+360)%360,r=(1-Math.abs(2*s-1))*t,o=r*(1-Math.abs(i/60%2-1)),d=s-r/2;let c;return i<60?c=[r,o,0]:i<120?c=[o,r,0]:i<180?c=[0,r,o]:i<240?c=[0,o,r]:i<300?c=[o,0,r]:c=[r,0,o],{r:Math.round((c[0]+d)*255),g:Math.round((c[1]+d)*255),b:Math.round((c[2]+d)*255)}}function Sn(n){const t=[];let s=0,i="";for(const r of n){if(r==="("?s+=1:r===")"&&(s-=1),r===","&&s===0){t.push(i),i="";continue}i+=r}return t.push(i),t.map(r=>r.trim()).filter(r=>r.length>0)}function M(n){const t=n.trim(),s=/\s(\d*\.?\d+)%$/.exec(t);if(s)return{color:t.slice(0,s.index).trim(),pct:Number.parseFloat(s[1])};const i=/^(\d*\.?\d+)%\s/.exec(t);return i?{color:t.slice(i[0].length).trim(),pct:Number.parseFloat(i[1])}:{color:t,pct:null}}function $n(n){const t=/^color-mix\((.*)\)$/is.exec(n.trim());if(!t)return null;const s=Sn(t[1]);if(s.length!==3||s[0].replace(/\s+/g," ").trim()!=="in srgb")return null;const i=M(s[1]),r=M(s[2]);if(!i||!r)return null;const o=y(i.color),d=y(r.color);if(!o||!d)return null;let c=i.pct,h=r.pct;c===null&&h===null?(c=50,h=50):c===null?c=100-h:h===null&&(h=100-c);const p=c+h;if(p<=0)return null;const a=c/p,u=h/p,m=o.a*a+d.a*u;if(m<=0)return{r:0,g:0,b:0,a:0};const _=R=>g(Math.round((o[R]*o.a*a+d[R]*d.a*u)/m),0,255);return{r:_("r"),g:_("g"),b:_("b"),a:g(m,0,1)}}function y(n){const t=n.trim().toLowerCase();if(t==="transparent")return{r:0,g:0,b:0,a:0};if(t.startsWith("color-mix("))return $n(t);const s=yn.exec(t);if(s){const a=s[1],u=m=>Number.parseInt(m.length===1?m+m:m,16);return a.length===3||a.length===4?{r:u(a[0]),g:u(a[1]),b:u(a[2]),a:a.length===4?u(a[3])/255:1}:a.length===6||a.length===8?{r:u(a.slice(0,2)),g:u(a.slice(2,4)),b:u(a.slice(4,6)),a:a.length===8?u(a.slice(6,8))/255:1}:null}const i=Nn.exec(t);if(!i)return null;const r=i[1],o=i[2].replace(/\//g," ").split(/[\s,]+/).filter(Boolean);if(o.length<3)return null;const d=o.length>=4?g(j(o[3],1),0,1):1;if(r.startsWith("rgb"))return{r:g(Math.round(j(o[0],255)),0,255),g:g(Math.round(j(o[1],255)),0,255),b:g(Math.round(j(o[2],255)),0,255),a:d};const c=Number.parseFloat(o[0]),h=g(j(o[1],1),0,1),p=g(j(o[2],1),0,1);return Number.isFinite(c)?{...F(c,h,p),a:d}:null}function D(n,t){if(n.a>=1)return n;const s=n.a;return{r:Math.round(n.r*s+t.r*(1-s)),g:Math.round(n.g*s+t.g*(1-s)),b:Math.round(n.b*s+t.b*(1-s)),a:1}}function H(n){const t=s=>{const i=s/255;return i<=.03928?i/12.92:((i+.055)/1.055)**2.4};return .2126*t(n.r)+.7152*t(n.g)+.0722*t(n.b)}function E(n,t,s="#ffffff"){const i=y(t),r=y(n),o=y(s);if(!i||!r||!o)return null;const d=D(i,o),c=D(r,d),h=H(c),p=H(d),[a,u]=h>=p?[h,p]:[p,h];return(a+.05)/(u+.05)}function I(n,t,s,i=0){const r=F(n,g(t,0,100)/100,g(s+i,0,100)/100),o=d=>d.toString(16).padStart(2,"0");return`#${o(r.r)}${o(r.g)}${o(r.b)}`}const In="#ffffff",Cn="#121214",Tn=6,P=8,qn=[{value:"system",label:"System",icon:e.jsx(ee,{})},{value:"light",label:"Light",icon:e.jsx(ne,{})},{value:"dark",label:"Dark",icon:e.jsx(te,{})}],Rn=[{value:"comfortable",label:"Comfortable"},{value:"compact",label:"Compact"}],Ln=[{value:"grotesk",label:"Space Grotesk"},{value:"ui",label:"UI sans"},{value:"mono",label:"Mono"}],An=[{value:"sharp",label:"Sharp"},{value:"default",label:"Default"},{value:"soft",label:"Soft"}];function Mn(n,t){return`linear-gradient(to right, ${[0,60,120,180,240,300,360].map(i=>`${I(i,n,t)} ${i/360*100}%`).join(", ")})`}function Dn(n,t,s){const i=I(n,t,s,-P),r=I(n,t,s,Tn+P),o=E(i,In),d=E(r,Cn),c=[];return o!==null&&o<4.5&&c.push("light"),d!==null&&d<4.5&&c.push("dark"),{lightRatio:o,darkRatio:d,failing:c}}function Hn({appearance:n,onChange:t,onReset:s}){const i=v.useId(),r=v.useId(),o=v.useId(),d=v.useId(),c=v.useId(),h=B(n),p=Dn(n.accentH,n.accentS,n.accentL);return e.jsxs(N,{title:"Appearance",action:e.jsx(f,{variant:"ghost",size:"sm",onClick:s,disabled:z(n),title:"Restore the shipped theme, accent, density, font, radius and motion",children:"Reset to defaults"}),children:[e.jsx(b,{label:"Theme",description:"System follows your OS appearance setting.",children:e.jsx(S,{"aria-label":"Theme",options:qn,value:n.theme,onChange:a=>t({theme:a})})}),e.jsx(b,{label:"Accent",labelId:i,description:h?`${h.label} — used for links, focus rings and the one primary action per surface.`:"Custom hue — used for links, focus rings and the one primary action per surface.",children:e.jsx("div",{className:l.swatches,role:"radiogroup","aria-labelledby":i,children:L.map(a=>{const u=h?.id===a.id;return e.jsx("button",{type:"button",role:"radio","aria-checked":u,"aria-label":a.label,tabIndex:u||!h&&a.id===L[0].id?0:-1,className:l.swatch,style:{background:I(a.h,a.s,a.l)},onClick:()=>t({accentH:a.h,accentS:a.s,accentL:a.l}),children:u?e.jsx("span",{className:l.swatchCheck,children:e.jsx(X,{size:12})}):null},a.id)})})}),e.jsx(b,{label:"Accent channels",description:"Hue, saturation and lightness are written straight onto the root element — the whole app follows as you drag.",stacked:!0,children:e.jsxs("div",{className:l.sliderStack,children:[e.jsx(C,{id:r,label:"Hue",min:0,max:359,value:n.accentH,valueLabel:`${n.accentH}°`,valueText:`${n.accentH} degrees`,trackImage:Mn(n.accentS,n.accentL),onChange:a=>t({accentH:Number(a.currentTarget.value)})}),e.jsx(C,{id:o,label:"Saturation",min:0,max:100,value:n.accentS,valueLabel:`${n.accentS}%`,valueText:`${n.accentS} percent`,onChange:a=>t({accentS:Number(a.currentTarget.value)})}),e.jsx(C,{id:d,label:"Lightness",min:A.min,max:A.max,value:n.accentL,valueLabel:`${n.accentL}%`,valueText:`${n.accentL} percent`,onChange:a=>t({accentL:Number(a.currentTarget.value)})}),p.failing.length>0?e.jsxs("p",{className:l.contrastWarning,role:"status",children:[e.jsx(Z,{size:14}),e.jsxs("span",{children:["This accent falls below 4.5:1 as link text in"," ",p.failing.length===2?"both themes":`${p.failing[0]} mode`,". Raise or lower the lightness to keep it readable."]})]}):null]})}),e.jsx(b,{label:"Density",description:"Row height and control padding across every view.",children:e.jsx(S,{"aria-label":"Density",options:Rn,value:n.density,onChange:a=>t({density:a})})}),e.jsx(b,{label:"Display font",description:"Titles, seat names, metrics and numerals. Body copy stays in the UI sans.",children:e.jsx(S,{"aria-label":"Display font",options:Ln,value:n.displayFont,onChange:a=>t({displayFont:a})})}),e.jsx(b,{label:"Corner radius",description:"Sharp reads like a terminal; soft reads like a consumer app.",children:e.jsx(S,{"aria-label":"Corner radius",options:An,value:n.radius,onChange:a=>t({radius:a})})}),e.jsx(b,{label:"Reduce motion",htmlFor:c,description:"Collapses every transition to 1ms. Defaults to your system preference; turning it off here overrides that.",children:e.jsx(Le,{id:c,checked:n.reduceMotion,onChange:a=>t({reduceMotion:a}),"aria-label":"Reduce motion"})}),e.jsx(b,{label:"Preview",description:"Live — these are the real primitives, not a picture of them.",stacked:!0,children:e.jsxs("div",{className:l.preview,children:[e.jsx("p",{className:l.previewHeading,children:"Ashlr Verse"}),e.jsxs("p",{className:l.previewBody,children:["Body copy stays in the UI sans at the reading measure; numerals like"," ",e.jsx("span",{className:l.previewNumerals,children:"18,420 / 66,000"})," use the display face."]}),e.jsxs("div",{className:l.previewRow,children:[e.jsx(f,{variant:"primary",size:"sm",children:"Primary"}),e.jsx(f,{variant:"subtle",size:"sm",children:"Subtle"}),e.jsx(f,{variant:"ghost",size:"sm",children:"Ghost"}),e.jsx(f,{variant:"danger",size:"sm",children:"Destructive"})]}),e.jsxs("div",{className:l.previewRow,children:[e.jsx(q,{status:"running"}),e.jsx(T,{engine:"claude",children:"Claude Max"}),e.jsx(T,{engine:"local",mono:!0,children:"qwen3-coder"})]}),e.jsx(oe,{value:18420,max:66e3,label:"Context"}),e.jsx(O,{"aria-label":"Preview field",placeholder:"A field at the current density",size:"sm"})]})})]})}function En(n){if(n===null)return"locked";const t=Math.max(0,Math.round((n-Date.now())/6e4));return t<=0?"expiring now":`unlocked for ${t} more minute${t===1?"":"s"}`}function Pn(){const n=W(),t=K(),s=re(),[i,r]=v.useState(!1),o=v.useRef(null),d=typeof window>"u"?"":window.location.origin;async function c(){try{await navigator.clipboard.writeText(d),s.show("Server address copied.")}catch{s.show("Could not reach the clipboard — select the field and copy manually.","danger")}}async function h(){r(!1),await G(),s.show("Disconnected. Paste the read token to reconnect.")}return e.jsxs(N,{title:"Connection",children:[e.jsxs(b,{label:"Server",description:"This window talks to one local hub. Nothing leaves your machine.",children:[e.jsx("div",{className:l.origin,children:e.jsx(O,{value:d,readOnly:!0,mono:!0,size:"sm","aria-label":"Server address"})}),e.jsx(f,{variant:"ghost",size:"sm",icon:e.jsx(se,{}),onClick:()=>void c(),children:"Copy"})]}),e.jsx(b,{label:"Read session",description:"A 15-minute signed cookie, renewed silently while this tab stays open.",children:e.jsx(q,{status:n==="authenticated"?"connected":n==="checking"?"checking":"disconnected",tone:n==="authenticated"?"success":n==="checking"?"running":"danger"})}),e.jsxs(b,{label:"Mutation hold",description:"Every action that changes something needs the mutation token. It is held in memory only, never stored, and clears when this tab closes.",children:[e.jsx(q,{status:t.hasHold?En(t.heldUntil):"locked",tone:t.hasHold?"success":"neutral"}),e.jsx(f,{variant:"subtle",size:"sm",icon:e.jsx(ae,{}),onClick:()=>{U(),s.show("Mutation hold cleared.")},disabled:!t.hasHold,children:"Lock now"})]}),e.jsx(b,{label:"Disconnect",description:"Ends the read session in this browser and clears the mutation hold. Chats on the server are untouched.",children:e.jsx(f,{variant:"danger",size:"sm",onClick:()=>r(!0),children:"Disconnect"})}),e.jsx("div",{className:l.row,children:e.jsxs("p",{className:l.note,children:[e.jsx("span",{className:l.noteIcon,children:e.jsx(ie,{size:14})}),e.jsxs("span",{children:[e.jsx("strong",{children:"Where the tokens come from."})," Start the console with"," ",e.jsx("code",{className:l.code,children:"ashlr verse"})," — it prints a read token and a mutation token in that terminal, and opens this page. The desktop app injects both for you. Tokens are never displayed here, and the hub never writes them into a page, a log line or an API response. Lost them? Stop the server and start it again; it mints a fresh pair."]})]})}),e.jsx(le,{open:i,onClose:()=>r(!1),titleId:"verse-settings-disconnect",title:"Disconnect from this server?",description:"You will need the read token again to get back in. Running sessions keep running on the server.",initialFocusRef:o,children:e.jsxs("div",{className:l.previewRow,style:{justifyContent:"flex-end"},children:[e.jsx(f,{ref:o,variant:"subtle",onClick:()=>r(!1),children:"Cancel"}),e.jsx(f,{variant:"danger",onClick:()=>void h(),children:"Disconnect"})]})})]})}function On(){if(typeof navigator>"u")return!0;const n=`${navigator.platform??""} ${navigator.userAgent??""}`;return/mac|iphone|ipad|ipod/i.test(n)}function Fn(n){return[{title:"Navigation",items:[{keys:[n,"1"],action:"Chat"},{keys:[n,"2"],action:"Autonomy"},{keys:[n,"3"],action:"Approvals"},{keys:[n,"4"],action:"Usage"},{keys:[n,"5"],action:"Settings"},{keys:[n,"K"],action:"Quick switcher"},{keys:[n,","],action:"Settings"}]},{title:"Chat",items:[{keys:[n,"N"],action:"New chat"},{keys:["Enter"],action:"Send message"},{keys:["Shift","Enter"],action:"New line"},{keys:["Esc"],action:"Stop dictation / close overlay"}]}]}function Bn(){const n=On()?"⌘":"Ctrl";return e.jsx(N,{title:"Keyboard",children:e.jsx("div",{className:l.shortcuts,children:Fn(n).flatMap(t=>t.items.map(s=>e.jsxs("div",{className:l.shortcut,children:[e.jsx("span",{children:s.action}),e.jsx("span",{className:l.keys,children:s.keys.map(i=>e.jsx("kbd",{className:l.key,children:i},i))})]},`${t.title}-${s.action}-${s.keys.join("+")}`)))})})}function Xn(){const{appearance:n,set:t,reset:s}=V();return e.jsxs("div",{className:l.section,children:[e.jsx("header",{className:l.strip,"data-app-region":"drag",children:e.jsx("h2",{className:l.stripTitle,children:"Settings"})}),e.jsx("div",{className:l.scroll,children:e.jsxs("div",{className:l.column,children:[e.jsx(Hn,{appearance:n,onChange:t,onReset:s}),e.jsx(Pn,{}),e.jsx(Bn,{}),e.jsx(gn,{}),e.jsx(kn,{})]})})]})}export{Xn as SettingsSection};
|
|
2
|
-
//# sourceMappingURL=SettingsSection-C9Qs9JWW.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SettingsSection-C9Qs9JWW.js","sources":["../../../../../../src/web-ui/components/primitives/Input.tsx","../../../../../../src/web-ui/components/primitives/Segmented.tsx","../../../../../../src/web-ui/components/primitives/Slider.tsx","../../../../../../src/web-ui/components/primitives/Switch.tsx","../../../../../../src/web-ui/routes/verse/sections/SettingRow.tsx","../../../../../../src/web-ui/routes/verse/onboarding/OnboardingPanel.tsx","../../../../../../src/web-ui/routes/verse/sections/app-version.ts","../../../../../../src/web-ui/routes/verse/sections/AboutPanel.tsx","../../../../../../src/web-ui/design/contrast.ts","../../../../../../src/web-ui/routes/verse/sections/AppearancePanel.tsx","../../../../../../src/web-ui/routes/verse/sections/ConnectionPanel.tsx","../../../../../../src/web-ui/routes/verse/sections/ShortcutsPanel.tsx","../../../../../../src/web-ui/routes/verse/sections/SettingsSection.tsx"],"sourcesContent":["/**\n * components/primitives/Input.tsx — single-line text/number entry.\n *\n * Nothing here is a default browser control: hairline border, no inner card,\n * accent on focus. The accessible name comes from `label` when the field\n * stands alone, or from the caller's own `aria-label`/`aria-labelledby` when\n * it sits in a two-column settings row whose label lives on the other side.\n * An `error` is announced via role=\"alert\" and wired with aria-describedby —\n * red text alone never carries the message (design doc §6).\n */\nimport { useId, type InputHTMLAttributes, type ReactNode } from 'react';\nimport styles from './Input.module.css';\n\nexport interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'className' | 'prefix'> {\n label?: ReactNode;\n /** Quiet helper text under the field. */\n hint?: ReactNode;\n /** Error message; also flips the field into its invalid styling. */\n error?: ReactNode;\n size?: 'sm' | 'md';\n /** Paths, ids, tokens counts — anything that should not be kerned. */\n mono?: boolean;\n /** Non-interactive leading text (e.g. \"$\", \"http://\"). Shadows the rarely\n * used HTML `prefix` attribute on purpose — this is the useful meaning. */\n prefix?: ReactNode;\n className?: string;\n}\n\nexport function Input({\n label,\n hint,\n error,\n size = 'md',\n mono = false,\n prefix,\n className,\n id,\n ...rest\n}: InputProps) {\n const generatedId = useId();\n const inputId = id ?? generatedId;\n const hintId = `${inputId}-hint`;\n const errorId = `${inputId}-error`;\n const describedBy = [rest['aria-describedby'], hint ? hintId : null, error ? errorId : null]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div className={`${styles.field} ${className ?? ''}`}>\n {label ? (\n <label className={styles.label} htmlFor={inputId}>\n {label}\n </label>\n ) : null}\n <div className={`${styles.shell} ${styles[size]} ${error ? styles.invalid : ''}`}>\n {prefix ? <span className={styles.prefix}>{prefix}</span> : null}\n <input\n {...rest}\n id={inputId}\n className={`${styles.input} ${mono ? styles.mono : ''}`}\n aria-invalid={error ? true : rest['aria-invalid']}\n aria-describedby={describedBy || undefined}\n />\n </div>\n {hint ? (\n <p id={hintId} className={styles.hint}>\n {hint}\n </p>\n ) : null}\n {error ? (\n <p id={errorId} className={styles.error} role=\"alert\">\n {error}\n </p>\n ) : null}\n </div>\n );\n}\n","/**\n * components/primitives/Segmented.tsx — pick one of 2-4 options where the\n * choice applies instantly (theme, density, a status filter). It replaces\n * both a <select> (too heavy for three options) and a row of toggle buttons\n * (no single-selection semantics for a screen reader).\n *\n * Implemented as a radiogroup with ROVING TABINDEX: one Tab stop for the\n * group, arrows move between options and select as they go — the WAI-ARIA\n * radio-group pattern. Every option is reachable by keyboard and announced\n * as \"N of M\".\n */\nimport { useRef, type ReactNode } from 'react';\nimport styles from './Segmented.module.css';\n\nexport interface SegmentedOption<T extends string> {\n value: T;\n label: ReactNode;\n /** Leading 16px glyph; the text label always stays visible. */\n icon?: ReactNode;\n /** Spoken name when `label` is a glyph or an abbreviation. */\n ariaLabel?: string;\n disabled?: boolean;\n}\n\nexport interface SegmentedProps<T extends string> {\n options: ReadonlyArray<SegmentedOption<T>>;\n value: T;\n onChange: (next: T) => void;\n /** Accessible name for the group — required when no visible label precedes it. */\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n size?: 'sm' | 'md';\n /** Stretch each option to an equal share of the width. */\n block?: boolean;\n className?: string;\n}\n\nexport function Segmented<T extends string>({\n options,\n value,\n onChange,\n size = 'md',\n block = false,\n className,\n ...aria\n}: SegmentedProps<T>) {\n const groupRef = useRef<HTMLDivElement>(null);\n\n function move(delta: number): void {\n const enabled = options.filter((o) => !o.disabled);\n if (enabled.length === 0) return;\n const current = enabled.findIndex((o) => o.value === value);\n const next = enabled[(((current + delta) % enabled.length) + enabled.length) % enabled.length]!;\n onChange(next.value);\n // Keep DOM focus on the newly selected option (roving tabindex).\n requestAnimationFrame(() => {\n groupRef.current?.querySelector<HTMLButtonElement>(`[data-value=\"${next.value}\"]`)?.focus();\n });\n }\n\n return (\n <div\n ref={groupRef}\n role=\"radiogroup\"\n className={`${styles.group} ${styles[size]} ${block ? styles.block : ''} ${className ?? ''}`}\n {...aria}\n >\n {options.map((option) => {\n const selected = option.value === value;\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={selected}\n aria-label={option.ariaLabel}\n data-value={option.value}\n tabIndex={selected ? 0 : -1}\n disabled={option.disabled}\n className={styles.option}\n onClick={() => onChange(option.value)}\n onKeyDown={(e) => {\n if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {\n e.preventDefault();\n move(1);\n } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {\n e.preventDefault();\n move(-1);\n }\n }}\n >\n {option.icon ? <span className={styles.glyph}>{option.icon}</span> : null}\n {option.label}\n </button>\n );\n })}\n </div>\n );\n}\n","/**\n * components/primitives/Slider.tsx — a continuous value (accent hue,\n * saturation, a budget). Native <input type=\"range\"> so the platform's\n * keyboard model (arrows, Home/End, PageUp/PageDown) comes for free; the\n * track and thumb are restyled to the token system.\n *\n * `valueLabel` renders the number in the display face next to the control.\n * It is presentational: the control's own accessible value is carried by\n * aria-valuetext when a unit would otherwise be lost (\"245\" -> \"245 degrees\").\n */\nimport { useId, type InputHTMLAttributes, type ReactNode } from 'react';\nimport styles from './Slider.module.css';\n\nexport interface SliderProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'className' | 'value'> {\n label?: ReactNode;\n value: number;\n min?: number;\n max?: number;\n /** Rendered to the right of the track, in the display face. */\n valueLabel?: ReactNode;\n /** Spoken value, when the raw number needs a unit. */\n valueText?: string;\n /** Paint the filled portion of the track (hue sliders want a gradient instead). */\n trackImage?: string;\n className?: string;\n}\n\nexport function Slider({\n label,\n value,\n min = 0,\n max = 100,\n valueLabel,\n valueText,\n trackImage,\n className,\n id,\n ...rest\n}: SliderProps) {\n const generatedId = useId();\n const sliderId = id ?? generatedId;\n const span = Math.max(1, max - min);\n const percent = Math.round(((value - min) / span) * 100);\n\n return (\n <div className={`${styles.field} ${className ?? ''}`}>\n {label ? (\n <label className={styles.label} htmlFor={sliderId}>\n {label}\n </label>\n ) : null}\n <div className={styles.row}>\n <input\n {...rest}\n id={sliderId}\n type=\"range\"\n className={styles.input}\n value={value}\n min={min}\n max={max}\n aria-valuetext={valueText}\n style={\n {\n '--slider-fill': `${percent}%`,\n ...(trackImage ? { '--slider-track-image': trackImage } : {}),\n } as React.CSSProperties\n }\n data-custom-track={trackImage ? 'true' : undefined}\n />\n {valueLabel !== undefined ? <span className={styles.value}>{valueLabel}</span> : null}\n </div>\n </div>\n );\n}\n","/**\n * components/primitives/Switch.tsx — a binary setting that takes effect\n * immediately (no form submit). role=\"switch\" + aria-checked, so a screen\n * reader announces \"on\"/\"off\" rather than \"checkbox, checked\".\n *\n * State is never carried by color alone: the knob's POSITION is the primary\n * signal (design doc §6), the accent fill is reinforcement.\n */\nimport type { ReactNode } from 'react';\nimport styles from './Switch.module.css';\n\nexport interface SwitchProps {\n checked: boolean;\n onChange: (next: boolean) => void;\n /** Visible label; when omitted, pass `aria-label`. */\n label?: ReactNode;\n 'aria-label'?: string;\n 'aria-describedby'?: string;\n disabled?: boolean;\n id?: string;\n className?: string;\n}\n\nexport function Switch({\n checked,\n onChange,\n label,\n disabled = false,\n id,\n className,\n ...aria\n}: SwitchProps) {\n const control = (\n <button\n type=\"button\"\n id={id}\n role=\"switch\"\n aria-checked={checked}\n disabled={disabled}\n className={styles.track}\n onClick={() => onChange(!checked)}\n {...aria}\n >\n <span className={styles.knob} aria-hidden=\"true\" />\n </button>\n );\n\n if (!label) return <span className={className}>{control}</span>;\n\n return (\n <label className={`${styles.wrapper} ${className ?? ''}`}>\n {control}\n <span className={styles.label}>{label}</span>\n </label>\n );\n}\n","/**\n * routes/verse/sections/SettingRow.tsx — the Settings layout primitive:\n * label + description on the left, control on the right, hairline between.\n *\n * The label is a real <label> bound to the control's id when one is given;\n * for composite controls (a radiogroup, a swatch grid) pass `labelId` and\n * point the group's `aria-labelledby` at it instead — a <label> cannot name\n * a group, and an unnamed radiogroup is announced as \"group\".\n */\nimport type { ReactNode } from 'react';\nimport styles from './SettingsSection.module.css';\n\nexport interface PanelProps {\n title: ReactNode;\n /** Right-aligned affordance in the panel header (e.g. \"Reset\"). */\n action?: ReactNode;\n children: ReactNode;\n}\n\nexport function Panel({ title, action, children }: PanelProps) {\n return (\n <section className={styles.panel}>\n <div className={styles.panelHead}>\n <h3 className={styles.panelTitle}>{title}</h3>\n {action}\n </div>\n <div className={styles.panelBody}>{children}</div>\n </section>\n );\n}\n\nexport interface SettingRowProps {\n label: ReactNode;\n description?: ReactNode;\n /** id of the control this row labels (renders a real <label for>). */\n htmlFor?: string;\n /** id to put on the label text, for a control using aria-labelledby. */\n labelId?: string;\n /** Put the control under the text instead of beside it (sliders, previews). */\n stacked?: boolean;\n children: ReactNode;\n}\n\nexport function SettingRow({\n label,\n description,\n htmlFor,\n labelId,\n stacked = false,\n children,\n}: SettingRowProps) {\n const text = (\n <>\n <span className={styles.rowLabel} id={labelId}>\n {label}\n </span>\n {description ? <span className={styles.rowDescription}>{description}</span> : null}\n </>\n );\n\n return (\n <div className={`${styles.row} ${stacked ? styles.rowStacked : ''}`}>\n <div className={styles.rowText}>\n {htmlFor ? (\n <label htmlFor={htmlFor} className={styles.rowText}>\n {text}\n </label>\n ) : (\n text\n )}\n </div>\n <div className={styles.rowControl}>{children}</div>\n </div>\n );\n}\n","/**\n * routes/verse/onboarding/OnboardingPanel.tsx — the Settings row that brings\n * the first-run tour back.\n *\n * It lives here rather than in sections/ so the whole onboarding feature is\n * one folder; SettingsSection.tsx imports it the same way it imports its own\n * panels, and reuses the same Panel/SettingRow primitives so the row keeps\n * the label-left / control-right rhythm of every other setting.\n *\n * The description states what the tour actually covers, and — because this\n * is the only place the stored answer is visible — whether it has been seen.\n */\nimport { Button } from '../../../components/primitives/index.js';\nimport { Panel, SettingRow } from '../sections/SettingRow.js';\nimport { replayOnboarding } from './onboarding-store.js';\nimport { useOnboarding } from './useOnboarding.js';\n\nfunction describe(completedAt: string | null, dismissedAt: string | null): string {\n if (completedAt) return `Last completed ${new Date(completedAt).toLocaleDateString()}.`;\n if (dismissedAt) return 'Skipped. Nothing was missed — it is all reachable from the sections themselves.';\n return 'Not seen yet.';\n}\n\nexport function OnboardingPanel() {\n const { completedAt, dismissedAt, open } = useOnboarding();\n\n return (\n <Panel title=\"Onboarding\">\n <SettingRow\n label=\"Replay the first-run tour\"\n description={`Your connected seats, whether a local runtime is available, and what each of the three stop controls really halts. ${describe(completedAt, dismissedAt)}`}\n >\n <Button variant=\"subtle\" size=\"sm\" onClick={replayOnboarding} disabled={open}>\n {open ? 'Showing' : 'Replay'}\n </Button>\n </SettingRow>\n </Panel>\n );\n}\n","/**\n * routes/verse/sections/app-version.ts — the hub's version, for About.\n *\n * Read straight from package.json (Vite inlines the named export at build\n * time and `resolveJsonModule` types it), because no API route reports it:\n * /api/health answers liveness, /api/snapshot answers fleet state, and\n * neither carries the running hub's version. A hardcoded string here would\n * silently drift from the published package on every release.\n */\nimport { version } from '../../../../../package.json';\n\nexport const APP_VERSION: string = version;\nexport const APP_NAME = 'Ashlr Verse';\n","/**\n * routes/verse/sections/AboutPanel.tsx — what this is and which build it is.\n * The version comes from package.json at build time (./app-version.ts).\n */\nimport { IconExternalLink } from '../../../components/primitives/icons.js';\nimport { Tag } from '../../../components/primitives/index.js';\nimport { APP_NAME, APP_VERSION } from './app-version.js';\nimport { Panel } from './SettingRow.js';\nimport styles from './SettingsSection.module.css';\n\nexport function AboutPanel() {\n return (\n <Panel title=\"About\">\n <div className={`${styles.row} ${styles.rowStacked}`}>\n <div className={styles.about}>\n <p className={styles.aboutName}>{APP_NAME}</p>\n <p className={styles.aboutLine}>\n <Tag mono>v{APP_VERSION}</Tag>\n <span>ashlr-hub — local-first command center for agentic engineers.</span>\n </p>\n <p className={styles.aboutLine}>\n Every session, token and artifact stays on this machine. The console talks to one local server and no\n third-party service.\n </p>\n <p className={styles.aboutLine}>\n <a\n className={styles.link}\n href=\"https://github.com/ashlrai/ashlr-hub\"\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n >\n Source and changelog\n <IconExternalLink size={12} />\n </a>\n </p>\n </div>\n </div>\n </Panel>\n );\n}\n","/**\n * design/contrast.ts — WCAG 2.1 contrast math over CSS color strings.\n *\n * Two callers, one implementation:\n * - routes/verse/sections/AppearancePanel.tsx warns, live, when a\n * hand-dragged accent stops being readable as link/button text in the\n * active theme. The design language allows any hue; it does not allow an\n * unreadable one to ship silently.\n * - design/tokens-contrast.test.ts asserts the whole palette in BOTH\n * themes (design doc §6: >= 4.5:1 body text, >= 3:1 meaningful borders).\n *\n * Deliberately dependency-free and DOM-free: parse -> linearize -> ratio.\n * Supports the subset of CSS color syntax the stylesheets actually use —\n * #rgb / #rrggbb / #rrggbbaa, rgb()/rgba(), hsl()/hsla(), both the legacy\n * comma form and the modern space form, plus `color-mix(in srgb, ...)`.\n * Anything else returns null rather than guessing a color.\n *\n * `color-mix` is in that list because the meaning-carrying marks that the\n * contrast suite has to guard are not all plain tokens: the chart gridline,\n * the empty half of a window meter and the diff row tints are all declared as\n * a mix in a CSS module. Without this the suite could only assert the token a\n * mix is DERIVED from, which is precisely the gap that let a 45%-alpha\n * gridline ship under a comment claiming it cleared 3:1.\n */\n\nexport interface Rgba {\n /** 0-255 */\n r: number;\n /** 0-255 */\n g: number;\n /** 0-255 */\n b: number;\n /** 0-1 */\n a: number;\n}\n\nconst HEX_RE = /^#([0-9a-f]{3,8})$/i;\nconst FN_RE = /^(rgba?|hsla?)\\(([^)]*)\\)$/i;\n\nfunction clamp(n: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, n));\n}\n\n/** \"50%\" -> 0.5, \"0.5\" -> 0.5, \"128\" (of 255) handled by the caller. */\nfunction unitValue(raw: string, scale: number): number {\n const text = raw.trim();\n if (text.endsWith('%')) return (Number.parseFloat(text) / 100) * scale;\n return Number.parseFloat(text);\n}\n\nfunction hslToRgb(h: number, s: number, l: number): { r: number; g: number; b: number } {\n const hue = ((h % 360) + 360) % 360;\n const c = (1 - Math.abs(2 * l - 1)) * s;\n const x = c * (1 - Math.abs(((hue / 60) % 2) - 1));\n const m = l - c / 2;\n let rgb: [number, number, number];\n if (hue < 60) rgb = [c, x, 0];\n else if (hue < 120) rgb = [x, c, 0];\n else if (hue < 180) rgb = [0, c, x];\n else if (hue < 240) rgb = [0, x, c];\n else if (hue < 300) rgb = [x, 0, c];\n else rgb = [c, 0, x];\n return {\n r: Math.round((rgb[0] + m) * 255),\n g: Math.round((rgb[1] + m) * 255),\n b: Math.round((rgb[2] + m) * 255),\n };\n}\n\n/**\n * Split a function's argument list on top-level commas, so a nested\n * `rgb(...)`/`color-mix(...)` argument survives intact.\n */\nfunction splitTopLevel(text: string): string[] {\n const parts: string[] = [];\n let depth = 0;\n let current = '';\n for (const ch of text) {\n if (ch === '(') depth += 1;\n else if (ch === ')') depth -= 1;\n if (ch === ',' && depth === 0) {\n parts.push(current);\n current = '';\n continue;\n }\n current += ch;\n }\n parts.push(current);\n return parts.map((p) => p.trim()).filter((p) => p.length > 0);\n}\n\n/** `#abc 40%` -> ['#abc', 40]; a missing percentage comes back as null. */\nfunction colorWithPercent(raw: string): { color: string; pct: number | null } | null {\n const text = raw.trim();\n const m = /\\s(\\d*\\.?\\d+)%$/.exec(text);\n if (m) return { color: text.slice(0, m.index).trim(), pct: Number.parseFloat(m[1]!) };\n const lead = /^(\\d*\\.?\\d+)%\\s/.exec(text);\n if (lead) return { color: text.slice(lead[0].length).trim(), pct: Number.parseFloat(lead[1]!) };\n return { color: text, pct: null };\n}\n\n/**\n * `color-mix(in srgb, <color> [p%], <color> [p%])`, per CSS Color 5: the two\n * percentages are normalized to sum to 100, the result's alpha is their\n * alpha-weighted sum, and the channels are mixed PREMULTIPLIED — which is why\n * mixing against `transparent` yields the first color at that alpha rather\n * than a color darkened toward black.\n *\n * Only the `srgb` color space is accepted. Every other space would need its\n * own transfer function, and silently treating `oklab` as srgb would report a\n * contrast ratio the browser does not agree with.\n */\nfunction parseColorMix(text: string): Rgba | null {\n const body = /^color-mix\\((.*)\\)$/is.exec(text.trim());\n if (!body) return null;\n const args = splitTopLevel(body[1]!);\n if (args.length !== 3) return null;\n if (args[0]!.replace(/\\s+/g, ' ').trim() !== 'in srgb') return null;\n\n const first = colorWithPercent(args[1]!);\n const second = colorWithPercent(args[2]!);\n if (!first || !second) return null;\n const c1 = parseColor(first.color);\n const c2 = parseColor(second.color);\n if (!c1 || !c2) return null;\n\n let p1 = first.pct;\n let p2 = second.pct;\n if (p1 === null && p2 === null) {\n p1 = 50;\n p2 = 50;\n } else if (p1 === null) p1 = 100 - p2!;\n else if (p2 === null) p2 = 100 - p1;\n const total = p1 + p2!;\n if (total <= 0) return null;\n const w1 = p1 / total;\n const w2 = p2! / total;\n\n const alpha = c1.a * w1 + c2.a * w2;\n if (alpha <= 0) return { r: 0, g: 0, b: 0, a: 0 };\n const channel = (k: 'r' | 'g' | 'b'): number =>\n clamp(Math.round((c1[k] * c1.a * w1 + c2[k] * c2.a * w2) / alpha), 0, 255);\n return { r: channel('r'), g: channel('g'), b: channel('b'), a: clamp(alpha, 0, 1) };\n}\n\n/** Parse a CSS color string. Returns null for anything unrecognized. */\nexport function parseColor(input: string): Rgba | null {\n const text = input.trim().toLowerCase();\n if (text === 'transparent') return { r: 0, g: 0, b: 0, a: 0 };\n if (text.startsWith('color-mix(')) return parseColorMix(text);\n\n const hex = HEX_RE.exec(text);\n if (hex) {\n const body = hex[1]!;\n const expand = (s: string) => Number.parseInt(s.length === 1 ? s + s : s, 16);\n if (body.length === 3 || body.length === 4) {\n return {\n r: expand(body[0]!),\n g: expand(body[1]!),\n b: expand(body[2]!),\n a: body.length === 4 ? expand(body[3]!) / 255 : 1,\n };\n }\n if (body.length === 6 || body.length === 8) {\n return {\n r: expand(body.slice(0, 2)),\n g: expand(body.slice(2, 4)),\n b: expand(body.slice(4, 6)),\n a: body.length === 8 ? expand(body.slice(6, 8)) / 255 : 1,\n };\n }\n return null;\n }\n\n const fn = FN_RE.exec(text);\n if (!fn) return null;\n const name = fn[1]!;\n // Both syntaxes: `a, b, c, d` and `a b c / d`.\n const parts = fn[2]!\n .replace(/\\//g, ' ')\n .split(/[\\s,]+/)\n .filter(Boolean);\n if (parts.length < 3) return null;\n const alpha = parts.length >= 4 ? clamp(unitValue(parts[3]!, 1), 0, 1) : 1;\n\n if (name.startsWith('rgb')) {\n return {\n r: clamp(Math.round(unitValue(parts[0]!, 255)), 0, 255),\n g: clamp(Math.round(unitValue(parts[1]!, 255)), 0, 255),\n b: clamp(Math.round(unitValue(parts[2]!, 255)), 0, 255),\n a: alpha,\n };\n }\n\n const hue = Number.parseFloat(parts[0]!);\n const sat = clamp(unitValue(parts[1]!, 1), 0, 1);\n const light = clamp(unitValue(parts[2]!, 1), 0, 1);\n if (!Number.isFinite(hue)) return null;\n return { ...hslToRgb(hue, sat, light), a: alpha };\n}\n\n/** Composite a (possibly translucent) color over an opaque backdrop. */\nexport function flatten(color: Rgba, backdrop: Rgba): Rgba {\n if (color.a >= 1) return color;\n const a = color.a;\n return {\n r: Math.round(color.r * a + backdrop.r * (1 - a)),\n g: Math.round(color.g * a + backdrop.g * (1 - a)),\n b: Math.round(color.b * a + backdrop.b * (1 - a)),\n a: 1,\n };\n}\n\n/** WCAG relative luminance of an opaque color. */\nexport function relativeLuminance(color: Rgba): number {\n const channel = (v: number): number => {\n const s = v / 255;\n return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;\n };\n return 0.2126 * channel(color.r) + 0.7152 * channel(color.g) + 0.0722 * channel(color.b);\n}\n\n/**\n * WCAG contrast ratio (1-21) between two CSS colors. A translucent color is\n * composited over `backdrop` first (default white) — asking for the contrast\n * of a 14%-alpha status background is otherwise meaningless.\n * Returns null when either color cannot be parsed, so a caller can say\n * \"unknown\" instead of asserting on a guess.\n */\nexport function contrastRatio(foreground: string, background: string, backdrop = '#ffffff'): number | null {\n const bgRaw = parseColor(background);\n const fgRaw = parseColor(foreground);\n const base = parseColor(backdrop);\n if (!bgRaw || !fgRaw || !base) return null;\n const bg = flatten(bgRaw, base);\n const fg = flatten(fgRaw, bg);\n const l1 = relativeLuminance(fg);\n const l2 = relativeLuminance(bg);\n const [hi, lo] = l1 >= l2 ? [l1, l2] : [l2, l1];\n return (hi + 0.05) / (lo + 0.05);\n}\n\n/** Convenience for the appearance panel: does this pair clear body-text contrast? */\nexport function meetsTextContrast(foreground: string, background: string, backdrop?: string): boolean {\n const ratio = contrastRatio(foreground, background, backdrop);\n return ratio !== null && ratio >= 4.5;\n}\n\n/**\n * The accent, resolved to a hex the same way tokens.css derives its ramp\n * (hsl channels + a per-step lightness offset). Used by the appearance panel\n * to preview and contrast-check a hue the operator is dragging, without\n * reading computed styles mid-drag.\n */\nexport function accentHex(h: number, s: number, l: number, lightnessOffset = 0): string {\n const rgb = hslToRgb(h, clamp(s, 0, 100) / 100, clamp(l + lightnessOffset, 0, 100) / 100);\n const hex = (n: number) => n.toString(16).padStart(2, '0');\n return `#${hex(rgb.r)}${hex(rgb.g)}${hex(rgb.b)}`;\n}\n","/**\n * routes/verse/sections/AppearancePanel.tsx — the \"Linux\" part of the design\n * language: theme, accent, density, display face, radius, motion.\n *\n * Every control applies IMMEDIATELY (design doc §3: live preview, no save\n * button) because the whole app is the preview — the panel writes through\n * data/appearance-store.ts, which writes the tokens on <html>. The preview\n * block at the end exists to show type, numerals, a filled action and a\n * meter in one place, so the effect of a change is visible without leaving\n * Settings.\n *\n * The hue slider is free-range, so the panel checks the resulting link color\n * against BOTH themes with design/contrast.ts and warns when a choice drops\n * under 4.5:1 — the operator keeps the hue they asked for, but is never\n * allowed to make it unreadable without being told.\n */\nimport { useId } from 'react';\nimport { Button, Input, Meter, Segmented, Slider, StatusBadge, Switch, Tag } from '../../../components/primitives/index.js';\nimport { IconAlert, IconCheck, IconMonitor, IconMoon, IconSun } from '../../../components/primitives/icons.js';\nimport { accentHex, contrastRatio } from '../../../design/contrast.js';\nimport {\n ACCENT_LIGHTNESS_RANGE,\n ACCENT_PRESETS,\n isDefaultAppearance,\n matchingAccentPreset,\n type Appearance,\n type Density,\n type DisplayFont,\n type RadiusScale,\n type ThemePreference,\n} from '../../../data/appearance-store.js';\nimport { Panel, SettingRow } from './SettingRow.js';\nimport styles from './SettingsSection.module.css';\n\n/**\n * The literal `--bg-surface` of each theme (design/tokens.css). Used only to\n * score a candidate accent; design/tokens-contrast.test.ts asserts these two\n * constants still match the stylesheet, so a future retune cannot leave the\n * warning scoring against a color the app no longer paints.\n */\nexport const LIGHT_SURFACE = '#ffffff';\nexport const DARK_SURFACE = '#121214';\n/** Dark raises accent lightness by --accent-l-shift; --accent-600 sits 8% below/above it. */\nconst DARK_L_SHIFT = 6;\nconst LINK_STEP = 8;\n\nconst THEME_OPTIONS = [\n { value: 'system' as ThemePreference, label: 'System', icon: <IconMonitor /> },\n { value: 'light' as ThemePreference, label: 'Light', icon: <IconSun /> },\n { value: 'dark' as ThemePreference, label: 'Dark', icon: <IconMoon /> },\n];\n\nconst DENSITY_OPTIONS = [\n { value: 'comfortable' as Density, label: 'Comfortable' },\n { value: 'compact' as Density, label: 'Compact' },\n];\n\nconst FONT_OPTIONS = [\n { value: 'grotesk' as DisplayFont, label: 'Space Grotesk' },\n { value: 'ui' as DisplayFont, label: 'UI sans' },\n { value: 'mono' as DisplayFont, label: 'Mono' },\n];\n\nconst RADIUS_OPTIONS = [\n { value: 'sharp' as RadiusScale, label: 'Sharp' },\n { value: 'default' as RadiusScale, label: 'Default' },\n { value: 'soft' as RadiusScale, label: 'Soft' },\n];\n\n/** A 360° sweep at the current saturation/lightness, so the track shows the choice. */\nfunction hueTrack(s: number, l: number): string {\n const stops = [0, 60, 120, 180, 240, 300, 360].map((h) => `${accentHex(h, s, l)} ${(h / 360) * 100}%`);\n return `linear-gradient(to right, ${stops.join(', ')})`;\n}\n\nexport interface AccentReadability {\n lightRatio: number | null;\n darkRatio: number | null;\n /** Themes in which the derived link color drops below 4.5:1. */\n failing: Array<'light' | 'dark'>;\n}\n\n/** Exported for the section's test: the same math the warning renders from. */\nexport function accentReadability(h: number, s: number, l: number): AccentReadability {\n const lightLink = accentHex(h, s, l, -LINK_STEP);\n const darkLink = accentHex(h, s, l, DARK_L_SHIFT + LINK_STEP);\n const lightRatio = contrastRatio(lightLink, LIGHT_SURFACE);\n const darkRatio = contrastRatio(darkLink, DARK_SURFACE);\n const failing: Array<'light' | 'dark'> = [];\n if (lightRatio !== null && lightRatio < 4.5) failing.push('light');\n if (darkRatio !== null && darkRatio < 4.5) failing.push('dark');\n return { lightRatio, darkRatio, failing };\n}\n\nexport interface AppearancePanelProps {\n appearance: Appearance;\n onChange: (patch: Partial<Appearance>) => void;\n onReset: () => void;\n}\n\nexport function AppearancePanel({ appearance, onChange, onReset }: AppearancePanelProps) {\n const accentLabelId = useId();\n const hueId = useId();\n const satId = useId();\n const lightId = useId();\n const motionId = useId();\n\n const preset = matchingAccentPreset(appearance);\n const readability = accentReadability(appearance.accentH, appearance.accentS, appearance.accentL);\n\n return (\n <Panel\n title=\"Appearance\"\n action={\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={onReset}\n disabled={isDefaultAppearance(appearance)}\n title=\"Restore the shipped theme, accent, density, font, radius and motion\"\n >\n Reset to defaults\n </Button>\n }\n >\n <SettingRow label=\"Theme\" description=\"System follows your OS appearance setting.\">\n <Segmented\n aria-label=\"Theme\"\n options={THEME_OPTIONS}\n value={appearance.theme}\n onChange={(theme) => onChange({ theme })}\n />\n </SettingRow>\n\n <SettingRow\n label=\"Accent\"\n labelId={accentLabelId}\n description={\n preset\n ? `${preset.label} — used for links, focus rings and the one primary action per surface.`\n : 'Custom hue — used for links, focus rings and the one primary action per surface.'\n }\n >\n <div className={styles.swatches} role=\"radiogroup\" aria-labelledby={accentLabelId}>\n {ACCENT_PRESETS.map((p) => {\n const selected = preset?.id === p.id;\n return (\n <button\n key={p.id}\n type=\"button\"\n role=\"radio\"\n aria-checked={selected}\n aria-label={p.label}\n tabIndex={selected || (!preset && p.id === ACCENT_PRESETS[0]!.id) ? 0 : -1}\n className={styles.swatch}\n style={{ background: accentHex(p.h, p.s, p.l) }}\n onClick={() => onChange({ accentH: p.h, accentS: p.s, accentL: p.l })}\n >\n {selected ? (\n <span className={styles.swatchCheck}>\n <IconCheck size={12} />\n </span>\n ) : null}\n </button>\n );\n })}\n </div>\n </SettingRow>\n\n <SettingRow\n label=\"Accent channels\"\n description=\"Hue, saturation and lightness are written straight onto the root element — the whole app follows as you drag.\"\n stacked\n >\n <div className={styles.sliderStack}>\n <Slider\n id={hueId}\n label=\"Hue\"\n min={0}\n max={359}\n value={appearance.accentH}\n valueLabel={`${appearance.accentH}°`}\n valueText={`${appearance.accentH} degrees`}\n trackImage={hueTrack(appearance.accentS, appearance.accentL)}\n onChange={(e) => onChange({ accentH: Number(e.currentTarget.value) })}\n />\n <Slider\n id={satId}\n label=\"Saturation\"\n min={0}\n max={100}\n value={appearance.accentS}\n valueLabel={`${appearance.accentS}%`}\n valueText={`${appearance.accentS} percent`}\n onChange={(e) => onChange({ accentS: Number(e.currentTarget.value) })}\n />\n <Slider\n id={lightId}\n label=\"Lightness\"\n min={ACCENT_LIGHTNESS_RANGE.min}\n max={ACCENT_LIGHTNESS_RANGE.max}\n value={appearance.accentL}\n valueLabel={`${appearance.accentL}%`}\n valueText={`${appearance.accentL} percent`}\n onChange={(e) => onChange({ accentL: Number(e.currentTarget.value) })}\n />\n {readability.failing.length > 0 ? (\n <p className={styles.contrastWarning} role=\"status\">\n <IconAlert size={14} />\n <span>\n This accent falls below 4.5:1 as link text in{' '}\n {readability.failing.length === 2 ? 'both themes' : `${readability.failing[0]} mode`}. Raise or lower\n the lightness to keep it readable.\n </span>\n </p>\n ) : null}\n </div>\n </SettingRow>\n\n <SettingRow label=\"Density\" description=\"Row height and control padding across every view.\">\n <Segmented\n aria-label=\"Density\"\n options={DENSITY_OPTIONS}\n value={appearance.density}\n onChange={(density) => onChange({ density })}\n />\n </SettingRow>\n\n <SettingRow label=\"Display font\" description=\"Titles, seat names, metrics and numerals. Body copy stays in the UI sans.\">\n <Segmented\n aria-label=\"Display font\"\n options={FONT_OPTIONS}\n value={appearance.displayFont}\n onChange={(displayFont) => onChange({ displayFont })}\n />\n </SettingRow>\n\n <SettingRow label=\"Corner radius\" description=\"Sharp reads like a terminal; soft reads like a consumer app.\">\n <Segmented\n aria-label=\"Corner radius\"\n options={RADIUS_OPTIONS}\n value={appearance.radius}\n onChange={(radius) => onChange({ radius })}\n />\n </SettingRow>\n\n <SettingRow\n label=\"Reduce motion\"\n htmlFor={motionId}\n description=\"Collapses every transition to 1ms. Defaults to your system preference; turning it off here overrides that.\"\n >\n <Switch\n id={motionId}\n checked={appearance.reduceMotion}\n onChange={(reduceMotion) => onChange({ reduceMotion })}\n aria-label=\"Reduce motion\"\n />\n </SettingRow>\n\n <SettingRow label=\"Preview\" description=\"Live — these are the real primitives, not a picture of them.\" stacked>\n <div className={styles.preview}>\n <p className={styles.previewHeading}>Ashlr Verse</p>\n <p className={styles.previewBody}>\n Body copy stays in the UI sans at the reading measure; numerals like{' '}\n <span className={styles.previewNumerals}>18,420 / 66,000</span> use the display face.\n </p>\n <div className={styles.previewRow}>\n <Button variant=\"primary\" size=\"sm\">\n Primary\n </Button>\n <Button variant=\"subtle\" size=\"sm\">\n Subtle\n </Button>\n <Button variant=\"ghost\" size=\"sm\">\n Ghost\n </Button>\n <Button variant=\"danger\" size=\"sm\">\n Destructive\n </Button>\n </div>\n <div className={styles.previewRow}>\n <StatusBadge status=\"running\" />\n <Tag engine=\"claude\">Claude Max</Tag>\n <Tag engine=\"local\" mono>\n qwen3-coder\n </Tag>\n </div>\n <Meter value={18_420} max={66_000} label=\"Context\" />\n <Input aria-label=\"Preview field\" placeholder=\"A field at the current density\" size=\"sm\" />\n </div>\n </SettingRow>\n </Panel>\n );\n}\n","/**\n * routes/verse/sections/ConnectionPanel.tsx — which server this window is\n * talking to, what authority it currently holds, and how to get the tokens\n * back if it loses them.\n *\n * SECURITY: this panel never renders, copies or logs a token. It shows the\n * STATE of the two authorities (read session, mutation hold) and tells the\n * operator where the real values are printed — the terminal that started the\n * server. The mutation token is memory-only by design (data/auth-store.ts);\n * showing it here would put it on screen, in a screenshot, and in any\n * screen-recording of a demo.\n */\nimport { useRef, useState } from 'react';\nimport { Button, Dialog, Input, StatusBadge } from '../../../components/primitives/index.js';\nimport { IconCopy, IconInfo, IconLock } from '../../../components/primitives/icons.js';\nimport { clearMutationToken, clearReadSession } from '../../../data/auth-store.js';\nimport { useAuthPhase, useMutationHold } from '../../../data/hooks.js';\nimport { useToast } from '../../../components/primitives/Toast.js';\nimport { Panel, SettingRow } from './SettingRow.js';\nimport styles from './SettingsSection.module.css';\n\nfunction formatHoldExpiry(heldUntil: number | null): string {\n if (heldUntil === null) return 'locked';\n const minutes = Math.max(0, Math.round((heldUntil - Date.now()) / 60_000));\n if (minutes <= 0) return 'expiring now';\n return `unlocked for ${minutes} more minute${minutes === 1 ? '' : 's'}`;\n}\n\nexport function ConnectionPanel() {\n const phase = useAuthPhase();\n const hold = useMutationHold();\n const toast = useToast();\n const [confirmOpen, setConfirmOpen] = useState(false);\n const cancelRef = useRef<HTMLButtonElement>(null);\n\n const origin = typeof window === 'undefined' ? '' : window.location.origin;\n\n async function copyOrigin(): Promise<void> {\n try {\n await navigator.clipboard.writeText(origin);\n toast.show('Server address copied.');\n } catch {\n toast.show('Could not reach the clipboard — select the field and copy manually.', 'danger');\n }\n }\n\n async function disconnect(): Promise<void> {\n setConfirmOpen(false);\n await clearReadSession();\n toast.show('Disconnected. Paste the read token to reconnect.');\n }\n\n return (\n <Panel title=\"Connection\">\n <SettingRow label=\"Server\" description=\"This window talks to one local hub. Nothing leaves your machine.\">\n <div className={styles.origin}>\n <Input value={origin} readOnly mono size=\"sm\" aria-label=\"Server address\" />\n </div>\n <Button variant=\"ghost\" size=\"sm\" icon={<IconCopy />} onClick={() => void copyOrigin()}>\n Copy\n </Button>\n </SettingRow>\n\n <SettingRow label=\"Read session\" description=\"A 15-minute signed cookie, renewed silently while this tab stays open.\">\n <StatusBadge\n status={phase === 'authenticated' ? 'connected' : phase === 'checking' ? 'checking' : 'disconnected'}\n tone={phase === 'authenticated' ? 'success' : phase === 'checking' ? 'running' : 'danger'}\n />\n </SettingRow>\n\n <SettingRow\n label=\"Mutation hold\"\n description=\"Every action that changes something needs the mutation token. It is held in memory only, never stored, and clears when this tab closes.\"\n >\n <StatusBadge\n status={hold.hasHold ? formatHoldExpiry(hold.heldUntil) : 'locked'}\n tone={hold.hasHold ? 'success' : 'neutral'}\n />\n <Button\n variant=\"subtle\"\n size=\"sm\"\n icon={<IconLock />}\n onClick={() => {\n clearMutationToken();\n toast.show('Mutation hold cleared.');\n }}\n disabled={!hold.hasHold}\n >\n Lock now\n </Button>\n </SettingRow>\n\n <SettingRow\n label=\"Disconnect\"\n description=\"Ends the read session in this browser and clears the mutation hold. Chats on the server are untouched.\"\n >\n <Button variant=\"danger\" size=\"sm\" onClick={() => setConfirmOpen(true)}>\n Disconnect\n </Button>\n </SettingRow>\n\n <div className={styles.row}>\n <p className={styles.note}>\n <span className={styles.noteIcon}>\n <IconInfo size={14} />\n </span>\n <span>\n <strong>Where the tokens come from.</strong> Start the console with{' '}\n <code className={styles.code}>ashlr verse</code> — it prints a read token and a mutation token in that\n terminal, and opens this page. The desktop app injects both for you. Tokens are never displayed here, and\n the hub never writes them into a page, a log line or an API response. Lost them? Stop the server and start\n it again; it mints a fresh pair.\n </span>\n </p>\n </div>\n\n <Dialog\n open={confirmOpen}\n onClose={() => setConfirmOpen(false)}\n titleId=\"verse-settings-disconnect\"\n title=\"Disconnect from this server?\"\n description=\"You will need the read token again to get back in. Running sessions keep running on the server.\"\n initialFocusRef={cancelRef}\n >\n <div className={styles.previewRow} style={{ justifyContent: 'flex-end' }}>\n <Button ref={cancelRef} variant=\"subtle\" onClick={() => setConfirmOpen(false)}>\n Cancel\n </Button>\n <Button variant=\"danger\" onClick={() => void disconnect()}>\n Disconnect\n </Button>\n </div>\n </Dialog>\n </Panel>\n );\n}\n","/**\n * routes/verse/sections/ShortcutsPanel.tsx — the keyboard reference.\n *\n * It documents the bindings the V2 shell contract fixes (⌘1-⌘5, ⌘K, ⌘N, ⌘,)\n * plus the composer's own keys. It is a REFERENCE, not the implementation:\n * the handlers live with the shell (owner C) and the composer. Keeping the\n * list here means an operator can find a binding without a manual; keeping\n * it declarative means it is one array to update when a binding changes.\n */\nimport { Panel } from './SettingRow.js';\nimport styles from './SettingsSection.module.css';\n\n/** ⌘ on Apple platforms, Ctrl everywhere else. */\nexport function isApplePlatform(): boolean {\n if (typeof navigator === 'undefined') return true;\n const source = `${navigator.platform ?? ''} ${navigator.userAgent ?? ''}`;\n return /mac|iphone|ipad|ipod/i.test(source);\n}\n\ninterface Shortcut {\n keys: string[];\n action: string;\n}\n\nexport function shortcutGroups(mod: string): Array<{ title: string; items: Shortcut[] }> {\n return [\n {\n title: 'Navigation',\n items: [\n { keys: [mod, '1'], action: 'Chat' },\n { keys: [mod, '2'], action: 'Autonomy' },\n { keys: [mod, '3'], action: 'Approvals' },\n { keys: [mod, '4'], action: 'Usage' },\n { keys: [mod, '5'], action: 'Settings' },\n { keys: [mod, 'K'], action: 'Quick switcher' },\n { keys: [mod, ','], action: 'Settings' },\n ],\n },\n {\n title: 'Chat',\n items: [\n { keys: [mod, 'N'], action: 'New chat' },\n { keys: ['Enter'], action: 'Send message' },\n { keys: ['Shift', 'Enter'], action: 'New line' },\n { keys: ['Esc'], action: 'Stop dictation / close overlay' },\n ],\n },\n ];\n}\n\nexport function ShortcutsPanel() {\n const mod = isApplePlatform() ? '⌘' : 'Ctrl';\n return (\n <Panel title=\"Keyboard\">\n <div className={styles.shortcuts}>\n {shortcutGroups(mod).flatMap((group) =>\n group.items.map((item) => (\n <div key={`${group.title}-${item.action}-${item.keys.join('+')}`} className={styles.shortcut}>\n <span>{item.action}</span>\n <span className={styles.keys}>\n {item.keys.map((key) => (\n <kbd key={key} className={styles.key}>\n {key}\n </kbd>\n ))}\n </span>\n </div>\n )),\n )}\n </div>\n </Panel>\n );\n}\n","/**\n * routes/verse/sections/SettingsSection.tsx — the Settings rail item\n * (VERSE-CONTRACT-V2, owner A). Named export, NO props: the shell\n * lazy-mounts it and it reads everything it needs from the stores.\n *\n * Four panels in one 720px reading column: Appearance (live, no save\n * button), Connection (server, authority state, how to get tokens back),\n * Keyboard, and About. Each row is label + description on the left, control\n * on the right — the same rhythm all the way down, so the page reads as one\n * object rather than four inventions.\n */\nimport { useAppearance } from '../../../data/hooks.js';\nimport { OnboardingPanel } from '../onboarding/OnboardingPanel.js';\nimport { AboutPanel } from './AboutPanel.js';\nimport { AppearancePanel } from './AppearancePanel.js';\nimport { ConnectionPanel } from './ConnectionPanel.js';\nimport { ShortcutsPanel } from './ShortcutsPanel.js';\nimport styles from './SettingsSection.module.css';\n\nexport function SettingsSection() {\n const { appearance, set, reset } = useAppearance();\n\n return (\n <div className={styles.section}>\n <header className={styles.strip} data-app-region=\"drag\">\n <h2 className={styles.stripTitle}>Settings</h2>\n </header>\n <div className={styles.scroll}>\n <div className={styles.column}>\n <AppearancePanel appearance={appearance} onChange={set} onReset={reset} />\n <ConnectionPanel />\n <ShortcutsPanel />\n <OnboardingPanel />\n <AboutPanel />\n </div>\n </div>\n </div>\n );\n}\n"],"names":["Input","label","hint","error","size","mono","prefix","className","id","rest","generatedId","useId","inputId","hintId","errorId","describedBy","jsxs","styles","jsx","Segmented","options","value","onChange","block","aria","groupRef","useRef","move","delta","enabled","o","current","next","option","selected","e","Slider","min","max","valueLabel","valueText","trackImage","sliderId","span","percent","Switch","checked","disabled","control","Panel","title","action","children","SettingRow","description","htmlFor","labelId","stacked","text","Fragment","describe","completedAt","dismissedAt","OnboardingPanel","open","useOnboarding","Button","replayOnboarding","APP_VERSION","version","APP_NAME","AboutPanel","Tag","IconExternalLink","HEX_RE","FN_RE","clamp","unitValue","raw","scale","hslToRgb","h","s","l","hue","c","x","m","rgb","splitTopLevel","parts","depth","ch","p","colorWithPercent","lead","parseColorMix","body","args","first","second","c1","parseColor","c2","p1","p2","total","w1","w2","alpha","channel","k","input","hex","expand","fn","name","sat","light","flatten","color","backdrop","a","relativeLuminance","v","contrastRatio","foreground","background","bgRaw","fgRaw","base","bg","fg","l1","l2","hi","lo","accentHex","lightnessOffset","n","LIGHT_SURFACE","DARK_SURFACE","DARK_L_SHIFT","LINK_STEP","THEME_OPTIONS","IconMonitor","IconSun","IconMoon","DENSITY_OPTIONS","FONT_OPTIONS","RADIUS_OPTIONS","hueTrack","accentReadability","lightLink","darkLink","lightRatio","darkRatio","failing","AppearancePanel","appearance","onReset","accentLabelId","hueId","satId","lightId","motionId","preset","matchingAccentPreset","readability","isDefaultAppearance","theme","ACCENT_PRESETS","IconCheck","ACCENT_LIGHTNESS_RANGE","IconAlert","density","displayFont","radius","reduceMotion","StatusBadge","Meter","formatHoldExpiry","heldUntil","minutes","ConnectionPanel","phase","useAuthPhase","hold","useMutationHold","toast","useToast","confirmOpen","setConfirmOpen","useState","cancelRef","origin","copyOrigin","disconnect","clearReadSession","IconCopy","IconLock","clearMutationToken","IconInfo","Dialog","isApplePlatform","source","shortcutGroups","mod","ShortcutsPanel","group","item","key","SettingsSection","set","reset","useAppearance"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
._field_ki2n9_1{display:flex;flex-direction:column;gap:var(--space-1);min-width:0}._label_ki2n9_8{font-size:var(--text-xs-size);line-height:var(--text-xs-line);color:var(--text-secondary);font-weight:var(--font-weight-medium)}._shell_ki2n9_15{display:flex;align-items:center;gap:var(--space-1);height:var(--density-row);padding:0 var(--space-2);background:var(--bg-input);border:1px solid var(--border-default);border-radius:var(--radius-sm);transition:border-color var(--duration-fast) var(--ease-standard),box-shadow var(--duration-fast) var(--ease-standard)}._sm_ki2n9_29{height:var(--density-row-sm)}._shell_ki2n9_15:hover:not(:has(._input_ki2n9_33:disabled)){border-color:var(--border-strong)}._shell_ki2n9_15:has(._input_ki2n9_33:focus-visible){border-color:var(--border-focus);box-shadow:var(--shadow-focus-ring)}._invalid_ki2n9_50{border-color:var(--status-danger-solid)}._input_ki2n9_33{flex:1;min-width:0;height:100%;border:none;background:none;color:var(--text-primary);font-family:var(--font-ui);font-size:var(--text-sm-size)}._input_ki2n9_33:focus,._input_ki2n9_33:focus-visible{outline:none;box-shadow:none}._input_ki2n9_33::placeholder{color:var(--text-tertiary)}._input_ki2n9_33:disabled{color:var(--text-disabled);cursor:not-allowed}._mono_ki2n9_80{font-family:var(--font-mono);font-size:var(--text-xs-size)}._prefix_ki2n9_85{color:var(--text-tertiary);font-size:var(--text-xs-size);white-space:nowrap}._hint_ki2n9_91{font-size:var(--text-xs-size);line-height:var(--text-xs-line);color:var(--text-tertiary)}._error_ki2n9_97{font-size:var(--text-xs-size);line-height:var(--text-xs-line);color:var(--status-danger-fg)}._group_15ia8_1{display:inline-flex;align-items:center;gap:2px;padding:2px;background:var(--bg-hover);border:1px solid var(--border-subtle);border-radius:var(--radius-sm)}._block_15ia8_11{display:flex;width:100%}._block_15ia8_11 ._option_15ia8_16{flex:1;justify-content:center}._option_15ia8_16{display:inline-flex;align-items:center;justify-content:center;gap:var(--space-1);height:calc(var(--density-row) - 6px);padding:0 var(--space-3);border:1px solid transparent;border-radius:calc(var(--radius-sm) - 1px);background:transparent;color:var(--text-secondary);font-family:var(--font-ui);font-size:var(--text-xs-size);font-weight:var(--font-weight-medium);white-space:nowrap;cursor:pointer;transition:background-color var(--duration-fast) var(--ease-standard),color var(--duration-fast) var(--ease-standard)}._sm_15ia8_45 ._option_15ia8_16{height:calc(var(--density-row-sm) - 6px);padding:0 var(--space-2);font-size:var(--text-2xs-size)}._option_15ia8_16:hover:not(:disabled):not([aria-checked=true]){color:var(--text-primary)}._option_15ia8_16[aria-checked=true]{background:var(--bg-surface);color:var(--text-primary);border-color:var(--border-default)}._option_15ia8_16:disabled{color:var(--text-disabled);cursor:not-allowed}._glyph_15ia8_72{display:inline-flex;flex:none}._field_228wn_1{display:flex;flex-direction:column;gap:var(--space-1);min-width:0}._label_228wn_8{font-size:var(--text-xs-size);line-height:var(--text-xs-line);color:var(--text-secondary);font-weight:var(--font-weight-medium)}._row_228wn_15{display:flex;align-items:center;gap:var(--space-3);height:var(--density-row)}._value_228wn_22{flex:none;min-width:4ch;text-align:right;font-family:var(--font-display);font-variant-numeric:tabular-nums;font-size:var(--text-xs-size);color:var(--text-secondary)}._input_228wn_32{appearance:none;-webkit-appearance:none;flex:1;min-width:0;height:16px;background:none;cursor:pointer}._input_228wn_32:focus{outline:none}._input_228wn_32:focus-visible{box-shadow:none}._input_228wn_32::-webkit-slider-runnable-track{height:4px;border-radius:var(--radius-full);background:var(--slider-track-image, linear-gradient(to right, var(--accent-500) var(--slider-fill, 0%), var(--bg-active) var(--slider-fill, 0%)))}._input_228wn_32::-moz-range-track{height:4px;border-radius:var(--radius-full);background:var(--slider-track-image, linear-gradient(to right, var(--accent-500) var(--slider-fill, 0%), var(--bg-active) var(--slider-fill, 0%)))}._input_228wn_32::-webkit-slider-thumb{appearance:none;-webkit-appearance:none;width:12px;height:12px;margin-top:-4px;border-radius:var(--radius-full);background:var(--bg-surface);border:2px solid var(--accent-500);transition:border-color var(--duration-fast) var(--ease-standard)}._input_228wn_32::-moz-range-thumb{width:12px;height:12px;border-radius:var(--radius-full);background:var(--bg-surface);border:2px solid var(--accent-500)}._input_228wn_32:focus-visible::-webkit-slider-thumb{box-shadow:var(--shadow-focus-ring)}._input_228wn_32:focus-visible::-moz-range-thumb{box-shadow:var(--shadow-focus-ring)}._input_228wn_32:disabled{cursor:not-allowed;opacity:.55}._wrapper_1xq82_1{display:inline-flex;align-items:center;gap:var(--space-2);cursor:pointer}._label_1xq82_8{font-size:var(--text-sm-size);color:var(--text-primary)}._track_1xq82_13{position:relative;flex:none;width:34px;height:18px;padding:0;border:1px solid var(--border-strong);border-radius:var(--radius-full);background:var(--bg-active);cursor:pointer;transition:background-color var(--duration-fast) var(--ease-standard),border-color var(--duration-fast) var(--ease-standard)}._track_1xq82_13:hover:not(:disabled){border-color:var(--text-tertiary)}._track_1xq82_13[aria-checked=true]{background:var(--accent-600);border-color:var(--accent-600)}._track_1xq82_13[aria-checked=true]:hover:not(:disabled){background:var(--accent-700);border-color:var(--accent-700)}._track_1xq82_13:active:not(:disabled) ._knob_1xq82_44{width:14px}._track_1xq82_13[aria-checked=true]:active:not(:disabled) ._knob_1xq82_44{transform:translate(14px)}._track_1xq82_13:disabled{cursor:not-allowed;opacity:.55}._knob_1xq82_44{position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:var(--radius-full);background:var(--bg-surface);transition:transform var(--duration-fast) var(--ease-standard),width var(--duration-fast) var(--ease-standard)}._track_1xq82_13[aria-checked=true] ._knob_1xq82_44{transform:translate(16px);background:var(--accent-contrast)}._section_3qpbp_5{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--bg-canvas)}._strip_3qpbp_13{display:flex;align-items:center;justify-content:space-between;gap:var(--space-3);flex:none;height:var(--strip-height);padding:0 var(--space-5);border-bottom:1px solid var(--border-subtle);background:var(--bg-surface)}._stripTitle_3qpbp_25{font-family:var(--font-display);font-size:var(--text-sm-size);font-weight:var(--font-weight-semibold);letter-spacing:var(--tracking-display)}._scroll_3qpbp_32{flex:1;min-height:0;overflow:auto}._column_3qpbp_38{width:100%;max-width:var(--measure-read);margin:0 auto;padding:var(--space-6) var(--space-5) var(--space-16);display:flex;flex-direction:column;gap:var(--space-8)}._panel_3qpbp_51{display:flex;flex-direction:column}._panelHead_3qpbp_56{display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-3);padding-bottom:var(--space-2)}._panelTitle_3qpbp_64{font-family:var(--font-display);font-size:var(--text-2xs-size);line-height:var(--text-2xs-line);letter-spacing:var(--tracking-label);text-transform:uppercase;font-weight:var(--font-weight-medium);color:var(--text-tertiary)}._panelBody_3qpbp_74{border-top:1px solid var(--border-subtle)}._row_3qpbp_81{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:var(--space-4);padding:var(--density-pad) 0;border-bottom:1px solid var(--border-subtle)}._rowStacked_3qpbp_90{grid-template-columns:minmax(0,1fr);align-items:stretch}._rowText_3qpbp_95{min-width:0}._rowLabel_3qpbp_99{display:block;font-size:var(--text-sm-size);line-height:var(--text-sm-line);color:var(--text-primary);font-weight:var(--font-weight-medium)}._rowDescription_3qpbp_107{margin-top:2px;font-size:var(--text-xs-size);line-height:var(--text-xs-line);color:var(--text-secondary)}._rowControl_3qpbp_114{display:flex;align-items:center;justify-content:flex-end;gap:var(--space-2);min-width:0}._rowStacked_3qpbp_90 ._rowControl_3qpbp_114{justify-content:flex-start}@media(max-width:720px){._row_3qpbp_81{grid-template-columns:minmax(0,1fr)}._rowControl_3qpbp_114{justify-content:flex-start}}._swatches_3qpbp_140{display:flex;flex-wrap:wrap;gap:var(--space-2)}._swatch_3qpbp_140{width:22px;height:22px;padding:0;border:1px solid var(--border-default);border-radius:var(--radius-xs);cursor:pointer;transition:transform var(--duration-fast) var(--ease-standard)}._swatch_3qpbp_140:hover{transform:translateY(-1px)}._swatch_3qpbp_140[aria-checked=true]{box-shadow:0 0 0 2px var(--bg-surface),0 0 0 3px var(--text-primary)}._swatchCheck_3qpbp_165{display:flex;align-items:center;justify-content:center;color:#fff;mix-blend-mode:difference}._sliderStack_3qpbp_173{display:flex;flex-direction:column;gap:var(--space-1);width:min(320px,100%)}._contrastWarning_3qpbp_180{display:flex;align-items:flex-start;gap:var(--space-2);margin-top:var(--space-2);padding:var(--space-2) var(--space-3);border:1px solid var(--status-warning-solid);border-radius:var(--radius-xs);background:var(--status-warning-bg);color:var(--status-warning-fg);font-size:var(--text-xs-size);line-height:var(--text-xs-line)}._preview_3qpbp_197{display:flex;flex-direction:column;gap:var(--space-3);padding:var(--space-4);border:1px solid var(--border-default);border-radius:var(--radius-md);background:var(--bg-surface)}._previewRow_3qpbp_207{display:flex;align-items:center;flex-wrap:wrap;gap:var(--space-2)}._previewHeading_3qpbp_214{font-family:var(--font-display);font-size:var(--text-md-size);line-height:var(--text-md-line);letter-spacing:var(--tracking-display);font-weight:var(--font-weight-semibold)}._previewBody_3qpbp_222{font-size:var(--text-sm-size);line-height:var(--text-sm-line);color:var(--text-secondary)}._previewNumerals_3qpbp_228{font-family:var(--font-display);font-variant-numeric:tabular-nums;letter-spacing:var(--tracking-display);color:var(--text-primary)}._origin_3qpbp_238{width:min(320px,100%)}._note_3qpbp_242{display:flex;gap:var(--space-2);padding:var(--space-3);border:1px solid var(--border-subtle);border-radius:var(--radius-xs);background:var(--bg-canvas);color:var(--text-secondary);font-size:var(--text-xs-size);line-height:var(--text-xs-line)}._noteIcon_3qpbp_258{flex:none;margin-top:1px;color:var(--text-tertiary)}._code_3qpbp_249{font-family:var(--font-mono);font-size:var(--text-2xs-size);padding:1px 4px;border:1px solid var(--border-subtle);border-radius:var(--radius-xs);background:var(--bg-code);color:var(--text-primary);white-space:nowrap}._shortcuts_3qpbp_278{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:0 var(--space-6)}._shortcut_3qpbp_278{display:flex;align-items:center;justify-content:space-between;gap:var(--space-3);padding:var(--space-2) 0;border-bottom:1px solid var(--border-subtle);font-size:var(--text-sm-size)}._keys_3qpbp_294{display:inline-flex;align-items:center;gap:2px;flex:none}._key_3qpbp_294{min-width:20px;padding:2px var(--space-1);border:1px solid var(--border-default);border-bottom-width:2px;border-radius:var(--radius-xs);background:var(--bg-surface);color:var(--text-secondary);font-family:var(--font-display);font-size:var(--text-2xs-size);line-height:var(--text-2xs-line);text-align:center}._about_3qpbp_315{display:flex;flex-direction:column;gap:var(--space-2)}._aboutLine_3qpbp_321{display:flex;align-items:center;gap:var(--space-2);font-size:var(--text-sm-size);color:var(--text-secondary)}._aboutName_3qpbp_329{font-family:var(--font-display);font-size:var(--text-lg-size);line-height:var(--text-lg-line);letter-spacing:var(--tracking-display);font-weight:var(--font-weight-semibold);color:var(--text-primary)}._link_3qpbp_338{display:inline-flex;align-items:center;gap:var(--space-1);color:var(--text-link);text-decoration:none}._link_3qpbp_338:hover{text-decoration:underline}._strip_3qpbp_13{padding-left:max(var(--space-5),calc(var(--app-traffic-light-inset, 0px) - var(--rail-width, 56px)))}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
._grid_x7p2y_1{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:var(--space-4)}._card_x7p2y_10{display:flex;flex-direction:column;gap:var(--space-3);padding:var(--space-4) 0}._title_x7p2y_19{height:var(--text-xs-line);width:60%;border-radius:var(--radius-xs)}._stat_x7p2y_25{height:var(--text-2xl-line);width:40%;border-radius:var(--radius-xs)}._caption_x7p2y_31{height:var(--text-2xs-line);width:80%;border-radius:var(--radius-xs)}._line_x7p2y_37{height:var(--text-base-line);border-radius:var(--radius-xs)}._row_x7p2y_42{display:flex;align-items:center;gap:var(--space-4);min-height:var(--density-row);padding:var(--space-3) var(--space-4);border-bottom:1px solid var(--border-subtle)}._cell_x7p2y_51{height:var(--text-sm-line);border-radius:var(--radius-xs)}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{j as s}from"./index-CpgkRaTi.js";const n="_grid_x7p2y_1",a="_card_x7p2y_10",c="_title_x7p2y_19",i="_stat_x7p2y_25",o="_caption_x7p2y_31",r="_line_x7p2y_37",d="_row_x7p2y_42",_="_cell_x7p2y_51",e={grid:n,card:a,title:c,stat:i,caption:o,line:r,row:d,cell:_};function y({width:t="100%"}){return s.jsx("div",{className:`skeleton ${e.line}`,style:{width:t}})}function x(){return s.jsxs("div",{className:e.card,children:[s.jsx("div",{className:`skeleton ${e.title}`}),s.jsx("div",{className:`skeleton ${e.stat}`}),s.jsx("div",{className:`skeleton ${e.caption}`})]})}function j(){return s.jsxs("div",{className:e.row,children:[s.jsx("div",{className:`skeleton ${e.cell}`,style:{width:"18%"}}),s.jsx("div",{className:`skeleton ${e.cell}`,style:{width:"38%"}}),s.jsx("div",{className:`skeleton ${e.cell}`,style:{width:"14%"}}),s.jsx("div",{className:`skeleton ${e.cell}`,style:{width:"10%"}})]})}function k({count:t=4}){return s.jsx("div",{className:e.grid,children:Array.from({length:t},(m,l)=>s.jsx(x,{},l))})}export{y as S,k as a,j as b};
|
|
2
|
-
//# sourceMappingURL=Skeleton-YkcOpgFb.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Skeleton-YkcOpgFb.js","sources":["../../../../../../src/web-ui/components/primitives/Skeleton.tsx"],"sourcesContent":["/**\n * components/primitives/Skeleton.tsx — loading placeholders. Used ONLY for\n * `status === 'loading'` (no data at all yet). A resource that already has\n * data and is merely refreshing should show <RefreshIndicator/> instead —\n * never re-blank a populated view (see DESIGN.md \"no blank screens\").\n */\nimport styles from './Skeleton.module.css';\n\nexport function SkeletonLine({ width = '100%' }: { width?: string }) {\n return <div className={`skeleton ${styles.line}`} style={{ width }} />;\n}\n\nexport function SkeletonCard() {\n return (\n <div className={styles.card}>\n <div className={`skeleton ${styles.title}`} />\n <div className={`skeleton ${styles.stat}`} />\n <div className={`skeleton ${styles.caption}`} />\n </div>\n );\n}\n\nexport function SkeletonRow() {\n return (\n <div className={styles.row}>\n <div className={`skeleton ${styles.cell}`} style={{ width: '18%' }} />\n <div className={`skeleton ${styles.cell}`} style={{ width: '38%' }} />\n <div className={`skeleton ${styles.cell}`} style={{ width: '14%' }} />\n <div className={`skeleton ${styles.cell}`} style={{ width: '10%' }} />\n </div>\n );\n}\n\nexport function SkeletonCardGrid({ count = 4 }: { count?: number }) {\n return (\n <div className={styles.grid}>\n {Array.from({ length: count }, (_, i) => (\n <SkeletonCard key={i} />\n ))}\n </div>\n );\n}\n"],"names":["SkeletonLine","width","jsx","styles","SkeletonCard","jsxs","SkeletonRow","SkeletonCardGrid","count","_","i"],"mappings":"uQAQO,SAASA,EAAa,CAAE,MAAAC,EAAQ,QAA8B,CACnE,OAAOC,MAAC,MAAA,CAAI,UAAW,YAAYC,EAAO,IAAI,GAAI,MAAO,CAAE,MAAAF,CAAA,CAAM,CAAG,CACtE,CAEO,SAASG,GAAe,CAC7B,OACEC,EAAAA,KAAC,MAAA,CAAI,UAAWF,EAAO,KACrB,SAAA,CAAAD,MAAC,MAAA,CAAI,UAAW,YAAYC,EAAO,KAAK,GAAI,QAC3C,MAAA,CAAI,UAAW,YAAYA,EAAO,IAAI,GAAI,QAC1C,MAAA,CAAI,UAAW,YAAYA,EAAO,OAAO,EAAA,CAAI,CAAA,EAChD,CAEJ,CAEO,SAASG,GAAc,CAC5B,OACED,EAAAA,KAAC,MAAA,CAAI,UAAWF,EAAO,IACrB,SAAA,CAAAD,EAAAA,IAAC,MAAA,CAAI,UAAW,YAAYC,EAAO,IAAI,GAAI,MAAO,CAAE,MAAO,KAAA,CAAM,CAAG,EACpED,EAAAA,IAAC,MAAA,CAAI,UAAW,YAAYC,EAAO,IAAI,GAAI,MAAO,CAAE,MAAO,KAAA,CAAM,CAAG,EACpED,EAAAA,IAAC,MAAA,CAAI,UAAW,YAAYC,EAAO,IAAI,GAAI,MAAO,CAAE,MAAO,KAAA,CAAM,CAAG,EACpED,EAAAA,IAAC,MAAA,CAAI,UAAW,YAAYC,EAAO,IAAI,GAAI,MAAO,CAAE,MAAO,KAAA,CAAM,CAAG,CAAA,EACtE,CAEJ,CAEO,SAASI,EAAiB,CAAE,MAAAC,EAAQ,GAAyB,CAClE,aACG,MAAA,CAAI,UAAWL,EAAO,KACpB,SAAA,MAAM,KAAK,CAAE,OAAQK,CAAA,EAAS,CAACC,EAAGC,UAChCN,EAAA,CAAA,EAAkBM,CAAG,CACvB,EACH,CAEJ"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{j as r}from"./index-CpgkRaTi.js";const u="_badge_ytqgz_4",c="_dot_ytqgz_17",o="_neutral_ytqgz_24",g="_info_ytqgz_32",d="_running_ytqgz_40",i="_pulse_ytqgz_1",_="_success_ytqgz_49",l="_warning_ytqgz_57",p="_danger_ytqgz_65",w="_unknown_ytqgz_73",y="_phaseDot_ytqgz_82",e={badge:u,dot:c,neutral:o,info:g,running:d,pulse:i,success:_,warning:l,danger:p,unknown:w,phaseDot:y},q={pending:"neutral",queued:"neutral",waiting:"neutral",running:"running",active:"running",in_progress:"running",building:"running",applying:"running",done:"success",success:"success",succeeded:"success",applied:"success",merged:"success",ready:"success",approved:"success",ship:"success",review:"warning",degraded:"warning",paused:"warning",noise:"neutral",failed:"danger",error:"danger",errored:"danger",rejected:"danger",harmful:"danger",cancelled:"neutral",canceled:"neutral",unknown:"unknown"};function h(n){return n?q[n.toLowerCase()]??"neutral":"unknown"}function f({status:n,tone:s,children:a}){const t=s??h(n);return r.jsxs("span",{className:`${e.badge} ${e[t]}`,children:[r.jsx("span",{className:e.dot,"aria-hidden":"true"}),a??n]})}function m({index:n}){const s=(n%6+6)%6;return r.jsx("span",{className:e.phaseDot,style:{background:`var(--phase-${s+1})`},"aria-hidden":"true"})}export{m as P,f as S,h as s};
|
|
2
|
-
//# sourceMappingURL=StatusBadge-DJw0LSPg.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"StatusBadge-DJw0LSPg.js","sources":["../../../../../../src/web-ui/components/primitives/StatusBadge.tsx"],"sourcesContent":["/**\n * components/primitives/StatusBadge.tsx — the ONE status-color mapping for\n * the whole app. See DESIGN.md \"Status-color semantics\" for the reasoning;\n * the short version: `running` is amber (motion, unresolved — matches\n * Vercel/GitHub Actions \"in progress\"), `done` is green (resolved,\n * successful). Neither reuses the accent color, so \"this is clickable\"\n * (accent) never visually collides with \"this succeeded\" (green).\n *\n * Every view should route run/swarm/proposal/daemon status strings through\n * `statusToTone()` rather than switching on raw strings itself, so adding a\n * new backend status value only ever needs one edit, here.\n */\nimport type { ReactNode } from 'react';\nimport styles from './StatusBadge.module.css';\n\nexport type Tone = 'neutral' | 'info' | 'running' | 'success' | 'warning' | 'danger' | 'unknown';\n\nconst STATUS_TONE: Record<string, Tone> = {\n // Run / swarm / proposal lifecycle.\n pending: 'neutral',\n queued: 'neutral',\n waiting: 'neutral',\n running: 'running',\n active: 'running',\n in_progress: 'running',\n building: 'running',\n applying: 'running',\n done: 'success',\n success: 'success',\n succeeded: 'success',\n applied: 'success',\n merged: 'success',\n ready: 'success',\n approved: 'success',\n ship: 'success',\n review: 'warning',\n degraded: 'warning',\n paused: 'warning',\n noise: 'neutral',\n failed: 'danger',\n error: 'danger',\n errored: 'danger',\n rejected: 'danger',\n harmful: 'danger',\n cancelled: 'neutral',\n canceled: 'neutral',\n unknown: 'unknown',\n};\n\nexport function statusToTone(status: string | undefined | null): Tone {\n if (!status) return 'unknown';\n return STATUS_TONE[status.toLowerCase()] ?? 'neutral';\n}\n\nexport interface StatusBadgeProps {\n status: string;\n /** Override the derived tone (rare — prefer letting statusToTone decide). */\n tone?: Tone;\n children?: ReactNode;\n}\n\nexport function StatusBadge({ status, tone, children }: StatusBadgeProps): ReactNode {\n const resolved = tone ?? statusToTone(status);\n return (\n <span className={`${styles.badge} ${styles[resolved]}`}>\n <span className={styles.dot} aria-hidden=\"true\" />\n {children ?? status}\n </span>\n );\n}\n\n/** A named DAG/milestone phase — categorical color, unrelated to health. */\nexport function PhaseDot({ index }: { index: number }): ReactNode {\n const n = ((index % 6) + 6) % 6; // wrap safely for any index, including negatives\n return <span className={styles.phaseDot} style={{ background: `var(--phase-${n + 1})` }} aria-hidden=\"true\" />;\n}\n"],"names":["STATUS_TONE","statusToTone","status","StatusBadge","tone","children","resolved","jsxs","styles","jsx","PhaseDot","index","n"],"mappings":"0XAiBMA,EAAoC,CAExC,QAAS,UACT,OAAQ,UACR,QAAS,UACT,QAAS,UACT,OAAQ,UACR,YAAa,UACb,SAAU,UACV,SAAU,UACV,KAAM,UACN,QAAS,UACT,UAAW,UACX,QAAS,UACT,OAAQ,UACR,MAAO,UACP,SAAU,UACV,KAAM,UACN,OAAQ,UACR,SAAU,UACV,OAAQ,UACR,MAAO,UACP,OAAQ,SACR,MAAO,SACP,QAAS,SACT,SAAU,SACV,QAAS,SACT,UAAW,UACX,SAAU,UACV,QAAS,SACX,EAEO,SAASC,EAAaC,EAAyC,CACpE,OAAKA,EACEF,EAAYE,EAAO,YAAA,CAAa,GAAK,UADxB,SAEtB,CASO,SAASC,EAAY,CAAE,OAAAD,EAAQ,KAAAE,EAAM,SAAAC,GAAyC,CACnF,MAAMC,EAAWF,GAAQH,EAAaC,CAAM,EAC5C,OACEK,EAAAA,KAAC,OAAA,CAAK,UAAW,GAAGC,EAAO,KAAK,IAAIA,EAAOF,CAAQ,CAAC,GAClD,SAAA,CAAAG,EAAAA,IAAC,OAAA,CAAK,UAAWD,EAAO,IAAK,cAAY,OAAO,EAC/CH,GAAYH,CAAA,EACf,CAEJ,CAGO,SAASQ,EAAS,CAAE,MAAAC,GAAuC,CAChE,MAAMC,GAAMD,EAAQ,EAAK,GAAK,EAC9B,OAAOF,EAAAA,IAAC,OAAA,CAAK,UAAWD,EAAO,SAAU,MAAO,CAAE,WAAY,eAAeI,EAAI,CAAC,GAAA,EAAO,cAAY,OAAO,CAC9G"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
._badge_ytqgz_4{display:inline-flex;align-items:center;gap:var(--space-1);height:var(--density-row-sm);padding:0 var(--space-2);border-radius:var(--radius-xs);font-size:var(--text-xs-size);font-weight:var(--font-weight-medium);line-height:1;white-space:nowrap}._dot_ytqgz_17{width:6px;height:6px;border-radius:var(--radius-full);flex-shrink:0}._neutral_ytqgz_24{background:var(--status-neutral-bg);color:var(--status-neutral-fg)}._neutral_ytqgz_24 ._dot_ytqgz_17{background:var(--status-neutral-solid)}._info_ytqgz_32{background:var(--status-info-bg);color:var(--status-info-fg)}._info_ytqgz_32 ._dot_ytqgz_17{background:var(--status-info-solid)}._running_ytqgz_40{background:var(--status-running-bg);color:var(--status-running-fg)}._running_ytqgz_40 ._dot_ytqgz_17{background:var(--status-running-solid);animation:_pulse_ytqgz_1 1.6s ease-in-out infinite}._success_ytqgz_49{background:var(--status-success-bg);color:var(--status-success-fg)}._success_ytqgz_49 ._dot_ytqgz_17{background:var(--status-success-solid)}._warning_ytqgz_57{background:var(--status-warning-bg);color:var(--status-warning-fg)}._warning_ytqgz_57 ._dot_ytqgz_17{background:var(--status-warning-solid)}._danger_ytqgz_65{background:var(--status-danger-bg);color:var(--status-danger-fg)}._danger_ytqgz_65 ._dot_ytqgz_17{background:var(--status-danger-solid)}._unknown_ytqgz_73{background:var(--status-unknown-bg);color:var(--status-unknown-fg);font-style:italic}._unknown_ytqgz_73 ._dot_ytqgz_17{background:var(--status-unknown-solid)}._phaseDot_ytqgz_82{display:inline-block;width:8px;height:8px;border-radius:var(--radius-full)}@keyframes _pulse_ytqgz_1{0%,to{opacity:1}50%{opacity:.4}}@media(prefers-reduced-motion:reduce){:root:not([data-motion=full]) ._running_ytqgz_40 ._dot_ytqgz_17{animation:none}}:root[data-motion=reduce] ._running_ytqgz_40 ._dot_ytqgz_17{animation:none}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{j as e,r as O}from"./index-CpgkRaTi.js";const ie="_figure_1si9v_1",re="_caption_1si9v_12",ue="_title_1si9v_20",de="_description_1si9v_26",xe="_plot_1si9v_31",_e="_tableDisclosure_1si9v_36",me="_tableBody_1si9v_61",he="_caveat_1si9v_65",pe="_empty_1si9v_75",W={figure:ie,caption:re,title:ue,description:de,plot:xe,tableDisclosure:_e,tableBody:me,caveat:he,empty:pe};function ft({title:t,description:l,caveat:n,children:o,table:c,empty:b,emptyMessage:x="No data for this window."}){return e.jsxs("figure",{className:W.figure,children:[e.jsxs("figcaption",{className:W.caption,children:[e.jsx("span",{className:W.title,children:t}),l?e.jsx("span",{className:W.description,children:l}):null]}),n?e.jsx("p",{className:W.caveat,role:"note",children:n}):null,b?e.jsx("p",{className:W.empty,children:x}):e.jsx("div",{className:W.plot,children:o}),c?e.jsxs("details",{className:W.tableDisclosure,children:[e.jsx("summary",{children:"View as table"}),e.jsx("div",{className:W.tableBody,children:c})]}):null]})}const je="_legend_4pgvn_1",ge="_item_4pgvn_10",ve="_swatch_4pgvn_18",be="_swatchLine_4pgvn_25",Y={legend:je,item:ge,swatch:ve,swatchLine:be};function fe({items:t}){return t.length<2?null:e.jsx("ul",{className:Y.legend,children:t.map(l=>e.jsxs("li",{className:Y.item,children:[e.jsx("span",{className:l.kind==="line"?Y.swatchLine:Y.swatch,style:{background:l.color},"aria-hidden":"true"}),l.label]},l.label))})}const te=7;function q(t){return`var(--chart-series-${(t%te+te)%te+1})`}const ye="var(--chart-sequential)",se="var(--chart-grid)",ne="var(--chart-axis)",Ne="_svg_djmd1_1",Le="_gridline_djmd1_7",$e="_axis_djmd1_12",we="_axisLabel_djmd1_17",Ae="_line_djmd1_23",Me="_area_djmd1_30",Be="_marker_djmd1_35",Se="_endLabel_djmd1_40",ke="_crosshairLine_djmd1_46",De="_overlay_djmd1_52",Ee="_wrap_djmd1_57",Re="_tooltip_djmd1_61",Pe="_tooltipDate_djmd1_77",We="_tooltipRow_djmd1_82",Te="_tooltipKey_djmd1_88",Fe="_tooltipValue_djmd1_94",Ce="_tooltipGap_djmd1_99",p={svg:Ne,gridline:Le,axis:$e,axisLabel:we,line:Ae,area:Me,marker:Be,endLabel:Se,crosshairLine:ke,overlay:De,wrap:Ee,tooltip:Re,tooltipDate:Pe,tooltipRow:We,tooltipKey:Te,tooltipValue:Fe,tooltipGap:Ce},U=640,X=44,Ie=12,Q=12,J=24,He=4,Ge=6.4,oe=4,Xe=150;function Ve(t){const l=[];let n=[];for(const o of t){if(o.y===null){n.length&&l.push(n),n=[];continue}n.push({x:o.x,y:o.y})}return n.length&&l.push(n),l}function Ke(t,l,n){if(l<=t)return[t];const o=(l-t)/n;return Array.from({length:n+1},(c,b)=>t+o*b)}function yt({series:t,height:l=200,area:n=!1,formatX:o=x=>String(x),formatY:c=x=>String(x),ariaLabel:b}){const x=O.useRef(null),[r,f]=O.useState(null),[S,F]=O.useState(null),g=t.flatMap(s=>s.points.map(a=>a.x)),M=t.flatMap(s=>s.points.map(a=>a.y)).filter(s=>s!==null);if(g.length===0)return e.jsx("p",{children:"No data."});const k=Math.min(...g),i=Math.max(...g),L=Math.min(0,...M),C=Math.max(1e-4,...M),D=i-k||1,V=C-L||1,K=t.length>=1&&t.length<=4,E=K?Math.max(...t.map(s=>s.label.length))*Ge:0,u=K&&E<=Xe,$=Ie+(u?oe+E:0),_=t.length>=2,R=U-X-$,B=l-Q-J,m=s=>X+(s-k)/D*R,d=s=>Q+B-(s-L)/V*B,T=Ke(L,C,He),y=Array.from(new Set(g)).sort((s,a)=>s-a);function Z(s){const a=x.current;if(!a)return null;const v=a.getBoundingClientRect(),w=(s-v.left)/v.width*U,N=k+(w-X)/R*D;let P=y[0],H=1/0;for(const G of y){const z=Math.abs(G-N);z<H&&(H=z,P=G)}return P}function I(s){const a=Z(s.clientX);if(a===null)return;f(a);const v=x.current;if(v){const w=v.getBoundingClientRect(),N=m(a)/U*w.width;F({left:N,top:0})}}const ae=r!==null?t.map(s=>({series:s,point:s.points.find(a=>a.x===r)??null})):null;return e.jsxs("div",{className:p.wrap,children:[e.jsxs("svg",{ref:x,className:p.svg,viewBox:`0 0 ${U} ${l}`,role:"img","aria-label":b,onPointerMove:I,onPointerLeave:()=>f(null),children:[T.map((s,a)=>e.jsxs("g",{children:[e.jsx("line",{x1:X,x2:U-$,y1:d(s),y2:d(s),className:p.gridline,stroke:se}),e.jsx("text",{x:X-6,y:d(s),dy:"0.32em",textAnchor:"end",className:p.axisLabel,children:c(s)})]},a)),e.jsx("line",{x1:X,x2:U-$,y1:l-J,y2:l-J,className:p.axis,stroke:ne}),y.length>1?[y[0],y[y.length-1]].map((s,a)=>e.jsx("text",{x:m(s),y:l-6,textAnchor:a===0?"start":"end",className:p.axisLabel,children:o(s)},a)):null,t.map((s,a)=>{const v=q(a),w=Ve(s.points);return e.jsxs("g",{children:[n&&t.length===1?w.map((N,P)=>{const H=N.map((G,z)=>`${z===0?"M":"L"}${m(G.x)},${d(G.y)}`).join(" ")+` L${m(N[N.length-1].x)},${d(L)} L${m(N[0].x)},${d(L)} Z`;return e.jsx("path",{d:H,fill:v,className:p.area},P)}):null,w.map((N,P)=>e.jsx("path",{d:N.map((H,G)=>`${G===0?"M":"L"}${m(H.x)},${d(H.y)}`).join(" "),stroke:v,className:p.line},P)),u&&w.length?(()=>{const N=w[w.length-1],P=N[N.length-1];return e.jsx("text",{x:m(P.x)+oe,y:d(P.y),dy:"0.32em",className:p.endLabel,fill:v,children:s.label})})():null]},s.id)}),r!==null?e.jsx("line",{x1:m(r),x2:m(r),y1:Q,y2:l-J,className:p.crosshairLine}):null,r!==null?t.map((s,a)=>{const v=s.points.find(w=>w.x===r);return!v||v.y===null?null:e.jsx("circle",{cx:m(v.x),cy:d(v.y),r:4,fill:q(a),className:p.marker},s.id)}):null,e.jsx("rect",{x:X,y:Q,width:R,height:B,className:p.overlay,onFocus:()=>f(y[y.length-1]??null)})]}),ae&&S?e.jsxs("div",{className:p.tooltip,style:{left:S.left,top:S.top},children:[e.jsx("div",{className:p.tooltipDate,children:o(r)}),ae.map(({series:s,point:a},v)=>e.jsxs("div",{className:p.tooltipRow,children:[e.jsx("span",{className:p.tooltipKey,style:{background:q(v)},"aria-hidden":"true"}),a&&a.y!==null?e.jsxs(e.Fragment,{children:[e.jsx("span",{className:p.tooltipValue,children:c(a.y)}),_?e.jsx("span",{children:s.label}):null]}):e.jsxs("span",{className:p.tooltipGap,children:["no data",_?` — ${s.label}`:""]})]},s.id))]}):null,_?e.jsx(fe,{items:t.map((s,a)=>({label:s.label,color:q(a),kind:"line"}))}):null]})}const Ue="_svg_o4jfa_1",Oe="_bar_o4jfa_6",Ze="_baseline_o4jfa_15",ze="_axisLabel_o4jfa_25",Ye="_valueLabel_o4jfa_31",qe="_categoryLabel_o4jfa_38",Qe="_hitArea_o4jfa_44",Je="_tooltip_o4jfa_49",et="_tooltipValue_o4jfa_63",tt="_tooltipLabel_o4jfa_68",lt="_wrap_o4jfa_73",h={svg:Ue,bar:Oe,baseline:Ze,axisLabel:ze,valueLabel:Ye,categoryLabel:qe,hitArea:Qe,tooltip:Je,tooltipValue:et,tooltipLabel:tt,wrap:lt},ee=24,j=10;function Nt({data:t,height:l=160,orientation:n="vertical",color:o=ye,formatValue:c=x=>String(x),ariaLabel:b}){const x=O.useId(),[r,f]=O.useState(null),S=t.map(u=>u.value).filter(u=>u!==null),F=Math.max(0,...S,1e-4),g=Math.min(0,...S),M=F-g||1;if(n==="horizontal"){const _=Math.min(ee,Math.max(14,Math.floor((l-j)/t.length)-j)),R=420,B=t.length*(_+j)+j,m=120+R+48;return e.jsxs("div",{className:h.wrap,children:[e.jsxs("svg",{className:h.svg,width:m,height:B,viewBox:`0 0 ${m} ${B}`,role:"img","aria-label":b,children:[e.jsx("line",{x1:120,y1:0,x2:120,y2:B,className:h.baseline,stroke:ne}),t.map((d,T)=>{const y=j+T*(_+j),Z=d.value!==null?(d.value-g)/M*R:0;return e.jsxs("g",{children:[e.jsx("text",{x:112,y:y+_/2,dy:"0.32em",textAnchor:"end",className:h.categoryLabel,children:d.label.length>22?`${d.label.slice(0,21)}…`:d.label}),d.value===null?e.jsx("line",{x1:124,y1:y+_/2,x2:134,y2:y+_/2,stroke:se,strokeWidth:2,strokeDasharray:"2 2"}):e.jsxs(e.Fragment,{children:[e.jsx("rect",{x:120,y,width:Math.max(2,Z),height:_,rx:4,fill:o,className:h.bar}),e.jsx("text",{x:120+Math.max(2,Z)+6,y:y+_/2,dy:"0.32em",className:h.valueLabel,children:c(d.value)})]}),e.jsx("rect",{className:h.hitArea,x:0,y:y-j/2,width:m,height:_+j,tabIndex:0,role:"img","aria-label":`${d.label}: ${d.value===null?"no data":c(d.value)}`,onPointerEnter:()=>f(T),onPointerLeave:()=>f(I=>I===T?null:I),onFocus:()=>f(T),onBlur:()=>f(I=>I===T?null:I)})]},d.label+T)})]}),r!==null?e.jsxs("div",{className:h.tooltip,style:{left:128,top:j+r*(_+j)-4},children:[e.jsx("span",{className:h.tooltipValue,children:t[r].value===null?"no data":c(t[r].value)}),e.jsx("span",{className:h.tooltipLabel,children:t[r].label})]}):null]})}const k=t.length?Math.max(ee,0):ee,i=Math.min(ee,k),L=20,C=30,D=l,V=D+L+C,K=t.length*(i+j)+j,E=L+D-(0-g)/M*D;return e.jsxs("div",{className:h.wrap,children:[e.jsxs("svg",{className:h.svg,width:K,height:V,viewBox:`0 0 ${K} ${V}`,role:"img","aria-label":b,children:[e.jsx("line",{x1:0,y1:E,x2:K,y2:E,className:h.baseline,stroke:ne}),t.map((u,$)=>{const _=j+$*(i+j),R=u.value!==null?Math.abs(u.value-g)/M*D:0,B=u.value!==null&&u.value>=0?E-R:E;return e.jsxs("g",{children:[u.value===null?e.jsx("line",{x1:_+i/2-5,y1:E,x2:_+i/2+5,y2:E,stroke:se,strokeWidth:2,strokeDasharray:"2 2"}):e.jsxs(e.Fragment,{children:[e.jsx("rect",{x:_,y:B,width:i,height:Math.max(2,R),rx:4,fill:o,className:h.bar}),e.jsx("text",{x:_+i/2,y:B-4,textAnchor:"middle",className:h.valueLabel,children:c(u.value)})]}),e.jsx("text",{x:_+i/2,y:V-8,textAnchor:"middle",className:h.axisLabel,children:u.label.length>10?`${u.label.slice(0,9)}…`:u.label}),e.jsx("rect",{className:h.hitArea,x:_-j/2,y:0,width:i+j,height:V,tabIndex:0,role:"img","aria-label":`${u.label}: ${u.value===null?"no data":c(u.value)}`,onPointerEnter:()=>f($),onPointerLeave:()=>f(m=>m===$?null:m),onFocus:()=>f($),onBlur:()=>f(m=>m===$?null:m)})]},u.label+$)})]}),r!==null?e.jsxs("div",{className:h.tooltip,style:{left:j+r*(i+j),top:0},id:`${x}-tooltip`,children:[e.jsx("span",{className:h.tooltipValue,children:t[r].value===null?"no data":c(t[r].value)}),e.jsx("span",{className:h.tooltipLabel,children:t[r].label})]}):null]})}const st="_line_gomyo_6",nt="_dot_gomyo_14",ce={line:st,dot:nt};function at({points:t,width:l=72,height:n=24,ariaLabel:o}){const c=t.filter(i=>i!==null);if(c.length<2)return e.jsx("svg",{width:l,height:n,viewBox:`0 0 ${l} ${n}`,role:"img","aria-label":o});const b=Math.min(...c,0),r=Math.max(...c,0)-b||1,f=l/Math.max(1,t.length-1),S=i=>n-(i-b)/r*(n-2)-1,F=[];let g=[];t.forEach((i,L)=>{if(i===null){g.length&&F.push(g),g=[];return}g.push({x:L*f,y:S(i)})}),g.length&&F.push(g);const M=t.map(i=>i!==null).lastIndexOf(!0),k=M>=0?{x:M*f,y:S(t[M])}:null;return e.jsxs("svg",{width:l,height:n,viewBox:`0 0 ${l} ${n}`,role:"img","aria-label":o,children:[F.map((i,L)=>e.jsx("path",{className:ce.line,d:i.map((C,D)=>`${D===0?"M":"L"}${C.x.toFixed(1)},${C.y.toFixed(1)}`).join(" ")},L)),k?e.jsx("circle",{className:ce.dot,cx:k.x,cy:k.y,r:2}):null]})}function ot(t){if(!Number.isFinite(t))return"—";const l=Math.abs(t);return l>=1e6?`${(t/1e6).toFixed(l>=1e7?0:1)}M`:l>=1e4?`${Math.round(t/1e3)}K`:l>=1e3?t.toLocaleString("en-US"):Number.isInteger(t)?String(t):t.toFixed(1)}function Lt(t){if(!Number.isFinite(t))return"—";const l=Math.abs(t),n=t<0?"-":"";return l>=1e6?`${n}$${(l/1e6).toFixed(1)}M`:l>=1e3?`${n}$${(l/1e3).toFixed(1)}K`:`${n}$${l.toFixed(2)}`}function $t(t,l=0){return Number.isFinite(t)?`${(t*100).toFixed(l)}%`:"—"}function ct(t){if(!Number.isFinite(t))return"—";const l=ot(Math.abs(t));return t>0?`+${l}`:t<0?`-${l}`:l}function wt(t){if(!/^\d{4}-\d{2}-\d{2}$/.test(t))return t;const l=new Date(`${t}T00:00:00Z`);return Number.isNaN(l.getTime())||l.toISOString().slice(0,10)!==t?t:l.toLocaleDateString("en-US",{month:"short",day:"numeric",timeZone:"UTC"})}function At(t){const l=new Date(t);return Number.isNaN(l.getTime())?"":l.toLocaleDateString("en-US",{month:"short",day:"numeric"})}const it="_tile_rp7c9_1",rt="_label_rp7c9_11",ut="_row_rp7c9_18",dt="_value_rp7c9_25",xt="_trendRow_rp7c9_31",_t="_delta_rp7c9_38",mt="_deltaGood_rp7c9_43",ht="_deltaBad_rp7c9_47",pt="_deltaNeutral_rp7c9_51",jt="_caption_rp7c9_55",A={tile:it,label:rt,row:ut,value:dt,trendRow:xt,delta:_t,deltaGood:mt,deltaBad:ht,deltaNeutral:pt,caption:jt};function Mt({label:t,value:l,caption:n,delta:o,trend:c,trendLabel:b}){const x=o==null||o.goodWhenPositive===void 0||o.value===0?A.deltaNeutral:o.value>0===o.goodWhenPositive?A.deltaGood:A.deltaBad;return e.jsxs("div",{className:A.tile,children:[e.jsx("span",{className:A.label,children:t}),e.jsx("div",{className:A.row,children:e.jsx("span",{className:A.value,children:l})}),e.jsxs("div",{className:A.trendRow,children:[n?e.jsx("span",{className:A.caption,children:n}):e.jsx("span",{}),c?e.jsx(at,{points:c,ariaLabel:b??`${t} trend`}):null]}),o?e.jsxs("span",{className:`${A.delta} ${x}`,children:[ct(o.value),o.versus?` ${o.versus}`:""]}):null]})}const gt="_table_1ggl4_1",vt="_numeric_1ggl4_22",le={table:gt,numeric:vt};function Bt({caption:t,columns:l,rows:n,rowKey:o}){return e.jsxs("table",{className:le.table,children:[e.jsx("caption",{className:"visually-hidden",children:t}),e.jsx("thead",{children:e.jsx("tr",{children:l.map(c=>e.jsx("th",{scope:"col",className:c.numeric?le.numeric:void 0,children:c.label},c.key))})}),e.jsx("tbody",{children:n.map((c,b)=>e.jsx("tr",{children:l.map(x=>e.jsx("td",{className:x.numeric?le.numeric:void 0,children:x.render(c)},x.key))},o(c,b)))})]})}export{Nt as B,ft as C,yt as L,Mt as S,Bt as T,ot as a,wt as b,$t as c,fe as d,At as e,Lt as f,q as s};
|
|
2
|
-
//# sourceMappingURL=TableView-Bj-w1O6o.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TableView-Bj-w1O6o.js","sources":["../../../../../../src/web-ui/components/charts/ChartContainer.tsx","../../../../../../src/web-ui/components/charts/Legend.tsx","../../../../../../src/web-ui/components/charts/colors.ts","../../../../../../src/web-ui/components/charts/LineChart.tsx","../../../../../../src/web-ui/components/charts/BarChart.tsx","../../../../../../src/web-ui/components/charts/Sparkline.tsx","../../../../../../src/web-ui/components/charts/format.ts","../../../../../../src/web-ui/components/charts/StatTile.tsx","../../../../../../src/web-ui/components/charts/TableView.tsx"],"sourcesContent":["/**\n * components/charts/ChartContainer.tsx — the figure every chart mounts\n * inside: title/description, the plot itself, an optional caveat banner\n * (epistemic-honesty-adjacent: for a chart built on data with a known,\n * disclosed limitation — see ProductionView's judge-verdict caveat), an\n * optional table-view twin (the WCAG-clean accessibility equivalent every\n * chart should ship per the dataviz skill), and an empty state that never\n * lies about missing data.\n */\nimport type { ReactNode } from 'react';\nimport './chart-tokens.css';\nimport styles from './ChartContainer.module.css';\n\nexport interface ChartContainerProps {\n title: string;\n description?: string;\n /** A short, honest note about a known limitation of the data behind this\n * chart (e.g. \"counts may include X, not yet separable\"). Never omit a\n * caveat to make a chart look cleaner than the data actually is. */\n caveat?: string;\n /** The chart itself (SVG + legend). */\n children: ReactNode;\n /** The accessibility twin — same data as a real HTML table. Omit only\n * when the chart already IS a table. */\n table?: ReactNode;\n /** When true, renders the empty state instead of `children`. */\n empty?: boolean;\n emptyMessage?: string;\n}\n\nexport function ChartContainer({\n title,\n description,\n caveat,\n children,\n table,\n empty,\n emptyMessage = 'No data for this window.',\n}: ChartContainerProps) {\n return (\n <figure className={styles.figure}>\n <figcaption className={styles.caption}>\n <span className={styles.title}>{title}</span>\n {description ? <span className={styles.description}>{description}</span> : null}\n </figcaption>\n {caveat ? (\n <p className={styles.caveat} role=\"note\">\n {caveat}\n </p>\n ) : null}\n {empty ? (\n <p className={styles.empty}>{emptyMessage}</p>\n ) : (\n <div className={styles.plot}>{children}</div>\n )}\n {table ? (\n <details className={styles.tableDisclosure}>\n <summary>View as table</summary>\n <div className={styles.tableBody}>{table}</div>\n </details>\n ) : null}\n </figure>\n );\n}\n","/**\n * components/charts/Legend.tsx — the dependable identity channel. A legend\n * is always present for two or more series (never rely on color-matching\n * alone); a single series needs no legend box because the chart's own title\n * already names it (see marks-and-anatomy.md \"Labels & legend\").\n */\nimport styles from './Legend.module.css';\n\nexport interface LegendItem {\n label: string;\n color: string;\n /** 'line' for line charts (a short stroke key), 'swatch' for bar/area. */\n kind?: 'line' | 'swatch';\n}\n\nexport function Legend({ items }: { items: LegendItem[] }) {\n if (items.length < 2) return null;\n return (\n <ul className={styles.legend}>\n {items.map((it) => (\n <li key={it.label} className={styles.item}>\n <span\n className={it.kind === 'line' ? styles.swatchLine : styles.swatch}\n style={{ background: it.color }}\n aria-hidden=\"true\"\n />\n {it.label}\n </li>\n ))}\n </ul>\n );\n}\n","/**\n * components/charts/colors.ts — the one place a chart asks for a color.\n * Every function returns a `var(--chart-*)` reference into chart-tokens.css\n * (never a literal hex) so theming is automatic and colors can never drift\n * out of sync between light and dark. See chart-tokens.css's header comment\n * for the palette-selection rationale — an exhaustive permutation search\n * clears the CVD adjacent floor (worst ΔE 13.8 light / 14.5 dark, target\n * 8.0) without changing which hues are used, only their series order.\n */\n\nconst SERIES_SLOTS = 7;\n\n/** Fixed-order categorical color for series index `slot` (0-based). Color\n * follows the entity, never its row number — callers must assign a series\n * its slot once (e.g. by stable sort order) and keep it even if other\n * series are filtered out; never reassign slots to \"fill the gap\" left by\n * a removed series (see dataviz anti-patterns: \"recolor-on-filter\"). */\nexport function seriesColor(slot: number): string {\n const n = ((slot % SERIES_SLOTS) + SERIES_SLOTS) % SERIES_SLOTS;\n return `var(--chart-series-${n + 1})`;\n}\n\n/** The \"Other\"/overflow bucket color — never part of the identity rotation. */\nexport const CHART_NEUTRAL = 'var(--chart-neutral)';\n\n/** Default single hue for magnitude (sequential) and for a single nominal\n * series (one series needs no legend box — every bar takes the same hue). */\nexport const CHART_SEQUENTIAL = 'var(--chart-sequential)';\nexport const CHART_SEQUENTIAL_SOFT = 'var(--chart-sequential-soft)';\n\nexport const CHART_DIVERGING_POS = 'var(--chart-diverging-pos)';\nexport const CHART_DIVERGING_NEG = 'var(--chart-diverging-neg)';\nexport const CHART_DIVERGING_MID = 'var(--chart-diverging-mid)';\n\nexport const CHART_GRID = 'var(--chart-grid)';\nexport const CHART_AXIS = 'var(--chart-axis)';\n","/**\n * components/charts/LineChart.tsx — trend over time. A gap (`null` y) is\n * split into a separate path segment so it renders as a visible break in\n * the line, never as a straight line through a missing value and never as\n * a silent zero. Single series gets an optional soft area fill; two-plus\n * series always render a legend (never color-matching alone).\n */\nimport { useRef, useState } from 'react';\nimport type { Series } from './types.js';\nimport { seriesColor, CHART_GRID, CHART_AXIS } from './colors.js';\nimport { Legend } from './Legend.js';\nimport './chart-tokens.css';\nimport styles from './LineChart.module.css';\n\nconst VBOX_W = 640;\nconst PAD_L = 44;\nconst PAD_R = 12;\nconst PAD_T = 12;\nconst PAD_B = 24;\nconst TICKS_Y = 4;\n/* Direct end-of-line labels need a gutter of their own. They are drawn in USER\n units — the viewBox scales the font along with the geometry, so a reserve\n measured in user units holds at every rendered width — and `--text-xs-size`\n resolves to 12 user units here, where the UI sans averages a shade over 6\n units per character at medium weight. 6.4 rounds that up so the reserve errs\n wide rather than clipping. Without the reserve the label was drawn at\n `VBOX_W - PAD_R + 4` with only PAD_R (12u) of room and the svg's own\n `overflow: hidden` cropped it to its first glyph — \"Estimated spend\"\n rendered as a lone \"E\". */\nconst END_LABEL_CH = 6.4;\nconst END_LABEL_GAP = 4;\n/* Past this the gutter would cost more plot than the label is worth, so the\n label is dropped rather than shrinking the chart around it. Nothing is lost:\n Legend.tsx deliberately renders nothing below two series because the panel\n heading already names a lone series, and two-plus series always have the\n legend regardless. */\nconst END_LABEL_MAX = 150;\n\ninterface Run {\n x: number;\n y: number;\n}\n\nfunction splitRuns(points: Series['points']): Run[][] {\n const runs: Run[][] = [];\n let current: Run[] = [];\n for (const p of points) {\n if (p.y === null) {\n if (current.length) runs.push(current);\n current = [];\n continue;\n }\n current.push({ x: p.x, y: p.y });\n }\n if (current.length) runs.push(current);\n return runs;\n}\n\nfunction niceTicks(min: number, max: number, count: number): number[] {\n if (max <= min) return [min];\n const step = (max - min) / count;\n return Array.from({ length: count + 1 }, (_, i) => min + step * i);\n}\n\nexport function LineChart({\n series,\n height = 200,\n area = false,\n formatX = (x: number) => String(x),\n formatY = (y: number) => String(y),\n ariaLabel,\n}: {\n series: Series[];\n height?: number;\n area?: boolean;\n formatX?: (x: number) => string;\n formatY?: (y: number) => string;\n ariaLabel: string;\n}) {\n const svgRef = useRef<SVGSVGElement>(null);\n const [hoverX, setHoverX] = useState<number | null>(null);\n const [tooltipPos, setTooltipPos] = useState<{ left: number; top: number } | null>(null);\n\n const allX = series.flatMap((s) => s.points.map((p) => p.x));\n const knownY = series.flatMap((s) => s.points.map((p) => p.y)).filter((y): y is number => y !== null);\n if (allX.length === 0) {\n return <p>No data.</p>;\n }\n const xMin = Math.min(...allX);\n const xMax = Math.max(...allX);\n const yMin = Math.min(0, ...knownY);\n const yMax = Math.max(0.0001, ...knownY);\n const xRange = xMax - xMin || 1;\n const yRange = yMax - yMin || 1;\n\n /* Decided before the scales, because the reserved gutter is what plotW is\n measured against — and the gridlines and x-axis stop at the same edge. */\n const wantEndLabels = series.length >= 1 && series.length <= 4;\n const endLabelW = wantEndLabels\n ? Math.max(...series.map((s) => s.label.length)) * END_LABEL_CH\n : 0;\n const showEndLabels = wantEndLabels && endLabelW <= END_LABEL_MAX;\n const padR = PAD_R + (showEndLabels ? END_LABEL_GAP + endLabelW : 0);\n const showLegend = series.length >= 2;\n\n const plotW = VBOX_W - PAD_L - padR;\n const plotH = height - PAD_T - PAD_B;\n const xScale = (x: number) => PAD_L + ((x - xMin) / xRange) * plotW;\n const yScale = (y: number) => PAD_T + plotH - ((y - yMin) / yRange) * plotH;\n\n const yTicks = niceTicks(yMin, yMax, TICKS_Y);\n\n // Nearest-x lookup across a reference axis (the union of all distinct x\n // values, since series may not share every point).\n const xAxis = Array.from(new Set(allX)).sort((a, b) => a - b);\n\n function nearestX(clientX: number): number | null {\n const svg = svgRef.current;\n if (!svg) return null;\n const rect = svg.getBoundingClientRect();\n const svgX = ((clientX - rect.left) / rect.width) * VBOX_W;\n const dataX = xMin + ((svgX - PAD_L) / plotW) * xRange;\n let nearest = xAxis[0];\n let best = Infinity;\n for (const x of xAxis) {\n const d = Math.abs(x - dataX);\n if (d < best) {\n best = d;\n nearest = x;\n }\n }\n return nearest;\n }\n\n function handleMove(e: React.PointerEvent<SVGSVGElement>) {\n const x = nearestX(e.clientX);\n if (x === null) return;\n setHoverX(x);\n const svg = svgRef.current;\n if (svg) {\n const rect = svg.getBoundingClientRect();\n const px = (xScale(x) / VBOX_W) * rect.width;\n setTooltipPos({ left: px, top: 0 });\n }\n }\n\n const hoverPoints =\n hoverX !== null\n ? series.map((s) => ({\n series: s,\n point: s.points.find((p) => p.x === hoverX) ?? null,\n }))\n : null;\n\n return (\n <div className={styles.wrap}>\n <svg\n ref={svgRef}\n className={styles.svg}\n viewBox={`0 0 ${VBOX_W} ${height}`}\n role=\"img\"\n aria-label={ariaLabel}\n onPointerMove={handleMove}\n onPointerLeave={() => setHoverX(null)}\n >\n {yTicks.map((t, i) => (\n <g key={i}>\n <line\n x1={PAD_L}\n x2={VBOX_W - padR}\n y1={yScale(t)}\n y2={yScale(t)}\n className={styles.gridline}\n stroke={CHART_GRID}\n />\n <text x={PAD_L - 6} y={yScale(t)} dy=\"0.32em\" textAnchor=\"end\" className={styles.axisLabel}>\n {formatY(t)}\n </text>\n </g>\n ))}\n <line\n x1={PAD_L}\n x2={VBOX_W - padR}\n y1={height - PAD_B}\n y2={height - PAD_B}\n className={styles.axis}\n stroke={CHART_AXIS}\n />\n {xAxis.length > 1\n ? [xAxis[0], xAxis[xAxis.length - 1]].map((x, i) => (\n <text\n key={i}\n x={xScale(x)}\n y={height - 6}\n textAnchor={i === 0 ? 'start' : 'end'}\n className={styles.axisLabel}\n >\n {formatX(x)}\n </text>\n ))\n : null}\n\n {series.map((s, si) => {\n const color = seriesColor(si);\n const runs = splitRuns(s.points);\n return (\n <g key={s.id}>\n {area && series.length === 1\n ? runs.map((run, ri) => {\n const d =\n run.map((p, j) => `${j === 0 ? 'M' : 'L'}${xScale(p.x)},${yScale(p.y)}`).join(' ') +\n ` L${xScale(run[run.length - 1].x)},${yScale(yMin)} L${xScale(run[0].x)},${yScale(yMin)} Z`;\n return <path key={ri} d={d} fill={color} className={styles.area} />;\n })\n : null}\n {runs.map((run, ri) => (\n <path\n key={ri}\n d={run.map((p, j) => `${j === 0 ? 'M' : 'L'}${xScale(p.x)},${yScale(p.y)}`).join(' ')}\n stroke={color}\n className={styles.line}\n />\n ))}\n {showEndLabels && runs.length ? (\n (() => {\n const lastRun = runs[runs.length - 1];\n const last = lastRun[lastRun.length - 1];\n return (\n <text\n x={xScale(last.x) + END_LABEL_GAP}\n y={yScale(last.y)}\n dy=\"0.32em\"\n className={styles.endLabel}\n fill={color}\n >\n {s.label}\n </text>\n );\n })()\n ) : null}\n </g>\n );\n })}\n\n {hoverX !== null ? (\n <line\n x1={xScale(hoverX)}\n x2={xScale(hoverX)}\n y1={PAD_T}\n y2={height - PAD_B}\n className={styles.crosshairLine}\n />\n ) : null}\n {hoverX !== null\n ? series.map((s, si) => {\n const p = s.points.find((pt) => pt.x === hoverX);\n if (!p || p.y === null) return null;\n return (\n <circle\n key={s.id}\n cx={xScale(p.x)}\n cy={yScale(p.y)}\n r={4}\n fill={seriesColor(si)}\n className={styles.marker}\n />\n );\n })\n : null}\n\n <rect\n x={PAD_L}\n y={PAD_T}\n width={plotW}\n height={plotH}\n className={styles.overlay}\n onFocus={() => setHoverX(xAxis[xAxis.length - 1] ?? null)}\n />\n </svg>\n {hoverPoints && tooltipPos ? (\n <div className={styles.tooltip} style={{ left: tooltipPos.left, top: tooltipPos.top }}>\n <div className={styles.tooltipDate}>{formatX(hoverX as number)}</div>\n {hoverPoints.map(({ series: s, point }, i) => (\n <div className={styles.tooltipRow} key={s.id}>\n <span className={styles.tooltipKey} style={{ background: seriesColor(i) }} aria-hidden=\"true\" />\n {point && point.y !== null ? (\n <>\n <span className={styles.tooltipValue}>{formatY(point.y)}</span>\n {showLegend ? <span>{s.label}</span> : null}\n </>\n ) : (\n <span className={styles.tooltipGap}>no data{showLegend ? ` — ${s.label}` : ''}</span>\n )}\n </div>\n ))}\n </div>\n ) : null}\n {showLegend ? (\n <Legend items={series.map((s, i) => ({ label: s.label, color: seriesColor(i), kind: 'line' }))} />\n ) : null}\n </div>\n );\n}\n","/**\n * components/charts/BarChart.tsx — categorical magnitude comparison.\n * Single hue by default (nominal categories never get a value-ramp — see\n * dataviz anti-patterns \"a value-ramp on nominal categories\"). Vertical for\n * a handful of short-named categories, horizontal for many or long-named\n * ones (dataviz choosing-a-form.md). Null values render as an explicit\n * \"no data\" dash, never a silent zero-height bar indistinguishable from a\n * real zero.\n */\nimport { useId, useState } from 'react';\nimport type { CategoricalDatum } from './types.js';\nimport { CHART_SEQUENTIAL, CHART_AXIS, CHART_GRID } from './colors.js';\nimport './chart-tokens.css';\nimport styles from './BarChart.module.css';\n\nconst BAR_MAX = 24;\nconst GAP = 10;\n\nexport function BarChart({\n data,\n height = 160,\n orientation = 'vertical',\n color = CHART_SEQUENTIAL,\n formatValue = (v: number) => String(v),\n ariaLabel,\n}: {\n data: CategoricalDatum[];\n height?: number;\n orientation?: 'vertical' | 'horizontal';\n color?: string;\n formatValue?: (v: number) => string;\n ariaLabel: string;\n}) {\n const uid = useId();\n const [hover, setHover] = useState<number | null>(null);\n\n const known = data.map((d) => d.value).filter((v): v is number => v !== null);\n const maxVal = Math.max(0, ...known, 0.0001);\n const minVal = Math.min(0, ...known);\n const range = maxVal - minVal || 1;\n\n if (orientation === 'horizontal') {\n const LABEL_W = 120;\n const PAD_R = 48;\n const rowH = Math.min(BAR_MAX, Math.max(14, Math.floor((height - GAP) / data.length) - GAP));\n const plotW = 420;\n const svgH = data.length * (rowH + GAP) + GAP;\n const svgW = LABEL_W + plotW + PAD_R;\n\n return (\n <div className={styles.wrap}>\n <svg\n className={styles.svg}\n width={svgW}\n height={svgH}\n viewBox={`0 0 ${svgW} ${svgH}`}\n role=\"img\"\n aria-label={ariaLabel}\n >\n <line x1={LABEL_W} y1={0} x2={LABEL_W} y2={svgH} className={styles.baseline} stroke={CHART_AXIS} />\n {data.map((d, i) => {\n const y = GAP + i * (rowH + GAP);\n const barW = d.value !== null ? ((d.value - minVal) / range) * plotW : 0;\n return (\n <g key={d.label + i}>\n <text\n x={LABEL_W - 8}\n y={y + rowH / 2}\n dy=\"0.32em\"\n textAnchor=\"end\"\n className={styles.categoryLabel}\n >\n {d.label.length > 22 ? `${d.label.slice(0, 21)}…` : d.label}\n </text>\n {d.value === null ? (\n <line\n x1={LABEL_W + 4}\n y1={y + rowH / 2}\n x2={LABEL_W + 14}\n y2={y + rowH / 2}\n stroke={CHART_GRID}\n strokeWidth={2}\n strokeDasharray=\"2 2\"\n />\n ) : (\n <>\n <rect\n x={LABEL_W}\n y={y}\n width={Math.max(2, barW)}\n height={rowH}\n rx={4}\n fill={color}\n className={styles.bar}\n />\n <text\n x={LABEL_W + Math.max(2, barW) + 6}\n y={y + rowH / 2}\n dy=\"0.32em\"\n className={styles.valueLabel}\n >\n {formatValue(d.value)}\n </text>\n </>\n )}\n <rect\n className={styles.hitArea}\n x={0}\n y={y - GAP / 2}\n width={svgW}\n height={rowH + GAP}\n tabIndex={0}\n role=\"img\"\n aria-label={`${d.label}: ${d.value === null ? 'no data' : formatValue(d.value)}`}\n onPointerEnter={() => setHover(i)}\n onPointerLeave={() => setHover((h) => (h === i ? null : h))}\n onFocus={() => setHover(i)}\n onBlur={() => setHover((h) => (h === i ? null : h))}\n />\n </g>\n );\n })}\n </svg>\n {hover !== null ? (\n <div\n className={styles.tooltip}\n style={{ left: LABEL_W + 8, top: GAP + hover * (rowH + GAP) - 4 }}\n >\n <span className={styles.tooltipValue}>\n {data[hover].value === null ? 'no data' : formatValue(data[hover].value as number)}\n </span>\n <span className={styles.tooltipLabel}>{data[hover].label}</span>\n </div>\n ) : null}\n </div>\n );\n }\n\n // Vertical orientation.\n const barSlot = data.length ? Math.max(BAR_MAX, 0) : BAR_MAX;\n const barW = Math.min(BAR_MAX, barSlot);\n const PAD_T = 20;\n const PAD_B = 30;\n const plotH = height;\n const svgH = plotH + PAD_T + PAD_B;\n const svgW = data.length * (barW + GAP) + GAP;\n const zeroY = PAD_T + plotH - ((0 - minVal) / range) * plotH;\n\n return (\n <div className={styles.wrap}>\n <svg\n className={styles.svg}\n width={svgW}\n height={svgH}\n viewBox={`0 0 ${svgW} ${svgH}`}\n role=\"img\"\n aria-label={ariaLabel}\n >\n <line x1={0} y1={zeroY} x2={svgW} y2={zeroY} className={styles.baseline} stroke={CHART_AXIS} />\n {data.map((d, i) => {\n const x = GAP + i * (barW + GAP);\n const barH = d.value !== null ? (Math.abs(d.value - minVal) / range) * plotH : 0;\n const top = d.value !== null && d.value >= 0 ? zeroY - barH : zeroY;\n return (\n <g key={d.label + i}>\n {d.value === null ? (\n <line\n x1={x + barW / 2 - 5}\n y1={zeroY}\n x2={x + barW / 2 + 5}\n y2={zeroY}\n stroke={CHART_GRID}\n strokeWidth={2}\n strokeDasharray=\"2 2\"\n />\n ) : (\n <>\n <rect\n x={x}\n y={top}\n width={barW}\n height={Math.max(2, barH)}\n rx={4}\n fill={color}\n className={styles.bar}\n />\n <text x={x + barW / 2} y={top - 4} textAnchor=\"middle\" className={styles.valueLabel}>\n {formatValue(d.value)}\n </text>\n </>\n )}\n <text\n x={x + barW / 2}\n y={svgH - 8}\n textAnchor=\"middle\"\n className={styles.axisLabel}\n >\n {d.label.length > 10 ? `${d.label.slice(0, 9)}…` : d.label}\n </text>\n <rect\n className={styles.hitArea}\n x={x - GAP / 2}\n y={0}\n width={barW + GAP}\n height={svgH}\n tabIndex={0}\n role=\"img\"\n aria-label={`${d.label}: ${d.value === null ? 'no data' : formatValue(d.value)}`}\n onPointerEnter={() => setHover(i)}\n onPointerLeave={() => setHover((h) => (h === i ? null : h))}\n onFocus={() => setHover(i)}\n onBlur={() => setHover((h) => (h === i ? null : h))}\n />\n </g>\n );\n })}\n </svg>\n {hover !== null ? (\n <div\n className={styles.tooltip}\n style={{ left: GAP + hover * (barW + GAP), top: 0 }}\n id={`${uid}-tooltip`}\n >\n <span className={styles.tooltipValue}>\n {data[hover].value === null ? 'no data' : formatValue(data[hover].value as number)}\n </span>\n <span className={styles.tooltipLabel}>{data[hover].label}</span>\n </div>\n ) : null}\n </div>\n );\n}\n","/**\n * components/charts/Sparkline.tsx — the 12-ish-point inline trend for a\n * stat tile (marks-and-anatomy.md \"Figures\" stat-tile contract). No axes,\n * no legend, no tooltip — it is a glance, not a chart; the real numbers\n * live in the stat tile's value and in the full chart elsewhere on the\n * view. Gaps (`null`) break the line rather than reading as a dip to zero.\n */\nimport './chart-tokens.css';\nimport styles from './Sparkline.module.css';\n\nexport function Sparkline({\n points,\n width = 72,\n height = 24,\n ariaLabel,\n}: {\n points: (number | null)[];\n width?: number;\n height?: number;\n ariaLabel: string;\n}) {\n const known = points.filter((p): p is number => p !== null);\n if (known.length < 2) {\n return (\n <svg width={width} height={height} viewBox={`0 0 ${width} ${height}`} role=\"img\" aria-label={ariaLabel} />\n );\n }\n const min = Math.min(...known, 0);\n const max = Math.max(...known, 0);\n const range = max - min || 1;\n const stepX = width / Math.max(1, points.length - 1);\n const yOf = (v: number) => height - ((v - min) / range) * (height - 2) - 1;\n\n // Split into contiguous runs so a null renders as a real gap, not a dip.\n const runs: { x: number; y: number }[][] = [];\n let current: { x: number; y: number }[] = [];\n points.forEach((v, i) => {\n if (v === null) {\n if (current.length) runs.push(current);\n current = [];\n return;\n }\n current.push({ x: i * stepX, y: yOf(v) });\n });\n if (current.length) runs.push(current);\n\n const lastKnownIndex = points.map((v) => v !== null).lastIndexOf(true);\n const lastPoint =\n lastKnownIndex >= 0 ? { x: lastKnownIndex * stepX, y: yOf(points[lastKnownIndex] as number) } : null;\n\n return (\n <svg width={width} height={height} viewBox={`0 0 ${width} ${height}`} role=\"img\" aria-label={ariaLabel}>\n {runs.map((run, i) => (\n <path\n key={i}\n className={styles.line}\n d={run.map((p, j) => `${j === 0 ? 'M' : 'L'}${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(' ')}\n />\n ))}\n {lastPoint ? <circle className={styles.dot} cx={lastPoint.x} cy={lastPoint.y} r={2} /> : null}\n </svg>\n );\n}\n","/**\n * components/charts/format.ts — number formatting shared by every chart and\n * stat tile. Proportional figures everywhere EXCEPT columns that must align\n * vertically (table cells, axis ticks) — see marks-and-anatomy.md \"Proportional\n * figures for big numbers; tabular only in columns.\" Callers apply\n * `font-variant-numeric: tabular-nums` via CSS where that applies; these\n * functions only produce the string.\n */\n\n/** Auto-compact a count: 1,284 / 12.9K / 4.2M. */\nexport function formatCompact(n: number): string {\n if (!Number.isFinite(n)) return '—';\n const abs = Math.abs(n);\n if (abs >= 1_000_000) return `${(n / 1_000_000).toFixed(abs >= 10_000_000 ? 0 : 1)}M`;\n if (abs >= 10_000) return `${Math.round(n / 1000)}K`;\n if (abs >= 1_000) return n.toLocaleString('en-US');\n return Number.isInteger(n) ? String(n) : n.toFixed(1);\n}\n\n/** Auto-compact USD: $4.20 / $1.2K / $4.2M. */\nexport function formatUsd(n: number): string {\n if (!Number.isFinite(n)) return '—';\n const abs = Math.abs(n);\n const sign = n < 0 ? '-' : '';\n if (abs >= 1_000_000) return `${sign}$${(abs / 1_000_000).toFixed(1)}M`;\n if (abs >= 1_000) return `${sign}$${(abs / 1_000).toFixed(1)}K`;\n return `${sign}$${abs.toFixed(2)}`;\n}\n\n/** Fraction (0..1) as a percentage. */\nexport function formatPercent(fraction: number, digits = 0): string {\n if (!Number.isFinite(fraction)) return '—';\n return `${(fraction * 100).toFixed(digits)}%`;\n}\n\n/** Signed delta for a stat tile: \"+12\" / \"-3\" / \"0\". */\nexport function formatSignedCompact(n: number): string {\n if (!Number.isFinite(n)) return '—';\n const s = formatCompact(Math.abs(n));\n if (n > 0) return `+${s}`;\n if (n < 0) return `-${s}`;\n return s;\n}\n\n/** YYYY-MM-DD -> short label, e.g. \"Aug 14\". Local-independent (UTC parse). */\nexport function formatDayLabel(day: string): string {\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(day)) return day;\n const d = new Date(`${day}T00:00:00Z`);\n // Date normalizes impossible dates; compare the padded UTC date to reject rollover.\n if (Number.isNaN(d.getTime()) || d.toISOString().slice(0, 10) !== day) return day;\n return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', timeZone: 'UTC' });\n}\n\n/** Epoch ms -> short label for axis ticks. */\nexport function formatTimeLabel(ms: number): string {\n const d = new Date(ms);\n if (Number.isNaN(d.getTime())) return '';\n return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });\n}\n","/**\n * components/charts/StatTile.tsx — value + delta + optional sparkline, the\n * figure contract from marks-and-anatomy.md. Use for a single current value\n * (a one-bar bar chart is never the answer — this is). `value` takes a\n * ReactNode (not just a string) so callers can wrap a sourceQuality-bearing\n * field in <Epistemic/> and pass that straight through.\n */\nimport type { ReactNode } from 'react';\nimport { formatSignedCompact } from './format.js';\nimport { Sparkline } from './Sparkline.js';\nimport styles from './StatTile.module.css';\n\nexport interface StatTileDelta {\n /** Signed raw value, e.g. +12 or -3. */\n value: number;\n /** Whether a positive delta reads as good (green) or bad (red). Omit for\n * a neutral, non-judgmental delta (e.g. \"goals in flight\" — more isn't\n * inherently good or bad). */\n goodWhenPositive?: boolean;\n /** vs which period, e.g. \"vs yesterday\". */\n versus?: string;\n}\n\nexport function StatTile({\n label,\n value,\n caption,\n delta,\n trend,\n trendLabel,\n}: {\n label: string;\n value: ReactNode;\n caption?: ReactNode;\n delta?: StatTileDelta | null;\n trend?: (number | null)[];\n trendLabel?: string;\n}) {\n const deltaTone =\n delta == null || delta.goodWhenPositive === undefined\n ? styles.deltaNeutral\n : delta.value === 0\n ? styles.deltaNeutral\n : (delta.value > 0) === delta.goodWhenPositive\n ? styles.deltaGood\n : styles.deltaBad;\n\n return (\n <div className={styles.tile}>\n <span className={styles.label}>{label}</span>\n <div className={styles.row}>\n <span className={styles.value}>{value}</span>\n </div>\n <div className={styles.trendRow}>\n {caption ? <span className={styles.caption}>{caption}</span> : <span />}\n {trend ? <Sparkline points={trend} ariaLabel={trendLabel ?? `${label} trend`} /> : null}\n </div>\n {delta ? (\n <span className={`${styles.delta} ${deltaTone}`}>\n {formatSignedCompact(delta.value)}\n {delta.versus ? ` ${delta.versus}` : ''}\n </span>\n ) : null}\n </div>\n );\n}\n","/**\n * components/charts/TableView.tsx — the WCAG-clean accessibility twin every\n * chart should ship (dataviz skill: \"no table view / color-only encoding on\n * a continuous scale\" is an anti-pattern). Every value a chart's tooltip or\n * direct label shows must also be reachable here without hovering anything.\n */\nimport type { ReactNode } from 'react';\nimport styles from './TableView.module.css';\n\nexport interface TableColumn<T> {\n key: string;\n label: string;\n numeric?: boolean;\n render: (row: T) => ReactNode;\n}\n\nexport function TableView<T>({\n caption,\n columns,\n rows,\n rowKey,\n}: {\n caption: string;\n columns: TableColumn<T>[];\n rows: T[];\n rowKey: (row: T, index: number) => string;\n}) {\n return (\n <table className={styles.table}>\n <caption className=\"visually-hidden\">{caption}</caption>\n <thead>\n <tr>\n {columns.map((c) => (\n <th key={c.key} scope=\"col\" className={c.numeric ? styles.numeric : undefined}>\n {c.label}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {rows.map((row, i) => (\n <tr key={rowKey(row, i)}>\n {columns.map((c) => (\n <td key={c.key} className={c.numeric ? styles.numeric : undefined}>\n {c.render(row)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n );\n}\n"],"names":["ChartContainer","title","description","caveat","children","table","empty","emptyMessage","jsxs","styles","jsx","Legend","items","it","SERIES_SLOTS","seriesColor","slot","CHART_SEQUENTIAL","CHART_GRID","CHART_AXIS","VBOX_W","PAD_L","PAD_R","PAD_T","PAD_B","TICKS_Y","END_LABEL_CH","END_LABEL_GAP","END_LABEL_MAX","splitRuns","points","runs","current","p","niceTicks","min","max","count","step","_","i","LineChart","series","height","area","formatX","formatY","y","ariaLabel","svgRef","useRef","hoverX","setHoverX","useState","tooltipPos","setTooltipPos","allX","knownY","xMin","xMax","yMin","yMax","xRange","yRange","wantEndLabels","endLabelW","showEndLabels","padR","showLegend","plotW","plotH","xScale","x","yScale","yTicks","xAxis","a","b","nearestX","clientX","svg","rect","svgX","dataX","nearest","best","d","handleMove","e","px","hoverPoints","t","si","color","run","ri","j","lastRun","last","pt","point","Fragment","BAR_MAX","GAP","BarChart","data","orientation","formatValue","v","uid","useId","hover","setHover","known","maxVal","minVal","range","rowH","svgH","svgW","barW","h","barSlot","zeroY","barH","top","Sparkline","width","stepX","yOf","lastKnownIndex","lastPoint","formatCompact","n","abs","formatUsd","sign","formatPercent","fraction","digits","formatSignedCompact","s","formatDayLabel","day","formatTimeLabel","ms","StatTile","label","value","caption","delta","trend","trendLabel","deltaTone","TableView","columns","rows","rowKey","row","c"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
:root{--chart-series-1: var(--status-success-solid);--chart-series-2: var(--phase-2);--chart-series-3: var(--phase-5);--chart-series-4: var(--status-danger-solid);--chart-series-5: var(--phase-1);--chart-series-6: var(--phase-4);--chart-series-7: var(--phase-3);--chart-neutral: var(--status-neutral-solid);--chart-sequential: var(--accent-500);--chart-sequential-soft: var(--accent-300);--chart-diverging-pos: var(--accent-500);--chart-diverging-neg: var(--status-danger-solid);--chart-diverging-mid: var(--border-strong);--chart-grid: var(--border-subtle);--chart-axis: var(--border-strong);--chart-surface: var(--bg-surface);--chart-tooltip-bg: var(--bg-surface-raised);--chart-tooltip-border: var(--border-default)}._figure_1si9v_1{margin:0;border:1px solid var(--border-subtle);border-radius:var(--radius-lg);background:var(--bg-surface);padding:var(--space-4)}._caption_1si9v_12{display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-3);margin-bottom:var(--space-3)}._title_1si9v_20{font-size:var(--text-sm-size);font-weight:var(--font-weight-semibold);color:var(--text-primary)}._description_1si9v_26{font-size:var(--text-xs-size);color:var(--text-tertiary)}._plot_1si9v_31{width:100%;overflow-x:auto}._tableDisclosure_1si9v_36{margin-top:var(--space-3);border-top:1px solid var(--border-subtle);padding-top:var(--space-2)}._tableDisclosure_1si9v_36>summary{cursor:pointer;font-size:var(--text-xs-size);color:var(--text-secondary);list-style:none}._tableDisclosure_1si9v_36>summary::-webkit-details-marker{display:none}._tableDisclosure_1si9v_36>summary:before{content:"▸ "}._tableDisclosure_1si9v_36[open]>summary:before{content:"▾ "}._tableBody_1si9v_61{margin-top:var(--space-2)}._caveat_1si9v_65{margin:0 0 var(--space-3);padding:var(--space-2) var(--space-3);border-radius:var(--radius-md);background:var(--status-unknown-bg);color:var(--status-unknown-fg);font-size:var(--text-xs-size);line-height:var(--text-sm-line)}._empty_1si9v_75{color:var(--text-tertiary);font-size:var(--text-sm-size);padding:var(--space-6) 0;text-align:center}._legend_4pgvn_1{display:flex;flex-wrap:wrap;gap:var(--space-1) var(--space-4);margin:var(--space-2) 0 0;padding:0;list-style:none}._item_4pgvn_10{display:inline-flex;align-items:center;gap:var(--space-2);font-size:var(--text-xs-size);color:var(--text-secondary)}._swatch_4pgvn_18{width:10px;height:10px;border-radius:var(--radius-full);flex:none}._swatchLine_4pgvn_25{width:14px;height:2px;border-radius:var(--radius-full);flex:none}._svg_djmd1_1{display:block;width:100%;height:auto}._gridline_djmd1_7{stroke:var(--chart-grid);stroke-width:1}._axis_djmd1_12{stroke:var(--chart-axis);stroke-width:1}._axisLabel_djmd1_17{font-size:var(--text-xs-size);fill:var(--text-tertiary);font-family:var(--font-ui)}._line_djmd1_23{fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}._area_djmd1_30{opacity:.1;stroke:none}._marker_djmd1_35{stroke:var(--chart-surface);stroke-width:2}._endLabel_djmd1_40{font-size:var(--text-xs-size);font-family:var(--font-ui);font-weight:var(--font-weight-medium)}._crosshairLine_djmd1_46{stroke:var(--chart-axis);stroke-width:1;pointer-events:none}._overlay_djmd1_52{fill:transparent;cursor:crosshair}._wrap_djmd1_57{position:relative}._tooltip_djmd1_61{position:absolute;pointer-events:none;background:var(--chart-tooltip-bg);border:1px solid var(--chart-tooltip-border);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);padding:var(--space-2);font-size:var(--text-xs-size);color:var(--text-primary);white-space:nowrap;z-index:var(--z-dropdown);transform:translate(-50%,-100%);margin-top:-10px}._tooltipDate_djmd1_77{color:var(--text-tertiary);margin-bottom:var(--space-1)}._tooltipRow_djmd1_82{display:flex;align-items:center;gap:var(--space-1)}._tooltipKey_djmd1_88{width:12px;height:2px;flex:none}._tooltipValue_djmd1_94{font-weight:var(--font-weight-semibold);font-variant-numeric:tabular-nums}._tooltipGap_djmd1_99{color:var(--text-tertiary);font-style:italic}._svg_o4jfa_1{display:block;overflow:visible}._bar_o4jfa_6{transition:opacity var(--duration-fast) var(--ease-standard)}._bar_o4jfa_6:hover,._bar_o4jfa_6:focus-visible{opacity:.82}._baseline_o4jfa_15{stroke:var(--chart-axis);stroke-width:1}._gridline_o4jfa_20{stroke:var(--chart-grid);stroke-width:1}._axisLabel_o4jfa_25{font-size:10px;fill:var(--text-tertiary);font-family:var(--font-ui)}._valueLabel_o4jfa_31{font-size:10px;fill:var(--text-secondary);font-family:var(--font-ui);font-variant-numeric:tabular-nums}._categoryLabel_o4jfa_38{font-size:10px;fill:var(--text-secondary);font-family:var(--font-ui)}._hitArea_o4jfa_44{fill:transparent;cursor:pointer}._tooltip_o4jfa_49{position:absolute;pointer-events:none;background:var(--chart-tooltip-bg);border:1px solid var(--chart-tooltip-border);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);padding:var(--space-1) var(--space-2);font-size:var(--text-xs-size);color:var(--text-primary);white-space:nowrap;z-index:var(--z-dropdown)}._tooltipValue_o4jfa_63{font-weight:var(--font-weight-semibold);font-variant-numeric:tabular-nums}._tooltipLabel_o4jfa_68{color:var(--text-tertiary);margin-left:var(--space-1)}._wrap_o4jfa_73{position:relative}._sparkline_gomyo_1{display:block;overflow:visible}._line_gomyo_6{fill:none;stroke:var(--text-tertiary);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}._dot_gomyo_14{fill:var(--chart-sequential)}._tile_rp7c9_1{display:flex;flex-direction:column;gap:var(--space-1);padding:var(--space-4);border-radius:var(--radius-lg);border:1px solid var(--border-subtle);background:var(--bg-surface)}._label_rp7c9_11{font-size:var(--text-xs-size);color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.04em}._row_rp7c9_18{display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-2)}._value_rp7c9_25{font-size:var(--text-2xl-size);font-weight:var(--font-weight-semibold);color:var(--text-primary)}._trendRow_rp7c9_31{display:flex;align-items:center;justify-content:space-between;gap:var(--space-2)}._delta_rp7c9_38{font-size:var(--text-xs-size);font-variant-numeric:tabular-nums}._deltaGood_rp7c9_43{color:var(--status-success-fg)}._deltaBad_rp7c9_47{color:var(--status-danger-fg)}._deltaNeutral_rp7c9_51{color:var(--text-tertiary)}._caption_rp7c9_55{font-size:var(--text-xs-size);color:var(--text-tertiary)}._table_1ggl4_1{width:100%;border-collapse:collapse;font-size:var(--text-xs-size)}._table_1ggl4_1 th,._table_1ggl4_1 td{text-align:left;padding:var(--space-1) var(--space-2);border-bottom:1px solid var(--border-subtle)}._table_1ggl4_1 th{color:var(--text-tertiary);font-weight:var(--font-weight-medium);text-transform:uppercase;letter-spacing:.04em;font-size:var(--text-xs-size)}._numeric_1ggl4_22{text-align:right;font-variant-numeric:tabular-nums}
|