Skip to content

Commit 5dc711c

Browse files
feat: enhance PatternsSidebar with category filtering and improved pattern display
1 parent 9cb9b36 commit 5dc711c

1 file changed

Lines changed: 70 additions & 25 deletions

File tree

components/layout/PatternsSidebar.tsx

Lines changed: 70 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ type PatternsSidebarProps = {
1414
onSelectPattern: (pattern: Pattern) => void;
1515
};
1616

17+
type CategoryFilter = "all" | "spaceship" | "oscillator" | "still";
18+
1719
const categoryIcons = {
1820
still: Box,
1921
oscillator: Zap,
@@ -28,14 +30,24 @@ const categoryLabels = {
2830
custom: "Custom",
2931
};
3032

33+
const categoryFilters: Array<{ value: CategoryFilter; label: string }> = [
34+
{ value: "all", label: "All" },
35+
{ value: "spaceship", label: "Spaceships" },
36+
{ value: "oscillator", label: "Oscillators" },
37+
{ value: "still", label: "Still Lives" },
38+
];
39+
3140
export const PatternsSidebar = ({ onSelectPattern }: PatternsSidebarProps) => {
3241
const [search, setSearch] = useState("");
42+
const [selectedCategory, setSelectedCategory] = useState<CategoryFilter>("all");
3343

34-
const filteredPatterns = PATTERNS.filter(
35-
(p) =>
44+
const filteredPatterns = PATTERNS.filter((p) => {
45+
const matchesSearch =
3646
p.name.toLowerCase().includes(search.toLowerCase()) ||
37-
p.description.toLowerCase().includes(search.toLowerCase()),
38-
);
47+
p.description.toLowerCase().includes(search.toLowerCase());
48+
const matchesCategory = selectedCategory === "all" || p.category === selectedCategory;
49+
return matchesSearch && matchesCategory;
50+
});
3951

4052
const groupedPatterns = filteredPatterns.reduce(
4153
(acc, pattern) => {
@@ -60,33 +72,66 @@ export const PatternsSidebar = ({ onSelectPattern }: PatternsSidebarProps) => {
6072
className="pl-9 h-9 bg-background/50 border-border/50 text-sm"
6173
/>
6274
</div>
75+
<div className="mt-3 flex flex-wrap gap-2">
76+
{categoryFilters.map((category) => {
77+
const isActive = selectedCategory === category.value;
78+
79+
return (
80+
<button
81+
key={category.value}
82+
type="button"
83+
onClick={() => setSelectedCategory(category.value)}
84+
className={[
85+
"rounded-md border px-2.5 py-1 text-xs font-medium transition-colors",
86+
isActive
87+
? "border-primary/40 bg-primary/15 text-primary"
88+
: "border-border/60 bg-background/40 text-muted-foreground hover:bg-accent/60",
89+
].join(" ")}
90+
>
91+
{category.label}
92+
</button>
93+
);
94+
})}
95+
</div>
6396
</div>
6497

6598
{/* Patterns List */}
6699
<ScrollArea className="flex-1">
67100
<div className="p-3 space-y-4">
68-
{Object.entries(groupedPatterns).map(([category, patterns]) => {
69-
const Icon = categoryIcons[category as keyof typeof categoryIcons];
70-
return (
71-
<div key={category}>
72-
<div className="flex items-center gap-2 px-2 mb-2">
73-
<Icon className="h-3.5 w-3.5 text-muted-foreground" />
74-
<span className="text-xs font-medium text-muted-foreground uppercase tracking-wide">
75-
{categoryLabels[category as keyof typeof categoryLabels]}
76-
</span>
77-
</div>
78-
<div className="space-y-1">
79-
{patterns.map((pattern) => (
80-
<PatternItem
81-
key={pattern.id}
82-
pattern={pattern}
83-
onSelect={() => onSelectPattern(pattern)}
84-
/>
85-
))}
101+
{selectedCategory === "all" ? (
102+
Object.entries(groupedPatterns).map(([category, patterns]) => {
103+
const Icon = categoryIcons[category as keyof typeof categoryIcons];
104+
return (
105+
<div key={category}>
106+
<div className="flex items-center gap-2 px-2 mb-2">
107+
<Icon className="h-3.5 w-3.5 text-muted-foreground" />
108+
<span className="text-xs font-medium text-muted-foreground uppercase tracking-wide">
109+
{categoryLabels[category as keyof typeof categoryLabels]}
110+
</span>
111+
</div>
112+
<div className="space-y-1">
113+
{patterns.map((pattern) => (
114+
<PatternItem
115+
key={pattern.id}
116+
pattern={pattern}
117+
onSelect={() => onSelectPattern(pattern)}
118+
/>
119+
))}
120+
</div>
86121
</div>
87-
</div>
88-
);
89-
})}
122+
);
123+
})
124+
) : (
125+
<div className="space-y-1">
126+
{filteredPatterns.map((pattern) => (
127+
<PatternItem
128+
key={pattern.id}
129+
pattern={pattern}
130+
onSelect={() => onSelectPattern(pattern)}
131+
/>
132+
))}
133+
</div>
134+
)}
90135

91136
{filteredPatterns.length === 0 && (
92137
<div className="text-center py-8 text-muted-foreground text-sm">No patterns found</div>

0 commit comments

Comments
 (0)