Skip to content

Commit a455ae3

Browse files
committed
Support color schemes and dark mode
1 parent 4d4b5f1 commit a455ae3

File tree

1 file changed

+88
-29
lines changed

1 file changed

+88
-29
lines changed

src/components/EnumerationDemo.tsx

Lines changed: 88 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
55

66
export type EnumerationType = 'eager' | 'lazy';
77

8+
export type ThemeColors = {
9+
background?: string;
10+
text?: string;
11+
primary?: string;
12+
secondary?: string;
13+
accent?: string;
14+
gridLines?: string;
15+
};
16+
817
interface Dot {
918
pos: number;
1019
column: number;
@@ -42,15 +51,45 @@ interface Narration {
4251
}
4352

4453
interface EnumerationDemoProps extends React.HTMLAttributes<HTMLDivElement> {
45-
demoType?: EnumerationType | undefined | null;
54+
demoType?: EnumerationType;
55+
isDarkMode?: boolean;
56+
customColors?: ThemeColors;
4657
}
4758

48-
const EnumerationDemo: React.FC<EnumerationDemoProps> = ({ demoType }) => {
59+
const EnumerationDemo: React.FC<EnumerationDemoProps> = ({
60+
demoType,
61+
isDarkMode = false,
62+
customColors = {},
63+
className,
64+
...props
65+
}) => {
4966
const [progress, setProgress] = useState(0);
5067
const [playing, setPlaying] = useState(false);
5168
const [type, setType] = useState<EnumerationType>(demoType || 'eager');
5269
const [explosions, setExplosions] = useState<ExplosionParticle[]>([]);
5370
const [positions, setPositions] = useState<Position[]>([]);
71+
72+
// Theme configuration
73+
const theme = {
74+
background:
75+
customColors.background || (isDarkMode ? 'rgb(24, 24, 27)' : 'white'),
76+
text:
77+
customColors.text ||
78+
(isDarkMode ? 'rgb(250, 250, 250)' : 'rgb(24, 24, 27)'),
79+
primary:
80+
customColors.primary ||
81+
(isDarkMode ? 'rgb(59, 130, 246)' : 'rgb(59, 130, 246)'),
82+
secondary:
83+
customColors.secondary ||
84+
(isDarkMode ? 'rgb(244, 114, 182)' : 'rgb(249, 115, 22)'),
85+
accent:
86+
customColors.accent ||
87+
(isDarkMode ? 'rgb(168, 85, 247)' : 'rgb(168, 85, 247)'),
88+
gridLines:
89+
customColors.gridLines ||
90+
(isDarkMode ? 'rgb(63, 63, 70)' : 'rgb(229, 231, 235)'),
91+
};
92+
5493
const processedStepsRef = useRef<Set<string>>(new Set());
5594
const animationRef = useRef<number | null>(null);
5695

@@ -448,21 +487,41 @@ const EnumerationDemo: React.FC<EnumerationDemoProps> = ({ demoType }) => {
448487
const narration = getNarration();
449488

450489
return (
451-
<Card className='w-full max-w-2xl'>
490+
<Card
491+
className={`w-full max-w-2xl ${isDarkMode ? 'dark' : ''} ${
492+
className || ''
493+
}`}
494+
style={{
495+
backgroundColor: theme.background,
496+
color: theme.text,
497+
}}
498+
{...props}
499+
>
452500
<CardHeader>
453501
<CardTitle className='flex items-baseline gap-2'>
454-
<span>{type === 'eager' ? 'Eager' : 'Lazy'} Enumeration</span>
455-
<span className='text-sm text-gray-500 font-normal'>
502+
<span style={{ color: theme.text }}>
503+
{type === 'eager' ? 'Eager' : 'Lazy'} Enumeration
504+
</span>
505+
<span
506+
className='text-sm font-normal'
507+
style={{ color: `${theme.text}88` }}
508+
>
456509
{type === 'eager'
457510
? 'Processes all items through each step before moving to next step'
458-
: 'Processes each needed item through all steps before moving to next item'}
511+
: 'Processes each needed item through steps before moving to next item'}
459512
</span>
460513
</CardTitle>
461514
</CardHeader>
462515
<CardContent>
463-
<div className='h-12 mb-4 text-lg font-medium text-center'>
516+
<div
517+
className='h-12 mb-4 text-lg font-medium text-center'
518+
style={{ color: theme.text }}
519+
>
464520
{narration.title}
465-
<div className='text-sm text-gray-500 font-normal'>
521+
<div
522+
className='text-sm font-normal'
523+
style={{ color: `${theme.text}88` }}
524+
>
466525
{narration.description}
467526
</div>
468527
</div>
@@ -472,6 +531,7 @@ const EnumerationDemo: React.FC<EnumerationDemoProps> = ({ demoType }) => {
472531
key={i}
473532
x={50 + i * 100}
474533
y={30}
534+
style={{ fill: theme.text }}
475535
className='text-sm font-medium'
476536
textAnchor='middle'
477537
>
@@ -488,7 +548,7 @@ const EnumerationDemo: React.FC<EnumerationDemoProps> = ({ demoType }) => {
488548
y1={40}
489549
x2={100 + i * 100}
490550
y2={360}
491-
stroke='#ddd'
551+
stroke={theme.gridLines}
492552
strokeDasharray='4,4'
493553
/>
494554
))}
@@ -501,16 +561,14 @@ const EnumerationDemo: React.FC<EnumerationDemoProps> = ({ demoType }) => {
501561
cx={50 + dot.column * 100}
502562
cy={80 + i * 40}
503563
r={8}
504-
className={`
505-
${
506-
dot.skipped
507-
? 'fill-gray-300'
508-
: dot.transformed
509-
? 'fill-blue-500'
510-
: 'fill-orange-500'
511-
}
512-
transition-colors duration-500
513-
`}
564+
fill={
565+
dot.skipped
566+
? theme.gridLines
567+
: dot.transformed
568+
? theme.primary
569+
: theme.secondary
570+
}
571+
className='transition-colors duration-500'
514572
/>
515573
),
516574
)}
@@ -528,19 +586,20 @@ const EnumerationDemo: React.FC<EnumerationDemoProps> = ({ demoType }) => {
528586
cx={x}
529587
cy={y}
530588
r={radius}
531-
fill='red'
589+
fill={theme.accent}
532590
opacity={opacity}
533591
/>
534592
);
535593
})}
536594
</svg>
537595

