diff --git a/build/generate-search-data.js b/build/generate-search-data.js new file mode 100644 index 000000000..a3d7fe824 --- /dev/null +++ b/build/generate-search-data.js @@ -0,0 +1,39 @@ +/** + * @file 生成给前端全文搜索用的文件 + * @author wuduoyi + */ + +const glob = require('glob'); +const fs = require('fs'); +let yaml = require('js-yaml'); +var rYml = /^\s*---([\s\S]*?)---\s/; + +const resultData = {docs: []}; + +glob('./docs/**/*.md', {}, function (er, docs) { + for (const doc of docs) { + let content = fs.readFileSync(doc, {encoding: 'utf8'}); + let m = rYml.exec(content); + let info = {}; + if (m && m[1]) { + info = yaml.safeLoad(m[1]); + content = content.substring(m[0].length); + } + + const title = info.title || doc; + // todo: 属性列表单独处理,检索的时候优先检索 + resultData.docs.push({ + title: title, + // 去掉注释、换行、图片等 + body: content + .replace(/<\!---.+-->/g, '') + .replace(/!?\[.*\]\(.*\)/g, '') + .replace(/\n/g, '') + .replace(/```.*```/g, '') + + .toLowerCase(), + path: doc.replace('.md', '') + }); + } + fs.writeFileSync('./gh-pages/docs/docs.json', JSON.stringify(resultData)); +}); diff --git a/deploy-gh-pages.sh b/deploy-gh-pages.sh index 10d0f92c4..b27330a5d 100755 --- a/deploy-gh-pages.sh +++ b/deploy-gh-pages.sh @@ -1,10 +1,10 @@ #!/bin/bash set -e -if [ -z "$(git status --porcelain)" ]; then +if [ -z "$(git status --porcelain)" ]; then # Working directory clean echo "Working directory clean" -else +else # Uncommitted changes read -p "You got uncommitted changes, press y to continue? " -n 1 -r echo # (optional) move to a new line @@ -21,6 +21,8 @@ fis3 release gh-pages -c node ./build/upload2cdn.js $1 +node ./build/generate-search-data.js + git add gh-pages -f git commit -m "更新 gh-pages" @@ -33,4 +35,4 @@ git commit -m 'rebuild pages' --allow-empty git push origin -echo "done" \ No newline at end of file +echo "done" diff --git a/examples/components/DocSearch.jsx b/examples/components/DocSearch.jsx index 117f96f28..e9016929b 100644 --- a/examples/components/DocSearch.jsx +++ b/examples/components/DocSearch.jsx @@ -1,47 +1,79 @@ +/** + * @file 实现前端文档搜索 + */ import React from 'react'; -import makeSchemaRenderer from './SchemaRender'; - -const FormComponent = makeSchemaRenderer({ - type: 'form', - mode: 'inline', - wrapWithPanel: false, - className: ':Doc-search', - controls: [ - { - type: 'input-group', - size: 'sm', - controls: [ - { - type: 'icon', - addOnclassName: 'no-bg no-border p-r-none p-l', - className: 'text-sm', - icon: 'search', - vendor: 'iconfont' - }, - { - type: 'text', - placeholder: '搜索...', - inputClassName: 'no-border', - name: 'docsearch' - } - ] - } - ] -}); +import Axios from 'axios'; +import SearchBox from '../../src/components/SearchBox'; export default class DocSearch extends React.Component { + docs = []; + constructor(props) { + super(props); + this.state = { + searchResults: [], + loadError: false + }; + this.onSearch = this.onSearch.bind(this); + this.onSearchCancel = this.onSearchCancel.bind(this); + } componentDidMount() { - // const inputSelector = 'input[name="docsearch"]'; - // docsearch({ - // appId: 'S08MJHBHFJ', - // apiKey: '5fba814bb773d08b5d2a3f6074f926a5', - // indexName: 'gh_pages', - // inputSelector, - // debug: false - // }); + Axios.get('/docs/docs.json') + .then(result => { + this.docs = result.data.docs; + }) + .catch(err => { + this.setState({loadError: true}); + }); + } + + onSearch(query) { + if (query === '') { + this.setState({searchResults: []}); + return; + } + let results = []; + for (let doc of this.docs) { + let index = doc.body.indexOf(query); + + if (index !== -1) { + results.push({ + title: doc.title, + path: doc.path, + abstract: doc.body + .substring(Math.max(0, index - 20), index + 60) + .replace(query, `${query}`) + }); + } else if (doc.title.indexOf(query) !== -1) { + results.push({ + title: doc.title, + path: doc.path, + abstract: '' + }); + } + } + this.setState({searchResults: results}); + } + + onSearchCancel() { + this.setState({searchResults: []}); } render() { - return ; + const searchResults = this.state.searchResults; + return ( +
+ +
+ {searchResults.map(item => { + return ( + +
{item.title}
+

+ + ); + })} +

+
+ ); } } diff --git a/examples/style.scss b/examples/style.scss index b36ce854a..ed2200f11 100644 --- a/examples/style.scss +++ b/examples/style.scss @@ -123,7 +123,7 @@ a { .gh-icon { position: fixed; - right: 20px; + right: 15px; top: 15px; font-size: 22px; padding: 0 10px; @@ -711,3 +711,18 @@ a { } } } + +.search-result { + background-color: #fff; + top: 45px; + bottom: 0; + position: fixed; + overflow-y: scroll; + overflow-x: hidden; +} + +.dark { + .search-result { + background-color: #333538; + } +} diff --git a/package.json b/package.json index 9554d6e39..5cc89740c 100644 --- a/package.json +++ b/package.json @@ -126,6 +126,7 @@ "fis3-preprocessor-js-require-css": "^0.1.3", "font-awesome": "4.7.0", "fs-walk": "0.0.2", + "glob": "^7.1.6", "husky": "^2.2.0", "jest": "^24.5.0", "jest-canvas-mock": "^2.1.0",