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
2 changes: 2 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import SortingPage from "./pages/sorting/SortingPage";
import GraphPage from "./pages/graph/GraphPage";
import Homepage from "./pages/Homepage.jsx";
import DSPage from "./pages/dataStructure/datastructurePage.jsx"
import DynamicProgrammingPage from "./pages/dynamic-programming/DyanmicProgrammingPage.jsx";

function App() {
Expand All @@ -13,6 +14,7 @@ function App() {
<Route path="/" element={<Homepage />} />
{/* <Route path="/graph/union-find" element={<UnionFindPage />} /> */}
<Route path="/sorting" element={<SortingPage />} />
<Route path="/data-structures" element={<DSPage/>}/>
<Route path="/graph" element={<GraphPage />} />
<Route path="/dynamic-programming" element={<DynamicProgrammingPage />} />
</Routes>
Expand Down
51 changes: 51 additions & 0 deletions src/algorithms/dataStructure/stack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
export function* stackOp(array, action) {

const arr = [...array];

const snapshot = () => [...arr];

switch (action?.type) {
case "push": {
yield { type: "push-start", value: action.value };
arr.unshift(action.value);
yield { type: "push", value: action.value, array: snapshot() };
break;
}

case "pop": {
if (arr.length === 0) {
yield { type: "underflow" };
} else {
yield { type: "pop-start", index: 0, value: arr[0] };
const popped = arr.shift();
yield { type: "pop", value: popped, array: snapshot() };
}
break;
}

case "peek": {
if (arr.length === 0) {
yield { type: "peek-empty" };
} else {
yield { type: "peek", value: arr[0], index: 0 };
}
break;
}

case "clear": {
if (arr.length === 0) {
yield { type: "clear-empty" };
} else {
yield { type: "clear", array: [] };
arr.length = 0;
}
break;
}

default: {
yield { type: "invalid", action };
}
}

yield { type: "done", array: snapshot() };
}
60 changes: 60 additions & 0 deletions src/components/dataStructure/stack.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React from "react";

const COLORS = {
default: "bg-slate-700 shadow-[0_0_8px_rgba(15,23,42,0.6)]",
push: "bg-green-500 shadow-[0_0_12px_rgba(34,197,94,0.4)]",
pop: "bg-red-500 shadow-[0_0_12px_rgba(239,68,68,0.35)]",
peek: "bg-yellow-400 shadow-[0_0_12px_rgba(250,204,21,0.3)]",
underflow: "bg-rose-600/60",
};

export default function StackVisualizer({ array = [], highlight = null }) {
return (
<div className="flex flex-col items-center">
<div className="mb-2 text-sm text-slate-400">Top</div>

<div className="w-48 min-h-[200px] max-h-[420px] border rounded-lg p-3 bg-white/5 overflow-auto">
<div className="flex flex-col items-center space-y-2">
{array.length === 0 ? (
<div className="text-slate-400 italic py-6">Stack is empty</div>
) : (
array.map((value, idx) => {
let cls = COLORS.default;

if (highlight) {
if (highlight.type === "push" && highlight.array && highlight.array[0] === value && idx === 0) {
cls = COLORS.push;
}
if ((highlight.type === "pop" || highlight.type === "pop-start") && idx === 0) {
cls = COLORS.pop;
}
if (highlight.type === "peek" && highlight.index === idx) {
cls = COLORS.peek;
}
if (highlight.type === "underflow") {
cls = COLORS.underflow;
}
if (highlight.type === "clear" && array.length === 0) {
cls = COLORS.default;
}
}

return (
<div
key={idx + "-" + String(value)}
className={`${cls} w-full rounded-md px-3 py-2 flex justify-between items-center text-white transition-all duration-300`}
style={{ minHeight: 40 }}
>
<div className="truncate">{String(value)}</div>
<div className="text-xs opacity-80">#{array.length - idx}</div>
</div>
);
})
)}
</div>
</div>

<div className="mt-2 text-sm text-slate-500">Bottom</div>
</div>
);
}
86 changes: 86 additions & 0 deletions src/pages/dataStructure/datastructurePage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React, { useState } from "react";
import { Network, Compass, Rocket } from "lucide-react";
import StackPage from "./stack.jsx";

export default function DSPage() {
const [selectedDS, setSelectedDS] = useState("");

const renderDataStructure = () => {
switch (selectedDS) {
case "stack":
return (
<div className="w-full h-full overflow-auto">
<StackPage />
</div>
);

default:
return (
<div className="flex flex-col items-center justify-center text-center p-6">
<div className="bg-gradient-to-tr from-indigo-500 via-blue-400 to-purple-500 p-[2px] rounded-2xl">
<div className="bg-gray-950 rounded-2xl px-10 py-12 shadow-2xl">
<div className="flex justify-center mb-4">
<Network className="w-16 h-16 text-indigo-400" />
</div>
<h2 className="text-2xl font-extrabold bg-gradient-to-r from-indigo-400 to-purple-400 bg-clip-text text-transparent mb-2">
Data Structure Visualizer
</h2>
<p className="text-gray-400 mb-6 max-w-sm">
Select a data structure from the sidebar to begin visualization.
Watch how elements, stacks, and queues transform step by step! 🧠✨
</p>
<div className="flex items-center justify-center gap-6">
<Compass className="w-8 h-8 text-blue-400 animate-pulse" />
<Rocket className="w-8 h-8 text-purple-400 animate-bounce" />
</div>
</div>
</div>
</div>
);
}
};

return (
<div className="flex h-screen bg-black text-white">
{/* Sidebar */}
<div className="w-64 bg-[#0f172a] p-6 border-r border-gray-800 flex-shrink-0">
<h2 className="text-xl font-bold mb-6 text-indigo-400 tracking-wide">
Data Structure Panel
</h2>

<label className="block mb-2 text-sm">Select Data Structure:</label>
<select
value={selectedDS}
onChange={(e) => setSelectedDS(e.target.value)}
className="w-full p-2 rounded bg-[#1e293b] text-white border border-gray-600 focus:ring-2 focus:ring-indigo-500 focus:outline-none"
>
<option value="">Select Data Structure</option>
<option value="stack">Stack</option>
<option value="queue">Queue</option>
{/* <option value="linkedlist">Linked List</option> */}
</select>

<button
onClick={() => setSelectedDS("")}
className="w-full mt-4 py-2 bg-gray-700 hover:bg-gray-600 rounded transition font-medium"
>
Reset
</button>

<a
href="/"
className="inline-block mt-10 text-indigo-400 hover:underline text-sm"
>
← Back to Home
</a>
</div>

{/* Visualization Area */}
<div className="flex-1 flex overflow-auto">
<div className="flex-1 min-w-[800px] min-h-full">
{renderDataStructure()}
</div>
</div>
</div>
);
}
148 changes: 148 additions & 0 deletions src/pages/dataStructure/stack.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import React, { useState } from "react";
import { Toaster, toast } from "react-hot-toast";
import StackVisualizer from "../../components/dataStructure/stack.jsx";
import { stackOp } from "../../algorithms/dataStructure/stack.js";

export default function StackPage() {
const [array, setArray] = useState([]);
const [input, setInput] = useState("");
const [highlight, setHighlight] = useState(null);
const [isRunning, setIsRunning] = useState(false);

const delay = (ms) => new Promise((r) => setTimeout(r, ms));

const runAction = async (action) => {
if (isRunning) return;
setIsRunning(true);

const gen = stackOp(array, action);
for (let step of gen) {
setHighlight(step);
if (step.array) setArray([...step.array]);
await delay(400);
}

await delay(150);
setHighlight(null);
setIsRunning(false);
};

const handlePush = async () => {
if (!input.trim()) {
toast.error("Enter a value to push");
return;
}
const parsed = input.trim();
const value = parsed.length && !Number.isNaN(Number(parsed)) ? Number(parsed) : parsed;
await runAction({ type: "push", value });
setInput("");
};

const handlePop = async () => {
await runAction({ type: "pop" });
};

const handlePeek = async () => {
await runAction({ type: "peek" });
};

const handleClear = async () => {
await runAction({ type: "clear" });
};

const handleReset = () => {
setArray([]);
setInput("");
setHighlight(null);
};

const sampleLoad = () => {
setArray(["X", "Y", "Z"]);
setHighlight({ type: "done", array: ["X", "Y", "Z"] });
};

return (
<div className="min-h-screen bg-black text-gray-200 flex flex-col items-center p-4 sm:p-6">
<Toaster position="top-center" />
<h1 className="text-3xl sm:text-4xl font-extrabold mb-6 sm:mb-8 text-indigo-400 drop-shadow-lg text-center">
Stack Visualizer
</h1>

<div className="w-full max-w-2xl">
<div className="bg-gray-900/40 rounded-lg p-4 sm:p-6 shadow-md">
<div className="flex flex-col sm:flex-row sm:items-center gap-3 sm:gap-4">
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Value to push (number or string)"
className="flex-1 w-full sm:w-auto border-2 border-indigo-500 bg-gray-900 text-indigo-200 rounded-lg p-3 text-center outline-none shadow-inner"
/>
<button
onClick={handlePush}
disabled={isRunning}
className={`w-full sm:w-auto ${
isRunning ? "bg-indigo-700 cursor-not-allowed" : "bg-indigo-600 hover:bg-indigo-500"
} px-4 py-2 rounded text-white font-semibold`}
>
Push
</button>
</div>

<div className="mt-4 grid grid-cols-1 sm:grid-cols-5 gap-3">
<button
onClick={handlePop}
disabled={isRunning}
className={`col-span-1 w-full ${
isRunning ? "bg-gray-700 cursor-not-allowed" : "bg-rose-600 hover:bg-rose-500"
} px-4 py-2 rounded text-white font-semibold`}
>
Pop
</button>

<button
onClick={handlePeek}
disabled={isRunning}
className={`col-span-1 w-full ${
isRunning ? "bg-gray-700 cursor-not-allowed" : "bg-yellow-500 hover:bg-yellow-400"
} px-4 py-2 rounded text-white font-semibold`}
>
Peek
</button>

<button
onClick={handleClear}
disabled={isRunning}
className={`col-span-1 w-full ${
isRunning ? "bg-gray-700 cursor-not-allowed" : "bg-gray-700 hover:bg-gray-600"
} px-4 py-2 rounded text-white font-semibold`}
>
Clear
</button>

<button
onClick={handleReset}
className="col-span-1 w-full bg-gray-600 hover:bg-gray-500 px-4 py-2 rounded text-white font-semibold"
>
Reset
</button>

<button
onClick={sampleLoad}
className="col-span-1 w-full bg-indigo-500 hover:bg-indigo-400 px-4 py-2 rounded text-white font-semibold"
>
Load Demo
</button>
</div>
</div>

<div className="mt-6">
<StackVisualizer array={array} highlight={highlight} />
</div>

<div className="mt-4 text-sm text-slate-400 text-center">
Tip: top of stack is shown at the top (index 0). Push adds to top; Pop removes the top (LIFO).
</div>
</div>
</div>
);
}
Loading