1
0
mirror of https://github.com/kremalicious/blog.git synced 2024-06-26 03:06:25 +02:00

tweaks to search usability

This commit is contained in:
Matthias Kretschmann 2018-11-18 16:41:37 +01:00
parent b149811eaa
commit 2a95ffebb9
Signed by: m
GPG Key ID: 606EEEF3C479A91F
11 changed files with 113 additions and 71 deletions

View File

@ -1,3 +0,0 @@
All post content under `./content/posts` is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
http://creativecommons.org/licenses/by-nc-sa/4.0/.

View File

@ -1,6 +0,0 @@
All photos & image assets under `./content/media`, `./src/images`, and `assets sheet.psd` are plain ol' copyright.
Copyright (c) 20082018 Matthias Kretschmann
Don't care if you fork & play with it, but you're not allowed to publish
anything from it as a whole without my written permission.

View File

@ -20,6 +20,7 @@
- [🎆 EXIF extraction](#-exif-extraction)
- [💰 Cryptocurrency donation via Web3/MetaMask](#-cryptocurrency-donation-via-web3metamask)
- [🕸 Related Posts](#-related-posts)
- [🔍 Search](#-search)
- [🐝 Coinhive](#-coinhive)
- [🏆 SEO component](#-seo-component)
- [📈 Matomo (formerly Piwik) analytics tracking](#-matomo-formerly-piwik-analytics-tracking)
@ -83,6 +84,10 @@ If you want to know how this works, have a look at the respective component unde
- [`src/components/molecules/RelatedPosts.jsx`](src/components/molecules/RelatedPosts.jsx)
### 🔍 Search
[gatsby-plugin-lunr](https://github.com/humanseelabs/gatsby-plugin-lunr)
### 🐝 Coinhive
Includes a component for mining Monero with JavaScript via [Coinhive](https://coinhive.com).
@ -198,20 +203,18 @@ The deploymeng script can be used locally too, the branch checks are only happen
The MIT License (MIT)
except for:
EXCEPT FOR:
### Posts
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
<img alt="Creative Commons License" style="border-width:0;" src="https://i.creativecommons.org/l/by-nc-sa/4.0/80x15.png" />
</a>
[![Creative Commons License](https://i.creativecommons.org/l/by-nc-sa/4.0/80x15.png)](http://creativecommons.org/licenses/by-nc-sa/4.0/)
All post content under `./content/posts` is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License</a>.
All post content under `./content/posts` is licensed under a [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-nc-sa/4.0/).
### Photos & images
All photos & image assets under `./content/media`, `./src/images`, and `assets sheet.psd` are plain ol' copyright.
All photos & image assets are plain ol' copyright.
Copyright (c) 20082018 Matthias Kretschmann
Don't care if you fork & play with it, but you're not allowed to publish anything from it as a whole without my written permission.
Don't care if you fork & play with it, but you're not allowed to publish anything from it as a whole without my written permission. Also please be aware, the combination of typography, colors & layout makes up my brand identity. So please don't just clone everything, but rather do a remix!

View File

@ -100,8 +100,9 @@ module.exports = {
// Attributes for custom indexing logic. See https://lunrjs.com/docs/lunr.Builder.html for details
fields: [
{ name: 'title', store: true, attributes: { boost: 20 } },
{ name: 'tags', attributes: { boost: 15 } },
{ name: 'slug', store: true },
{ name: 'excerpt', attributes: { boost: 10 } },
{ name: 'tags', store: true, attributes: { boost: 5 } },
{ name: 'content' }
],
// How to resolve each field's value for a supported node type
@ -111,7 +112,8 @@ module.exports = {
title: node => node.frontmatter.title,
excerpt: node => node.excerpt,
tags: node => node.frontmatter.tags,
content: node => node.rawMarkdownBody
content: node => node.rawMarkdownBody,
slug: node => node.fields.slug
}
}
}

View File

@ -1,4 +1,4 @@
import React, { PureComponent, Fragment } from 'react'
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import Helmet from 'react-helmet'
import { CSSTransition } from 'react-transition-group'
@ -25,16 +25,6 @@ export default 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]
@ -55,34 +45,32 @@ export default class Search extends PureComponent {
const { searchOpen, query, results } = this.state
return (
<Fragment>
<Helmet>
<body className={this.isSearchOpen() ? 'has-search-open' : null} />
</Helmet>
<>
<SearchButton onClick={this.toggleSearch} />
{searchOpen && (
<CSSTransition
appear={searchOpen}
in={searchOpen}
timeout={200}
classNames={styles}
>
<section className={styles.search}>
<SearchInput
value={query}
onChange={this.search}
onToggle={this.closeSearch}
/>
</section>
</CSSTransition>
<>
<Helmet>
<body className="hasSearchOpen" />
</Helmet>
<CSSTransition
appear={searchOpen}
in={searchOpen}
timeout={200}
classNames={styles}
>
<section className={styles.search}>
<SearchInput
value={query}
onChange={this.search}
onToggle={this.toggleSearch}
/>
</section>
</CSSTransition>
<SearchResults results={results} onClose={this.toggleSearch} />
</>
)}
{query && (
<SearchResults results={results} onClose={this.closeSearch} />
)}
</Fragment>
</>
)
}
}

View File

@ -4,7 +4,7 @@
position: absolute;
left: $spacer / 2;
right: $spacer / 2;
top: 0;
top: -($spacer / 4);
z-index: 10;
input {
@ -40,3 +40,13 @@
transform: translate3d(0, -100px, 0);
}
}
:global(.hasSearchOpen) {
overflow: hidden;
// more cross-browser backdrop-filter
main > div:first-child {
transition: filter .85s ease-out;
filter: blur(5px);
}
}

View File

@ -1,14 +1,24 @@
import React, { Fragment } from 'react'
import React from 'react'
import Input from '../atoms/Input'
import styles from './SearchInput.module.scss'
const SearchInput = props => (
<Fragment>
<Input type="search" placeholder="Search everything" {...props} />
<button className={styles.searchInputClose} onClick={props.onToggle}>
const SearchInput = ({ onToggle, ...props }) => (
<>
<Input
className={styles.searchInput}
type="search"
placeholder="Search everything"
autoFocus // eslint-disable-line
{...props}
/>
<button
className={styles.searchInputClose}
onClick={onToggle}
title="Close search"
>
&times;
</button>
</Fragment>
</>
)
export default SearchInput

View File

@ -1,7 +1,27 @@
@import 'variables';
.searchInput {
composes: input from '../atoms/Input.module.scss';
background: $input-bg-focus;
&::-webkit-search-cancel-button {
display: none;
}
&:hover {
background: $input-bg-focus;
}
}
.searchInputClose {
position: absolute;
right: $spacer / 4;
right: $spacer / 2;
top: $spacer / 4;
font-size: $font-size-h3;
color: $brand-grey-light;
&:hover,
&:focus {
color: $link-color;
}
}

View File

@ -10,13 +10,14 @@ const SearchResults = ({ results, onClose }) =>
<div className={styles.searchResults}>
<Container>
<ul>
{results.map(page => (
<li key={page.url}>
<Link to={page.url} onClick={onClose}>
{page.title}
</Link>
</li>
))}
{results.length > 0 &&
results.map(page => (
<li key={page.slug}>
<Link to={page.slug} onClick={onClose}>
{page.title}
</Link>
</li>
))}
</ul>
</Container>
</div>,

View File

@ -8,12 +8,19 @@
z-index: 10;
top: 0;
bottom: 0;
background: $body-background-color;
background: rgba($body-background-color, .95);
// backdrop-filter: blur(5px);
animation: fadein .3s;
ul {
@include breakoutviewport;
margin-top: $spacer;
padding-top: $spacer;
padding-bottom: $spacer;
margin-bottom: 0;
overflow: scroll;
-webkit-overflow-scrolling: touch;
max-height: 81vh;
li {
margin-left: $spacer;
@ -31,3 +38,13 @@
display: inline-block;
}
}
@keyframes fadein {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}

View File

@ -14,7 +14,7 @@
border-radius: $input-border-radius;
box-shadow: none;
transition: all ease-in-out .15s;
-webkit-appearance: none; // screw you, iOS default inset box-shadow
appearance: none;
&:hover {
background: lighten($input-bg, 30%);