Skip to content

Commit 1be4119

Browse files
Merge pull request #1 from AhmadAlBarasy/feat/add-simulation-steps-control
Added simulation steps controller + Fixed canvas animation bugs
2 parents 0e28027 + 8684a91 commit 1be4119

10 files changed

Lines changed: 407 additions & 209 deletions

File tree

src/App.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@ import { CanvasProvider } from "./context/CanvasProvider";
44
import { VisualizationProvider } from "./context/VisualizationProvider";
55

66
function App() {
7-
return <div className="flex w-full h-screen">
8-
<VisualizationProvider>
7+
return (
8+
<div className="flex w-full h-screen">
99
<CanvasProvider>
10-
<SidePanel />
11-
<Canvas />
10+
<VisualizationProvider>
11+
<SidePanel />
12+
<Canvas />
13+
</VisualizationProvider>
1214
</CanvasProvider>
13-
</VisualizationProvider>
14-
</div>
15+
</div>
16+
);
1517
}
1618

1719
export default App;

src/classes/Node.tsx

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/classes/SimulationStepNode.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
export type action = 'create' | 'delete';
3+
4+
export type Position = {
5+
x: number;
6+
y: number;
7+
};
8+
9+
export type SimulationStep = {
10+
text: string;
11+
nodeId: string;
12+
action: action;
13+
position: Position;
14+
parentId?: string;
15+
};
16+
17+
class SimulationStepNode {
18+
data: SimulationStep;
19+
next: SimulationStepNode | null = null;
20+
prev: SimulationStepNode | null = null;
21+
22+
constructor(data: SimulationStep) {
23+
this.data = data;
24+
}
25+
}
26+
27+
export default SimulationStepNode;

src/components/AlgorithmForm.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,21 @@
22
import FactorialFormFields from "./formFields/FactorialFormFields";
33
import FibonacciFormFields from "./formFields/FibonacciFormFields";
44
import { useVisualizationContext } from "../hooks/useVisualizationContext";
5-
import { useVisualization } from "../hooks/useVisualization";
65
import { useCanvasContext } from "../hooks/useCanvasContext";
76

87
export default function AlgorithmForm() {
98

109
const {
1110
ongoingVisualization,
1211
setOngoingVisualization,
13-
selectedAlgorithm,
14-
setSelectedAlgorithm
15-
} = useVisualizationContext();
12+
selectedAlgorithm,
13+
setSelectedAlgorithm,
14+
visualizeFibonacci,
15+
visualizeFactorial,
16+
setAbort,
17+
} = useVisualizationContext();
1618

1719
const { setNodes, setEdges } = useCanvasContext();
18-
const { visualizeFibonacci, visualizeFactorial, setAbort } = useVisualization();
1920

