1
0
mirror of https://github.com/oceanprotocol/commons.git synced 2023-03-15 18:03:00 +01:00

Merge pull request #7 from oceanprotocol/feature/form-components

Form components
This commit is contained in:
Matthias Kretschmann 2019-02-08 11:41:20 +01:00 committed by GitHub
commit b1c0ade6ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 2995 additions and 5093 deletions

View File

@ -6,10 +6,11 @@
"extends": [ "extends": [
"oceanprotocol", "oceanprotocol",
"oceanprotocol/react", "oceanprotocol/react",
"plugin:prettier/recommended",
"prettier/react", "prettier/react",
"prettier/standard", "prettier/standard",
"plugin:@typescript-eslint/recommended" "plugin:prettier/recommended",
"plugin:@typescript-eslint/recommended",
"prettier/@typescript-eslint"
], ],
"plugins": ["@typescript-eslint", "prettier"], "plugins": ["@typescript-eslint", "prettier"],
"rules": { "rules": {
@ -20,6 +21,8 @@
] ]
}, },
"env": { "env": {
"es6": true,
"browser": true,
"jest": true "jest": true
} }
} }

View File

@ -49,7 +49,7 @@ See the section about [running tests](https://facebook.github.io/create-react-ap
For linting and auto-formatting you can use: For linting and auto-formatting you can use:
```bash ```bash
# auto format all ts & css with tslint & stylelint # auto format all ts & css with eslint & stylelint
npm run lint npm run lint
# auto format all ts & css with prettier, taking all configs into account # auto format all ts & css with prettier, taking all configs into account

7028
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -15,39 +15,40 @@
"lint": "npm run lint:js && npm run lint:css" "lint": "npm run lint:js && npm run lint:css"
}, },
"dependencies": { "dependencies": {
"@oceanprotocol/squid": "^0.2.7", "@oceanprotocol/squid": "^0.2.8",
"classnames": "^2.2.6",
"eslint": "^5.6.0",
"query-string": "^6.2.0", "query-string": "^6.2.0",
"react": "^16.7.0", "react": "^16.8.1",
"react-dom": "^16.7.0", "react-dom": "^16.8.1",
"react-router-dom": "^4.3.1", "react-router-dom": "^4.3.1",
"web3": "^1.0.0-beta.37" "slugify": "^1.3.4",
"web3": "^1.0.0-beta.43"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "23.3.13", "@types/classnames": "^2.2.7",
"@types/node": "10.12.19", "@types/jest": "^24.0.0",
"@types/node": "^10.12.21",
"@types/query-string": "^6.2.0", "@types/query-string": "^6.2.0",
"@types/react": "16.7.22", "@types/react": "^16.8.2",
"@types/react-dom": "16.0.11", "@types/react-dom": "^16.8.0",
"@types/react-router-dom": "^4.3.1", "@types/react-router-dom": "^4.3.1",
"@types/web3": "^1.0.18", "@types/web3": "^1.0.18",
"@typescript-eslint/eslint-plugin": "^1.2.0", "@typescript-eslint/eslint-plugin": "^1.2.0",
"@typescript-eslint/parser": "^1.2.0", "@typescript-eslint/parser": "^1.2.0",
"eslint-config-oceanprotocol": "^1.3.0", "eslint-config-oceanprotocol": "^1.3.0",
"eslint-config-prettier": "^3.3.0", "eslint-config-prettier": "^4.0.0",
"eslint-plugin-prettier": "^3.0.0", "eslint-plugin-prettier": "^3.0.1",
"node-sass": "^4.11.0", "node-sass": "^4.11.0",
"prettier": "^1.16.2", "prettier": "^1.16.4",
"prettier-stylelint": "^0.4.2", "prettier-stylelint": "^0.4.2",
"react-scripts": "2.1.3", "react-scripts": "^2.1.3",
"stylelint": "^9.10.1", "stylelint": "^9.10.1",
"stylelint-config-bigchaindb": "^1.2.1", "stylelint-config-bigchaindb": "^1.2.1",
"stylelint-config-css-modules": "^1.3.0", "stylelint-config-css-modules": "^1.3.0",
"stylelint-config-standard": "^18.2.0", "stylelint-config-standard": "^18.2.0",
"typescript": "3.2.4" "typescript": "3.2.4"
}, },
"eslintConfig": {
"extends": "react-app"
},
"browserslist": [ "browserslist": [
">0.2%", ">0.2%",
"not dead", "not dead",

View File

@ -52,16 +52,16 @@ class App extends Component<{}, AppState> {
if (accounts.length === 0 && (window as any).ethereum) { if (accounts.length === 0 && (window as any).ethereum) {
await (window as any).ethereum.enable() await (window as any).ethereum.enable()
const { ocean } = await provideOcean() const { ocean } = await provideOcean()
this.setState(state => ({ this.setState({
isLogged: true, isLogged: true,
web3, web3,
ocean ocean
})) })
} else { } else {
this.setState(state => ({ this.setState({
isLogged: true, isLogged: true,
web3 web3
})) })
} }
} catch (e) { } catch (e) {
this.setDefaultProvider() this.setDefaultProvider()
@ -78,11 +78,11 @@ class App extends Component<{}, AppState> {
const accounts = await web3.eth.getAccounts() const accounts = await web3.eth.getAccounts()
if (accounts.length > 0) { if (accounts.length > 0) {
const { ocean } = await provideOcean() const { ocean } = await provideOcean()
this.setState(state => ({ this.setState({
isLogged: true, isLogged: true,
web3, web3,
ocean ocean
})) })
} }
} catch (e) { } catch (e) {
this.setDefaultProvider() this.setDefaultProvider()
@ -93,14 +93,14 @@ class App extends Component<{}, AppState> {
} }
private setDefaultProvider = () => { private setDefaultProvider = () => {
this.setState(state => ({ this.setState({
isLogged: false, isLogged: false,
web3: new Web3( web3: new Web3(
new Web3.providers.HttpProvider( new Web3.providers.HttpProvider(
`${nodeScheme}://${nodeHost}:${nodePort}` `${nodeScheme}://${nodeHost}:${nodePort}`
) )
) )
})) })
} }
} }

View File

@ -7,11 +7,13 @@ import Home from './pages/Home'
import NotFound from './pages/NotFound' import NotFound from './pages/NotFound'
import Publish from './pages/Publish' import Publish from './pages/Publish'
import Search from './pages/Search' import Search from './pages/Search'
import Styleguide from './pages/Styleguide'
const Routes = () => ( const Routes = () => (
<Router> <Router>
<Switch> <Switch>
<Route exact component={Home} path="/" /> <Route exact component={Home} path="/" />
<Route component={Styleguide} path="/styleguide" />
<Route component={About} path="/about" /> <Route component={About} path="/about" />
<Route component={Publish} path="/publish" /> <Route component={Publish} path="/publish" />
<Route component={Search} path="/search" /> <Route component={Search} path="/search" />

View File

@ -7,7 +7,7 @@ it('Button renders without crashing', () => {
ReactDOM.render( ReactDOM.render(
<> <>
<Button>I am a button</Button> <Button>I am a button</Button>
<Button primary="true">I am a primary button</Button> <Button primary>I am a primary button</Button>
<Button href="https://hello.com">I am a button</Button> <Button href="https://hello.com">I am a button</Button>
</>, </>,
div div

View File

@ -12,7 +12,7 @@ interface ButtonProps {
export default class Button extends PureComponent<ButtonProps, any> { export default class Button extends PureComponent<ButtonProps, any> {
public render() { public render() {
let classes let classes
const { primary, link, href, children } = this.props const { primary, link, href, children, ...props } = this.props
if (primary) { if (primary) {
classes = styles.buttonPrimary classes = styles.buttonPrimary
@ -23,11 +23,11 @@ export default class Button extends PureComponent<ButtonProps, any> {
} }
return href ? ( return href ? (
<a href={href} className={classes} {...this.props}> <a href={href} className={classes} {...props}>
{children} {children}
</a> </a>
) : ( ) : (
<button className={classes} {...this.props}> <button className={classes} {...props}>
{children} {children}
</button> </button>
) )

View File

@ -0,0 +1,27 @@
@import '../../../styles/variables';
.form {
width: 100%;
margin: 0 auto;
margin-top: 4rem;
max-width: 40rem;
fieldset {
border: 0;
padding: 0;
}
}
.formHeader {
margin-bottom: $spacer;
}
.formTitle {
font-size: $font-size-h2;
margin: 0;
}
.formDescription {
margin-bottom: 0;
margin-top: $spacer / 2;
}

View File

@ -0,0 +1,26 @@
import React from 'react'
import styles from './Form.module.scss'
const Form = ({
title,
description,
children,
onSubmit,
...props
}: {
title?: string
description?: string
children: any
onSubmit?: any
}) => (
<form className={styles.form} onSubmit={onSubmit} {...props}>
<header className={styles.formHeader}>
<h1 className={styles.formTitle}>{title}</h1>
<p className={styles.formDescription}>{description}</p>
</header>
{children}
</form>
)
export default Form

View File

@ -0,0 +1,7 @@
@import '../../../styles/variables';
.help {
font-size: $font-size-small;
color: darken($brand-grey-light, 10%);
margin-top: $spacer / 4;
}

View File

@ -0,0 +1,13 @@
import React from 'react'
import ReactDOM from 'react-dom'
import Help from './Help'
it('FormHelp renders without crashing', () => {
const div = document.createElement('div')
ReactDOM.render(
<Help>Price of your data set asset in Ocean Tokens.</Help>,
div
)
ReactDOM.unmountComponentAtNode(div)
})

View File

@ -0,0 +1,8 @@
import React from 'react'
import styles from './Help.module.scss'
const FormHelp = ({ children }: { children: string }) => (
<div className={styles.help}>{children}</div>
)
export default FormHelp

View File

@ -0,0 +1,184 @@
@import '../../../styles/variables';
.inputWrap {
background: $brand-gradient;
border-radius: $border-radius;
width: 100%;
padding: 2px;
display: flex;
position: relative;
&.isFocused {
background: $brand-black;
}
}
.inputWrapSearch {
composes: inputWrap;
.input {
padding-left: $spacer / 1.25;
}
svg {
position: absolute;
left: $spacer / 3;
width: 1.25rem;
height: 1.25rem;
top: 50%;
margin-top: -.75rem;
fill: rgba($brand-grey-light, .7);
}
}
.input {
font-size: $font-size-base;
font-family: $font-family-button;
color: $brand-black;
border: none;
box-shadow: none;
width: 100%;
background: $brand-white;
padding: $spacer / 3;
margin: 0;
border-radius: $border-radius;
transition: .2s ease-out;
min-height: 43px;
appearance: none;
&:focus {
border: none;
box-shadow: none;
outline: 0;
}
&::placeholder {
font-family: $font-family-base;
font-size: $font-size-base;
color: $brand-grey-light;
font-weight: $font-weight-base;
transition: .2s ease-out;
opacity: .7;
}
&[readonly],
&[disabled] {
background-color: $brand-grey-lighter;
cursor: not-allowed;
pointer-events: none;
}
// &::-webkit-credentials-auto-fill-button,
// &::-webkit-caps-lock-indicator {
// background: $brand-white;
// }
// &:-webkit-autofill,
// &:-webkit-autofill:hover,
// &:-webkit-autofill:focus {
// -webkit-text-fill-color: $brand-white;
// box-shadow: 0 0 0 1000px $brand-black inset;
// transition: background-color 5000s ease-in-out 0s;
// }
}
.select {
composes: input;
height: 43px;
padding-right: 3rem;
border: 0;
// custom arrow
// stylelint-disable
background-image: linear-gradient(45deg, transparent 50%, $brand-purple 50%),
linear-gradient(135deg, $brand-purple 50%, transparent 50%),
linear-gradient(
to right,
$brand-pink 1px,
lighten($brand-grey-lighter, 5%) 2px,
lighten($brand-grey-lighter, 5%)
);
background-position: calc(100% - 18px) calc(1rem + 5px),
calc(100% - 13px) calc(1rem + 5px), 100% 0;
background-size: 5px 5px, 5px 5px, 2.5rem 3rem;
// stylelint-enable
background-repeat: no-repeat;
&:focus {
outline: 0;
font-family: $font-family-base;
}
}
.radioGroup {
margin-top: $spacer / 2;
margin-bottom: -2%;
@media screen and (min-width: $break-point--small) {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
}
.radioWrap {
position: relative;
padding: $spacer / 2;
text-align: center;
display: flex;
align-items: center;
margin-bottom: 2%;
@media screen and (min-width: $break-point--small) {
flex: 0 0 49%;
}
}
.radio {
&:checked + label {
border-color: $brand-pink;
}
}
.radioLabel {
margin: 0;
padding: 0;
font-family: $font-family-button;
font-size: $font-size-small;
line-height: 1.2;
border: 2px solid $brand-grey-lighter;
border-radius: .2rem;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
color: $brand-grey;
text-align: left;
padding-left: 2.5rem;
display: flex;
align-items: center;
}
// Size modifiers
.inputSmall {
composes: input;
font-size: $font-size-small;
min-height: 32px;
padding: $spacer / 4;
&::placeholder {
font-size: $font-size-small;
}
}
.selectSmall {
composes: select;
height: 32px;
padding-right: 2rem;
// custom arrow
background-position: calc(100% - 14px) 1rem, calc(100% - 9px) 1rem, 100% 0;
background-size: 5px 5px, 5px 5px, 2rem 3rem;
}

View File

@ -0,0 +1,150 @@
import cx from 'classnames'
import React, { PureComponent } from 'react'
import slugify from 'slugify'
import { ReactComponent as SearchIcon } from '../../../img/search.svg'
import Help from './Help'
import styles from './Input.module.scss'
import Label from './Label'
import Row from './Row'
interface InputProps {
name: string
label: string
placeholder?: string
required?: boolean
help?: string
tag?: string
type?: string
options?: string[]
additionalComponent?: void
value?: string
onChange?: any
rows?: number
}
interface InputState {
isFocused: boolean
}
export default class Input extends PureComponent<InputProps, InputState> {
public state: InputState = { isFocused: false }
public inputWrapClasses() {
if (this.props.type === 'search') {
return styles.inputWrapSearch
} else if (this.props.type === 'search' && this.state.isFocused) {
return cx(styles.inputWrapSearch, styles.isFocused)
} else if (this.state.isFocused && this.props.type !== 'search') {
return cx(styles.inputWrap, styles.isFocused)
} else {
return styles.inputWrap
}
}
public toggleFocus = () => {
this.setState({ isFocused: !this.state.isFocused })
}
public InputComponent = ({ ...props }) => {
if (props.type === 'select') {
return (
<div className={this.inputWrapClasses()}>
<select className={styles.select} {...props}>
{props.options &&
props.options.map(
(option: string, index: number) => (
<option
key={index}
value={slugify(option, {
lower: true
})}
>
{option}
</option>
)
)}
</select>
</div>
)
} else if (props.type === 'textarea') {
return (
<div className={this.inputWrapClasses()}>
<textarea className={styles.input} {...props} />
</div>
)
} else if (props.type === 'radio' || props.type === 'checkbox') {
return (
<div className={styles.radioGroup}>
{props.options &&
props.options.map((option: string, index: number) => (
<div className={styles.radioWrap} key={index}>
<input
className={styles.radio}
type={this.props.type}
id={slugify(option, {
lower: true
})}
name={this.props.name}
value={slugify(option, {
lower: true
})}
/>
<label
className={styles.radioLabel}
htmlFor={slugify(option, {
lower: true
})}
>
{option}
</label>
</div>
))}
</div>
)
}
return (
<div className={this.inputWrapClasses()}>
<input className={styles.input} {...props} />
</div>
)
}
public render() {
const {
name,
label,
required,
type,
help,
additionalComponent,
options,
...props
} = this.props
return (
<Row>
<Label htmlFor={name} required={required}>
{label}
</Label>
<this.InputComponent
id={name}
label={label}
name={name}
required={required}
type={type}
options={options}
{...props}
onFocus={this.toggleFocus}
onBlur={this.toggleFocus}
/>
{type === 'search' && <SearchIcon />}
{help && <Help>{help}</Help>}
{additionalComponent && additionalComponent}
</Row>
)
}
}

View File

@ -0,0 +1,22 @@
@import '../../../styles/variables';
.label {
color: $brand-grey;
font-size: $font-size-base;
font-family: $font-family-title;
line-height: 1.2;
display: block;
margin-bottom: $spacer / 6;
}
.required {
composes: label;
&:after {
content: '*';
font-size: $font-size-base;
color: $brand-grey-light;
display: inline-block;
margin-left: .1rem;
}
}

View File

@ -0,0 +1,22 @@
import React from 'react'
import styles from './Label.module.scss'
const Label = ({
required,
children,
...props
}: {
required?: boolean
children: string
htmlFor: string
}) => (
<label
className={required ? styles.required : styles.label}
title={required ? 'Required' : ''}
{...props}
>
{children}
</label>
)
export default Label

View File

@ -0,0 +1,5 @@
@import '../../../styles/variables';
.row {
margin-bottom: $spacer;
}

View File

@ -0,0 +1,8 @@
import React from 'react'
import styles from './Row.module.scss'
const Row = ({ children }: { children: any }) => (
<div className={styles.row}>{children}</div>
)
export default Row

104
src/data/form-publish.json Normal file
View File

@ -0,0 +1,104 @@
{
"title": "Publish a new data asset",
"description": "A cool form description",
"fields": {
"name": {
"label": "Title",
"placeholder": "i.e. My cool data set",
"type": "text",
"required": true,
"help": "Help me"
},
"description": {
"label": "Description",
"placeholder": "i.e. My cool data set",
"type": "textarea",
"required": true,
"rows": 5
},
"price": {
"label": "Price",
"placeholder": "i.e. 1000",
"type": "number",
"required": true
},
"author": {
"label": "Author",
"placeholder": "i.e. Jelly McJellyfish",
"type": "text",
"required": true
},
"files": {
"label": "Files",
"placeholder": "i.e. https://file.com/file.json",
"type": "text",
"required": true
},
"type": {
"label": "Type",
"type": "select",
"required": true,
"options": ["", "Data set", "Algorithm", "Container", "Workflow", "Other"]
},
"license": {
"label": "License",
"type": "select",
"required": true,
"options": [
"No License Specified",
"Public Domain",
"CC BY: Attribution",
"CC BY-SA: Attribution ShareAlike",
"CC BY-ND: Attribution-NoDerivs",
"CC BY-NC: Attribution-NonCommercial",
"CC BY-NC-SA: Attribution-NonCommercial-ShareAlike",
"CC BY-NC-ND: Attribution-NonCommercial-NoDerivs"
]
},
"copyrightHolder": {
"label": "Copyright Holder",
"placeholder": "i.e. fwhfiw",
"type": "text",
"required": true
},
"categories": {
"label": "Categories",
"type": "select",
"required": true,
"options": [
"",
"Image Recognition",
"Dataset Of Datasets",
"Language",
"Performing Arts",
"Visual Arts & Design",
"Philosophy",
"History",
"Theology",
"Anthropology & Archeology",
"Sociology",
"Psychology",
"Politics",
"Interdisciplinary",
"Economics & Finance",
"Demography",
"Biology",
"Chemistry",
"Physics & Energy",
"Earth & Climate",
"Space & Astronomy",
"Mathematics",
"Computer Technology",
"Engineering",
"Agriculture & Bio Engineering",
"Transportation",
"Urban Planning",
"Medicine",
"Business & Management",
"Sports & Recreation",
"Communication & Journalism",
"Other"
]
}
}
}

View File

@ -0,0 +1,43 @@
{
"title": "A cool form title",
"description": "A cool form description",
"fields": {
"name": {
"label": "Your name",
"placeholder": "i.e. Jelly McJellyfish",
"type": "text",
"required": true,
"help": "Help me"
},
"email": {
"label": "Your email",
"placeholder": "i.e. jelly@mcjellyfish.com",
"type": "email",
"required": true
},
"message": {
"label": "Your message",
"placeholder": "i.e. jelly@mcjellyfish.com",
"type": "textarea",
"required": true
},
"about": {
"label": "About you",
"type": "radio",
"required": true,
"options": ["I can provide more data", "I want to use more data"]
},
"about2": {
"label": "About you",
"type": "checkbox",
"required": true,
"options": ["I can provide data", "I want to use data"]
},
"industry": {
"label": "Industry",
"type": "select",
"required": true,
"options": ["Automotive", "Technology"]
}
}
}

3
src/img/search.svg Normal file
View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 25 25">
<path d="M32.421875,39.9179688 C34.552875,39.9179688 36.510875,39.1689688 38.054875,37.9259688 L45.712875,45.6229687 C46.101875,46.0149688 46.733875,46.0159688 47.126875,45.6259687 C47.518875,45.2359687 47.519875,44.6029688 47.130875,44.2119687 L39.462875,36.5059688 C40.685875,34.9699687 41.421875,33.0289688 41.421875,30.9179688 C41.421875,25.9549687 37.384875,21.9179688 32.421875,21.9179688 C27.458875,21.9179688 23.421875,25.9549687 23.421875,30.9179688 C23.421875,35.8799688 27.458875,39.9179688 32.421875,39.9179688 Z M32.421875,23.9179688 C36.280875,23.9179688 39.421875,27.0579688 39.421875,30.9179688 C39.421875,34.7769688 36.280875,37.9179688 32.421875,37.9179688 C28.561875,37.9179688 25.421875,34.7769688 25.421875,30.9179688 C25.421875,27.0579688 28.561875,23.9179688 32.421875,23.9179688 Z" transform="translate(-23 -21)"/>
</svg>

After

Width:  |  Height:  |  Size: 932 B

View File

@ -8,9 +8,25 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-wrap: wrap; flex-wrap: wrap;
padding-top: 4rem;
padding-bottom: 4rem;
> div { > div {
text-align: center; text-align: center;
width: 100%; width: 100%;
} }
} }
.form {
width: 100%;
background: $brand-grey-lighter;
margin: 0 auto;
max-width: 40rem;
padding: $spacer;
margin-top: 4rem;
fieldset {
border: 0;
padding: 0;
}
}

View File

@ -1,5 +1,8 @@
import React, { ChangeEvent, Component, FormEvent } from 'react' import React, { ChangeEvent, Component, FormEvent } from 'react'
import { Link } from 'react-router-dom'
import Button from '../components/atoms/Button' import Button from '../components/atoms/Button'
import Form from '../components/atoms/Form/Form'
import Input from '../components/atoms/Form/Input'
import styles from './Home.module.scss' import styles from './Home.module.scss'
interface HomeState { interface HomeState {
@ -18,16 +21,19 @@ class Home extends Component<HomeProps, HomeState> {
<div className={styles.home}> <div className={styles.home}>
<div>Home</div> <div>Home</div>
<Link to={'/styleguide'}>Styleguide</Link>
<div> <div>
<form onSubmit={this.searchAssets}> <Form onSubmit={this.searchAssets}>
<input <Input
type="text" type="search"
name="search" name="search"
label="Search"
value={this.state.search} value={this.state.search}
onChange={this.inputChange} onChange={this.inputChange}
/> />
<Button>Search</Button> <Button>Search</Button>
</form> </Form>
</div> </div>
</div> </div>
) )

View File

@ -1,8 +1,12 @@
import React, { ChangeEvent, Component, FormEvent } from 'react' import React, { ChangeEvent, Component, FormEvent } from 'react'
import Button from '../components/atoms/Button' import Button from '../components/atoms/Button'
import Form from '../components/atoms/Form/Form'
import Input from '../components/atoms/Form/Input'
import { User } from '../context/User' import { User } from '../context/User'
import AssetModel from '../models/AssetModel' import AssetModel from '../models/AssetModel'
import form from '../data/form-publish.json'
type AssetType = 'dataset' | 'algorithm' | 'container' | 'workflow' | 'other' type AssetType = 'dataset' | 'algorithm' | 'container' | 'workflow' | 'other'
interface PublishState { interface PublishState {
@ -33,209 +37,31 @@ class Publish extends Component<{}, PublishState> {
categories: [''] categories: ['']
} }
public render() { public formFields = (entries: any[]) =>
return ( entries.map(([key, value]) => {
<div> let onChange = this.inputChange
<h1>Publish</h1>
<form onSubmit={this.registerAsset}> if (key === 'files' || key === 'categories') {
<div> onChange = this.inputToArrayChange
Name:
<input
type="text"
name="name"
value={this.state.name}
onChange={this.inputChange}
/>
</div>
<div>
Description:
<input
type="text"
name="description"
value={this.state.description}
onChange={this.inputChange}
/>
</div>
<div>
Price:
<input
type="number"
name="price"
value={this.state.price}
onChange={this.inputChange}
/>
</div>
<div>
Author:
<input
type="text"
name="author"
value={this.state.author}
onChange={this.inputChange}
/>
</div>
<div>
Files:
<input
type="text"
name="files"
value={this.state.files[0]}
onChange={this.inputToArrayChange}
/>
</div>
<div>
Type:
<select
name="type"
value={this.state.type}
onChange={this.inputChange}
>
<option value="dataset">Data set</option>
<option value="algorithm">Algorithm</option>
<option value="container">Container</option>
<option value="workflow">Workflow</option>
<option value="other">Other</option>
</select>
</div>
<div>
License:
<select
name="license"
value={this.state.license}
onChange={this.inputChange}
>
<option value="none">No License Specified</option>
<option value="Public Domain">Public Domain</option>
<option value="CC BY">CC BY: Attribution</option>
<option value="CC BY-SA">
CC BY-SA: Attribution ShareAlike
</option>
<option value="CC BY-ND">
CC BY-ND: Attribution-NoDerivs
</option>
<option value="CC BY-NC">
CC BY-NC: Attribution-NonCommercial
</option>
<option value="CC BY-NC-SA">
CC BY-NC-SA:
Attribution-NonCommercial-ShareAlike
</option>
<option value="CC BY-NC-ND">
CC BY-NC-ND: Attribution-NonCommercial-NoDerivs
</option>
</select>
</div>
<div>
Category:
<select
name="categories"
value={this.state.categories[0]}
onChange={this.inputToArrayChange}
>
<option value="No Category Specified">
No Category Specified
</option>
<option value="Image Recognition">
Image Recognition
</option>
<option value="Dataset Of Datasets">
Dataset Of Datasets
</option>
<option value="Language">Language</option>
<option value="Performing Arts">
Performing Arts
</option>
<option value="Visual Arts & Design">
Visual Arts & Design
</option>
<option value="Philosophy">Philosophy</option>
<option value="History">History</option>
<option value="Theology">Theology</option>
<option value="Anthropology & Archeology">
Anthropology & Archeology
</option>
<option value="Sociology">Sociology</option>
<option value="Psychology">Psychology</option>
<option value="Politics">Politics</option>
<option value="Interdisciplinary">
Interdisciplinary
</option>
<option value="Economics & Finance">
Economics & Finance
</option>
<option value="Demography">Demography</option>
<option value="Biology">Biology</option>
<option value="Chemistry">Chemistry</option>
<option value="Physics & Energy">
Physics & Energy
</option>
<option value="Earth & Climate">
Earth & Climate
</option>
<option value="Space & Astronomy">
Space & Astronomy
</option>
<option value="Mathematics">Mathematics</option>
<option value="Computer Technology">
Computer Technology
</option>
<option value="Engineering">Engineering</option>
<option value="Agriculture & Bio Engineering">
Agriculture & Bio Engineering
</option>
<option value="Transportation">
Transportation
</option>
<option value="Urban Planning">
Urban Planning
</option>
<option value="Medicine">Medicine</option>
<option value="Language">Language</option>
<option value="Business & Management">
Business & Management
</option>
<option value="Sports & Recreation">
Sports & Recreation
</option>
<option value="Communication & Journalism">
Communication & Journalism
</option>
<option value="Other">Other</option>
</select>
</div>
<div>
CopyrightHolder:
<input
type="text"
name="copyrightHolder"
value={this.state.copyrightHolder}
onChange={this.inputChange}
/>
</div>
<User.Consumer>
{(states /* tslint:disable-next-line */) => (
<div>
{states.isLogged ? (
<div>
<Button>
Register asset (we are logged)
</Button>
</div>
) : (
<div>
<button onClick={states.startLogin}>
Register asset (login first)
</button>
</div>
)}
</div>
)}
</User.Consumer>
</form>
</div>
)
} }
return (
<Input
key={key}
name={key}
label={value.label}
placeholder={value.placeholder}
required={value.required}
type={value.type}
help={value.help}
options={value.options}
onChange={onChange}
rows={value.rows}
value={(this.state as any)[key]}
/>
)
})
private inputChange = ( private inputChange = (
event: ChangeEvent<HTMLInputElement> | ChangeEvent<HTMLSelectElement> event: ChangeEvent<HTMLInputElement> | ChangeEvent<HTMLSelectElement>
) => { ) => {
@ -282,7 +108,38 @@ class Publish extends Component<{}, PublishState> {
) )
} }
const ddo = await this.context.ocean.registerAsset(newAsset, account[0]) await this.context.ocean.registerAsset(newAsset, account[0])
}
public render() {
const entries = Object.entries(form.fields)
return (
<div>
<h1>Publish</h1>
<Form
title={form.title}
description={form.description}
onSubmit={this.registerAsset}
>
{this.formFields(entries)}
<User.Consumer>
{states =>
states.isLogged ? (
<Button primary>
Register asset (we are logged)
</Button>
) : (
<Button primary onClick={states.startLogin}>
Register asset (login first)
</Button>
)
}
</User.Consumer>
</Form>
</div>
)
} }
} }

View File

@ -29,7 +29,7 @@ class Search extends Component<SearchProps, SearchState> {
} }
} }
const assets = await ocean.searchAssets(queryRequest) const assets = await ocean.searchAssets(queryRequest)
this.setState(state => ({ results: assets })) this.setState({ results: assets })
} }
public render() { public render() {

View File

@ -0,0 +1,7 @@
@import '../styles/variables';
.page {
margin: 0 auto;
max-width: 40rem;
padding: $spacer;
}

44
src/pages/Styleguide.tsx Normal file
View File

@ -0,0 +1,44 @@
import React, { Component } from 'react'
import Button from '../components/atoms/Button'
import Form from '../components/atoms/Form/Form'
import Input from '../components/atoms/Form/Input'
import styles from './Styleguide.module.scss'
import form from '../data/form-styleguide.json'
class Styleguide extends Component {
public formFields = (entries: any[]) =>
entries.map(([key, value]) => (
<Input
key={key}
name={key}
label={value.label}
placeholder={value.placeholder}
required={value.required}
type={value.type}
help={value.help}
options={value.options}
/>
))
public render() {
const entries = Object.entries(form.fields)
return (
<div className={styles.page}>
<h1>Styleguide</h1>
<Button>I am a button</Button>
<Button primary>I am a primary button</Button>
<Button href="https://hello.com">
I am a link disguised as a button
</Button>
<Form title={form.title} description={form.description}>
{this.formFields(entries)}
</Form>
</div>
)
}
}
export default Styleguide