Merge pull request #341 from atesgoral/dark-mode

Add dark mode support to docs
This commit is contained in:
Koichi ITO 2026-05-12 01:17:34 +09:00 • committed by GitHub
commit 5153c399a9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 221 additions and 4 deletions

View file

@ -7,10 +7,6 @@ remote_theme: just-the-docs/just-the-docs
include:
- "_*"
# Header links
aux_links:
GitHub: https://github.com/modelcontextprotocol/ruby-sdk
# Search
search_enabled: true

View file

@ -0,0 +1,117 @@
<script>
(function() {
const storageKey = "mcp-ruby-sdk-docs-theme";
const validPreferences = ["system", "light", "dark"];
const preferenceLabels = {
system: "System",
light: "Light",
dark: "Dark"
};
const mediaQuery = window.matchMedia ?
window.matchMedia("(prefers-color-scheme: dark)") :
{ matches: false };
function isValidPreference(preference) {
return validPreferences.indexOf(preference) !== -1;
}
function getStoredPreference() {
try {
const preference = window.localStorage.getItem(storageKey);
return isValidPreference(preference) ? preference : "system";
} catch (error) {
return "system";
}
}
function savePreference(preference) {
try {
window.localStorage.setItem(storageKey, preference);
} catch (error) {
/* Ignore storage errors so private browsing modes still get theme switching. */
}
}
function resolvedTheme(preference) {
if (preference === "dark" || preference === "light") {
return preference;
}
return mediaQuery.matches ? "dark" : "light";
}
function nextPreference(preference) {
const index = validPreferences.indexOf(preference);
if (index === -1 || index === validPreferences.length - 1) {
return validPreferences[0];
}
return validPreferences[index + 1];
}
function setThemeToggleLabel(preference) {
const buttons = document.querySelectorAll("[data-theme-toggle]");
const label = "Theme: " + preferenceLabels[preference];
for (let index = 0; index < buttons.length; index += 1) {
buttons[index].setAttribute("aria-label", label);
buttons[index].setAttribute("title", label);
}
}
function applyPreference(preference) {
const safePreference = isValidPreference(preference) ? preference : "system";
const theme = resolvedTheme(safePreference);
if (window.jtd && typeof window.jtd.setTheme === "function") {
window.jtd.setTheme(theme);
}
document.documentElement.setAttribute("data-theme-preference", safePreference);
document.documentElement.setAttribute("data-theme", theme);
setThemeToggleLabel(safePreference);
}
window.mcpDocsTheme = {
apply: applyPreference,
getPreference: getStoredPreference,
save: function(preference) {
const safePreference = isValidPreference(preference) ? preference : "system";
savePreference(safePreference);
applyPreference(safePreference);
}
};
applyPreference(getStoredPreference());
function initThemeToggle() {
const buttons = document.querySelectorAll("[data-theme-toggle]");
if (buttons.length === 0) {
return;
}
setThemeToggleLabel(getStoredPreference());
for (let index = 0; index < buttons.length; index += 1) {
buttons[index].addEventListener("click", function() {
window.mcpDocsTheme.save(nextPreference(getStoredPreference()));
});
}
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initThemeToggle);
} else {
initThemeToggle();
}
function applySystemPreference() {
if (getStoredPreference() === "system") {
applyPreference("system");
}
}
if (mediaQuery.addEventListener) {
mediaQuery.addEventListener("change", applySystemPreference);
} else if (mediaQuery.addListener) {
mediaQuery.addListener(applySystemPreference);
}
})();
</script>

View file

@ -0,0 +1,8 @@
<div class="docs-header-controls" aria-label="Site controls">
<button class="site-button docs-icon-button theme-toggle" type="button" data-theme-toggle aria-label="Theme: System" title="Theme: System">
<span class="docs-icon docs-icon--theme" aria-hidden="true"></span>
</button>
<a class="site-button docs-icon-button" href="{{ site.gh_edit_repository | default: 'https://github.com/modelcontextprotocol/ruby-sdk' }}" aria-label="GitHub" title="GitHub">
<span class="docs-icon docs-icon--github" aria-hidden="true"></span>
</a>
</div>

View file

@ -0,0 +1,67 @@
.docs-header-controls {
display: flex;
height: 3.75rem;
align-items: stretch;
justify-content: flex-end;
margin-left: auto;
}
@media (min-width: 50rem) {
.docs-header-controls {
height: 100%;
padding-right: 1rem;
}
}
.docs-icon-button.site-button {
width: 3.75rem;
justify-content: center;
padding: 0;
color: inherit;
background-color: transparent;
border: 0;
cursor: pointer;
font: inherit;
text-decoration: none;
}
.docs-icon {
display: block;
width: 1.25rem;
height: 1.25rem;
background-color: currentColor;
-webkit-mask-position: center;
-webkit-mask-repeat: no-repeat;
-webkit-mask-size: contain;
mask-position: center;
mask-repeat: no-repeat;
mask-size: contain;
}
.docs-icon--github {
-webkit-mask-image: url("/assets/images/icons/github.svg");
mask-image: url("/assets/images/icons/github.svg");
}
.docs-icon--theme {
-webkit-mask-image: url("/assets/images/icons/theme-system.svg");
mask-image: url("/assets/images/icons/theme-system.svg");
}
:root[data-theme-preference="light"] .docs-icon--theme {
-webkit-mask-image: url("/assets/images/icons/theme-light.svg");
mask-image: url("/assets/images/icons/theme-light.svg");
}
:root[data-theme-preference="dark"] .docs-icon--theme {
-webkit-mask-image: url("/assets/images/icons/theme-dark.svg");
mask-image: url("/assets/images/icons/theme-dark.svg");
}
:root[data-theme="dark"] {
color-scheme: dark;
}
:root[data-theme="light"] {
color-scheme: light;
}

View file

@ -0,0 +1,3 @@
---
---
{% include css/just-the-docs.scss.liquid color_scheme="dark" %}

View file

@ -0,0 +1,3 @@
---
---
{% include css/just-the-docs.scss.liquid color_scheme="light" %}

View file

@ -0,0 +1,4 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<title>GitHub</title>
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/>
</svg>

After

Width:  |  Height:  |  Size: 830 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"/>
</svg>

After

Width:  |  Height:  |  Size: 284 B

View file

@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="4"/>
<path d="M12 2v2"/>
<path d="M12 20v2"/>
<path d="m4.93 4.93 1.41 1.41"/>
<path d="m17.66 17.66 1.41 1.41"/>
<path d="M2 12h2"/>
<path d="M20 12h2"/>
<path d="m6.34 17.66-1.41 1.41"/>
<path d="m19.07 4.93-1.41 1.41"/>
</svg>

After

Width:  |  Height:  |  Size: 427 B

View file

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect width="20" height="14" x="2" y="3" rx="2"/>
<line x1="8" x2="16" y1="21" y2="21"/>
<line x1="12" x2="12" y1="17" y2="21"/>
</svg>

After

Width:  |  Height:  |  Size: 294 B