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
257 changes: 115 additions & 142 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// * Imports *
import { useState, useCallback, useEffect, useRef, version } from 'react';

Check failure on line 2 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.10)

'version' is defined but never used. Allowed unused vars must match /^[A-Z_]/u

Check failure on line 2 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.11)

'version' is defined but never used. Allowed unused vars must match /^[A-Z_]/u
import {
ReactFlowProvider,
useReactFlow,
Expand Down Expand Up @@ -90,7 +90,7 @@
}, []);

const onDragStart = (event, nodeType) => {
setType(nodeType);

Check failure on line 93 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.10)

'setType' is not defined

Check failure on line 93 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.11)

'setType' is not defined
event.dataTransfer.setData('text/plain', nodeType);
event.dataTransfer.effectAllowed = 'move';
};
Expand All @@ -107,7 +107,7 @@
const [pythonCode, setPythonCode] = useState("# Define your Python variables and functions here\n# Example:\n# my_variable = 42\n# def my_function(x):\n# return x * 2\n");

// State for URL sharing feedback
const [shareUrlFeedback, setShareUrlFeedback] = useState('');

Check failure on line 110 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.10)

'shareUrlFeedback' is assigned a value but never used. Allowed unused vars must match /^[A-Z_]/u

Check failure on line 110 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.11)

'shareUrlFeedback' is assigned a value but never used. Allowed unused vars must match /^[A-Z_]/u
const [showShareModal, setShowShareModal] = useState(false);
const [shareableURL, setShareableURL] = useState('');
const [urlMetadata, setUrlMetadata] = useState(null);
Expand Down Expand Up @@ -161,7 +161,7 @@
};

loadGraphFromURL();
}, []); // Empty dependency array means this runs once on mount

Check warning on line 164 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.10)

React Hook useEffect has missing dependencies: 'setEdges' and 'setNodes'. Either include them or remove the dependency array

Check warning on line 164 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.11)

React Hook useEffect has missing dependencies: 'setEdges' and 'setNodes'. Either include them or remove the dependency array

const [defaultValues, setDefaultValues] = useState({});
const [isEditingLabel, setIsEditingLabel] = useState(false);
Expand Down Expand Up @@ -366,7 +366,7 @@
setNodes((nds) => [...nds, newNode]);
setNodeCounter((count) => count + 1);
},
[screenToFlowPosition, type, nodeCounter, fetchDefaultValues, setDefaultValues, setNodes, setNodeCounter],

Check warning on line 369 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.10)

React Hook useCallback has an unnecessary dependency: 'setDefaultValues'. Either exclude it or remove the dependency array

Check warning on line 369 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.11)

React Hook useCallback has an unnecessary dependency: 'setDefaultValues'. Either exclude it or remove the dependency array
);

// Function to save a graph to computer with "Save As" dialog
Expand Down Expand Up @@ -1052,7 +1052,7 @@
return () => {
document.removeEventListener('keydown', handleKeyDown);
};
}, [selectedEdge, selectedNode, copiedNode, duplicateNode, setCopyFeedback]);

Check warning on line 1055 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.10)

React Hook useEffect has missing dependencies: 'deleteSelectedEdge' and 'deleteSelectedNode'. Either include them or remove the dependency array

Check warning on line 1055 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.11)

React Hook useEffect has missing dependencies: 'deleteSelectedEdge' and 'deleteSelectedNode'. Either include them or remove the dependency array