538596
<div className='space-y-4'>
539-
{demoType ? (
540-
''
541-
) : (
597+
{!demoType && (
542598
<div className='flex items-center justify-between mb-4'>
543-
<div className='flex items-center gap-2'>
599+
<div
600+
className='flex items-center gap-2'
601+
style={{ color: theme.text }}
602+
>
544603
<span>Eager</span>
545604
<Switch
546605
checked={type === 'lazy'}
@@ -558,9 +617,7 @@ const EnumerationDemo: React.FC<EnumerationDemoProps> = ({ demoType }) => {
558617
</div>
559618
)}
560619

561-
{demoType ? (
562-
''
563-
) : (
620+
{!demoType && (
564621
<Slider
565622
value={[progress]}
566623
onValueChange={([value]) => {
@@ -577,7 +634,8 @@ const EnumerationDemo: React.FC<EnumerationDemoProps> = ({ demoType }) => {
577634
{progress < MAX_PROGRESS && (
578635
<button
579636
onClick={() => setPlaying((prev) => !prev)}
580-
className='px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600'
637+
className='px-4 py-2 rounded hover:opacity-90 transition-opacity'
638+
style={{ backgroundColor: theme.primary, color: 'white' }}
581639
>
582640
{playing ? 'Pause' : 'Play'}
583641
</button>
@@ -590,7 +648,8 @@ const EnumerationDemo: React.FC<EnumerationDemoProps> = ({ demoType }) => {
590648
setExplosions([]);
591649
processedStepsRef.current.clear();
592650
}}
593-
className='px-4 py-2 bg-gray-200 text-gray-800 rounded hover:bg-gray-300'
651+
className='px-4 py-2 rounded hover:opacity-90 transition-opacity'
652+
style={{ backgroundColor: theme.gridLines, color: theme.text }}
594653
>
595654
Reset
596655
</button>

0 commit comments

Comments
 (0)