Skip to content

Commit

Permalink
Add search to docs (#530)
Browse files Browse the repository at this point in the history
* Start adding DocSearch

* Fix z-index

* Change styles

* Remove docsearch.js dep

* Async load docsearch.js

* Remove commented import

* Fix header on mobile

* Fix searches on the same page

* Fix heading styles

* Fix ssr

* Fix ssr and revert prettier upgrade(we'll do it later)

* Fix docs not showing up in sidebar on /docs/

* Fix flow error

* Change thing

* Change renderSidebar into a component
  • Loading branch information
emmatown authored Jan 11, 2018
1 parent a7c3047 commit e063372
Show file tree
Hide file tree
Showing 10 changed files with 781 additions and 54 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@
"babel-eslint": "^7.2.3",
"babel-flow-types": "^1.2.2",
"babel-jest": "^20.0.3",
"babel-plugin-macros": "^2.0.0",
"babel-plugin-closure-elimination": "^1.3.0",
"babel-plugin-codegen": "^1.2.0",
"babel-plugin-external-helpers": "^6.22.0",
"babel-plugin-macros": "^2.0.0",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.5.1",
"babel-preset-flow": "^6.23.0",
Expand Down Expand Up @@ -80,7 +80,7 @@
"module-alias": "^2.0.1",
"npm-run-all": "^4.0.2",
"polished": "^1.2.1",
"prettier": "^1.7.4",
"prettier": "1.7.4",
"prettier-eslint-cli": "^4.0.3",
"react": "^16.2.0",
"react-dom": "^16.2.0",
Expand Down
21 changes: 3 additions & 18 deletions packages/site/gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,7 @@ module.exports = {
path: `${__dirname}/../../emotion.png`
}
},
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
'gatsby-remark-prismjs',
'gatsby-remark-autolink-headers',
'gatsby-remark-smartypants',
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: 590,
linkImagesToOriginal: false
}
}
]
}
},
`gatsby-transformer-remark`,
`gatsby-plugin-react-helmet`,
'gatsby-plugin-sharp',
'gatsby-transformer-sharp',
Expand All @@ -57,7 +41,8 @@ module.exports = {
options: {
mergeLinkHeaders: true,
allPageHeaders: [
'Link: <https://unpkg.com/[email protected]/babel.min.js>; rel=preload; as=script; cross-origin=anonymous'
'Link: <https://unpkg.com/[email protected]/babel.min.js>; rel=preload; as=script; cross-origin=anonymous',
'Link: <https://unpkg.com/[email protected]/dist/cdn/docsearch.min.js>; rel=preload; as=script; cross-origin=anonymous'
]
}
}
Expand Down
95 changes: 65 additions & 30 deletions packages/site/src/components/DocWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import MenuIcon from 'react-icons/lib/md/menu'
import { getDocMap, docList } from '../utils/misc'

import type { Match } from '../utils/types'
import { Route } from 'react-router'
import { Route, Switch } from 'react-router'

