From 4c1a28d69bef02e5f39ea91b4122eac63ae63117 Mon Sep 17 00:00:00 2001 From: Roger Hutchings Date: Wed, 14 Aug 2019 16:29:54 +0100 Subject: [PATCH 01/17] Add Hero widget - Set default screen size to 'small' - Update React to match other apps - Add Hero component - Add background - Add about link and intro - Add workflow loader --- packages/app-project/package.json | 5 +- .../GrommetWrapper/GrommetWrapperContainer.js | 2 +- .../src/helpers/GrommetWrapper/README.md | 1 + .../ProjectHomePage/ProjectHomePage.js | 34 +++++---- .../ProjectHomePage/components/Hero/Hero.js | 66 ++++++++++++++++ .../components/Hero/Hero.spec.js | 31 ++++++++ .../components/Hero/HeroContainer.js | 75 +++++++++++++++++++ .../components/Hero/HeroContainer.spec.js | 23 ++++++ .../ProjectHomePage/components/Hero/README.md | 8 ++ .../Hero/components/Background/Background.js | 39 ++++++++++ .../components/Background/Background.spec.js | 22 ++++++ .../Background/BackgroundContainer.js | 32 ++++++++ .../Background/BackgroundContainer.spec.js | 29 +++++++ .../Hero/components/Background/index.js | 1 + .../components/Introduction/Introduction.js | 45 +++++++++++ .../Introduction/Introduction.spec.js | 38 ++++++++++ .../Introduction/IntroductionContainer.js | 58 ++++++++++++++ .../IntroductionContainer.spec.js | 30 ++++++++ .../Hero/components/Introduction/README.md | 3 + .../Hero/components/Introduction/index.js | 1 + .../components/Introduction/locales/en.json | 5 ++ .../WorkflowSelector/WorkflowSelector.js | 70 +++++++++++++++++ .../WorkflowSelector/WorkflowSelector.spec.js | 16 ++++ .../WorkflowSelectButton.js | 37 +++++++++ .../WorkflowSelectButton.spec.js | 16 ++++ .../components/WorkflowSelectButton/index.js | 1 + .../WorkflowSelectButton/locales/en.json | 4 + .../components/WorkflowSelectButton/theme.js | 17 +++++ .../Hero/components/WorkflowSelector/index.js | 1 + .../WorkflowSelector/locales/en.json | 6 ++ .../fetchWorkflowsHelper.js | 50 +++++++++++++ .../fetchWorkflowsHelper.spec.js | 72 ++++++++++++++++++ .../helpers/fetchWorkflowsHelper/index.js | 1 + .../ProjectHomePage/components/Hero/index.js | 1 + packages/lib-grommet-theme/src/index.js | 18 ++++- yarn.lock | 32 ++++++++ 36 files changed, 868 insertions(+), 22 deletions(-) create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/Hero.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/Hero.spec.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/HeroContainer.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/HeroContainer.spec.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/README.md create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/Background.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/Background.spec.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/BackgroundContainer.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/BackgroundContainer.spec.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/index.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/Introduction.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/Introduction.spec.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/IntroductionContainer.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/IntroductionContainer.spec.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/README.md create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/index.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/locales/en.json create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/WorkflowSelector/WorkflowSelector.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/WorkflowSelector/WorkflowSelector.spec.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/WorkflowSelector/components/WorkflowSelectButton/WorkflowSelectButton.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/WorkflowSelector/components/WorkflowSelectButton/WorkflowSelectButton.spec.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/WorkflowSelector/components/WorkflowSelectButton/index.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/WorkflowSelector/components/WorkflowSelectButton/locales/en.json create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/WorkflowSelector/components/WorkflowSelectButton/theme.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/WorkflowSelector/index.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/components/WorkflowSelector/locales/en.json create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/helpers/fetchWorkflowsHelper/fetchWorkflowsHelper.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/helpers/fetchWorkflowsHelper/fetchWorkflowsHelper.spec.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/helpers/fetchWorkflowsHelper/index.js create mode 100644 packages/app-project/src/screens/ProjectHomePage/components/Hero/index.js diff --git a/packages/app-project/package.json b/packages/app-project/package.json index edbb8adcf0..337d06f719 100644 --- a/packages/app-project/package.json +++ b/packages/app-project/package.json @@ -42,9 +42,10 @@ "next": "~9.0.3", "panoptes-client": "~2.12.0", "path-match": "~1.2.4", - "react": "~16.8.4", - "react-dom": "~16.8.4", + "react": "~16.8.6", + "react-dom": "~16.8.6", "styled-components": "~4.1.3", + "svg-loaders-react": "~2.0.1", "url-parse": "~1.4.7", "validator": "~11.0.0" }, diff --git a/packages/app-project/src/helpers/GrommetWrapper/GrommetWrapperContainer.js b/packages/app-project/src/helpers/GrommetWrapper/GrommetWrapperContainer.js index f2d8ba8381..4f3d4cebe8 100644 --- a/packages/app-project/src/helpers/GrommetWrapper/GrommetWrapperContainer.js +++ b/packages/app-project/src/helpers/GrommetWrapper/GrommetWrapperContainer.js @@ -25,7 +25,7 @@ class GrommetWrapperContainer extends Component { const mergedThemes = this.mergeThemes() return ( - + {children} ) diff --git a/packages/app-project/src/helpers/GrommetWrapper/README.md b/packages/app-project/src/helpers/GrommetWrapper/README.md index 7bb37cea33..251ad1a4a1 100644 --- a/packages/app-project/src/helpers/GrommetWrapper/README.md +++ b/packages/app-project/src/helpers/GrommetWrapper/README.md @@ -6,3 +6,4 @@ This component handles a few things related to the Grommet theme: - Merging the Zooniverse Grommet theme with the Grommet base theme - Observing the UI store, fetching the `mode` property, and using that to set the `dark` boolean property on the theme - Passing the theme into the Grommet context +- Setting a default screen size diff --git a/packages/app-project/src/screens/ProjectHomePage/ProjectHomePage.js b/packages/app-project/src/screens/ProjectHomePage/ProjectHomePage.js index f01f300250..77a02a350a 100644 --- a/packages/app-project/src/screens/ProjectHomePage/ProjectHomePage.js +++ b/packages/app-project/src/screens/ProjectHomePage/ProjectHomePage.js @@ -2,6 +2,7 @@ import { Grid } from 'grommet' import React from 'react' import { withResponsiveContext } from '@zooniverse/react-components' +import Hero from './components/Hero' import MessageFromResearcher from './components/MessageFromResearcher' import AboutProject from '../../shared/components/AboutProject' import ConnectWithProject from '../../shared/components/ConnectWithProject' @@ -13,22 +14,25 @@ function ProjectHomePage (props) { const { screenSize } = props const responsiveColumns = (screenSize === 'small') ? ['auto'] : ['auto', '1em'] return ( - - - - + <> + + + + + + + + + + + + - - - - - - - + ) } diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/Hero.js b/packages/app-project/src/screens/ProjectHomePage/components/Hero/Hero.js new file mode 100644 index 0000000000..7d07e35b4a --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/Hero.js @@ -0,0 +1,66 @@ +import { withResponsiveContext } from '@zooniverse/react-components' +import { Box, Grid } from 'grommet' +import React from 'react' +import styled from 'styled-components' + +import Background from './components/Background' +import Introduction from './components/Introduction' +import WorkflowSelector from './components/WorkflowSelector' +import ContentBox from '../../../../shared/components/ContentBox' + +const StyledContentBox = styled(ContentBox)` + ${props => (props.screenSize !== 'small') && ` + border-color: transparent; + `} +` + +function Hero (props) { + const { className, screenSize, workflows } = props + + // Default to `small` layout + let component = ( + + + + + + + + + + ) + + if (screenSize !== 'small') { + component = ( + + + + + + + + ) + } + + return component +} + +const DecoratedHero = withResponsiveContext(Hero) + +export { + DecoratedHero as default, + Hero +} diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/Hero.spec.js b/packages/app-project/src/screens/ProjectHomePage/components/Hero/Hero.spec.js new file mode 100644 index 0000000000..3596cdd74d --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/Hero.spec.js @@ -0,0 +1,31 @@ +import { shallow } from 'enzyme' +import React from 'react' + +import { Hero } from './Hero' +import Background from './components/Background' +import Introduction from './components/Introduction' +import WorkflowSelector from './components/WorkflowSelector' + +let wrapper + +describe('Component > Hero', function () { + before(function () { + wrapper = shallow() + }) + + it('should render without crashing', function () { + console.info(wrapper.debug()) + }) + + it('should render the `Background` component', function () { + expect(wrapper.find(Background)).to.have.lengthOf(1) + }) + + it('should render the `Introduction` component', function () { + expect(wrapper.find(Introduction)).to.have.lengthOf(1) + }) + + it('should render the `WorkflowSelector` component', function () { + expect(wrapper.find(WorkflowSelector)).to.have.lengthOf(1) + }) +}) diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/HeroContainer.js b/packages/app-project/src/screens/ProjectHomePage/components/Hero/HeroContainer.js new file mode 100644 index 0000000000..bb94a7a72c --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/HeroContainer.js @@ -0,0 +1,75 @@ +import { inject, observer } from 'mobx-react' +import PropTypes from 'prop-types' +import React, { Component } from 'react' +import asyncStates from '@zooniverse/async-states' + +import Hero from './Hero' +import fetchWorkflowsHelper from './helpers/fetchWorkflowsHelper' + +function storeMapper(stores) { + return { + activeWorkflows: stores.store.project.links['active_workflows'], + defaultWorkflow: stores.store.project.configuration['default_workflow'], + language: stores.store.ui.language + } +} + +@inject(storeMapper) +@observer +class HeroContainer extends Component { + constructor() { + super() + this.state = { + workflows: { + loading: asyncStates.initialized, + data: [] + } + } + } + + componentDidMount () { + this.fetchWorkflows() + } + + async fetchWorkflows() { + this.setState(state => ({ + workflows: { + ...state.workflows, + loading: asyncStates.loading + } + })) + try { + const { activeWorkflows, defaultWorkflow, language } = this.props + const workflows = await fetchWorkflowsHelper(language, activeWorkflows, defaultWorkflow) + this.setState({ + workflows: { + loading: asyncStates.success, + data: workflows + } + }) + } catch (error) { + console.error(error) + this.setState(state => ({ + workflows: { + ...state.workflows, + loading: asyncStates.error + } + })) + } + } + + render () { + const { workflows } = this.state + return ( + + ) + } +} + +HeroContainer.propTypes = { +} + +HeroContainer.defaultProps = { +} + +export default HeroContainer diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/HeroContainer.spec.js b/packages/app-project/src/screens/ProjectHomePage/components/Hero/HeroContainer.spec.js new file mode 100644 index 0000000000..e22a33ae74 --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/HeroContainer.spec.js @@ -0,0 +1,23 @@ +import { shallow } from 'enzyme' +import React from 'react' + +import HeroContainer from './HeroContainer' +import Hero from './Hero' + +let wrapper +let componentWrapper + +describe('Component > HeroContainer', function () { + before(function () { + wrapper = shallow() + componentWrapper = wrapper.find(Hero) + }) + + it('should render without crashing', function () { + expect(wrapper).to.be.ok() + }) + + it('should render the `Hero` component', function () { + expect(componentWrapper).to.have.lengthOf(1) + }) +}) diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/README.md b/packages/app-project/src/screens/ProjectHomePage/components/Hero/README.md new file mode 100644 index 0000000000..8a4260371f --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/README.md @@ -0,0 +1,8 @@ +# Hero + +This is the main hero component at the top of the project home / landing page. + +## Notes + +- The workflows to be shown are fetched in ``, as the component that actually lists them can be unmounted depending on screen size. +- The component defaults to a narrow view. \ No newline at end of file diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/Background.js b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/Background.js new file mode 100644 index 0000000000..3b7be73ba8 --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/Background.js @@ -0,0 +1,39 @@ +import { withResponsiveContext } from '@zooniverse/react-components' +import { string } from 'prop-types' +import React from 'react' +import styled from 'styled-components' + +const Img = styled.img` + height: 100%; + min-height: 61.8vh; + object-fit: cover; + object-position: 0 50%; + width: 100%; + + ${props => props.screenSize === 'small' && ` + height: auto; + min-height: inherit; + object-fit: contain; + width: 100%; + `} +` + +function Background (props) { + const { className, backgroundSrc, screenSize } = props + return ( + + ) +} + +Background.propTypes = { + backgroundSrc: string +} + +export default withResponsiveContext(Background) +export { + Background +} diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/Background.spec.js b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/Background.spec.js new file mode 100644 index 0000000000..6f0fdeefee --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/Background.spec.js @@ -0,0 +1,22 @@ +import { render } from 'enzyme' +import React from 'react' + +import { Background } from './Background' + +const BACKGROUND_SRC = '/foo/bar/baz.jpg' + +describe('Component > Background', function () { + let wrapper + before(function () { + wrapper = render() + }) + + it('should render without crashing', function () { + expect(wrapper).to.be.ok() + }) + + it('should render an `img` with the correct src', function () { + expect(wrapper[0].name).to.equal('img') + expect(wrapper.attr('src')).to.equal(BACKGROUND_SRC) + }) +}) diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/BackgroundContainer.js b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/BackgroundContainer.js new file mode 100644 index 0000000000..64fd50d03a --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/BackgroundContainer.js @@ -0,0 +1,32 @@ +import { inject, observer } from 'mobx-react' +import { string } from 'prop-types' +import React, { Component } from 'react' + +import Background from './Background' + +function storeMapper(stores) { + return { + backgroundSrc: stores.store.project.background.src + } +} + +class BackgroundContainer extends Component { + render() { + return ( + + ) + } +} + +BackgroundContainer.propTypes = { + backgroundSrc: string +} + +@inject(storeMapper) +@observer +class DecoratedBackgroundContainer extends BackgroundContainer { } + +export { + DecoratedBackgroundContainer as default, + BackgroundContainer +} diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/BackgroundContainer.spec.js b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/BackgroundContainer.spec.js new file mode 100644 index 0000000000..5f3802b918 --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/BackgroundContainer.spec.js @@ -0,0 +1,29 @@ +import { shallow } from 'enzyme' +import React from 'react' + +import { BackgroundContainer } from './BackgroundContainer' +import Background from './Background' + +const BACKGROUND_SRC = '/foo/bar/baz.jpg' + +let wrapper +let componentWrapper + +describe('Component > BackgroundContainer', function () { + before(function () { + wrapper = shallow() + componentWrapper = wrapper.find(Background) + }) + + it('should render without crashing', function () { + expect(wrapper).to.be.ok() + }) + + it('should render the `Background` component', function () { + expect(componentWrapper).to.have.lengthOf(1) + }) + + it('should pass down the `backgroundSrc` prop', function () { + expect(componentWrapper.prop('backgroundSrc')).to.equal(BACKGROUND_SRC) + }) +}) diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/index.js b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/index.js new file mode 100644 index 0000000000..837131eab6 --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Background/index.js @@ -0,0 +1 @@ +export { default } from './BackgroundContainer' diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/Introduction.js b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/Introduction.js new file mode 100644 index 0000000000..25472f9ba5 --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/Introduction.js @@ -0,0 +1,45 @@ +import { SpacedText } from '@zooniverse/react-components' +import counterpart from 'counterpart' +import { Anchor, Box, Text } from 'grommet' +import { Next } from 'grommet-icons' +import Link from 'next/link' +import { object, string } from 'prop-types' +import React from 'react' + +import en from './locales/en' + +counterpart.registerTranslations('en', en) + +function Introduction (props) { + const { description, link, title } = props + return ( + + + + {title} + + + + + {description} + + + + } + label={{counterpart('Introduction.link')}} + reverse + /> + + + ) +} + +Introduction.propTypes = { + description: string, + link: object, + title: string, +} + +export default Introduction diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/Introduction.spec.js b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/Introduction.spec.js new file mode 100644 index 0000000000..07fccef92a --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/Introduction.spec.js @@ -0,0 +1,38 @@ +import { render } from 'enzyme' +import React from 'react' + +import Introduction from './Introduction' + +let wrapper + +const DESCRIPTION = 'Project Title!' +const LINK = { + href: '/projects/foo/bar/about' +} +const TITLE = 'baz' + +describe('Component > Introduction', function () { + before(function () { + wrapper = render() + }) + + it('should render without crashing', function () { + expect(wrapper).to.be.ok() + }) + + it('should render the title', function () { + expect(wrapper.text().includes(TITLE)).to.be.true() + }) + + it('should render the description', function () { + expect(wrapper.text().includes(DESCRIPTION)).to.be.true() + }) + + it('should render a link to the about page', function () { + expect(wrapper.find(`a[href="${LINK.href}"]`)).to.have.lengthOf(1) + }) +}) diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/IntroductionContainer.js b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/IntroductionContainer.js new file mode 100644 index 0000000000..991102b767 --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/IntroductionContainer.js @@ -0,0 +1,58 @@ +import { inject, observer } from 'mobx-react' +import { withRouter } from 'next/router' +import { shape, string } from 'prop-types' +import React, { Component } from 'react' + +import Introduction from './Introduction' + +function storeMapper (stores) { + const { project } = stores.store + return { + description: project.description, + title: project.display_name, + } +} + +class IntroductionContainer extends Component { + getLink () { + const { query } = this.props.router + const linkQuery = { + owner: query.owner, + project: query.project, + } + + return { + as: `/projects/${query.owner}/${query.project}/about`, + href: '/about' + } + } + + render () { + const { description, title } = this.props + const link = this.getLink() + return ( + + ) + } +} + +IntroductionContainer.propTypes = { + description: string, + router: shape({ + query: shape({ + owner: string, + project: string + }) + }), + title: string +} + +@inject(storeMapper) +@withRouter +@observer +class DecoratedIntroductionContainer extends IntroductionContainer {} + +export { + DecoratedIntroductionContainer as default, + IntroductionContainer +} diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/IntroductionContainer.spec.js b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/IntroductionContainer.spec.js new file mode 100644 index 0000000000..a804ec6f44 --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/IntroductionContainer.spec.js @@ -0,0 +1,30 @@ +import { shallow } from 'enzyme' +import React from 'react' + +import { IntroductionContainer } from './IntroductionContainer' +import Introduction from './Introduction' + +let wrapper +let componentWrapper + +const ROUTER = { + query: { + owner: 'foo', + project: 'bar' + } +} + +describe('Component > IntroductionContainer', function () { + before(function () { + wrapper = shallow() + componentWrapper = wrapper.find(Introduction) + }) + + it('should render without crashing', function () { + expect(wrapper).to.be.ok() + }) + + it('should render the `Introduction` component', function () { + expect(componentWrapper).to.have.lengthOf(1) + }) +}) diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/README.md b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/README.md new file mode 100644 index 0000000000..04a1a29d10 --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/README.md @@ -0,0 +1,3 @@ +# Introduction + +The top section of the Hero component with the project title, description and a link to the about page. diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/index.js b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/index.js new file mode 100644 index 0000000000..3ac2fc5790 --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/index.js @@ -0,0 +1 @@ +export { default } from './IntroductionContainer' diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/locales/en.json b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/locales/en.json new file mode 100644 index 0000000000..bae1b9b092 --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/Introduction/locales/en.json @@ -0,0 +1,5 @@ +{ + "Introduction": { + "link": "Learn more" + } +} diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/WorkflowSelector/WorkflowSelector.js b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/WorkflowSelector/WorkflowSelector.js new file mode 100644 index 0000000000..1a2d382bb2 --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/WorkflowSelector/WorkflowSelector.js @@ -0,0 +1,70 @@ +import asyncStates from '@zooniverse/async-states' +import { SpacedText } from '@zooniverse/react-components' +import counterpart from 'counterpart' +import { Box, Text } from 'grommet' +import { arrayOf, shape, string } from 'prop-types' +import React from 'react' +import { withTheme } from 'styled-components' +import { Bars } from 'svg-loaders-react' + +import WorkflowSelectButton from './components/WorkflowSelectButton' +import en from './locales/en' + +counterpart.registerTranslations('en', en) + +function WorkflowSelector (props) { + const { workflows } = props + const loaderColor = props.theme.global.colors.brand + + return ( + + + {counterpart('WorkflowSelector.classify')} + + + {counterpart('WorkflowSelector.message')} + + + {(workflows.loading === asyncStates.error) && ( + + There was an error fetching the workflows :( + + )} + + {(workflows.loading === asyncStates.success) && ( + + {workflows.data.map(workflow => + + )} + + )} + + {(!asyncStates.values.includes(workflows.loading)) && ( + + + + + + )} + + ) +} + +WorkflowSelector.propTypes = { + workflows: shape({ + data: arrayOf(shape({ + id: string + })) + }) +} + +export default withTheme(WorkflowSelector) diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/WorkflowSelector/WorkflowSelector.spec.js b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/WorkflowSelector/WorkflowSelector.spec.js new file mode 100644 index 0000000000..4d7168231a --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/WorkflowSelector/WorkflowSelector.spec.js @@ -0,0 +1,16 @@ +import { shallow } from 'enzyme' +import React from 'react' + +import WorkflowSelector from './WorkflowSelector' + +let wrapper + +describe('Component > WorkflowSelector', function () { + before(function () { + wrapper = shallow() + }) + + it('should render without crashing', function () { + expect(wrapper).to.be.ok() + }) +}) diff --git a/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/WorkflowSelector/components/WorkflowSelectButton/WorkflowSelectButton.js b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/WorkflowSelector/components/WorkflowSelectButton/WorkflowSelectButton.js new file mode 100644 index 0000000000..7dd6df50ad --- /dev/null +++ b/packages/app-project/src/screens/ProjectHomePage/components/Hero/components/WorkflowSelector/components/WorkflowSelectButton/WorkflowSelectButton.js @@ -0,0 +1,37 @@ +import { withThemeContext } from '@zooniverse/react-components' +import { Button } from 'grommet' +import Link from 'next/link' +import { useRouter } from 'next/router' +import { bool, shape, string } from 'prop-types' +import React from 'react' + +import theme from './theme' + +function WorkflowSelectButton (props) { + const { workflow } = props + const router = useRouter() + + const as = workflow.default + ? `${router.asPath}/classify` + : `${router.asPath}/classify/workflow/${workflow.id}` + + const href = '/Classify' + + return ( + +