diff --git a/src/components/SelectOptions.tsx b/src/components/SelectOptions.tsx new file mode 100644 index 000000000..5d507d9f3 --- /dev/null +++ b/src/components/SelectOptions.tsx @@ -0,0 +1,117 @@ +import { createSignal, createEffect, on, Show, For } from "solid-js" +import { + hope, + useSelectContext, + SelectTrigger, + SelectPlaceholder, + SelectValue, + SelectIcon, + Input, + SelectContent, + SelectListbox, + SelectOption, + SelectOptionText, + SelectOptionIndicator, +} from "@hope-ui/solid" +import { BsSearch } from "solid-icons/bs" +import { useT } from "~/hooks" + +interface SelectOptionsProps { + options: { key: string; label: string }[] + searchable?: boolean + readonly?: boolean +} + +const SearchIcon = hope(BsSearch, { baseStyle: { color: "$neutral11" } }) + +export const SelectOptions = (props: SelectOptionsProps) => { + const t = useT() + const selectContext = useSelectContext() + + const [searching, setSearching] = createSignal(false) + const [displayValue, setDisplayValue] = createSignal("") + + let tid: ReturnType + + const displayOptions = () => { + if (!props.searchable) return props.options + return props.options.filter((o) => + new RegExp(displayValue(), "i").test(o.label), + ) + } + + const selectedLabel = () => + selectContext.state.selectedOptions.map((o) => o.textValue).join(",") + + createEffect(on(selectedLabel, setDisplayValue)) + + return ( + <> + + + {t("global.choose")} + + + + } + when={!props.readonly && props.searchable} + > + e.stopPropagation()} + onClick={(e) => { + if (!selectContext.state.opened) return + e.stopPropagation() + }} + onInput={(e) => { + clearTimeout(tid) + setDisplayValue(e.currentTarget.value) + }} + onBlur={() => { + setSearching(false) + tid = setTimeout( + () => setDisplayValue(""), + 300 /* transition duration of */, + ) + }} + onFocus={() => { + clearTimeout(tid) + setDisplayValue("") + setSearching(true) + }} + /> + }> + + + + + + + + {(item) => ( + + {item.label} + + + )} + + + + + ) +} diff --git a/src/components/index.ts b/src/components/index.ts index 937b46a75..c24d1b03b 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -13,3 +13,4 @@ export * from "./Base" export * from "./Paginator" export * from "./icons" export * from "./EncodingSelect" +export * from "./SelectOptions" diff --git a/src/pages/manage/storages/AddOrEdit.tsx b/src/pages/manage/storages/AddOrEdit.tsx index b5950a06a..8f1010643 100644 --- a/src/pages/manage/storages/AddOrEdit.tsx +++ b/src/pages/manage/storages/AddOrEdit.tsx @@ -106,6 +106,7 @@ const AddOrEdit = () => { default="" readonly={id !== undefined} required + searchable type={Type.Select} options={id ? storage.driver : Object.keys(drivers()).join(",")} value={storage.driver} diff --git a/src/pages/manage/storages/Item.tsx b/src/pages/manage/storages/Item.tsx index 953689a43..9c648b488 100644 --- a/src/pages/manage/storages/Item.tsx +++ b/src/pages/manage/storages/Item.tsx @@ -5,21 +5,13 @@ import { FormLabel, Input, Select, - SelectContent, - SelectIcon, - SelectListbox, - SelectOption, - SelectOptionIndicator, - SelectOptionText, - SelectPlaceholder, - SelectTrigger, - SelectValue, Switch as HopeSwitch, Textarea, } from "@hope-ui/solid" -import { For, Match, Show, Switch } from "solid-js" +import { Match, Show, Switch } from "solid-js" import { useT } from "~/hooks" import { DriverItem, Type } from "~/types" +import { SelectOptions } from "~/components" export type ItemProps = DriverItem & { readonly?: boolean @@ -38,7 +30,13 @@ export type ItemProps = DriverItem & { value: number } | { - type: Type.String | Type.Text | Type.Select + type: Type.String | Type.Text + onChange?: (value: string) => void + value: string + } + | { + type: Type.Select + searchable?: boolean onChange?: (value: string) => void value: string } @@ -122,31 +120,19 @@ const Item = (props: ItemProps) => { : undefined } > - - {t("global.choose")} - - - - - - - {(item) => ( - - - {t( - (props.options_prefix ?? - (props.driver === "common" - ? `storages.common.${props.name}s` - : `drivers.${props.driver}.${props.name}s`)) + - `.${item}`, - )} - - - - )} - - - + ({ + key, + label: t( + (props.options_prefix ?? + (props.driver === "common" + ? `storages.common.${props.name}s` + : `drivers.${props.driver}.${props.name}s`)) + `.${key}`, + ), + }))} + />