From d3ae48a564724bfae3212789a38cbf765f675c49 Mon Sep 17 00:00:00 2001
From: Luffy <52o@qq52o.cn>
Date: Fri, 30 Oct 2026 16:29:04 +0800
Subject: [PATCH 1/2] fix: improve G-S search modal input
---
include/header.inc | 2 +-
public/js/common.js | 53 +++++++++----------
public/js/search.js | 9 ++++
public/styles/theme-base.css | 98 ++++++++++++++++++++++++++++++------
4 files changed, 116 insertions(+), 46 deletions(-)
diff --git a/include/header.inc b/include/header.inc
index 4660e5fb39..92abb26c70 100644
--- a/include/header.inc
+++ b/include/header.inc
@@ -330,7 +330,7 @@ if (!isset($config["languages"])) {
diff --git a/public/js/common.js b/public/js/common.js
index fe45d50041..3236b599a1 100644
--- a/public/js/common.js
+++ b/public/js/common.js
@@ -21,7 +21,14 @@ Mousetrap.bind("?", function () {
});
Mousetrap.bind("esc", function () {
$("#trick").slideUp();
- $("#goto").slideUp();
+ $("#goto").slideUp(function () {
+ if ($(this).is(":visible")) {
+ return;
+ }
+
+ $("#goto .text").val("");
+ $("#goto .results ul").empty();
+ });
$("html").off("keydown");
$("html").off("keypress");
@@ -196,48 +203,36 @@ Mousetrap.bind("g s", function (e) {
});
function boogie(e, cb) {
- cb($("#goto .text").text());
- $("#goto .results a:first").focus();
+ e.preventDefault();
+ var searchInput = $("#goto .text");
+ cb(searchInput.val());
$("#goto").slideToggle();
+ $("#goto").scrollTop(0);
+ searchInput[0].focus({ preventScroll: true });
+
+ searchInput.off("input.gotoSearch").on("input.gotoSearch", function () {
+ var txt = $(this).val().trim();
+ $("#goto .results ul").empty();
+ cb(txt);
+ });
$("html").on("keydown", function (e) {
switch (e.which || e.keyCode) {
- case 8:
- /* Backspace */
- var txt = $("#goto .text").text();
- txt = txt.substring(0, txt.length - 1);
- $("#goto .text").text(txt);
- $("#goto .results ul").empty();
- cb(txt);
- $("#goto .results a:first").focus();
- e.preventDefault();
- break;
case 13:
/* Enter */
+ var firstResult = $("#goto .results a:first")[0];
+ if (firstResult) {
+ firstResult.click();
+ }
Mousetrap.unpause();
Mousetrap.trigger('esc');
+ e.preventDefault();
return true;
- case 9:
- /* Tab */
- $(document.activeElement).parent().next().first().focus();
- break;
case 27:
Mousetrap.unpause();
Mousetrap.trigger('esc');
}
});
- $("html").on("keypress", function (e) {
- if (e.which == 13) {
- return true;
- }
- e.preventDefault();
- var letter = String.fromCharCode(e.which || e.keyCode);
- $("#goto .text").append(letter);
- var txt = $("#goto .text").text().trim();
- $("#goto .results ul").empty();
- cb(txt);
- $("#goto .results a:first").focus();
- });
Mousetrap.pause();
}
diff --git a/public/js/search.js b/public/js/search.js
index 5fdd21d8df..0411c48345 100644
--- a/public/js/search.js
+++ b/public/js/search.js
@@ -255,6 +255,15 @@ const initSearchModal = () => {
// Open when / is pressed
document.addEventListener("keydown", (event) => {
+ if (event.key === "/") {
+ const gotoOverlay = document.getElementById("goto");
+ if (gotoOverlay && getComputedStyle(gotoOverlay).display !== "none") {
+ event.preventDefault();
+ event.stopImmediatePropagation();
+ return;
+ }
+ }
+
const target = event.target;
if (
diff --git a/public/styles/theme-base.css b/public/styles/theme-base.css
index 00dafff1d5..79cebfa04a 100644
--- a/public/styles/theme-base.css
+++ b/public/styles/theme-base.css
@@ -1307,29 +1307,95 @@ div.soft-deprecation-notice blockquote.sidebar {
#goto {
display: none;
- background-color: var(--dark-grey-color);
- height: 100%;
- width: 100%;
- opacity: 0.9;
position: fixed;
- top: 64px;
+ inset: 0;
z-index: 5000;
color: #E6E6E6;
+ box-sizing: border-box;
+ overflow-y: auto;
+ padding: 0 1rem 1rem;
+ background-color: rgba(0, 0, 0, 0.65);
+}
+#goto div {
+ width: auto;
+}
+#goto .search {
+ width: min(100%, 52rem);
+ margin: 0 auto;
+ padding: 0.625rem clamp(1rem, 3vw, 1.75rem) 1rem;
+ box-sizing: border-box;
+ border: 1px solid rgba(255, 255, 255, 0.12);
+ border-radius: 1rem;
+ background-color: var(--dark-grey-color);
+ box-shadow: 0 1.25rem 3rem rgba(0, 0, 0, 0.35);
+}
+#goto .search .text {
+ display: block;
+ box-sizing: border-box;
+ width: 100%;
+ min-height: 2.5rem;
+ padding: 0.5rem 0.75rem;
+ color: #222;
+ font-size: 1rem;
+ line-height: 1.5;
+ border: 0;
+ border-radius: 0.5rem;
+ background-color: #fff;
+}
+#goto .search .text::placeholder {
+ color: #777;
+ opacity: 1;
+}
+#goto .search .text:focus {
+ outline: none;
+ box-shadow: none;
}
#goto .search .results {
- text-shadow: 0 2px 3px #555;
- font-size: 2rem;
- line-height: 1;
+ margin-top: 1rem;
+ font-size: 1.125rem;
+ line-height: 1.5;
}
-#goto .search .results :focus {
- font-size: 2rem;
- line-height: 1.2;
+#goto .search .results ul {
+ margin: 0;
+ padding: 0;
+ list-style: none;
}
-#goto .search .text {
- color: #222;
- text-shadow: 0 2px 3px #555;
- font-size: 10rem;
- line-height: .7;
+#goto .search .results ul:empty::before {
+ content: "No matching pages found";
+ display: block;
+ padding: 0.5rem 0.75rem;
+ color: rgba(255, 255, 255, 0.7);
+}
+#goto .search .text:placeholder-shown ~ .results ul:empty::before {
+ content: none;
+}
+#goto .search .results li + li {
+ margin-top: 0.25rem;
+}
+#goto .search .results a {
+ display: block;
+ padding: 0.65rem 0.75rem;
+ overflow-wrap: anywhere;
+ color: #E6E6E6;
+ text-decoration: none;
+ border-bottom: 0;
+ border-radius: 0.5rem;
+}
+#goto .search .results a:hover,
+#goto .search .results a:focus {
+ color: #fff;
+ outline: 2px solid rgba(255, 255, 255, 0.45);
+ outline-offset: -2px;
+ background-color: rgba(255, 255, 255, 0.1);
+}
+@media (min-width: 992px) {
+ #goto {
+ padding-top: 1rem;
+ }
+
+ #goto .search {
+ padding-top: 1.125rem;
+ }
}
#trick {
display: none;
From bfe2a15b8bb5642948f7730b9d827db058ffd84d Mon Sep 17 00:00:00 2001
From: Luffy <52o@qq52o.cn>
Date: Mon, 2 Nov 2026 16:04:48 +0800
Subject: [PATCH 2/2] Fix enhance keyboard navigation for search modal
---
public/js/search.js | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/public/js/search.js b/public/js/search.js
index 0411c48345..a7039638f0 100644
--- a/public/js/search.js
+++ b/public/js/search.js
@@ -257,7 +257,12 @@ const initSearchModal = () => {
document.addEventListener("keydown", (event) => {
if (event.key === "/") {
const gotoOverlay = document.getElementById("goto");
- if (gotoOverlay && getComputedStyle(gotoOverlay).display !== "none") {
+ const gotoInput = gotoOverlay?.querySelector(".text");
+ if (
+ gotoOverlay &&
+ getComputedStyle(gotoOverlay).display !== "none" &&
+ event.target !== gotoInput
+ ) {
event.preventDefault();
event.stopImmediatePropagation();
return;