doc search style

This commit is contained in:
RickCole21 2020-08-21 17:33:31 +08:00
parent 13edec24e9
commit 892a0ad427
3 changed files with 187 additions and 37 deletions

View File

@ -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

View File

@ -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>
</>
);
}
}

View File

@ -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;
}
}
}
}