mirror of
https://github.com/JOYCEQL/magic-resume.git
synced 2026-07-03 14:07:11 +02:00
perf: delete editor save button
This commit is contained in:
@@ -26,7 +26,7 @@ import {
|
||||
|
||||
interface EducationEditorProps {
|
||||
education: Education;
|
||||
onSave: (educaton: Education) => void;
|
||||
onSave: (education: Education) => void;
|
||||
onDelete: () => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
@@ -40,41 +40,28 @@ const EducationEditor: React.FC<EducationEditorProps> = ({
|
||||
education,
|
||||
onSave
|
||||
}) => {
|
||||
const theme = useResumeStore((state) => state.theme);
|
||||
const [data, setData] = useState<Education>(education);
|
||||
|
||||
const handleSave = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (
|
||||
!data.school ||
|
||||
!data.major ||
|
||||
!data.degree ||
|
||||
!data.startDate ||
|
||||
!data.endDate
|
||||
)
|
||||
return;
|
||||
onSave(data);
|
||||
const handleChange = (field: keyof Education, value: string) => {
|
||||
onSave({
|
||||
...education,
|
||||
[field]: value
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSave} className="space-y-5">
|
||||
<div className="space-y-5">
|
||||
<div className="grid gap-5">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<Field
|
||||
label="学校名称"
|
||||
value={data.school}
|
||||
onChange={(value) =>
|
||||
setData((prev) => ({ ...prev, school: value }))
|
||||
}
|
||||
value={education.school}
|
||||
onChange={(value) => handleChange("school", value)}
|
||||
placeholder="学校名称"
|
||||
required
|
||||
/>
|
||||
<Field
|
||||
label="所在地"
|
||||
value={data.location || ""}
|
||||
onChange={(value) =>
|
||||
setData((prev) => ({ ...prev, location: value }))
|
||||
}
|
||||
value={education.location || ""}
|
||||
onChange={(value) => handleChange("location", value)}
|
||||
placeholder="城市"
|
||||
/>
|
||||
</div>
|
||||
@@ -82,40 +69,33 @@ const EducationEditor: React.FC<EducationEditorProps> = ({
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<Field
|
||||
label="专业"
|
||||
value={data.major}
|
||||
onChange={(value) => setData((prev) => ({ ...prev, major: value }))}
|
||||
value={education.major}
|
||||
onChange={(value) => handleChange("major", value)}
|
||||
placeholder="专业名称"
|
||||
required
|
||||
/>
|
||||
<Field
|
||||
label="学历"
|
||||
value={data.degree}
|
||||
onChange={(value) =>
|
||||
setData((prev) => ({ ...prev, degree: value }))
|
||||
}
|
||||
value={education.degree}
|
||||
onChange={(value) => handleChange("degree", value)}
|
||||
placeholder="学历"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 时间和GPA */}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<Field
|
||||
label="开始时间"
|
||||
value={data.startDate}
|
||||
onChange={(value) =>
|
||||
setData((prev) => ({ ...prev, startDate: value }))
|
||||
}
|
||||
value={education.startDate}
|
||||
onChange={(value) => handleChange("startDate", value)}
|
||||
type="date"
|
||||
placeholder="YYYY-MM"
|
||||
required
|
||||
/>
|
||||
<Field
|
||||
label="结束时间"
|
||||
value={data.endDate}
|
||||
onChange={(value) =>
|
||||
setData((prev) => ({ ...prev, endDate: value }))
|
||||
}
|
||||
value={education.endDate}
|
||||
onChange={(value) => handleChange("endDate", value)}
|
||||
type="date"
|
||||
placeholder="YYYY-MM"
|
||||
required
|
||||
@@ -124,37 +104,20 @@ const EducationEditor: React.FC<EducationEditorProps> = ({
|
||||
|
||||
<Field
|
||||
label="GPA"
|
||||
value={data.gpa || ""}
|
||||
onChange={(value) => setData((prev) => ({ ...prev, gpa: value }))}
|
||||
value={education.gpa || ""}
|
||||
onChange={(value) => handleChange("gpa", value)}
|
||||
placeholder="选填"
|
||||
/>
|
||||
|
||||
{/* 在校经历描述 */}
|
||||
<Field
|
||||
label="在校经历"
|
||||
value={data.description}
|
||||
onChange={(value) =>
|
||||
setData((prev) => ({ ...prev, description: value }))
|
||||
}
|
||||
value={education.description}
|
||||
onChange={(value) => handleChange("description", value)}
|
||||
type="editor"
|
||||
placeholder="描述你的在校表现、获奖经历等..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end gap-2 pt-2">
|
||||
<Button
|
||||
type="submit"
|
||||
size="sm"
|
||||
className={cn(
|
||||
theme === "dark"
|
||||
? "bg-indigo-600 hover:bg-indigo-700 text-white"
|
||||
: "bg-black hover:bg-neutral-800 text-white"
|
||||
)}
|
||||
>
|
||||
保存修改
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -271,7 +234,6 @@ const EducationItem = ({ education }: { education: Education }) => {
|
||||
"dark:hover:border-indigo-600"
|
||||
)}
|
||||
>
|
||||
{/* 拖拽手柄区域 */}
|
||||
<div
|
||||
onPointerDown={(event) => {
|
||||
if (expandedId === education.id) return;
|
||||
@@ -295,7 +257,6 @@ const EducationItem = ({ education }: { education: Education }) => {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 内容区域 */}
|
||||
<div className="flex-1 min-w-0">
|
||||
<div
|
||||
className={cn(
|
||||
@@ -407,10 +368,7 @@ const EducationItem = ({ education }: { education: Education }) => {
|
||||
/>
|
||||
<EducationEditor
|
||||
education={education}
|
||||
onSave={(updatedEducation) => {
|
||||
updateEducation(updatedEducation);
|
||||
setExpandedId(null);
|
||||
}}
|
||||
onSave={updateEducation}
|
||||
onDelete={() => {
|
||||
deleteEducation(education.id);
|
||||
setExpandedId(null);
|
||||
|
||||
@@ -114,67 +114,48 @@ const ProjectEditor: React.FC<ProjectEditorProps> = ({
|
||||
experience,
|
||||
onSave
|
||||
}) => {
|
||||
const theme = useResumeStore((state) => state.theme);
|
||||
const [data, setData] = useState<Experience>(experience);
|
||||
|
||||
const handleSave = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (!data.company || !data.position || !data.date) return;
|
||||
onSave(data);
|
||||
const handleChange = (field: keyof Experience, value: string) => {
|
||||
onSave({
|
||||
...experience,
|
||||
[field]: value
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSave} className="space-y-5">
|
||||
<div className="space-y-5">
|
||||
<div className="grid gap-5">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<Field
|
||||
label="公司名称"
|
||||
value={data.company}
|
||||
onChange={(value) =>
|
||||
setData((prev) => ({ ...prev, company: value }))
|
||||
}
|
||||
value={experience.company}
|
||||
onChange={(value) => handleChange("company", value)}
|
||||
placeholder="项目名称"
|
||||
required
|
||||
/>
|
||||
<Field
|
||||
label="岗位"
|
||||
value={data.position}
|
||||
onChange={(value) =>
|
||||
setData((prev) => ({ ...prev, position: value }))
|
||||
}
|
||||
value={experience.position}
|
||||
onChange={(value) => handleChange("position", value)}
|
||||
placeholder="如:前端工程师"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<Field
|
||||
label="开始时间-结束时间"
|
||||
value={data.date}
|
||||
onChange={(value) => setData((prev) => ({ ...prev, date: value }))}
|
||||
value={experience.date}
|
||||
onChange={(value) => handleChange("date", value)}
|
||||
placeholder="如:2023.01 - 2023.06"
|
||||
required
|
||||
/>
|
||||
<Field
|
||||
label="主要职责"
|
||||
value={data.details}
|
||||
onChange={(value) => setData((prev) => ({ ...prev, details: value }))}
|
||||
value={experience.details}
|
||||
onChange={(value) => handleChange("details", value)}
|
||||
type="editor"
|
||||
placeholder="简要描述项目的背景和目标..."
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-end gap-2 pt-2">
|
||||
<Button
|
||||
type="submit"
|
||||
size="sm"
|
||||
className={cn(
|
||||
theme === "dark"
|
||||
? "bg-indigo-600 hover:bg-indigo-700 text-white"
|
||||
: "bg-black hover:bg-neutral-800 text-white"
|
||||
)}
|
||||
>
|
||||
保存修改
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -219,7 +200,6 @@ const ExperienceItem = ({ experience }: { experience: Experience }) => {
|
||||
"dark:hover:border-indigo-600"
|
||||
)}
|
||||
>
|
||||
{/* 拖拽手柄区域 */}
|
||||
<div
|
||||
onPointerDown={(event) => {
|
||||
if (expandedId === experience.id) return;
|
||||
@@ -250,7 +230,6 @@ const ExperienceItem = ({ experience }: { experience: Experience }) => {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 内容区域 */}
|
||||
<div className="flex-1 min-w-0">
|
||||
<div
|
||||
className={cn(
|
||||
@@ -346,10 +325,7 @@ const ExperienceItem = ({ experience }: { experience: Experience }) => {
|
||||
/>
|
||||
<ProjectEditor
|
||||
experience={experience}
|
||||
onSave={(updatedData) => {
|
||||
updateExperience(updatedData);
|
||||
setExpandedId(null);
|
||||
}}
|
||||
onSave={updateExperience}
|
||||
onDelete={() => {
|
||||
deleteExperience(experience.id);
|
||||
setExpandedId(null);
|
||||
|
||||
@@ -122,65 +122,69 @@ const DeleteConfirmDialog: React.FC<DeleteConfirmDialogProps> = ({
|
||||
};
|
||||
|
||||
const ProjectEditor: React.FC<ProjectEditorProps> = ({ project, onSave }) => {
|
||||
const theme = useResumeStore((state) => state.theme);
|
||||
const [data, setData] = useState<Project>(project);
|
||||
|
||||
const handleSave = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (!data.name || !data.role || !data.date) return;
|
||||
onSave(data);
|
||||
const handleChange = (field: keyof Project, value: string) => {
|
||||
onSave({
|
||||
...project,
|
||||
[field]: value
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSave} className="space-y-5">
|
||||
<div className="space-y-5">
|
||||
<div className="grid gap-5">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<Field
|
||||
label="项目名称"
|
||||
value={data.name}
|
||||
onChange={(value) => setData((prev) => ({ ...prev, name: value }))}
|
||||
value={project.name}
|
||||
onChange={(value) => handleChange("name", value)}
|
||||
placeholder="项目名称"
|
||||
required
|
||||
/>
|
||||
<Field
|
||||
label="担任角色"
|
||||
value={data.role}
|
||||
onChange={(value) => setData((prev) => ({ ...prev, role: value }))}
|
||||
value={project.role}
|
||||
onChange={(value) => handleChange("role", value)}
|
||||
placeholder="如:前端负责人"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<Field
|
||||
label="项目时间"
|
||||
value={data.date}
|
||||
onChange={(value) => setData((prev) => ({ ...prev, date: value }))}
|
||||
value={project.date}
|
||||
onChange={(value) => handleChange("date", value)}
|
||||
placeholder="如:2023.01 - 2023.06"
|
||||
required
|
||||
/>
|
||||
<Field
|
||||
label="项目描述"
|
||||
value={data.description}
|
||||
onChange={(value) =>
|
||||
setData((prev) => ({ ...prev, description: value }))
|
||||
}
|
||||
value={project.description}
|
||||
onChange={(value) => handleChange("description", value)}
|
||||
type="editor"
|
||||
placeholder="简要描述项目的背景和目标..."
|
||||
/>
|
||||
<Field
|
||||
label="技术栈"
|
||||
value={project.technologies}
|
||||
onChange={(value) => handleChange("technologies", value)}
|
||||
type="editor"
|
||||
placeholder="使用的技术栈和工具..."
|
||||
/>
|
||||
<Field
|
||||
label="主要职责"
|
||||
value={project.responsibilities}
|
||||
onChange={(value) => handleChange("responsibilities", value)}
|
||||
type="editor"
|
||||
placeholder="在项目中的主要职责..."
|
||||
/>
|
||||
<Field
|
||||
label="项目成果"
|
||||
value={project.achievements}
|
||||
onChange={(value) => handleChange("achievements", value)}
|
||||
type="editor"
|
||||
placeholder="项目取得的成果..."
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-end gap-2 pt-2">
|
||||
<Button
|
||||
type="submit"
|
||||
size="sm"
|
||||
className={cn(
|
||||
theme === "dark"
|
||||
? "bg-indigo-600 hover:bg-indigo-700 text-white"
|
||||
: "bg-black hover:bg-neutral-800 text-white"
|
||||
)}
|
||||
>
|
||||
保存修改
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -353,7 +357,6 @@ const ProjectItem = ({ project }: { project: Project }) => {
|
||||
project={project}
|
||||
onSave={(updatedProject) => {
|
||||
updateProjects(updatedProject);
|
||||
setExpandedId(null);
|
||||
}}
|
||||
onDelete={() => {
|
||||
deleteProject(project.id);
|
||||
|
||||
@@ -62,15 +62,14 @@ export function ExperienceSection({
|
||||
{exp.date}
|
||||
</span>
|
||||
</div>
|
||||
<p
|
||||
<div
|
||||
className="text-gray-600"
|
||||
style={{
|
||||
fontSize: `${globalSettings?.baseFontSize || 14}px`,
|
||||
lineHeight: globalSettings?.lineHeight || 1.6
|
||||
}}
|
||||
>
|
||||
{exp.details}
|
||||
</p>
|
||||
dangerouslySetInnerHTML={{ __html: exp.details }}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user