Skip to content

Commit 9a048a4

Browse files
committed
add basic filter-by-tag functionality
1 parent bdac6c6 commit 9a048a4

File tree

2 files changed

+49
-3
lines changed

2 files changed

+49
-3
lines changed

src/routes/Resources/ResourcePage.tsx

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ import { useEffect, useState } from "react";
22
import { useParams } from "react-router";
33
import { JsonData, Entry } from "./types";
44
import ResourceCard from "./ResourceCard";
5-
import { sortEntries } from "./utils";
5+
import { extractTags, sortEntries } from "./utils";
66

77
const ResourcePage = () => {
88
const { category } = useParams();
99
const [data, setData] = useState<JsonData | null>(null);
1010
const [entries, setEntries] = useState<Entry[]>([]);
11+
const [tags, setTags] = useState<string[]>([]);
12+
const [filters, setFilters] = useState<string[]>([]);
1113

1214
useEffect(() => {
1315
const fetchData = async () => {
@@ -26,19 +28,54 @@ const ResourcePage = () => {
2628
if (json.entries.length > 0) {
2729
setData(json);
2830
setEntries(sortEntries(json.entries));
31+
setTags(extractTags(json.entries));
2932
}
3033
})
3134
.catch(console.error);
3235
}, [category]);
3336

37+
const filterColor = (tag: string) =>
38+
filters.includes(tag) ? "bg-slate-400" : "bg-slate-300";
39+
3440
if (data) {
3541
return (
3642
<>
37-
<section className="h-2/3 w-full bg-background">
43+
<section className="w-full bg-background">
3844
<h3 className="my-12 text-center text-4xl text-primary">
3945
{data.pageName}
4046
</h3>
41-
<div className="flex w-full justify-center">
47+
<div className="mb-6 flex w-full flex-col items-center justify-center text-center">
48+
<h4 className="text-xl font-bold text-primary">Categories</h4>
49+
<div className="mt-4 flex w-96 flex-wrap justify-center gap-2 xl:w-[600px]">
50+
{tags.map((t) => (
51+
<div
52+
key={t}
53+
onClick={() => {
54+
setFilters([...filters, t]);
55+
setEntries(entries.filter((e) => e.tags.includes(t)));
56+
}}
57+
>
58+
<button
59+
className={`rounded-xl border-transparent bg-slate-300 px-2 pb-1 ${filterColor(t)}`}
60+
>
61+
{t}
62+
</button>
63+
</div>
64+
))}
65+
{filters.length > 0 && (
66+
<button
67+
className="rounded-xl bg-accent px-2 pb-1 text-primary"
68+
onClick={() => {
69+
setFilters([]);
70+
setEntries(sortEntries(data.entries));
71+
}}
72+
>
73+
Clear filters &times;
74+
</button>
75+
)}
76+
</div>
77+
</div>
78+
<div className="flex w-full justify-center pb-12">
4279
<div className="mx-4 flex flex-wrap justify-center gap-6 sm:w-5/6 xl:w-3/4">
4380
{entries.map((e) => (
4481
<ResourceCard entry={e} key={e.title} />

src/routes/Resources/utils.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,12 @@ export const sortEntries = (entries: Entry[]) =>
55

66
const sanitize = (title: string) =>
77
title.toLowerCase().replace("the", "").trim();
8+
9+
export const extractTags = (entries: Entry[]) => [
10+
...new Set(
11+
entries.reduce<string[]>((acc, cur) => {
12+
acc.push(...cur.tags);
13+
return acc;
14+
}, []),
15+
),
16+
];

0 commit comments

Comments
 (0)