Skip to content

Commit f5d7489

Browse files
committed
E search!
1 parent 9c4b00e commit f5d7489

File tree

9 files changed

+5458
-4583
lines changed

9 files changed

+5458
-4583
lines changed

packages/webdoc-default-template/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
"webpack": "^4.43.0",
8383
"webpack-stream": "^5.2.1",
8484
"redux": "~4.0.5",
85-
"react-redux": "~7.2.2"
85+
"react-redux": "~7.2.2",
86+
"lodash": "~4.17.20"
8687
}
8788
}

packages/webdoc-default-template/src/app/components/Explorer/ExplorerCategoryItem.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ export default function ExplorerCategoryItem(props) {
2323
label={props.title}
2424
>
2525
{props.data.map(
26-
(explorerTarget, i) => (<ExplorerItem key={i} data={explorerTarget} />),
26+
(explorerTarget, i) => (
27+
<ExplorerItem key={i} data={explorerTarget} toggle={props.toggle} />
28+
),
2729
)}
2830
</TreeItem>
2931
);
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import React from "react";
2+
import {connect} from "react-redux";
3+
import debounce from "lodash/debounce";
4+
import store from "../../store";
5+
6+
function filterTree(query, collector, data) {
7+
data.$match = !query || (!!data.title && data.title.toLowerCase().includes(query));
8+
9+
if (data.children) {
10+
for (const [key, value] of Object.entries(data.children)) {
11+
if (key.charAt(0) === "$") {
12+
continue;
13+
}
14+
filterTree(query, collector, value);
15+
data.$match = data.$match || value.$match;
16+
}
17+
}
18+
19+
if (query && data.$match) {
20+
collector.add(data.$nodeId);
21+
}
22+
}
23+
24+
export default connect(() => ({
25+
nextQuery: (query, items) => store.dispatch({
26+
type: "setQuery",
27+
value: query,
28+
items,
29+
}),
30+
}))(function ExplorerFilter(props) {
31+
const onNativeChange = React.useCallback(
32+
debounce((e) => {
33+
const query = e.target.value;
34+
const items = new Set();
35+
36+
const startish = Date.now();
37+
filterTree(query.toLowerCase(), items, props.data);
38+
console.log("Search took: " + Date.now() - startish + " ms");
39+
props.nextQuery(query, items);
40+
}, 200, {
41+
maxWait: 1000,
42+
}),
43+
[props.data],
44+
);
45+
46+
const onChange = React.useCallback(
47+
(e) => onNativeChange(e.nativeEvent),
48+
[onNativeChange],
49+
);
50+
51+
return (
52+
<input
53+
onChange={onChange}
54+
placeholder="Filter"
55+
type="text"
56+
/>
57+
);
58+
});

packages/webdoc-default-template/src/app/components/Explorer/ExplorerItem.js

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import {useExplorerCategoryStyles, useExplorerStyles} from "./useExplorerStyles";
2-
import ExplorerTargetGroup from "./ExplorerCategoryItem";
2+
import ExplorerCategoryItem from "./ExplorerCategoryItem";
33
import Link from "@material-ui/core/Link";
4-
//import React from "react";
4+
import React from "react";
55
import TreeItem from "@material-ui/lab/TreeItem";
6-
import cuid from "cuid";
76