const ToggleSidebarButton = styled.button`
position: fixed;
Expand Down Expand Up @@ -97,6 +97,39 @@ const docHeadingMap = docList.reduce((obj, current) => {
return obj
}, {})

const Sidebar = (props: {
item: { title: string, items: Array<string> },
setSidebarOpenState: boolean => void,
docMap: *,
docName?: string
}) => {
const { item, setSidebarOpenState, docMap, docName } = props
return (
<Box onClick={() => setSidebarOpenState(false)}>
<h3
className={
docName !== undefined &&
cx({
'docSearch-lvl0': docHeadingMap[docName] === item.title
})
}
>
{item.title}
</h3>
{item.items.map(slug => (
<Link
key={slug}
className={linkStyles}
activeClassName={cx(activeStyles, 'docSearch-lvl1')}
to={`/docs/${slug}`}
>
{docMap[slug] || slug}
</Link>
))}
</Box>
)
}

export default (props: Props) => {
const docMap = getDocMap(props.sidebarNodes)
return (
Expand Down Expand Up @@ -189,35 +222,37 @@ export default (props: Props) => {
renderSidebar={({ setSidebarOpenState }) =>
docList.map(item => {
return (
<Route
path="/docs/:docName"
key={item.title}
render={({ match }) => {
const { docName } = match.params
return (
<Box onClick={() => setSidebarOpenState(false)}>
<h3
className={cx({
'docSearch-lvl0':
docHeadingMap[docName] === item.title
})}
>
{item.title}
</h3>
{item.items.map(slug => (
<Link
key={slug}
className={linkStyles}
activeClassName={cx(activeStyles, 'docSearch-lvl1')}
to={`/docs/${slug}`}
>
{docMap[slug] || slug}
</Link>
))}
</Box>
)
}}
/>
<Switch>
<Route
path="/docs/:docName"
key={item.title}
render={({ match }) => {
const { docName } = match.params
return (
<Sidebar
item={item}
setSidebarOpenState={setSidebarOpenState}
docMap={docMap}
docName={docName}
/>
)
}}
/>
<Route
exact
path="/docs"
key={item.title}
render={() => {
return (
<Sidebar
item={item}
setSidebarOpenState={setSidebarOpenState}
docMap={docMap}
/>
)
}}
/>
</Switch>
)
})}
/>
Expand Down
123 changes: 123 additions & 0 deletions packages/site/src/components/Search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// @flow
import React from 'react'
import { withRouter } from 'react-router'
import { algoliaStyles } from '../utils/algolia-styles'
import { addCallback } from '../utils/async-load-search'

type Props = {
history: { push: string => void }
}

type State = {
enabled: boolean
}

let a

if (typeof window !== 'undefined') {
a = document.createElement('a')
}

function getHash(url) {
a.href = url
return a.hash
}

// https://feathericons.com search
const icon =
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiIgdmlld0JveD0iMCAwIDI0IDI0Ij48Y2lyY2xlIGN4PSIxMSIgY3k9IjExIiByPSI4Ii8+PHBhdGggZD0iTTIxIDIxbC00LjM1LTQuMzUiLz48L3N2Zz4='

class Search extends React.Component<Props, State> {
input: ?HTMLInputElement
state = { enabled: true }
componentDidMount() {
addCallback(loaded => {
if (loaded) {
window.docsearch({
apiKey: 'd160789a17f10ba962c4bce1b298fbbb',
indexName: 'emotion_sh',
inputSelector: '#algolia-doc-search',
handleSelected: (input, event, suggestion) => {
event.preventDefault()
input.setVal('')
input.close()
if (this.input) {
this.input.blur()
}

const url = suggestion.url.replace('https://emotion.sh', '')
this.props.history.push(url)
var hash = window.decodeURI(getHash(url))

if (hash !== '#' && hash !== '') {
var element = document.querySelector(
`.docSearch-content ${hash} a`
)
if (element) {
element.click()
}
}
}
})
} else {
// eslint-disable-next-line no-console
console.warn('Search has failed to load and is now disabled')
this.setState({ enabled: false })
}
})
}

render() {
return this.state.enabled ? (
<form
css={[
{ zIndex: 100, display: 'flex', alignItems: 'center' },
algoliaStyles
]}
>
<input
css={{
border: 0,
fontSize: 16,
borderRadius: 4,
background: 'transparent',
padding: `5px 5px 5px 16px`,
backgroundImage: `url(${icon})`,
backgroundSize: '16px 16px',
backgroundRepeat: 'no-repeat',
backgroundPositionY: 'center',
backgroundPositionX: 5,
color: 'white',
outline: 0,
width: 16,
margin: 8,
transition:
'width 200ms ease,padding 200ms ease, background-color 100ms ease',
'@media (max-width: 600px)': {
':focus': {
paddingLeft: 29,
width: '8rem'
}
},
':focus': {
backgroundColor: '#444'
},
'@media (min-width: 601px)': {
width: '12rem',
paddingLeft: 29
}
}}
ref={ele => {
this.input = ele
}}
id="algolia-doc-search"
type="search"
placeholder="Search..."
aria-label="Search..."
/>
</form>
) : null
}
}

export default withRouter(Search)
12 changes: 12 additions & 0 deletions packages/site/src/html.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ export default class HTML extends Component {
content="width=device-width, initial-scale=1.0"
/>
<link rel="icon" href="/favicon.ico" />
<script
dangerouslySetInnerHTML={{
__html:
'window.searchError = function() {window.searchErrored = true;};window.searchLoaded = function() {};'
}}
/>
{this.props.headComponents}
{css}
</head>
Expand All @@ -41,6 +47,12 @@ export default class HTML extends Component {
dangerouslySetInnerHTML={{ __html: this.props.body }}
/>
{this.props.postBodyComponents}
<div
dangerouslySetInnerHTML={{
__html:
'<script src="https://unpkg.com/[email protected]/dist/cdn/docsearch.min.js" onload="searchLoaded()" async defer onerror="searchError()"></script>'
}}
/>
</body>
</html>
)
Expand Down
4 changes: 3 additions & 1 deletion packages/site/src/layouts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import styled from 'react-emotion'
import Box from '../components/Box'
import Helmet from 'react-helmet'
import DocWrapper from '../components/DocWrapper'
import Search from '../components/Search'
import { colors, constants, animatedUnderline } from '../utils/style'
import Image from 'gatsby-image'
import type { Location, Match } from '../utils/types'
Expand Down Expand Up @@ -81,6 +82,7 @@ const Header = ({ isHome, avatar }) => (
justify="flex-end"
css={{ overflow: 'initial' }}
>
<Search />
<StyledLink to="/docs">Documentation</StyledLink>
<StyledLink to="https://github.com/emotion-js/emotion">
GitHub
Expand All @@ -98,7 +100,7 @@ const Header = ({ isHome, avatar }) => (
transform: `scaleX(${isHome ? 0 : 1})`,
background:
!isHome && `linear-gradient(90deg, ${colors.pink}, ${colors.blue})`,
zIndex: 100
zIndex: 50
}}
/>
</Children>
Expand Down
Loading

0 comments on commit e063372

Please sign in to comment.