list.html 3.2 KB

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