forked from TanStack/tanstack.com
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFrameworkSelect.tsx
More file actions
120 lines (113 loc) · 4.28 KB
/
FrameworkSelect.tsx
File metadata and controls
120 lines (113 loc) · 4.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import { Fragment } from 'react'
import { Listbox, Transition } from '@headlessui/react'
import { HiCheck, HiChevronDown } from 'react-icons/hi'
export type SelectOption = {
label: string
value: string
logo?: string
}
export type SelectProps<T extends SelectOption> = {
className?: string
label: string
selected: string
available: T[]
onSelect: (selected: T) => void
}
export function FrameworkSelect<T extends SelectOption>({
className = '',
label,
selected,
available,
onSelect,
}: SelectProps<T>) {
if (available.length === 0) {
return null
}
const selectedOption = available.find(({ value }) => selected === value)
if (!selectedOption) {
return null
}
return (
<div className={`top-16 w-full flex-1 ${className}`}>
<div className="text-[.8em] uppercase font-black">{label}</div>
<form
onSubmit={(e) => {
e.preventDefault()
}}
>
<Listbox name="framework" value={selectedOption} onChange={onSelect}>
<div className="relative mt-1">
<Listbox.Button className="relative items-center w-full gap-2 flex hover:bg-gray-100/70 dark:hover:bg-gray-800 cursor-default border-2 dark:border-gray-700/80 rounded-md py-2 pl-2 pr-10 text-left focus:outline-none focus-visible:border-indigo-500 sm:text-sm">
{selectedOption.logo ? (
<figure className="flex">
<img
height={18}
width={18}
src={selectedOption.logo}
alt={`${selectedOption.label} logo`}
/>
</figure>
) : null}
<span className="truncate">{selectedOption.label}</span>
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
<HiChevronDown
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</span>
</Listbox.Button>
<Transition
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options className="absolute z-10 dark:bg-gray-800 dark:border-2 border-gray-600/70 mt-1 max-h-60 w-fit overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
{Object.values(available).map((option) => (
<Listbox.Option
key={option.value}
className={({ active }) =>
`relative cursor-default select-none py-2 pr-10 ${
active
? 'bg-gray-100 dark:bg-gray-700'
: 'text-gray-900 dark:text-gray-300'
} ${option.logo ? 'pl-10' : 'pl-2'}`
}
value={option}
>
{({ selected }) => (
<>
{option.logo ? (
<figure className="absolute inset-y-0 left-0 flex items-center pl-2 text-gray-800">
<img
height={18}
width={18}
src={option.logo}
alt={`${option.label} logo`}
/>
</figure>
) : null}
<span
className={`block truncate ${
selected ? 'font-medium' : 'font-normal'
}`}
>
{option.label}
</span>
{selected ? (
<span className="absolute inset-y-0 right-0 flex items-center pr-3 text-gray-800 dark:text-gray-400">
<HiCheck className="h-5 w-5" aria-hidden="true" />
</span>
) : null}
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</div>
</Listbox>
</form>
</div>
)
}