Skip to content

Commit 39595a0

Browse files
committed
docs: add dark mode support
1 parent 811c56a commit 39595a0

10 files changed

Lines changed: 221 additions & 4 deletions

File tree

docs/_config.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@ remote_theme: just-the-docs/just-the-docs
77
include:
88
- "_*"
99

10-
# Header links
11-
aux_links:
12-
GitHub: https://github.com/modelcontextprotocol/ruby-sdk
13-
1410
# Search
1511
search_enabled: true
1612

docs/_includes/head_custom.html

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<script>
2+
(function() {
3+
var storageKey = "mcp-ruby-sdk-docs-theme";
4+
var validPreferences = ["system", "light", "dark"];
5+
var preferenceLabels = {
6+
system: "System",
7+
light: "Light",
8+
dark: "Dark"
9+
};
10+
var mediaQuery = window.matchMedia ?
11+
window.matchMedia("(prefers-color-scheme: dark)") :
12+
{ matches: false };
13+
14+
function isValidPreference(preference) {
15+
return validPreferences.indexOf(preference) !== -1;
16+
}
17+
18+
function getStoredPreference() {
19+
try {
20+
var preference = window.localStorage.getItem(storageKey);
21+
return isValidPreference(preference) ? preference : "system";
22+
} catch (error) {
23+
return "system";
24+
}
25+
}
26+
27+
function savePreference(preference) {
28+
try {
29+
window.localStorage.setItem(storageKey, preference);
30+
} catch (error) {
31+
/* Ignore storage errors so private browsing modes still get theme switching. */
32+
}
33+
}
34+
35+
function resolvedTheme(preference) {
36+
if (preference === "dark" || preference === "light") {
37+
return preference;
38+
}
39+
40+
return mediaQuery.matches ? "dark" : "light";
41+
}
42+
43+
function nextPreference(preference) {
44+
var index = validPreferences.indexOf(preference);
45+
if (index === -1 || index === validPreferences.length - 1) {
46+
return validPreferences[0];
47+
}
48+
49+
return validPreferences[index + 1];
50+
}
51+
52+
function setThemeToggleLabel(preference) {
53+
var buttons = document.querySelectorAll("[data-theme-toggle]");
54+
var label = "Theme: " + preferenceLabels[preference];
55+
for (var index = 0; index < buttons.length; index += 1) {
56+
buttons[index].setAttribute("aria-label", label);
57+
buttons[index].setAttribute("title", label);
58+
}
59+
}
60+
61+
function applyPreference(preference) {
62+
var safePreference = isValidPreference(preference) ? preference : "system";
63+
var theme = resolvedTheme(safePreference);
64+
65+
if (window.jtd && typeof window.jtd.setTheme === "function") {
66+
window.jtd.setTheme(theme);
67+
}
68+
document.documentElement.setAttribute("data-theme-preference", safePreference);
69+
document.documentElement.setAttribute("data-theme", theme);
70+
setThemeToggleLabel(safePreference);
71+
}
72+
73+
window.mcpDocsTheme = {
74+
apply: applyPreference,
75+
getPreference: getStoredPreference,
76+
save: function(preference) {
77+
var safePreference = isValidPreference(preference) ? preference : "system";
78+
savePreference(safePreference);
79+
applyPreference(safePreference);
80+
}
81+
};
82+
83+
applyPreference(getStoredPreference());
84+
85+
function initThemeToggle() {
86+
var buttons = document.querySelectorAll("[data-theme-toggle]");
87+
if (buttons.length === 0) {
88+
return;
89+
}
90+
91+
setThemeToggleLabel(getStoredPreference());
92+
for (var index = 0; index < buttons.length; index += 1) {
93+
buttons[index].addEventListener("click", function() {
94+
window.mcpDocsTheme.save(nextPreference(getStoredPreference()));
95+
});
96+
}
97+
}
98+
99+
if (document.readyState === "loading") {
100+
document.addEventListener("DOMContentLoaded", initThemeToggle);
101+
} else {
102+
initThemeToggle();
103+
}
104+
105+
function applySystemPreference() {
106+
if (getStoredPreference() === "system") {
107+
applyPreference("system");
108+
}
109+
}
110+
111+
if (mediaQuery.addEventListener) {
112+
mediaQuery.addEventListener("change", applySystemPreference);
113+
} else if (mediaQuery.addListener) {
114+
mediaQuery.addListener(applySystemPreference);
115+
}
116+
})();
117+
</script>

docs/_includes/header_custom.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<div class="docs-header-controls" aria-label="Site controls">
2+
<button class="site-button docs-icon-button theme-toggle" type="button" data-theme-toggle aria-label="Theme: System" title="Theme: System">
3+
<span class="docs-icon docs-icon--theme" aria-hidden="true"></span>
4+
</button>
5+
<a class="site-button docs-icon-button" href="{{ site.gh_edit_repository | default: 'https://github.com/modelcontextprotocol/ruby-sdk' }}" aria-label="GitHub" title="GitHub">
6+
<span class="docs-icon docs-icon--github" aria-hidden="true"></span>
7+
</a>
8+
</div>

docs/_sass/custom/custom.scss

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
.docs-header-controls {
2+
display: flex;
3+
height: 3.75rem;
4+
align-items: stretch;
5+
justify-content: flex-end;
6+
margin-left: auto;
7+
}
8+
9+
@media (min-width: 50rem) {
10+
.docs-header-controls {
11+
height: 100%;
12+
padding-right: 1rem;
13+
}
14+
}
15+
16+
.docs-icon-button.site-button {
17+
width: 3.75rem;
18+
justify-content: center;
19+
padding: 0;
20+
color: inherit;
21+
background-color: transparent;
22+
border: 0;
23+
cursor: pointer;
24+
font: inherit;
25+
text-decoration: none;
26+
}
27+
28+
.docs-icon {
29+
display: block;
30+
width: 1.25rem;
31+
height: 1.25rem;
32+
background-color: currentColor;
33+
-webkit-mask-position: center;
34+
-webkit-mask-repeat: no-repeat;
35+
-webkit-mask-size: contain;
36+
mask-position: center;
37+
mask-repeat: no-repeat;
38+
mask-size: contain;
39+
}
40+
41+
.docs-icon--github {
42+
-webkit-mask-image: url("/assets/images/icons/github.svg");
43+
mask-image: url("/assets/images/icons/github.svg");
44+
}
45+
46+
.docs-icon--theme {
47+
-webkit-mask-image: url("/assets/images/icons/theme-system.svg");
48+
mask-image: url("/assets/images/icons/theme-system.svg");
49+
}
50+
51+
:root[data-theme-preference="light"] .docs-icon--theme {
52+
-webkit-mask-image: url("/assets/images/icons/theme-light.svg");
53+
mask-image: url("/assets/images/icons/theme-light.svg");
54+
}
55+
56+
:root[data-theme-preference="dark"] .docs-icon--theme {
57+
-webkit-mask-image: url("/assets/images/icons/theme-dark.svg");
58+
mask-image: url("/assets/images/icons/theme-dark.svg");
59+
}
60+
61+
:root[data-theme="dark"] {
62+
color-scheme: dark;
63+
}
64+
65+
:root[data-theme="light"] {
66+
color-scheme: light;
67+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
---
2+
---
3+
{% include css/just-the-docs.scss.liquid color_scheme="dark" %}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
---
2+
---
3+
{% include css/just-the-docs.scss.liquid color_scheme="light" %}
Lines changed: 4 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 11 additions & 0 deletions
Loading
Lines changed: 5 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)