diff --git a/gatsby-config.js b/gatsby-config.js
index 498c8ff4..999b86e0 100644
--- a/gatsby-config.js
+++ b/gatsby-config.js
@@ -99,10 +99,10 @@ module.exports = {
// 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: 'title', attributes: { boost: 20 } },
{ name: 'tags', attributes: { boost: 15 } },
- { name: 'slug', store: true },
{ name: 'excerpt', attributes: { boost: 10 } },
+ { name: 'slug', store: true },
{ name: 'content' }
],
// How to resolve each field's value for a supported node type
diff --git a/src/components/Post/PostTeaser.jsx b/src/components/Post/PostTeaser.jsx
new file mode 100644
index 00000000..c66deb1a
--- /dev/null
+++ b/src/components/Post/PostTeaser.jsx
@@ -0,0 +1,36 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import { Link } from 'gatsby'
+import Image from '../atoms/Image'
+import styles from './PostTeaser.module.scss'
+
+export default class PostTeaser extends PureComponent {
+ static propTypes = {
+ post: PropTypes.object.isRequired,
+ toggleSearch: PropTypes.func
+ }
+
+ render() {
+ const { post, toggleSearch } = this.props
+
+ return (
+
+
+ {post.frontmatter.image ? (
+ <>
+
+ {post.frontmatter.title}
+ >
+ ) : (
+
+
{post.frontmatter.title}
+
+ )}
+
+
+ )
+ }
+}
diff --git a/src/components/Post/PostTeaser.module.scss b/src/components/Post/PostTeaser.module.scss
new file mode 100644
index 00000000..749f70cf
--- /dev/null
+++ b/src/components/Post/PostTeaser.module.scss
@@ -0,0 +1,29 @@
+@import 'variables';
+
+.postTitle {
+ display: inline-block;
+ margin-top: $spacer / 4;
+ margin-bottom: 0;
+ font-size: $font-size-small;
+ line-height: $line-height-small;
+ color: $brand-grey-light;
+ padding-left: .2rem;
+ padding-right: .2rem;
+ transition: color .2s ease-out;
+
+ @media (min-width: $screen-md) {
+ font-size: $font-size-base;
+ }
+}
+
+.empty {
+ height: 100%;
+ min-height: 80px;
+ display: flex;
+ align-items: center;
+ padding: $spacer / 4;
+
+ .postTitle {
+ margin-top: 0;
+ }
+}
diff --git a/src/components/Search/Search.jsx b/src/components/Search/Search.jsx
index 55601c16..2a79a304 100644
--- a/src/components/Search/Search.jsx
+++ b/src/components/Search/Search.jsx
@@ -34,7 +34,9 @@ export default class Search extends PureComponent {
search = event => {
const query = event.target.value
- const results = this.getSearchResults(query)
+ // wildcard search https://lunrjs.com/guides/searching.html#wildcards
+ const results = query.length > 1 ? this.getSearchResults(`${query}*`) : []
+
this.setState({
results,
query
@@ -53,6 +55,7 @@ export default class Search extends PureComponent {
+
-
+
+
>
)}
>
diff --git a/src/components/Search/Search.module.scss b/src/components/Search/Search.module.scss
index a21e1ee8..ae573f17 100644
--- a/src/components/Search/Search.module.scss
+++ b/src/components/Search/Search.module.scss
@@ -43,10 +43,4 @@
:global(.hasSearchOpen) {
overflow: hidden;
-
- // more cross-browser backdrop-filter
- main > div:first-child {
- transition: filter .85s ease-out;
- filter: blur(5px);
- }
}
diff --git a/src/components/Search/SearchInput.jsx b/src/components/Search/SearchInput.jsx
index 6148a478..6651e9ce 100644
--- a/src/components/Search/SearchInput.jsx
+++ b/src/components/Search/SearchInput.jsx
@@ -1,24 +1,26 @@
-import React from 'react'
+import React, { PureComponent } from 'react'
import Input from '../atoms/Input'
import styles from './SearchInput.module.scss'
-const SearchInput = ({ onToggle, ...props }) => (
- <>
-
-
- >
-)
-
-export default SearchInput
+export default class SearchInput extends PureComponent {
+ render() {
+ return (
+ <>
+
+
+ >
+ )
+ }
+}
diff --git a/src/components/Search/SearchInput.module.scss b/src/components/Search/SearchInput.module.scss
index 68376949..9e252de6 100644
--- a/src/components/Search/SearchInput.module.scss
+++ b/src/components/Search/SearchInput.module.scss
@@ -16,7 +16,7 @@
.searchInputClose {
position: absolute;
right: $spacer / 2;
- top: $spacer / 4;
+ top: $spacer / 5;
font-size: $font-size-h3;
color: $brand-grey-light;
diff --git a/src/components/Search/SearchResults.jsx b/src/components/Search/SearchResults.jsx
index d4b9c788..29b135e0 100644
--- a/src/components/Search/SearchResults.jsx
+++ b/src/components/Search/SearchResults.jsx
@@ -1,31 +1,97 @@
-import React from 'react'
+import React, { PureComponent } from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
-import { Link } from 'gatsby'
+import { graphql, StaticQuery } from 'gatsby'
import Container from '../atoms/Container'
+import PostTeaser from '../Post/PostTeaser'
import styles from './SearchResults.module.scss'
-const SearchResults = ({ results, onClose }) =>
- ReactDOM.createPortal(
-
-
-
- {results.length > 0 &&
- results.map(page => (
- -
-
- {page.title}
-
-
- ))}
-
-
-
,
- document.getElementById('document')
- )
+const SearchEmpty = ({ searchQuery, results }) => (
+
+)
-SearchResults.propTypes = {
- results: PropTypes.array.isRequired
+SearchEmpty.propTypes = {
+ results: PropTypes.array.isRequired,
+ searchQuery: PropTypes.string.isRequired
}
-export default SearchResults
+const query = graphql`
+ query {
+ allMarkdownRemark {
+ edges {
+ node {
+ id
+ frontmatter {
+ title
+ image {
+ childImageSharp {
+ ...ImageFluidThumb
+ }
+ }
+ }
+ fields {
+ slug
+ }
+ }
+ }
+ }
+ }
+`
+
+export default class SearchResults extends PureComponent {
+ static propTypes = {
+ results: PropTypes.array.isRequired,
+ searchQuery: PropTypes.string.isRequired,
+ toggleSearch: PropTypes.func.isRequired
+ }
+
+ render() {
+ const { searchQuery, results, toggleSearch } = this.props
+
+ return (
+ {
+ const posts = data.allMarkdownRemark.edges
+
+ // creating portal to break out of DOM node we're in
+ // and render the results in content container
+ return ReactDOM.createPortal(
+
+
+ {results.length > 0 ? (
+
+ {results.map(page =>
+ posts
+ .filter(post => post.node.fields.slug === page.slug)
+ .map(({ node }) => (
+
+ ))
+ )}
+
+ ) : (
+
+ )}
+
+
,
+ document.getElementById('document')
+ )
+ }}
+ />
+ )
+ }
+}
diff --git a/src/components/Search/SearchResults.module.scss b/src/components/Search/SearchResults.module.scss
index 86beabe8..208a7488 100644
--- a/src/components/Search/SearchResults.module.scss
+++ b/src/components/Search/SearchResults.module.scss
@@ -9,33 +9,80 @@
top: 0;
bottom: 0;
background: rgba($body-background-color, .95);
- // backdrop-filter: blur(5px);
+ backdrop-filter: blur(5px);
animation: fadein .3s;
+ overflow: scroll;
+ -webkit-overflow-scrolling: touch;
+ height: 91vh;
ul {
@include breakoutviewport;
- padding-top: $spacer;
- padding-bottom: $spacer;
+ padding: $spacer $spacer / 2;
margin-bottom: 0;
- overflow: scroll;
- -webkit-overflow-scrolling: touch;
- max-height: 81vh;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
li {
- margin-left: $spacer;
- margin-right: $spacer;
- }
+ display: block;
+ flex: 0 0 48%;
+ margin-bottom: $spacer;
- li::before {
- top: $spacer / 7;
+ @media (min-width: $screen-sm) {
+ flex-basis: 31%;
+ }
+
+ &::before {
+ display: none;
+ }
}
}
+ img {
+ margin-bottom: 0;
+ }
+
a {
- padding-top: $spacer / 6;
- padding-bottom: $spacer / 6;
+ display: block;
+
+ > div {
+ margin-bottom: 0;
+ }
+
+ &:hover,
+ &:focus {
+ h4 {
+ color: $link-color;
+ }
+ }
+ }
+}
+
+.empty {
+ padding-top: 15vh;
+ display: flex;
+ justify-content: center;
+}
+
+.emptyMessage {
+ color: $brand-grey-light;
+}
+
+.emptyMessageText {
+ margin-bottom: 0;
+ position: relative;
+
+ &::after {
+ overflow: hidden;
display: inline-block;
+ vertical-align: bottom;
+ animation: ellipsis steps(4, end) 1s infinite;
+ content: '\2026'; // ascii code for the ellipsis character
+ width: 0;
+ position: absolute;
+ left: 101%;
+ bottom: 0;
}
}
@@ -48,3 +95,9 @@
opacity: 1;
}
}
+
+@keyframes ellipsis {
+ to {
+ width: 1rem;
+ }
+}
diff --git a/src/components/atoms/Image.jsx b/src/components/atoms/Image.jsx
index aa34f98e..fffd4a07 100644
--- a/src/components/atoms/Image.jsx
+++ b/src/components/atoms/Image.jsx
@@ -1,23 +1,29 @@
-import React from 'react'
+import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import { graphql } from 'gatsby'
import Img from 'gatsby-image'
import styles from './Image.module.scss'
-const Image = ({ fluid, fixed, alt }) => (
-
-)
+export default class Image extends PureComponent {
+ static propTypes = {
+ fluid: PropTypes.object,
+ fixed: PropTypes.object,
+ alt: PropTypes.string.isRequired
+ }
-Image.propTypes = {
- fluid: PropTypes.object,
- fixed: PropTypes.object,
- alt: PropTypes.string.isRequired
+ render() {
+ const { fluid, fixed, alt } = this.props
+
+ return (
+
+ )
+ }
}
export const imageSizeDefault = graphql`
@@ -35,5 +41,3 @@ export const imageSizeThumb = graphql`
}
}
`
-
-export default Image
diff --git a/src/components/atoms/Modal.module.scss b/src/components/atoms/Modal.module.scss
index 38535960..76cddab7 100644
--- a/src/components/atoms/Modal.module.scss
+++ b/src/components/atoms/Modal.module.scss
@@ -9,8 +9,8 @@
right: 0;
bottom: 0;
z-index: 9;
- background: rgba($body-background-color, .9);
- // backdrop-filter: blur(5px);
+ background: rgba($body-background-color, .95);
+ backdrop-filter: blur(5px);
animation: fadein .3s;
padding: $spacer;
@@ -65,10 +65,10 @@
overflow: hidden;
// more cross-browser backdrop-filter
- body > div:first-child {
- transition: filter .85s ease-out;
- filter: blur(5px);
- }
+ // body > div:first-child {
+ // transition: filter .85s ease-out;
+ // filter: blur(5px);
+ // }
}
.modal__title {
diff --git a/src/components/molecules/RelatedPosts.jsx b/src/components/molecules/RelatedPosts.jsx
index 76e8c534..12e5dfe0 100644
--- a/src/components/molecules/RelatedPosts.jsx
+++ b/src/components/molecules/RelatedPosts.jsx
@@ -1,7 +1,7 @@
-import React, { Fragment, PureComponent } from 'react'
+import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
-import { Link, graphql, StaticQuery } from 'gatsby'
-import Image from '../atoms/Image'
+import { graphql, StaticQuery } from 'gatsby'
+import PostTeaser from '../Post/PostTeaser'
import styles from './RelatedPosts.module.scss'
const query = graphql`
@@ -45,32 +45,6 @@ const postsWithDataFilter = (postsArray, key, valuesToFind) => {
return newArray
}
-const PostItem = ({ post }) => {
- return (
-
-
- {post.node.frontmatter.image ? (
-
-
- {post.node.frontmatter.title}
-
- ) : (
-
-
{post.node.frontmatter.title}
-
- )}
-
-
- )
-}
-
-PostItem.propTypes = {
- post: PropTypes.object.isRequired
-}
-
class RelatedPosts extends PureComponent {
shufflePosts = () => {
this.forceUpdate()
@@ -95,8 +69,8 @@ class RelatedPosts extends PureComponent {
{filteredPosts
.sort(() => 0.5 - Math.random())
.slice(0, 6)
- .map(post => (
-
+ .map(({ node }) => (
+
))}