155 lines
6.4 KiB
Markdown
155 lines
6.4 KiB
Markdown
# 公开页 · iframe 嵌入外观对接说明(主题 / 背景色)
|
||
|
||
本文档面向**嵌入方(宿主系统)**,说明如何在用 `<iframe>` 嵌入 DeerFlow 公开页时,从外部控制页面的**整体明暗主题(light/dark)**与**背景色 / 文字色**,使其与宿主站点的视觉风格保持一致。
|
||
|
||
前端实现见:`src/core/embed/background.ts`(参数解析与 postMessage 监听)、`src/App.tsx`(主题接入 `forcedTheme`)。
|
||
|
||
---
|
||
|
||
## 0. 速读
|
||
|
||
| 想做什么 | 怎么做 |
|
||
|----------|--------|
|
||
| 嵌入时指定深色主题 | iframe `src` 加 `?theme=dark` |
|
||
| 嵌入时指定背景/文字色 | iframe `src` 加 `?bg=%23001529&text=%23ffffff`(`#` 需编码为 `%23`) |
|
||
| 宿主切主题时同步切换 | `postMessage({ type: "deerflow:set-theme", theme: "dark" }, "*")` |
|
||
| 宿主动态改背景色 | `postMessage({ type: "deerflow:set-bg", bg: "#001529", text: "#fff" }, "*")` |
|
||
| 什么都不传 | 页面使用 DeerFlow 自带默认配色,互不影响 |
|
||
|
||
---
|
||
|
||
## 1. 适用页面
|
||
|
||
以下公开页(免登录、只读)均支持本文档的全部参数:
|
||
|
||
| 页面 | 路由 |
|
||
|------|------|
|
||
| 会话分享页 | `/#/share/{shareCode}` |
|
||
| 圆桌分享页 | `/#/roundtable-share/{shareCode}`、`/#/roundtable-share/{shareCode}/report` |
|
||
| 用户排行榜 | `/#/public/leaderboard` |
|
||
| 定时任务公开页 | `/#/public/scheduled-tasks/{taskId}`(含 `/runs/{runId}/fullscreen` 全屏页) |
|
||
|
||
> 注意:站点使用 **hash 路由**,路径在 `#` 之后。
|
||
> 嵌入聊天页(`/#/embed/chats/*`、`/#/embed/roundtable`)有自己的主题约定,见 `embed-iframe-chat.md`,不在本文范围内。
|
||
|
||
---
|
||
|
||
## 2. URL 查询参数(嵌入时一次性指定)
|
||
|
||
### 2.1 参数列表
|
||
|
||
| 参数 | 别名 | 作用 | 合法值 |
|
||
|------|------|------|--------|
|
||
| `theme` | — | 切整体明暗主题 | 见 2.2 取值映射表 |
|
||
| `bg` | `background` | 页面根容器背景色 | 见 2.3 颜色格式 |
|
||
| `text` | `fg` | 页面根容器文字色 | 见 2.3 颜色格式 |
|
||
|
||
三个参数相互独立,可任意组合;不传或传非法值时该项忽略、沿用默认。
|
||
|
||
### 2.2 `theme` 取值映射
|
||
|
||
| 传入值(不区分大小写) | 实际主题 |
|
||
|------|------|
|
||
| `dark`、`dark-blue`、`深蓝`、`深色` | 深色 |
|
||
| `light`、`red`、`红白`、`浅色` | 浅色 |
|
||
| 其他 / 不传 | 忽略,沿用站内默认(浅色) |
|
||
|
||
### 2.3 颜色格式(`bg` / `text`)
|
||
|
||
颜色值经过白名单校验,仅接受以下写法,其余一律丢弃(防注入):
|
||
|
||
- **hex**:`#fff`、`#ffffffcc` 等 3/4/6/8 位(`#` 可省略;URL 里 `#` 必须编码为 `%23`)
|
||
- **函数式**:`rgb()` / `rgba()` / `hsl()` / `hsla()`,括号内仅允许数字、逗号、百分号、空格、`/`
|
||
- **命名色**:纯英文字母,如 `white`、`transparent`
|
||
|
||
### 2.4 参数位置
|
||
|
||
参数放在 hash 路由之后(推荐)或 `#` 之前都能识别;两处都传时**hash 路由内的优先**:
|
||
|
||
```
|
||
https://<host>/#/public/leaderboard?theme=dark ← 推荐
|
||
https://<host>/?theme=dark#/public/leaderboard ← 也支持
|
||
```
|
||
|
||
### 2.5 示例
|
||
|
||
```html
|
||
<!-- 深色主题 -->
|
||
<iframe src="https://<host>/#/public/leaderboard?theme=dark"></iframe>
|
||
|
||
<!-- 浅色主题 + 自定义背景与文字色(# 编码为 %23) -->
|
||
<iframe src="https://<host>/#/share/Ab3xYz?theme=light&bg=%23f5f7fa&text=%23333333"></iframe>
|
||
|
||
<!-- 主题与背景叠加:整页走深色变量,根背景用宿主品牌色 -->
|
||
<iframe src="https://<host>/#/roundtable-share/Ab3xYz?theme=dark&bg=%23001529"></iframe>
|
||
```
|
||
|
||
---
|
||
|
||
## 3. postMessage(嵌入后动态切换)
|
||
|
||
适用于宿主站点支持用户切主题、需要 iframe 实时跟随的场景。向 iframe 的 `contentWindow` 发消息即可,**无需等待子页面回执**(监听器在应用挂载时注册)。
|
||
|
||
### 3.1 消息格式
|
||
|
||
```js
|
||
const frame = document.getElementById("deerflow-frame");
|
||
|
||
// 切整体明暗主题(theme 取值同 2.2)
|
||
frame.contentWindow.postMessage({ type: "deerflow:set-theme", theme: "dark" }, "*");
|
||
|
||
// 改背景色 / 文字色(字段名与 URL 参数一致,bg/background、text/fg 均可)
|
||
frame.contentWindow.postMessage({ type: "deerflow:set-bg", bg: "#001529", text: "#fff" }, "*");
|
||
// 兼容别名:type 也可写 "deerflow:set-background"
|
||
```
|
||
|
||
说明:
|
||
|
||
- 两类消息相互独立,可只发其一;`set-bg` 里 `bg`、`text` 也可只传其一,未传的字段保持当前值。
|
||
- 非法颜色值 / 不认识的 `theme` 取值会被忽略,不会清空已有设置。
|
||
- targetOrigin 建议按需收紧(写 DeerFlow 站点的 origin 而非 `"*"`)。
|
||
|
||
### 3.2 宿主主题联动示例
|
||
|
||
```js
|
||
function syncDeerflowTheme(isDark) {
|
||
const win = document.getElementById("deerflow-frame").contentWindow;
|
||
win.postMessage({ type: "deerflow:set-theme", theme: isDark ? "dark" : "light" }, "*");
|
||
win.postMessage(
|
||
{ type: "deerflow:set-bg", bg: isDark ? "#001529" : "#ffffff" },
|
||
"*",
|
||
);
|
||
}
|
||
|
||
// iframe 首次加载用 URL 参数兜底,之后切换走 postMessage
|
||
myThemeStore.subscribe((theme) => syncDeerflowTheme(theme === "dark"));
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 优先级与默认行为
|
||
|
||
同一项配置多处传入时,按以下优先级取值(高 → 低):
|
||
|
||
1. **postMessage** 动态设置的值
|
||
2. hash 路由内的 URL 参数(`#/路由?theme=...`)
|
||
3. `#` 之前的 URL 参数(`?theme=...#/路由`)
|
||
4. 都没传 → DeerFlow 默认配色(浅色主题 + 页面自带 Tailwind 配色)
|
||
|
||
其他保证:
|
||
|
||
- 外部主题只影响**当前 iframe 的渲染**,不写 localStorage——不会污染用户直接访问 DeerFlow 主站时自己选择的主题。
|
||
- `bg`/`text` 是内联样式,作用在页面根容器上,优先级高于主题变量;与 `theme` 叠加时以 `bg`/`text` 为准。
|
||
|
||
---
|
||
|
||
## 5. 常见问题排查
|
||
|
||
| 现象 | 排查 |
|
||
|------|------|
|
||
| `theme=dark` 不生效 | 确认路由属于第 1 节列出的公开页;确认参数拼在 hash 路由后(`/#/share/xx?theme=dark`),而不是写成了 `/#/share/xx#theme=dark` |
|
||
| `bg=#fff` 不生效 | URL 里 `#` 没编码会被浏览器截断,必须写 `%23fff`;或直接省略 `#` 写 `bg=fff` |
|
||
| postMessage 无反应 | 确认消息体是对象且 `type` 拼写为 `deerflow:set-theme` / `deerflow:set-bg`;确认在 iframe `load` 之后发送 |
|
||
| 颜色被忽略 | 检查是否符合 2.3 白名单格式(如 `linear-gradient(...)` 等复杂值不支持) |
|
||
| 主题切了但个别区域颜色没变 | 该区域可能使用了固定配色;把页面路由与截图反馈给 DeerFlow 维护方补充 `dark:` 样式 |
|