index.html 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. {{ define "main" }}
  2. <section class="card page-head">
  3. <span class="eyebrow">Search</span>
  4. <h1>搜索</h1>
  5. <p>搜索全站文章和标签</p>
  6. <!-- 搜索框 -->
  7. <div class="search-box">
  8. <input type="text" id="search-input" placeholder="搜索文章标题、内容或标签..." />
  9. <div id="search-results" class="search-results"></div>
  10. </div>
  11. </section>
  12. <script src="https://cdn.jsdelivr.net/npm/fuse.js@6.6.2"></script>
  13. <script>
  14. // 文章内容索引
  15. const posts = [
  16. {{ range .Site.RegularPages }}
  17. {
  18. title: {{ .Title | jsonify }},
  19. url: {{ .RelPermalink | jsonify }},
  20. date: {{ .Date.Format "2006-01-02" | jsonify }},
  21. summary: {{ .Summary | plainify | jsonify }},
  22. tags: {{ .Params.tags | jsonify }},
  23. content: {{ .Content | plainify | jsonify }}
  24. },
  25. {{ end }}
  26. ];
  27. // 初始化 Fuse.js
  28. const options = {
  29. includeScore: true,
  30. threshold: 0.4,
  31. location: 0,
  32. distance: 100,
  33. maxPatternLength: 32,
  34. minMatchCharLength: 1,
  35. keys: [
  36. { name: "title", weight: 0.5 },
  37. { name: "content", weight: 0.3 },
  38. { name: "tags", weight: 0.2 }
  39. ]
  40. };
  41. const fuse = new Fuse(posts, options);
  42. // 搜索事件
  43. document.getElementById("search-input").addEventListener("input", function(e) {
  44. const query = e.target.value.trim();
  45. const resultsDiv = document.getElementById("search-results");
  46. if (!query) {
  47. resultsDiv.innerHTML = "";
  48. return;
  49. }
  50. const results = fuse.search(query);
  51. if (results.length === 0) {
  52. resultsDiv.innerHTML = '<p class="no-results">没有找到匹配的内容</p>';
  53. return;
  54. }
  55. resultsDiv.innerHTML = results.slice(0, 10).map(result => {
  56. const post = result.item;
  57. const tagsHtml = post.tags ? post.tags.map(tag =>
  58. `<span class="tag">${tag}</span>`
  59. ).join("") : "";
  60. // 高亮匹配内容
  61. const preview = post.summary
  62. .replace(/<[^>]*>/g, '')
  63. .substring(0, 150) + "...";
  64. return `
  65. <article class="search-result-item">
  66. <h3><a href="${post.url}">${post.title}</a></h3>
  67. <p class="meta">${post.date}</p>
  68. <p class="preview">${preview}</p>
  69. <div class="tags">${tagsHtml}</div>
  70. </article>
  71. `;
  72. }).join("");
  73. });
  74. </script>
  75. {{ end }}