From 327828ea561c22177c84474cc151e2a9f4fdf897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=9B=E5=85=AE?= Date: Fri, 12 Jun 2026 17:05:22 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E7=AE=80=E5=8E=86?= =?UTF-8?q?=E6=8A=80=E8=83=BD=E6=A0=8F=E6=8A=80=E6=9C=AF=E6=A0=88=E5=91=88?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/render.js | 33 +++++++++++++++++++++++++++----- src/resume-data.js | 43 +++++++++++++++++++++++++++--------------- src/styles.css | 47 ++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 99 insertions(+), 24 deletions(-) diff --git a/src/render.js b/src/render.js index c5452a6..8346b48 100644 --- a/src/render.js +++ b/src/render.js @@ -1,3 +1,6 @@ +/** + * 将简历数据渲染为对话式作品集页面,负责不同回合的 DOM 结构装配。 + */ import { experiences, focusAreas, @@ -119,15 +122,28 @@ function skillsContent(answer) { answer.append(el("div", "a-title gen", "Token Stream / Skills")); const HOT = new Set([ "SSE 流式通信", - "Next.js", - "React", + "Next.js 16", + "React 19", "React Native", "TypeScript", + "NestJS", + "MySQL", + "Redis", + "Jenkins", + "Gitea", + "BPMN", "Qiankun", ]); + const grid = el("div", "skills-grid"); skills.forEach((group) => { - const wrap = el("div", "skill-group"); - wrap.append(el("div", "g-name", group.group)); + const wrap = el("div", "skill-group gen"); + const head = el("div", "g-head"); + head.append( + el("div", "g-name", group.group), + el("span", "g-count", `${group.items.length} 项`), + ); + wrap.append(head); + if (group.summary) wrap.append(el("p", "g-summary", group.summary)); const row = el("div", "tag-row"); group.items.forEach((item) => { row.append( @@ -135,8 +151,9 @@ function skillsContent(answer) { ); }); wrap.append(row); - answer.append(wrap); + grid.append(wrap); }); + answer.append(grid); } function experienceContent(answer) { @@ -200,6 +217,9 @@ const CONTENT = { /* ---------- 装配 ---------- */ +/** + * 根据对话回合配置生成主内容区,保留滚动叙事所需的 section 结构。 + */ export function renderDialogue(mount) { rounds.forEach((round) => { const section = el("section", "round"); @@ -228,6 +248,9 @@ export function renderDialogue(mount) { }); } +/** + * 生成右侧回合导航节点,并把点击行为交给滚动编排模块处理。 + */ export function renderRail(mount, onJump) { rounds.forEach((round) => { const node = el("button", "rail-node"); diff --git a/src/resume-data.js b/src/resume-data.js index c31654b..4cb5aaa 100644 --- a/src/resume-data.js +++ b/src/resume-data.js @@ -34,42 +34,55 @@ export const focusAreas = [ }, ]; +/** + * 首页自我介绍回合的关键叙事点,突出近一年方向与个人项目信号。 + */ export const resumeSignals = [ "前端经验覆盖 PC 管理后台、小程序、H5、React Native 和微前端,最近一年主要在 AI 产品团队做业务前端。", "SeaBuzz 侧更偏用户体验:对话、内容流、新闻详情、游客数据、分享和反馈链路。", "SeaCloud / Vtrix 侧更偏控制台:Pricing、Billing、API Keys、组织权限、交易筛选和分销配置。", "个人工程实践里搭建了 DevOps 运维平台,把 Gitea、Jenkins、BPMN、通知、审计、Agent 诊断和 Jenkins 直构导入串成发布闭环。", - "技术栈以 React / Next.js / React Native / TypeScript 为主,也有 Vue、UniApp 和 Qiankun 项目经验。", + "技术栈以 React / Next.js / React Native / TypeScript 为主,能覆盖 Vue、UniApp、Qiankun、NestJS、MySQL、Redis 和 Jenkins/Gitea 发布链路。", ]; +/** + * 技能栏按招聘方扫读路径分组,避免基础设施与数据层能力被埋在项目详情里。 + */ export const skills = [ { - group: "对话与内容", - items: ["SSE 流式通信", "打字机响应", "Markdown/LaTeX", "来源引用", "对话历史", "新闻详情"], + group: "前端主栈", + summary: "主力交付栈,覆盖 AI 产品、控制台、移动端和多端内容流。", + items: ["React 19", "Next.js 16", "React Native", "TypeScript", "Vue 3", "Element Plus", "Tailwind CSS", "Zustand", "Alova"], }, { - group: "控制台", - items: ["Pricing", "Billing", "API Keys", "组织权限", "额度限制", "交易筛选", "Excel 导出"], + group: "数据与后端协作", + summary: "能理解接口、数据模型和状态一致性,不只停留在页面拼装。", + items: ["NestJS", "OpenAPI", "DTO 校验", "Prisma", "MySQL", "Redis", "BullMQ", "幂等键", "乐观锁"], }, { - group: "跨端体验", - items: ["React Native", "Expo Router", "NativeWind", "游客转登录", "只读分享", "Smart Image"], + group: "DevOps 与发布", + summary: "从个人项目实践中补齐发布闭环、可观测性和运维诊断意识。", + items: ["DevOps 平台", "Jenkins", "Jenkins 直构导入", "Gitea", "BPMN", "Outbox", "审计日志", "构建日志脱敏", "Runbook"], }, { - group: "Web 主栈", - items: ["Next.js", "React", "Vue 3", "TypeScript", "Tailwind CSS", "Zustand", "Alova"], + group: "AI 对话与内容", + summary: "最近一年重点投入的方向,关注流式体验、上下文恢复和内容可读性。", + items: ["SSE 流式通信", "打字机响应", "Markdown/LaTeX", "来源引用", "思考态", "对话历史", "新闻详情"], }, { - group: "小程序与 H5", - items: ["UniApp", "微信小程序", "飞书小程序", "H5", "摄像头扫码", "低功耗蓝牙"], + group: "控制台业务", + summary: "长期处理权限、账务、额度、筛选导出等后台业务边界。", + items: ["Pricing", "Billing", "API Keys", "组织权限", "额度限制", "交易筛选", "Excel 导出", "成员权限"], }, { - group: "工程协作", - items: ["pnpm Monorepo", "Git Submodules", "Qiankun", "Lerna", "i18n 同步", "Code Review"], + group: "跨端与小程序", + summary: "覆盖 App、H5、小程序和门店设备链路,能处理端侧能力差异。", + items: ["Expo Router", "NativeWind", "UniApp", "微信小程序", "飞书小程序", "游客转登录", "Smart Image", "摄像头扫码", "低功耗蓝牙"], }, { - group: "工程化与质量", - items: ["DevOps 平台", "Jenkins 直构导入", "Gitea", "BPMN", "ARMS 监控", "Playwright", "Git Flow", "Code Review"], + group: "工程协作与质量", + summary: "偏团队长期维护视角,关注复用、规范、监控和评审质量。", + items: ["pnpm Monorepo", "Git Submodules", "Qiankun", "Lerna", "i18n 同步", "ARMS 监控", "Playwright", "Git Flow", "Code Review"], }, ]; diff --git a/src/styles.css b/src/styles.css index b13fe77..f41c198 100644 --- a/src/styles.css +++ b/src/styles.css @@ -581,19 +581,53 @@ main { } /* ============ Round 4: 技能 ============ */ +.skills-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 14px; +} + .skill-group { - margin-bottom: 20px; + min-width: 0; + padding: 14px; + border: 1px solid rgba(139, 151, 173, 0.18); + border-radius: 8px; + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.035), rgba(255, 255, 255, 0.012)), + rgba(11, 17, 32, 0.54); +} + +.g-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-bottom: 8px; } .skill-group .g-name { font-family: var(--mono); font-size: 11px; - letter-spacing: 0.2em; - color: var(--ink-faint); - margin-bottom: 8px; + letter-spacing: 0; + color: var(--ink); text-transform: uppercase; } +.g-count { + flex: 0 0 auto; + font-family: var(--mono); + font-size: 10px; + color: var(--ink-faint); +} + +.g-summary { + min-height: 42px; + margin-bottom: 12px; + font-size: 12px; + line-height: 1.65; + color: var(--ink-dim); +} + .skill-token { font-family: var(--mono); font-size: 12px; @@ -607,6 +641,7 @@ main { .skill-token.hot { border-color: rgba(34, 211, 238, 0.5); + background: rgba(34, 211, 238, 0.08); color: var(--cyan); } @@ -768,6 +803,10 @@ main { grid-template-columns: 1fr; } + .skills-grid { + grid-template-columns: 1fr; + } + #session-rail { right: auto; top: 54px;