authorgravatar for ian@ianjohnson.devIan Johnson <ian@ianjohnson.dev> 2023-06-27 00:19:40-04:00
committergravatar for kappaloris@gmail.comLoris Cro <kappaloris@gmail.com> 2023-06-28 18:16:16+02:00
log4dacaa1e129a3991cd805f5a602bcc329e5794d2
tree12e70f9d0bb8ffe5fa5178d7bfd46fa2dd007b03
parent7166407d8f2e9e080f4f97926a2b543150261576

Autodoc: add preference for `/` search

Closes #16081

2 files changed, 158 insertions(+), 43 deletions(-)

lib/docs/index.html+36-18
......@@ -25,8 +25,8 @@
2525 --search-bg-color-focus: #ffffff;
2626 --search-sh-color: rgba(0, 0, 0, 0.18);
2727 --search-other-results-color: rgb(100, 100, 100);
28 --help-sh-color: rgba(0, 0, 0, 0.75);
29 --help-bg-color: #aaa;
28 --modal-sh-color: rgba(0, 0, 0, 0.75);
29 --modal-bg-color: #aaa;
3030 }
3131
3232 html, body { margin: 0; padding: 0; height: 100%; }
......@@ -99,7 +99,7 @@
9999 flex-shrink: 1;
100100 }
101101
102 .help-modal {
102 .modal-container {
103103 z-index: 400;
104104 }
105105
......@@ -412,8 +412,8 @@
412412 padding: 1px 1em;
413413 }
414414
415 /* help modal */
416 .help-modal {
415 /* modals */
416 .modal-container {
417417 display: flex;
418418 width: 100%;
419419 height: 100%;
......@@ -426,29 +426,36 @@
426426 backdrop-filter: blur(0.3em);
427427 }
428428
429 .help-modal > .modal {
429 .modal-container > .modal {
430430 max-width: 97vw;
431431 max-height: 97vh;
432432 overflow: auto;
433433 font-size: 1rem;
434434 color: #fff;
435 background-color: var(--help-bg-color);
435 background-color: var(--modal-bg-color);
436436 border: 0.125rem solid #000;
437 box-shadow: 0 0.5rem 2.5rem 0.3rem var(--help-sh-color);
437 box-shadow: 0 0.5rem 2.5rem 0.3rem var(--modal-sh-color);
438438 }
439439
440 .help-modal h1 {
440 .modal-container h1 {
441441 margin: 0.75em 2.5em 1em 2.5em;
442442 font-size: 1.5em;
443443 text-align: center;
444444 }
445445
446 .help-modal dt, .help-modal dd {
446 .modal-container dt, .modal-container dd {
447447 display: inline;
448448 margin: 0 0.2em;
449449 }
450450
451 .help-modal dl {
451 .modal-container dl {
452 margin-left: 0.5em;
453 margin-right: 0.5em;
454 }
455
456 .prefs-list {
457 list-style: none;
458 padding: 0;
452459 margin-left: 0.5em;
453460 margin-right: 0.5em;
454461 }
......@@ -539,8 +546,8 @@
539546 --search-bg-color-focus: #000;
540547 --search-sh-color: rgba(255, 255, 255, 0.28);
541548 --search-other-results-color: rgba(255, 255, 255, 0.28);
542 --help-sh-color: rgba(142, 142, 142, 0.5);
543 --help-bg-color: #333;
549 --modal-sh-color: rgba(142, 142, 142, 0.5);
550 --modal-bg-color: #333;
544551 }
545552
546553 .docs pre {
......@@ -677,13 +684,13 @@
677684 </style>
678685 </head>
679686 <body class="canvas">
680 <div class="banner">
687 <div id="banner" class="banner">
681688 This is a beta autodoc build; expect bugs and missing information.
682689 <a href="https://github.com/ziglang/zig/wiki/How-to-contribute-to-Autodoc">Report an Issue</a>,
683690 <a href="https://github.com/ziglang/zig/wiki/How-to-contribute-to-Autodoc">Contribute</a>,
684691 <a href="https://github.com/ziglang/zig/wiki/How-to-read-the-standard-library-source-code">Learn more about stdlib source code</a>.
685692 </div>
686 <div class="flex-main">
693 <div id="main" class="flex-main">
687694 <div class="flex-filler"></div>
688695 <div class="flex-left sidebar">
689696 <nav>
......@@ -758,7 +765,7 @@
758765 <div class="wrap">
759766 <section class="docs" style="padding-top: 1.5rem; padding-bottom:0;">
760767 <div style="position: relative">
761 <span id="searchPlaceholder"><kbd>/</kbd> or <kbd>s</kbd> to search, <kbd>?</kbd> for more options</span>
768 <span id="searchPlaceholder"><!-- populated by setPrefSlashSearch --></span>
762769 <input type="search" class="search" id="search" autocomplete="off" spellcheck="false" disabled>
763770 </div>
764771 </section>
......@@ -872,20 +879,31 @@
872879 </div>
873880 </div>
874881 <div id="helpModal" class="hidden">
875 <div class="help-modal">
882 <div class="modal-container">
876883 <div class="modal">
877884 <h1>Keyboard Shortcuts</h1>
878885 <dl><dt><kbd>?</kbd></dt><dd>Toggle this help modal</dd></dl>
879 <dl><dt><kbd>s</kbd> or <kbd>/</kbd></dt><dd>Focus the search field</dd></dl>
886 <dl><dt id="searchKeys"><!-- populated by setPrefSlashSearch --></dt><dd>Focus the search field</dd></dl>
880887 <div style="margin-left: 1em">
881888 <dl><dt><kbd>↑</kbd></dt><dd>Move up in search results</dd></dl>
882889 <dl><dt><kbd>↓</kbd></dt><dd>Move down in search results</dd></dl>
883890 <dl><dt><kbd>⏎</kbd></dt><dd>Go to active search result</dd></dl>
884891 </div>
892 <dl><dt><kbd>p</kbd></dt><dd>Open preferences</dd></dl>
885893 <dl><dt><kbd>Esc</kbd></dt><dd>Clear focus; close this modal</dd></dl>
886894 </div>
887895 </div>
888896 </div>
897 <div id="prefsModal" class="hidden">
898 <div class="modal-container">
899 <div class="modal">
900 <h1>Preferences</h1>
901 <ul class="prefs-list">
902 <li><input id="prefSlashSearch" type="checkbox"><label for="prefSlashSearch">Enable <kbd>/</kbd> for search</label></li>
903 </ul>
904 </div>
905 </div>
906 </div>
889907 <script src="data.js"></script>
890908 <script src="commonmark.js"></script>
891909 <script src="main.js"></script>
lib/docs/main.js+122-25
......@@ -8,6 +8,8 @@ const NAV_MODES = {
88};
99
1010(function () {
11 const domBanner = document.getElementById("banner");
12 const domMain = document.getElementById("main");
1113 const domStatus = document.getElementById("status");
1214 const domSectNav = document.getElementById("sectNav");
1315 const domListNav = document.getElementById("listNav");
......@@ -65,10 +67,18 @@ const NAV_MODES = {
6567 const domTdZigVer = document.getElementById("tdZigVer");
6668 const domHdrName = document.getElementById("hdrName");
6769 const domHelpModal = document.getElementById("helpModal");
70 const domSearchKeys = document.getElementById("searchKeys");
71 const domPrefsModal = document.getElementById("prefsModal");
6872 const domSearchPlaceholder = document.getElementById("searchPlaceholder");
6973 const sourceFileUrlTemplate = "src/{{mod}}/{{file}}.html#L{{line}}"
7074 const domLangRefLink = document.getElementById("langRefLink");
7175
76 const domPrefSlashSearch = document.getElementById("prefSlashSearch");
77 const prefs = getLocalStorage();
78 loadPrefs();
79
80 domPrefSlashSearch.addEventListener("change", () => setPrefSlashSearch(domPrefSlashSearch.checked));
81
7282 let searchTimer = null;
7383 let searchTrimResults = true;
7484
......@@ -127,21 +137,21 @@ const NAV_MODES = {
127137 window.guideSearch = guidesSearchIndex;
128138 parseGuides();
129139
130 // identifiers can contain '?' so we want to allow typing
131 // the question mark when the search is focused instead of toggling the help modal
132 let canToggleHelpModal = true;
140 // identifiers can contain modal trigger characters so we want to allow typing
141 // such characters when the search is focused instead of toggling the modal
142 let canToggleModal = true;
133143
134144 domSearch.disabled = false;
135145 domSearch.addEventListener("keydown", onSearchKeyDown, false);
136146 domSearch.addEventListener("input", onSearchInput, false);
137147 domSearch.addEventListener("focus", ev => {
138148 domSearchPlaceholder.classList.add("hidden");
139 canToggleHelpModal = false;
149 canToggleModal = false;
140150 });
141151 domSearch.addEventListener("blur", ev => {
142152 if (domSearch.value.length == 0)
143153 domSearchPlaceholder.classList.remove("hidden");
144 canToggleHelpModal = true;
154 canToggleModal = true;
145155 });
146156 domSectSearchAllResultsLink.addEventListener('click', onClickSearchShowAllResults, false);
147157 function onClickSearchShowAllResults(ev) {
......@@ -156,10 +166,13 @@ const NAV_MODES = {
156166 }
157167
158168 // make the modal disappear if you click outside it
159 domHelpModal.addEventListener("click", ev => {
160 if (ev.target.className == "help-modal")
161 domHelpModal.classList.add("hidden");
162 });
169 function handleModalClick(ev) {
170 if (ev.target.classList.contains("modal-container")) {
171 hideModal(this);
172 }
173 }
174 domHelpModal.addEventListener("click", handleModalClick);
175 domPrefsModal.addEventListener("click", handleModalClick);
163176
164177 window.addEventListener("hashchange", onHashChange, false);
165178 window.addEventListener("keydown", onWindowKeyDown, false);
......@@ -3996,8 +4009,12 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
39964009
39974010 // hide the modal if it's visible or return to the previous result page and unfocus the search
39984011 function onEscape(ev) {
3999 if (!domHelpModal.classList.contains("hidden")) {
4000 domHelpModal.classList.add("hidden");
4012 if (isModalVisible(domHelpModal)) {
4013 hideModal(domHelpModal);
4014 ev.preventDefault();
4015 ev.stopPropagation();
4016 } else if (isModalVisible(domPrefsModal)) {
4017 hideModal(domPrefsModal);
40014018 ev.preventDefault();
40024019 ev.stopPropagation();
40034020 } else {
......@@ -4110,8 +4127,10 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
41104127 onEscape(ev);
41114128 break;
41124129 case "/":
4130 if (!getPrefSlashSearch()) break;
4131 // fallthrough
41134132 case "s":
4114 if (domHelpModal.classList.contains("hidden")) {
4133 if (!isModalVisible(domHelpModal) && !isModalVisible(domPrefsModal)) {
41154134 if (ev.target == domSearch) break;
41164135
41174136 domSearch.focus();
......@@ -4123,28 +4142,65 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
41234142 }
41244143 break;
41254144 case "?":
4126 if (!canToggleHelpModal) break;
4145 if (!canToggleModal) break;
4146
4147 if (isModalVisible(domPrefsModal)) {
4148 hideModal(domPrefsModal);
4149 }
41274150
41284151 // toggle the help modal
4129 if (!domHelpModal.classList.contains("hidden")) {
4130 onEscape(ev);
4152 if (isModalVisible(domHelpModal)) {
4153 hideModal(domHelpModal);
41314154 } else {
4132 ev.preventDefault();
4133 ev.stopPropagation();
4134 showHelpModal();
4155 showModal(domHelpModal);
41354156 }
4157 ev.preventDefault();
4158 ev.stopPropagation();
41364159 break;
4160 case "p":
4161 if (!canToggleModal) break;
4162
4163 if (isModalVisible(domHelpModal)) {
4164 hideModal(domHelpModal);
4165 }
4166
4167 // toggle the preferences modal
4168 if (isModalVisible(domPrefsModal)) {
4169 hideModal(domPrefsModal);
4170 } else {
4171 showModal(domPrefsModal);
4172 }
4173 ev.preventDefault();
4174 ev.stopPropagation();
41374175 }
41384176 }
41394177
4140 function showHelpModal() {
4141 domHelpModal.classList.remove("hidden");
4142 domHelpModal.style.left =
4143 window.innerWidth / 2 - domHelpModal.clientWidth / 2 + "px";
4144 domHelpModal.style.top =
4145 window.innerHeight / 2 - domHelpModal.clientHeight / 2 + "px";
4146 domHelpModal.focus();
4178 function isModalVisible(modal) {
4179 return !modal.classList.contains("hidden");
4180 }
4181
4182 function showModal(modal) {
4183 modal.classList.remove("hidden");
4184 modal.style.left =
4185 window.innerWidth / 2 - modal.clientWidth / 2 + "px";
4186 modal.style.top =
4187 window.innerHeight / 2 - modal.clientHeight / 2 + "px";
4188 const firstInput = modal.querySelector("input");
4189 if (firstInput) {
4190 firstInput.focus();
4191 } else {
4192 modal.focus();
4193 }
41474194 domSearch.blur();
4195 domBanner.inert = true;
4196 domMain.inert = true;
4197 }
4198
4199 function hideModal(modal) {
4200 modal.classList.add("hidden");
4201 domBanner.inert = false;
4202 domMain.inert = false;
4203 modal.blur();
41484204 }
41494205
41504206 function clearAsyncSearch() {
......@@ -4678,6 +4734,47 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
46784734 }
46794735 }
46804736
4737 function getLocalStorage() {
4738 if ("localStorage" in window) {
4739 try {
4740 return window.localStorage;
4741 } catch (ignored) {
4742 // localStorage may be disabled (SecurityError)
4743 }
4744 }
4745 // If localStorage isn't available, persist preferences only for the current session
4746 const sessionPrefs = {};
4747 return {
4748 getItem(key) {
4749 return key in sessionPrefs ? sessionPrefs[key] : null;
4750 },
4751 setItem(key, value) {
4752 sessionPrefs[key] = String(value);
4753 },
4754 };
4755 }
4756
4757 function loadPrefs() {
4758 const storedPrefSlashSearch = prefs.getItem("slashSearch");
4759 if (storedPrefSlashSearch === null) {
4760 // Slash search defaults to enabled for all browsers except Firefox
4761 setPrefSlashSearch(navigator.userAgent.indexOf("Firefox") === -1);
4762 } else {
4763 setPrefSlashSearch(storedPrefSlashSearch === "true");
4764 }
4765 }
4766
4767 function getPrefSlashSearch() {
4768 return prefs.getItem("slashSearch") === "true";
4769 }
4770
4771 function setPrefSlashSearch(enabled) {
4772 prefs.setItem("slashSearch", String(enabled));
4773 domPrefSlashSearch.checked = enabled;
4774 const searchKeys = enabled ? "<kbd>/</kbd> or <kbd>s</kbd>" : "<kbd>s</kbd>";
4775 domSearchKeys.innerHTML = searchKeys;
4776 domSearchPlaceholder.innerHTML = searchKeys + " to search, <kbd>?</kbd> for more options";
4777 }
46814778})();
46824779
46834780function toggleExpand(event) {