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

Commit 2d75038

Browse files
committed
add sorting options and updates to styling
1 parent 9add972 commit 2d75038

File tree

4 files changed

+98
-30
lines changed

4 files changed

+98
-30
lines changed

src/components/guides/GuideItem.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ export const GuideItem: React.FC<Props> = ({ guide, featured }) => {
2121
>
2222
<div className="flex flex-col gap-y-4">
2323
<div>
24+
<time
25+
dateTime={guide.published_at}
26+
className="absolute right-0 top-0 m-3 text-2xs text-muted-foreground"
27+
>
28+
{new Date(guide.published_at).toLocaleDateString('en-US', {
29+
year: 'numeric',
30+
month: 'short',
31+
day: 'numeric',
32+
})}
33+
</time>
2434
<p
2535
className={cn(
2636
'font-display text-xl font-semibold',

src/components/guides/GuideList.tsx

Lines changed: 73 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,64 @@
11
'use client'
22

3-
import React from 'react'
3+
import React, { useMemo } from 'react'
44
import { GuideItem } from './GuideItem'
55
import { cn } from '@/lib/utils'
66
import useParams from '@/hooks/useParams'
77
import type { Guide } from '@/content'
8+
import {
9+
Select,
10+
SelectContent,
11+
SelectItem,
12+
SelectTrigger,
13+
SelectValue,
14+
} from '../ui/select'
815

916
interface Props {
1017
className?: string
1118
allGuides: Guide[]
1219
}
1320

1421
const GuideList: React.FC<Props> = ({ className, allGuides }) => {
15-
const { searchParams } = useParams()
22+
const { searchParams, setParams } = useParams()
23+
const sortBy = searchParams?.get('sort') || 'published_date'
1624
const selectedTags = searchParams?.get('tags')?.split(',') || []
1725
const selectedLangs = searchParams?.get('langs')?.split(',') || []
1826

19-
const filteredGuides = allGuides
20-
.filter((guide) => {
21-
let include = true
27+
const filteredGuides = useMemo(() => {
28+
return allGuides
29+
.filter((guide) => {
30+
let include = true
2231

23-
if (selectedLangs.length) {
24-
include = selectedLangs.some((lang) => guide.languages?.includes(lang))
25-
}
32+
if (selectedLangs.length) {
33+
include = selectedLangs.some((lang) =>
34+
guide.languages?.includes(lang),
35+
)
36+
}
2637

27-
if (!selectedTags.length) return include
38+
if (!selectedTags.length) return include
2839

29-
return include && selectedTags.some((tag) => guide.tags?.includes(tag))
30-
})
31-
.sort((a, b) => a.title.localeCompare(b.title))
40+
return include && selectedTags.some((tag) => guide.tags?.includes(tag))
41+
})
42+
.sort((a, b) => {
43+
if (sortBy === 'published_date') {
44+
const dateDiff =
45+
new Date(b.published_at).getTime() -
46+
new Date(a.published_at).getTime()
47+
48+
return dateDiff !== 0 ? dateDiff : a.title.localeCompare(b.title)
49+
} else if (sortBy === 'last_updated') {
50+
const dateDiff =
51+
new Date(b.updated_at || b.published_at).getTime() -
52+
new Date(a.updated_at || a.published_at).getTime()
53+
54+
return dateDiff !== 0 ? dateDiff : a.title.localeCompare(b.title)
55+
}
56+
57+
return sortBy === 'alpha-reverse'
58+
? b.title.localeCompare(a.title)
59+
: a.title.localeCompare(b.title)
60+
})
61+
}, [allGuides, selectedTags, selectedLangs, sortBy])
3262

3363
return filteredGuides.length === 0 ? (
3464
<div className={className}>
@@ -37,13 +67,37 @@ const GuideList: React.FC<Props> = ({ className, allGuides }) => {
3767
</p>
3868
</div>
3969
) : (
40-
<ul className={cn('space-y-4', className)}>
41-
{filteredGuides.map((guide) => (
42-
<li key={guide.slug}>
43-
<GuideItem guide={guide} />
44-
</li>
45-
))}
46-
</ul>
70+
<div className={cn('flex flex-col gap-4', className)}>
71+
<Select
72+
value={sortBy}
73+
onValueChange={(val) => {
74+
// This is necessary to fix a ui update delay causing 200ms lag
75+
setTimeout(() => setParams('sort', val), 0)
76+
}}
77+
>
78+
<SelectTrigger
79+
aria-label="Sort options"
80+
className="ml-auto max-w-52 bg-white/5 text-xs font-medium ring-1 ring-inset ring-zinc-300/10 hover:bg-white/7.5 dark:bg-white/2.5 dark:text-zinc-400 dark:hover:bg-white/5 md:flex"
81+
>
82+
<SelectValue />
83+
</SelectTrigger>
84+
<SelectContent position="item-aligned">
85+
<SelectItem value="published_date">Sort by Date Published</SelectItem>
86+
<SelectItem value="last_updated">Sort by Last Updated</SelectItem>
87+
<SelectItem value="alpha">Sort Alphabetically (A-Z)</SelectItem>
88+
<SelectItem value="alpha-reverse">
89+
Sort Alphabetically (Z-A)
90+
</SelectItem>
91+
</SelectContent>
92+
</Select>
93+
<ul className={'space-y-4'}>
94+
{filteredGuides.map((guide) => (
95+
<li key={guide.slug}>
96+
<GuideItem guide={guide} />
97+
</li>
98+
))}
99+
</ul>
100+
</div>
47101
)
48102
}
49103

src/components/guides/GuidePage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const GuidePage: React.FC<Props> = ({ allTags }) => {
2626
<Suspense>
2727
<GuideList
2828
allGuides={allGuides}
29-
className="relative mx-2 my-4 w-full sm:px-8 lg:my-10"
29+
className="relative mx-2 my-4 w-full sm:px-8 lg:mb-8"
3030
/>
3131
</Suspense>
3232
</div>

src/components/guides/GuidesFeatured.tsx

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,7 @@ const GuidesFeatured: React.FC = ({ take = 3 }: { take?: number }) => {
1313
const featuredGuides = allGuides
1414
.filter((guide): guide is RequiredFeaturedGuide => !!guide.featured)
1515
.sort((a, b) => {
16-
if (a.published_at && b.published_at) {
17-
return a.published_at > b.published_at ? -1 : 1
18-
}
19-
20-
return 0
16+
return a.published_at > b.published_at ? -1 : 1
2117
})
2218
.slice(0, take)
2319

@@ -30,7 +26,7 @@ const GuidesFeatured: React.FC = ({ take = 3 }: { take?: number }) => {
3026
{featuredGuides.map((guide) => (
3127
<article
3228
key={guide.slug}
33-
className="group relative isolate flex flex-col justify-end overflow-hidden rounded-lg bg-zinc-900 px-8 pb-8 pt-48"
29+
className="group relative isolate flex flex-col justify-end overflow-hidden rounded-lg bg-zinc-900 px-8 pb-8 pt-60"
3430
>
3531
<Image
3632
alt={guide.featured.image_alt}
@@ -40,16 +36,24 @@ const GuidesFeatured: React.FC = ({ take = 3 }: { take?: number }) => {
4036
priority
4137
className="absolute inset-0 -z-10 h-full w-full object-cover"
4238
/>
43-
<div className="absolute inset-0 -z-10 bg-gradient-to-t from-primary-300/50 via-secondary-400/30 to-primary-500/40 dark:from-primary-700/50 dark:via-secondary-800/40 dark:to-primary-900/50" />
39+
<div className="absolute inset-0 -z-10 bg-gradient-to-t from-primary-400/60 via-secondary-400/30 to-primary-500/40 dark:from-primary-800/60 dark:via-secondary-800/20 dark:to-primary-900/50" />
4440
<div className="absolute inset-0 -z-10 rounded-2xl ring-1 ring-inset ring-primary-500/10 dark:ring-primary-900/10" />
45-
46-
<h3 className="mt-3 text-lg/6 font-semibold tracking-wide text-white">
41+
<time
42+
dateTime={guide.published_at}
43+
className="absolute left-0 top-0 m-4 text-2xs text-zinc-300 dark:text-muted-foreground"
44+
>
45+
{new Date(guide.published_at).toLocaleDateString('en-US', {
46+
month: 'short',
47+
day: 'numeric',
48+
})}
49+
</time>
50+
<h3 className="mt-4 text-lg/6 font-semibold tracking-wide text-white">
4751
<Link href={`/${guide.slug}`}>
4852
<span className="absolute inset-0" />
4953
{guide.title}
5054
</Link>
5155
</h3>
52-
<p className="mt-1 text-base leading-5 text-white dark:text-muted-foreground">
56+
<p className="mt-1 text-sm leading-5 text-white dark:text-muted-foreground">
5357
{guide.description}
5458
</p>
5559
<ArrowUpRightIcon

0 commit comments

Comments
 (0)