Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 8 additions & 14 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"@codemirror/theme-one-dark": "^6.0.0",
"@xyflow/svelte": "^1.5.0",
"codemirror": "^6.0.0",
"driver.js": "^1.4.0",
"jspdf": "^4.1.0",
"katex": "^0.16.0",
"opentype.js": "^1.3.4",
Expand Down
1 change: 1 addition & 0 deletions src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -717,3 +717,4 @@ body.assembly-pending .svelte-flow__edge {
transform: scale(1);
}
}

17 changes: 17 additions & 0 deletions src/lib/components/FlowCanvas.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import '@xyflow/svelte/dist/style.css';

import { isInputFocused } from '$lib/utils/focus';
import { isTourActive } from '$lib/tours/inputMode';
import BaseNode from './nodes/BaseNode.svelte';
import EventNode from './nodes/EventNode.svelte';
import AnnotationNode from './nodes/AnnotationNode.svelte';
Expand All @@ -31,6 +32,7 @@
import { dropTargetBridge } from '$lib/stores/dropTargetBridge';
import { contextMenuStore } from '$lib/stores/contextMenu';
import { nodeUpdatesStore } from '$lib/stores/nodeUpdates';
import { assemblyAnimationTrigger } from '$lib/animation/assemblyAnimation';
import { nodeRegistry } from '$lib/nodes';
import { NODE_TYPES } from '$lib/constants/nodeTypes';
import { GRID_SIZE, SNAP_GRID, BACKGROUND_GAP } from '$lib/constants/grid';
Expand Down Expand Up @@ -74,6 +76,8 @@

// Keyboard shortcuts for node manipulation
function handleKeydown(event: KeyboardEvent) {
// While a guided tour runs, driver.js owns the keyboard.
if (isTourActive()) return;
if (isInputFocused(event)) return;

// Handle Delete key (SvelteFlow's deleteKeyCode doesn't work reliably for 'Delete')
Expand Down Expand Up @@ -444,6 +448,19 @@
}
});

// On model load, the initial routing pass runs with fallback 80×40
// dimensions because nodes haven't been measured yet, and the per-node
// $effect above silently records first measurements without rerouting.
// Trigger a full reroute once measurements have settled.
let lastAssemblyTrigger = 0;
const unsubAssembly = assemblyAnimationTrigger.subscribe((v) => {
if (v > lastAssemblyTrigger) {
lastAssemblyTrigger = v;
setTimeout(() => updateRoutingContext(), 400);
}
});
onDestroy(() => unsubAssembly());

// Track if we're currently syncing to prevent loops
let isSyncing = false;

Expand Down
2 changes: 2 additions & 0 deletions src/lib/components/ResizablePanel.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@
<aside
class="resizable-panel glass-panel {position}"
class:resizing={isResizing}
data-panel={title ?? ''}
data-tour={title ? `panel-${title.toLowerCase()}` : ''}
style="
{position === 'left' || position === 'right' ? `width: ${getWidth()}px;` : ''}
{(position === 'bottom-left' || position === 'bottom-right') && controlledWidth !== undefined ? `width: ${getWidth()}px;` : ''}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/SubsystemBreadcrumb.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
</script>

