From 366f9c5ea4ea98573be7d56938028cb9f814ff78 Mon Sep 17 00:00:00 2001
From: Matthias Kretschmann
Date: Tue, 28 Aug 2018 23:28:42 +0200
Subject: [PATCH] make search functional
---
gatsby-config.js | 33 ++++++++
package.json | 1 +
src/components/Layout.jsx | 2 +-
src/components/atoms/SearchButton.jsx | 11 +++
src/components/atoms/SearchButton.module.scss | 33 ++++++++
src/components/atoms/SearchInput.jsx | 14 ++++
src/components/atoms/SearchInput.module.scss | 7 ++
src/components/atoms/SearchResults.jsx | 30 ++++++++
.../atoms/SearchResults.module.scss | 28 +++++++
src/components/molecules/Search.jsx | 77 ++++++++++++-------
src/components/molecules/Search.module.scss | 38 ---------
src/components/organisms/Header.jsx | 2 +-
src/templates/Post.jsx | 1 +
13 files changed, 210 insertions(+), 67 deletions(-)
create mode 100644 src/components/atoms/SearchButton.jsx
create mode 100644 src/components/atoms/SearchButton.module.scss
create mode 100644 src/components/atoms/SearchInput.jsx
create mode 100644 src/components/atoms/SearchInput.module.scss
create mode 100644 src/components/atoms/SearchResults.jsx
create mode 100644 src/components/atoms/SearchResults.module.scss
diff --git a/gatsby-config.js b/gatsby-config.js
index ef7bfaa3..a55a2cec 100644
--- a/gatsby-config.js
+++ b/gatsby-config.js
@@ -70,6 +70,39 @@ module.exports = {
includePaths: [`${__dirname}/node_modules`, `${__dirname}/src/styles`]
}
},
+ {
+ resolve: 'gatsby-plugin-lunr',
+ options: {
+ languages: [
+ {
+ // ISO 639-1 language codes. See https://lunrjs.com/guides/language_support.html for details
+ name: 'en'
+ }
+ ],
+ // Fields to index. If store === true value will be stored in index file.
+ // Attributes for custom indexing logic. See https://lunrjs.com/docs/lunr.Builder.html for details
+ fields: [
+ { name: 'title', store: true, attributes: { boost: 20 } },
+ { name: 'content' },
+ { name: 'excerpt', attributes: { boost: 10 } },
+ { name: 'category', store: true, attributes: { boost: 5 } },
+ { name: 'tags', store: true },
+ { name: 'url', store: true }
+ ],
+ // How to resolve each field's value for a supported node type
+ resolvers: {
+ // For any node of type MarkdownRemark, list how to resolve the fields' values
+ MarkdownRemark: {
+ title: node => node.frontmatter.title,
+ content: node => node.rawMarkdownBody,
+ excerpt: node => node.frontmatter.excerpt,
+ category: node => node.frontmatter.category,
+ tags: node => node.frontmatter.tags,
+ url: node => node.fields.slug
+ }
+ }
+ }
+ },
'gatsby-plugin-react-helmet',
'gatsby-transformer-yaml',
'gatsby-transformer-sharp',
diff --git a/package.json b/package.json
index 66264012..4bcc9dd6 100644
--- a/package.json
+++ b/package.json
@@ -27,6 +27,7 @@
"gatsby": "^2.0.0-rc.0",
"gatsby-image": "^2.0.0-rc.0",
"gatsby-plugin-catch-links": "^2.0.2-rc.0",
+ "gatsby-plugin-lunr": "^1.1.0",
"gatsby-plugin-matomo": "^0.4.1",
"gatsby-plugin-react-helmet": "^3.0.0-rc.0",
"gatsby-plugin-sass": "^2.0.0-rc.0",
diff --git a/src/components/Layout.jsx b/src/components/Layout.jsx
index b93c356c..429874f8 100644
--- a/src/components/Layout.jsx
+++ b/src/components/Layout.jsx
@@ -11,7 +11,7 @@ const Layout = ({ children }) => (
-
+
{children}
diff --git a/src/components/atoms/SearchButton.jsx b/src/components/atoms/SearchButton.jsx
new file mode 100644
index 00000000..5cd78c80
--- /dev/null
+++ b/src/components/atoms/SearchButton.jsx
@@ -0,0 +1,11 @@
+import React from 'react'
+import SearchIcon from '../svg/MagnifyingGlass'
+import styles from './SearchButton.module.scss'
+
+const SearchButton = props => (
+
+)
+
+export default SearchButton
diff --git a/src/components/atoms/SearchButton.module.scss b/src/components/atoms/SearchButton.module.scss
new file mode 100644
index 00000000..7229a39d
--- /dev/null
+++ b/src/components/atoms/SearchButton.module.scss
@@ -0,0 +1,33 @@
+@import 'variables';
+
+.searchButton {
+ padding: .65rem .85rem;
+ text-align: center;
+ line-height: 1;
+ vertical-align: middle;
+ display: inline-block;
+ margin-right: $spacer / 4;
+
+ &:focus {
+ outline: 0;
+ }
+
+ svg {
+ fill: $text-color-light;
+ width: 21px;
+ height: 21px;
+ }
+
+ &:hover,
+ &:focus {
+ svg {
+ fill: $brand-cyan;
+ }
+ }
+
+ &:active {
+ svg {
+ fill: darken($brand-cyan, 30%);
+ }
+ }
+}
diff --git a/src/components/atoms/SearchInput.jsx b/src/components/atoms/SearchInput.jsx
new file mode 100644
index 00000000..04ef9fca
--- /dev/null
+++ b/src/components/atoms/SearchInput.jsx
@@ -0,0 +1,14 @@
+import React, { Fragment } from 'react'
+import Input from './Input'
+import styles from './SearchInput.module.scss'
+
+const SearchInput = props => (
+
+
+
+
+)
+
+export default SearchInput
diff --git a/src/components/atoms/SearchInput.module.scss b/src/components/atoms/SearchInput.module.scss
new file mode 100644
index 00000000..808c2cba
--- /dev/null
+++ b/src/components/atoms/SearchInput.module.scss
@@ -0,0 +1,7 @@
+@import 'variables';
+
+.searchInputClose {
+ position: absolute;
+ right: $spacer / 4;
+ top: $spacer / 4;
+}
diff --git a/src/components/atoms/SearchResults.jsx b/src/components/atoms/SearchResults.jsx
new file mode 100644
index 00000000..65d9c97e
--- /dev/null
+++ b/src/components/atoms/SearchResults.jsx
@@ -0,0 +1,30 @@
+import React from 'react'
+import ReactDOM from 'react-dom'
+import PropTypes from 'prop-types'
+import { Link } from 'gatsby'
+import Container from '../atoms/Container'
+import styles from './SearchResults.module.scss'
+
+const SearchResults = ({ results, onClose }) =>
+ ReactDOM.createPortal(
+
+
+
+ {results.map(page => (
+ -
+
+ {page.title}
+
+
+ ))}
+
+
+
,
+ document.getElementById('document')
+ )
+
+SearchResults.propTypes = {
+ results: PropTypes.array.isRequired
+}
+
+export default SearchResults
diff --git a/src/components/atoms/SearchResults.module.scss b/src/components/atoms/SearchResults.module.scss
new file mode 100644
index 00000000..e32e90b0
--- /dev/null
+++ b/src/components/atoms/SearchResults.module.scss
@@ -0,0 +1,28 @@
+@import 'variables';
+@import 'mixins';
+
+.searchResults {
+ position: absolute;
+ left: 0;
+ right: 0;
+ z-index: 10;
+ top: 0;
+ bottom: 0;
+ background: $body-background-color;
+
+ ul {
+ @include breakoutviewport;
+
+ margin-top: $spacer;
+
+ li::before {
+ top: $spacer / 7;
+ }
+ }
+
+ a {
+ padding-top: $spacer / 6;
+ padding-bottom: $spacer / 6;
+ display: inline-block;
+ }
+}
diff --git a/src/components/molecules/Search.jsx b/src/components/molecules/Search.jsx
index f38b365e..9f62f552 100644
--- a/src/components/molecules/Search.jsx
+++ b/src/components/molecules/Search.jsx
@@ -1,9 +1,11 @@
import React, { PureComponent, Fragment } from 'react'
-// import { Link } from 'gatsby'
+import PropTypes from 'prop-types'
import Helmet from 'react-helmet'
import { CSSTransition } from 'react-transition-group'
-import Input from '../atoms/Input'
-import SearchIcon from '../svg/MagnifyingGlass'
+import SearchInput from '../atoms/SearchInput'
+import SearchButton from '../atoms/SearchButton'
+import SearchResults from '../atoms/SearchResults'
+
import styles from './Search.module.scss'
class Search extends PureComponent {
@@ -11,7 +13,9 @@ class Search extends PureComponent {
super(props)
this.state = {
- searchOpen: false
+ searchOpen: false,
+ query: '',
+ results: []
}
}
@@ -21,51 +25,70 @@ class Search extends PureComponent {
}))
}
+ closeSearch = () => {
+ this.setState({
+ searchOpen: false,
+ query: '',
+ results: []
+ })
+ }
+
isSearchOpen = () => this.state.searchOpen === true
+ getSearchResults(query) {
+ if (!query || !window.__LUNR__) return []
+ const lunrIndex = window.__LUNR__[this.props.lng]
+ const results = lunrIndex.index.search(query)
+ return results.map(({ ref }) => lunrIndex.store[ref])
+ }
+
+ search = event => {
+ const query = event.target.value
+ const results = this.getSearchResults(query)
+ this.setState({
+ results,
+ query
+ })
+ }
+
render() {
+ const { searchOpen, query, results } = this.state
+
return (
-
+
- {this.state.searchOpen && (
+ {searchOpen && (
)}
+
+ {query && (
+
+ )}
)
}
}
+Search.propTypes = {
+ lng: PropTypes.string.isRequired
+}
+
export default Search
diff --git a/src/components/molecules/Search.module.scss b/src/components/molecules/Search.module.scss
index 94ea83ee..74e2792e 100644
--- a/src/components/molecules/Search.module.scss
+++ b/src/components/molecules/Search.module.scss
@@ -1,37 +1,5 @@
@import 'variables';
-.searchButton {
- padding: .65rem .85rem;
- text-align: center;
- line-height: 1;
- vertical-align: middle;
- display: inline-block;
- margin-right: $spacer / 4;
-
- &:focus {
- outline: 0;
- }
-
- svg {
- fill: $text-color-light;
- width: 21px;
- height: 21px;
- }
-
- &:hover,
- &:focus {
- svg {
- fill: $brand-cyan;
- }
- }
-
- &:active {
- svg {
- fill: darken($brand-cyan, 30%);
- }
- }
-}
-
.search {
position: absolute;
left: $spacer / 2;
@@ -49,12 +17,6 @@
}
}
-.searchInputClose {
- position: absolute;
- right: $spacer / 4;
- top: $spacer / 4;
-}
-
.appear,
.enter {
opacity: .01;
diff --git a/src/components/organisms/Header.jsx b/src/components/organisms/Header.jsx
index 510d3991..0330aa68 100644
--- a/src/components/organisms/Header.jsx
+++ b/src/components/organisms/Header.jsx
@@ -19,7 +19,7 @@ class Header extends PureComponent {
diff --git a/src/templates/Post.jsx b/src/templates/Post.jsx
index b9392b99..4499706f 100644
--- a/src/templates/Post.jsx
+++ b/src/templates/Post.jsx
@@ -76,6 +76,7 @@ export const pageQuery = graphql`
slug
date(formatString: "MMMM DD, YYYY")
}
+ rawMarkdownBody
}
contentYaml {