Skip to content

Commit fc0689b

Browse files
authored
feat(say-server): add light/dark theme support (#338)
- Add importmap entry for main SDK exports (applyDocumentTheme, etc.) - Import and apply host theme and styles on context changes - Apply initial host context theme/styles when app connects - Update CSS to use [data-theme="dark"] selector for host-provided themes - Keep @media prefers-color-scheme as fallback for standalone mode - Add color-scheme meta tag for native element theming
1 parent cf9fed1 commit fc0689b

1 file changed

Lines changed: 30 additions & 1 deletion

File tree

examples/say-server/server.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,13 +672,15 @@ def generate_sync():
672672
<head>
673673
<meta charset="UTF-8">
674674
<meta name="viewport" content="width=device-width, initial-scale=1.0">
675+
<meta name="color-scheme" content="light dark">
675676
<title>Say View</title>
676677
<script src="https://unpkg.com/@babel/standalone@7.26.10/babel.min.js"></script>
677678
<script type="importmap">
678679
{
679680
"imports": {
680681
"react": "https://esm.sh/react@19.2.0",
681682
"react-dom/client": "https://esm.sh/react-dom@19.2.0/client",
683+
"@modelcontextprotocol/ext-apps": "https://esm.sh/@modelcontextprotocol/ext-apps@0.4.1?deps=zod@3.25.1&external=react,react-dom",
682684
"@modelcontextprotocol/ext-apps/react": "https://esm.sh/@modelcontextprotocol/ext-apps@0.4.1/react?deps=zod@3.25.1&external=react,react-dom"
683685
}
684686
}
@@ -769,8 +771,14 @@ def generate_sync():
769771
.infoPopup a:hover { text-decoration: underline; }
770772
.infoPopup ul { margin: 0; padding-left: 16px; }
771773
.infoPopup li { margin: 4px 0; }
774+
/* Dark mode: host-provided theme via data-theme attribute */
775+
[data-theme="dark"] {
776+
--color-text-primary: #eee;
777+
--color-text-secondary: #666;
778+
}
779+
/* Fallback: system preference when running standalone without host */
772780
@media (prefers-color-scheme: dark) {
773-
:root {
781+
:root:not([data-theme]) {
774782
--color-text-primary: #eee;
775783
--color-text-secondary: #666;
776784
}
@@ -783,6 +791,7 @@ def generate_sync():
783791
import React, { useState, useCallback, useEffect, useRef, StrictMode } from 'react';
784792
import { createRoot } from 'react-dom/client';
785793
import { useApp } from '@modelcontextprotocol/ext-apps/react';
794+
import { applyDocumentTheme, applyHostStyleVariables, applyHostFonts } from '@modelcontextprotocol/ext-apps';
786795
787796
function SayView() {
788797
const [hostContext, setHostContext] = useState(undefined);
@@ -1251,6 +1260,16 @@ def generate_sync():
12511260
if (params.displayMode) {
12521261
setDisplayMode(params.displayMode);
12531262
}
1263+
// Apply host theme and styles
1264+
if (params.theme) {
1265+
applyDocumentTheme(params.theme);
1266+
}
1267+
if (params.styles?.variables) {
1268+
applyHostStyleVariables(params.styles.variables);
1269+
}
1270+
if (params.styles?.css?.fonts) {
1271+
applyHostFonts(params.styles.css.fonts);
1272+
}
12541273
};
12551274
},
12561275
});
@@ -1265,6 +1284,16 @@ def generate_sync():
12651284
if (ctx?.displayMode) {
12661285
setDisplayMode(ctx.displayMode);
12671286
}
1287+
// Apply initial host theme and styles
1288+
if (ctx?.theme) {
1289+
applyDocumentTheme(ctx.theme);
1290+
}
1291+
if (ctx?.styles?.variables) {
1292+
applyHostStyleVariables(ctx.styles.variables);
1293+
}
1294+
if (ctx?.styles?.css?.fonts) {
1295+
applyHostFonts(ctx.styles.css.fonts);
1296+
}
12681297
}, [app]);
12691298
12701299
// Speak lock: coordinate with other TTS Views

0 commit comments

Comments
 (0)