NamH 86e693b250
refactor: model plugin to follow new specs (#682)
* refactor: model plugin to follow new specs

Signed-off-by: James <james@jan.ai>

* chore: rebase main

chore: rebase main

---------

Signed-off-by: James <james@jan.ai>
Co-authored-by: James <james@jan.ai>
Co-authored-by: Louis <louis@jan.ai>
2023-11-29 11:36:59 +07:00

105 lines
3.7 KiB
TypeScript

import { Fragment, useEffect, useState } from 'react'
import { Listbox, Transition } from '@headlessui/react'
import { CheckIcon, ChevronUpDownIcon } from '@heroicons/react/20/solid'
import { Model } from '@janhq/core/lib/types'
import { atom, useSetAtom } from 'jotai'
import { twMerge } from 'tailwind-merge'
import { getDownloadedModels } from '@/hooks/useGetDownloadedModels'
export const selectedModelAtom = atom<Model | undefined>(undefined)
export default function DropdownListSidebar() {
const [downloadedModels, setDownloadedModels] = useState<Model[]>([])
const [selected, setSelected] = useState<Model | undefined>()
const setSelectedModel = useSetAtom(selectedModelAtom)
useEffect(() => {
getDownloadedModels().then((downloadedModels) => {
setDownloadedModels(downloadedModels)
if (downloadedModels.length > 0) {
setSelected(downloadedModels[0])
setSelectedModel(downloadedModels[0])
}
})
}, [])
if (!selected) return null
return (
<Listbox
value={selected}
onChange={(model) => {
setSelected(model)
setSelectedModel(model)
}}
>
{({ open }) => (
<>
<div className="relative mt-2">
<Listbox.Button className="relative w-full cursor-default rounded-md bg-white py-1.5 pl-3 pr-10 text-left text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-600 sm:text-sm sm:leading-6">
<span className="block truncate">{selected.name}</span>
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
<ChevronUpDownIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</span>
</Listbox.Button>
<Transition
show={open}
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.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">
{downloadedModels.map((model) => (
<Listbox.Option
key={model.id}
className={({ active }) =>
twMerge(
active ? 'bg-indigo-600 text-white' : 'text-gray-900',
'relative cursor-default select-none py-2 pl-3 pr-9'
)
}
value={model}
>
{({ selected, active }) => (
<>
<span
className={twMerge(
selected ? 'font-semibold' : 'font-normal',
'block truncate'
)}
>
{model.name}
</span>
{selected ? (
<span
className={twMerge(
active ? 'text-white' : 'text-indigo-600',
'absolute inset-y-0 right-0 flex items-center pr-4'
)}
>
<CheckIcon className="h-5 w-5" aria-hidden="true" />
</span>
) : null}
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</div>
</>
)}
</Listbox>
)
}