doc search style

This commit is contained in:
RickCole21 2020-08-21 17:33:31 +08:00
parent 5591a5db4e
commit 4c12b0e2d9
3 changed files with 187 additions and 37 deletions

View File

@ -281,10 +281,10 @@ export class App extends React.PureComponent {
}} }}
/> />
</div> </div>
</div>
<div className="hidden-xs p-t pull-right"> <div className={`${theme.ns}Layout-searchBar hidden-xs hidden-sm`}>
<DocSearch theme={this.state.theme.value} /> <DocSearch theme={theme} />
</div>
</div> </div>
<a <a

View File

@ -2,8 +2,10 @@
* @file 实现前端文档搜索 * @file 实现前端文档搜索
*/ */
import React from 'react'; import React from 'react';
import Axios from 'axios'; import axios from 'axios';
import SearchBox from '../../src/components/SearchBox'; import SearchBox from '../../src/components/SearchBox';
import Drawer from '../../src/components/Drawer';
import {Icon} from '../../src';
let ContextPath = ''; let ContextPath = '';
@ -13,17 +15,27 @@ if (process.env.NODE_ENV === 'production') {
export default class DocSearch extends React.Component { export default class DocSearch extends React.Component {
docs = []; docs = [];
ref = React.createRef();
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
query: '',
show: false,
searchResults: [], searchResults: [],
loadError: false loadError: false
}; };
this.onSearch = this.onSearch.bind(this); this.onSearch = this.onSearch.bind(this);
this.onSearchCancel = this.onSearchCancel.bind(this); this.onChange = this.onChange.bind(this);
this.onOpen = this.onOpen.bind(this);
this.onClose = this.onClose.bind(this);
this.onEntered = this.onEntered.bind(this);
this.onExited = this.onExited.bind(this);
this.clearValue = this.clearValue.bind(this);
} }
componentDidMount() { componentDidMount() {
Axios.get(ContextPath + __uri('../docs.json')) axios
.get(ContextPath + __uri('../docs.json'))
.then(result => { .then(result => {
this.docs = result.data.docs; this.docs = result.data.docs;
}) })
@ -32,12 +44,14 @@ export default class DocSearch extends React.Component {
}); });
} }
onSearch(query) { onSearch() {
query = query.trim().toLowerCase(); let query = this.state.query.trim().toLowerCase();
if (query === '') { if (query === '') {
this.setState({searchResults: []}); this.setState({searchResults: []});
return; return;
} }
let results = []; let results = [];
for (let doc of this.docs) { for (let doc of this.docs) {
let index = doc.body.indexOf(query); let index = doc.body.indexOf(query);
@ -67,28 +81,94 @@ export default class DocSearch extends React.Component {
this.setState({searchResults: results}); this.setState({searchResults: results});
} }
onSearchCancel() { onChange(e) {
this.setState(
{
query: e.currentTarget.value
},
() => this.onSearch()
);
}
onOpen() {
this.setState({
show: true
});
}
onClose() {
this.setState({
show: false
});
}
onEntered() {
this.ref.current.focus();
}
onExited() {
this.setState({searchResults: []}); this.setState({searchResults: []});
} }
clearValue() {
this.setState(
{
query: ''
},
() => {
this.setState({searchResults: []});
}
);
}
render() { render() {
const searchResults = this.state.searchResults; const searchResults = this.state.searchResults;
const ns = this.props.theme.ns;
return ( return (
<div className="p-r"> <>
<SearchBox onSearch={this.onSearch} onCancel={this.onSearchCancel} /> <div className={`${ns}TextControl-input Doc-search`}>
{searchResults.length > 0 ? ( <Icon icon="search" className="icon" />
<div className="search-result"> <input readOnly placeholder={'搜索...'} onClick={this.onOpen} />
{searchResults.map(item => { </div>
return (
<a href={ContextPath + item.path} key={`list_${item.path}`}> <Drawer
<h5>{item.title}</h5> className="Doc-searchDrawer"
<p dangerouslySetInnerHTML={{__html: item.abstract}} /> overlay
</a> closeOnOutside
); onHide={this.onClose}
})} onEntered={this.onEntered}
onExited={this.onExited}
show={this.state.show}
position={'right'}
>
<div className={`${this.props.theme.ns}TextControl-input search-bar`}>
<Icon icon="search" className="icon" />
<input
ref={this.ref}
placeholder={'搜索...'}
onChange={this.onChange}
value={this.state.query}
/>
{this.state.query ? (
<a onClick={this.clearValue} className={`${ns}TextControl-clear`}>
<Icon icon="close" className="icon" />
</a>
) : null}
</div> </div>
) : null}
</div> {searchResults.length > 0 ? (
<div className="search-result">
{searchResults.map(item => {
return (
<a href={ContextPath + item.path} key={`list_${item.path}`}>
<h4>{item.title}</h4>
<p dangerouslySetInnerHTML={{__html: item.abstract}} />
</a>
);
})}
</div>
) : null}
</Drawer>
</>
); );
} }
} }

View File

@ -218,7 +218,13 @@ a {
width: 120px; width: 120px;
.Doc-search { .Doc-search {
top: 15px; margin-top: 15px;
border: 0;
> .icon-search {
margin-right: 8px;
top: 3px;
}
} }
&::before { &::before {
@ -712,20 +718,84 @@ a {
} }
} }
.search-result { .Doc-searchDrawer {
background-color: #fff; border: 0;
top: 50px;
bottom: 0; .a-Drawer-content,
position: fixed; .cxd-Drawer-content,
overflow-y: scroll; .dark-Drawer-content {
overflow-x: hidden; border: 0;
box-shadow: 0px 2px 7px #888888;
a {
padding: 0 5px;
display: block;
} }
a:hover {
background-color: $gray200; .a-Drawer-close,
.cxd-Drawer-close,
.dark-Drawer-close {
display: none;
}
.a-Drawer-overlay,
.cxd-Drawer-overlay,
.dark-Drawer-overlay {
background-color: rgba(25, 35, 60, 0.3);
}
.search-bar {
padding: 22px 20px;
border: 0;
border-bottom: 1px solid #e8ebee;
border-radius: 0;
font-size: 16px;
font-weight: 500;
> .icon-search {
margin-right: 10px;
top: 4px;
}
}
.search-result {
// background-color: #fff;
top: 65px;
bottom: 0;
left: 0;
right: 0;
position: fixed;
overflow-y: scroll;
overflow-x: hidden;
// box-shadow: 0px 2px 7px #888888;
h4,
p {
padding: 20px;
border-bottom: 1px solid #e8ebee;
margin: 0;
&:hover {
background-color: #f5f7f9;
}
}
h4 {
font-weight: 500;
position: relative;
color: #000;
&::before {
content: ' ';
border-left: 2px solid #108cee;
margin-right: 10px;
}
}
p {
color: #666;
strong {
color: #19233c;
background-color: rgba(16, 140, 238, 0.3);
font-weight: 700;
}
}
} }
} }