Skip to content

Commit 91382da

Browse files
committed
feat(ui): visual improvements across toolbar and panel components
- DropdownMenu: replace static ▼ with animated SVG chevron that rotates when open - Navbar: replace emoji sun/moon with proper SVG icons and add hover background - ExecutionOutput: Stop button only visible when running, with stop icon; header/content separated by divider; empty-result italicised hint - ModelInformation: add section header label; add hover and transition to Syntax Validation button - FeatureTree: add "Configuration Panel" section header - ModelProperties: reduce oversized h2 (text-2xl → text-lg) - EditorPage toolbar: add transition-colors and hover states to all tab buttons (View, Solver, Compute); fix missing dark:border-gray-600 on Export group; replace ⚙ text with gear SVG icon; replace rotated-text hide/show panel buttons with compact chevron arrow buttons https://claude.ai/code/session_01Kp6RLceBS9Eb8x8CPiQ7dx
1 parent 5a3b148 commit 91382da

7 files changed

Lines changed: 83 additions & 40 deletions

File tree

src/components/DropdownMenu.jsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,15 @@ const DropdownMenu = ({
8787
aria-expanded={isOpen}
8888
>
8989
{buttonLabel}
90-
<span className="ml-2">&#9660;</span>
90+
<svg
91+
className={`ml-2 w-3 h-3 shrink-0 transition-transform duration-200 ${isOpen ? "rotate-180" : ""}`}
92+
fill="none"
93+
stroke="currentColor"
94+
viewBox="0 0 24 24"
95+
aria-hidden="true"
96+
>
97+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M19 9l-7 7-7-7" />
98+
</svg>
9199
</button>
92100

93101
{isOpen && (

src/components/ExecutionOutput.jsx

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,28 @@ const ExecutionOutput = ({
2828
resizeHandles={["n"]}
2929
onResize={handleResize}
3030
>
31-
<div className="overflow-auto h-full">
32-
<button
33-
onClick={handleStop}
34-
className="absolute top-0 right-0 m-2 p-2 bg-red-600 text-white rounded"
35-
>
36-
Stop
37-
</button>
38-
<div className="flex items-center font-semibold text-xl">
39-
{isAwaiting ? (
40-
<>
41-
<Spinner /> {children.label}
42-
</>
43-
) : (
44-
children.label
31+
<div className="flex flex-col h-full overflow-hidden">
32+
<div className="flex items-center justify-between shrink-0 pb-2 border-b border-gray-500 dark:border-gray-600">
33+
<div className="flex items-center gap-2 font-semibold text-base leading-tight">
34+
{isAwaiting && <Spinner />}
35+
<span>{children.label}</span>
36+
</div>
37+
{isAwaiting && (
38+
<button
39+
onClick={handleStop}
40+
className="flex items-center gap-1 px-3 py-1 text-sm bg-red-600 hover:bg-red-700 active:bg-red-800 text-white rounded transition-colors duration-150"
41+
>
42+
<svg className="w-3 h-3" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
43+
<rect x="4" y="4" width="16" height="16" rx="2" />
44+
</svg>
45+
Stop
46+
</button>
4547
)}
4648
</div>
47-
<div className="font-mono text-sm">
49+
<div className="font-mono text-sm mt-2 overflow-auto flex-1">
4850
{children.result == null ||
4951
(Array.isArray(children.result) && children.result.length === 0) ? (
50-
<div>There are no {children.label}.</div>
52+
<div className="text-gray-400 italic">There are no {children.label}.</div>
5153
) : Array.isArray(children.result) ? (
5254
children.result.map((item, index) => (
5355
<div key={index}>{item.toString()}</div>

src/components/FeatureTree.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ const TreeView = ({ treeData, executeAction, operations, history }) => {
126126
}
127127
>
128128
<div className="space-y-4 h-full">
129+
<h2 className="text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-widest">
130+
Configuration Panel
131+
</h2>
129132
<DropdownMenu
130133
buttonLabel={"Configuration Operations"}
131134
options={operations}

src/components/ModelInformation.jsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@ const ModelInformation = ({
2424
resizeHandles={["w"]}
2525
>
2626
<div>
27+
<h2 className="text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-widest mb-3">
28+
Model Information
29+
</h2>
2730
<button
28-
className="w-full bg-[#356C99] text-white py-2 px-4 rounded active:bg-[#0D486C] shadow-lg"
31+
className="w-full bg-[#356C99] hover:bg-[#0D486C] active:bg-[#0a3a57] text-white py-2 px-4 rounded shadow-lg transition-colors duration-150"
2932
onClick={onValidateModel}
3033
>
3134
{buttonText}

src/components/ModelProperties.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const ModelProperties = ({ modelProperties }) => {
88
The model is syntactically valid
99
</div>
1010

11-
<h2 className="text-[#0D486C] dark:text-blue-300 font-bold text-2xl mb-4">
11+
<h2 className="text-[#0D486C] dark:text-blue-300 font-bold text-lg mb-3">
1212
Model Information
1313
</h2>
1414

src/components/Navbar.jsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,17 @@ function Navbar({ children, controls, darkMode, toggleDark }) {
2929
<button
3030
onClick={toggleDark}
3131
aria-label="Toggle dark mode"
32-
className="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white transition-colors text-lg"
32+
className="p-1.5 rounded-md text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
3333
>
34-
{darkMode ? "☀️" : "🌙"}
34+
{darkMode ? (
35+
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
36+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364-6.364l-.707.707M6.343 17.657l-.707.707M17.657 17.657l-.707-.707M6.343 6.343l-.707-.707M12 7a5 5 0 110 10A5 5 0 0112 7z" />
37+
</svg>
38+
) : (
39+
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
40+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
41+
</svg>
42+
)}
3543
</button>
3644
</div>
3745
</nav>

src/pages/editor/EditorPage.jsx

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -747,8 +747,10 @@ function EditorPage({ selectedFile, setNavControls, darkMode }) {
747747
{viewOptions.map((option) => (
748748
<button
749749
key={option.value}
750-
className={`px-2.5 py-2 text-sm ${
751-
currentView === option.value ? "bg-[#356C99] text-white" : "bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200"
750+
className={`px-2.5 py-2 text-sm transition-colors duration-150 ${
751+
currentView === option.value
752+
? "bg-[#356C99] text-white"
753+
: "bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600"
752754
}`}
753755
onClick={() => toggleView(option)}
754756
>
@@ -760,7 +762,7 @@ function EditorPage({ selectedFile, setNavControls, darkMode }) {
760762
buttonLabel="Metrics"
761763
options={metricsOptions}
762764
executeAction={toggleView}
763-
className="bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200 py-2 px-3 rounded-none shadow-none w-[100px] justify-between border-l border-gray-300 dark:border-gray-600"
765+
className="bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200 py-2 px-3 rounded-none shadow-none w-[100px] justify-between border-l border-gray-300 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors duration-150"
764766
/>
765767
)}
766768
</div>
@@ -774,7 +776,7 @@ function EditorPage({ selectedFile, setNavControls, darkMode }) {
774776
buttonLabel="Structural operation"
775777
options={STRUCTURAL_OPERATIONS}
776778
executeAction={executeAction}
777-
className="bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200 py-2 px-3 rounded-none shadow-none w-[170px] justify-between"
779+
className="bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200 py-2 px-3 rounded-none shadow-none w-[170px] justify-between hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors duration-150"
778780
/>
779781
</div>
780782
</div>
@@ -786,8 +788,10 @@ function EditorPage({ selectedFile, setNavControls, darkMode }) {
786788
{solverOptions.map((option) => (
787789
<button
788790
key={option.value}
789-
className={`px-2.5 py-2 text-sm min-w-[60px] ${
790-
selectedSolver === option.value ? "bg-[#356C99] text-white" : "bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200"
791+
className={`px-2.5 py-2 text-sm min-w-[60px] transition-colors duration-150 ${
792+
selectedSolver === option.value
793+
? "bg-[#356C99] text-white"
794+
: "bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600"
791795
}`}
792796
onClick={() => setSelectedSolver(option.value)}
793797
>
@@ -798,7 +802,7 @@ function EditorPage({ selectedFile, setNavControls, darkMode }) {
798802
buttonLabel="Analysis operation"
799803
options={operationsForSolver(selectedSolver)}
800804
executeAction={executeAction}
801-
className="bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200 py-2 px-3 rounded-none shadow-none w-[170px] justify-between border-l"
805+
className="bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200 py-2 px-3 rounded-none shadow-none w-[170px] justify-between border-l border-gray-300 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors duration-150"
802806
/>
803807
</div>
804808
</div>
@@ -808,17 +812,21 @@ function EditorPage({ selectedFile, setNavControls, darkMode }) {
808812
<div className="h-px bg-gray-300 dark:bg-gray-600 w-full" />
809813
<div className="flex items-stretch rounded overflow-hidden border border-gray-300 dark:border-gray-600">
810814
<button
811-
className={`px-2.5 py-2 text-sm ${
812-
computeBackend === WASM ? "bg-[#356C99] text-white" : "bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200"
815+
className={`px-2.5 py-2 text-sm transition-colors duration-150 ${
816+
computeBackend === WASM
817+
? "bg-[#356C99] text-white"
818+
: "bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600"
813819
}`}
814820
onClick={() => selectBackend(WASM)}
815821
title="Run analysis operations in your browser (WebAssembly)"
816822
>
817823
In-browser
818824
</button>
819825
<button
820-
className={`px-2.5 py-2 text-sm border-l border-gray-300 dark:border-gray-600 ${
821-
computeBackend === REST ? "bg-[#356C99] text-white" : "bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200"
826+
className={`px-2.5 py-2 text-sm border-l border-gray-300 dark:border-gray-600 transition-colors duration-150 ${
827+
computeBackend === REST
828+
? "bg-[#356C99] text-white"
829+
: "bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600"
822830
}`}
823831
onClick={() => selectBackend(REST)}
824832
title="Run analysis operations on a remote flamapy-rest API"
@@ -827,11 +835,14 @@ function EditorPage({ selectedFile, setNavControls, darkMode }) {
827835
</button>
828836
{computeBackend === REST && (
829837
<button
830-
className="px-2.5 py-2 text-sm border-l border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200"
838+
className="px-2.5 py-2 text-sm border-l border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors duration-150"
831839
onClick={() => setIsBackendModalOpen(true)}
832840
title={`Configure the API URL (current: ${restApiUrl})`}
833841
>
834-
842+
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
843+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
844+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
845+
</svg>
835846
</button>
836847
)}
837848
</div>
@@ -840,12 +851,12 @@ function EditorPage({ selectedFile, setNavControls, darkMode }) {
840851
<div className="flex flex-col gap-1 whitespace-nowrap">
841852
<span className="text-[11px] text-gray-600 dark:text-gray-300 text-center w-full">Export</span>
842853
<div className="h-px bg-gray-300 dark:bg-gray-600 w-full" />
843-
<div className="flex rounded overflow-hidden border border-gray-300">
854+
<div className="flex rounded overflow-hidden border border-gray-300 dark:border-gray-600">
844855
<DropdownMenu
845856
buttonLabel="Export"
846857
options={EXPORT_OPERATIONS}
847858
executeAction={downloadFile}
848-
className="bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200 py-2 px-3 rounded-none shadow-none w-[120px] justify-between"
859+
className="bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200 py-2 px-3 rounded-none shadow-none w-[120px] justify-between hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors duration-150"
849860
/>
850861
</div>
851862
</div>
@@ -938,20 +949,28 @@ function EditorPage({ selectedFile, setNavControls, darkMode }) {
938949
<TreeView treeData={featureTree} executeAction={executeActionWithConf} operations={CONFIG_OPERATIONS} history={history} />
939950
{currentView !== "configurator" && (
940951
<button
941-
className="absolute right-[-12px] top-1/2 -translate-y-1/2 bg-gray-300 dark:bg-gray-600 text-gray-700 dark:text-gray-200 text-[10px] px-1 py-10 rounded-r shadow hover:bg-gray-400 dark:hover:bg-gray-500 rotate-180 [writing-mode:vertical-rl]"
952+
aria-label="Hide configuration panel"
953+
title="Hide configuration panel"
954+
className="absolute right-[-14px] top-1/2 -translate-y-1/2 z-20 flex items-center justify-center w-7 h-10 bg-gray-200 dark:bg-gray-600 text-gray-600 dark:text-gray-300 rounded-r shadow hover:bg-gray-300 dark:hover:bg-gray-500 transition-colors duration-150"
942955
onClick={() => setShowConfiguratorPanel(false)}
943956
>
944-
Hide configuration panel
957+
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
958+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
959+
</svg>
945960
</button>
946961
)}
947962
</div>
948963
)}
949964
{!showConfiguratorPanel && currentView !== "configurator" && (
950965
<button
951-
className="absolute left-0 top-1/2 -translate-y-1/2 bg-gray-300 dark:bg-gray-600 text-gray-700 dark:text-gray-200 text-[10px] px-1 py-10 rounded-r shadow hover:bg-gray-400 dark:hover:bg-gray-500 z-40 rotate-180 [writing-mode:vertical-rl]"
966+
aria-label="Show configuration panel"
967+
title="Show configuration panel"
968+
className="absolute left-0 top-1/2 -translate-y-1/2 z-40 flex items-center justify-center w-7 h-10 bg-gray-200 dark:bg-gray-600 text-gray-600 dark:text-gray-300 rounded-r shadow hover:bg-gray-300 dark:hover:bg-gray-500 transition-colors duration-150"
952969
onClick={() => setShowConfiguratorPanel(true)}
953970
>
954-
Show configuration panel
971+
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
972+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
973+
</svg>
955974
</button>
956975
)}
957976

0 commit comments

Comments
 (0)