Skip to content

Commit 70addc4

Browse files
committed
feat(search): add basic search functionality
1 parent 570c043 commit 70addc4

File tree

6 files changed

+144
-0
lines changed

6 files changed

+144
-0
lines changed

src/webapp/components/filelist/filelist.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88
flex-direction: column;
99
align-items: stretch;
1010
border: solid 1px #999;
11+
box-sizing: border-box;
1112
}

src/webapp/components/report/report.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
@import "../header/header";
2+
@import "../search/search";
23
@import "../stats/stats";
34
@import "../breadcrumbs/breadcrumbs";
45
@import "../filebox/filebox";

src/webapp/components/report/report.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import h from 'virtual-dom/h';
22
import findSubtree from '../../services/find-subtree';
33
import header from '../header/header';
4+
import search from '../search/search';
45
import stats from '../stats/stats';
56
import footer from '../footer/footer';
67
import filebox from '../filebox/filebox';
@@ -12,6 +13,7 @@ export default function report(state) {
1213
className: 'report'
1314
}, [
1415
header(state),
16+
search(state),
1517
stats(currentSubtree),
1618
filebox(currentSubtree),
1719
footer(state)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
.search {
2+
position: relative;
3+
width: 55rem;
4+
margin-bottom: 0.5rem;
5+
}
6+
7+
/* --- search input --- */
8+
9+
.search__input {
10+
display: block;
11+
width: 100%;
12+
font-weight: normal;
13+
padding: 0.3rem 0.5rem;
14+
box-sizing: border-box !important;
15+
font-size: 0.9rem;
16+
border: solid 1px var(--textSubColor);
17+
}
18+
19+
.search__input::placeholder {
20+
color: #999;
21+
}
22+
23+
.search__input:focus {
24+
outline: none;
25+
}
26+
27+
/* --- search suggestion list --- */
28+
29+
.search__suggestion-list {
30+
position: absolute;
31+
left: 0;
32+
right: 50%;
33+
top: calc(100% - 1px);
34+
display: flex;
35+
flex-direction: column;
36+
background: #fff;
37+
box-sizing: border-box;
38+
border: solid 1px var(--textSubColor);
39+
}
40+
41+
.search__suggestion-list--visible {
42+
@extend .search__suggestion-list;
43+
display: block;;
44+
}
45+
46+
.search__suggestion-list--hidden {
47+
@extend .search__suggestion-list;
48+
display: none;
49+
}
50+
51+
/* --- search suggestion --- */
52+
53+
.search__suggestion {
54+
display: block;
55+
width: 100%;
56+
padding: 0.3rem 0.5rem;
57+
box-sizing: border-box;
58+
font-size: 0.9rem;
59+
border-bottom: solid 1px var(--textSubColor);
60+
color: var(--textColor);
61+
text-decoration: none;
62+
}
63+
64+
.search__suggestion:last-child {
65+
border-bottom: none;
66+
}
67+
68+
.search__suggestion:hover {
69+
background-color: #bdc3c7;
70+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import h from 'virtual-dom/h';
2+
import store from '../../store';
3+
4+
function suggestionsSelector(state) {
5+
const current = state.location.path[0];
6+
return Object
7+
.keys(state.files.contents)
8+
.filter(fileName => {
9+
return state.search && current !== fileName && fileName.includes(state.search);
10+
});
11+
}
12+
13+
function clearSearch() {
14+
store.dispatch({
15+
type: 'SEARCH',
16+
payload: ''
17+
});
18+
}
19+
20+
function runSearch(searchText) {
21+
store.dispatch({
22+
type: 'SEARCH',
23+
payload: searchText
24+
});
25+
}
26+
27+
function searchInput(searchText) {
28+
return h('input', {
29+
type: 'text',
30+
value: searchText,
31+
placeholder: 'Search for files in the project...',
32+
className: 'search__input',
33+
oninput: event => runSearch(event.target.value)
34+
}, []);
35+
}
36+
37+
function searchSuggestion(suggestion) {
38+
return h('a', {
39+
href: `#/${suggestion}`,
40+
className: 'search__suggestion',
41+
onclick: clearSearch()
42+
}, [suggestion]);
43+
}
44+
45+
function searchSuggestionList(suggestions) {
46+
return h('div', {
47+
className: suggestions.length ?
48+
'search__suggestion-list--visible' :
49+
'search__suggestion-list--hidden'
50+
}, suggestions.map(searchSuggestion));
51+
}
52+
53+
export default function search(state) {
54+
return h('div', {
55+
className: 'search'
56+
}, [
57+
searchInput(state.search),
58+
searchSuggestionList(suggestionsSelector(state))
59+
]);
60+
}

src/webapp/reducers/report-reducer.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,18 @@ function locationReducer(state = {}, action) {
1313
}
1414
}
1515

16+
function searchReducer(state = '', action) {
17+
switch (action.type) {
18+
case 'SEARCH':
19+
return action.payload;
20+
default:
21+
return state;
22+
}
23+
}
24+
1625
export default combineReducers({
1726
location: locationReducer,
27+
search: searchReducer,
1828
files: noopReducer,
1929
metrics: noopReducer,
2030
environment: noopReducer,

0 commit comments

Comments
 (0)