|
116 | 116 | nav.querySelectorAll(".nav-children").forEach((el) => el.classList.add("open")); |
117 | 117 | nav.querySelectorAll(".nav-domain").forEach((el) => el.classList.add("expanded")); |
118 | 118 | } |
119 | | - // Full-text search results dropdown |
120 | | - showSearchResults(e.target.value); |
121 | | - }); |
122 | | - searchInput.addEventListener("focus", () => { |
123 | | - if (searchInput.value.trim()) showSearchResults(searchInput.value); |
| 119 | + // Full-text search: show results in main area |
| 120 | + if (e.target.value.trim()) { |
| 121 | + showSearchResults(e.target.value); |
| 122 | + } else { |
| 123 | + renderPage(); |
| 124 | + renderRail(); |
| 125 | + } |
124 | 126 | }); |
125 | | - searchInput.addEventListener("blur", (e) => { |
126 | | - setTimeout(() => removeSearchDropdown(), 200); |
| 127 | + searchInput.addEventListener("keydown", (e) => { |
| 128 | + if (e.key === "Escape") { |
| 129 | + searchInput.value = ""; |
| 130 | + searchInput.blur(); |
| 131 | + renderPage(); |
| 132 | + renderRail(); |
| 133 | + } |
127 | 134 | }); |
128 | 135 | } |
129 | 136 |
|
|
690 | 697 | } |
691 | 698 |
|
692 | 699 | let searchIndex = null; |
693 | | - let searchDropdown = null; |
694 | 700 |
|
695 | 701 | function initSearch() { |
696 | 702 | searchIndex = buildSearchIndex(); |
697 | 703 | } |
698 | 704 |
|
699 | 705 | function showSearchResults(query) { |
700 | 706 | if (!searchIndex) initSearch(); |
701 | | - removeSearchDropdown(); |
702 | | - |
703 | | - if (!query.trim()) return; |
| 707 | + if (!query.trim()) { renderPage(); renderRail(); return; } |
704 | 708 |
|
705 | 709 | const results = searchQuery(query, searchIndex); |
| 710 | + |
| 711 | + // Clear the concept rail during search |
| 712 | + rail.innerHTML = ` |
| 713 | + <div class="rail-header">${lang === 'cn' ? '搜索' : 'Search'}</div> |
| 714 | + <div class="rail-empty">${results.length} ${lang === 'cn' ? '个结果' : 'result(s)'}</div>`; |
| 715 | + |
706 | 716 | if (results.length === 0) { |
707 | | - const dd = createSearchDropdown(); |
708 | | - dd.innerHTML = `<div class="search-empty">${lang === 'cn' ? '未找到结果' : 'No results found'}</div>`; |
| 717 | + main.innerHTML = ` |
| 718 | + <div class="search-results-page"> |
| 719 | + <h1 class="article-title">${lang === 'cn' ? '搜索结果' : 'Search Results'}</h1> |
| 720 | + <p class="search-query-label">"${escapeHtml(query)}"</p> |
| 721 | + <div class="search-no-results"> |
| 722 | + <p>${lang === 'cn' ? '未找到匹配的内容。' : 'No matching content found.'}</p> |
| 723 | + <p style="color:var(--c-text-tertiary);font-size:0.875rem;">${lang === 'cn' ? '尝试不同的关键词或更短的查询。' : 'Try different keywords or a shorter query.'}</p> |
| 724 | + </div> |
| 725 | + </div>`; |
709 | 726 | return; |
710 | 727 | } |
711 | 728 |
|
712 | | - const dd = createSearchDropdown(); |
713 | | - let html = ""; |
| 729 | + let html = `<div class="search-results-page">`; |
| 730 | + html += `<h1 class="article-title">${lang === 'cn' ? '搜索结果' : 'Search Results'}</h1>`; |
| 731 | + html += `<p class="search-query-label">"${escapeHtml(query)}" — ${results.length} ${lang === 'cn' ? '个匹配' : 'match(es)'}</p>`; |
| 732 | + html += `<div class="search-results-list">`; |
| 733 | + |
714 | 734 | for (const r of results) { |
715 | 735 | const icon = r.type === "page" ? "📄" : "💡"; |
716 | | - const snippet = getSnippet(r.text, query); |
| 736 | + const snippet = getSnippet(r.text, query, 200); |
717 | 737 | const meta = r.type === "page" ? r.domain : (lang === 'cn' ? '概念' : 'Concept'); |
718 | | - html += `<div class="search-result" data-type="${r.type}" data-id="${r.id}">`; |
719 | | - html += `<div class="search-result-header">`; |
| 738 | + html += `<div class="search-result-card" data-type="${r.type}" data-id="${r.id}">`; |
| 739 | + html += `<div class="search-result-card-header">`; |
720 | 740 | html += `<span class="search-result-icon">${icon}</span>`; |
721 | 741 | html += `<span class="search-result-title">${r.title}</span>`; |
722 | | - html += `<span class="search-result-meta">${meta}</span>`; |
| 742 | + html += `<span class="search-result-badge">${meta}</span>`; |
723 | 743 | html += `</div>`; |
724 | | - html += `<div class="search-result-snippet">${snippet}</div>`; |
| 744 | + html += `<div class="search-result-body">${snippet}</div>`; |
725 | 745 | html += `</div>`; |
726 | 746 | } |
727 | | - dd.innerHTML = html; |
728 | 747 |
|
729 | | - dd.querySelectorAll(".search-result").forEach((el) => { |
| 748 | + html += `</div></div>`; |
| 749 | + main.innerHTML = html; |
| 750 | + |
| 751 | + main.querySelectorAll(".search-result-card").forEach((el) => { |
730 | 752 | el.addEventListener("click", () => { |
731 | 753 | const type = el.dataset.type; |
732 | 754 | const id = el.dataset.id; |
733 | | - removeSearchDropdown(); |
734 | 755 | document.getElementById("nav-search-input").value = ""; |
735 | 756 | if (type === "page") { |
736 | 757 | navigate(id); |
737 | 758 | } else { |
738 | | - // For concepts, navigate to the first page that uses it |
739 | 759 | const concept = WIKI.concepts?.[id]; |
740 | 760 | if (concept?.usedIn?.length > 0) { |
741 | 761 | navigate(concept.usedIn[0]); |
|
745 | 765 | }); |
746 | 766 | } |
747 | 767 |
|
748 | | - function createSearchDropdown() { |
749 | | - removeSearchDropdown(); |
750 | | - const dd = document.createElement("div"); |
751 | | - dd.className = "search-dropdown"; |
752 | | - dd.id = "search-dropdown"; |
753 | | - nav.appendChild(dd); |
754 | | - searchDropdown = dd; |
755 | | - return dd; |
756 | | - } |
757 | | - |
758 | | - function removeSearchDropdown() { |
759 | | - const existing = document.getElementById("search-dropdown"); |
760 | | - if (existing) existing.remove(); |
761 | | - searchDropdown = null; |
| 768 | + function escapeHtml(str) { |
| 769 | + return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """); |
762 | 770 | } |
763 | 771 |
|
764 | 772 | // Global keyboard shortcuts |
|
768 | 776 | const input = document.getElementById("nav-search-input"); |
769 | 777 | if (input) { input.focus(); input.select(); } |
770 | 778 | } |
771 | | - if (e.key === "Escape") { |
772 | | - removeSearchDropdown(); |
773 | | - const input = document.getElementById("nav-search-input"); |
774 | | - if (input) input.blur(); |
775 | | - } |
776 | 779 | }); |
777 | 780 |
|
778 | 781 | // === Init === |
|
0 commit comments