From f98173fbb91b1da89232b9cc43300e978c3f7918 Mon Sep 17 00:00:00 2001 From: wuduoyi Date: Thu, 20 Aug 2020 23:56:28 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E7=AE=80=E6=98=93=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E6=96=87=E6=A1=A3=E6=A3=80=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/generate-search-data.js | 39 +++++++++++ examples/components/DocSearch.jsx | 108 +++++++++++++++++++----------- examples/style.scss | 12 +++- package.json | 1 + 4 files changed, 121 insertions(+), 39 deletions(-) create mode 100644 build/generate-search-data.js diff --git a/build/generate-search-data.js b/build/generate-search-data.js new file mode 100644 index 000000000..1708edcef --- /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('./public/docs/docs.json', JSON.stringify(resultData)); +}); diff --git a/examples/components/DocSearch.jsx b/examples/components/DocSearch.jsx index 117f96f28..3e2e8e50d 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..72f11680c 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,13 @@ a { } } } + +.search-result { + background-color: #fff; +} + +.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",