Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions examples/customer-segmentation-server/mcp-app.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
<main class="main">
<header class="header">
<h1 class="title">Customer Segmentation</h1>
<button id="fullscreen-btn" class="fullscreen-btn" title="Toggle fullscreen">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.22461 11.082C8.41868 10.9539 8.68265 10.9756 8.85352 11.1465C9.02437 11.3173 9.04613 11.5813 8.91797 11.7754L8.85352 11.8535L4.70703 16H7.5C7.77614 16 8 16.2239 8 16.5C8 16.7761 7.77614 17 7.5 17H3.5C3.46695 17 3.43389 16.9967 3.40137 16.9902H3.39941C3.33993 16.9781 3.2851 16.9541 3.23535 16.9229C3.22314 16.9152 3.21185 16.9063 3.2002 16.8975C3.18573 16.8865 3.17138 16.8757 3.1582 16.8633C3.15452 16.8598 3.15008 16.8571 3.14648 16.8535C3.14173 16.8488 3.13832 16.8428 3.13379 16.8379C3.12089 16.8239 3.10891 16.8093 3.09766 16.7939C3.08941 16.7827 3.0814 16.7715 3.07422 16.7598C3.0639 16.7429 3.05517 16.7252 3.04688 16.707C3.04311 16.6988 3.03845 16.691 3.03516 16.6826C3.0248 16.6562 3.01653 16.6289 3.01074 16.6006C3.00395 16.5674 3 16.5337 3 16.5V12.5C3 12.2239 3.22386 12 3.5 12C3.77614 12 4 12.2239 4 12.5V15.293L8.14648 11.1465L8.22461 11.082ZM16.5 3C16.5374 3 16.5747 3.00436 16.6113 3.0127C16.6347 3.01803 16.6574 3.02559 16.6797 3.03418C16.687 3.03701 16.6939 3.04076 16.7012 3.04395C16.7213 3.05283 16.7409 3.06272 16.7598 3.07422C16.7675 3.07892 16.7757 3.08274 16.7832 3.08789C16.8082 3.10508 16.8317 3.12471 16.8535 3.14648L16.918 3.22461C16.9289 3.24116 16.9356 3.25988 16.9443 3.27734C16.95 3.28857 16.9572 3.29894 16.9619 3.31055C16.9868 3.37121 17 3.43545 17 3.5V7.5C17 7.77614 16.7761 8 16.5 8C16.2239 8 16 7.77614 16 7.5V4.70703L11.8535 8.85352C11.6583 9.04878 11.3417 9.04878 11.1465 8.85352C10.9512 8.65825 10.9512 8.34175 11.1465 8.14648L15.293 4H12.5C12.2239 4 12 3.77614 12 3.5C12 3.22386 12.2239 3 12.5 3H16.5Z" fill="currentColor"/>
</svg>
</button>
</header>

