Skip to content
This repository was archived by the owner on May 20, 2025. It is now read-only.

Commit a02d383

Browse files
committed
filter guides by tag
1 parent bd295f9 commit a02d383

File tree

3 files changed

+72
-20
lines changed

3 files changed

+72
-20
lines changed

src/components/guides/GuideList.tsx

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
1+
'use client'
2+
13
import { Doc } from '@/content'
24
import React from 'react'
3-
import { Separator } from '../ui/separator'
4-
import Link from 'next/link'
5-
import { cn } from '@/lib/utils'
6-
import { title } from 'radash'
75
import GuideItem from './GuideItem'
86
import { Checkbox } from '../ui/checkbox'
7+
import useParams from '@/hooks/useParams'
98

109
interface Props {
1110
guides: Doc[]
1211
allTags: string[]
1312
}
1413

1514
const GuideList: React.FC<Props> = ({ guides, allTags }) => {
16-
allTags = ['python', 'node', 'go']
15+
const { searchParams, setParams } = useParams()
16+
const selectedTags = searchParams.get('tags')?.split(',') || []
17+
18+
const filteredGuides = guides.filter((guide) => {
19+
if (!selectedTags.length) return true
20+
return selectedTags.some((tag) => guide.tags?.includes(tag))
21+
})
1722

1823
return (
1924
<div className="mt-10 grid grid-cols-[280px,1fr]">
@@ -25,21 +30,37 @@ const GuideList: React.FC<Props> = ({ guides, allTags }) => {
2530
{allTags.map((tag) => (
2631
<li key={tag}>
2732
<div className="flex items-center space-x-4">
28-
<Checkbox id={tag} />
33+
<Checkbox
34+
id={tag}
35+
checked={selectedTags.includes(tag)}
36+
onCheckedChange={(checked) => {
37+
if (checked) {
38+
setParams('tags', [...selectedTags, tag].join(','))
39+
} else {
40+
setParams(
41+
'tags',
42+
selectedTags
43+
.filter((selectedTag) => selectedTag !== tag)
44+
.join(','),
45+
)
46+
}
47+
}}
48+
className="h-5 w-5 border-primary-400 data-[state=checked]:bg-primary"
49+
/>
2950
<label
3051
htmlFor={tag}
31-
className="cursor-pointer text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
52+
className="cursor-pointer text-base font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
3253
>
33-
{title(tag)}
54+
{tag}
3455
</label>
3556
</div>
3657
</li>
3758
))}
3859
</ul>
3960
</aside>
4061
<ul className="space-y-4">
41-
{guides.map((guide) => (
42-
<li key={guide.title}>
62+
{filteredGuides.map((guide) => (
63+
<li key={guide.slug}>
4364
<GuideItem guide={guide} />
4465
</li>
4566
))}

src/hooks/useLang.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { useSearchParams } from 'next/navigation'
22
import { useCallback, useEffect } from 'react'
3+
import useParams from './useParams'
4+
import { set } from 'node_modules/cypress/types/lodash'
35

46
export type LanguageId =
57
| 'javascript'
@@ -28,7 +30,7 @@ const languages = ['javascript', 'python', 'go', 'typescript', 'dart']
2830
const LOCAL_STORAGE_KEY = 'nitric.docs.selected.language'
2931

3032
const useLang = () => {
31-
const searchParams = useSearchParams() || new URLSearchParams()
33+
const { searchParams, setParams } = useParams()
3234

3335
const queryParamLang = searchParams.get('lang') as LanguageId
3436

@@ -45,17 +47,10 @@ const useLang = () => {
4547
)
4648

4749
if (!id) {
48-
currentParams.delete('lang')
50+
setParams('lang', null)
4951
} else {
50-
currentParams.set('lang', id)
51-
}
52-
53-
const search = currentParams.toString()
54-
const query = search ? `?${search}` : ''
55-
56-
window.history.pushState(null, '', query)
52+
setParams('lang', id)
5753

58-
if (query) {
5954
// set language in local storage
6055
try {
6156
localStorage.setItem(LOCAL_STORAGE_KEY, id)

src/hooks/useParams.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { usePathname, useSearchParams } from 'next/navigation'
2+
import { useCallback } from 'react'
3+
4+
const useParams = () => {
5+
const searchParams = useSearchParams()
6+
const pathname = usePathname()
7+
8+
const setParams = useCallback(
9+
(name: string, value: string | null) => {
10+
// Apparently this nonsense is necessary to update the URL.
11+
// See: https://github.com/vercel/next.js/discussions/47583
12+
const currentParams = new URLSearchParams(
13+
Array.from(searchParams.entries()),
14+
)
15+
16+
if (!value) {
17+
currentParams.delete(name)
18+
} else {
19+
currentParams.set(name, value)
20+
}
21+
22+
const search = currentParams.toString()
23+
const url = search ? `/docs${pathname}?${search}` : `/docs${pathname}`
24+
25+
window.history.pushState(null, '', url)
26+
},
27+
[searchParams, pathname],
28+
)
29+
30+
return {
31+
setParams,
32+
searchParams,
33+
}
34+
}
35+
36+
export default useParams

0 commit comments

Comments
 (0)