2021
const clearCanvas = () => {
2122
setNodes([]);

src/components/PlayController.tsx

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { ChevronLeft, ChevronRight, Pause, Play } from 'lucide-react';
2+
import { useVisualizationContext } from "../hooks/useVisualizationContext";
3+
4+
export default function PlayController() {
5+
const {
6+
isPlaying,
7+
togglePlay,
8+
goNextStep,
9+
goPreviousStep,
10+
canGoNext,
11+
canGoPrevious,
12+
} = useVisualizationContext();
13+
14+
return (
15+
<div className="mt-4 bg-gray-900/90 w-fit rounded-3xl p-2 mx-auto">
16+
<div className="flex items-center justify-center gap-2">
17+
<button
18+
type="button"
19+
aria-label="Previous step"
20+
disabled={!canGoPrevious}
21+
onClick={goPreviousStep}
22+
className="grid place-items-center w-11 h-11 bg-gray-800 text-white rounded-2xl border border-gray-700 hover:bg-gray-700 transition disabled:opacity-50 disabled:cursor-not-allowed"
23+
>
24+
<ChevronLeft className="w-5 h-5" />
25+
</button>
26+
<button
27+
type="button"
28+
aria-label={isPlaying ? "Pause visualization" : "Resume visualization"}
29+
onClick={togglePlay}
30+
className="grid place-items-center w-12 h-12 bg-violet-600 text-white rounded-2xl border border-violet-700 hover:bg-violet-700 transition"
31+
>
32+
{isPlaying ? <Pause className="w-5 h-5" /> : <Play className="w-5 h-5" />}
33+
</button>
34+
<button
35+
type="button"
36+
aria-label="Next step"
37+
disabled={!canGoNext}
38+
onClick={goNextStep}
39+
className="grid place-items-center w-11 h-11 bg-gray-800 text-white rounded-2xl border border-gray-700 hover:bg-gray-700 transition disabled:opacity-50 disabled:cursor-not-allowed"
40+
>
41+
<ChevronRight className="w-5 h-5" />
42+
</button>
43+
</div>
44+
</div>
45+
);
46+
}

src/components/SidePanel.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import AlgorithmForm from "./AlgorithmForm";
2+
import PlayController from "./PlayController";
23
import { Github, Linkedin } from 'lucide-react';
34
import { useVisualizationContext } from "../hooks/useVisualizationContext";
45
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
5-
import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism';
6+
import { atomDark } from 'react-syntax-highlighter/dist/esm/styles/prism';
67

78
export default function SidePanel() {
8-
const { selectedAlgorithm } = useVisualizationContext();
9+
const { selectedAlgorithm, ongoingVisualization } = useVisualizationContext();
910

1011
const getAlgorithmCode = (algorithm: string) => {
1112
switch (algorithm) {
@@ -38,7 +39,8 @@ export default function SidePanel() {
3839
md:h-screen
3940
flex flex-col
4041
justify-between
41-
overflow-y-auto
42+
overflow-y-auto
43+
md:overflow-hidden
4244
"
4345
>
4446
{/* Main content */}
@@ -56,18 +58,19 @@ export default function SidePanel() {
5658
<div className="bg-black rounded-md p-4 overflow-x-auto">
5759
<SyntaxHighlighter
5860
language="javascript"
59-
style={oneDark}
60-
customStyle={{ background: 'transparent', margin: 0 }}
61+
style={atomDark}
62+
customStyle={{ background: 'transparent', padding: 0, margin: 0 }}
6163
>
6264
{getAlgorithmCode(selectedAlgorithm)}
6365
</SyntaxHighlighter>
6466
</div>
67+
{ongoingVisualization && <PlayController />}
6568
</div>
6669
)}
6770
</div>
6871

6972
{/* Footer */}
70-
<div className="mt-6 text-center text-gray-400 text-sm">
73+
<div className="mt-3 text-center text-gray-400 text-sm">
7174
<p>Built by: Ahmad Albarasy</p>
7275
<div className="flex justify-center space-x-4 mt-2">
7376
<a

src/components/formFields/FibonacciFormFields.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export default function FibonacciFormFields() {
1818
max={5}
1919
required
2020
disabled={ongoingVisualization}
21-
placeholder="e.g. 6"
21+
placeholder="e.g. 5"
2222
className="
2323
bg-gray-800 text-white
2424
p-2
Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
import { createContext } from "react";
22

33
export type VisualizationContextType = {
4-
ongoingVisualization: boolean,
4+
ongoingVisualization: boolean;
55
setOngoingVisualization: React.Dispatch<React.SetStateAction<boolean>>;
6-
selectedAlgorithm: string,
6+
selectedAlgorithm: string;
77
setSelectedAlgorithm: React.Dispatch<React.SetStateAction<string>>;
8+
isPlaying: boolean;
9+
togglePlay: () => void;
10+
goNextStep: () => void;
11+
goPreviousStep: () => void;
12+
visualizeFibonacci: (n: number, id: string, y: number, minX: number, maxX: number) => void;
13+
visualizeFactorial: (n: number, id: string, x: number, y: number) => void;
14+
setAbort: (bool: boolean) => void;
15+
canGoNext: boolean;
16+
canGoPrevious: boolean;
817
};
918

1019
export const VisualizationContext = createContext<VisualizationContextType | null>(null);

0 commit comments

Comments
 (0)