Skip to content

Commit 1493fb7

Browse files
authored
Puzzle feedback improvements (#21)
- added a better tutorial - change the order of some components on mobile
1 parent b53b030 commit 1493fb7

21 files changed

+730
-316
lines changed

frontend/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<html lang="en">
33
<head>
44
<meta charset="UTF-8" />
5-
<link rel="icon" type="image/x-icon" href="favicon.ico" />
5+
<link rel="icon" type="image/x-icon" href="/favicon.png" />
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
77
<title>Linera Game of Life</title>
88

frontend/public/favicon.png

4.75 KB
Loading

frontend/public/next.svg

Lines changed: 0 additions & 1 deletion
This file was deleted.

frontend/public/vercel.svg

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { DifficultyLevel, formatDifficulty } from "@/lib/types/puzzle.types";
2+
import { difficultyConfig } from "@/lib/game-of-life/config/difficulty-config";
3+
4+
interface DifficultyBadgeProps {
5+
difficulty: DifficultyLevel;
6+
size?: "sm" | "md" | "lg";
7+
showText?: boolean;
8+
}
9+
10+
export function DifficultyBadge({
11+
difficulty,
12+
size = "md",
13+
showText = true
14+
}: DifficultyBadgeProps) {
15+
const config = difficultyConfig[difficulty];
16+
17+
const sizeClasses = {
18+
sm: "px-1.5 py-0.5 text-xs gap-1",
19+
md: "px-2 py-1 text-sm gap-1.5",
20+
lg: "px-3 py-1.5 text-base gap-2",
21+
};
22+
23+
const iconSizeClasses = {
24+
sm: "text-xs",
25+
md: "text-sm",
26+
lg: "text-base",
27+
};
28+
29+
return (
30+
<span
31+
className={`
32+
inline-flex items-center rounded-full font-medium
33+
${config.bgColor} ${config.textColor} ${config.borderColor}
34+
${sizeClasses[size]}
35+
border
36+
`}
37+
>
38+
<span className={iconSizeClasses[size]}>{config.icon}</span>
39+
{showText && <span>{formatDifficulty(difficulty)}</span>}
40+
</span>
41+
);
42+
}
Lines changed: 84 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
import { Button } from "@heroui/button";
2-
import { Play, Pause, ChevronRight, ChevronLeft, Lightbulb, Target } from "lucide-react";
2+
import {
3+
Play,
4+
Pause,
5+
ChevronRight,
6+
ChevronLeft,
7+
Lightbulb,
8+
Target,
9+
RotateCcw,
10+
Trash2,
11+
} from "lucide-react";
312
import { Tooltip } from "@heroui/tooltip";
413

514
interface GameControlsProps {
@@ -10,13 +19,12 @@ interface GameControlsProps {
1019
onNext: () => void;
1120
onPrevious: () => void;
1221
onClear: () => void;
22+
onResetToInitial: () => void;
1323
showHints?: boolean;
1424
showGoals?: boolean;
1525
onToggleHints?: () => void;
1626
onToggleGoals?: () => void;
1727
hasConditions?: boolean;
18-
minSteps?: number;
19-
maxSteps?: number;
2028
}
2129

2230
export function GameControls({
@@ -27,95 +35,93 @@ export function GameControls({
2735
onNext,
2836
onPrevious,
2937
onClear,
38+
onResetToInitial,
3039
showHints = false,
3140
showGoals = false,
3241
onToggleHints,
3342
onToggleGoals,
3443
hasConditions = false,
35-
minSteps,
36-
maxSteps,
3744
}: GameControlsProps) {
38-
const hasStepRequirement = minSteps !== undefined && maxSteps !== undefined;
39-
4045
return (
4146
<div className="flex flex-col items-center gap-4">
42-
<div className="flex gap-6 items-center">
43-
<button
44-
onClick={onPrevious}
45-
disabled={!canUndo}
46-
className="w-12 h-12 rounded-full bg-gray-200 hover:bg-gray-300 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center transition-colors"
47-
>
48-
<ChevronLeft size={24} className="text-gray-600" />
49-
</button>
50-
<button
51-
onClick={isPlaying ? onPause : onPlay}
52-
className="w-16 h-16 rounded-full bg-linera-primary hover:bg-linera-primary-dark text-white flex items-center justify-center transition-colors shadow-lg"
53-
>
54-
{isPlaying ? (
55-
<Pause size={28} className="fill-white" />
56-
) : (
57-
<Play size={28} className="ml-1 fill-white" />
58-
)}
59-
</button>
60-
<button
61-
onClick={onNext}
62-
className="w-12 h-12 rounded-full bg-gray-200 hover:bg-gray-300 flex items-center justify-center transition-colors"
63-
>
64-
<ChevronRight size={24} className="text-gray-600" />
65-
</button>
66-
</div>
6747
<div className="flex gap-3 items-center">
48+
<Tooltip content="Previous generation">
49+
<button
50+
onClick={onPrevious}
51+
disabled={!canUndo}
52+
className="w-10 h-10 rounded-full bg-gray-200 hover:bg-gray-300 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center transition-colors"
53+
>
54+
<ChevronLeft className="w-5 h-5 text-gray-600" />
55+
</button>
56+
</Tooltip>
57+
<Tooltip content={isPlaying ? "Pause" : "Play"}>
58+
<button
59+
onClick={isPlaying ? onPause : onPlay}
60+
className="p-3 rounded-full bg-linera-primary hover:bg-linera-primary-dark text-white transition-colors shadow-lg"
61+
>
62+
{isPlaying ? (
63+
<Pause className="w-5 h-5 fill-white" />
64+
) : (
65+
<Play className="w-5 h-5 ml-0.5 fill-white" />
66+
)}
67+
</button>
68+
</Tooltip>
69+
<Tooltip content="Next generation">
70+
<button
71+
onClick={onNext}
72+
className="w-10 h-10 rounded-full bg-gray-200 hover:bg-gray-300 flex items-center justify-center transition-colors"
73+
>
74+
<ChevronRight className="w-5 h-5 text-gray-600" />
75+
</button>
76+
</Tooltip>
77+
<div className="w-px h-8 bg-gray-300 mx-2" /> {/* Divider */}
78+
<Tooltip content="Reset to generation 0">
79+
<button
80+
onClick={onResetToInitial}
81+
className="w-10 h-10 rounded-full bg-gray-200 hover:bg-gray-300 flex items-center justify-center transition-colors"
82+
>
83+
<RotateCcw className="w-5 h-5 text-gray-600" />
84+
</button>
85+
</Tooltip>
86+
<Tooltip content="Clear all cells">
87+
<button
88+
onClick={onClear}
89+
className="w-10 h-10 rounded-full bg-gray-200 hover:bg-gray-300 flex items-center justify-center transition-colors"
90+
>
91+
<Trash2 className="w-5 h-5 text-gray-600" />
92+
</button>
93+
</Tooltip>
94+
</div>
95+
<div className="flex gap-3 items-center flex-wrap justify-center">
6896
{hasConditions && (
6997
<>
70-
<Tooltip content="Show starting position hints">
71-
<button
72-
onClick={onToggleHints}
73-
className={`w-12 h-12 rounded-full flex items-center justify-center transition-colors ${
74-
showHints
75-
? "bg-green-500 text-white"
76-
: "bg-gray-200 hover:bg-gray-300 text-gray-600"
77-
}`}
78-
>
79-
<Lightbulb size={20} />
80-
</button>
81-
</Tooltip>
82-
<Tooltip content="Show goal pattern">
83-
<button
84-
onClick={onToggleGoals}
85-
className={`w-12 h-12 rounded-full flex items-center justify-center transition-colors ${
86-
showGoals
87-
? "bg-blue-500 text-white"
88-
: "bg-gray-200 hover:bg-gray-300 text-gray-600"
89-
}`}
90-
>
91-
<Target size={20} />
92-
</button>
93-
</Tooltip>
98+
<Button
99+
variant="flat"
100+
onPress={onToggleHints}
101+
className={`font-medium text-xs sm:text-base px-4 py-2 sm:px-6 sm:py-2.5 min-w-[120px] sm:min-w-[140px] rounded-full transition-colors flex items-center gap-2 ${
102+
showHints
103+
? "bg-green-500 text-white hover:bg-green-600"
104+
: "bg-gray-200 hover:bg-gray-300 text-gray-700"
105+
}`}
106+
>
107+
<Lightbulb className="w-4 h-4 sm:w-5 sm:h-5" />
108+
Show Hints
109+
</Button>
110+
<Button
111+
variant="flat"
112+
onPress={onToggleGoals}
113+
className={`font-medium text-xs sm:text-base px-4 py-2 sm:px-6 sm:py-2.5 min-w-[120px] sm:min-w-[140px] rounded-full transition-colors flex items-center gap-2 ${
114+
showGoals
115+
? "bg-blue-500 text-white hover:bg-blue-600"
116+
: "bg-gray-200 hover:bg-gray-300 text-gray-700"
117+
}`}
118+
>
119+
<Target className="w-4 h-4 sm:w-5 sm:h-5" />
120+
Show Goal
121+
</Button>
94122
</>
95123
)}
96-
<Button
97-
variant="flat"
98-
onPress={onClear}
99-
className="bg-gray-200 hover:bg-gray-300 text-gray-700 font-medium text-lg px-8 min-w-[120px] rounded-full"
100-
>
101-
Clear
102-
</Button>
103124
</div>
104-
{hasStepRequirement && (
105-
<div className="mt-2 text-center">
106-
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-gray-50 border border-gray-200">
107-
<span className="text-lg">🎯</span>
108-
<span className="text-sm font-medium text-gray-700">
109-
{minSteps === maxSteps
110-
? `Reach goal pattern in exactly ${minSteps} step${minSteps !== 1 ? "s" : ""}`
111-
: `Reach goal pattern in ${minSteps}-${maxSteps} steps`}
112-
</span>
113-
</div>
114-
<div className="text-xs text-gray-500 mt-1">
115-
Each step = 1 generation of the Game of Life
116-
</div>
117-
</div>
118-
)}
119125
</div>
120126
);
121127
}

0 commit comments

Comments
 (0)