return (
<div style={{ width: '100vw', height: '100vh', display: 'flex', flexDirection: 'column' }}>
Expand All @@ -1063,164 +1063,137 @@
{/* Graph Editor Tab */}
{activeTab === 'graph' && (
<div style={{ display: 'flex', flex: 1, height: 'calc(100vh - 50px)', overflow: 'hidden' }}>
{/* Sidebar Toggle Button */}
<button
onClick={() => setSidebarVisible(!sidebarVisible)}
{/* Sidebar */}
<div
data-sidebar-state={sidebarVisible ? 'expanded' : 'collapsed'}
className="sidebar-container"
style={{
position: 'absolute',
top: '60px',
left: sidebarVisible ? '240px' : '10px',
zIndex: 1000,
backgroundColor: '#2c2c54',
color: '#ffffff',
border: '1px solid #555',
borderRadius: '4px',
width: '32px',
height: '32px',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
transition: 'left 0.3s ease',
boxShadow: '0 2px 4px rgba(0,0,0,0.3)',
padding: '4px'
}}
onMouseEnter={(e) => {
e.target.style.backgroundColor = '#3c3c64';
e.target.style.borderColor = '#78A083';
}}
onMouseLeave={(e) => {
e.target.style.backgroundColor = '#2c2c54';
e.target.style.borderColor = '#555';
position: 'relative',
width: sidebarVisible ? '250px' : '0px',
height: '100%',
transition: 'width 0.5s ease',
overflow: 'hidden'
}}
title={sidebarVisible ? 'Hide Sidebar' : 'Show Sidebar'}
>
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
<div
style={{
position: 'fixed',
left: sidebarVisible ? '0px' : '-250px',
top: '50px', // Account for top bar height
width: '250px',
height: 'calc(100vh - 50px)',
transition: 'left 0.5s ease',
zIndex: 10,
borderRight: '1px solid #ccc',
backgroundColor: '#1e1e2f'
}}
>
{sidebarVisible ? (
// Hide sidebar icon (sidebar with left arrow)
<>
<rect x="2" y="3" width="6" height="18" rx="1" fill="currentColor" opacity="0.3" />
<rect x="10" y="3" width="12" height="18" rx="1" stroke="currentColor" strokeWidth="1.5" fill="none" />
<path d="M6 12L4 10M6 12L4 14M6 12H1" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</>
) : (
// Show sidebar icon (sidebar with right arrow)
<>
<rect x="2" y="3" width="6" height="18" rx="1" stroke="currentColor" strokeWidth="1.5" fill="none" />
<rect x="10" y="3" width="12" height="18" rx="1" stroke="currentColor" strokeWidth="1.5" fill="none" />
<path d="M5 12L7 10M5 12L7 14M5 12H10" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</>
)}
</svg>
</button>

{/* Sidebar */}
{sidebarVisible && (
<div style={{
width: 250,
height: '100%',
borderRight: '1px solid #ccc',
transition: 'width 0.3s ease'
}}>
<Sidebar />
</div>
)}

<GraphView
refEl={ref}
reactFlowWrapperRef={reactFlowWrapper}
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
onNodeClick={onNodeClick}
onEdgeClick={onEdgeClick}
onPaneClick={onPaneClick}
onNodeContextMenu={onNodeContextMenu}
nodeTypes={nodeTypes}
onDrop={onDrop}
onDragStart={onDragStart}
onDragOver={onDragOver}
menu={menu}
duplicateNode={duplicateNode}
copyFeedback={copyFeedback}
ui={{
selectedNode, selectedEdge,
deleteSelectedNode, deleteSelectedEdge,
saveGraph, loadGraph, resetGraph, saveToPython, runPathsim,
shareGraphURL,
dockOpen, setDockOpen, onToggleLogs,
showKeyboardShortcuts, setShowKeyboardShortcuts,
}}
/>
{/* Log Dock */}
<LogDock
open={dockOpen}
onClose={() => setDockOpen(false)}
lines={logLines}
progress={null}
/>
{/* Node Sidebar */}
<NodeSidebar
selectedNode={selectedNode}
defaultValues={defaultValues}
setNodes={setNodes}
setSelectedNode={setSelectedNode}
isEditingLabel={isEditingLabel}
setIsEditingLabel={setIsEditingLabel}
tempLabel={tempLabel}
setTempLabel={setTempLabel}
nodeDocumentation={nodeDocumentation}
isDocumentationExpanded={isDocumentationExpanded}
setIsDocumentationExpanded={setIsDocumentationExpanded}
/>
{/* Edge Details */}
<EdgeDetails
selectedEdge={selectedEdge}
onClose={() => setSelectedEdge(null)}
onDelete={deleteSelectedEdge}
/>
</div>

{/* Main content area that moves with sidebar */}
<div style={{ position: 'relative', flex: 1, height: '100%' }}>
<GraphView
refEl={ref}
reactFlowWrapperRef={reactFlowWrapper}
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
onNodeClick={onNodeClick}
onEdgeClick={onEdgeClick}
onPaneClick={onPaneClick}
onNodeContextMenu={onNodeContextMenu}
nodeTypes={nodeTypes}
onDrop={onDrop}
onDragStart={onDragStart}
onDragOver={onDragOver}
menu={menu}
duplicateNode={duplicateNode}
copyFeedback={copyFeedback}
ui={{
selectedNode, selectedEdge,
deleteSelectedNode, deleteSelectedEdge,
saveGraph, loadGraph, resetGraph, saveToPython, runPathsim,
shareGraphURL,
dockOpen, setDockOpen, onToggleLogs,
showKeyboardShortcuts, setShowKeyboardShortcuts,
sidebarVisible, setSidebarVisible,
}}
/>

{/* Log Dock */}
<LogDock
open={dockOpen}
onClose={() => setDockOpen(false)}
lines={logLines}
progress={null}
/>

{/* Node Sidebar */}
<NodeSidebar
selectedNode={selectedNode}
defaultValues={defaultValues}
setNodes={setNodes}
setSelectedNode={setSelectedNode}
isEditingLabel={isEditingLabel}
setIsEditingLabel={setIsEditingLabel}
tempLabel={tempLabel}
setTempLabel={setTempLabel}
nodeDocumentation={nodeDocumentation}
isDocumentationExpanded={isDocumentationExpanded}
setIsDocumentationExpanded={setIsDocumentationExpanded}
/>

{/* Edge Details */}
<EdgeDetails
selectedEdge={selectedEdge}
onClose={() => setSelectedEdge(null)}
onDelete={deleteSelectedEdge}
/>
</div>
</div>
)}

{/* Events tab */}
{activeTab === 'events' && <EventsTab events={events} setEvents={setEvents} />}

{/* Solver Parameters Tab */}
{activeTab === 'solver' && (
<SolverPanel
solverParams={solverParams}
setSolverParams={setSolverParams}
setActiveTab={setActiveTab}
/>
)}
{
activeTab === 'solver' && (
<SolverPanel
solverParams={solverParams}
setSolverParams={setSolverParams}
setActiveTab={setActiveTab}
/>
)
}

{/* Global Variables Tab */}
{activeTab === 'globals' && (
<GlobalVariablesTab
globalVariables={globalVariables}
setGlobalVariables={setGlobalVariables}
setActiveTab={setActiveTab}
pythonCode={pythonCode}
setPythonCode={setPythonCode}
/>
)}
{
activeTab === 'globals' && (
<GlobalVariablesTab
globalVariables={globalVariables}
setGlobalVariables={setGlobalVariables}
setActiveTab={setActiveTab}
pythonCode={pythonCode}
setPythonCode={setPythonCode}
/>
)
}

{/* Results Tab */}
{activeTab === 'results' && (
<ResultsPanel
simulationResults={simulationResults}
downloadHtml={downloadHtml}
downloadCsv={downloadCsv}
/>
)}
{
activeTab === 'results' && (
<ResultsPanel
simulationResults={simulationResults}
downloadHtml={downloadHtml}
downloadCsv={downloadCsv}
/>
)
}

{/* Share URL Modal */}
<ShareModal
Expand All @@ -1230,7 +1203,7 @@
urlMetadata={urlMetadata}
/>

</div>
</div >
);
}

