Skip to content

Commit f11b8e7

Browse files
authored
Merge pull request #14 from easyops-cn/steve/loading
feat: show loading status
2 parents 399dc14 + 853603a commit f11b8e7

File tree

4 files changed

+105
-5
lines changed

4 files changed

+105
-5
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"@hapi/joi": "^17.1.1",
3131
"autocomplete.js": "^0.38.0",
3232
"cheerio": "^1.0.0-rc.3",
33+
"clsx": "^1.1.1",
3334
"debug": "^4.2.0",
3435
"fs-extra": "^9.0.1",
3536
"klaw-sync": "^6.0.0",

src/client/theme/SearchBar/SearchBar.css

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,67 @@ html[data-theme="dark"] .doc-search-empty-icon {
164164
.aa-suggestion.aa-cursor mark {
165165
text-decoration: underline;
166166
}
167+
168+
/* Start: pure CSS loaders */
169+
/* https://loading.io/css/ */
170+
.lds-ring {
171+
display: none;
172+
position: absolute;
173+
left: calc(var(--ifm-navbar-padding-horizontal) + 10px);
174+
top: 6px;
175+
width: 20px;
176+
height: 20px;
177+
opacity: var(--search-local-loading-icon-opacity, 0.5);
178+
}
179+
180+
.lds-ring div {
181+
box-sizing: border-box;
182+
display: block;
183+
position: absolute;
184+
width: 16px;
185+
height: 16px;
186+
margin: 2px;
187+
border: 2px solid
188+
var(--search-load-loading-icon-color, var(--ifm-navbar-search-input-color));
189+
border-radius: 50%;
190+
animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
191+
border-color: var(
192+
--search-load-loading-icon-color,
193+
var(--ifm-navbar-search-input-color)
194+
)
195+
transparent transparent transparent;
196+
}
197+
198+
.lds-ring div:nth-child(1) {
199+
animation-delay: -0.45s;
200+
}
201+
202+
.lds-ring div:nth-child(2) {
203+
animation-delay: -0.3s;
204+
}
205+
206+
.lds-ring div:nth-child(3) {
207+
animation-delay: -0.15s;
208+
}
209+
210+
@keyframes lds-ring {
211+
0% {
212+
transform: rotate(0deg);
213+
}
214+
100% {
215+
transform: rotate(360deg);
216+
}
217+
}
218+
/* End: pure CSS loaders */
219+
220+
.navbar__search {
221+
position: relative;
222+
}
223+
224+
.search-index-loading .navbar__search-input {
225+
background-image: none;
226+
}
227+
228+
.search-index-loading .lds-ring {
229+
display: inline-block;
230+
}

src/client/theme/SearchBar/SearchBar.tsx

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import React, { ReactElement, useCallback, useRef } from "react";
1+
import React, { ReactElement, useCallback, useRef, useState } from "react";
22
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
33
import { useHistory } from "@docusaurus/router";
4+
import clsx from "clsx";
45
import { fetchIndexes } from "./fetchIndexes";
56
import { SearchSourceFactory } from "../../utils/SearchSourceFactory";
67
import { SuggestionTemplate } from "../../utils/SuggestionTemplate.js";
@@ -31,20 +32,23 @@ export default function SearchBar({
3132
const indexState = useRef("empty"); // empty, loaded, done
3233
// Should the input be focused after the index is loaded?
3334
const focusAfterIndexLoaded = useRef(false);
35+
const [loading, setLoading] = useState(false);
36+
const [inputChanged, setInputChanged] = useState(false);
3437

3538
const loadIndex = useCallback(async () => {
3639
if (indexState.current !== "empty") {
3740
// Do not load the index (again) if its already loaded or in the process of being loaded.
3841
return;
3942
}
4043
indexState.current = "loading";
44+
setLoading(true);
4145

4246
const [{ wrappedIndexes, zhDictionary }, autoComplete] = await Promise.all([
4347
fetchIndexes(baseUrl),
4448
fetchAutoCompleteJS(),
4549
]);
4650

47-
autoComplete(
51+
const search = autoComplete(
4852
searchBarRef.current,
4953
{
5054
hint: false,
@@ -73,10 +77,16 @@ export default function SearchBar({
7377
history.push(document.u);
7478
});
7579

80+
indexState.current = "done";
81+
setLoading(false);
82+
7683
if (focusAfterIndexLoaded.current) {
77-
(searchBarRef.current as HTMLInputElement).focus();
84+
const input = searchBarRef.current as HTMLInputElement;
85+
if (input.value) {
86+
search.autocomplete.open();
87+
}
88+
input.focus();
7889
}
79-
indexState.current = "done";
8090
}, [baseUrl, history]);
8191

8292
const onInputFocus = useCallback(() => {
@@ -93,17 +103,37 @@ export default function SearchBar({
93103
loadIndex();
94104
}, [loadIndex]);
95105

106+
const onInputChange = useCallback(
107+
(event: React.ChangeEvent<HTMLInputElement>) => {
108+
if (event.target.value) {
109+
setInputChanged(true);
110+
}
111+
},
112+
[]
113+
);
114+
96115
return (
97-
<div className="navbar__search">
116+
<div
117+
className={clsx("navbar__search", {
118+
"search-index-loading": loading && inputChanged,
119+
})}
120+
>
98121
<input
99122
placeholder="Search"
100123
aria-label="Search"
101124
className="navbar__search-input"
102125
onMouseEnter={onInputMouseEnter}
103126
onFocus={onInputFocus}
104127
onBlur={onInputBlur}
128+
onChange={onInputChange}
105129
ref={searchBarRef}
106130
/>
131+
<div className="lds-ring">
132+
<div></div>
133+
<div></div>
134+
<div></div>
135+
<div></div>
136+
</div>
107137
</div>
108138
);
109139
}

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2148,6 +2148,11 @@ cliui@^6.0.0:
21482148
strip-ansi "^6.0.0"
21492149
wrap-ansi "^6.2.0"
21502150

2151+
clsx@^1.1.1:
2152+
version "1.1.1"
2153+
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188"
2154+
integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==
2155+
21512156
co@^4.6.0:
21522157
version "4.6.0"
21532158
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"

0 commit comments

Comments
 (0)