diff --git a/src/app.css b/src/app.css index e570d513..85c5edae 100644 --- a/src/app.css +++ b/src/app.css @@ -211,6 +211,7 @@ button.icon-btn { height: 32px; } + /* Form elements */ input, select, @@ -337,6 +338,105 @@ input[type="checkbox"]:focus-visible { color: var(--accent); } +/* ─── Component library ───────────────────────────────────────────────────── + Shared building blocks — prefer these over per-component re-definitions. */ + +/* Section label — small uppercase heading used across panels, dialogs and pages */ +.section-label, +.properties-dialog .section-title { + font-size: 10px; + font-weight: 600; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.5px; +} + +/* App nav bar — same chrome on the editor and the landing page */ +.nav { + display: flex; + align-items: center; + justify-content: space-between; + height: var(--header-height); + padding: 0 var(--space-md); + background: var(--surface-raised); + border-bottom: 1px solid var(--border); + flex-shrink: 0; +} + +.nav .nav-side { + display: flex; + align-items: center; + gap: var(--space-xs); +} + +/* Header strip atop panels and dialogs */ +.panel-header { + display: flex; + align-items: center; + justify-content: space-between; + min-height: var(--header-height); + padding: 0 var(--space-md); + background: var(--surface-raised); + border-bottom: 1px solid var(--border); + font-weight: 500; + font-size: var(--font-base); + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.5px; + flex-shrink: 0; +} + +/* Card — raised tile; `.interactive` adds the accent-ring hover signature */ +.card { + background: var(--surface-raised); + border: 1px solid var(--border); + border-radius: var(--radius-lg); + overflow: hidden; + transition: border-color var(--transition-fast), box-shadow var(--transition-fast); +} + +.card.interactive { + cursor: pointer; +} + +.card.interactive:hover { + border-color: var(--accent); + box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 25%, transparent); +} + +/* Action card — vertical icon-over-label link/button (quick actions) */ +.action-card { + display: flex; + flex-direction: column; + align-items: center; + gap: 6px; + padding: 6px 8px; + background: transparent; + border: none; + border-radius: var(--radius-md); + color: var(--text-muted); + cursor: pointer; + text-decoration: none; + font-family: inherit; + font-size: 11px; + font-weight: 500; +} + +.action-card svg { + color: var(--accent); + transition: transform 0.15s ease; +} + +.action-card:hover svg { + transform: scale(1.2); +} + +/* Separator — hairline between page sections */ +.separator { + height: 1px; + background: var(--border); +} + /* Dialog backdrop */ .dialog-backdrop { position: fixed; @@ -354,7 +454,7 @@ input[type="checkbox"]:focus-visible { background: transparent; } -/* Dialog header */ +/* Dialog header — the panel-header strip with dialog corner rounding */ .dialog-header { display: flex; align-items: center; @@ -369,6 +469,7 @@ input[type="checkbox"]:focus-visible { color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; + flex-shrink: 0; } /* Properties dialog shared styles (Block/Event properties) */ @@ -445,12 +546,8 @@ input[type="checkbox"]:focus-visible { margin-bottom: 0; } +/* Typography from .section-label (see component library); spacing only */ .properties-dialog .section-title { - font-size: 10px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.5px; - color: var(--text-muted); margin-bottom: var(--space-sm); } diff --git a/src/app.html b/src/app.html index 3e67f325..b32c8eeb 100644 --- a/src/app.html +++ b/src/app.html @@ -4,11 +4,11 @@ - PathView — Visual Block Diagram Simulation Editor + PathView · Visual Block Diagram Simulation Editor - + - +
{#if isFileDragOver}
@@ -1079,32 +1086,40 @@ bind:edges {nodeTypes} {edgeTypes} - onconnect={handleConnect} - onnodedragstart={handleNodeDragStart} - onnodedrag={handleNodeDrag} - onnodedragstop={handleNodeDragStop} - ondelete={handleDelete} - onselectionchange={handleSelectionChange} - ondrop={(e: any) => handleDrop(e.event || e)} - ondragover={(e: any) => handleDragOver(e.event || e)} - onnodecontextmenu={handleNodeContextMenu} - onedgecontextmenu={handleEdgeContextMenu} - onpanecontextmenu={handlePaneContextMenu} + onconnect={readonly ? undefined : handleConnect} + onnodedragstart={readonly ? undefined : handleNodeDragStart} + onnodedrag={readonly ? undefined : handleNodeDrag} + onnodedragstop={readonly ? undefined : handleNodeDragStop} + ondelete={readonly ? undefined : handleDelete} + onselectionchange={readonly ? undefined : handleSelectionChange} + ondrop={readonly ? undefined : (e: any) => handleDrop(e.event || e)} + ondragover={readonly ? undefined : (e: any) => handleDragOver(e.event || e)} + onnodecontextmenu={readonly ? undefined : handleNodeContextMenu} + onedgecontextmenu={readonly ? undefined : handleEdgeContextMenu} + onpanecontextmenu={readonly ? undefined : handlePaneContextMenu} nodeOrigin={[0.5, 0.5]} {...{ snapToGrid: true, snapGrid: SNAP_GRID } as any} - deleteKeyCode={['Delete', 'Backspace']} - selectionKeyCode={['Shift']} - multiSelectionKeyCode={['Shift', 'Meta', 'Control']} + deleteKeyCode={readonly ? null : ['Delete', 'Backspace']} + selectionKeyCode={readonly ? null : ['Shift']} + multiSelectionKeyCode={readonly ? null : ['Shift', 'Meta', 'Control']} {colorMode} - connectOnClick - edgesReconnectable - edgesFocusable - edgesSelectable + connectOnClick={!readonly} + nodesDraggable={!readonly} + nodesConnectable={!readonly} + elementsSelectable={!readonly} + edgesReconnectable={!readonly} + edgesFocusable={!readonly} + edgesSelectable={!readonly} + panOnDrag={!readonly} + zoomOnScroll={!readonly} + zoomOnPinch={!readonly} + preventScrolling={!readonly} + fitView={readonly} zoomOnDoubleClick={false} elevateEdgesOnSelect={false} proOptions={{ hideAttribution: true }} > - +
diff --git a/src/lib/components/FlowUpdater.svelte b/src/lib/components/FlowUpdater.svelte index a6b1dbef..4b891a00 100644 --- a/src/lib/components/FlowUpdater.svelte +++ b/src/lib/components/FlowUpdater.svelte @@ -23,9 +23,13 @@ pendingUpdates: string[]; onUpdatesProcessed: () => void; edges?: { id: string }[]; + /** The canvas doesn't fill the window (e.g. landing preview tile) — + * the panel-padding fitView math is window-based, so use SvelteFlow's + * native fitView against the actual canvas dimensions instead. */ + embedded?: boolean; } - let { pendingUpdates, onUpdatesProcessed, edges = [] }: Props = $props(); + let { pendingUpdates, onUpdatesProcessed, edges = [], embedded = false }: Props = $props(); const { getNodes, getEdges, fitView, zoomIn, zoomOut, getViewport, setViewport, screenToFlowPosition } = useSvelteFlow(); const updateNodeInternals = useUpdateNodeInternals(); @@ -36,6 +40,10 @@ if (nodes.length === 0) { return; } + if (embedded) { + fitView({ padding: 0.1, duration }); + return; + } const previewsPinned = get(pinnedPreviewsStore); const plotState = get(plotDataStore); diff --git a/src/lib/components/ResizablePanel.svelte b/src/lib/components/ResizablePanel.svelte index a7af2989..a2de80a1 100644 --- a/src/lib/components/ResizablePanel.svelte +++ b/src/lib/components/ResizablePanel.svelte @@ -343,22 +343,7 @@ } - /* Panel header */ - .panel-header { - display: flex; - align-items: center; - justify-content: space-between; - height: var(--header-height); - padding: 0 var(--space-md); - background: var(--surface-raised); - border-bottom: 1px solid var(--border); - font-weight: 500; - font-size: var(--font-base); - color: var(--text-muted); - text-transform: uppercase; - letter-spacing: 0.5px; - flex-shrink: 0; - } + /* .panel-header comes from the app.css component library */ .panel-toolbar { flex-shrink: 0; diff --git a/src/lib/components/WelcomeModal.svelte b/src/lib/components/WelcomeModal.svelte deleted file mode 100644 index 22e1eaf8..00000000 --- a/src/lib/components/WelcomeModal.svelte +++ /dev/null @@ -1,479 +0,0 @@ - - - - - - - - - - - diff --git a/src/lib/components/dialogs/KeyboardShortcutsDialog.svelte b/src/lib/components/dialogs/KeyboardShortcutsDialog.svelte index 52ba9b3f..af5e390f 100644 --- a/src/lib/components/dialogs/KeyboardShortcutsDialog.svelte +++ b/src/lib/components/dialogs/KeyboardShortcutsDialog.svelte @@ -97,7 +97,7 @@
{#each shortcuts as section}
-
{section.category}
+
{#each section.items as shortcut}
@@ -151,11 +151,8 @@ border-bottom: none; } + /* Typography from .section-label (app.css component library) */ .section-header { - font-size: 10px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.5px; color: var(--text-disabled); margin-bottom: var(--space-sm); } diff --git a/src/lib/components/panels/NodeLibrary.svelte b/src/lib/components/panels/NodeLibrary.svelte index 0c1e9094..a397fef0 100644 --- a/src/lib/components/panels/NodeLibrary.svelte +++ b/src/lib/components/panels/NodeLibrary.svelte @@ -246,7 +246,7 @@
{#each Array.from(groupedNodes().entries()) as [category, nodes]}
-
{:else if !filterHasResults}
diff --git a/src/lib/components/panels/library-detail/EventDetail.svelte b/src/lib/components/panels/library-detail/EventDetail.svelte index 9cc90ade..f45d4410 100644 --- a/src/lib/components/panels/library-detail/EventDetail.svelte +++ b/src/lib/components/panels/library-detail/EventDetail.svelte @@ -28,7 +28,7 @@
-
+