Skip to content

Commit 1fb7903

Browse files
committed
pr feedback
1 parent 0167a9e commit 1fb7903

2 files changed

Lines changed: 113 additions & 34 deletions

File tree

Lines changed: 109 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1-
import { Select, type SelectOption } from '~/components/Select'
1+
import { Check, ChevronsUpDown } from 'lucide-react'
2+
import { twMerge } from 'tailwind-merge'
3+
import {
4+
Dropdown,
5+
DropdownContent,
6+
DropdownItem,
7+
DropdownSeparator,
8+
DropdownTrigger,
9+
} from '~/components/Dropdown'
210
import { findMaintainerByAuthorName } from '~/utils/authors'
311
import authorFallbackAvatar from '~/images/author-fallback.svg'
412

5-
const ALL_AUTHORS_VALUE = 'all'
6-
713
function getAuthorAvatar(name: string): string {
814
return findMaintainerByAuthorName(name)?.avatar ?? authorFallbackAvatar
915
}
@@ -21,37 +27,107 @@ export function BlogAuthorFilter({
2127
onSelect,
2228
className,
2329
}: BlogAuthorFilterProps) {
24-
const available: SelectOption[] = [
25-
{ label: 'All authors', value: ALL_AUTHORS_VALUE },
26-
...authors.map((name) => ({
27-
label: name,
28-
value: name,
29-
logo: getAuthorAvatar(name),
30-
})),
31-
]
32-
33-
// If the URL has an author that isn't in the post list, surface it anyway
34-
// so the trigger renders and the user can still reset to "All authors".
35-
if (
36-
selected &&
37-
selected !== ALL_AUTHORS_VALUE &&
38-
!authors.includes(selected)
39-
) {
40-
available.push({
41-
label: selected,
42-
value: selected,
43-
logo: getAuthorAvatar(selected),
44-
})
45-
}
30+
// Ignore URL values that don't correspond to a real author in the list.
31+
const activeAuthor =
32+
selected && authors.includes(selected) ? selected : undefined
4633

4734
return (
48-
<Select
49-
className={className}
50-
selected={selected ?? ALL_AUTHORS_VALUE}
51-
available={available}
52-
onSelect={(option) =>
53-
onSelect(option.value === ALL_AUTHORS_VALUE ? undefined : option.value)
54-
}
55-
/>
35+
<div className={twMerge('w-full', className)}>
36+
<Dropdown>
37+
<DropdownTrigger>
38+
<button
39+
type="button"
40+
className={twMerge(
41+
'relative w-full flex items-center gap-2 rounded-md py-1.5 px-2 text-left text-sm cursor-pointer transition-colors',
42+
'focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500',
43+
activeAuthor
44+
? 'bg-blue-50 dark:bg-blue-950/40 ring-1 ring-blue-500/50 text-blue-700 dark:text-blue-200'
45+
: 'hover:bg-gray-500/10',
46+
)}
47+
>
48+
<span
49+
className={twMerge(
50+
'flex items-center justify-center w-6 h-6 rounded border overflow-hidden flex-shrink-0',
51+
activeAuthor ? 'border-blue-500/30' : 'border-gray-500/20',
52+
)}
53+
>
54+
<img
55+
height={20}
56+
width={20}
57+
src={
58+
activeAuthor
59+
? getAuthorAvatar(activeAuthor)
60+
: authorFallbackAvatar
61+
}
62+
alt=""
63+
className="w-full h-full object-cover"
64+
/>
65+
</span>
66+
<span className="truncate font-medium flex-1">
67+
{activeAuthor ?? 'All authors'}
68+
</span>
69+
<span className="flex items-center pr-1">
70+
<ChevronsUpDown
71+
className="h-4 w-4 opacity-40"
72+
aria-hidden="true"
73+
/>
74+
</span>
75+
</button>
76+
</DropdownTrigger>
77+
<DropdownContent
78+
align="start"
79+
className="max-h-80 overflow-auto min-w-[16rem]"
80+
>
81+
<DropdownItem
82+
onSelect={() => onSelect(undefined)}
83+
className={twMerge(
84+
'pr-8 relative',
85+
!activeAuthor
86+
? 'bg-blue-50 dark:bg-blue-900/30 text-blue-700 dark:text-blue-200 font-medium'
87+
: 'font-normal',
88+
)}
89+
>
90+
<span className="truncate">All authors</span>
91+
{!activeAuthor ? (
92+
<Check
93+
className="h-4 w-4 absolute right-2 text-blue-600 dark:text-blue-300"
94+
aria-hidden="true"
95+
/>
96+
) : null}
97+
</DropdownItem>
98+
{authors.length > 0 ? <DropdownSeparator /> : null}
99+
{authors.map((name) => {
100+
const isSelected = activeAuthor === name
101+
return (
102+
<DropdownItem
103+
key={name}
104+
onSelect={() => onSelect(name)}
105+
className={twMerge(
106+
'pr-8 pl-2 relative',
107+
isSelected
108+
? 'bg-blue-50 dark:bg-blue-900/30 text-blue-700 dark:text-blue-200 font-medium'
109+
: 'font-normal',
110+
)}
111+
>
112+
<img
113+
height={20}
114+
width={20}
115+
src={getAuthorAvatar(name)}
116+
alt=""
117+
className="w-5 h-5 rounded object-cover flex-shrink-0"
118+
/>
119+
<span className="truncate">{name}</span>
120+
{isSelected ? (
121+
<Check
122+
className="h-4 w-4 absolute right-2 text-blue-600 dark:text-blue-300"
123+
aria-hidden="true"
124+
/>
125+
) : null}
126+
</DropdownItem>
127+
)
128+
})}
129+
</DropdownContent>
130+
</Dropdown>
131+
</div>
56132
)
57133
}

src/libraries/maintainers.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ export const allMaintainers: Maintainer[] = [
3838
'ranger',
3939
'store',
4040
'pacer',
41+
'cli',
4142
'mcp',
4243
'react-charts',
4344
],
45+
maintainerOf: ['intent'],
4446
frameworkExpertise: ['react', 'solid'],
4547
specialties: ['Architecture', 'Core API', 'Documentation'],
4648
social: {
@@ -162,7 +164,7 @@ export const allMaintainers: Maintainer[] = [
162164
isCoreMaintainer: true,
163165
avatar: 'https://github.com/KyleAMathews.png',
164166
github: 'KyleAMathews',
165-
creatorOf: ['db'],
167+
creatorOf: ['db', 'intent'],
166168
frameworkExpertise: ['react'],
167169
specialties: ['Sync Engines'],
168170
},
@@ -306,6 +308,7 @@ export const allMaintainers: Maintainer[] = [
306308
name: 'Sarah Gerrard',
307309
avatar: 'https://github.com/ladybluenotes.png',
308310
github: 'ladybluenotes',
311+
creatorOf: ['intent'],
309312
contributorOf: [
310313
'ai',
311314
'config',

0 commit comments

Comments
 (0)