forked from p96170835/amis
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>
|
||||||
|
|
||||||
<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
|
||||||
|
|
|
@ -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>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue