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
11 changes: 3 additions & 8 deletions frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,9 @@ const AppContent = () => {
path="*"
element={<NotFoundPage />}
/>
<Route
path="/tutorials"
element={<TutorialsPage darkMode={darkMode} />}
/>
<Route
path="/tutorial/:tutorialId"
element={<TutorialPage darkMode={darkMode} />}
/>
<Route path="/tutorials" element={<TutorialsPage darkMode={isDark} />} />
<Route path="/tutorial/:tutorialId" element={<TutorialPage darkMode={isDark} />} />

</Routes>
</Layout>
</Router>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Sorting/ComplexityDisplay.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const ComplexityDisplay = ({ algorithm, currentData, steps }) => {
</div>
<div className="flex justify-between">
<span className="text-gray-600">Steps:</span>
<span className="font-medium">{steps.length}</span>
<span className="font-medium">{steps?.length || 0}</span>
</div>
</div>
</div>
Expand Down
98 changes: 69 additions & 29 deletions frontend/src/pages/StringVisualizer.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import React, { useState } from 'react';
import { useTheme } from '../contexts/ThemeContext'; // Use the project's theme system
import { Play, RotateCcw, Text, Hash } from 'lucide-react';
// STEP 1: Add 'BookOpen' to the import list
import { Play, RotateCcw, Text, Hash, BookOpen } from 'lucide-react';
import { useTheme } from '../contexts/ThemeContext';

const StringVisualizer = () => {
const { classes } = useTheme(); // Get the theme classes
const { isDark } = useTheme();
const [text, setText] = useState('ababcabcabababd');
const [pattern, setPattern] = useState('abababd');

// STEP 2: Add the new state for the explanation text
const [showDetailedLog, setShowDetailedLog] = useState(false);
const [explanation, setExplanation] = useState({
operation: 'Ready to start.',
details: 'Enter text and a pattern, then click Visualize to begin the process.',
algorithmInfo: 'The Naive (or Brute-Force) search algorithm checks for a match at every possible position in the text.'
});

const handleVisualize = () => console.log('Visualize clicked!', { text, pattern });
const handleReset = () => {
setText('');
Expand All @@ -15,9 +24,8 @@ const StringVisualizer = () => {
};

return (
// Use the theme's background class
<div className={`w-full min-h-screen ${classes.bgPrimary} p-4 sm:p-8`}>
{/* Spacer div */}
<div className="w-full min-h-screen bg-slate-50 p-4 sm:p-8">
{/* Spacer to push content down from the main site navigation */}
<div className="h-24"></div>

{/* 1. Gradient Header Card */}
Expand All @@ -32,42 +40,40 @@ const StringVisualizer = () => {

<div className="max-w-7xl mx-auto grid grid-cols-1 lg:grid-cols-3 gap-8">

{/* 2. Left Column: Inputs & Controls Card */}
<div className="lg:col-span-1">
<div className={`${classes.cardBg} p-6 rounded-xl shadow-md border ${classes.border}`}>
<h2 className={`text-xl font-bold ${classes.textPrimary} mb-6 flex items-center gap-2`}>
{/* 2. Left Column: Contains both cards now */}
<div className="lg:col-span-1 space-y-8">
{/* Inputs & Controls Card */}
<div className="bg-white p-6 rounded-xl shadow-md border border-slate-200">
<h2 className="text-xl font-bold text-slate-800 mb-6 flex items-center gap-2">
<Text size={22} className="text-indigo-500" />
Inputs & Controls
</h2>

<div className="mb-4">
<label htmlFor="main-text" className={`block text-sm font-medium ${classes.textSecondary} mb-2`}>
<label htmlFor="main-text" className="block text-sm font-medium text-slate-600 mb-2">
Main Text (Haystack)
</label>
<input
id="main-text"
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
className={`w-full p-3 ${classes.inputBg} ${classes.textPrimary} placeholder-slate-400 rounded-lg border ${classes.border} focus:outline-none focus:ring-2 focus:ring-indigo-500 transition`}
className="w-full p-3 bg-slate-100 text-slate-800 placeholder-slate-400 rounded-lg border border-slate-300 focus:outline-none focus:ring-2 focus:ring-indigo-500 transition"
placeholder="Enter text..."
/>
</div>

<div className="mb-6">
<label htmlFor="pattern-text" className={`block text-sm font-medium ${classes.textSecondary} mb-2`}>
<label htmlFor="pattern-text" className="block text-sm font-medium text-slate-600 mb-2">
Pattern to Find (Needle)
</label>
<input
id="pattern-text"
type="text"
value={pattern}
onChange={(e) => setPattern(e.target.value)}
className={`w-full p-3 ${classes.inputBg} ${classes.textPrimary} placeholder-slate-400 rounded-lg border ${classes.border} focus:outline-none focus:ring-2 focus:ring-indigo-500 transition`}
className="w-full p-3 bg-slate-100 text-slate-800 placeholder-slate-400 rounded-lg border border-slate-300 focus:outline-none focus:ring-2 focus:ring-indigo-500 transition"
placeholder="Enter pattern..."
/>
</div>

<div className="flex flex-col sm:flex-row gap-4">
<button
onClick={handleVisualize}
Expand All @@ -85,39 +91,73 @@ const StringVisualizer = () => {
</button>
</div>
</div>

{/* Step Explanation Card */}
<div className={`backdrop-blur-xl rounded-2xl shadow-2xl border overflow-hidden ${isDark ? 'bg-gray-800/20 border-gray-700/50' : 'bg-white/20 border-white/50'}`}>
<div className={`p-4 border-b ${isDark ? 'border-gray-700/50' : 'border-white/50'}`}>
<div className="flex justify-between items-center">
<h4 className={`text-lg font-bold flex items-center ${isDark ? 'text-white' : 'text-gray-800'}`}>
<BookOpen className="h-5 w-5 mr-2 text-purple-500" />
Step Explanation
</h4>
<button
onClick={() => setShowDetailedLog(!showDetailedLog)}
className={`text-sm px-3 py-1 rounded transition-colors ${isDark ? 'text-gray-300 hover:text-white hover:bg-gray-700' : 'text-gray-600 hover:text-gray-800 hover:bg-gray-100'}`}
>
{showDetailedLog ? 'Hide Log' : 'Show Log'}
</button>
</div>
</div>
<div className="p-4 space-y-4">
<div className={`p-4 rounded-lg border-l-4 border-blue-500 ${isDark ? 'bg-blue-900/20' : 'bg-blue-50'}`}>
<p className={`text-sm font-medium mb-1 ${isDark ? 'text-white' : 'text-gray-800'}`}>Current Operation:</p>
<p className={`text-sm ${isDark ? 'text-gray-300' : 'text-gray-700'}`}>{explanation.operation}</p>
</div>
<div className={`p-4 rounded-lg border-l-4 border-purple-500 ${isDark ? 'bg-purple-900/20' : 'bg-purple-50'}`}>
<p className={`text-sm font-medium mb-1 ${isDark ? 'text-white' : 'text-gray-800'}`}>What's Happening:</p>
<p className={`text-sm leading-relaxed ${isDark ? 'text-gray-300' : 'text-gray-700'}`}>{explanation.details}</p>
</div>
<div className={`p-4 rounded-lg border-l-4 border-green-500 bg-green-50`}>
<p className={`text-sm font-medium mb-1 text-slate-800`}>
Algorithm Info:
</p>
<p className={`text-sm leading-relaxed text-slate-700`}>
{explanation.algorithmInfo}
</p>
</div>
</div>
</div>
</div>

{/* 3. Right Column: Display Area Card */}
<div className="lg:col-span-2">
<div className={`${classes.cardBg} p-6 rounded-xl shadow-md border ${classes.border} min-h-[300px]`}>
<h2 className={`text-xl font-bold ${classes.textPrimary} mb-6 flex items-center gap-2`}>
<div className="bg-white p-6 rounded-xl shadow-md border border-slate-200 min-h-[300px]">
<h2 className="text-xl font-bold text-slate-800 mb-6 flex items-center gap-2">
<Hash size={22} className="text-indigo-500" />
Visualization
</h2>

<div className="mb-6">
<h3 className={`text-md font-semibold mb-3 ${classes.textSecondary}`}>Text</h3>
<div className={`flex flex-wrap gap-1 p-3 ${classes.inputBg} rounded-lg`}>
<h3 className="text-md font-semibold mb-3 text-slate-600">Text</h3>
<div className="flex flex-wrap gap-1 p-3 bg-slate-100 rounded-lg">
{text.split('').map((char, index) => (
<div key={`text-${index}`} className="flex flex-col items-center">
<div className={`flex items-center justify-center w-8 h-8 sm:w-10 sm:h-10 ${classes.cardBg} border ${classes.border} rounded-md text-lg font-mono ${classes.textPrimary}`}>
<div className="flex items-center justify-center w-8 h-8 sm:w-10 sm:h-10 bg-white border border-slate-300 rounded-md text-lg font-mono text-slate-800">
{char}
</div>
<span className={`text-xs ${classes.textMuted} mt-1`}>{index}</span>
<span className="text-xs text-slate-500 mt-1">{index}</span>
</div>
))}
</div>
</div>

<div>
<h3 className={`text-md font-semibold mb-3 ${classes.textSecondary}`}>Pattern</h3>
<div className={`flex flex-wrap gap-1 p-3 ${classes.inputBg} rounded-lg`}>
<h3 className="text-md font-semibold mb-3 text-slate-600">Pattern</h3>
<div className="flex flex-wrap gap-1 p-3 bg-slate-100 rounded-lg">
{pattern.split('').map((char, index) => (
<div key={`pattern-${index}`} className="flex flex-col items-center">
<div className={`flex items-center justify-center w-8 h-8 sm:w-10 sm:h-10 ${classes.cardBg} border ${classes.border} rounded-md text-lg font-mono ${classes.textPrimary}`}>
<div className="flex items-center justify-center w-8 h-8 sm:w-10 sm:h-10 bg-white border border-slate-300 rounded-md text-lg font-mono text-slate-800">
{char}
</div>
<span className={`text-xs ${classes.textMuted} mt-1`}>{index}</span>
<span className="text-xs text-slate-500 mt-1">{index}</span>
</div>
))}
</div>
Expand Down
Loading