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는 16진수 색상뿐만 아니라 전체 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";
앱 셸에서 해당 변수들을 사용하세요.
html,
body,
#root {
min-height: 100%;
margin: 0;
}
body {
background: var(--chastify-bg);
color: var(--chastify-text);
}
.panel {
border: 1px solid var(--chastify-border);
}
리액트 예제
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;
};
};
해당 메시지를 수신하고 논스를 확인하십시오.
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를 단순한 16진수 색상으로 취급합니다. 이는 그라데이션이거나 브라우저에서 정규화된 CSS 배경 문자열일 수 있습니다.- 배경색과 텍스트 색상을 모두 설정하지 않고 기본 폼 컨트롤을 사용하는 경우, 어두운 테마에서 선택 옵션이 읽기 어려워질 수 있습니다.
- 테마 변경 시 iframe 새로 고침이 필요하다고 가정합니다. 실시간 업데이트를 원하시면
chastify:ext:ui신호를 수신하세요.
테마 데이터는 프레젠테이션용 데이터일 뿐입니다. 권한 부여, 신뢰도 판단, 잠금 해제 로직, 보상, 처벌 또는 백엔드 세션 ID 관리에 사용하지 마십시오.
체크리스트
iframe 확장 프로그램을 게시하기 전에 다음 사항을 확인하세요.
- 라이트 테마를 테스트해 보세요.
- 다크 모드를 테스트해 보세요.
- 사용자 지정 테마가 있다면 테스트해 보세요.
- 모든 카드, 버튼, 배지, 폼 컨트롤, 진행률 링 및 결과 메시지의 대비가 읽기 쉬운지 확인하십시오.
- 모바일 화면에 텍스트가 제대로 표시되는지 확인하세요.
- 테마 또는 콘텐츠 변경 후 iframe의 크기가 자동으로 조정되는지 확인하십시오.
다음: Iframe 빠른 시작 또는 API 예제.