index.hbs

  1<!DOCTYPE HTML>
  2<html lang="{{ language }}" data-theme="{{ default_theme }}" data-color-scheme="{{ default_theme }}" dir="{{ text_direction }}">
  3    <head>
  4        <!-- Book generated using mdBook -->
  5        <meta charset="UTF-8">
  6        <title>{{ title }}</title>
  7        {{#if is_print }}
  8        <meta name="robots" content="noindex">
  9        {{/if}}
 10        {{#if base_url}}
 11        <base href="{{ base_url }}">
 12        {{/if}}
 13
 14
 15        <!-- Custom HTML head -->
 16        {{> head}}
 17
 18        <meta name="description" content="#description#">
 19        <meta name="viewport" content="width=device-width, initial-scale=1">
 20        <meta name="theme-color" content="#ffffff">
 21
 22        <link rel="shortcut icon" href="{{ path_to_root }}favicon.png">
 23        <link rel="stylesheet" href="{{ path_to_root }}css/variables.css">
 24        <link rel="stylesheet" href="{{ path_to_root }}css/general.css">
 25        <link rel="stylesheet" href="{{ path_to_root }}css/chrome.css">
 26        {{#if print_enable}}
 27        <link rel="stylesheet" href="{{ path_to_root }}css/print.css" media="print">
 28        {{/if}}
 29
 30        <!-- Fonts -->
 31        <link rel="stylesheet" href="{{ path_to_root }}FontAwesome/css/font-awesome.css">
 32        {{#if copy_fonts}}
 33        <link rel="stylesheet" href="{{ path_to_root }}fonts/fonts.css">
 34        {{/if}}
 35
 36        <!-- Highlight.js Stylesheets -->
 37        <link rel="stylesheet" href="{{ path_to_root }}highlight.css">
 38        <link rel="stylesheet" href="{{ path_to_root }}tomorrow-night.css">
 39        <link rel="stylesheet" href="{{ path_to_root }}ayu-highlight.css">
 40
 41        <!-- Custom theme stylesheets -->
 42        {{#each additional_css}}
 43        <link rel="stylesheet" href="{{ ../path_to_root }}{{ this }}">
 44        {{/each}}
 45
 46        {{#if mathjax_support}}
 47        <!-- MathJax -->
 48        <script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
 49        {{/if}}
 50    </head>
 51    <body class="no-js">
 52    <div id="body-container">
 53        <div class="noise-pattern" style="background-image: url('https://cdn.zed.dev/images/noise.png');"></div>
 54
 55        <!-- Provide site root to javascript -->
 56        <script>
 57            var path_to_root = "{{ path_to_root }}";
 58            var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "{{ preferred_dark_theme }}" : "{{ default_theme }}";
 59        </script>
 60
 61        <!-- Support dark mode -->
 62        <script>
 63            var theme;
 64            try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
 65            if (theme === null || theme === undefined) {
 66                theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
 67            }
 68            var html = document.querySelector('html');
 69            html.classList.remove('light', 'dark')
 70            html.classList.add(theme);
 71            var body = document.querySelector('body');
 72            body.classList.remove('no-js')
 73            body.classList.add('js');
 74        </script>
 75
 76        <header class="header-bar">
 77            <div class="left-container">
 78                <a href="/" class="logo-nav">
 79                    <img src="https://zed.dev/logo_icon.webp" class="icon-logo-img" alt="Zed Industries" style="height: 26px;">
 80                </a>
 81                <button id="sidebar-toggle" class="icon-button ib-hidden-desktop" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar" aria-expanded="false">
 82                    <i class="fa fa-bars"></i>
 83                </button>
 84            </div>
 85            {{#if search_enabled}}
 86            <button id="search-toggle" class="search-button" type="button" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
 87                <i class="icon fa fa-search"></i>
 88                <span class="search-content-desktop">
 89                    <span class="placeholder">Search docs…</span>
 90                    <kbd>S</kbd>
 91                </span>
 92                <span class="search-content-mobile">
 93                    <span class="placeholder">Search…</span>
 94                </span>
 95            </button>
 96            {{/if}}
 97            <div class="right-container">
 98                <button id="theme-toggle" class="icon-button" type="button" title="Change Theme" aria-label="Change Theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
 99                    <i class="fa fa-paint-brush"></i>
100                </button>
101
102                <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
103                    <li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
104                    <li role="none"><button role="menuitem" class="theme" id="dark">Dark</button></li>
105                </ul>
106
107                <button id="copy-markdown-toggle" class="icon-button ib-hidden-mobile" type="button" title="Copy Page as Markdown" aria-label="Copy page as markdown">
108                    <i class="fa fa-copy"></i>
109                </button>
110
111                <a class="download-button" href="https://zed.dev/download" title="Download Zed" aria-label="Download Zed">
112                    Download
113                </a>
114                {{#if git_repository_url}}
115                <a href="{{git_repository_url}}" title="Git repository" aria-label="Git repository">
116                    <i id="git-repository-button" class="fa {{git_repository_icon}}"></i>
117                </a>
118                {{/if}}
119                {{#if git_repository_edit_url}}
120                <a href="{{git_repository_edit_url}}" title="Suggest an edit" aria-label="Suggest an edit">
121                    <i id="git-edit-button" class="fa fa-edit"></i>
122                </a>
123                {{/if}}
124            </div>
125        </header>
126
127        <div id="page-wrapper" class="page-wrapper">
128
129            {{#if search_enabled}}
130            <div class="search-container">
131                <div id="search-wrapper" class="search-modal hidden">
132                    <form id="searchbar-outer" class="searchbar-outer">
133                        <input type="search" id="searchbar" name="searchbar" placeholder="Search…" aria-controls="searchresults-outer" aria-describedby="searchresults-header">
134                    </form>
135                    <div id="searchresults-outer" class="searchresults-outer">
136                        <div id="searchresults-header" class="searchresults-header"></div>
137                        <ul id="searchresults">
138                        </ul>
139                    </div>
140                </div>
141            </div>
142            {{/if}}
143
144            <nav id="sidebar" class="sidebar" aria-label="Table of contents">
145                <div class="sidebar-scrollbox">
146                    {{#toc}}{{/toc}}
147                </div>
148                <div style="display: none;" id="sidebar-resize-handle" class="sidebar-resize-handle">
149                    <div class="sidebar-resize-indicator"></div>
150                </div>
151            </nav>
152
153            <!-- Mobile sidebar toggle -->
154            <script>
155                (function() {
156                    var sidebarToggle = document.getElementById('sidebar-toggle');
157                    var sidebar = document.getElementById('sidebar');
158
159                    sidebarToggle.addEventListener('click', function() {
160                        var isOpen = document.body.classList.toggle('sidebar-open');
161                        sidebarToggle.setAttribute('aria-expanded', isOpen);
162                        sidebar.setAttribute('aria-hidden', !isOpen);
163                    });
164
165                    // Close sidebar when clicking a link inside it (on mobile)
166                    sidebar.addEventListener('click', function(e) {
167                        if (e.target.tagName === 'A' && window.innerWidth < 620) {
168                            document.body.classList.remove('sidebar-open');
169                            sidebarToggle.setAttribute('aria-expanded', 'false');
170                            sidebar.setAttribute('aria-hidden', 'true');
171                        }
172                    });
173                })();
174            </script>
175
176            <!-- Search backdrop handlers -->
177            <script>
178                (function() {
179                    var searchWrapper = document.getElementById('search-wrapper');
180                    var searchContainer = document.querySelector('.search-container');
181                    var searchResults = document.getElementById('searchresults');
182
183                    if (!searchWrapper || !searchContainer) return;
184
185                    searchContainer.addEventListener('click', function(e) {
186                        if (e.target === searchContainer) {
187                            searchWrapper.classList.add('hidden');
188                        }
189                    });
190
191                    if (searchResults) {
192                        searchResults.addEventListener('click', function(e) {
193                            if (e.target.tagName === 'A' || e.target.closest('a')) {
194                                searchWrapper.classList.add('hidden');
195                            }
196                        });
197                    }
198                })();
199            </script>
200
201            <!-- Insert section spacers and apply collapsed state before scroll restoration to prevent layout shift/flicker -->
202            <script>
203                (function() {
204                    var chapterList = document.querySelector('#sidebar ol.chapter');
205                    if (!chapterList) return;
206
207                    var collapsedSections = [];
208                    try {
209                        var stored = sessionStorage.getItem('sidebar-collapsed-sections');
210                        if (stored) {
211                            collapsedSections = JSON.parse(stored);
212                        }
213                    } catch (e) {}
214
215                    var partTitles = chapterList.querySelectorAll('li.part-title');
216                    var previousPartTitle = null;
217
218                    partTitles.forEach(function(partTitle, index) {
219                        partTitle._sectionName = partTitle.textContent.trim();
220
221                        // Insert a spacer before this part-title (except for the first one)
222                        if (index > 0) {
223                            var spacer = document.createElement('li');
224                            spacer.className = 'section-spacer';
225                            partTitle.parentNode.insertBefore(spacer, partTitle);
226
227                            if (previousPartTitle) {
228                                previousPartTitle._spacerAfter = spacer;
229                            }
230                        }
231
232                        var isCollapsed = collapsedSections.includes(partTitle._sectionName);
233                        if (isCollapsed) {
234                            // Hide all siblings until next part-title
235                            var sibling = partTitle.nextElementSibling;
236                            while (sibling && !sibling.classList.contains('part-title')) {
237                                sibling.classList.add('section-hidden');
238                                sibling = sibling.nextElementSibling;
239                            }
240                            // Hide the spacer after this section (will be set on next iteration)
241                            partTitle._isCollapsed = true;
242                        }
243
244                        // If previous section was collapsed, hide its spacer
245                        if (previousPartTitle && previousPartTitle._isCollapsed && previousPartTitle._spacerAfter) {
246                            previousPartTitle._spacerAfter.classList.add('section-hidden');
247                        }
248
249                        previousPartTitle = partTitle;
250                    });
251
252                    // Handle the last section's spacer if it was collapsed
253                    if (previousPartTitle && previousPartTitle._isCollapsed && previousPartTitle._spacerAfter) {
254                        previousPartTitle._spacerAfter.classList.add('section-hidden');
255                    }
256                })();
257            </script>
258
259            <!-- Track and set sidebar scroll position -->
260            <script>
261                var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
262                sidebarScrollbox.addEventListener('click', function(e) {
263                    if (e.target.tagName === 'A') {
264                        sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
265                    }
266                }, { passive: true });
267                var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
268                sessionStorage.removeItem('sidebar-scroll');
269                if (sidebarScrollTop) {
270                    // preserve sidebar scroll position when navigating via links within sidebar
271                    sidebarScrollbox.scrollTop = sidebarScrollTop;
272                } else {
273                    // scroll sidebar to current active section when navigating via "next/previous chapter" buttons
274                    var activeSection = document.querySelector('#sidebar .active');
275                    if (activeSection) {
276                        activeSection.scrollIntoView({ block: 'center' });
277                    }
278                }
279            </script>
280
281            <div class="page">
282                <div id="content" class="content">
283                    <main>
284                      {{{ content }}}
285                        <div class="footer-buttons">
286                            {{#previous}}
287                            <a rel="prev" href="{{ path_to_root }}{{link}}" class="footer-button" title="{{title}}">
288                                <i class="fa fa-angle-left"></i>
289                                {{title}}
290                            </a>
291                            {{/previous}}
292                            {{#next}}
293                            <a rel="next" href="{{ path_to_root }}{{link}}" class="footer-button" title="{{title}}">
294                                {{title}}
295                                <i class="fa fa-angle-right"></i>
296                            </a>
297                            {{/next}}
298                        </div>
299                    </main>
300                    <div class="toc-container">
301                        <nav class="pagetoc">
302                            <p class="toc-title">On this page</p>
303                        </nav>
304                    </div>
305                </div>
306            </div>
307        </div>
308
309        {{#if live_reload_endpoint}}
310        <!-- Livereload script (if served using the cli tool) -->
311        <script>
312            const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
313            const wsAddress = wsProtocol + "//" + location.host + "/" + "{{{live_reload_endpoint}}}";
314            const socket = new WebSocket(wsAddress);
315            socket.onmessage = function (event) {
316                if (event.data === "reload") {
317                    socket.close();
318                    location.reload();
319                }
320            };
321
322            window.onbeforeunload = function() {
323                socket.close();
324            }
325        </script>
326        {{/if}}
327
328        {{#if playground_line_numbers}}
329        <script>
330            window.playground_line_numbers = true;
331        </script>
332        {{/if}}
333
334        {{#if playground_copyable}}
335        <script>
336            window.playground_copyable = true;
337        </script>
338        {{/if}}
339
340        {{#if playground_js}}
341        <script src="{{ path_to_root }}ace.js"></script>
342        <script src="{{ path_to_root }}editor.js"></script>
343        <script src="{{ path_to_root }}mode-rust.js"></script>
344        <script src="{{ path_to_root }}theme-dawn.js"></script>
345        <script src="{{ path_to_root }}theme-tomorrow_night.js"></script>
346        {{/if}}
347
348        {{#if search_js}}
349        <script src="{{ path_to_root }}elasticlunr.min.js"></script>
350        <script src="{{ path_to_root }}mark.min.js"></script>
351        <script src="{{ path_to_root }}searcher.js"></script>
352        {{/if}}
353
354        <script src="{{ path_to_root }}clipboard.min.js"></script>
355        <script src="{{ path_to_root }}highlight.js"></script>
356        <script src="{{ path_to_root }}book.js"></script>
357
358        <!-- Custom JS scripts -->
359        {{#each additional_js}}
360        <script src="{{ ../path_to_root }}{{this}}"></script>
361        {{/each}}
362
363        {{#if is_print}}
364        {{#if mathjax_support}}
365        <script>
366        window.addEventListener('load', function() {
367            MathJax.Hub.Register.StartupHook('End', function() {
368                window.setTimeout(window.print, 100);
369            });
370        });
371        </script>
372        {{else}}
373        <script>
374        window.addEventListener('load', function() {
375            window.setTimeout(window.print, 100);
376        });
377        </script>
378        {{/if}}
379        {{/if}}
380
381        <script>
382          (function() {
383            var theme = localStorage.getItem('mdbook-theme');
384            var html = document.querySelector('html');
385            if (theme) {
386              html.setAttribute('data-theme', theme);
387              html.setAttribute('data-color-scheme', theme);
388              html.className = theme;
389            } else {
390              var systemPreference = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
391              html.setAttribute('data-theme', systemPreference);
392              html.setAttribute('data-color-scheme', systemPreference);
393              html.className = systemPreference;
394            }
395          })();
396        </script>
397
398        <!-- Amplitude Analytics -->
399        <script>
400          (function() {
401            var amplitudeKey = '#amplitude_key#';
402            if (amplitudeKey && amplitudeKey.indexOf('#') === -1) {
403              var script = document.createElement('script');
404              script.src = 'https://cdn.amplitude.com/script/' + amplitudeKey + '.js';
405              script.onload = function() {
406                window.amplitude.init(amplitudeKey, {
407                  fetchRemoteConfig: true,
408                  autocapture: true
409                });
410              };
411              document.head.appendChild(script);
412            }
413          })();
414        </script>
415    </div>
416    </body>
417</html>