diff --git a/apps/fronted/src/app/workbench/compoents/Editor/RichText.tsx b/apps/fronted/src/app/workbench/compoents/Editor/RichText.tsx
index cb5d443..2500f0d 100644
--- a/apps/fronted/src/app/workbench/compoents/Editor/RichText.tsx
+++ b/apps/fronted/src/app/workbench/compoents/Editor/RichText.tsx
@@ -584,7 +584,7 @@ const RichTextEditor = ({
{/* Bubble Menu */}
- {editor && (
+ {/* {editor && (
- )}
+ )} */}
);
};
diff --git a/apps/fronted/src/components/editor/PdfExport.tsx b/apps/fronted/src/components/PdfExport.tsx
similarity index 100%
rename from apps/fronted/src/components/editor/PdfExport.tsx
rename to apps/fronted/src/components/PdfExport.tsx
diff --git a/apps/fronted/src/components/editor/EditPanel.tsx b/apps/fronted/src/components/editor/EditPanel.tsx
index cabfa43..2fa0ade 100644
--- a/apps/fronted/src/components/editor/EditPanel.tsx
+++ b/apps/fronted/src/components/editor/EditPanel.tsx
@@ -9,6 +9,7 @@ import EducationPanel from "./education/EducationPanel";
import ProjectPanel from "./project/ProjectPanel";
import ExperiencePanel from "./experience/ExperiencePanel";
import CustomPanel from "./custom/CustomPanel";
+import SkillPanel from "./skills/SkillPanel";
export function EditPanel() {
const { theme, activeSection, menuSections } = useResumeStore();
@@ -25,7 +26,7 @@ export function EditPanel() {
case "experience":
return ;
case "skills":
- return null;
+ return ;
default:
if (activeSection.startsWith("custom")) {
return ;
diff --git a/apps/fronted/src/components/editor/EditorHeader.tsx b/apps/fronted/src/components/editor/EditorHeader.tsx
index 1b26b50..fbb956d 100644
--- a/apps/fronted/src/components/editor/EditorHeader.tsx
+++ b/apps/fronted/src/components/editor/EditorHeader.tsx
@@ -4,7 +4,7 @@ import { motion } from "framer-motion";
import { Sun, Moon, Eye } from "lucide-react";
import { useResumeStore } from "@/store/useResumeStore";
import { getThemeConfig } from "@/theme/themeConfig";
-import { PdfExport } from "./PdfExport";
+import { PdfExport } from "../PdfExport";
interface EditorHeaderProps {
isMobile?: boolean;
diff --git a/apps/fronted/src/components/editor/Field.tsx b/apps/fronted/src/components/editor/Field.tsx
index 0c6094f..7e97ccb 100644
--- a/apps/fronted/src/components/editor/Field.tsx
+++ b/apps/fronted/src/components/editor/Field.tsx
@@ -9,7 +9,7 @@ import { useResumeStore } from "@/store/useResumeStore";
import RichTextEditor from "@/app/workbench/compoents/Editor/RichText";
type FieldProps = {
- label: string;
+ label?: string;
value?: string;
onChange: (value: string) => void;
type?: "text" | "textarea" | "date" | "editor";
diff --git a/apps/fronted/src/components/editor/IconSelector.tsx b/apps/fronted/src/components/editor/IconSelector.tsx
index e5bad82..d41eeb0 100644
--- a/apps/fronted/src/components/editor/IconSelector.tsx
+++ b/apps/fronted/src/components/editor/IconSelector.tsx
@@ -82,7 +82,7 @@ interface IconOption {
}
interface IconSelectorProps {
- value: string;
+ value?: string;
onChange: (value: string) => void;
theme?: "light" | "dark";
}
diff --git a/apps/fronted/src/components/editor/skills/SkillPanel.tsx b/apps/fronted/src/components/editor/skills/SkillPanel.tsx
new file mode 100644
index 0000000..c814100
--- /dev/null
+++ b/apps/fronted/src/components/editor/skills/SkillPanel.tsx
@@ -0,0 +1,32 @@
+"use client";
+import { useResumeStore } from "@/store/useResumeStore";
+import Field from "../Field";
+import { cn } from "@/lib/utils";
+
+const SkillPanel = () => {
+ const { updateSkillContent, skillContent } = useResumeStore();
+
+ const handleChange = (value: string) => {
+ updateSkillContent(value);
+ };
+
+ return (
+
+
+
+ );
+};
+
+export default SkillPanel;
diff --git a/apps/fronted/src/components/preview/PreviewPanel.tsx b/apps/fronted/src/components/preview/PreviewPanel.tsx
index fe3b754..ca889cd 100644
--- a/apps/fronted/src/components/preview/PreviewPanel.tsx
+++ b/apps/fronted/src/components/preview/PreviewPanel.tsx
@@ -12,6 +12,7 @@ import { ProjectItem } from "./ProjectItem";
import { ExperienceSection } from "./ExperienceSection";
import { EducationSection } from "./EducationSection";
import { CustomSection } from "./CustomSection";
+import { SkillSection } from "./SkillPanel";
const getFontFamilyClass = (fontFamily: string) => {
switch (fontFamily) {
@@ -69,7 +70,8 @@ export function PreviewPanel() {
projects,
draggingProjectId,
colorTheme,
- customData
+ customData,
+ skillContent
} = useResumeStore();
const previewRef = React.useRef(null);
@@ -230,6 +232,14 @@ export function PreviewPanel() {
);
case "projects":
return renderProjects();
+ case "skills":
+ return (
+
+ );
default:
return null;
}
diff --git a/apps/fronted/src/components/preview/SkillPanel.tsx b/apps/fronted/src/components/preview/SkillPanel.tsx
new file mode 100644
index 0000000..ae1ad5d
--- /dev/null
+++ b/apps/fronted/src/components/preview/SkillPanel.tsx
@@ -0,0 +1,48 @@
+import { motion } from "framer-motion";
+import { GlobalSettings } from "@/types/resume";
+import { SectionTitle } from "./SectionTitle";
+
+interface SkillSectionProps {
+ skill: string;
+ globalSettings: GlobalSettings | undefined;
+ themeColor: string;
+}
+
+export function SkillSection({
+ skill,
+ globalSettings,
+ themeColor
+}: SkillSectionProps) {
+ if (!skill) {
+ return null;
+ }
+
+ return (
+
+
+
+
+ );
+}
diff --git a/apps/fronted/src/store/useResumeStore.ts b/apps/fronted/src/store/useResumeStore.ts
index 4a894c1..01a6659 100644
--- a/apps/fronted/src/store/useResumeStore.ts
+++ b/apps/fronted/src/store/useResumeStore.ts
@@ -72,6 +72,10 @@ interface ResumeStore {
deleteProject: (id: string) => void;
draggingProjectId: string | null;
setDraggingProjectId: (id: string | null) => void;
+
+ // 技能特长
+ skillContent: string;
+ updateSkillContent: (skillContent: string) => void;
}
const initialState = {
@@ -79,14 +83,17 @@ const initialState = {
basic: {
name: "张三",
title: "高级前端工程师",
- email: "example@email.com",
+ email: "zhangsan@example.com",
phone: "13800138000",
- location: "北京市",
- birthDate: "",
+ location: "北京市朝阳区",
+ birthDate: "1995-01",
icons: {},
photoConfig: DEFAULT_CONFIG,
- customFields: [],
- employementStatus: "",
+ customFields: [
+ { id: "personal", label: "个人网站", value: "https://zhangsan.dev" },
+ { id: "github", label: "GitHub", value: "https://github.com/zhangsan" }
+ ],
+ employementStatus: "全职",
photo: "avatar.svg"
},
education: [
@@ -95,22 +102,106 @@ const initialState = {
school: "北京大学",
major: "计算机科学与技术",
degree: "本科",
- startDate: "2019-09",
- endDate: "2023-06",
+ startDate: "2013-09",
+ endDate: "2017-06",
visible: true,
gpa: "3.8/4.0",
location: "北京",
- description:
- "主修课程:数据结构、算法设计、操作系统、计算机网络、数据库系统\n在校期间保持专业前10%,获得优秀学生奖学金,参与多个开源项目"
+ description: `
+ - 主修课程:数据结构、算法设计、操作系统、计算机网络、Web开发技术
+ - 专业排名前 5%,连续三年获得一等奖学金
+ - 担任计算机协会技术部部长,组织多次技术分享会
+ - 参与开源项目贡献,获得 GitHub Campus Expert 认证
+
`
}
],
+ skillContent: `
+
+ - 前端框架:精通 React、Vue.js,熟悉 Next.js、Nuxt.js 等 SSR 框架
+ - 开发语言:TypeScript、JavaScript(ES6+)、HTML5、CSS3
+ - UI/样式:精通 TailwindCSS、Sass/Less、CSS Module、Styled-components
+ - 状态管理:Redux、Vuex、Zustand、Jotai、React Query
+ - 工程化工具:Webpack、Vite、Rollup、Babel、ESLint
+ - 测试工具:Jest、React Testing Library、Cypress
+ - 性能优化:熟悉浏览器渲染原理、性能指标监控、代码分割、懒加载等优化技术
+ - 版本控制:Git、SVN
+
+
+ - 技术管理:具备团队管理经验,主导过多个大型项目的技术选型和架构设计
+ - 技术分享:定期组织团队技术分享,主导建设团队技术博客
+ - 敏捷开发:熟悉 Scrum 开发流程,具有良好的项目把控能力
+ - 英语能力:CET-6 分数 560,具备良好的英文文档阅读和技术交流能力
+
+
`,
experience: [
{
id: "1",
- company: "某科技有限公司",
+ company: "字节跳动",
position: "高级前端工程师",
- date: "2020-至今",
- details: "负责公司核心产品..."
+ date: "2021.07 - 至今",
+ details: `
+ - 负责抖音创作者平台的开发与维护,主导多个核心功能的技术方案设计
+ - 优化项目工程化配置,将构建时间从 8 分钟优化至 2 分钟,提升团队开发效率
+ - 设计并实现组件库,提升代码复用率达 70%,显著减少开发时间
+ - 主导性能优化项目,使平台首屏加载时间减少 50%,接入 APM 监控系统
+ - 指导初级工程师,组织技术分享会,提升团队整体技术水平
+
`
+ }
+ ],
+ projects: [
+ {
+ id: "p1",
+ name: "抖音创作者中台",
+ role: "前端负责人",
+ date: "2022.06 - 2023.12",
+ description:
+ "基于 React 的创作者数据分析和内容管理平台,服务百万级创作者群体,包含数据分析、内容管理、收益管理等多个子系统。",
+ technologies:
+ "React 18、TypeScript、TailwindCSS、Zustand、React Query、shadcn/ui、Recharts",
+ responsibilities: `- 主导项目技术选型和架构设计
+- 建立项目开发规范和 CI/CD 流程
+- 负责核心功能模块开发和性能优化
+- 指导团队成员,把控代码质量`,
+ achievements: `- 系统性能显著提升,首屏加载时间减少 50%
+- 代码重用率提高到 80%,显著减少开发时间
+- 平台日活跃用户提升 200%
+- 获得公司年度最佳项目奖`,
+ visible: true
+ },
+ {
+ id: "p2",
+ name: "微信小程序开发者工具",
+ role: "核心开发者",
+ date: "2020.03 - 2021.06",
+ description:
+ "为开发者提供小程序开发、调试和发布的一站式解决方案。基于 Electron 构建的跨平台桌面应用。",
+ technologies:
+ "Electron、React、TypeScript、Monaco Editor、Node.js、WebSocket",
+ responsibilities: `- 负责编辑器核心功能开发
+- 实现实时预览和调试功能
+- 优化开发者使用体验
+- 处理性能问题和 Bug 修复`,
+ achievements: `- 编辑器性能提升 40%
+- 月活用户增长 150%
+- 获得最佳工具奖`,
+ visible: true
+ },
+ {
+ id: "p3",
+ name: "前端监控平台",
+ role: "技术负责人",
+ date: "2021.09 - 2022.03",
+ description:
+ "一个完整的前端监控解决方案,包含错误监控、性能监控、用户行为分析等功能。",
+ technologies: "Vue 3、TypeScript、Vite、IndexedDB、WebWorker、Canvas",
+ responsibilities: `- 设计监控 SDK 和数据采集方案
+- 开发可视化数据面板
+- 优化数据处理性能
+- 制定监控告警策略`,
+ achievements: `- 准确捕获 99.9% 的前端异常
+- 帮助业务快速定位并解决问题
+- 平均故障排查时间减少 60%`,
+ visible: true
}
],
menuSections: [
@@ -133,40 +224,12 @@ const initialState = {
activeSection: "basic",
- projects: [
- {
- id: "p1",
- name: "企业中台系统",
- role: "前端负责人",
- date: "2023.06 - 2023.12",
- description:
- "基于 React 的企业级中台项目,包含工作流、报表、系统管理等多个子系统",
- technologies: "React, TypeScript, TailwindCSS, shadcn/ui",
- responsibilities:
- "负责整体技术方案设计和团队管理,把控项目进度和代码质量",
- achievements: "系统整体性能提升 50%,代码重用率提高到 80%",
- visible: true
- },
- {
- id: "p2",
- name: "xxx",
- role: "前端负责人",
- date: "2023.06 - 2023.12",
- description:
- "基于 React 的企业级中台项目,包含工作流、报表、系统管理等多个子系统",
- technologies: "React, TypeScript, TailwindCSS, shadcn/ui",
- responsibilities:
- "负责整体技术方案设计和团队管理,把控项目进度和代码质量",
- achievements: "系统整体性能提升 50%,代码重用率提高到 80%",
- visible: true
- }
- ],
globalSettings: {
fontFamily: "sans",
baseFontSize: 14,
pagePadding: 20,
paragraphSpacing: 20,
- lineHeight: 1,
+ lineHeight: 1.2,
sectionSpacing: 20,
headerSize: 18,
subheaderSize: 16,
@@ -345,7 +408,9 @@ export const useResumeStore = create()(
(item) => item.id !== itemId
)
}
- }))
+ })),
+
+ updateSkillContent: (content) => set({ skillContent: content })
}),
{
diff --git a/apps/fronted/src/types/resume.ts b/apps/fronted/src/types/resume.ts
index e1a823f..ebd8e54 100644
--- a/apps/fronted/src/types/resume.ts
+++ b/apps/fronted/src/types/resume.ts
@@ -56,7 +56,7 @@ export interface CustomFieldType {
id: string;
label: string;
value: string;
- icon: string;
+ icon?: string;
visible?: boolean;
}
export interface BasicInfo {
@@ -75,7 +75,7 @@ export interface BasicInfo {
id: string;
label: string;
value: string;
- icon: string;
+ icon?: string;
visible?: boolean;
}>;
}