Add Ternary Search Magic Trick interactive and fix layout issues
- Create new Ternary Search Magic Trick interactive with ternary search logic - Add emoji buttons and 'not present' option for better UX - Implement 'How it Works' modal with embedded YouTube video - Fix layout margins when accessing interactives from theme pages - Add standalone and green screen pages for the new interactive - Update Data Structures theme to include the new interactive
This commit is contained in:
parent
3f04e8c7d7
commit
7451682dd5
7 changed files with 419 additions and 26 deletions
|
|
@ -22,6 +22,8 @@ import BinarySearchTrickPage from "./pages/BinarySearchTrickPage";
|
||||||
import BinarySearchTrickGreenScreen from "./pages/BinarySearchTrickGreenScreen";
|
import BinarySearchTrickGreenScreen from "./pages/BinarySearchTrickGreenScreen";
|
||||||
import GameOfSimGreenScreen from "./pages/GameOfSimGreenScreen";
|
import GameOfSimGreenScreen from "./pages/GameOfSimGreenScreen";
|
||||||
import GameOfSimPage from "./pages/GameOfSimPage";
|
import GameOfSimPage from "./pages/GameOfSimPage";
|
||||||
|
import TernarySearchTrickPage from "./pages/TernarySearchTrickPage";
|
||||||
|
import TernarySearchTrickGreenScreen from "./pages/TernarySearchTrickGreenScreen";
|
||||||
import Foundations from "./pages/theme-pages/discrete-math/Foundations";
|
import Foundations from "./pages/theme-pages/discrete-math/Foundations";
|
||||||
import Proofs from "./pages/theme-pages/discrete-math/Proofs";
|
import Proofs from "./pages/theme-pages/discrete-math/Proofs";
|
||||||
import Counting from "./pages/theme-pages/discrete-math/Counting";
|
import Counting from "./pages/theme-pages/discrete-math/Counting";
|
||||||
|
|
@ -70,6 +72,8 @@ const App = () => (
|
||||||
<Route path="/binary-search-trick/:mode" element={<BinarySearchTrickGreenScreen />} />
|
<Route path="/binary-search-trick/:mode" element={<BinarySearchTrickGreenScreen />} />
|
||||||
<Route path="/game-of-sim" element={<GameOfSimPage />} />
|
<Route path="/game-of-sim" element={<GameOfSimPage />} />
|
||||||
<Route path="/game-of-sim/:mode" element={<GameOfSimGreenScreen />} />
|
<Route path="/game-of-sim/:mode" element={<GameOfSimGreenScreen />} />
|
||||||
|
<Route path="/ternary-search-trick" element={<TernarySearchTrickPage />} />
|
||||||
|
<Route path="/ternary-search-trick/:mode" element={<TernarySearchTrickGreenScreen />} />
|
||||||
|
|
||||||
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
|
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
|
||||||
<Route path="*" element={<NotFound />} />
|
<Route path="*" element={<NotFound />} />
|
||||||
|
|
|
||||||
|
|
@ -3,38 +3,60 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Search } from 'lucide-react';
|
import { Search } from 'lucide-react';
|
||||||
|
import Layout from '@/components/Layout';
|
||||||
import BinarySearchTrick from '@/components/BinarySearchTrick';
|
import BinarySearchTrick from '@/components/BinarySearchTrick';
|
||||||
|
import TernarySearchTrick from '@/components/TernarySearchTrick';
|
||||||
|
|
||||||
interface Interactive {
|
interface Interactive {
|
||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
tags: string[];
|
tags: string[];
|
||||||
component: React.ComponentType;
|
component: React.ComponentType<{ showSocialShare?: boolean }>;
|
||||||
}
|
}
|
||||||
const interactives: Interactive[] = [{
|
|
||||||
id: 'binary-search-trick',
|
const interactives: Interactive[] = [
|
||||||
title: 'Binary Search Magic Trick',
|
{
|
||||||
description: 'Perform an amazing magic trick that reveals how binary numbers work. Think of a number and watch the magic happen!',
|
id: 'binary-search-trick',
|
||||||
tags: ['binary', 'magic', 'numbers', 'trick', 'data-structures'],
|
title: 'Binary Search Magic Trick',
|
||||||
component: BinarySearchTrick
|
description: 'Perform an amazing magic trick that reveals how binary numbers work. Think of a number and watch the magic happen!',
|
||||||
}];
|
tags: ['binary', 'magic', 'numbers', 'trick', 'data-structures'],
|
||||||
|
component: BinarySearchTrick
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ternary-search-trick',
|
||||||
|
title: 'Ternary Search Magic Trick',
|
||||||
|
description: 'Experience the magic of ternary search! Think of a number and watch as the cards reveal it through mathematical calculations.',
|
||||||
|
tags: ['ternary', 'magic', 'numbers', 'trick', 'data-structures', 'search'],
|
||||||
|
component: TernarySearchTrick
|
||||||
|
}
|
||||||
|
];
|
||||||
const InteractiveGallery = () => {
|
const InteractiveGallery = () => {
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
const [selectedInteractive, setSelectedInteractive] = useState<Interactive | null>(null);
|
const [selectedInteractive, setSelectedInteractive] = useState<Interactive | null>(null);
|
||||||
const filteredInteractives = interactives.filter(interactive => interactive.title.toLowerCase().includes(searchTerm.toLowerCase()) || interactive.description.toLowerCase().includes(searchTerm.toLowerCase()) || interactive.tags.some(tag => tag.toLowerCase().includes(searchTerm.toLowerCase())));
|
const filteredInteractives = interactives.filter(interactive => interactive.title.toLowerCase().includes(searchTerm.toLowerCase()) || interactive.description.toLowerCase().includes(searchTerm.toLowerCase()) || interactive.tags.some(tag => tag.toLowerCase().includes(searchTerm.toLowerCase())));
|
||||||
if (selectedInteractive) {
|
if (selectedInteractive) {
|
||||||
const InteractiveComponent = selectedInteractive.component;
|
const InteractiveComponent = selectedInteractive.component;
|
||||||
return <div className="space-y-6">
|
return (
|
||||||
<div className="flex items-center gap-4">
|
<div className="min-h-screen bg-background">
|
||||||
<button onClick={() => setSelectedInteractive(null)} className="text-primary hover:text-primary/80 font-medium">← Back to Data Structures and Algorithms</button>
|
<div className="container mx-auto px-4 py-8 space-y-6">
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<button
|
||||||
|
onClick={() => setSelectedInteractive(null)}
|
||||||
|
className="text-primary hover:text-primary/80 font-medium"
|
||||||
|
>
|
||||||
|
← Back to Data Structures and Algorithms
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<InteractiveComponent showSocialShare={true} />
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-background border rounded-lg p-6">
|
</div>
|
||||||
<InteractiveComponent />
|
);
|
||||||
</div>
|
|
||||||
</div>;
|
|
||||||
}
|
}
|
||||||
return <div className="space-y-6">
|
return (
|
||||||
|
<Layout>
|
||||||
|
<div className="max-w-7xl mx-auto p-6">
|
||||||
|
<div className="space-y-6">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<h1 className="text-3xl font-bold text-foreground">Data Structures and Algorithms</h1>
|
<h1 className="text-3xl font-bold text-foreground">Data Structures and Algorithms</h1>
|
||||||
<p className="text-muted-foreground text-lg">Interactive explorations of elementary data structures and algorithms.</p>
|
<p className="text-muted-foreground text-lg">Interactive explorations of elementary data structures and algorithms.</p>
|
||||||
|
|
@ -68,6 +90,9 @@ const InteractiveGallery = () => {
|
||||||
{filteredInteractives.length === 0 && <div className="text-center py-12">
|
{filteredInteractives.length === 0 && <div className="text-center py-12">
|
||||||
<p className="text-muted-foreground text-lg">No interactives found matching your search.</p>
|
<p className="text-muted-foreground text-lg">No interactives found matching your search.</p>
|
||||||
</div>}
|
</div>}
|
||||||
</div>;
|
</div>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
export default InteractiveGallery;
|
export default InteractiveGallery;
|
||||||
|
|
@ -45,6 +45,15 @@ const allInteractives: Interactive[] = [
|
||||||
path: '/game-of-sim',
|
path: '/game-of-sim',
|
||||||
theme: 'Games',
|
theme: 'Games',
|
||||||
dateAdded: '2024-03-10'
|
dateAdded: '2024-03-10'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ternary-search-trick',
|
||||||
|
title: 'Ternary Search Magic Trick',
|
||||||
|
description: 'Experience the magic of ternary search! Think of a number and watch as the cards reveal it through mathematical calculations.',
|
||||||
|
tags: ['ternary', 'magic', 'numbers', 'trick', 'data-structures', 'search'],
|
||||||
|
path: '/ternary-search-trick',
|
||||||
|
theme: 'Data Structures',
|
||||||
|
dateAdded: '2024-07-20'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
331
src/components/TernarySearchTrick.tsx
Normal file
331
src/components/TernarySearchTrick.tsx
Normal file
|
|
@ -0,0 +1,331 @@
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
|
||||||
|
import { RotateCcw, Wand2, Info } from 'lucide-react';
|
||||||
|
import SocialShare from '@/components/SocialShare';
|
||||||
|
|
||||||
|
interface TernarySearchTrickProps {
|
||||||
|
showSocialShare?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TernarySearchTrick: React.FC<TernarySearchTrickProps> = ({ showSocialShare = true }) => {
|
||||||
|
const [step, setStep] = useState<'cards' | 'final-question' | 'result'>('cards');
|
||||||
|
const [cardSelections, setCardSelections] = useState<{
|
||||||
|
card1: 'left' | 'right' | 'missing' | null;
|
||||||
|
card2: 'left' | 'right' | 'missing' | null;
|
||||||
|
card3: 'left' | 'right' | 'missing' | null;
|
||||||
|
}>({
|
||||||
|
card1: null,
|
||||||
|
card2: null,
|
||||||
|
card3: null
|
||||||
|
});
|
||||||
|
const [isBiggerThan13, setIsBiggerThan13] = useState<boolean | null>(null);
|
||||||
|
const [calculatedNumber, setCalculatedNumber] = useState<number | null>(null);
|
||||||
|
|
||||||
|
const cardData = {
|
||||||
|
card1: {
|
||||||
|
left: [5, 6, 7, 8, 9, 10, 11, 12, 13, 32, 33, 34, 35, 36, 37, 38, 39, 40],
|
||||||
|
right: [14, 15, 16, 17, 18, 19, 20, 21, 22]
|
||||||
|
},
|
||||||
|
card2: {
|
||||||
|
left: [2, 3, 4, 11, 12, 13, 20, 21, 22, 29, 30, 31, 38, 39, 40],
|
||||||
|
right: [5, 6, 7, 14, 15, 16, 23, 24, 25, 32, 33, 34]
|
||||||
|
},
|
||||||
|
card3: {
|
||||||
|
left: [1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40],
|
||||||
|
right: [2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetTrick = () => {
|
||||||
|
setStep('cards');
|
||||||
|
setCardSelections({
|
||||||
|
card1: null,
|
||||||
|
card2: null,
|
||||||
|
card3: null
|
||||||
|
});
|
||||||
|
setIsBiggerThan13(null);
|
||||||
|
setCalculatedNumber(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCardSelection = (cardNumber: 1 | 2 | 3, side: 'left' | 'right' | 'missing') => {
|
||||||
|
setCardSelections(prev => ({
|
||||||
|
...prev,
|
||||||
|
[`card${cardNumber}`]: side
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleContinue = () => {
|
||||||
|
if (cardSelections.card1 && cardSelections.card2 && cardSelections.card3) {
|
||||||
|
setStep('final-question');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFinalAnswer = (biggerThan13: boolean) => {
|
||||||
|
setIsBiggerThan13(biggerThan13);
|
||||||
|
|
||||||
|
// Calculate the number
|
||||||
|
let guess = 0;
|
||||||
|
|
||||||
|
// Card 1: left adds 9, right subtracts 9, missing adds 0
|
||||||
|
if (cardSelections.card1 === 'left') guess += 9;
|
||||||
|
else if (cardSelections.card1 === 'right') guess -= 9;
|
||||||
|
// missing adds 0, so no change
|
||||||
|
|
||||||
|
// Card 2: left adds 3, right subtracts 3, missing adds 0
|
||||||
|
if (cardSelections.card2 === 'left') guess += 3;
|
||||||
|
else if (cardSelections.card2 === 'right') guess -= 3;
|
||||||
|
// missing adds 0, so no change
|
||||||
|
|
||||||
|
// Card 3: left adds 1, right subtracts 1, missing adds 0
|
||||||
|
if (cardSelections.card3 === 'left') guess += 1;
|
||||||
|
else if (cardSelections.card3 === 'right') guess -= 1;
|
||||||
|
// missing adds 0, so no change
|
||||||
|
|
||||||
|
// If bigger than 13, add 27
|
||||||
|
if (biggerThan13) guess += 27;
|
||||||
|
|
||||||
|
setCalculatedNumber(guess);
|
||||||
|
setStep('result');
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderCard = (cardNumber: 1 | 2 | 3) => {
|
||||||
|
const cardKey = `card${cardNumber}` as keyof typeof cardData;
|
||||||
|
const isSelected = cardSelections[cardKey as keyof typeof cardSelections];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className={`w-full max-w-md ${isSelected ? 'ring-2 ring-primary' : ''}`}>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-center">Card {cardNumber}</CardTitle>
|
||||||
|
<CardDescription className="text-center">
|
||||||
|
{isSelected ? `You selected: ${isSelected === 'missing' ? 'not present' : isSelected}` : 'Choose where your number appears'}
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-4">
|
||||||
|
{/* Emoji Buttons at Top */}
|
||||||
|
<div className="grid grid-cols-3 gap-4">
|
||||||
|
<div className="text-center">
|
||||||
|
<Button
|
||||||
|
variant={isSelected === 'left' ? 'default' : 'outline'}
|
||||||
|
size="lg"
|
||||||
|
className="w-full h-16 text-2xl"
|
||||||
|
onClick={() => handleCardSelection(cardNumber, 'left')}
|
||||||
|
>
|
||||||
|
⬅️
|
||||||
|
</Button>
|
||||||
|
<p className="text-sm font-medium mt-2">Left</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="text-center">
|
||||||
|
<Button
|
||||||
|
variant={isSelected === 'missing' ? 'default' : 'outline'}
|
||||||
|
size="lg"
|
||||||
|
className="w-full h-16 text-2xl"
|
||||||
|
onClick={() => handleCardSelection(cardNumber, 'missing')}
|
||||||
|
>
|
||||||
|
❌
|
||||||
|
</Button>
|
||||||
|
<p className="text-sm font-medium mt-2">Not Present</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="text-center">
|
||||||
|
<Button
|
||||||
|
variant={isSelected === 'right' ? 'default' : 'outline'}
|
||||||
|
size="lg"
|
||||||
|
className="w-full h-16 text-2xl"
|
||||||
|
onClick={() => handleCardSelection(cardNumber, 'right')}
|
||||||
|
>
|
||||||
|
➡️
|
||||||
|
</Button>
|
||||||
|
<p className="text-sm font-medium mt-2">Right</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Number Boxes at Bottom */}
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="bg-muted p-3 rounded-lg text-xs">
|
||||||
|
{cardData[cardKey].left.map(num => (
|
||||||
|
<span key={num} className="inline-block w-6 text-center">{num}</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="bg-muted p-3 rounded-lg text-xs">
|
||||||
|
{cardData[cardKey].right.map(num => (
|
||||||
|
<span key={num} className="inline-block w-6 text-center">{num}</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderFinalQuestion = () => (
|
||||||
|
<Card className="w-full max-w-md mx-auto">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-center">Final Question</CardTitle>
|
||||||
|
<CardDescription className="text-center">
|
||||||
|
Is your number bigger than 13?
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-4">
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
className="flex-1"
|
||||||
|
onClick={() => handleFinalAnswer(true)}
|
||||||
|
>
|
||||||
|
Yes, bigger than 13
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
className="flex-1"
|
||||||
|
onClick={() => handleFinalAnswer(false)}
|
||||||
|
>
|
||||||
|
No, 13 or smaller
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderResult = () => (
|
||||||
|
<Card className="w-full max-w-md mx-auto">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-center flex items-center justify-center gap-2">
|
||||||
|
<Wand2 className="w-6 h-6" />
|
||||||
|
Magic Result!
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="text-center space-y-4">
|
||||||
|
<div className="text-6xl font-bold text-primary">
|
||||||
|
{calculatedNumber}
|
||||||
|
</div>
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
That's your number! 🎉
|
||||||
|
</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-2xl font-bold text-center">Ternary Search Magic Trick</CardTitle>
|
||||||
|
<CardDescription className="text-center">
|
||||||
|
Think of a number between 1 and 40, then follow the magic cards to reveal your number!
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-6">
|
||||||
|
{/* Step Indicator */}
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Badge variant={step === 'cards' ? 'default' : 'secondary'}>1. Cards</Badge>
|
||||||
|
<span className="text-muted-foreground">→</span>
|
||||||
|
<Badge variant={step === 'final-question' ? 'default' : 'secondary'}>2. Question</Badge>
|
||||||
|
<span className="text-muted-foreground">→</span>
|
||||||
|
<Badge variant={step === 'result' ? 'default' : 'secondary'}>3. Result</Badge>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Content based on step */}
|
||||||
|
{step === 'cards' && (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||||
|
{renderCard(1)}
|
||||||
|
{renderCard(2)}
|
||||||
|
{renderCard(3)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<Button
|
||||||
|
onClick={handleContinue}
|
||||||
|
disabled={!cardSelections.card1 || !cardSelections.card2 || !cardSelections.card3}
|
||||||
|
className="flex items-center gap-2"
|
||||||
|
>
|
||||||
|
Continue to Final Question
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{step === 'final-question' && renderFinalQuestion()}
|
||||||
|
{step === 'result' && renderResult()}
|
||||||
|
|
||||||
|
{/* Action Buttons */}
|
||||||
|
<div className="flex justify-center gap-4">
|
||||||
|
<Button variant="outline" onClick={resetTrick} className="flex items-center gap-2">
|
||||||
|
<RotateCcw className="w-4 h-4" />
|
||||||
|
Start Over
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Dialog>
|
||||||
|
<DialogTrigger asChild>
|
||||||
|
<Button variant="outline" className="flex items-center gap-2">
|
||||||
|
<Info className="w-4 h-4" />
|
||||||
|
How it Works
|
||||||
|
</Button>
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent className="sm:max-w-2xl">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle className="flex items-center gap-2">
|
||||||
|
<Info className="w-5 h-5" />
|
||||||
|
How the Ternary Search Magic Trick Works
|
||||||
|
</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
This trick uses the balanced ternary representation of numbers, about which you can learn more in the following video:
|
||||||
|
</p>
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<iframe
|
||||||
|
width="560"
|
||||||
|
height="315"
|
||||||
|
src="https://www.youtube.com/embed/yfQVL0_POKg?si=h52dE5LtTb7BWoHG"
|
||||||
|
title="YouTube video player"
|
||||||
|
frameBorder="0"
|
||||||
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||||
|
referrerPolicy="strict-origin-when-cross-origin"
|
||||||
|
allowFullScreen
|
||||||
|
className="w-full max-w-full rounded-lg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Instructions */}
|
||||||
|
<div className="text-center space-y-2 p-4 bg-muted rounded-lg">
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Think of a number between 1 and 40, then select which side of each card contains your number.
|
||||||
|
</p>
|
||||||
|
<p className="text-sm font-medium text-foreground">
|
||||||
|
The magic will reveal your number through mathematical calculations!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Social Share */}
|
||||||
|
{showSocialShare && (
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<SocialShare
|
||||||
|
title="Ternary Search Magic Trick"
|
||||||
|
description="Experience the magic of ternary search! Think of a number and watch as the cards reveal it through mathematical calculations."
|
||||||
|
url={`${window.location.origin}/ternary-search-trick`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TernarySearchTrick;
|
||||||
18
src/pages/TernarySearchTrickGreenScreen.tsx
Normal file
18
src/pages/TernarySearchTrickGreenScreen.tsx
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import TernarySearchTrick from '@/components/TernarySearchTrick';
|
||||||
|
import GreenScreenWrapper from '@/components/GreenScreenWrapper';
|
||||||
|
|
||||||
|
const TernarySearchTrickGreenScreen = () => {
|
||||||
|
const { mode } = useParams<{ mode: 'gs-lite' | 'gs-dark' }>();
|
||||||
|
const greenScreenMode = mode === 'gs-dark' ? 'dark' : 'lite';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<GreenScreenWrapper mode={greenScreenMode}>
|
||||||
|
<div className="space-y-6">
|
||||||
|
<TernarySearchTrick showSocialShare={false} />
|
||||||
|
</div>
|
||||||
|
</GreenScreenWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TernarySearchTrickGreenScreen;
|
||||||
13
src/pages/TernarySearchTrickPage.tsx
Normal file
13
src/pages/TernarySearchTrickPage.tsx
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import TernarySearchTrick from '@/components/TernarySearchTrick';
|
||||||
|
|
||||||
|
const TernarySearchTrickPage = () => {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-background flex items-center justify-center">
|
||||||
|
<div className="w-full max-w-6xl px-4 py-8">
|
||||||
|
<TernarySearchTrick showSocialShare={true} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TernarySearchTrickPage;
|
||||||
|
|
@ -1,14 +1,7 @@
|
||||||
import Layout from "@/components/Layout";
|
|
||||||
import InteractiveGallery from "@/components/InteractiveGallery";
|
import InteractiveGallery from "@/components/InteractiveGallery";
|
||||||
|
|
||||||
const DataStructures = () => {
|
const DataStructures = () => {
|
||||||
return (
|
return <InteractiveGallery />;
|
||||||
<Layout>
|
|
||||||
<div className="max-w-7xl mx-auto p-6">
|
|
||||||
<InteractiveGallery />
|
|
||||||
</div>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DataStructures;
|
export default DataStructures;
|
||||||
Loading…
Add table
Add a link
Reference in a new issue