import React, { useState } from "react"; import { PlusCircle, X, User, Briefcase, Calendar, Mail, Phone, MapPin, FileText, Smartphone, Globe, Github, GripVertical, Trash2, LucideIcon } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Switch } from "@/components/ui/switch"; import { Label } from "@/components/ui/label"; import Field from "../Field"; import { useResumeStore } from "@/store/useResumeStore"; import { cn } from "@/lib/utils"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { motion, Reorder } from "framer-motion"; type IconOption = { label: string; value: string; icon: LucideIcon; }; type CustomFieldType = { id: string; label: string; value: string; icon: string; }; type Theme = "dark" | "light"; interface IconSelectorProps { value: string; onChange: (value: string) => void; theme: Theme; } interface CustomFieldProps { field: CustomFieldType; onUpdate: (field: CustomFieldType) => void; onDelete: (id: string) => void; theme: Theme; } interface BasicInfo { name?: string; title?: string; birthDate?: string; email?: string; phone?: string; location?: string; summary?: string; employed?: boolean; customFields?: CustomFieldType[]; icons?: Record; } const iconOptions: IconOption[] = [ { label: "用户", value: "User", icon: User }, { label: "工作", value: "Briefcase", icon: Briefcase }, { label: "日期", value: "Calendar", icon: Calendar }, { label: "邮箱", value: "Mail", icon: Mail }, { label: "电话", value: "Phone", icon: Phone }, { label: "地址", value: "MapPin", icon: MapPin }, { label: "简介", value: "FileText", icon: FileText }, { label: "手机", value: "Smartphone", icon: Smartphone }, { label: "网站", value: "Globe", icon: Globe }, { label: "Github", value: "Github", icon: Github } ]; const IconSelector: React.FC = ({ value, onChange, theme }) => { const [open, setOpen] = React.useState(false); const selectedIcon = iconOptions.find((i) => i.value === value) || iconOptions[0]; const Icon = selectedIcon.icon; const handleSelect = (iconValue: string) => { onChange(iconValue); setOpen(false); }; return ( {iconOptions.map(({ value: iconValue, icon: Icon, label }) => ( ))} ); }; const CustomField: React.FC = ({ field, onUpdate, onDelete, theme }) => { return (
onUpdate({ ...field, icon: value })} theme={theme} /> onUpdate({ ...field, label: value })} placeholder="字段名称" /> onUpdate({ ...field, value })} placeholder="字段内容" /> onDelete(field.id)} size={26} className={cn( "p-1.5 rounded-md cursor-pointer", theme === "dark" ? "text-red-400 hover:text-red-300" : "text-red-500 hover:text-red-600" )} />
); }; const BasicPanel: React.FC = () => { const { basic, updateBasicInfo, theme } = useResumeStore(); const [fields, setFields] = useState( basic?.customFields || [] ); const addCustomField = () => { const fieldToAdd: CustomFieldType = { id: crypto.randomUUID(), label: "", value: "", icon: "User" }; const updatedFields = [...fields, fieldToAdd]; setFields(updatedFields); updateBasicInfo({ ...basic, customFields: updatedFields }); }; const updateField = (updatedField: CustomFieldType) => { const updatedFields = fields.map((field) => field.id === updatedField.id ? updatedField : field ); setFields(updatedFields); updateBasicInfo({ ...basic, customFields: updatedFields }); }; const deleteField = (id: string) => { const updatedFields = fields.filter((field) => field.id !== id); setFields(updatedFields); updateBasicInfo({ ...basic, customFields: updatedFields }); }; const handleReorder = (newOrder: CustomFieldType[]) => { setFields(newOrder); updateBasicInfo({ ...basic, customFields: newOrder }); }; const renderField = ( key: keyof BasicInfo, label: string, options: { type?: "date" | "textarea" | "text" | "editor" | undefined; isCustom?: boolean; field?: CustomFieldType | null; } = {} ) => { const { type = "text", isCustom = false, field = null } = options; const selectedIcon = basic?.icons?.[key] || "User"; return (
{ updateBasicInfo({ ...basic, icons: { ...(basic?.icons || {}), [key]: value } }); }} theme={theme} /> {label}
isCustom && field ? updateField({ ...field, value }) : updateBasicInfo({ ...basic, [key]: value }) } placeholder={`请输入${label}`} type={type} />
); }; return (
{renderField("name", "姓名")}
updateBasicInfo({ ...basic, employed: checked }) } className={cn( theme === "dark" ? "bg-neutral-700" : "bg-neutral-200", "data-[state=checked]:bg-green-500" )} />
{renderField("title", "职位")} {renderField("birthDate", "出生日期", { type: "date" })}
{renderField("email", "电子邮箱")} {renderField("phone", "电话")}
{renderField("location", "所在地")} {renderField("summary", "个人简介", { type: "textarea" })} {/* 自定义字段 */}
{Array.isArray(fields) && fields.map((field) => ( ))} {/* 添加按钮 */}
); }; export default BasicPanel;