Skip to content

Commit d25ec32

Browse files
committed
添加搜索结果高亮
1 parent 92c27f3 commit d25ec32

File tree

2 files changed

+68
-11
lines changed

2 files changed

+68
-11
lines changed

docs/content/setup/feature.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,4 +193,16 @@ PageForge 支持 Dark Mode,需要启用后才能使用。
193193
feature:
194194
darkMode:
195195
enable: true
196+
```
197+
198+
## 搜索功能
199+
200+
---
201+
202+
PageForge 支持搜索功能,需要启用后才能使用。
203+
204+
```yaml
205+
feature:
206+
search:
207+
enable: true
196208
```

templates/assets/js/pageforge-search.js

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,45 @@ const Search = {
132132
}
133133
},
134134

135+
// 高亮文本
136+
highlightText(text, query) {
137+
if (!text || !query) {
138+
return text;
139+
}
140+
141+
// 转义正则表达式特殊字符
142+
const escapedQuery = query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
143+
const regex = new RegExp(`(${escapedQuery})`, 'gi');
144+
145+
return text.replace(regex, `<mark class="bg-yellow-200 dark:bg-yellow-800 dark:text-gray-100">$1</mark>`);
146+
},
147+
148+
// 获取包含匹配内容的摘要
149+
getContentExcerpt(content, query, maxLength = 160) {
150+
if (!content || !query) {
151+
return content;
152+
}
153+
154+
const lowerContent = content.toLowerCase();
155+
const lowerQuery = query.toLowerCase();
156+
const matchIndex = lowerContent.indexOf(lowerQuery);
157+
158+
if (matchIndex === -1) {
159+
return content.substring(0, maxLength);
160+
}
161+
162+
// 确定摘要的起始和结束位置
163+
let start = Math.max(0, matchIndex - 60);
164+
let end = Math.min(content.length, matchIndex + 100);
165+
166+
// 如果摘要不是从开头开始,添加省略号
167+
let excerpt = (start > 0 ? '...' : '') +
168+
content.substring(start, end) +
169+
(end < content.length ? '...' : '');
170+
171+
return excerpt;
172+
},
173+
135174
// 执行搜索
136175
async performSearch(query) {
137176
// 确保索引已加载
@@ -164,17 +203,23 @@ const Search = {
164203

165204
this.els.searchResults.innerHTML = `
166205
<div class="divide-y divide-gray-100 dark:divide-gray-800">
167-
${results.map(result => `
168-
<a href="${result.url}"
169-
class="block px-4 py-3 hover:bg-gray-50 dark:hover:bg-gray-700/50">
170-
<div class="text-sm font-medium text-gray-900 dark:text-gray-100">
171-
${result.title}
172-
</div>
173-
<div class="mt-1 text-sm text-gray-500 dark:text-gray-400 line-clamp-2">
174-
${result.content.substring(0, 160)}...
175-
</div>
176-
</a>
177-
`).join('')}
206+
${results.map(result => {
207+
const highlightedTitle = this.highlightText(result.title, query);
208+
const contentExcerpt = this.getContentExcerpt(result.content, query);
209+
const highlightedContent = this.highlightText(contentExcerpt, query);
210+
211+
return `
212+
<a href="${result.url}"
213+
class="block px-4 py-3 hover:bg-gray-50 dark:hover:bg-gray-700/50">
214+
<div class="text-sm font-medium text-gray-900 dark:text-gray-100">
215+
${highlightedTitle}
216+
</div>
217+
<div class="mt-1 text-sm text-gray-500 dark:text-gray-400 line-clamp-2">
218+
${highlightedContent}
219+
</div>
220+
</a>
221+
`;
222+
}).join('')}
178223
</div>
179224
`;
180225
}

0 commit comments

Comments
 (0)