1function detectOS() {
2 var userAgent = navigator.userAgent;
3
4 var platform = navigator.platform;
5 var macosPlatforms = ["Macintosh", "MacIntel", "MacPPC", "Mac68K"];
6 var windowsPlatforms = ["Win32", "Win64", "Windows", "WinCE"];
7 var iosPlatforms = ["iPhone", "iPad", "iPod"];
8
9 if (macosPlatforms.indexOf(platform) !== -1) {
10 return "Mac";
11 } else if (iosPlatforms.indexOf(platform) !== -1) {
12 return "iOS";
13 } else if (windowsPlatforms.indexOf(platform) !== -1) {
14 return "Windows";
15 } else if (/Android/.test(userAgent)) {
16 return "Android";
17 } else if (/Linux/.test(platform)) {
18 return "Linux";
19 }
20
21 return "Unknown";
22}
23
24// Usage
25var os = detectOS();
26console.log("Operating System:", os);
27
28(function updateKeybindings() {
29 const os = detectOS();
30 const isMac = os === "Mac" || os === "iOS";
31
32 function processKeybinding(element) {
33 const [macKeybinding, linuxKeybinding] = element.textContent.split("|");
34 element.textContent = isMac ? macKeybinding : linuxKeybinding;
35 element.classList.add("keybinding");
36 }
37
38 function walkDOM(node) {
39 if (node.nodeType === Node.ELEMENT_NODE) {
40 if (node.tagName.toLowerCase() === "kbd") {
41 processKeybinding(node);
42 } else {
43 Array.from(node.children).forEach(walkDOM);
44 }
45 }
46 }
47
48 // Start the process from the body
49 walkDOM(document.body);
50})();
51
52function darkModeToggle() {
53 var html = document.documentElement;
54 var themeToggleButton = document.getElementById("theme-toggle");
55 var themePopup = document.getElementById("theme-list");
56 var themePopupButtons = themePopup.querySelectorAll("button");
57
58 function setTheme(theme) {
59 html.setAttribute("data-theme", theme);
60 html.setAttribute("data-color-scheme", theme);
61 html.className = theme;
62 localStorage.setItem("mdbook-theme", theme);
63
64 // Force a repaint to ensure the changes take effect in the client immediately
65 document.body.style.display = "none";
66 document.body.offsetHeight;
67 document.body.style.display = "";
68 }
69
70 themeToggleButton.addEventListener("click", function (event) {
71 event.preventDefault();
72 themePopup.style.display =
73 themePopup.style.display === "block" ? "none" : "block";
74 });
75
76 themePopupButtons.forEach(function (button) {
77 button.addEventListener("click", function () {
78 setTheme(this.id);
79 themePopup.style.display = "none";
80 });
81 });
82
83 document.addEventListener("click", function (event) {
84 if (
85 !themePopup.contains(event.target) &&
86 !themeToggleButton.contains(event.target)
87 ) {
88 themePopup.style.display = "none";
89 }
90 });
91
92 // Set initial theme
93 var currentTheme = localStorage.getItem("mdbook-theme");
94 if (currentTheme) {
95 setTheme(currentTheme);
96 } else {
97 // If no theme is set, use the system's preference
98 var systemPreference = window.matchMedia("(prefers-color-scheme: dark)")
99 .matches
100 ? "dark"
101 : "light";
102 setTheme(systemPreference);
103 }
104
105 // Listen for system's preference changes
106 const darkModeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
107 darkModeMediaQuery.addEventListener("change", function (e) {
108 if (!localStorage.getItem("mdbook-theme")) {
109 setTheme(e.matches ? "dark" : "light");
110 }
111 });
112}
113
114const copyMarkdown = () => {
115 const copyButton = document.getElementById("copy-markdown-toggle");
116 if (!copyButton) return;
117
118 // Store the original icon class, loading state, and timeout reference
119 const originalIconClass = "fa fa-copy";
120 let isLoading = false;
121 let iconTimeoutId = null;
122
123 const getCurrentPagePath = () => {
124 const pathname = window.location.pathname;
125
126 // Handle root docs path
127 if (pathname === "/docs/" || pathname === "/docs") {
128 return "getting-started.md";
129 }
130
131 // Remove /docs/ prefix and .html suffix, then add .md
132 const cleanPath = pathname
133 .replace(/^\/docs\//, "")
134 .replace(/\.html$/, "")
135 .replace(/\/$/, "");
136
137 return cleanPath ? cleanPath + ".md" : "getting-started.md";
138 };
139
140 const showToast = (message, isSuccess = true) => {
141 // Remove existing toast if any
142 const existingToast = document.getElementById("copy-toast");
143 existingToast?.remove();
144
145 const toast = document.createElement("div");
146 toast.id = "copy-toast";
147 toast.className = `copy-toast ${isSuccess ? "success" : "error"}`;
148 toast.textContent = message;
149
150 document.body.appendChild(toast);
151
152 // Show toast with animation
153 setTimeout(() => {
154 toast.classList.add("show");
155 }, 10);
156
157 // Hide and remove toast after 2 seconds
158 setTimeout(() => {
159 toast.classList.remove("show");
160 setTimeout(() => {
161 toast.parentNode?.removeChild(toast);
162 }, 300);
163 }, 2000);
164 };
165
166 const changeButtonIcon = (iconClass, duration = 1000) => {
167 const icon = copyButton.querySelector("i");
168 if (!icon) return;
169
170 // Clear any existing timeout
171 if (iconTimeoutId) {
172 clearTimeout(iconTimeoutId);
173 iconTimeoutId = null;
174 }
175
176 icon.className = iconClass;
177
178 if (duration > 0) {
179 iconTimeoutId = setTimeout(() => {
180 icon.className = originalIconClass;
181 iconTimeoutId = null;
182 }, duration);
183 }
184 };
185
186 const fetchAndCopyMarkdown = async () => {
187 // Prevent multiple simultaneous requests
188 if (isLoading) return;
189
190 try {
191 isLoading = true;
192 changeButtonIcon("fa fa-spinner fa-spin", 0); // Don't auto-restore spinner
193
194 const pagePath = getCurrentPagePath();
195 const rawUrl = `https://raw.githubusercontent.com/zed-industries/zed/main/docs/src/${pagePath}`;
196
197 const response = await fetch(rawUrl);
198 if (!response.ok) {
199 throw new Error(
200 `Failed to fetch markdown: ${response.status} ${response.statusText}`,
201 );
202 }
203
204 const markdownContent = await response.text();
205
206 // Copy to clipboard using modern API
207 if (navigator.clipboard?.writeText) {
208 await navigator.clipboard.writeText(markdownContent);
209 } else {
210 // Fallback: throw error if clipboard API isn't available
211 throw new Error("Clipboard API not supported in this browser");
212 }
213
214 changeButtonIcon("fa fa-check", 1000);
215 showToast("Page content copied to clipboard!");
216 } catch (error) {
217 console.error("Error copying markdown:", error);
218 changeButtonIcon("fa fa-exclamation-triangle", 2000);
219 showToast("Failed to copy markdown. Please try again.", false);
220 } finally {
221 isLoading = false;
222 }
223 };
224
225 copyButton.addEventListener("click", fetchAndCopyMarkdown);
226};
227
228// Initialize functionality when DOM is loaded
229document.addEventListener("DOMContentLoaded", () => {
230 copyMarkdown();
231});