Skip to content

Commit

Permalink
WIP: Add autocompletion
Browse files Browse the repository at this point in the history
  • Loading branch information
Joozty committed Sep 3, 2020
1 parent a7e9d69 commit f79cfb0
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 27 deletions.
89 changes: 64 additions & 25 deletions components/search/forms/simple.jsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,74 @@
import React from 'react'
import { Button, InputGroup, InputGroupAddon, Input } from 'reactstrap'
import React, { useRef } from 'react'
import { Select } from '@oacore/design'

const SearchField = ({
size = '',
id = 'search-form-field',
label = 'Search in CORE',
...fieldProps
}) => (
<>
<label className="sr-only" htmlFor={id}>
{label}
</label>
<InputGroup size={size}>
<Input type="search" id={id} {...fieldProps} />
<InputGroupAddon addonType="append">
<Button color="primary">Search</Button>
</InputGroupAddon>
</InputGroup>
</>
)
import styles from './styles.module.css'

const options = [
{ id: 1, icon: '#magnify', value: 'Option A' },
{ id: 2, icon: '#magnify', value: 'Option B' },
{ id: 3, icon: '#magnify', value: 'Option C' },
{ id: 4, icon: '#magnify', value: 'Option D' },
{ id: 5, icon: '#magnify', value: 'Option E' },
]

const SearchAutocompletion = ({ formRef, ...passProps }) => {
const [suggestions, setSuggestions] = React.useState(options)
const [value, setValue] = React.useState('')

const handleOnChange = data => {
if (data.value === '') return
formRef.current.submit()
}

const handleOnInput = data => {
// if id doesn't exists it means user type own text
// and didn't use suggestion
if (!data.id) {
setSuggestions(
options.slice(0, Math.max(0, options.length - data.value.length))
)
}

setValue(data.value)
}

return (
<Select
id="search-select"
value={value}
onChange={handleOnChange}
onInput={handleOnInput}
prependIcon="#magnify"
className={styles['search-box']}
{...passProps}
>
{suggestions.map(el => (
<Select.Option key={el.id} id={el.id} value={el.value} icon={el.icon}>
{el.value}
</Select.Option>
))}
{
<Select.Option key={6} id={6} value={value} icon="#magnify">
{`All results for "${value}"`}
</Select.Option>
}
</Select>
)
}

const SearchForm = ({
action,
method,
onSubmit,
id = 'search-form',
...fieldProps
}) => (
<form id={id} action={action} method={method} onSubmit={onSubmit}>
<SearchField id={`${id}-field`} size="lg" {...fieldProps} />
</form>
)
}) => {
const ref = useRef(null)
return (
<form ref={ref} id={id} action={action} method={method} onSubmit={onSubmit}>
<SearchAutocompletion id={`${id}-field`} {...fieldProps} formRef={ref} />
</form>
)
}

export default SearchForm
46 changes: 46 additions & 0 deletions components/search/forms/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
.search-box {
--form-control-corner-radius: 0.3rem;
--form-control-color: var(--gray-500);
--form-label-color: var(--gray-500);
--select-option-color: var(--gray-700);
--select-option-icon-color: var(--black);

border-bottom: 1px solid transparent;
}

.search-box:focus-within,
.search-box ul > * {
padding-left: 0.25rem;
padding-right: 0.25rem;
}

.search-box:focus-within {
--form-control-color: var(--primary);
}

.search-box:focus-within div:nth-child(2) {
border-bottom: 1px solid var(--primary);
}

.search-box:focus-within {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05), 0 1px 2px rgba(0, 0, 0, 0.25);
}

.search-box:focus-within div:nth-child(2) > * {
border-color: transparent;
}

.search-box:focus-within ul {
color: var(--gray-500)
}

.search-box:focus-within ul > li:last-child {
position: relative;
}
.search-box:focus-within ul > li:last-child::after {
content: '';
left: 0.25rem;
right: 0.25rem;
position: absolute;
border-top: 1px solid var(--gray-300);
}
26 changes: 26 additions & 0 deletions design.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const path = require('path')

const icons = ['magnify']

const iconsRoot = path.join(
path.dirname(require.resolve('@mdi/svg/package.json')),
'./svg'
)

const config = {
icons: {
path: iconsRoot,
files: icons,
},

output: {
path: path.join(__dirname, 'public/design'),
publicPath: '/design',
icons: {
files: 'icons',
sprite: 'icons.svg',
},
},
}

module.exports = config
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
"test-staging": "blc https://${CORE_STAGING_AREA}core.ac.uk -ro --exclude='/browse' --exclude='/search' --exclude='/public'",
"test": "npm run test-dev",
"dev": "next",
"build": "next build",
"build": "node ./node_modules/.bin/design build icons && next build",
"export": "next build && next export",
"start": "next start"
}
Expand Down
4 changes: 3 additions & 1 deletion pages/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ const IndexPage = () => (
<SearchForm
action="/search"
name="q"
placeholder={patchStats(page.searchPlaceholder, page.statistics)}
label={patchStats(page.searchPlaceholder, page.statistics)}
placeholder="e.g. article title or author name"
variant="pure"
/>
<SearchIntro>
<Markdown>{page.covid19Notice}</Markdown>
Expand Down

0 comments on commit f79cfb0

Please sign in to comment.