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; }>; }