mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
Global search bar (#690)
* move search bar Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * update search bar Signed-off-by: mihaisc <mihai@oceanprotocol.com> * add enter event Signed-off-by: mihaisc <mihai@oceanprotocol.com> * fix lint * small button fixes * add padding, change media width to rem * remove comments
This commit is contained in:
parent
60addda1cc
commit
3798d80a4d
@ -27,6 +27,13 @@ export interface InputProps {
|
||||
| ChangeEvent<HTMLSelectElement>
|
||||
| ChangeEvent<HTMLTextAreaElement>
|
||||
): void
|
||||
onKeyPress?(
|
||||
e:
|
||||
| React.KeyboardEvent<HTMLInputElement>
|
||||
| React.KeyboardEvent<HTMLInputElement>
|
||||
| React.KeyboardEvent<HTMLSelectElement>
|
||||
| React.KeyboardEvent<HTMLTextAreaElement>
|
||||
): void
|
||||
rows?: number
|
||||
multiple?: boolean
|
||||
pattern?: string
|
||||
@ -42,6 +49,7 @@ export interface InputProps {
|
||||
defaultChecked?: boolean
|
||||
size?: 'mini' | 'small' | 'large' | 'default'
|
||||
className?: string
|
||||
divClassName?: string
|
||||
}
|
||||
|
||||
export default function Input(props: Partial<InputProps>): ReactElement {
|
||||
@ -50,10 +58,13 @@ export default function Input(props: Partial<InputProps>): ReactElement {
|
||||
const hasError =
|
||||
props.form?.touched[field.name] && props.form?.errors[field.name]
|
||||
|
||||
const styleClasses = cx({
|
||||
const styleClasses = cx(
|
||||
{
|
||||
field: true,
|
||||
hasError: hasError
|
||||
})
|
||||
},
|
||||
props.divClassName
|
||||
)
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -9,36 +9,76 @@
|
||||
.logo {
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
order: 1;
|
||||
}
|
||||
|
||||
.navigation {
|
||||
order: 3;
|
||||
width: 100%;
|
||||
margin-top: calc(var(--spacer) / 2);
|
||||
text-align: center;
|
||||
border-top: 1px solid var(--border-color);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
margin-left: -1rem;
|
||||
margin-right: -1rem;
|
||||
width: calc(100% + 2rem);
|
||||
width: auto;
|
||||
margin: 0;
|
||||
text-align: left;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.search {
|
||||
display: flex;
|
||||
flex: 1 0 auto;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
align-self: flex-start;
|
||||
padding-left: 20px;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
align-self: flex-start;
|
||||
margin-left: auto;
|
||||
order: 2;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width: 38rem) {
|
||||
.actions {
|
||||
margin-left: auto;
|
||||
}
|
||||
.navigation {
|
||||
order: 3;
|
||||
display: block;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: calc(var(--spacer) / 2);
|
||||
text-align: center;
|
||||
border-top: 1px solid var(--border-color);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
margin-left: -1rem;
|
||||
margin-right: -1rem;
|
||||
width: calc(50% + 2rem);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 75rem) {
|
||||
.navigation {
|
||||
flex: 1 0 auto;
|
||||
justify-content: left;
|
||||
align-items: left;
|
||||
}
|
||||
.search {
|
||||
flex: 0 0 100%;
|
||||
padding-top: 10px;
|
||||
order: 4;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 42rem) {
|
||||
.navigation {
|
||||
order: 2;
|
||||
width: auto;
|
||||
margin: 0;
|
||||
text-align: left;
|
||||
|
@ -8,6 +8,7 @@ import UserPreferences from './UserPreferences'
|
||||
import Badge from '../atoms/Badge'
|
||||
import Logo from '../atoms/Logo'
|
||||
import Networks from './UserPreferences/Networks'
|
||||
import SearchBar from './SearchBar'
|
||||
|
||||
const Wallet = loadable(() => import('./Wallet'))
|
||||
|
||||
@ -51,6 +52,9 @@ export default function Menu(): ReactElement {
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<div className={styles.search}>
|
||||
<SearchBar />
|
||||
</div>
|
||||
<div className={styles.actions}>
|
||||
<Networks />
|
||||
<Wallet />
|
||||
|
@ -1,17 +1,49 @@
|
||||
.form {
|
||||
margin-bottom: var(--spacer);
|
||||
width: 100%;
|
||||
max-width: 30rem;
|
||||
.search {
|
||||
display: flex;
|
||||
flex: 1 0 auto;
|
||||
align-self: stretch;
|
||||
}
|
||||
.button {
|
||||
padding: calc(var(--spacer) / 6) calc(var(--spacer) / 3);
|
||||
cursor: pointer;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--border-radius);
|
||||
background-color: var(--background-content);
|
||||
border-left: none;
|
||||
white-space: nowrap;
|
||||
min-width: 4rem;
|
||||
}
|
||||
|
||||
.form > div > div {
|
||||
.button:hover,
|
||||
.button:focus {
|
||||
color: var(--brand-white);
|
||||
text-decoration: none;
|
||||
transform: translate3d(0, -0.05rem, 0);
|
||||
box-shadow: 0 12px 30px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.input {
|
||||
height: 36px !important;
|
||||
border-top-right-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
}
|
||||
.searchInput {
|
||||
flex-grow: 2;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.searchIcon {
|
||||
fill: var(--brand-grey-light);
|
||||
transition: 0.2s ease-out;
|
||||
}
|
||||
.search > div > div {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.form label {
|
||||
.search label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.form input {
|
||||
.search input {
|
||||
background-color: var(--background-content);
|
||||
}
|
||||
|
@ -10,5 +10,3 @@ export default {
|
||||
export const Normal = () => <SearchBar />
|
||||
|
||||
export const WithInitialValue = () => <SearchBar initialValue="Water" />
|
||||
|
||||
export const WithFilters = () => <SearchBar filters />
|
||||
|
@ -1,24 +1,35 @@
|
||||
import React, { useState, ChangeEvent, FormEvent, ReactElement } from 'react'
|
||||
import React, {
|
||||
useState,
|
||||
useEffect,
|
||||
ChangeEvent,
|
||||
FormEvent,
|
||||
ReactElement
|
||||
} from 'react'
|
||||
import { navigate } from 'gatsby'
|
||||
import queryString from 'query-string'
|
||||
import styles from './SearchBar.module.css'
|
||||
import Button from '../atoms/Button'
|
||||
import Input from '../atoms/Input'
|
||||
import InputGroup from '../atoms/Input/InputGroup'
|
||||
import { addExistingParamsToUrl } from '../templates/Search/utils'
|
||||
import { ReactComponent as SearchIcon } from '../../images/search.svg'
|
||||
|
||||
export default function SearchBar({
|
||||
placeholder,
|
||||
initialValue,
|
||||
filters,
|
||||
size
|
||||
}: {
|
||||
placeholder?: string
|
||||
initialValue?: string
|
||||
filters?: boolean
|
||||
size?: 'small' | 'large'
|
||||
}): ReactElement {
|
||||
let [value, setValue] = useState(initialValue || '')
|
||||
const parsed = queryString.parse(location.search)
|
||||
const { text, owner } = parsed
|
||||
|
||||
useEffect(() => {
|
||||
;(text || owner) && setValue((text || owner) as string)
|
||||
}, [text, owner])
|
||||
async function startSearch(e: FormEvent<HTMLButtonElement>) {
|
||||
e.preventDefault()
|
||||
if (value === '') value = ' '
|
||||
@ -50,8 +61,7 @@ export default function SearchBar({
|
||||
}
|
||||
|
||||
return (
|
||||
<form className={styles.form}>
|
||||
<InputGroup>
|
||||
<form className={styles.search}>
|
||||
<Input
|
||||
type="search"
|
||||
name="search"
|
||||
@ -59,18 +69,25 @@ export default function SearchBar({
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
required
|
||||
size={size}
|
||||
size="small"
|
||||
divClassName={styles.searchInput}
|
||||
className={styles.input}
|
||||
onKeyPress={async (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === 'Enter') {
|
||||
await startSearch(e)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
onClick={async (e: FormEvent<HTMLButtonElement>) =>
|
||||
await startSearch(e)
|
||||
}
|
||||
style="text"
|
||||
size="small"
|
||||
className={styles.button}
|
||||
>
|
||||
Search
|
||||
<SearchIcon className={styles.searchIcon} />
|
||||
</Button>
|
||||
</InputGroup>
|
||||
|
||||
{filters && <fieldset className={styles.filters}>Type, Price</fieldset>}
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
.wallet {
|
||||
display: flex;
|
||||
align-self: stretch;
|
||||
}
|
||||
|
@ -134,10 +134,6 @@ export default function HomePage(): ReactElement {
|
||||
return (
|
||||
<Permission eventType="browse">
|
||||
<>
|
||||
<Container narrow className={styles.searchWrap}>
|
||||
<SearchBar size="large" />
|
||||
</Container>
|
||||
|
||||
<section className={styles.section}>
|
||||
<h3>Bookmarks</h3>
|
||||
<Bookmarks />
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React, { ReactElement, useState, useEffect } from 'react'
|
||||
import Permission from '../../organisms/Permission'
|
||||
import { QueryResult } from '@oceanprotocol/lib/dist/node/metadatacache/MetadataCache'
|
||||
import SearchBar from '../../molecules/SearchBar'
|
||||
import AssetList from '../../organisms/AssetList'
|
||||
import styles from './index.module.css'
|
||||
import queryString from 'query-string'
|
||||
@ -65,9 +64,6 @@ export default function SearchPage({
|
||||
<Permission eventType="browse">
|
||||
<>
|
||||
<div className={styles.search}>
|
||||
{(text || owner || tags) && (
|
||||
<SearchBar initialValue={(text || owner) as string} />
|
||||
)}
|
||||
<div className={styles.row}>
|
||||
<ServiceFilter
|
||||
serviceType={service}
|
||||
|
1
src/images/search.svg
Normal file
1
src/images/search.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd"><path d="M15.853 16.56c-1.683 1.517-3.911 2.44-6.353 2.44-5.243 0-9.5-4.257-9.5-9.5s4.257-9.5 9.5-9.5 9.5 4.257 9.5 9.5c0 2.442-.923 4.67-2.44 6.353l7.44 7.44-.707.707-7.44-7.44zm-6.353-15.56c4.691 0 8.5 3.809 8.5 8.5s-3.809 8.5-8.5 8.5-8.5-3.809-8.5-8.5 3.809-8.5 8.5-8.5z"/></svg>
|
After Width: | Height: | Size: 385 B |
Loading…
Reference in New Issue
Block a user