Skip to content

Commit 915bd54

Browse files
committed
feat:#51 优化笔记搜索,添加自定完成功能
1 parent 3ccdd61 commit 915bd54

File tree

7 files changed

+259
-37
lines changed

7 files changed

+259
-37
lines changed

components/themes/default/css/searchbar.module.css

Whitespace-only changes.

components/themes/default/defaultNavbar.tsx

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ import {faBook, faDownload, faFile, faFileText, faHome, faPieChart} from '@forta
66
import SiteConfig from "../../../lib/common/siteconfig";
77
import {useState} from "react";
88
import Image from "next/image";
9-
import {isEmptyString} from "../../../lib/util";
10-
import {API_TYPE_CONSTANTS} from "../../../lib/constants";
119
import {CategoryInfo} from "../../../lib/common/categoryInfo";
10+
import DefaultSearchBar from "./defaultSearchBar";
1211

1312
export default function DefaultNavbar({
1413
props,
@@ -70,17 +69,22 @@ export default function DefaultNavbar({
7069
}
7170

7271
<Nav.Item>
73-
<Form onSubmit={(e) => handleSearch(e)} className={clsx("d-flex", navbarStyles.sFormGroup)}>
74-
<Form.Control
75-
type="text"
76-
value={value}
77-
placeholder="请输入关键词"
78-
onChange={(e) => setValue(e.target.value)}
79-
/>
80-
<Button type="submit">
81-
搜索
82-
</Button>
83-
</Form>
72+
{
73+
false &&
74+
<Form onSubmit={(e) => handleSearch(e)} className={clsx("d-flex", navbarStyles.sFormGroup)}>
75+
<Form.Control
76+
type="text"
77+
value={value}
78+
placeholder="请输入关键词"
79+
onChange={(e) => setValue(e.target.value)}
80+
/>
81+
<Button type="submit">
82+
搜索
83+
</Button>
84+
</Form>
85+
}
86+
87+
<DefaultSearchBar />
8488
</Nav.Item>
8589
</Container>
8690
</Navbar>
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import React, {useCallback, useState} from 'react';
2+
import {AsyncTypeahead} from 'react-bootstrap-typeahead';
3+
4+
import 'react-bootstrap-typeahead/css/Typeahead.css';
5+
import './css/searchbar.module.css';
6+
import {Button, Form} from "react-bootstrap";
7+
import clsx from "clsx";
8+
import navbarStyles from "./css/navbar.module.css";
9+
import {getRootBlocks} from "../../../lib/siyuan/siYuanApi";
10+
11+
const CACHE: any = {};
12+
const PER_PAGE = 50;
13+
// const SEARCH_URI = 'https://api.github.com/search/users';
14+
15+
export default function DefaultSearchBar() {
16+
const [isLoading, setIsLoading] = useState(false);
17+
const [options, setOptions] = useState([]);
18+
const [query, setQuery] = useState('');
19+
20+
const goPage = () => {
21+
window.location.href = "/s/" + query
22+
}
23+
24+
const handleInputChange = (q: string) => {
25+
setQuery(q);
26+
};
27+
28+
const handlePagination = (e: any, shownResults: any) => {
29+
const cachedQuery = CACHE[query];
30+
31+
// Don't make another request if:
32+
// - the cached results exceed the shown results
33+
// - we've already fetched all possible results
34+
if (
35+
cachedQuery.options.length > shownResults ||
36+
cachedQuery.options.length === cachedQuery.total_count
37+
) {
38+
return;
39+
}
40+
41+
setIsLoading(true);
42+
43+
const page = cachedQuery.page + 1;
44+
45+
makeAndHandleRequest(query, page).then((resp) => {
46+
const options = cachedQuery.options.concat(resp.options);
47+
CACHE[query] = {...cachedQuery, options, page};
48+
49+
setIsLoading(false);
50+
setOptions(options);
51+
});
52+
};
53+
54+
// `handleInputChange` updates state and triggers a re-render, so
55+
// use `useCallback` to prevent the debounced search handler from
56+
// being cancelled.
57+
const handleSearch = useCallback((q: string) => {
58+
if (CACHE[q]) {
59+
setOptions(CACHE[q].options);
60+
return;
61+
}
62+
63+
setIsLoading(true);
64+
makeAndHandleRequest(q).then((resp) => {
65+
CACHE[q] = {...resp, page: 1};
66+
67+
setIsLoading(false);
68+
// @ts-ignore
69+
setOptions(resp.options);
70+
});
71+
}, []);
72+
73+
return (
74+
<Form className={clsx("d-flex", navbarStyles.sFormGroup)}>
75+
<AsyncTypeahead
76+
id="async-pagination-searchbar"
77+
isLoading={isLoading}
78+
labelKey="login"
79+
maxResults={PER_PAGE - 1}
80+
minLength={1}
81+
onChange={goPage}
82+
onInputChange={handleInputChange}
83+
onPaginate={handlePagination}
84+
onSearch={handleSearch}
85+
options={options}
86+
paginate
87+
placeholder="请输入关键词"
88+
searchText="搜索中..."
89+
emptyLabel="暂无结果"
90+
paginationText="加载更多"
91+
promptText="输入关键词搜索"
92+
renderMenuItemChildren={(option: any) => (
93+
<div key={option.id}>
94+
<span>{option.login}</span>
95+
</div>
96+
)}
97+
useCache={false}
98+
/>
99+
<Button type="button" onClick={goPage}>
100+
搜索
101+
</Button>
102+
</Form>
103+
);
104+
}
105+
106+
function makeAndHandleRequest(query: any, page = 0) {
107+
return getRootBlocks(page, PER_PAGE, query).then((items: any) => {
108+
const options: any = []
109+
110+
if (items && items.length > 0) {
111+
items.forEach((i: any) => {
112+
const item = {
113+
id: i.root_id,
114+
login: i.content,
115+
}
116+
117+
options.push(item)
118+
});
119+
}
120+
console.log("items=>", items)
121+
122+
const total = options.length;
123+
const bardata = {options, total}
124+
console.log("bardata=>", bardata)
125+
return bardata;
126+
})
127+
128+
// return fetch(`${SEARCH_URI}?q=${query}+in:login&page=${page}&per_page=${PER_PAGE}`)
129+
// .then((resp) => resp.json())
130+
// .then(({items, total_count}) => {
131+
// const options = items.map((i: any) => ({
132+
// id: i.id,
133+
// login: i.login,
134+
// }));
135+
// return {options, total_count};
136+
// });
137+
}

lib/siyuan/siYuanApi.ts

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,12 @@ export {
8888
*/
8989
async function request(url: string, data: any, method?: string, useToken?: boolean) {
9090
let resData = null
91-
if (config.baseUrl != "") {
92-
url = config.baseUrl + url
91+
var baseUrl = config.baseUrl
92+
if (typeof baseUrl == "undefined" || baseUrl == "undefined") {
93+
baseUrl = "http://127.0.0.1:6806"
94+
}
95+
if (baseUrl != "") {
96+
url = baseUrl + url
9397
}
9498

9599
let m = "POST"
@@ -336,28 +340,27 @@ async function getHPathByID(blockId: string) {
336340
* @param pagesize 数目
337341
*
338342
* select DISTINCT b2.root_id,b2.parent_id,b2.content from blocks b2
339-
* WHERE 1==1
343+
* WHERE 1==1
340344
* AND b2.id IN (
341-
* SELECT DISTINCT b1.id
342-
* FROM blocks b1
343-
* WHERE 1 = 1
344-
* AND b1.parent_id=''
345-
* AND ((b1.content LIKE '%jdbc%') OR (b1.tag LIKE '%jdbc%'))
346-
* ORDER BY b1.created DESC LIMIT 0, 10
345+
* SELECT DISTINCT b1.root_id
346+
* FROM blocks b1
347+
* WHERE 1 = 1
348+
* AND ((b1.content LIKE '%github%') OR (b1.tag LIKE '%github%'))
349+
* ORDER BY b1.updated DESC,b1.created DESC LIMIT 0,10
347350
* )
351+
* ORDER BY b2.updated DESC,b2.created DESC
348352
*/
349353
async function getRootBlocks(page: number, pagesize: number, keyword: string) {
350354
let stmt = `select DISTINCT b2.root_id,b2.parent_id,b2.content from blocks b2
351355
WHERE 1==1
352-
AND b2.id IN (
353-
SELECT DISTINCT b1.id
354-
FROM blocks b1
355-
WHERE 1 = 1
356-
AND b1.parent_id=''
357-
AND ((b1.content LIKE '%${keyword}%') OR (b1.tag LIKE '%${keyword}%'))
358-
ORDER BY b1.updated DESC,b1.created DESC LIMIT ${page}, ${pagesize}
359-
)
360-
ORDER BY b2.updated DESC,b2.created DESC`
356+
AND b2.id IN (
357+
SELECT DISTINCT b1.root_id
358+
FROM blocks b1
359+
WHERE 1 = 1
360+
AND ((b1.content LIKE '%${keyword}%') OR (b1.tag LIKE '%${keyword}%'))
361+
ORDER BY b1.updated DESC,b1.created DESC LIMIT ${page},${pagesize}
362+
)
363+
ORDER BY b2.updated DESC,b2.created DESC`
361364
let data = await sql(stmt)
362365
return data
363366
}

lib/siyuan/siYuanApiAdaptor.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import {exportMdContent, getBlockAttrs, getBlockByID, getBlockBySlug, getDoc, ge
33
import {Post} from "../common/post";
44
import {UserBlog} from "../common/userBlog";
55
import {API_TYPE_CONSTANTS} from "../constants";
6-
import logUtil from "../logUtil";
7-
import {render} from "../markdownUtil";
86
import {mdToHtml, removeTitleNumber, removeWidgetTag} from "../htmlUtil";
97
import {CategoryInfo} from "../common/categoryInfo";
108

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"plantuml-encoder": "^1.4.0",
2222
"react": "18.2.0",
2323
"react-bootstrap": "^2.4.0",
24+
"react-bootstrap-typeahead": "^6.0.0",
2425
"react-dom": "18.2.0",
2526
"xmlrpc": "^1.3.2"
2627
},

0 commit comments

Comments
 (0)