mirror of
https://github.com/JOYCEQL/magic-resume.git
synced 2026-07-03 14:07:11 +02:00
feat: skills && default data
This commit is contained in:
@@ -584,7 +584,7 @@ const RichTextEditor = ({
|
||||
<EditorContent editor={editor} />
|
||||
|
||||
{/* Bubble Menu */}
|
||||
{editor && (
|
||||
{/* {editor && (
|
||||
<BubbleMenu
|
||||
className={cn(
|
||||
"flex items-center gap-0.5 p-1 rounded-md backdrop-blur border shadow-lg",
|
||||
@@ -616,7 +616,7 @@ const RichTextEditor = ({
|
||||
<TextColorButton editor={editor} />
|
||||
<BackgroundColorButton editor={editor} />
|
||||
</BubbleMenu>
|
||||
)}
|
||||
)} */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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 <ExperiencePanel />;
|
||||
case "skills":
|
||||
return null;
|
||||
return <SkillPanel />;
|
||||
default:
|
||||
if (activeSection.startsWith("custom")) {
|
||||
return <CustomPanel sectionId={activeSection} />;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -82,7 +82,7 @@ interface IconOption {
|
||||
}
|
||||
|
||||
interface IconSelectorProps {
|
||||
value: string;
|
||||
value?: string;
|
||||
onChange: (value: string) => void;
|
||||
theme?: "light" | "dark";
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
<div
|
||||
className={cn(
|
||||
"rounded-lg border p-4",
|
||||
"bg-white",
|
||||
"dark:bg-neutral-900/30",
|
||||
"border-gray-100 dark:border-neutral-800"
|
||||
)}
|
||||
>
|
||||
<Field
|
||||
value={skillContent}
|
||||
onChange={handleChange}
|
||||
type="editor"
|
||||
placeholder="描述你的技能、专长等..."
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SkillPanel;
|
||||
@@ -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<HTMLDivElement>(null);
|
||||
@@ -230,6 +232,14 @@ export function PreviewPanel() {
|
||||
);
|
||||
case "projects":
|
||||
return renderProjects();
|
||||
case "skills":
|
||||
return (
|
||||
<SkillSection
|
||||
skill={skillContent}
|
||||
globalSettings={globalSettings}
|
||||
themeColor={currentThemeColor}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
<motion.div
|
||||
layout
|
||||
style={{
|
||||
marginTop: `${globalSettings?.sectionSpacing || 24}px`
|
||||
}}
|
||||
>
|
||||
<SectionTitle
|
||||
title="技能特长"
|
||||
themeColor={themeColor}
|
||||
globalSettings={globalSettings}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
marginTop: `${globalSettings?.paragraphSpacing}px`
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="text-gray-600"
|
||||
style={{
|
||||
fontSize: `${globalSettings?.baseFontSize || 14}px`,
|
||||
lineHeight: globalSettings?.lineHeight || 1.6
|
||||
}}
|
||||
dangerouslySetInnerHTML={{ __html: skill }}
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
@@ -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: `<ul>
|
||||
<li>主修课程:数据结构、算法设计、操作系统、计算机网络、Web开发技术</li>
|
||||
<li>专业排名前 5%,连续三年获得一等奖学金</li>
|
||||
<li>担任计算机协会技术部部长,组织多次技术分享会</li>
|
||||
<li>参与开源项目贡献,获得 GitHub Campus Expert 认证</li>
|
||||
</ul>`
|
||||
}
|
||||
],
|
||||
skillContent: `<div class="skill-content">
|
||||
<ul>
|
||||
<li>前端框架:精通 React、Vue.js,熟悉 Next.js、Nuxt.js 等 SSR 框架</li>
|
||||
<li>开发语言:TypeScript、JavaScript(ES6+)、HTML5、CSS3</li>
|
||||
<li>UI/样式:精通 TailwindCSS、Sass/Less、CSS Module、Styled-components</li>
|
||||
<li>状态管理:Redux、Vuex、Zustand、Jotai、React Query</li>
|
||||
<li>工程化工具:Webpack、Vite、Rollup、Babel、ESLint</li>
|
||||
<li>测试工具:Jest、React Testing Library、Cypress</li>
|
||||
<li>性能优化:熟悉浏览器渲染原理、性能指标监控、代码分割、懒加载等优化技术</li>
|
||||
<li>版本控制:Git、SVN</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>技术管理:具备团队管理经验,主导过多个大型项目的技术选型和架构设计</li>
|
||||
<li>技术分享:定期组织团队技术分享,主导建设团队技术博客</li>
|
||||
<li>敏捷开发:熟悉 Scrum 开发流程,具有良好的项目把控能力</li>
|
||||
<li>英语能力:CET-6 分数 560,具备良好的英文文档阅读和技术交流能力</li>
|
||||
</ul>
|
||||
</div>`,
|
||||
experience: [
|
||||
{
|
||||
id: "1",
|
||||
company: "某科技有限公司",
|
||||
company: "字节跳动",
|
||||
position: "高级前端工程师",
|
||||
date: "2020-至今",
|
||||
details: "负责公司核心产品..."
|
||||
date: "2021.07 - 至今",
|
||||
details: `<ul>
|
||||
<li>负责抖音创作者平台的开发与维护,主导多个核心功能的技术方案设计</li>
|
||||
<li>优化项目工程化配置,将构建时间从 8 分钟优化至 2 分钟,提升团队开发效率</li>
|
||||
<li>设计并实现组件库,提升代码复用率达 70%,显著减少开发时间</li>
|
||||
<li>主导性能优化项目,使平台首屏加载时间减少 50%,接入 APM 监控系统</li>
|
||||
<li>指导初级工程师,组织技术分享会,提升团队整体技术水平</li>
|
||||
</ul>`
|
||||
}
|
||||
],
|
||||
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<ResumeStore>()(
|
||||
(item) => item.id !== itemId
|
||||
)
|
||||
}
|
||||
}))
|
||||
})),
|
||||
|
||||
updateSkillContent: (content) => set({ skillContent: content })
|
||||
}),
|
||||
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user