Firefly 是一个基于 React 18 + TypeScript + Vite 构建的高性能个人职业形象门户。它旨在帮助专业人士构建模块化的知识中枢,系统化展示专业价值与思想深度。
项目采用模块化设计,数据与 UI 分离,支持 Markdown/MDX 内容驱动。
.
├── .github/workflows/ # CI/CD 自动化部署配置
├── public/ # 静态资源 (包含 .nojekyll 确保资源加载)
├── src/
│ ├── assets/ # 本地图片、字体等资源
│ ├── components/ # 通用 UI 原子组件
│ ├── content/ # Markdown 内容源 (博客、知识分享)
│ ├── data/ # 结构化 JSON 数据 (简历、工具、社交链接)
│ ├── layouts/ # 页面容器布局
│ ├── pages/ # 核心功能页面 (Resume, Blog, Social 等)
│ ├── types/ # TypeScript 类型定义
│ ├── utils/ # 工具函数 (Markdown 解析等)
│ ├── App.tsx # 路由配置中心
│ └── main.tsx # 项目入口
├── tailwind.config.js # Tailwind CSS 样式配置
├── vite.config.ts # Vite 构建与部署配置
└── package.json # 依赖管理与脚本
# 安装依赖
npm install
# 启动开发服务器
npm run dev项目已配置 GitHub Actions,只需推送代码到 main 分支即可自动部署。
git add .
git commit -m "feat: your message"
git push origin main在项目搭建和部署过程中,你可能会遇到以下典型问题:
- 错误信息:
remote: Invalid username or token. Password authentication is not supported. - 原因: GitHub 禁用了密码认证。
- 解决: 使用 Personal Access Token (PAT)。确保生成的 Token 勾选了
repo和workflow(修改 Action 脚本需要) 权限。
- 错误信息: 访问
https://<user>.github.io/firefly/却不显示内容。 - 解决:
- 在
vite.config.ts中设置base: '/firefly/'(或./)。 - 在
App.tsx中为BrowserRouter设置basename="/firefly"。
- 在
- 错误信息:
Failed to load resource: the server responded with a status of 404。 - 原因: GitHub Pages 默认使用的 Jekyll 引擎会忽略下划线
_开头的文件。 - 解决: 在
public/目录下创建一个空的.nojekyll文件,禁用 Jekyll 引擎。
- 错误信息:
An import path can only end with a '.tsx' extension when 'allowImportingTsExtensions' is enabled. - 解决: 在 TypeScript 项目中,
import本地组件时不要写.tsx后缀。例如:使用import App from './App'而不是import App from './App.tsx'。
- 部署分支: 请确保在 GitHub 仓库的
Settings -> Pages中,Source选择Deploy from a branch,且分支设置为gh-pages。 - 数据更新: 若要修改简历或链接,只需编辑
src/data/*.json文件,无需修改组件代码。 - CI/CD 权限: 在
Settings -> Actions -> General中,确保 Workflow permissions 设置为Read and write permissions。
- 个人简历: 结构化展示教育与工作经历。
- 社交聚合: 聚合 GitHub、LinkedIn 等专业平台。
- 内容引擎: 支持通过 Markdown 发布博客与知识分享。
- 响应式设计: 完美适配移动端与暗黑模式。
项目采用集中式配置管理社交媒体链接,支持通过简单的 JSON 配置实现首页、社交页面等多处统一展示。
社交媒体链接的配置文件位于:src/data/social.json
每个社交平台配置项包含以下字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
platform |
String | ✅ | 平台名称(如 GitHub、LinkedIn、WeChat) |
url |
String | ✅ | 链接地址(支持 https://、mailto:、skype: 等协议) |
icon |
String | ✅ | 图标名称(来自 Lucide React 图标库) |
showInHomePage |
Boolean | ❌ | 是否在首页显示(默认 true) |
ariaLabel |
String | ❌ | 无障碍标签(用于屏幕阅读器) |
openInNewTab |
Boolean | ❌ | 是否在新窗口打开(默认 true) |
{
"platform": "GitHub",
"url": "https://github.com/chandler-song",
"icon": "Github",
"showInHomePage": true,
"ariaLabel": "访问 Chandler 的 GitHub",
"openInNewTab": true
}{
"platform": "Email",
"url": "mailto:275737875@qq.com",
"icon": "Mail",
"showInHomePage": true,
"ariaLabel": "发送邮件给 Chandler",
"openInNewTab": false
}{
"platform": "WeChat",
"url": "/wechat-qrcode",
"icon": "MessageSquare",
"showInHomePage": true,
"ariaLabel": "查看 Chandler 的微信二维码",
"openInNewTab": false
}{
"platform": "Skype",
"url": "skype:chandler.song?chat",
"icon": "Phone",
"showInHomePage": true,
"ariaLabel": "通过 Skype 联系 Chandler",
"openInNewTab": false
}项目使用 Lucide React 图标库,以下是常用社交平台的推荐图标:
| 平台 | 推荐图标 | 说明 |
|---|---|---|
| GitHub | Github |
原生支持 |
Linkedin |
原生支持 | |
| Twitter/X | Twitter |
原生支持 |
| YouTube | Youtube |
原生支持 |
| 邮箱 | Mail |
通用邮件图标 |
| 微信 | MessageSquare |
聊天消息框 |
| Skype | Phone |
电话/语音通话 |
| CSDN | BookOpen |
技术博客/文档 |
| 微博 | Share2 |
社交分享 |
| 掘金 | Code2 |
技术开发平台 |
| 知乎 | Users |
社区/问答 |
| Telegram | Send |
即时通讯 |
在 src/data/social.json 文件的数组中添加新配置项即可:
[
// ... 现有配置 ...
{
"platform": "知乎",
"url": "https://www.zhihu.com/people/chandler-song",
"icon": "Users",
"showInHomePage": false,
"ariaLabel": "访问 Chandler 的知乎主页",
"openInNewTab": true
}
]通过 showInHomePage 字段灵活控制哪些社交链接在首页展示:
- 首页显示:设置
"showInHomePage": true - 仅在社交页显示:设置
"showInHomePage": false - 默认行为:若不设置该字段,默认为
true(显示在首页)
配置的社交链接会自动在以下位置展示:
- 首页 Hero 区域:仅显示
showInHomePage: true的链接 - 社交页面 (
/social):显示所有配置的社交链接 - 其他自定义组件:可导入
social.json在任意位置使用
- 配置化管理:所有社交链接集中在
src/data/social.json,遵循 DRY 原则 - 类型安全:在
src/types/index.ts中定义了SocialLink接口 - 动态图标:通过
import * as Icons from 'lucide-react'动态引用图标组件 - 过滤逻辑:在
Home.tsx中使用filter方法筛选首页显示的链接
Q: 如何添加自定义图标?
A: Lucide React 提供了 1600+ 图标。如果找不到合适的,可以使用通用图标如 Link、Globe、AtSign 等。
Q: 能否使用图片作为图标?
A: 当前架构基于 Lucide React 图标库。如需使用自定义图片,需修改 Home.tsx 和 Social.tsx 组件的渲染逻辑。
Q: 微信链接为什么使用内部路由?
A: 微信没有网页版个人主页,因此创建了 /wechat-qrcode 页面展示二维码,用户需将二维码图片放在 public/wechat-qrcode.png。
Q: 如何调整社交图标的顺序?
A: 调整 social.json 中配置项的顺序即可,系统会按数组顺序渲染。
项目支持在首页和简历页展示个人头像,通过集中式配置管理实现灵活控制。
个人头像功能为页面添加了更具个性化和专业感的视觉元素:
- 首页展示:头像显示在 Hero 区域顶部,作为个人品牌的视觉焦点
- 简历页展示:头像与个人信息组成卡片式布局,提升简历的专业性
- 配置化管理:通过 JSON 配置文件控制头像的显示、路径等属性
- 响应式设计:自动适配桌面端和移动端,确保在各种设备上的最佳显示效果
头像配置文件位于:src/data/profile.json
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
name |
String | ✅ | 个人姓名(用于简历页显示) |
title |
String | ✅ | 职位/头衔(如:前端架构师) |
subtitle |
String | ✅ | 个人简介/副标题 |
avatar.enabled |
Boolean | ✅ | 是否启用头像功能 |
avatar.path |
String | ✅ | 头像图片路径(相对于 public 目录) |
avatar.alt |
String | ✅ | 图片替代文本(用于无障碍访问) |
{
"name": "Chandler",
"title": "前端架构师",
"subtitle": "专注于前端开发与架构",
"avatar": {
"enabled": true,
"path": "/avatar.jpg",
"alt": "Chandler 的头像"
}
}- 圆形头像:采用
rounded-full实现完美的圆形效果 - 柔和渐变光晕:使用
from-primary/10 via-primary/5 to-transparent的三级渐变- 饱和度低至 5%-10%,确保视觉柔和自然
- 对角渐变(
to-br)提供更丰富的层次感
- 精细边框:2px 半透明边框(
border-border/50),与页面整体风格协调 - 柔和阴影:
- 首页:
shadow-lg(常规)→shadow-xl(悬停) - 简历页:
shadow-md(常规)→shadow-lg(悬停)
- 首页:
| 设备类型 | 首页尺寸 | 简历页尺寸 |
|---|---|---|
| 移动端 | 128×128px | 128×128px |
| 桌面端 | 160×160px | 144×144px |
- 悬停增强:
- 光晕透明度从 60% 提升至 80%(变化幅度仅 20%,过渡平滑)
- 边框添加微弱的主题色(
border-primary/20) - 阴影强度轻微增加
- 过渡动画:所有变化均采用 500ms 缓慢过渡(
transition-all duration-500) - 模糊效果:使用
blur-sm实现细腻的光晕模糊
- 位置:Hero Section 顶部,主标题上方
- 布局:垂直居中对齐,作为视觉焦点
- 特点:
- 独立展示,不与其他元素重叠
- 光晕效果更明显,强调个人品牌
- 尺寸较大,确保视觉冲击力
- 位置:页面顶部个人信息卡片区域
- 布局:
- 桌面端:头像在左,个人信息在右(横向布局)
- 移动端:头像在上,个人信息在下(纵向布局)
- 特点:
- 卡片式设计,带渐变背景(
from-muted/30 via-muted/10) - 与姓名、职位、简介信息协调统一
- 尺寸适中,保持整体平衡
- 卡片式设计,带渐变背景(
在 src/types/index.ts 中定义了 ProfileConfig 接口:
export interface ProfileConfig {
name: string;
title: string;
subtitle: string;
avatar: {
enabled: boolean;
path: string;
alt: string;
};
}当头像图片加载失败时,系统会自动显示美观的 SVG 占位符:
- 占位符设计:中性色渐变背景 + 用户图标
- 颜色方案:使用
muted色系确保与页面风格一致 - 自动替换:通过
onError事件监听实现无感切换
- Tailwind 断点:使用
md:前缀区分移动端和桌面端样式 - 弹性布局:简历页使用
flex-col md:flex-row实现自适应布局 - 尺寸适配:通过
w-32 h-32 md:w-40 md:h-40实现不同设备的尺寸调整
-
选择图片:
- 推荐使用正方形照片
- 建议分辨率:至少 400×400px(支持高清显示)
- 文件格式:JPG、PNG、WebP 均可
-
图片命名:
- 建议使用简洁的名称,如
avatar.jpg或profile.png - 避免使用中文或特殊字符
- 建议使用简洁的名称,如
将准备好的头像图片放置到 public/ 目录:
cp your-avatar.jpg /path/to/project/public/avatar.jpg编辑 src/data/profile.json,确保 avatar.path 指向正确的图片:
{
"avatar": {
"enabled": true,
"path": "/avatar.jpg", // 确保与实际文件名一致
"alt": "您的姓名 的头像"
}
}启动开发服务器查看效果:
npm run dev访问以下页面验证头像显示:
- 首页:
http://localhost:5173/ - 简历页:
http://localhost:5173/resume
如需临时隐藏头像,只需将 enabled 设置为 false:
{
"avatar": {
"enabled": false,
"path": "/avatar.jpg",
"alt": "Chandler 的头像"
}
}| 优化项 | 推荐值 | 说明 |
|---|---|---|
| 分辨率 | 400×400px - 800×800px | 平衡清晰度与加载速度 |
| 文件大小 | < 200KB | 确保快速加载 |
| 格式选择 | WebP > PNG > JPG | WebP 提供最佳压缩率 |
| 背景处理 | 纯色或透明背景 | 避免复杂背景影响视觉效果 |
✅ 推荐命名方式:
- avatar.jpg
- profile.png
- headshot.webp
❌ 不推荐命名方式:
- 我的照片.jpg(包含中文)
- my photo 2024.png(包含空格)
- IMG_1234.JPG(无语义)
-
照片质量:
- 使用专业或半专业的照片
- 确保光线充足,面部清晰
- 背景简洁,避免杂乱元素
-
构图建议:
- 头部和肩部占画面的 60%-80%
- 保持正面或 3/4 侧面角度
- 眼神自然,表情亲和
-
一致性:
- 与其他平台(LinkedIn、GitHub)使用相同或相似的头像
- 保持个人品牌形象的连贯性
Q: 头像图片不显示怎么办?
A: 请检查以下几点:
- 图片文件是否正确放置在
public/目录下 profile.json中的path是否与实际文件名一致(包括扩展名)- 图片文件是否损坏,可以尝试在浏览器中直接访问
http://localhost:5173/avatar.jpg - 如果使用了相对路径,确保路径以
/开头
Q: 如何更换头像?
A: 有两种方式:
- 替换文件:直接用新图片替换
public/目录下的原头像文件(保持文件名不变) - 更新配置:上传新图片并修改
profile.json中的path字段
Q: 能否使用外部链接的图片?
A: 可以,但不推荐。将 path 设置为完整的 URL 即可:
{
"avatar": {
"path": "https://example.com/avatar.jpg"
}
}不推荐的原因:
- 依赖外部服务的稳定性
- 可能影响加载速度
- 存在跨域和隐私问题
Q: 如何调整头像大小?
A: 头像尺寸通过 Tailwind CSS 类控制,如需自定义:
- 修改
Home.tsx中的w-32 h-32 md:w-40 md:h-40 - 修改
Resume.tsx中的w-32 h-32 md:w-36 md:h-36 - 数字表示 Tailwind 单位(1单位 = 0.25rem = 4px)
Q: 头像显示不清晰怎么办?
A: 确保原图分辨率足够高:
- 移动端显示最大 160px,建议原图至少 320px(2倍)
- 桌面端显示最大 160px,建议原图至少 400px
- 支持高 DPI 屏幕(如 Retina),建议提供 800px 的高清图片
Q: 占位符图标能否自定义?
A: 可以修改组件代码中的 SVG 路径,或替换为其他 Lucide React 图标。当前使用的是标准用户图标(User Profile),符合大多数场景需求。
本节将详细介绍如何管理项目中的六个核心模块:知识 (Knowledge)、博客 (Blog)、洞察 (Insights)、工具 (Tools)、笔记 (Notes)、成就 (Achievements)。
为模块添加新条目,请遵循以下步骤:
- 确定目录:根据模块类型,进入对应的
src/content/子目录:src/content/knowledge/src/content/blog/src/content/insights/src/content/tools/src/content/notes/src/content/achievements/
- 创建文件:新建一个以
.md结尾的 Markdown 文件。- 命名规则:建议使用小写字母和连字符(kebab-case),例如
my-new-post.md。文件名将作为访问该条目的slug(即 URL 的一部分)。
- 命名规则:建议使用小写字母和连字符(kebab-case),例如
- 编写 Frontmatter 元数据:在文件最顶部添加 YAML 格式的配置信息。
--- title: "文章标题" date: "2026-02-02" category: "技术分类" summary: "这是内容摘要,将显示在列表页。" tags: ["标签1", "标签2"] ---
- 编写正文:在第二个
---之后开始编写 Markdown 内容。
- 物理删除:直接删除
src/content/[module]/目录下对应的.md文件即可。 - 自动生效:由于系统采用动态加载机制,删除文件后,列表页和详情页将自动不再显示该条目,无需手动清理其他引用。
- 编辑文件:打开对应的
.md文件。 - 更新字段:您可以随时修改 Frontmatter 中的
title、date、summary等。 - 保存验证:
- 开发环境:保存后浏览器会通过 HMR 自动热更新。
- 生产环境:提交代码并推送至 GitHub,Action 自动部署后生效。
- 列表页访问:通过导航栏或 URL 直接访问模块主页,例如
/blog。 - 详情页定位:点击列表项,系统会根据文件名生成路由跳转,格式为
/[module]/[filename-without-ext]。例如访问blog/my-post.md的 URL 为/blog/my-post。
- 动态加载 (
import.meta.glob):在src/utils/markdown.ts中,我们使用了 Vite 提供的批量导入功能,它会在构建时自动扫描src/content/目录下的所有文件,避免了手动维护文件索引。 - 前端解析:为了兼容浏览器环境,我们避开了 Node.js 特有的
Buffer对象,采用正则表达式手动解析 Frontmatter YAML 块。 - 路由配置:在
src/App.tsx中使用了 React Router 的动态参数路由path="/[module]/:slug",通过useParams获取文件名并加载内容。
-
"Buffer is not defined":
- 原因:使用了依赖 Node.js 内置模块的
gray-matter。 - 解决:本项目已在
src/utils/markdown.ts中切换为纯前端正则解析方案,从源头上规避了此报错。
- 原因:使用了依赖 Node.js 内置模块的
-
页面显示“加载中...”且不更新:
- 排查:检查
src/utils/markdown.ts中的import.meta.glob路径;确保 Markdown 文件头部格式正确。
- 排查:检查
-
图片无法显示:
- 解决:相对路径引用的图片在子路径部署时易失效。建议将图片存放在
public/assets/并使用绝对路径访问。
项目包含一个功能强大的“对话访谈”模块,支持通过 Markdown 驱动自动生成嘉宾主页与访谈对话。
- 新建文件:在
src/content/interviews/目录下创建一个新的.md文件。 - 命名规范:遵循
YYYY-MM-DD-受访者姓名-领域关键词.md格式。- 示例:
2026-02-04-sarah-chen-ai-agent-field.md
- 示例:
- 编写 Frontmatter:这是驱动页面渲染的核心数据。
字段 类型 说明 titleString 访谈文章标题 dateString 发布日期 (用于排序,最新日期将显示在首页) categoryString 固定为 "Interview"summaryString 访谈摘要,显示在列表页和首页模块 guestNameString 嘉宾姓名 guestTitleString 嘉宾职衔 (如:首席科学家) guestOrgString 嘉宾所属机构 guestAvatarURL 嘉宾头像链接 guestDescriptionString 嘉宾背景详述 guestAchievementsArray 嘉宾主要成就标签列表 interviewRecordsArray 核心对话流:包含 timestamp, question, answer 对象 multimediaArray 多媒体画廊:包含 type, url, caption 对象 --- title: "访谈标题" date: "2026-02-04" category: "Interview" summary: "这里是访谈摘要..." guestName: "张三" guestTitle: "技术专家" guestOrg: "某某实验室" guestAvatar: "https://example.com/avatar.png" guestDescription: "详细背景介绍..." guestAchievements: ["成就1", "成就2"] interviewRecords: [ { "timestamp": "10:00", "question": "这里是问题内容?", "answer": "这里是回答内容..." } ] multimedia: [ { "type": "image", "url": "https://example.com/photo.jpg", "caption": "图片说明" } ] --- # 更多背景 这里可以编写 Markdown 格式的访谈侧记或补充资料。
- 支持类型:
image(自动处理网格布局)、video(原生播放器)、audio(带动效的音频播放器)。 - 网格布局:
- 单张图片:在容器中优雅居中。
- 多张图片:自动切换为响应式网格布局(桌面端双列,移动端单列),带悬停缩放效果。
- 容错处理:若图片加载失败,系统会自动显示统一的占位占位图。
- 引号自动剥离:解析器会自动移除回答内容前后的多余引号,并使用现代化的引用图标装饰。
- 交互效果:对话项在悬停时会触发左侧时间轴的动态高亮。
- 自动置顶:首页模块会扫描
src/content/interviews/下的所有文件,并自动提取 日期最新 的一个进行展示。 - 跳转逻辑:点击首页访谈模块将直接进入该访谈的详情路由
/interviews/[slug]。
- 解析机制:由于 YAML 默认不支持复杂的嵌套 JSON 数组,项目重写了
src/utils/markdown.ts解析引擎,支持跨行识别未闭合的 JSON 块。 - TypeError: records.map is not a function:
- 排查:检查 Markdown 文件中
interviewRecords的 JSON 格式是否正确(特别是引号和括号的闭合)。 - 解决:确保 JSON 块前后没有多余的空行干扰解析逻辑。
- 排查:检查 Markdown 文件中
核心任务:解决 GitHub Pages 部署下的子路径访问问题。
- 分析:检查
src/main.tsx和src/App.tsx,确认硬编码的basename导致开发环境空白。 - 动作:通过调研修改配置,引入
import.meta.env.DEV进行动态环境判断,确保本地开发与生产环境配置隔离。
核心任务:建立知识、博客、洞察、工具、笔记、成就的详情展示系统。
- 文件结构:
- 创建
src/content/各模块子目录及示例 Markdown 文档。 - 创建
src/pages/Detail.tsx通用详情组件,集成react-markdown和remark-gfm。
- 创建
- 自动化加载:升级
src/utils/markdown.ts,利用 Vite 的import.meta.glob实现内容自动扫描与热加载,降低维护成本。
核心任务:修复控制台
Buffer is not defined报错及数据加载卡死问题。- 报错排查:确认
gray-matter依赖 Node.js 模块,在浏览器端运行抛出 ReferenceError。 - 解决方案:彻底移除
gray-matter,在markdown.ts中手动实现轻量级正则解析器提取 Frontmatter。同时修正了import.meta.glob的相对路径匹配逻辑,解决数据无法读取的问题。 - 稳定性提升:在各模块页面增加异步捕获与状态恢复逻辑,确保 UI 加载反馈准确。
核心任务:协助用户完成站点定制化并录入真实荣誉数据。
- 荣誉文档:在
src/content/achievements/录入职场(最佳猎手、Top Biller)与学术(奖学金、优秀毕业生)高质量 Markdown 内容。 - 定制指引:
- Logo/文本:修改
src/layouts/Layout.tsx将 "Portal." 更改为个人品牌 "Chandler"。 - SEO/标题:优化
index.html中的 Title 与 Meta Description。 - 个人简介:更新
src/pages/Home.tsx中的 Hero 核心文案。 - 主题色彩:调整
src/index.css中的 HSL 变量以切换视觉风格。
- Logo/文本:修改
核心任务:建立标准化的内容运维体系。
- 成果:编写了详细的 CRUD 教程,涵盖新增、删除、修改、查询内容的标准流程与技术细节,确保项目的长期可维护性。
核心任务:引入 AntV G2/G6/Infographic 提供全方位的可视化能力。
- 组件开发:
G2Chart.tsx: 基于 G2 5.x 封装的声明式统计图表组件。G6Graph.tsx: 基于 G6 5.x 封装的关系图/树图组件,修复了 ESM 模块导出兼容性问题。InfographicChart.tsx: 基于 Infographic 0.2.x 封装的信息图表组件,支持极简 DSL。
- 渲染引擎:在
Detail.tsx中扩展react-markdown处理器,识别g2、g6和infographic代码块并动态渲染对应组件。 - 示例库:创建
src/content/visualization/gallery.md和infographic-gallery.md,提供 15+ 种场景配置。
- 解决:相对路径引用的图片在子路径部署时易失效。建议将图片存放在
项目集成了 AntV G2 (统计图表)、G6 (关系图谱) 与 Infographic (信息图表) 库,支持在 Markdown/MDX 中通过代码块直接渲染交互式图表。
在任何 Markdown 文件中,使用 g2、g6 或 infographic 语言标识的代码块并编写配置:
infographic list-row-simple-horizontal-arrow
data
items
- label: 步骤1
desc: 描述1
+### 2. 图表分类索引 + +详细示例请访问项目中的 图表全集。 +
| 分类 | 支持类型 |
|---|---|
| G2 统计图表 | 折线图、柱状图、饼图/玫瑰图、散点气泡图、渐变面积图、甘特图 |
| G6 关系图谱 | 组织架构图、关系网络图、桑基图、流程图、时间线图 |
| Infographic | 流程图、组织架构、思维导图、指标卡片、数据摘要 |
### 3. 配置参数说明
#### G2 核心参数
- `type`: 图表类型 (`line`, `interval`, `point`, `area` 等)
- `data`: 数据源数组
- `encode`: 字段映射 (`x`, `y`, `color`, `size`)
- `coordinate`: 坐标系配置
#### G6 核心参数
- `data`: 节点 (`nodes`) 与 边 (`edges`) 数据
- `layout`: 布局算法 (`force`, `dagre`, `compactBox`)
- `behaviors`: 交互行为 (`drag-canvas`, `zoom-canvas`, `collapse-expand`)
#### Infographic 核心参数
- `DSL`: 极简的声明式文本描述数据与结构。
### 4. 常见问题 (FAQ)
**Q: 为什么图表没有显示?**
A: 请检查代码块语言标识是否为 `g2`、`g6` 或 `infographic`;确保配置内容格式正确;检查浏览器控制台是否有语法错误。
**Q: 如何调整图表高度?**
A: 默认高度由组件统一控制。若需个性化调整,可在对应组件中修改 `height` 配置。
**Q: G6 导出错误 (Uncaught SyntaxError)?**
A: 项目采用 ESM 规范,必须使用 `import { Graph } from '@antv/g6'` 具名导入方式。
项目支持在 Markdown 内容中嵌入音频和视频,提供两种配置方式满足不同场景需求。
仅适用于 interviews 模块,通过 Frontmatter 中的 multimedia 数组配置多媒体内容。
---
title: "采访标题"
date: "2026-02-07"
guestName: "张三"
guestTitle: "AI 研究员"
guestOrg: "某公司"
guestAvatar: "/avatar.jpg"
guestDescription: "嘉宾简介"
guestAchievements: ["成就1", "成就2"]
multimedia: [
{"type": "video", "url": "/videos/interview.mp4", "caption": "采访现场"},
{"type": "audio", "url": "/audio/podcast.mp3", "caption": "播客录音"},
{"type": "image", "url": "/images/photo.jpg", "caption": "合影留念"}
]
interviewRecords: [
{"timestamp": "00:00", "question": "问题1", "answer": "回答1"}
]
---| type | 说明 | 渲染效果 |
|---|---|---|
video |
视频文件 | HTML5 video 播放器 |
audio |
音频文件 | HTML5 audio 播放器(带动效图标) |
image |
图片文件 | 响应式图片展示 |
- 单张媒体:居中显示,最大宽度限制
- 多张媒体:响应式网格布局(桌面端双列,移动端单列)
- 交互效果:悬停时图片轻微放大,带阴影增强
由于 Detail.tsx 使用了 rehypeRaw 插件,所有模块都支持直接在 Markdown 中编写 HTML 标签嵌入音视频。
本地视频文件
<video controls width="100%" style="border-radius: 8px;">
<source src="/videos/demo.mp4" type="video/mp4">
您的浏览器不支持视频播放
</video>外部视频直链
<video controls width="100%">
<source src="https://example.com/video.mp4" type="video/mp4">
</video>嵌入第三方平台(B站、YouTube等)
<iframe
src="https://player.bilibili.com/player.html?bvid=BV1xx411c7XX"
width="100%"
height="600"
frameborder="0"
allowfullscreen>
</iframe>本地音频文件
<audio controls style="width:100%; margin: 16px 0;">
<source src="/audio/podcast.mp3" type="audio/mpeg">
您的浏览器不支持音频播放
</audio>外部音频直链
<audio controls style="width:100%;">
<source src="https://example.com/audio.mp3" type="audio/mpeg">
</audio>| 类型 | 本地存放路径 | URL 引用方式 |
|---|---|---|
| 视频文件 | public/videos/demo.mp4 |
/videos/demo.mp4 |
| 音频文件 | public/audio/podcast.mp3 |
/audio/podcast.mp3 |
| 外部资源 | - | 使用完整 URL |
以下是一个包含音视频的博客文章示例:
---
title: "技术分享:AI 发展趋势"
date: "2026-02-07"
category: "Tech"
summary: "本期视频分享 AI 最新进展"
---
# AI 发展趋势解读
## 视频回顾
<video controls width="100%" style="border-radius: 8px;">
<source src="/videos/ai-trend-2026.mp4" type="video/mp4">
</video>
## 播客音频版
<audio controls style="width:100%; margin: 16px 0;">
<source src="/audio/ai-podcast-ep1.mp3" type="audio/mpeg">
</audio>
## 相关内容
这是正文内容...| 特性 | multimedia 字段 | HTML 标签 |
|---|---|---|
| 适用模块 | 仅 interviews | 所有模块 |
| 配置位置 | Frontmatter | Markdown 正文 |
| 布局控制 | 自动网格布局 | 手动控制样式 |
| 字幕支持 | 支持 caption | 需手动添加 |
| 灵活性 | 结构化配置 | 完全自定义 |
| 推荐场景 | 采访多媒体画廊 | 博客/文章内嵌 |
-
文件格式:
- 视频推荐:MP4 (H.264 编码)
- 音频推荐:MP3 或 AAC
- 确保格式兼容主流浏览器
-
文件大小:
- 建议视频压缩至合理大小(< 50MB)
- 大文件会影响页面加载速度
-
路径格式:
- 本地文件路径必须以
/开头 - 外部链接使用完整 URL(包含
https://)
- 本地文件路径必须以
-
跨域问题:
- 外部视频/音频可能受 CORS 限制
- 建议将重要媒体文件存放在
public/目录
-
移动端适配:
- 使用
width="100%"确保响应式显示 - iOS 设备部分视频需要用户手动播放
- 使用
Q: 视频无法播放怎么办?
A: 检查以下几点:
- 文件是否正确放置在
public/目录下 - 路径是否以
/开头 - 视频格式是否为浏览器支持的格式(推荐 MP4)
- 可尝试在浏览器直接访问视频 URL 验证
Q: 如何添加视频封面图?
A: 使用 poster 属性:
<video controls poster="/images/cover.jpg">
<source src="/videos/demo.mp4" type="video/mp4">
</video>Q: 能否自动播放视频?
A: 可以添加 autoplay muted 属性,但注意:
- 大多数浏览器要求自动播放的视频必须静音
- 自动播放可能影响用户体验,请谨慎使用
Q: B站视频嵌入后无法播放?
A: B站 iframe 嵌入需要使用正确的播放器 URL 格式,并确保视频允许外链播放。