From ba81d7c37fb7a0e5aaf8e598d7783f7535538a45 Mon Sep 17 00:00:00 2001 From: Nicholas Brown Date: Wed, 29 Jul 2026 13:23:36 -0400 Subject: [PATCH 1/2] add language dropdown --- docs/css/language-dropdown.css | 57 +++++++++++++++++++++++++ docs/language-dropdown.js | 77 ++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 docs/css/language-dropdown.css create mode 100644 docs/language-dropdown.js diff --git a/docs/css/language-dropdown.css b/docs/css/language-dropdown.css new file mode 100644 index 000000000..0eb810545 --- /dev/null +++ b/docs/css/language-dropdown.css @@ -0,0 +1,57 @@ +/* Language dropdown: injected by language-dropdown.js into the sidebar + footer, to the right of Mintlify's theme selector. Mirrors the almond + theme pill's exact metrics (lg:h-7 desktop / 2.375rem mobile, rounded-full, + border-gray-200/70, dark:border-white/[0.07]) so the two controls read as + one family. */ +#language-switch { + margin-left: auto; + display: inline-flex; + align-items: center; +} + +#language-switch select { + appearance: none; + -webkit-appearance: none; + background-color: transparent; + border: 1px solid rgb(229 231 235 / 0.7); + border-radius: 9999px; + color: rgb(107 114 128); + cursor: pointer; + font-size: 0.75rem; + line-height: 1rem; + height: 2.375rem; + padding: 0 1.375rem 0 0.75rem; + /* Chevron, drawn in the same gray as the label text. */ + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 0.5rem center; + background-size: 0.7rem; + transition: border-color 0.2s; +} + +@media (min-width: 1024px) { + #language-switch select { + height: 1.75rem; + } +} + +#language-switch select:hover { + color: rgb(75 85 99); + border-color: rgb(229 231 235); +} + +#language-switch select:focus-visible { + outline: 2px solid rgb(45 0 247 / 0.4); + outline-offset: 1px; +} + +.dark #language-switch select { + border-color: rgb(255 255 255 / 0.07); + color: rgb(156 163 175); + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); +} + +.dark #language-switch select:hover { + color: rgb(209 213 219); + border-color: rgb(255 255 255 / 0.1); +} diff --git a/docs/language-dropdown.js b/docs/language-dropdown.js new file mode 100644 index 000000000..4eb5131f6 --- /dev/null +++ b/docs/language-dropdown.js @@ -0,0 +1,77 @@ +// Language dropdown: a small Python/TypeScript switcher injected into the +// sidebar footer, next to Mintlify's theme selector. Selecting the other +// language navigates to that project's docs site; selecting the current +// language is a no-op. Styling lives in css/language-dropdown.css. +(function () { + if (typeof window === "undefined") return; + + var CURRENT_LANGUAGE = "python"; + + // TODO: fastmcp-ts has no public docs site URL discoverable in either repo + // yet. Until it exists, point at the repo README (the same cross-link the + // welcome page uses), then replace with the real docs URL. + var TYPESCRIPT_DOCS_URL = "https://github.com/PrefectHQ/fastmcp-ts"; + var PYTHON_DOCS_URL = "https://gofastmcp.com"; + + var URLS = { python: PYTHON_DOCS_URL, typescript: TYPESCRIPT_DOCS_URL }; + + function findThemeSelector() { + // Mintlify's sidebar-footer DOM is not a stable public API, so probe a + // few markers (almond theme first) and give up quietly if none match. + return ( + document.querySelector("[data-theme-preference-switch]") || + document.querySelector('[role="group"][aria-label="Theme preference"]') + ); + } + + function buildDropdown() { + var label = document.createElement("label"); + label.id = "language-switch"; + + var select = document.createElement("select"); + select.setAttribute("aria-label", "Switch documentation language"); + + [ + ["python", "Python"], + ["typescript", "TypeScript"], + ].forEach(function (entry) { + var option = document.createElement("option"); + option.value = entry[0]; + option.textContent = entry[1]; + if (entry[0] === CURRENT_LANGUAGE) option.selected = true; + select.appendChild(option); + }); + + select.addEventListener("change", function () { + if (select.value === CURRENT_LANGUAGE) return; + window.location.href = URLS[select.value]; + }); + + label.appendChild(select); + return label; + } + + function addDropdown() { + if (document.getElementById("language-switch")) return; + var theme = findThemeSelector(); + if (!theme || !theme.parentElement) return; + // Insert after the theme pill; margin-left:auto floats it right. + theme.parentElement.insertBefore(buildDropdown(), theme.nextSibling); + } + + function run() { + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", addDropdown); + } else { + addDropdown(); + } + } + + run(); + + // Mintlify re-renders the sidebar on client-side navigation; re-inject when + // the dropdown disappears. + new MutationObserver(function () { + if (!document.getElementById("language-switch")) addDropdown(); + }).observe(document.body, { subtree: true, childList: true }); +})(); From 6f4629a7dae9dd58bd440d97a7845afd6b382be2 Mon Sep 17 00:00:00 2001 From: Nicholas Brown Date: Fri, 7 Aug 2026 12:40:09 -0400 Subject: [PATCH 2/2] add dropdown to ts docs --- docs/css/language-dropdown.css | 31 ++++++++++++++++++++++++++++++- docs/language-dropdown.js | 8 ++++---- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/docs/css/language-dropdown.css b/docs/css/language-dropdown.css index 0eb810545..4ea9a8613 100644 --- a/docs/css/language-dropdown.css +++ b/docs/css/language-dropdown.css @@ -7,6 +7,7 @@ margin-left: auto; display: inline-flex; align-items: center; + position: relative; } #language-switch select { @@ -20,7 +21,7 @@ font-size: 0.75rem; line-height: 1rem; height: 2.375rem; - padding: 0 1.375rem 0 0.75rem; + padding: 0 1.375rem 0 2rem; /* Chevron, drawn in the same gray as the label text. */ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; @@ -55,3 +56,31 @@ color: rgb(209 213 219); border-color: rgb(255 255 255 / 0.1); } + +/* Colored language mark on the visible trigger; the native