mirror of
https://github.com/JOYCEQL/magic-resume.git
synced 2026-06-01 23:38:48 +02:00
feat: add self-evaluation section
This commit is contained in:
@@ -9,6 +9,7 @@ import ProjectPanel from "./project/ProjectPanel";
|
||||
import ExperiencePanel from "./experience/ExperiencePanel";
|
||||
import CustomPanel from "./custom/CustomPanel";
|
||||
import SkillPanel from "./skills/SkillPanel";
|
||||
import SelfEvaluationPanel from "./self-evaluation/SelfEvaluationPanel";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
@@ -34,6 +35,8 @@ export function EditPanel() {
|
||||
return <ExperiencePanel />;
|
||||
case "skills":
|
||||
return <SkillPanel />;
|
||||
case "selfEvaluation":
|
||||
return <SelfEvaluationPanel />;
|
||||
default:
|
||||
if (activeSection?.startsWith("custom")) {
|
||||
return <CustomPanel sectionId={activeSection} />;
|
||||
|
||||
@@ -104,6 +104,12 @@ export function SidePanel() {
|
||||
);
|
||||
}, [currentTemplate]);
|
||||
|
||||
// 过滤掉 menuSections 中已存在的模块,避免重复添加和 key 冲突
|
||||
const filteredModules = useMemo(() => {
|
||||
const existingIds = new Set(menuSections.map((s: MenuSection) => s.id));
|
||||
return availableModules.filter((m) => !existingIds.has(m.id));
|
||||
}, [availableModules, menuSections]);
|
||||
|
||||
const fontOptions = [
|
||||
{ value: "sans", label: t("typography.font.sans") },
|
||||
{ value: "serif", label: t("typography.font.serif") },
|
||||
@@ -180,7 +186,7 @@ export function SidePanel() {
|
||||
<PopoverContent className="w-[var(--radix-popover-trigger-width)] p-1" align="center">
|
||||
<div className="flex flex-col gap-1">
|
||||
{/* Standard Sections Library */}
|
||||
{availableModules.map((section) => (
|
||||
{filteredModules.map((section) => (
|
||||
<button
|
||||
key={section.id}
|
||||
onClick={() => {
|
||||
@@ -201,7 +207,7 @@ export function SidePanel() {
|
||||
))}
|
||||
|
||||
{/* Divider for Custom Section */}
|
||||
{availableModules.length > 0 && (
|
||||
{filteredModules.length > 0 && (
|
||||
<div className="h-px bg-border my-1" />
|
||||
)}
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { useResumeStore } from "@/store/useResumeStore";
|
||||
import { cn } from "@/lib/utils";
|
||||
import Field from "../Field";
|
||||
|
||||
const SelfEvaluationPanel = () => {
|
||||
const { activeResume, updateSelfEvaluationContent } = useResumeStore();
|
||||
const selfEvaluationContent = activeResume?.selfEvaluationContent ?? "";
|
||||
const handleChange = (value: string) => {
|
||||
updateSelfEvaluationContent(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"rounded-lg border p-4",
|
||||
"bg-card",
|
||||
"border-border"
|
||||
)}
|
||||
>
|
||||
<Field
|
||||
value={selfEvaluationContent}
|
||||
onChange={handleChange}
|
||||
type="editor"
|
||||
placeholder="描述你的自我评价..."
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelfEvaluationPanel;
|
||||
@@ -20,5 +20,5 @@ export const classicConfig: ResumeTemplate = {
|
||||
basic: {
|
||||
layout: "left",
|
||||
},
|
||||
availableSections: ["skills", "experience", "projects", "education"],
|
||||
availableSections: ["skills", "experience", "projects", "education", "selfEvaluation"],
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ import ExperienceSection from "./sections/ExperienceSection";
|
||||
import EducationSection from "./sections/EducationSection";
|
||||
import ProjectSection from "./sections/ProjectSection";
|
||||
import SkillSection from "./sections/SkillSection";
|
||||
import SelfEvaluationSection from "./sections/SelfEvaluationSection";
|
||||
import CustomSection from "./sections/CustomSection";
|
||||
|
||||
interface ClassicTemplateProps {
|
||||
@@ -29,6 +30,8 @@ const ClassicTemplate: React.FC<ClassicTemplateProps> = ({ data, template }) =>
|
||||
return <SkillSection skill={data.skillContent} globalSettings={data.globalSettings} />;
|
||||
case "projects":
|
||||
return <ProjectSection projects={data.projects} globalSettings={data.globalSettings} />;
|
||||
case "selfEvaluation":
|
||||
return <SelfEvaluationSection content={data.selfEvaluationContent} globalSettings={data.globalSettings} />;
|
||||
default:
|
||||
if (sectionId in data.customData) {
|
||||
const sectionTitle = data.menuSections.find((s) => s.id === sectionId)?.title || sectionId;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { motion } from "framer-motion";
|
||||
import SectionTitle from "./SectionTitle";
|
||||
import SectionWrapper from "../../shared/SectionWrapper";
|
||||
import { GlobalSettings } from "@/types/resume";
|
||||
import { normalizeRichTextContent } from "@/lib/richText";
|
||||
|
||||
interface SelfEvaluationSectionProps {
|
||||
content?: string;
|
||||
globalSettings?: GlobalSettings;
|
||||
showTitle?: boolean;
|
||||
}
|
||||
|
||||
const SelfEvaluationSection = ({ content, globalSettings, showTitle = true }: SelfEvaluationSectionProps) => {
|
||||
return (
|
||||
<SectionWrapper sectionId="selfEvaluation" style={{ marginTop: `${globalSettings?.sectionSpacing || 24}px` }}>
|
||||
<SectionTitle type="selfEvaluation" globalSettings={globalSettings} showTitle={showTitle} />
|
||||
<motion.div style={{ marginTop: `${globalSettings?.paragraphSpacing}px` }}>
|
||||
<motion.div className="text-baseFont" layout="position"
|
||||
style={{ fontSize: `${globalSettings?.baseFontSize || 14}px`, lineHeight: globalSettings?.lineHeight || 1.6 }}
|
||||
dangerouslySetInnerHTML={{ __html: normalizeRichTextContent(content) }}
|
||||
/>
|
||||
</motion.div>
|
||||
</SectionWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelfEvaluationSection;
|
||||
@@ -20,5 +20,5 @@ export const creativeConfig: ResumeTemplate = {
|
||||
basic: {
|
||||
layout: "left",
|
||||
},
|
||||
availableSections: ["skills", "experience", "projects", "education"],
|
||||
availableSections: ["skills", "experience", "projects", "education", "selfEvaluation"],
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ import ExperienceSection from "./sections/ExperienceSection";
|
||||
import EducationSection from "./sections/EducationSection";
|
||||
import ProjectSection from "./sections/ProjectSection";
|
||||
import SkillSection from "./sections/SkillSection";
|
||||
import SelfEvaluationSection from "./sections/SelfEvaluationSection";
|
||||
import CustomSection from "./sections/CustomSection";
|
||||
|
||||
interface CreativeTemplateProps {
|
||||
@@ -31,6 +32,8 @@ const CreativeTemplate: React.FC<CreativeTemplateProps> = ({ data, template }) =
|
||||
return <SkillSection skill={data.skillContent} globalSettings={data.globalSettings} />;
|
||||
case "projects":
|
||||
return <ProjectSection projects={data.projects} globalSettings={data.globalSettings} />;
|
||||
case "selfEvaluation":
|
||||
return <SelfEvaluationSection content={data.selfEvaluationContent} globalSettings={data.globalSettings} />;
|
||||
default:
|
||||
if (sectionId in data.customData) {
|
||||
const title = data.menuSections.find((s) => s.id === sectionId)?.title || sectionId;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { motion } from "framer-motion";
|
||||
import SectionTitle from "./SectionTitle";
|
||||
import SectionWrapper from "../../shared/SectionWrapper";
|
||||
import { GlobalSettings } from "@/types/resume";
|
||||
import { normalizeRichTextContent } from "@/lib/richText";
|
||||
|
||||
interface SelfEvaluationSectionProps {
|
||||
content?: string;
|
||||
globalSettings?: GlobalSettings;
|
||||
showTitle?: boolean;
|
||||
}
|
||||
|
||||
const SelfEvaluationSection = ({ content, globalSettings, showTitle = true }: SelfEvaluationSectionProps) => {
|
||||
return (
|
||||
<SectionWrapper sectionId="selfEvaluation" style={{ marginTop: `${globalSettings?.sectionSpacing || 24}px` }}>
|
||||
<SectionTitle type="selfEvaluation" globalSettings={globalSettings} showTitle={showTitle} />
|
||||
<motion.div style={{ marginTop: `${globalSettings?.paragraphSpacing}px` }}>
|
||||
<motion.div className="text-baseFont" layout="position"
|
||||
style={{ fontSize: `${globalSettings?.baseFontSize || 14}px`, lineHeight: globalSettings?.lineHeight || 1.6 }}
|
||||
dangerouslySetInnerHTML={{ __html: normalizeRichTextContent(content) }}
|
||||
/>
|
||||
</motion.div>
|
||||
</SectionWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelfEvaluationSection;
|
||||
@@ -20,5 +20,5 @@ export const elegantConfig: ResumeTemplate = {
|
||||
basic: {
|
||||
layout: "center",
|
||||
},
|
||||
availableSections: ["skills", "experience", "projects", "education"],
|
||||
availableSections: ["skills", "experience", "projects", "education", "selfEvaluation"],
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ import ExperienceSection from "./sections/ExperienceSection";
|
||||
import EducationSection from "./sections/EducationSection";
|
||||
import ProjectSection from "./sections/ProjectSection";
|
||||
import SkillSection from "./sections/SkillSection";
|
||||
import SelfEvaluationSection from "./sections/SelfEvaluationSection";
|
||||
import CustomSection from "./sections/CustomSection";
|
||||
|
||||
interface ElegantTemplateProps {
|
||||
@@ -29,6 +30,8 @@ const ElegantTemplate: React.FC<ElegantTemplateProps> = ({ data, template }) =>
|
||||
return <SkillSection skill={data.skillContent} globalSettings={data.globalSettings} />;
|
||||
case "projects":
|
||||
return <ProjectSection projects={data.projects} globalSettings={data.globalSettings} />;
|
||||
case "selfEvaluation":
|
||||
return <SelfEvaluationSection content={data.selfEvaluationContent} globalSettings={data.globalSettings} />;
|
||||
default:
|
||||
if (sectionId in data.customData) {
|
||||
const title = data.menuSections.find((s) => s.id === sectionId)?.title || sectionId;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { motion } from "framer-motion";
|
||||
import SectionTitle from "./SectionTitle";
|
||||
import SectionWrapper from "../../shared/SectionWrapper";
|
||||
import { GlobalSettings } from "@/types/resume";
|
||||
import { normalizeRichTextContent } from "@/lib/richText";
|
||||
|
||||
interface SelfEvaluationSectionProps {
|
||||
content?: string;
|
||||
globalSettings?: GlobalSettings;
|
||||
showTitle?: boolean;
|
||||
}
|
||||
|
||||
const SelfEvaluationSection = ({ content, globalSettings, showTitle = true }: SelfEvaluationSectionProps) => {
|
||||
return (
|
||||
<SectionWrapper sectionId="selfEvaluation" style={{ marginTop: `${globalSettings?.sectionSpacing || 24}px` }}>
|
||||
<SectionTitle type="selfEvaluation" globalSettings={globalSettings} showTitle={showTitle} />
|
||||
<motion.div style={{ marginTop: `${globalSettings?.paragraphSpacing}px` }}>
|
||||
<motion.div className="text-baseFont" layout="position"
|
||||
style={{ fontSize: `${globalSettings?.baseFontSize || 14}px`, lineHeight: globalSettings?.lineHeight || 1.6 }}
|
||||
dangerouslySetInnerHTML={{ __html: normalizeRichTextContent(content) }}
|
||||
/>
|
||||
</motion.div>
|
||||
</SectionWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelfEvaluationSection;
|
||||
@@ -20,5 +20,5 @@ export const leftRightConfig: ResumeTemplate = {
|
||||
basic: {
|
||||
layout: "left",
|
||||
},
|
||||
availableSections: ["skills", "experience", "projects", "education"],
|
||||
availableSections: ["skills", "experience", "projects", "education", "selfEvaluation"],
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ import ExperienceSection from "./sections/ExperienceSection";
|
||||
import EducationSection from "./sections/EducationSection";
|
||||
import ProjectSection from "./sections/ProjectSection";
|
||||
import SkillSection from "./sections/SkillSection";
|
||||
import SelfEvaluationSection from "./sections/SelfEvaluationSection";
|
||||
import CustomSection from "./sections/CustomSection";
|
||||
|
||||
interface LeftRightTemplateProps {
|
||||
@@ -29,6 +30,8 @@ const LeftRightTemplate: React.FC<LeftRightTemplateProps> = ({ data, template })
|
||||
return <SkillSection skill={data.skillContent} globalSettings={data.globalSettings} />;
|
||||
case "projects":
|
||||
return <ProjectSection projects={data.projects} globalSettings={data.globalSettings} />;
|
||||
case "selfEvaluation":
|
||||
return <SelfEvaluationSection content={data.selfEvaluationContent} globalSettings={data.globalSettings} />;
|
||||
default:
|
||||
if (sectionId in data.customData) {
|
||||
const title = data.menuSections.find((s) => s.id === sectionId)?.title || sectionId;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { motion } from "framer-motion";
|
||||
import SectionTitle from "./SectionTitle";
|
||||
import SectionWrapper from "../../shared/SectionWrapper";
|
||||
import { GlobalSettings } from "@/types/resume";
|
||||
import { normalizeRichTextContent } from "@/lib/richText";
|
||||
|
||||
interface SelfEvaluationSectionProps {
|
||||
content?: string;
|
||||
globalSettings?: GlobalSettings;
|
||||
showTitle?: boolean;
|
||||
}
|
||||
|
||||
const SelfEvaluationSection = ({ content, globalSettings, showTitle = true }: SelfEvaluationSectionProps) => {
|
||||
return (
|
||||
<SectionWrapper sectionId="selfEvaluation" style={{ marginTop: `${globalSettings?.sectionSpacing || 24}px` }}>
|
||||
<SectionTitle type="selfEvaluation" globalSettings={globalSettings} showTitle={showTitle} />
|
||||
<motion.div style={{ marginTop: `${globalSettings?.paragraphSpacing}px` }}>
|
||||
<motion.div className="text-baseFont" layout="position"
|
||||
style={{ fontSize: `${globalSettings?.baseFontSize || 14}px`, lineHeight: globalSettings?.lineHeight || 1.6 }}
|
||||
dangerouslySetInnerHTML={{ __html: normalizeRichTextContent(content) }}
|
||||
/>
|
||||
</motion.div>
|
||||
</SectionWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelfEvaluationSection;
|
||||
@@ -20,5 +20,5 @@ export const minimalistConfig: ResumeTemplate = {
|
||||
basic: {
|
||||
layout: "center",
|
||||
},
|
||||
availableSections: ["skills", "experience", "projects", "education"],
|
||||
availableSections: ["skills", "experience", "projects", "education", "selfEvaluation"],
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ import ExperienceSection from "./sections/ExperienceSection";
|
||||
import EducationSection from "./sections/EducationSection";
|
||||
import ProjectSection from "./sections/ProjectSection";
|
||||
import SkillSection from "./sections/SkillSection";
|
||||
import SelfEvaluationSection from "./sections/SelfEvaluationSection";
|
||||
import CustomSection from "./sections/CustomSection";
|
||||
|
||||
interface MinimalistTemplateProps {
|
||||
@@ -29,6 +30,8 @@ const MinimalistTemplate: React.FC<MinimalistTemplateProps> = ({ data, template
|
||||
return <SkillSection skill={data.skillContent} globalSettings={data.globalSettings} />;
|
||||
case "projects":
|
||||
return <ProjectSection projects={data.projects} globalSettings={data.globalSettings} />;
|
||||
case "selfEvaluation":
|
||||
return <SelfEvaluationSection content={data.selfEvaluationContent} globalSettings={data.globalSettings} />;
|
||||
default:
|
||||
if (sectionId in data.customData) {
|
||||
const title = data.menuSections.find((s) => s.id === sectionId)?.title || sectionId;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { motion } from "framer-motion";
|
||||
import SectionTitle from "./SectionTitle";
|
||||
import SectionWrapper from "../../shared/SectionWrapper";
|
||||
import { GlobalSettings } from "@/types/resume";
|
||||
import { normalizeRichTextContent } from "@/lib/richText";
|
||||
|
||||
interface SelfEvaluationSectionProps {
|
||||
content?: string;
|
||||
globalSettings?: GlobalSettings;
|
||||
showTitle?: boolean;
|
||||
}
|
||||
|
||||
const SelfEvaluationSection = ({ content, globalSettings, showTitle = true }: SelfEvaluationSectionProps) => {
|
||||
return (
|
||||
<SectionWrapper sectionId="selfEvaluation" style={{ marginTop: `${globalSettings?.sectionSpacing || 24}px` }}>
|
||||
<SectionTitle type="selfEvaluation" globalSettings={globalSettings} showTitle={showTitle} />
|
||||
<motion.div style={{ marginTop: `${globalSettings?.paragraphSpacing}px` }}>
|
||||
<motion.div className="text-baseFont" layout="position"
|
||||
style={{ fontSize: `${globalSettings?.baseFontSize || 14}px`, lineHeight: globalSettings?.lineHeight || 1.6 }}
|
||||
dangerouslySetInnerHTML={{ __html: normalizeRichTextContent(content) }}
|
||||
/>
|
||||
</motion.div>
|
||||
</SectionWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelfEvaluationSection;
|
||||
@@ -20,5 +20,5 @@ export const modernConfig: ResumeTemplate = {
|
||||
basic: {
|
||||
layout: "center",
|
||||
},
|
||||
availableSections: ["skills", "experience", "projects", "education"],
|
||||
availableSections: ["skills", "experience", "projects", "education", "selfEvaluation"],
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ import ExperienceSection from "./sections/ExperienceSection";
|
||||
import EducationSection from "./sections/EducationSection";
|
||||
import ProjectSection from "./sections/ProjectSection";
|
||||
import SkillSection from "./sections/SkillSection";
|
||||
import SelfEvaluationSection from "./sections/SelfEvaluationSection";
|
||||
import CustomSection from "./sections/CustomSection";
|
||||
|
||||
interface ModernTemplateProps {
|
||||
@@ -29,6 +30,8 @@ const ModernTemplate: React.FC<ModernTemplateProps> = ({ data, template }) => {
|
||||
return <SkillSection skill={data.skillContent} globalSettings={data.globalSettings} />;
|
||||
case "projects":
|
||||
return <ProjectSection projects={data.projects} globalSettings={data.globalSettings} />;
|
||||
case "selfEvaluation":
|
||||
return <SelfEvaluationSection content={data.selfEvaluationContent} globalSettings={data.globalSettings} />;
|
||||
default:
|
||||
if (sectionId in data.customData) {
|
||||
const title = data.menuSections.find((s) => s.id === sectionId)?.title || sectionId;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { motion } from "framer-motion";
|
||||
import SectionTitle from "./SectionTitle";
|
||||
import SectionWrapper from "../../shared/SectionWrapper";
|
||||
import { GlobalSettings } from "@/types/resume";
|
||||
import { normalizeRichTextContent } from "@/lib/richText";
|
||||
|
||||
interface SelfEvaluationSectionProps {
|
||||
content?: string;
|
||||
globalSettings?: GlobalSettings;
|
||||
showTitle?: boolean;
|
||||
}
|
||||
|
||||
const SelfEvaluationSection = ({ content, globalSettings, showTitle = true }: SelfEvaluationSectionProps) => {
|
||||
return (
|
||||
<SectionWrapper sectionId="selfEvaluation" style={{ marginTop: `${globalSettings?.sectionSpacing || 24}px` }}>
|
||||
<SectionTitle type="selfEvaluation" globalSettings={globalSettings} showTitle={showTitle} />
|
||||
<motion.div style={{ marginTop: `${globalSettings?.paragraphSpacing}px` }}>
|
||||
<motion.div className="text-baseFont" layout="position"
|
||||
style={{ fontSize: `${globalSettings?.baseFontSize || 14}px`, lineHeight: globalSettings?.lineHeight || 1.6 }}
|
||||
dangerouslySetInnerHTML={{ __html: normalizeRichTextContent(content) }}
|
||||
/>
|
||||
</motion.div>
|
||||
</SectionWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelfEvaluationSection;
|
||||
@@ -20,5 +20,5 @@ export const timelineConfig: ResumeTemplate = {
|
||||
basic: {
|
||||
layout: "right",
|
||||
},
|
||||
availableSections: ["skills", "experience", "projects", "education"],
|
||||
availableSections: ["skills", "experience", "projects", "education", "selfEvaluation"],
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ import ExperienceSection from "./sections/ExperienceSection";
|
||||
import EducationSection from "./sections/EducationSection";
|
||||
import ProjectSection from "./sections/ProjectSection";
|
||||
import SkillSection from "./sections/SkillSection";
|
||||
import SelfEvaluationSection from "./sections/SelfEvaluationSection";
|
||||
import CustomSection from "./sections/CustomSection";
|
||||
|
||||
interface TimelineTemplateProps {
|
||||
@@ -40,6 +41,8 @@ const TimelineTemplate: React.FC<TimelineTemplateProps> = ({ data, template }) =
|
||||
return <SkillSection skill={data.skillContent} globalSettings={data.globalSettings} showTitle={false} />;
|
||||
case "projects":
|
||||
return <ProjectSection projects={data.projects} globalSettings={data.globalSettings} showTitle={false} />;
|
||||
case "selfEvaluation":
|
||||
return <SelfEvaluationSection content={data.selfEvaluationContent} globalSettings={data.globalSettings} showTitle={false} />;
|
||||
default:
|
||||
if (sectionId in data.customData) {
|
||||
const title = data.menuSections.find((s) => s.id === sectionId)?.title || sectionId;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { motion } from "framer-motion";
|
||||
import SectionTitle from "./SectionTitle";
|
||||
import SectionWrapper from "../../shared/SectionWrapper";
|
||||
import { GlobalSettings } from "@/types/resume";
|
||||
import { normalizeRichTextContent } from "@/lib/richText";
|
||||
|
||||
interface SelfEvaluationSectionProps {
|
||||
content?: string;
|
||||
globalSettings?: GlobalSettings;
|
||||
showTitle?: boolean;
|
||||
}
|
||||
|
||||
const SelfEvaluationSection = ({ content, globalSettings, showTitle = true }: SelfEvaluationSectionProps) => {
|
||||
return (
|
||||
<SectionWrapper sectionId="selfEvaluation" style={{ marginTop: `${globalSettings?.sectionSpacing || 24}px` }}>
|
||||
<SectionTitle type="selfEvaluation" globalSettings={globalSettings} showTitle={showTitle} />
|
||||
<motion.div style={{ marginTop: `${globalSettings?.paragraphSpacing}px` }}>
|
||||
<motion.div className="text-baseFont" layout="position"
|
||||
style={{ fontSize: `${globalSettings?.baseFontSize || 14}px`, lineHeight: globalSettings?.lineHeight || 1.6 }}
|
||||
dangerouslySetInnerHTML={{ __html: normalizeRichTextContent(content) }}
|
||||
/>
|
||||
</motion.div>
|
||||
</SectionWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelfEvaluationSection;
|
||||
@@ -76,6 +76,7 @@ export const initialResumeState = {
|
||||
<li>技术管理:具备团队管理经验,主导过多个大型项目的技术选型和架构设计</li>
|
||||
</ul>
|
||||
</div>`,
|
||||
selfEvaluationContent: "",
|
||||
experience: [
|
||||
{
|
||||
id: "1",
|
||||
@@ -224,6 +225,7 @@ export const initialResumeStateEn = {
|
||||
<li>Technical Leadership: Team management experience, led technology selection and architecture design for large projects</li>
|
||||
</ul>
|
||||
</div>`,
|
||||
selfEvaluationContent: "",
|
||||
experience: [
|
||||
{
|
||||
id: "1",
|
||||
@@ -344,6 +346,7 @@ export const blankResumeState = {
|
||||
},
|
||||
education: [],
|
||||
skillContent: "",
|
||||
selfEvaluationContent: "",
|
||||
experience: [],
|
||||
projects: [],
|
||||
menuSections: [initialResumeState.menuSections[0]],
|
||||
@@ -366,6 +369,7 @@ export const blankResumeStateEn = {
|
||||
},
|
||||
education: [],
|
||||
skillContent: "",
|
||||
selfEvaluationContent: "",
|
||||
experience: [],
|
||||
projects: [],
|
||||
menuSections: [initialResumeStateEn.menuSections[0]],
|
||||
|
||||
@@ -9,4 +9,5 @@ export const STANDARD_MODULES: Record<string, ResumeModule> = {
|
||||
experience: { id: "experience", titleKey: "experience", icon: "💼" },
|
||||
projects: { id: "projects", titleKey: "projects", icon: "🚀" },
|
||||
education: { id: "education", titleKey: "education", icon: "🎓" },
|
||||
selfEvaluation: { id: "selfEvaluation", titleKey: "selfEvaluation", icon: "💬" },
|
||||
};
|
||||
|
||||
@@ -316,7 +316,8 @@
|
||||
"skills": "Skills",
|
||||
"experience": "Experience",
|
||||
"projects": "Projects",
|
||||
"education": "Education"
|
||||
"education": "Education",
|
||||
"selfEvaluation": "Self Evaluation"
|
||||
}
|
||||
},
|
||||
"theme": {
|
||||
|
||||
@@ -276,7 +276,8 @@
|
||||
"skills": "专业技能",
|
||||
"experience": "工作经验",
|
||||
"projects": "项目经历",
|
||||
"education": "教育经历"
|
||||
"education": "教育经历",
|
||||
"selfEvaluation": "自我评价"
|
||||
}
|
||||
},
|
||||
"theme": {
|
||||
|
||||
@@ -44,6 +44,7 @@ interface ResumeStore {
|
||||
deleteProject: (id: string) => void;
|
||||
setDraggingProjectId: (id: string | null) => void;
|
||||
updateSkillContent: (skillContent: string) => void;
|
||||
updateSelfEvaluationContent: (content: string) => void;
|
||||
reorderSections: (newOrder: ResumeData["menuSections"]) => void;
|
||||
toggleSectionVisibility: (sectionId: string) => void;
|
||||
setActiveSection: (sectionId: string) => void;
|
||||
@@ -417,6 +418,13 @@ export const useResumeStore = create(
|
||||
}
|
||||
},
|
||||
|
||||
updateSelfEvaluationContent: (selfEvaluationContent) => {
|
||||
const { activeResumeId } = get();
|
||||
if (activeResumeId) {
|
||||
get().updateResume(activeResumeId, { selfEvaluationContent });
|
||||
}
|
||||
},
|
||||
|
||||
reorderSections: (newOrder) => {
|
||||
const { activeResumeId, resumes } = get();
|
||||
if (activeResumeId) {
|
||||
|
||||
@@ -183,6 +183,7 @@ export interface ResumeData {
|
||||
projects: Project[];
|
||||
customData: Record<string, CustomItem[]>;
|
||||
skillContent: string;
|
||||
selfEvaluationContent: string;
|
||||
activeSection: string;
|
||||
draggingProjectId: string | null;
|
||||
menuSections: MenuSection[];
|
||||
|
||||
Reference in New Issue
Block a user