Skip to content

Commit 8a1b9ba

Browse files
committed
feat: add full text search document for html.
1 parent e26acfc commit 8a1b9ba

File tree

6 files changed

+76
-88
lines changed

6 files changed

+76
-88
lines changed

README.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,4 @@ This project follows the all-contributors specification. All kinds of contributi
5656

5757
> 中国大陆用户可以加微信群一起讨论设计与代码实现细节。
5858
59-
<img src="https://github.com/auula/typikon/assets/38412458/1eac857f-0309-404d-a8f9-f92dd1606677" alt="Alt text" style="width: 180px; height: 260px;">
60-
61-
59+
<img src="https://img.ibyte.me/nlbxzp.jpg" alt="Alt text" style="width: 180px; height: 260px;">

src/book/builder.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use tera::{Context, Tera};
22

33
use crate::{
4-
book::data::Document,
4+
book::search::Document,
55
cli,
66
html::{self, Hypertext, Markdown, Template},
77
utils::{self, Logger},
@@ -146,10 +146,10 @@ impl Builder {
146146

147147
// push full text search data
148148
self.document_index += 1;
149-
let _ = &mut self.search_data.push(Document::new(
149+
self.search_data.push(Document::new(
150150
self.document_index,
151151
"/index.html".to_string(),
152-
template.name,
152+
template.name.clone(),
153153
hypertext.to_html(),
154154
));
155155

@@ -206,7 +206,7 @@ impl Builder {
206206

207207
// push full text search data
208208
self.document_index += 1;
209-
let _ = &mut self.search_data.push(Document::new(
209+
self.search_data.push(Document::new(
210210
self.document_index,
211211
format!(
212212
"/{}/{}.html",
@@ -267,7 +267,7 @@ impl Builder {
267267

268268
// push full text search data
269269
self.document_index += 1;
270-
let _ = &mut self.search_data.push(Document::new(
270+
self.search_data.push(Document::new(
271271
self.document_index,
272272
format!(
273273
"/{}/index.html",
@@ -324,7 +324,7 @@ impl Builder {
324324
chapter_path
325325
));
326326
}
327-
Err(_) => continue,
327+
Err(_) => log.error(format_args!("file not found {:?}", &chapter_path)),
328328
}
329329
}
330330

src/book/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
pub mod builder;
22
pub mod root;
3-
pub mod data;
3+
pub mod search;
44
pub mod settings;
55

66
pub use builder::*;
77
pub use root::*;
8-
pub use data::*;
8+
pub use search::*;
99
pub use settings::*;
File renamed without changes.

src/utils/file.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pub fn remove_md_extension(filename: &str) -> String {
4242
}
4343

4444
pub fn download_zip() -> Result<(), Box<dyn std::error::Error>> {
45-
let repo_url = "https://github.com/typikonbook/typikon-book/archive/refs/heads/main.zip";
45+
let repo_url = "https://github.com/typikonbook/typikon-book-v3/archive/refs/heads/main.zip";
4646
let zip_path = Path::new("repo.zip");
4747
let extract_path = Path::new(".");
4848

theme/typikon-theme/index.html

+66-76
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@
44
<head>
55
<meta charset="UTF-8">
66
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7-
87
<title>{{ title }}</title>
9-
<meta name="description" content="{{ description }}" />
10-
<meta name="keywords" content="{{ keywords }}" />
11-
<meta name="generator" content="typikon" />
12-
<meta name="template" content="typikon-theme" />
8+
<meta name="description" content="{{ description }}">
9+
<meta name="keywords" content="{{ keywords }}">
10+
<meta name="generator" content="typikon">
11+
<meta name="template" content="typikon-theme">
1312

1413
{% for css_path in custom_css %}
1514
<link rel="stylesheet" href="{{ css_path | safe }}">
@@ -20,7 +19,6 @@
2019
<link rel="stylesheet" href="/assets/dark-theme.css" id="dark-theme" disabled>
2120

2221
<link rel="icon" href="{{ icon | safe }}" type="image/png">
23-
2422
</head>
2523

2624
<body>
@@ -41,7 +39,7 @@
4139
</path>
4240
</svg>
4341
</span>
44-
<input type="text" class="form-control" id="serach-text" placeholder="Full text serach..."
42+
<input type="text" class="form-control" id="search-text" placeholder="Full text search..."
4543
aria-describedby="basic-addon1">
4644
</div>
4745
<ul class="list-unstyled ps-0" id="chapterList">
@@ -90,36 +88,29 @@
9088
{% endfor %}
9189

9290
<script>
93-
document.addEventListener('DOMContentLoaded', initTheme);
94-
window.onload = () => {
95-
themeChange();
96-
fullTextSearch();
97-
};
91+
document.addEventListener('DOMContentLoaded', function () {
92+
initTheme();
93+
initializeSearch();
94+
});
9895

99-
function initTheme(event) {
96+
function initTheme() {
10097
const darkThemeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
10198
const lightThemeLink = document.getElementById('light-theme');
10299
const darkThemeLink = document.getElementById('dark-theme');
103100

104-
changeTheme = (mediaQuery) => {
101+
const changeTheme = (mediaQuery) => {
105102
if (mediaQuery.matches) {
106-
// Dark mode
107103
lightThemeLink.setAttribute('disabled', true);
108104
darkThemeLink.removeAttribute('disabled');
109105
} else {
110-
// Light mode
111106
darkThemeLink.setAttribute('disabled', true);
112107
lightThemeLink.removeAttribute('disabled');
113108
}
114109
};
115110

116-
// Initial check
117111
changeTheme(darkThemeMediaQuery);
118-
119-
// Listen for changes in OS theme
120112
darkThemeMediaQuery.addListener(changeTheme);
121113

122-
// Initial highlight.js
123114
document.querySelectorAll('pre code').forEach((block) => {
124115
hljs.highlightElement(block);
125116
});
@@ -131,62 +122,61 @@
131122
paragraph.classList.add('md-p');
132123
});
133124
}
134-
};
135-
136-
function fullTextSearch() {
137-
// Full text search data
138-
const data = [
139-
{ id: '1', title: '示例文档一', content: '这是示例文档一的内容。' },
140-
{ id: '2', title: '示例文档二', content: '这是示例文档二的内容。' }
141-
];
142-
143-
// Fuse.js options
144-
const options = {
145-
keys: ['title', 'content'],
146-
includeScore: true,
147-
tokenize: true,
148-
threshold: 0.3,
149-
tokenSeparator: /[,||]/
150-
};
151-
152-
const fuse = new Fuse(data, options);
153-
const chapterList = document.getElementById('chapterList');
154-
155-
function performSearch() {
156-
const query = document.getElementById('serach-text').value.trim();
157-
const results = fuse.search(query);
158-
159-
chapterList.style.display = query !== '' ? 'none' : 'block';
160-
161-
results.forEach(result => {
162-
console.log(`${result.item.title} - ${result.item.content}`);
163-
});
164-
};
165-
166-
const searchInput = document.getElementById("serach-text");
167-
searchInput.addEventListener("input", performSearch);
168-
};
169-
170-
function themeChange() {
171-
const darkThemeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
172-
const lightThemeLink = document.getElementById('light-theme');
173-
const darkThemeLink = document.getElementById('dark-theme');
174-
changeTheme = (mediaQuery) => {
175-
if (mediaQuery.matches) {
176-
// Dark mode
177-
lightThemeLink.setAttribute('disabled', true);
178-
darkThemeLink.removeAttribute('disabled');
179-
} else {
180-
// Light mode
181-
darkThemeLink.setAttribute('disabled', true);
182-
lightThemeLink.removeAttribute('disabled');
183-
}
184-
};
185-
// Initial check
186-
changeTheme(darkThemeMediaQuery);
187-
// Listen for changes in OS theme
188-
darkThemeMediaQuery.addListener(changeTheme);
189-
};
125+
}
126+
127+
function initializeSearch() {
128+
fetch('/data.json')
129+
.then(response => response.json())
130+
.then(data => {
131+
const options = {
132+
keys: ['title', "content"],
133+
includeScore: true,
134+
tokenize: true,
135+
threshold: 0.3,
136+
tokenSeparator: /[,||]/
137+
};
138+
139+
const fuse = new Fuse(data, options);
140+
const chapterList = document.getElementById('chapterList');
141+
// 复制一份复原使用
142+
let innerHTML = chapterList.innerHTML;
143+
function performSearch() {
144+
const query = document.getElementById('search-text').value.trim();
145+
const results = fuse.search(query);
146+
147+
// 设置显示菜单和搜索结果,如果没有搜索结果就显示菜单,有则反之
148+
chapterList.innerHTML = results.length <= 0 ? chapterList.innerHTML = innerHTML : '';
149+
150+
// 遍历搜索结果并生成对应的 HTML
151+
results.forEach(result => {
152+
const sub_chapter = result.item; // 假设每个搜索结果是 sub_chapter 对象
153+
154+
// 构建章节和子章节的列表项 HTML
155+
const listItem = `
156+
<li class="mb-1">
157+
<div class="collapse show" id="collapse1">
158+
<ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small">
159+
<li>
160+
<a href="${sub_chapter.url}"
161+
class="link-body-emphasis d-inline-flex text-decoration-none rounded">
162+
${sub_chapter.title}
163+
</a>
164+
</li>
165+
</ul>
166+
</div>
167+
</li>
168+
`;
169+
170+
// 将拼接好的章节列表项添加到章节列表容器
171+
chapterList.innerHTML += listItem;
172+
});
173+
}
174+
175+
const searchInput = document.getElementById('search-text');
176+
searchInput.addEventListener('input', performSearch);
177+
})
178+
.catch(error => console.error('Error fetching data:', error));
179+
}
190180
</script>
191181
</body>
192182

0 commit comments

Comments
 (0)