doc search style
This commit is contained in:
parent
5591a5db4e
commit
4c12b0e2d9
|
@ -281,10 +281,10 @@ export class App extends React.PureComponent {
|
|||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="hidden-xs p-t pull-right">
|
||||
<DocSearch theme={this.state.theme.value} />
|
||||
</div>
|
||||
<div className={`${theme.ns}Layout-searchBar hidden-xs hidden-sm`}>
|
||||
<DocSearch theme={theme} />
|
||||
</div>
|
||||
|
||||
<a
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
* @file 实现前端文档搜索
|
||||
*/
|
||||
import React from 'react';
|
||||
import Axios from 'axios';
|
||||
import axios from 'axios';
|
||||
import SearchBox from '../../src/components/SearchBox';
|
||||
import Drawer from '../../src/components/Drawer';
|
||||
import {Icon} from '../../src';
|
||||
|
||||
let ContextPath = '';
|
||||
|
||||
|
@ -13,17 +15,27 @@ if (process.env.NODE_ENV === 'production') {
|
|||
|
||||
export default class DocSearch extends React.Component {
|
||||
docs = [];
|
||||
ref = React.createRef();
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
query: '',
|
||||
show: false,
|
||||
searchResults: [],
|
||||
loadError: false
|
||||
};
|
||||
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() {
|
||||
Axios.get(ContextPath + __uri('../docs.json'))
|
||||
axios
|
||||
.get(ContextPath + __uri('../docs.json'))
|
||||
.then(result => {
|
||||
this.docs = result.data.docs;
|
||||
})
|
||||
|
@ -32,12 +44,14 @@ export default class DocSearch extends React.Component {
|
|||
});
|
||||
}
|
||||
|
||||
onSearch(query) {
|
||||
query = query.trim().toLowerCase();
|
||||
onSearch() {
|
||||
let query = this.state.query.trim().toLowerCase();
|
||||
|
||||
if (query === '') {
|
||||
this.setState({searchResults: []});
|
||||
return;
|
||||
}
|
||||
|
||||
let results = [];
|
||||
for (let doc of this.docs) {
|
||||
let index = doc.body.indexOf(query);
|
||||
|
@ -67,28 +81,94 @@ export default class DocSearch extends React.Component {
|
|||
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: []});
|
||||
}
|
||||
|
||||
clearValue() {
|
||||
this.setState(
|
||||
{
|
||||
query: ''
|
||||
},
|
||||
() => {
|
||||
this.setState({searchResults: []});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const searchResults = this.state.searchResults;
|
||||
const ns = this.props.theme.ns;
|
||||
return (
|
||||
<div className="p-r">
|
||||
<SearchBox onSearch={this.onSearch} onCancel={this.onSearchCancel} />
|
||||
{searchResults.length > 0 ? (
|
||||
<div className="search-result">
|
||||
{searchResults.map(item => {
|
||||
return (
|
||||
<a href={ContextPath + item.path} key={`list_${item.path}`}>
|
||||
<h5>{item.title}</h5>
|
||||
<p dangerouslySetInnerHTML={{__html: item.abstract}} />
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
<>
|
||||
<div className={`${ns}TextControl-input Doc-search`}>
|
||||
<Icon icon="search" className="icon" />
|
||||
<input readOnly placeholder={'搜索...'} onClick={this.onOpen} />
|
||||
</div>
|
||||
|
||||
<Drawer
|
||||
className="Doc-searchDrawer"
|
||||
overlay
|
||||
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>
|
||||
) : 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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -218,7 +218,13 @@ a {
|
|||
width: 120px;
|
||||
|
||||
.Doc-search {
|
||||
top: 15px;
|
||||
margin-top: 15px;
|
||||
border: 0;
|
||||
|
||||
> .icon-search {
|
||||
margin-right: 8px;
|
||||
top: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
&::before {
|
||||
|
@ -712,20 +718,84 @@ a {
|
|||
}
|
||||
}
|
||||
|
||||
.search-result {
|
||||
background-color: #fff;
|
||||
top: 50px;
|
||||
bottom: 0;
|
||||
position: fixed;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
box-shadow: 0px 2px 7px #888888;
|
||||
a {
|
||||
padding: 0 5px;
|
||||
display: block;
|
||||
.Doc-searchDrawer {
|
||||
border: 0;
|
||||
|
||||
.a-Drawer-content,
|
||||
.cxd-Drawer-content,
|
||||
.dark-Drawer-content {
|
||||
border: 0;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue