Skip to content

Commit 9a08bf6

Browse files
authored
feat: support theme control via postMessage for iframe embedding (#32)
## Summary - Adds a `postMessage` listener to `UIStore` that accepts `{type: "theme:set", theme: "light"|"dark"}` messages - Enables parent windows to control agentsview's theme without reloading the iframe - Closes #31 ## Details When agentsview is embedded as a cross-origin iframe, the host application can now send a `theme:set` message to switch themes instantly. This avoids the jarring reload previously needed when using the `?theme=` URL parameter approach. The implementation is minimal — a single `window.addEventListener("message", ...)` in the UIStore constructor. Since `this.theme` is a `$state` field, assigning it triggers the existing `$effect` that updates the DOM class and persists to localStorage. ## Protocol ```js iframe.contentWindow.postMessage({ type: "theme:set", theme: "dark" }, "*"); ``` Only `"light"` and `"dark"` are accepted; other values are silently ignored. ## Test plan - [x] Valid `theme:set` message changes theme - [x] Invalid theme value (e.g. "purple") is ignored - [x] Unrelated message types are ignored - [x] Full test suite passes (384/384, +3 new)
1 parent 8634987 commit 9a08bf6

2 files changed

Lines changed: 45 additions & 0 deletions

File tree

frontend/src/lib/stores/ui.svelte.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,19 @@ class UIStore {
4444
}
4545
});
4646
});
47+
48+
// Allow parent windows to control theme via postMessage
49+
if (typeof window !== "undefined") {
50+
window.addEventListener("message", (event: MessageEvent) => {
51+
if (
52+
event.data &&
53+
event.data.type === "theme:set" &&
54+
(event.data.theme === "light" || event.data.theme === "dark")
55+
) {
56+
this.theme = event.data.theme;
57+
}
58+
});
59+
}
4760
}
4861

4962
toggleTheme() {

frontend/src/lib/stores/ui.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,38 @@ describe("UIStore", () => {
172172
});
173173
});
174174

175+
describe("postMessage theme control", () => {
176+
it("should change theme on valid theme:set message", () => {
177+
ui.theme = "light";
178+
window.dispatchEvent(
179+
new MessageEvent("message", {
180+
data: { type: "theme:set", theme: "dark" },
181+
}),
182+
);
183+
expect(ui.theme).toBe("dark");
184+
});
185+
186+
it("should ignore invalid theme values", () => {
187+
ui.theme = "light";
188+
window.dispatchEvent(
189+
new MessageEvent("message", {
190+
data: { type: "theme:set", theme: "purple" },
191+
}),
192+
);
193+
expect(ui.theme).toBe("light");
194+
});
195+
196+
it("should ignore unrelated message types", () => {
197+
ui.theme = "light";
198+
window.dispatchEvent(
199+
new MessageEvent("message", {
200+
data: { type: "some-other-event", theme: "dark" },
201+
}),
202+
);
203+
expect(ui.theme).toBe("light");
204+
});
205+
});
206+
175207
describe("toggles", () => {
176208
it("should toggle theme between light and dark", () => {
177209
ui.theme = "light";

0 commit comments

Comments
 (0)