feat: categories autocomplete

This commit is contained in:
DIYgod 2024-05-15 16:23:15 +08:00
parent 87b952dd20
commit f82f695bae
No known key found for this signature in database
4 changed files with 115 additions and 3 deletions

View File

@ -10,7 +10,6 @@ import {
FormMessage,
FormDescription,
} from "@renderer/components/ui/form"
import { Input } from "@renderer/components/ui/input"
import { useMutation, useQueryClient } from "@tanstack/react-query"
import {
DialogContent,
@ -31,6 +30,8 @@ import { Switch } from "@renderer/components/ui/switch"
import { FollowSummary } from "../feed-summary"
import { apiFetch } from "@renderer/lib/queries/api-fetch"
import { SubscriptionResponse } from "@renderer/lib/types"
import { AutoComplete } from "@renderer/components/ui/autocomplete"
import { useSubscriptionCategories } from "@renderer/lib/queries/subscriptions"
const formSchema = z.object({
view: z.string(),
@ -96,6 +97,8 @@ export function FollowDialog({
followMutation.mutate(values)
}
const categories = useSubscriptionCategories(parseInt(form.watch("view")))
return (
<DialogContent>
<DialogHeader>
@ -148,7 +151,11 @@ export function FollowDialog({
</FormDescription>
</div>
<FormControl>
<Input {...field} />
<AutoComplete
options={categories.data}
emptyMessage="No resulsts."
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>

View File

@ -0,0 +1,88 @@
import {
Command,
CommandGroup,
CommandItem,
CommandList,
CommandInput,
} from "@renderer/components/ui/command"
import { useState, useCallback } from "react"
import { cn } from "@renderer/lib/utils"
import * as React from "react"
export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {
options: string[]
emptyMessage: string
value?: string
}
export const AutoComplete = React.forwardRef<HTMLInputElement, InputProps>(
({ options, emptyMessage, className, value, ...props }, ref) => {
const [open, setOpen] = useState(false)
const onValueChange = useCallback(
(value: string) => {
props.onChange?.({
target: {
value,
},
} as React.ChangeEvent<HTMLInputElement>)
},
[props.onChange],
)
const handleSelectOption = useCallback(
(option: string) => {
setOpen(false)
onValueChange(option)
},
[props.onChange],
)
return (
<Command className="rounded-lg border overflow-visible relative [&_[cmdk-input-wrapper]]:border-0 [&_.lucide-search]:hidden">
<CommandInput
{...props}
onBlur={(e) => {
setOpen(false)
props.onBlur?.(e)
}}
onFocus={(e) => {
setOpen(true)
props.onFocus?.(e)
}}
value={value}
onValueChange={(value) => {
setOpen(true)
onValueChange(value)
}}
ref={ref}
/>
<CommandList>
<CommandGroup
className={cn(
"absolute top-full bg-white w-full z-10 border rounded-lg mt-1 hidden [&[hidden]]:!hidden",
open && "block",
)}
>
{options.map((option) => (
<CommandItem
key={option}
value={option}
onSelect={() => handleSelectOption(option)}
className="text-zinc-800"
onMouseDown={(event) => {
event.preventDefault()
event.stopPropagation()
}}
>
{option}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
)
},
)

View File

@ -115,7 +115,7 @@ const CommandItem = React.forwardRef<
<CommandPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground",
className,
)}
{...props}

View File

@ -88,3 +88,20 @@ export const useSubscriptions = (view?: number) =>
} as Response
},
})
export const useSubscriptionCategories = (view?: number) =>
useQuery({
queryKey: ["subscription-categories", view],
queryFn: async () => {
const { data: categories } = await apiFetch<{
code: number
data: string[]
}>("/subscriptions/categories", {
query: {
view,
},
})
return categories || []
},
})