Expand Down
48 changes: 47 additions & 1 deletion src/components/GraphView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ function FloatingButtons({
deleteSelectedNode, deleteSelectedEdge,
saveGraph, loadGraph, resetGraph, saveToPython, runPathsim,
shareGraphURL,
dockOpen, onToggleLogs
dockOpen, onToggleLogs,
sidebarVisible, setSidebarVisible
}) {
return (
<>
Expand Down Expand Up @@ -142,6 +143,51 @@ function FloatingButtons({
>
New graph
</button>

{/* Sidebar Toggle Button - strudel-flow style */}
<button
onClick={() => setSidebarVisible(!sidebarVisible)}
className="sidebar-trigger"
style={{
position: 'absolute',
left: 15,
top: 20,
zIndex: 1000,
width: '20px',
height: '20px',
backgroundColor: 'transparent',
color: '#ffffff',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
// transition: 'all 0.2s ease',
padding: '0'
}}
title="Toggle Sidebar"
>
{/* PanelLeft icon - similar to lucide-react */}
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
style={{
color: '#ffffff',
transition: 'color 0.2s ease'
}}
>
<rect x="3" y="3" width="18" height="18" rx="2" ry="2" />
<line x1="9" y1="3" x2="9" y2="21" />
</svg>
</button>

<button
style={{
position: 'absolute',
Expand Down
2 changes: 1 addition & 1 deletion src/components/ShareModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
try {
await navigator.clipboard.writeText(shareableURL);
setCopyFeedback('Copied!');
} catch (error) {

Check failure on line 10 in src/components/ShareModal.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.10)

'error' is defined but never used

Check failure on line 10 in src/components/ShareModal.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.11)

'error' is defined but never used
// Fallback for older browsers
try {
const textArea = document.createElement('textarea');
Expand All @@ -17,7 +17,7 @@
document.execCommand('copy');
document.body.removeChild(textArea);
setCopyFeedback('Copied!');
} catch (fallbackError) {

Check failure on line 20 in src/components/ShareModal.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.10)

'fallbackError' is defined but never used

Check failure on line 20 in src/components/ShareModal.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.11)

'fallbackError' is defined but never used
setCopyFeedback('Failed to copy');
}
}
Expand Down Expand Up @@ -94,7 +94,7 @@
<p style={{ margin: 0, color: '#666', fontSize: 14 }}>
Copy this URL to share your workflow with others.
</p>

{/* URL Length Warning */}
{isLongURL && (
<div style={{
Expand Down
Loading
Loading