<section class="controls-section">
Expand Down
53 changes: 53 additions & 0 deletions examples/customer-segmentation-server/src/mcp-app.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
:root {
color-scheme: light dark;

/* Safe area insets (set by JS from host context) */
--safe-area-inset-top: 0px;
--safe-area-inset-right: 0px;
--safe-area-inset-bottom: 0px;
--safe-area-inset-left: 0px;

/* Font families */
--font-sans: system-ui, -apple-system, sans-serif;

Expand Down Expand Up @@ -61,6 +67,17 @@ html, body {
overflow: hidden;
}

/* Fullscreen mode - no border radius, fill container with safe area padding */
[data-display-mode="fullscreen"] .main {
border-radius: 0;
height: 100vh;
max-height: 100vh;
padding-top: var(--safe-area-inset-top);
padding-right: var(--safe-area-inset-right);
padding-bottom: var(--safe-area-inset-bottom);
padding-left: var(--safe-area-inset-left);
}

/* Header - ~40px */
.header {
display: flex;
Expand All @@ -78,6 +95,42 @@ html, body {
flex-shrink: 0;
}

.fullscreen-btn {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
padding: 0;
border: var(--border-width-regular) solid var(--color-border-primary);
border-radius: var(--border-radius-sm);
background: var(--color-background-secondary);
color: var(--color-text-secondary);
cursor: pointer;
transition: all 0.15s ease;
}

.fullscreen-btn:hover {
background: var(--color-background-tertiary);
color: var(--color-text-primary);
box-shadow: var(--shadow-sm);
}

.fullscreen-btn:focus {
outline: 2px solid var(--color-ring-info);
outline-offset: 1px;
}

.fullscreen-btn svg {
width: 16px;
height: 16px;
}

/* Hide fullscreen button when already in fullscreen mode */
[data-display-mode="fullscreen"] .fullscreen-btn {
display: none;
}

.header-controls {
display: flex;
align-items: center;
Expand Down
84 changes: 82 additions & 2 deletions examples/customer-segmentation-server/src/mcp-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,30 @@ const log = {
error: console.error.bind(console, "[APP]"),
};

/**
* Apply safe area insets as CSS custom properties on the document root.
*/
function applySafeAreaInsets(insets: {
top?: number;
right?: number;
bottom?: number;
left?: number;
}) {
const root = document.documentElement;
if (insets.top !== undefined) {
root.style.setProperty("--safe-area-inset-top", `${insets.top}px`);
}
if (insets.right !== undefined) {
root.style.setProperty("--safe-area-inset-right", `${insets.right}px`);
}
if (insets.bottom !== undefined) {
root.style.setProperty("--safe-area-inset-bottom", `${insets.bottom}px`);
}
if (insets.left !== undefined) {
root.style.setProperty("--safe-area-inset-left", `${insets.left}px`);
}
}

// DOM element references
const xAxisSelect = document.getElementById("x-axis") as HTMLSelectElement;
const yAxisSelect = document.getElementById("y-axis") as HTMLSelectElement;
Expand All @@ -32,6 +56,9 @@ const chartCanvas = document.getElementById(
) as HTMLCanvasElement;
const legendContainer = document.getElementById("legend")!;
const detailPanel = document.getElementById("detail-panel")!;
const fullscreenBtn = document.getElementById(
"fullscreen-btn",
) as HTMLButtonElement;

// App state
interface AppState {
Expand Down Expand Up @@ -364,8 +391,11 @@ function resetDetailPanel(): void {
'<span class="detail-placeholder">Hover over a point to see details</span>';
}

// Create app instance
const app = new App({ name: "Customer Segmentation", version: "1.0.0" });
// Create app instance with fullscreen support
const app = new App(
{ name: "Customer Segmentation", version: "1.0.0" },
{ availableDisplayModes: ["inline", "fullscreen"] },
);

// Fetch data from server
async function fetchData(): Promise<void> {
Expand Down Expand Up @@ -419,6 +449,16 @@ sizeMetricSelect.addEventListener("change", () => {
updateChart();
});

// Fullscreen toggle
fullscreenBtn.addEventListener("click", async () => {
try {
const result = await app.requestDisplayMode({ mode: "fullscreen" });
log.info("Display mode changed to:", result.mode);
} catch (error) {
log.error("Failed to change display mode:", error);
}
});

// Clear selection when clicking outside chart
document.addEventListener("click", (e) => {
if (!(e.target as HTMLElement).closest(".chart-section")) {
Expand Down Expand Up @@ -459,6 +499,33 @@ app.onhostcontextchanged = (params) => {
if (params.styles?.css?.fonts) {
applyHostFonts(params.styles.css.fonts);
}
if (params.displayMode) {
document.documentElement.setAttribute(
"data-display-mode",
params.displayMode,
);
}
if (params.safeAreaInsets) {
applySafeAreaInsets(params.safeAreaInsets);
}
// Update container height based on containerDimensions from host
// This ensures the chart resizes correctly during transitions
if (params.containerDimensions) {
const mainEl = document.querySelector(".main") as HTMLElement | null;
if (mainEl) {
if ("height" in params.containerDimensions) {
// If height is fixed, take up all the height
mainEl.style.height = "100vh";
} else if ("maxHeight" in params.containerDimensions) {
// If height is variable, let the rest of the css determine the height
mainEl.style.height = "";
}
// Resize chart after container dimensions change
if (state.chart) {
state.chart.resize();
}
}
}
// Recreate chart to pick up new colors
if (state.chart && (params.theme || params.styles?.variables)) {
state.chart.destroy();
Expand All @@ -478,6 +545,19 @@ app.connect().then(() => {
if (ctx?.styles?.css?.fonts) {
applyHostFonts(ctx.styles.css.fonts);
}
if (ctx?.displayMode) {
document.documentElement.setAttribute("data-display-mode", ctx.displayMode);
}
if (ctx?.safeAreaInsets) {
applySafeAreaInsets(ctx.safeAreaInsets);
}
// Apply initial container dimensions
if (ctx?.containerDimensions) {
const mainEl = document.querySelector(".main") as HTMLElement | null;
if (mainEl && "height" in ctx.containerDimensions) {
mainEl.style.height = `${ctx.containerDimensions.height}px`;
}
}
});

// Fetch data after connection
Expand Down
51 changes: 1 addition & 50 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading