ext-apps/examples/basic-host/src/theme.ts
Olivier Chafik 7bbf2bb250
feat(basic-host): Add theme toggle and MCP style variables (#336)
* feat(basic-host): add theme toggle and MCP style variables

Add theme support to basic-host example:
- theme.ts: Global theme manager with light/dark toggle
- host-styles.ts: Full set of MCP CSS variables using light-dark()
- ThemeToggle component with sun/moon icons
- Theme-aware CSS using CSS custom properties
- Pass theme + styles to apps via hostContext
- Notify apps when theme changes via sendHostContextChange

Apps now receive:
- hostContext.theme: 'light' | 'dark'
- hostContext.styles.variables: All 60+ MCP CSS variables
- onhostcontextchanged notifications when theme changes

* test: update e2e goldens for theme changes
2026-01-23 20:41:26 +00:00

64 lines
1.5 KiB
TypeScript

/**
* Simple theme manager for the basic-host example.
* Manages light/dark theme state and notifies listeners.
*/
export type Theme = "light" | "dark";
type ThemeListener = (theme: Theme) => void;
const listeners = new Set<ThemeListener>();
// Get initial theme from system preference
let currentTheme: Theme = window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
// Apply theme to document
function applyTheme(theme: Theme) {
document.documentElement.setAttribute("data-theme", theme);
document.documentElement.style.colorScheme = theme;
}
// Initial application
applyTheme(currentTheme);
/**
* Get current theme.
*/
export function getTheme(): Theme {
return currentTheme;
}
/**
* Set theme and notify all listeners.
*/
export function setTheme(theme: Theme): void {
if (theme === currentTheme) return;
currentTheme = theme;
applyTheme(theme);
listeners.forEach((listener) => listener(theme));
}
/**
* Toggle between light and dark themes.
*/
export function toggleTheme(): Theme {
const newTheme = currentTheme === "dark" ? "light" : "dark";
setTheme(newTheme);
return newTheme;
}
/**
* Subscribe to theme changes.
* Returns unsubscribe function.
*/
export function onThemeChange(listener: ThemeListener): () => void {
listeners.add(listener);
return () => listeners.delete(listener);
}
// Also listen for system preference changes
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => {
setTheme(e.matches ? "dark" : "light");
});