87
export default function ExplorerItem(props) {
9-
if (!props.data.nodeId) {
10-
props.data.nodeId = cuid();
8+
if (!props.data.$nodeId) {
9+
throw new Error("Ids must be assigned");
1110
}
1211

1312
const classesItem = useExplorerStyles();
@@ -17,13 +16,23 @@ export default function ExplorerItem(props) {
1716
let i = 0;
1817
for (const [key, value] of Object.entries(props.data.children || {})) {
1918
targetChildren.push(Array.isArray(value) ?
20-
(<ExplorerTargetGroup key={i} title={key} data={value} />) :
21-
(<ExplorerItem key={i} data={value} />),
19+
(<ExplorerCategoryItem key={i} title={key} data={value} toggle={props.toggle} />) :
20+
(<ExplorerItem key={i} data={value} toggle={props.toggle} />),
2221
);
2322
i++;
2423
}
2524

2625
const classes = i > 0 ? classesCategory : classesItem;
26+
const nodeId = props.data.$nodeId;
27+
28+
const toggle = React.useCallback(
29+
() => props.toggle(nodeId),
30+
[nodeId],
31+
);
32+
33+
if (props.data.title !== "(overview)" && props.data.$match === false) {
34+
return null;
35+
}
2736

2837
return (
2938
<TreeItem
@@ -33,7 +42,8 @@ export default function ExplorerItem(props) {
3342
iconContainer: classes.iconContainer,
3443
selected: classes.selected,
3544
}}
36-
nodeId={props.data.nodeId}
45+
onClick={toggle}
46+
nodeId={nodeId}
3747
label={
3848
props.data.page ?
3949
(

packages/webdoc-default-template/src/app/components/Explorer/index.js

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,50 @@
11
import ArrowDropDownIcon from "@material-ui/icons/ArrowDropDown";
22
import ArrowRightIcon from "@material-ui/icons/ArrowRight";
3+
import ExplorerFilter from "./ExplorerFilter";
34
import ExplorerHeader from "./ExplorerHeader";
45
import ExplorerTarget from "./ExplorerItem";
56
import ExplorerTargetGroup from "./ExplorerCategoryItem";
67
import React from "react";
78
import TreeView from "@material-ui/lab/TreeView";
89
import {connect} from "react-redux";
10+
import cuid from "cuid";
911
import store from "../../store";
1012
import {useExplorerStyles} from "./useExplorerStyles";
1113

1214
let fetched = false;
1315

14-
export default connect(({explorerOpen}) => ({
16+
function makeIds(data) {
17+
data.$nodeId = cuid();
18+
19+
if (data.children) {
20+
for (const [, value] of Object.entries(data.children)) {
21+
makeIds(value);
22+
}
23+
}
24+
}
25+
26+
export default connect(({
27+
expandedItems,
28+
explorerOpen,
29+
query,
30+
}) => ({
1531
isOpen: explorerOpen,
16-
setOpen: (isOpen) => store.dispatch({type: "setExplorerOpen", value: isOpen}),
32+
query, /* Added for re-rendering when query updates */
33+
setOpen: (isOpen) => store.dispatch({
34+
type: "setExplorerOpen",
35+
value: isOpen,
36+
}),
37+
expandedItems: Array.from(expandedItems),
38+
toggleItem: (nodeId, optValue) => store.dispatch({
39+
type: "toggleItem",
40+
nodeId,
41+
value: optValue,
42+
}),
1743
}))(function Explorer({
1844
isOpen,
1945
setOpen,
46+
expandedItems,
47+
toggleItem,
2048
}) {
2149
const [data, setData] = React.useState(null);
2250
const {root} = useExplorerStyles();
@@ -29,7 +57,7 @@ export default connect(({explorerOpen}) => ({
2957
.then((response) => {
3058
if (response.ok) {
3159
response.json().then((idata) => {
32-
// console.log(idata);
60+
makeIds(idata);
3361
setData(idata || {});
3462
});
3563
} else {
@@ -45,9 +73,13 @@ export default connect(({explorerOpen}) => ({
4573
let i = 0;
4674
if (data) {
4775
for (const [key, value] of Object.entries(data.children || {})) {
76+
if (value.$match === false) {
77+
continue;
78+
}
79+
4880
children.push(Array.isArray(value) ?
49-
(<ExplorerTargetGroup key={i} title={key} data={value} />) :
50-
(<ExplorerTarget key={i} data={value} />),
81+
(<ExplorerTargetGroup key={i} title={key} data={value} toggle={toggleItem} />) :
82+
(<ExplorerTarget key={i} data={value} toggle={toggleItem} />),
5183
);
5284
i++;
5385
}
@@ -67,7 +99,9 @@ export default connect(({explorerOpen}) => ({
6799
}),
68100
}}>
69101
<ExplorerHeader isOpen={isOpen} toggleOpen={toggleOpen} />
102+
{data && <ExplorerFilter data={data} />}
70103
<TreeView
104+
expanded={expandedItems}
71105
className={"explorer__tree " + (
72106
isOpen ? "explorer__tree-open" : "explorer__tree-open"
73107
)}

packages/webdoc-default-template/src/app/store.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,47 @@ function globalReducer(state = {}, action) {
77
...state,
88
explorerOpen: action.value,
99
};
10+
case "setQuery":
11+
if (!state.query && action.value) {
12+
state.expandedItemsBeforeQuery = state.expandedItems;
13+
} else if (state.query && !action.value) {
14+
state.expandedItems = state.expandedItemsBeforeQuery;
15+
}
16+
17+
if (action.value) {
18+
return {
19+
...state,
20+
query: action.value,
21+
expandedItems: action.items,
22+
};
23+
} else {
24+
return {
25+
...state,
26+
query: action.value,
27+
};
28+
}
29+
case "toggleItem": {
30+
const expandedItems = new Set(state.expandedItems);
31+
32+
if (action.value !== undefined) {
33+
expandedItems[action.value ? "add" : "delete"](action.nodeId);
34+
} else {
35+
expandedItems[expandedItems.has(action.nodeId) ? "delete" : "add"](action.nodeId);
36+
}
37+
38+
return {
39+
...state,
40+
expandedItems,
41+
};
42+
}
1043
default:
1144
return state;
1245
}
1346
}
1447

1548
export default createStore(globalReducer, {
49+
expandedItems: new Set(),
1650
explorerOpen: true,
51+
expandedItemsBeforeQuery: new Set(),
52+
query: "",
1753
});

packages/webdoc-default-template/src/styles/explorer.scss

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,20 @@
1515
overflow: auto;
1616
}
1717

18+
input {
19+
border: 1px solid rgba(0, 0, 0, 0.04);
20+
border-radius: 4px;
21+
font: 12px Arial;
22+
margin: 8px 24px 0 24px;
23+
min-height: 32px;
24+
padding: 0 8px;
25+
}
26+
27+
input:focus {
28+
border: 1px solid rgba(0, 0, 0, 0.4);
29+
outline: none;
30+
}
31+
1832
&__tree > *:first-child {
1933
margin-top: 8px;
2034
}

0 commit comments

Comments
 (0)