{#if !isAtRoot}
<nav class="breadcrumb glass-panel" transition:fly={{ y: -10, duration: 150 }}>
<nav class="breadcrumb glass-panel" data-tour="breadcrumb" transition:fly={{ y: -10, duration: 150 }}>
{#each breadcrumbs as crumb, i}
<button
class="crumb-pill"
Expand Down
73 changes: 68 additions & 5 deletions src/lib/components/WelcomeModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { cubicOut } from 'svelte/easing';
import Icon from '$lib/components/icons/Icon.svelte';
import { PATHVIEW_VERSION, EXTRACTED_VERSIONS } from '$lib/constants/dependencies';
import { startGuidedTour, type TourId } from '$lib/tours';

interface Example {
name: string;
Expand Down Expand Up @@ -51,6 +52,12 @@
onClose();
}

function handleStartTour(id: TourId) {
onClose();
// Wait for the banner's slide-out so highlights aren't covered
setTimeout(() => startGuidedTour(id), 350);
}

function handleKeydown(e: KeyboardEvent) {
if (e.key === 'Escape') {
onClose();
Expand Down Expand Up @@ -132,6 +139,29 @@

<div class="separator"></div>

<div class="tour-section">
<div class="tour-text">
<strong>Guided Tours</strong>
<span>Step-by-step walkthroughs that highlight the editor's main areas in turn so you know what each does.</span>
</div>
<div class="tour-buttons">
<button class="action-card" onclick={() => handleStartTour('start')}>
<Icon name="compass" size={20} />
<span class="action-label">Start</span>
</button>
<button class="action-card" onclick={() => handleStartTour('modeling')}>
<Icon name="shapes" size={20} />
<span class="action-label">Modeling</span>
</button>
<button class="action-card" onclick={() => handleStartTour('simulation')}>
<Icon name="play-circle" size={20} />
<span class="action-label">Simulation</span>
</button>
</div>
</div>

<div class="separator"></div>

<div class="examples-section">
<div class="examples-grid">
{#each examples as example}
Expand Down Expand Up @@ -228,6 +258,43 @@
letter-spacing: 0.2px;
}

.tour-section {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 8px;
align-items: center;
}

.tour-text {
grid-column: 1 / 4;
}

.tour-buttons {
grid-column: 4 / -1;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
}

.tour-text {
display: flex;
flex-direction: column;
gap: 2px;
line-height: 1.35;
color: var(--text-muted);
}

.tour-text strong {
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
}

.tour-text span {
font-size: 11px;
}

.actions {
display: grid;
grid-template-columns: repeat(6, 1fr);
Expand Down Expand Up @@ -278,7 +345,7 @@

.examples-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-columns: repeat(2, 1fr);
grid-auto-rows: min-content;
align-items: start;
gap: 10px;
Expand Down Expand Up @@ -383,10 +450,6 @@
.banner-content {
padding-right: 90px;
}

.examples-grid {
grid-template-columns: repeat(2, 1fr);
}
}

@media (max-width: 500px) {
Expand Down
4 changes: 3 additions & 1 deletion src/lib/components/dialogs/BlockPropertiesDialog.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@

{#if nodeId && node && typeDef}
<div class="dialog-backdrop" onclick={handleBackdropClick} transition:fade={{ duration: 150 }} role="presentation">
<div class="properties-dialog glass-panel" style="--node-color: {currentColor}" transition:scale={{ start: 0.95, duration: 150, easing: cubicOut }} role="dialog" tabindex="-1" aria-labelledby="dialog-title">
<div class="properties-dialog glass-panel" data-tour="dialog-properties" style="--node-color: {currentColor}" transition:scale={{ start: 0.95, duration: 150, easing: cubicOut }} role="dialog" tabindex="-1" aria-labelledby="dialog-title">
<div class="dialog-header">
{#if showCode}
<span id="dialog-title">Python Code</span>
Expand All @@ -258,6 +258,7 @@
<input
id="dialog-title"
class="node-name-input"
data-tour="block-name-input"
type="text"
value={node.name}
oninput={(e) => handleNameChange(e.currentTarget.value)}
Expand Down Expand Up @@ -377,6 +378,7 @@
<button
class="pin-btn"
class:pinned
data-tour="block-pin-btn"
onclick={() => togglePinParam(param.name)}
use:tooltip={pinned ? "Unpin from node" : "Pin to node"}
aria-label={pinned ? "Unpin from node" : "Pin to node"}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/dialogs/ExportDialog.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@

{#if open}
<div class="dialog-backdrop" transition:fade={{ duration: 150 }} onclick={handleBackdropClick} role="presentation">
<div class="dialog glass-panel" transition:scale={{ start: 0.95, duration: 150, easing: cubicOut }} role="dialog" tabindex="-1" aria-labelledby="dialog-title">
<div class="dialog glass-panel" data-tour="dialog-python-export" transition:scale={{ start: 0.95, duration: 150, easing: cubicOut }} role="dialog" tabindex="-1" aria-labelledby="dialog-title">
<div class="dialog-header">
<span id="dialog-title">Export Python Code</span>
<div class="header-actions">
Expand Down
1 change: 1 addition & 0 deletions src/lib/components/dialogs/KeyboardShortcutsDialog.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
<!-- svelte-ignore a11y_no_static_element_interactions, a11y_click_events_have_key_events -->
<div
class="dialog glass-panel"
data-tour="dialog-shortcuts"
transition:scale={{ start: 0.95, duration: 150, easing: cubicOut }}
onclick={(e) => e.stopPropagation()}
role="dialog"
Expand Down
1 change: 1 addition & 0 deletions src/lib/components/dialogs/SearchDialog.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@
<!-- svelte-ignore a11y_no_static_element_interactions, a11y_click_events_have_key_events -->
<div
class="search-dialog glass-panel"
data-tour="dialog-search"
transition:scale={{ start: 0.95, duration: 150, easing: cubicOut }}
onclick={(e) => e.stopPropagation()}
role="dialog"
Expand Down
1 change: 1 addition & 0 deletions src/lib/components/dialogs/ToolboxManagerDialog.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@
<div class="dialog-backdrop" transition:fade={{ duration: 150 }} onclick={handleBackdrop} role="presentation">
<div
class="dialog glass-panel manager-modal"
data-tour="dialog-toolbox-manager"
transition:scale={{ start: 0.95, duration: 150, easing: cubicOut }}
role="dialog"
aria-modal="true"
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/dialogs/shared/ColorPicker.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@

<svelte:window onclick={handleClickOutside} />

<div class="color-picker-wrapper">
<div class="color-picker-wrapper" data-tour="block-color-picker">
<button class="picker-btn" class:ghost={variant === 'ghost'} onclick={toggle} aria-label="Change color" use:tooltip={{ text: 'Color', position: tooltipPosition }}>
<svg width={iconSize} height={iconSize} viewBox="0 0 24 24" fill="none" stroke={iconColor || 'currentColor'} stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"/>
Expand Down
Loading
Loading