2025-10-16 21:40:42 +08:00
|
|
|
import { useTranslation } from "react-i18next";
|
2025-11-21 23:21:34 +08:00
|
|
|
import { useState } from "react";
|
2025-10-16 21:40:42 +08:00
|
|
|
import {
|
|
|
|
|
FormControl,
|
|
|
|
|
FormField,
|
|
|
|
|
FormItem,
|
|
|
|
|
FormLabel,
|
|
|
|
|
FormMessage,
|
|
|
|
|
} from "@/components/ui/form";
|
|
|
|
|
import { Input } from "@/components/ui/input";
|
2025-11-21 23:21:34 +08:00
|
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
|
import { ArrowLeft } from "lucide-react";
|
|
|
|
|
import {
|
|
|
|
|
Dialog,
|
|
|
|
|
DialogContent,
|
|
|
|
|
DialogTrigger,
|
|
|
|
|
DialogClose,
|
|
|
|
|
} from "@/components/ui/dialog";
|
|
|
|
|
import { ProviderIcon } from "@/components/ProviderIcon";
|
|
|
|
|
import { IconPicker } from "@/components/IconPicker";
|
|
|
|
|
import { getIconMetadata } from "@/icons/extracted/metadata";
|
2025-10-16 21:40:42 +08:00
|
|
|
import type { UseFormReturn } from "react-hook-form";
|
|
|
|
|
import type { ProviderFormData } from "@/lib/schemas/provider";
|
|
|
|
|
|
|
|
|
|
interface BasicFormFieldsProps {
|
|
|
|
|
form: UseFormReturn<ProviderFormData>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function BasicFormFields({ form }: BasicFormFieldsProps) {
|
|
|
|
|
const { t } = useTranslation();
|
2025-11-21 23:21:34 +08:00
|
|
|
const [iconDialogOpen, setIconDialogOpen] = useState(false);
|
|
|
|
|
|
|
|
|
|
const currentIcon = form.watch("icon");
|
|
|
|
|
const currentIconColor = form.watch("iconColor");
|
|
|
|
|
const providerName = form.watch("name") || "Provider";
|
|
|
|
|
const effectiveIconColor =
|
|
|
|
|
currentIconColor ||
|
|
|
|
|
(currentIcon ? getIconMetadata(currentIcon)?.defaultColor : undefined);
|
|
|
|
|
|
|
|
|
|
const handleIconSelect = (icon: string) => {
|
|
|
|
|
const meta = getIconMetadata(icon);
|
|
|
|
|
form.setValue("icon", icon);
|
|
|
|
|
form.setValue("iconColor", meta?.defaultColor ?? "");
|
|
|
|
|
};
|
2025-10-16 21:40:42 +08:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
2025-11-22 01:47:00 +08:00
|
|
|
{/* 图标选择区域 - 顶部居中,可选 */}
|
|
|
|
|
<div className="flex justify-center mb-6">
|
|
|
|
|
<Dialog open={iconDialogOpen} onOpenChange={setIconDialogOpen}>
|
|
|
|
|
<DialogTrigger asChild>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
className="w-20 h-20 p-3 rounded-xl border-2 border-gray-300 dark:border-gray-600 hover:border-primary dark:hover:border-primary transition-colors cursor-pointer bg-gray-50 dark:bg-gray-800/50 flex items-center justify-center"
|
|
|
|
|
title={currentIcon ? "点击更换图标" : "点击选择图标"}
|
|
|
|
|
>
|
|
|
|
|
<ProviderIcon
|
|
|
|
|
icon={currentIcon}
|
|
|
|
|
name={providerName}
|
|
|
|
|
color={effectiveIconColor}
|
|
|
|
|
size={48}
|
|
|
|
|
/>
|
|
|
|
|
</button>
|
|
|
|
|
</DialogTrigger>
|
|
|
|
|
<DialogContent
|
|
|
|
|
variant="fullscreen"
|
|
|
|
|
zIndex="top"
|
|
|
|
|
overlayClassName="bg-[hsl(var(--background))] backdrop-blur-0"
|
|
|
|
|
className="p-0 sm:rounded-none"
|
|
|
|
|
>
|
|
|
|
|
<div className="flex h-full flex-col">
|
|
|
|
|
<div className="flex-shrink-0 px-6 py-4 flex items-center gap-4 border-b border-border-default bg-muted/40">
|
|
|
|
|
<DialogClose asChild>
|
|
|
|
|
<Button
|
|
|
|
|
type="button"
|
|
|
|
|
variant="ghost"
|
|
|
|
|
size="icon"
|
|
|
|
|
className="hover:bg-black/5 dark:hover:bg-white/5"
|
|
|
|
|
>
|
|
|
|
|
<ArrowLeft className="h-5 w-5" />
|
|
|
|
|
</Button>
|
|
|
|
|
</DialogClose>
|
2025-11-22 02:41:17 +08:00
|
|
|
<p className="text-lg font-semibold leading-tight">
|
|
|
|
|
{t("providerIcon.selectIcon", {
|
|
|
|
|
defaultValue: "选择图标",
|
|
|
|
|
})}
|
|
|
|
|
</p>
|
2025-11-22 01:47:00 +08:00
|
|
|
</div>
|
|
|
|
|
<div className="flex-1 overflow-y-auto px-6 py-6">
|
|
|
|
|
<div className="space-y-6 max-w-5xl mx-auto w-full">
|
|
|
|
|
<IconPicker
|
|
|
|
|
value={currentIcon}
|
|
|
|
|
onValueChange={handleIconSelect}
|
|
|
|
|
color={effectiveIconColor}
|
|
|
|
|
/>
|
|
|
|
|
<div className="flex justify-end gap-2">
|
|
|
|
|
<DialogClose asChild>
|
|
|
|
|
<Button type="button" variant="outline">
|
|
|
|
|
{t("common.done", { defaultValue: "完成" })}
|
|
|
|
|
</Button>
|
|
|
|
|
</DialogClose>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</DialogContent>
|
|
|
|
|
</Dialog>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 基础信息 - 网格布局 */}
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="name"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<FormLabel>{t("provider.name")}</FormLabel>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Input {...field} placeholder={t("provider.namePlaceholder")} />
|
|
|
|
|
</FormControl>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="notes"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<FormLabel>{t("provider.notes")}</FormLabel>
|
|
|
|
|
<FormControl>
|
2025-11-22 03:26:28 +08:00
|
|
|
<Input
|
|
|
|
|
{...field}
|
|
|
|
|
placeholder={t("provider.notesPlaceholder")}
|
|
|
|
|
/>
|
2025-11-22 01:47:00 +08:00
|
|
|
</FormControl>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2025-10-16 21:40:42 +08:00
|
|
|
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="websiteUrl"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
2025-10-24 13:02:35 +08:00
|
|
|
<FormLabel>{t("provider.websiteUrl")}</FormLabel>
|
2025-10-16 21:40:42 +08:00
|
|
|
<FormControl>
|
|
|
|
|
<Input {...field} placeholder="https://" />
|
|
|
|
|
</FormControl>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
}
|