111 lines
4.7 KiB
TypeScript
111 lines
4.7 KiB
TypeScript
/*
|
|
This example requires some changes to your config:
|
|
|
|
```
|
|
// tailwind.config.js
|
|
module.exports = {
|
|
// ...
|
|
plugins: [
|
|
// ...
|
|
require('@tailwindcss/forms'),
|
|
],
|
|
}
|
|
```
|
|
*/
|
|
import {useMemo, useState} from 'react'
|
|
import {CheckIcon, ChevronUpDownIcon} from '@heroicons/react/20/solid'
|
|
import {Combobox} from '@headlessui/react'
|
|
import {useQuery} from "@tanstack/react-query";
|
|
|
|
function classNames(...classes: any[]) {
|
|
return classes.filter(Boolean).join(' ')
|
|
}
|
|
|
|
export default function Example() {
|
|
const {data: options} = useQuery({
|
|
queryKey: ['obsidian-metadata'],
|
|
initialData: [],
|
|
queryFn: async () => {
|
|
const response = await fetch("http://100.115.154.44:9002/metadata")
|
|
const fullData: any[] = await response.json();
|
|
|
|
return fullData.map(md => ({
|
|
id: md.relativePath,
|
|
name: md.fileName
|
|
}));
|
|
},
|
|
});
|
|
|
|
const [query, setQuery] = useState('')
|
|
const [selectedPerson, setSelectedPerson] = useState(null)
|
|
|
|
const filteredOptions =
|
|
useMemo(() => {
|
|
return query === ''
|
|
? options
|
|
: options.filter((option) => {
|
|
return option.name.toLowerCase().includes(query.toLowerCase())
|
|
})
|
|
}, [query, options])
|
|
|
|
return (
|
|
<Combobox as="div" value={selectedPerson} onChange={setSelectedPerson}>
|
|
<Combobox.Label className="block text-sm font-medium leading-6 text-gray-900">Assigned to</Combobox.Label>
|
|
<div className="relative mt-2">
|
|
<Combobox.Input
|
|
className="w-full rounded-md border-0 bg-white py-1.5 pl-3 pr-12 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
|
onChange={(event) => setQuery(event.target.value)}
|
|
displayValue={(person: (typeof filteredOptions)[number]) => person?.name}
|
|
/>
|
|
<Combobox.Button className="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none">
|
|
<ChevronUpDownIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
|
</Combobox.Button>
|
|
|
|
{filteredOptions.length > 0 && (
|
|
<Combobox.Options className="absolute z-10 mt-1 max-h-60 w-full 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">
|
|
{filteredOptions.map((person) => (
|
|
<Combobox.Option
|
|
key={person.id}
|
|
value={person}
|
|
className={({ active }) =>
|
|
classNames(
|
|
'relative cursor-default select-none py-2 pl-3 pr-9',
|
|
active ? 'bg-indigo-600 text-white' : 'text-gray-900'
|
|
)
|
|
}
|
|
>
|
|
{({ active, selected }) => (
|
|
<>
|
|
<div className="flex">
|
|
<span className={classNames('truncate', selected && 'font-semibold')}>{person.name}</span>
|
|
<span
|
|
className={classNames(
|
|
'ml-2 truncate text-gray-500',
|
|
active ? 'text-indigo-200' : 'text-gray-500'
|
|
)}
|
|
>
|
|
{person.id}
|
|
</span>
|
|
</div>
|
|
|
|
{selected && (
|
|
<span
|
|
className={classNames(
|
|
'absolute inset-y-0 right-0 flex items-center pr-4',
|
|
active ? 'text-white' : 'text-indigo-600'
|
|
)}
|
|
>
|
|
<CheckIcon className="h-5 w-5" aria-hidden="true" />
|
|
</span>
|
|
)}
|
|
</>
|
|
)}
|
|
</Combobox.Option>
|
|
))}
|
|
</Combobox.Options>
|
|
)}
|
|
</div>
|
|
</Combobox>
|
|
)
|
|
}
|