跳到主要内容

iframe 主题

Chastify 向 iframe 扩展发送主题信息,以便您的 UI 可以与嵌入它的锁定页面相匹配。

不要假定用户使用的是深色主题。您的扩展程序可以在浅色、深色、自定义、半透明和高对比度主题下打开。

提示

最安全的默认做法是将 iframe ui 有效负载视为页面背景、文本颜色和边框颜色的真实来源,然后从 ui.isDark 派生出您自己的可读面板和徽章。

主题有效载荷

当 Chastify 打开您的 iframe 时,它​​会将 URI 编码的 JSON 有效负载附加到 location.hash

有效载荷包含 ui

{
"bridge": {
"v": 1,
"nonce": "request-nonce",
"parentOrigin": "https://chastify.net"
},
"sessionId": "extension-session-id",
"lockId": "lock-id",
"ui": {
"isDark": true,
"bg": "rgb(10, 10, 10)",
"text": "#e5e7eb",
"border": "#27272a"
}
}

字段含义:

  • ui.isDark:主机页面当前是否使用深色主题。
  • ui.bg:来自主机的页面/表面背景。这可能是纯色或复杂的 CSS 背景。
  • ui.text:主要可读文本颜色。
  • ui.border:与主机主题相匹配的边框颜色。
警告

ui.bg 可以是一个完整的 CSS 背景字符串,而不仅仅是一个十六进制颜色值。请将其用作 CSS 值 background,而不是手动解析的值。

解析哈希值

type ChastifyThemePayload = {
ui?: {
isDark?: boolean;
bg?: string;
text?: string;
border?: string;
};
};

export function parseHashPayload(): ChastifyThemePayload | null {
const raw = window.location.hash.startsWith("#")
? window.location.hash.slice(1)
: window.location.hash;

if (!raw) return null;

try {
return JSON.parse(decodeURIComponent(raw));
} catch {
return null;
}
}

最小CSS变量

启动时将有效负载转换为 CSS 变量:

const payload = parseHashPayload();
const ui = payload?.ui ?? {};
const isDark = ui.isDark !== false;

document.documentElement.style.setProperty("--chastify-bg", ui.bg || (isDark ? "#040711" : "#f8fafc"));
document.documentElement.style.setProperty("--chastify-text", ui.text || (isDark ? "#e5e7eb" : "#0f172a"));
document.documentElement.style.setProperty("--chastify-border", ui.border || (isDark ? "#27272a" : "#e2e8f0"));
document.documentElement.dataset.themeMode = isDark ? "dark" : "light";

在应用程序 shell 中使用这些变量:

html,
body,
#root {
min-height: 100%;
margin: 0;
}

body {
background: var(--chastify-bg);
color: var(--chastify-text);
}

.panel {
border: 1px solid var(--chastify-border);
}

React 示例

import { useMemo } from "react";

function getTheme(payload: any) {
const ui = payload?.ui ?? {};
const isDark = ui.isDark !== false;

return {
isDark,
pageStyle: {
background: ui.bg || (isDark ? "#040711" : "#f8fafc"),
color: ui.text || (isDark ? "#e5e7eb" : "#0f172a"),
} satisfies React.CSSProperties,
panelClass: isDark
? "border-white/10 bg-black/35 text-slate-100"
: "border-slate-200 bg-white/85 text-slate-950 shadow-sm",
mutedClass: isDark ? "text-slate-400" : "text-slate-600",
badgeClass: isDark
? "bg-sky-400/15 text-sky-200"
: "bg-sky-50 text-sky-900 ring-1 ring-sky-200",
};
}

export function ExtensionApp({ payload }: { payload: any }) {
const theme = useMemo(() => getTheme(payload), [payload]);

return (
<main style={theme.pageStyle} className="min-h-screen p-4">
<section className={`rounded-2xl border p-4 ${theme.panelClass}`}>
<h1 className="text-xl font-bold">My Extension</h1>
<p className={`mt-2 text-sm ${theme.mutedClass}`}>
This text stays readable on light and dark Chastify themes.
</p>
<span className={`mt-3 inline-flex rounded-full px-3 py-1 text-xs font-semibold ${theme.badgeClass}`}>
Connected
</span>
</section>
</main>
);
}

顺风模式

如果使用 Tailwind,则从 ui.isDark 为每个包含文本的表面创建分支。

const isDarkTheme = payload?.ui?.isDark !== false;

const panelClass = isDarkTheme
? "border-white/10 bg-black/30 text-slate-100"
: "border-slate-200 bg-white/85 text-slate-950 shadow-sm";

const successClass = isDarkTheme
? "border-emerald-300/20 bg-emerald-400/10 text-emerald-100"
: "border-emerald-500/25 bg-emerald-50 text-emerald-950";

const errorClass = isDarkTheme
? "border-rose-300/20 bg-rose-400/10 text-rose-100"
: "border-rose-500/25 bg-rose-50 text-rose-950";

在文本渲染位置使用选定的类:

<div className={`rounded-xl border px-3 py-2 text-sm ${result.ok ? successClass : errorClass}`}>
<div className="font-semibold">{result.title}</div>
<div className="mt-1 opacity-85">{result.message}</div>
</div>

实时主题更新

当您的 iframe 打开时,父级可能会发送实时主题更新:

type UiUpdateMessage = {
type: "chastify:ext:ui";
v: 1;
nonce: string;
ui: {
isDark?: boolean;
bg?: string;
text?: string;
border?: string;
};
};

监听该消息并验证 nonce 值:

const nonce = payload.bridge.nonce;
const parentOrigin = payload.bridge.parentOrigin;

window.addEventListener("message", (event) => {
if (event.origin !== parentOrigin) return;

const msg = event.data as Partial<UiUpdateMessage>;
if (msg.type !== "chastify:ext:ui" || msg.v !== 1) return;
if (msg.nonce !== nonce) return;

applyTheme(msg.ui);
});

常见错误

  • 卡片内硬编码 text-white 或浅色 text-*-100,而没有浅色主题替代方案。
  • 只关注页面背景的样式,却忽略了嵌套卡片、徽章、进度环和结果流。
  • ui.bg 视为简单的十六进制颜色值。它可以是渐变色,也可以是浏览器规范化的 CSS 背景字符串。
  • 使用原生表单控件时,如果未同时设置背景色和文本颜色,则在深色主题下,选择选项可能难以辨认。
  • 假设主题更改需要重新加载 iframe。如果您想获取实时更新,请监听 chastify:ext:ui
注意

主题数据仅用于展示。请勿将其用于授权、信任决策、解锁逻辑、奖励、惩罚或后端会话身份。

检查清单

发布 iframe 扩展程序之前:

  • 测试灯光主题。
  • 测试深色主题。
  • 如有可用,请测试自定义主题。
  • 检查所有卡片、按钮、徽章、表单控件、进度环和结果消息是否具有清晰的对比度。
  • 确认文本在移动设备上仍然能够完整显示。
  • 验证 iframe 在主题或内容更改后是否自动调整大小。

接下来:Iframe 快速入门API 示例