Skip to content

Commit 604496a

Browse files
chore: refactored the FE state to be redux, preparing for workflows
1 parent 737c3fd commit 604496a

13 files changed

Lines changed: 447 additions & 217 deletions

File tree

string-art-demo/package-lock.json

Lines changed: 112 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

string-art-demo/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
"dependencies": {
1313
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
1414
"@esbuild-plugins/node-modules-polyfill": "^0.2.2",
15+
"@reduxjs/toolkit": "^2.8.2",
1516
"react": "^19.1.1",
16-
"react-dom": "^19.1.1"
17+
"react-dom": "^19.1.1",
18+
"react-redux": "^9.2.0"
1719
},
1820
"devDependencies": {
1921
"@eslint/js": "^9.33.0",

string-art-demo/src/App.tsx

Lines changed: 16 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,18 @@
1-
import { useState, useCallback } from 'react';
2-
import { ImageUploader } from './features/1Upload/components/ImageUploader';
3-
import { StringArtCanvas } from './features/3RenderImage/components/StringArtCanvas';
1+
import { useSelector } from 'react-redux';
42
import './App.css';
5-
import StringArtConfigSection from './features/3RenderImage/components/StringArtConfig/StringArtConfigSection';
6-
import { useStringArt, type ProgressInfo } from './features/shared/hooks/useStringArt';
7-
function App() {
8-
const [imageData, setImageData] = useState<Uint8Array | null>(null);
9-
const [imageUrl, setImageUrl] = useState<string>('');
10-
const [isGenerating, setIsGenerating] = useState(false);
11-
const [currentPath, setCurrentPath] = useState<number[]>([]);
12-
const [nailCoords, setNailCoords] = useState<Array<[number, number]>>([]);
13-
const [progress, setProgress] = useState<ProgressInfo | null>(null);
14-
const { generateStringArt, isLoading, error, settings } = useStringArt();
15-
const handleImageSelected = useCallback((data: Uint8Array, url: string) => {
16-
setImageData(data);
17-
setImageUrl(url);
18-
setCurrentPath([]);
19-
setProgress(null);
20-
setNailCoords([]); // Clear until we generate the string art
21-
}, []);
22-
23-
const handleStartGeneration = async () => {
24-
if (!imageData) return;
25-
26-
setIsGenerating(true);
27-
setCurrentPath([]);
28-
setProgress(null);
29-
30-
try {
31-
const onProgress = (progressInfo: ProgressInfo) => {
32-
setProgress(progressInfo);
33-
34-
// Update the path in real-time
35-
setCurrentPath((prevPath) => [...prevPath, ...progressInfo.current_path]);
36-
};
3+
import {
4+
type StringArtState
5+
} from './features/shared/redux/stringArtSlice';
6+
import UploadScreen from './features/1Upload/UploadScreen';
7+
import RenderImageScreen from './features/3RenderImage/RenderImageScreen';
8+
import CanvasScreen from './features/3RenderImage/CanvasScreen';
379

38-
const onNailCoords = (coords: Array<[number, number]>) => {
39-
setNailCoords(coords);
40-
};
41-
42-
const result = await generateStringArt(imageData, onProgress, onNailCoords);
43-
if (result.path) {
44-
setCurrentPath((prevPath) => [...prevPath, ...(result.path || [])]);
45-
}
46-
if (result.nailCoords.length > 0) {
47-
setNailCoords(result.nailCoords);
48-
}
49-
} catch (err) {
50-
console.error('Generation failed:', err);
51-
alert('String art generation failed. Please try again.');
52-
} finally {
53-
setIsGenerating(false);
54-
}
55-
};
10+
function App() {
11+
const {
12+
imageData,
13+
isLoading,
14+
error,
15+
} = useSelector((state: { stringArt: StringArtState }) => state.stringArt);
5616

5717
if (isLoading) {
5818
return (
@@ -83,56 +43,14 @@ function App() {
8343

8444
<main className="app-main">
8545
<div className="controls-section">
86-
<div className="upload-section">
87-
<ImageUploader
88-
onImageSelected={handleImageSelected}
89-
disabled={isGenerating}
90-
/>
91-
</div>
46+
<UploadScreen/>
9247

9348
{imageData && (
94-
<div className="generation-controls">
95-
<StringArtConfigSection key={"stringArt"} settings={settings} />
96-
97-
<button
98-
onClick={handleStartGeneration}
99-
disabled={isGenerating}
100-
className="generate-button"
101-
>
102-
{isGenerating ? 'Generating...' : 'Generate String Art'}
103-
</button>
104-
105-
{progress && (
106-
<div className="progress-section">
107-
<div className="progress-header">
108-
<span>Progress: {progress.completion_percent.toFixed(1)}%</span>
109-
<span>Lines: {progress.lines_completed}/{progress.total_lines}</span>
110-
</div>
111-
<div className="progress-bar">
112-
<div
113-
className="progress-fill"
114-
style={{ width: `${progress.completion_percent}%` }}
115-
></div>
116-
</div>
117-
<div className="progress-details">
118-
<span>Score: {progress.score.toFixed(1)}</span>
119-
</div>
120-
</div>
121-
)}
122-
</div>
49+
<RenderImageScreen/>
12350
)}
12451
</div>
12552

126-
<div className="canvas-section">
127-
<StringArtCanvas
128-
width={500}
129-
height={500}
130-
nailCoords={nailCoords}
131-
currentPath={currentPath}
132-
isAnimating={isGenerating}
133-
imageUrl={imageUrl}
134-
/>
135-
</div>
53+
<CanvasScreen/>
13654
</main>
13755
</div>
13856
);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { useCallback } from "react";
2+
import { useDispatch, useSelector } from "react-redux";
3+
import type { AppDispatch } from "../shared/redux/store";
4+
import { type StringArtState, resetState, setImageData, setImageUrl } from "../shared/redux/stringArtSlice";
5+
import { ImageUploader } from "./components/ImageUploader";
6+
7+
export default function UploadScreen() {
8+
const dispatch = useDispatch<AppDispatch>();
9+
const {
10+
isGenerating
11+
} = useSelector((state: { stringArt: StringArtState }) => state.stringArt);
12+
13+
const handleImageSelected = useCallback(
14+
(data: Uint8Array, url: string) => {
15+
dispatch(resetState());
16+
dispatch(setImageData(data));
17+
dispatch(setImageUrl(url));
18+
},
19+
[dispatch]
20+
);
21+
22+
return (
23+
<div className="upload-section">
24+
<ImageUploader
25+
onImageSelected={handleImageSelected}
26+
disabled={isGenerating}
27+
/>
28+
</div>
29+
);
30+
};
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { useSelector } from "react-redux";
2+
import { StringArtCanvas } from "./components/StringArtCanvas";
3+
import type { StringArtState } from "../shared/redux/stringArtSlice";
4+
5+
export default function CanvasScreen() {
6+
const { imageUrl, isGenerating, currentPath, nailCoords } = useSelector(
7+
(state: { stringArt: StringArtState }) => state.stringArt
8+
);
9+
return (
10+
<div className="canvas-section">
11+
<StringArtCanvas
12+
width={500}
13+
height={500}
14+
nailCoords={nailCoords}
15+
currentPath={currentPath}
16+
isAnimating={isGenerating}
17+
imageUrl={imageUrl}
18+
/>
19+
</div>
20+
);
21+
}

string-art-demo/src/features/3RenderImage/RenderImage.tsx

Whitespace-only changes.

0 commit comments

Comments
 (0)