Skip to content

Commit

Permalink
Add Hero widget (#1077)
Browse files Browse the repository at this point in the history
* 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

* Filter complete workflows, only get relevant fields

- Filter workflows response to only include requested fields
- Filter workflows response to only include incomplete workflows
- Move translations request to work in series, as `activeWorkflows` may
  include redundant translations and these can get big
- Create a map of display names, rather than do an array search
  for performance

* Don't read background out to screenreaders

* Improve propType checking

* Use paragraph for intro text

* move error message to en.json

* test url construction in workflow select button

* remove leftover debug

* limit max-height of hero image

* add tests

* Make Hero widget responsive with SSR (#1116)

* Make Hero widget responsive with SSR

- Install @artsy/fresnel
- Move grommet theme merger to its own helper
- Add fresnel helper components
- Add media queries to Hero widget
- Update tests

* Update packages/app-project/src/helpers/theme/README.md

Co-Authored-By: Jim O'Donnell <jim@zooniverse.org>

* Add per-layout tests

* start async component tests

* add remaining tests

* refactor tests

* Resize arrow

* Remove unused const

* lint
  • Loading branch information
rogerhutchings authored and eatyourgreens committed Sep 19, 2019
1 parent 6c0f302 commit 175010f
Show file tree
Hide file tree
Showing 45 changed files with 1,214 additions and 39 deletions.
6 changes: 4 additions & 2 deletions packages/app-project/package.json
Expand Up @@ -15,6 +15,7 @@
"test:ci": "BABEL_ENV=test mocha --reporter=min"
},
"dependencies": {
"@artsy/fresnel": "~1.0.7",
"@babel/plugin-proposal-decorators": "~7.4.4",
"@babel/plugin-proposal-optional-chaining": "~7.2.0",
"@sentry/browser": "^5.4.3",
Expand Down Expand Up @@ -42,9 +43,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"
},
Expand Down
29 changes: 16 additions & 13 deletions packages/app-project/pages/_app.js
Expand Up @@ -15,6 +15,7 @@ import Head from '../src/components/Head'
import ProjectHeader from '../src/components/ProjectHeader'
import ZooHeaderWrapper from '../src/components/ZooHeaderWrapper'
import { initializeLogger, logReactError } from '../src/helpers/logger'
import { MediaContextProvider } from '../src/shared/components/Media'
import initStore from '../stores'

const GlobalStyle = createGlobalStyle`
Expand Down Expand Up @@ -92,19 +93,21 @@ export default class MyApp extends App {
<Container>
<GlobalStyle />
<Provider store={this.store}>
<GrommetWrapper>
<Head host={pageProps.host} />
<ZooHeaderWrapper />
<ProjectHeader />
<Box background={{
dark: 'dark-1',
light: 'light-1'
}}>
<Component {...pageProps} />
</Box>
<ZooFooter />
<AuthModal />
</GrommetWrapper>
<MediaContextProvider>
<GrommetWrapper>
<Head host={pageProps.host} />
<ZooHeaderWrapper />
<ProjectHeader />
<Box background={{
dark: 'dark-1',
light: 'light-1'
}}>
<Component {...pageProps} />
</Box>
<ZooFooter />
<AuthModal />
</GrommetWrapper>
</MediaContextProvider>
</Provider>
</Container>
)
Expand Down
2 changes: 2 additions & 0 deletions packages/app-project/pages/_document.js
Expand Up @@ -2,6 +2,7 @@ import Document, { Head, Main, NextScript } from 'next/document'
import React from 'react'
import { ServerStyleSheet } from 'styled-components'

import { mediaStyle } from '../src/shared/components/Media'
import { logNodeError } from '../src/helpers/logger'

const GA_TRACKING_ID = 'GTM-WDW6V4'
Expand Down Expand Up @@ -40,6 +41,7 @@ export default class MyDocument extends Document {
return (
<html>
<Head>
<style type="text/css">${mediaStyle}</style>
{isProduction && (
<script dangerouslySetInnerHTML={{ __html: GA_TRACKING_SCRIPT }} />
)}
Expand Down
@@ -1,10 +1,11 @@
import zooTheme from '@zooniverse/grommet-theme'
import { Grommet, base as baseTheme } from 'grommet'
import { Grommet } from 'grommet'
import merge from 'lodash/merge'
import { inject, observer } from 'mobx-react'
import { node, object, oneOf } from 'prop-types'
import React, { Component } from 'react'

import theme from '../theme'

function storeMapper (stores) {
const { mode } = stores.store.ui
return {
Expand All @@ -17,7 +18,7 @@ function storeMapper (stores) {
class GrommetWrapperContainer extends Component {
mergeThemes () {
const { mode, theme } = this.props
return merge({}, baseTheme, theme, { dark: mode === 'dark' })
return merge({}, theme, { dark: mode === 'dark' })
}

render () {
Expand All @@ -40,7 +41,7 @@ GrommetWrapperContainer.propTypes = {

GrommetWrapperContainer.defaultProps = {
mode: 'light',
theme: zooTheme
theme
}

export default GrommetWrapperContainer
2 changes: 1 addition & 1 deletion packages/app-project/src/helpers/GrommetWrapper/README.md
Expand Up @@ -3,6 +3,6 @@
This component handles a few things related to the Grommet theme:

- Creating a Grommet context
- 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
5 changes: 5 additions & 0 deletions packages/app-project/src/helpers/theme/README.md
@@ -0,0 +1,5 @@
# Theme

Creates a Grommet theme by performing a deep merge of the Grommet base theme with the Zooniverse custom Grommet theme.

This was originally done in the `GrommetWrapper` theme, but was moved here so it can be reused with `@artsy/fresnel` to extract the breakpoints for responsive sizing.
1 change: 1 addition & 0 deletions packages/app-project/src/helpers/theme/index.js
@@ -0,0 +1 @@
export { default } from './theme'
7 changes: 7 additions & 0 deletions packages/app-project/src/helpers/theme/theme.js
@@ -0,0 +1,7 @@
import zooTheme from '@zooniverse/grommet-theme'
import { base as baseTheme } from 'grommet'
import merge from 'lodash/merge'

const theme = merge({}, baseTheme, zooTheme)

export default theme
34 changes: 19 additions & 15 deletions packages/app-project/src/screens/ProjectHomePage/ProjectHomePage.js
Expand Up @@ -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'
Expand All @@ -13,22 +14,25 @@ function ProjectHomePage (props) {
const { screenSize } = props
const responsiveColumns = (screenSize === 'small') ? ['auto'] : ['auto', '1em']
return (
<Grid gap='medium' margin='medium'>
<Grid columns={responsiveColumns} gap='small'>
<ZooniverseTalk />
<ThemeModeToggle />
<>
<Hero />
<Grid gap='medium' margin='medium'>
<Grid columns={responsiveColumns} gap='small'>
<ZooniverseTalk />
<ThemeModeToggle />
</Grid>
<ProjectStatistics />
<Grid
fill='horizontal'
gap='medium'
columns={['repeat(auto-fit, minmax(320px, 1fr))']}
>
<MessageFromResearcher />
<AboutProject />
</Grid>
<ConnectWithProject />
</Grid>
<ProjectStatistics />
<Grid
fill='horizontal'
gap='medium'
columns={['repeat(auto-fit, minmax(320px, 1fr))']}
>
<MessageFromResearcher />
<AboutProject />
</Grid>
<ConnectWithProject />
</Grid>
</>
)
}

Expand Down
@@ -0,0 +1,67 @@
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'
import { Media } from '../../../../shared/components/Media'

const StyledContentBox = styled(ContentBox)`
${props => (props.screenSize !== 'small') && `
border-color: transparent;
max-height: 763px;
`}
`

function Hero (props) {
const { screenSize, workflows } = props

return (
<>
<Media at='default'>
<Box
align='stretch'
background={{
dark: 'dark-1',
light: 'light-1'
}}
direction='column'
justify='between'
>
<Background />
<Grid margin={{ top: 'medium-neg', horizontal: 'medium' }}>
<StyledContentBox gap='medium' screenSize={screenSize}>
<Introduction />
<WorkflowSelector workflows={workflows} />
</StyledContentBox>
</Grid>
</Box>
</Media>

<Media greaterThan='default'>
<Grid columns={['1.618fr', '1fr']} margin={{ bottom: 'medium' }}>
<Background />
<StyledContentBox
gap='medium'
justify='between'
pad='medium'
screenSize={screenSize}
>
<Introduction />
<WorkflowSelector workflows={workflows} />
</StyledContentBox>
</Grid>
</Media>
</>
)
}

const DecoratedHero = withResponsiveContext(Hero)

export {
DecoratedHero as default,
Hero
}
@@ -0,0 +1,68 @@
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'
import { Media } from '../../../../shared/components/Media'

describe('Component > Hero', function () {
let wrapper

before(function () {
wrapper = shallow(<Hero screenSize='small' />)
})

it('should render without crashing', function () {
expect(wrapper).to.be.ok()
})

describe('behaviour on small screens', function () {
let mediaWrapper

before(function () {
mediaWrapper = wrapper.find(Media).find({ at: 'default' })
})

it('should have a layout for small screens', function () {
expect(mediaWrapper).to.have.lengthOf(1)
})

it('should render the `Background` component', function () {
expect(mediaWrapper.find(Background)).to.have.lengthOf(1)
})

it('should render the `Introduction` component', function () {
expect(mediaWrapper.find(Introduction)).to.have.lengthOf(1)
})

it('should render the `WorkflowSelector` component', function () {
expect(mediaWrapper.find(WorkflowSelector)).to.have.lengthOf(1)
})
})

describe('behaviour on larger screens', function () {
let mediaWrapper

before(function () {
mediaWrapper = wrapper.find(Media).find({ greaterThan: 'default' })
})

it('should have a layout for larger screens', function () {
expect(mediaWrapper).to.have.lengthOf(1)
})

it('should render the `Background` component', function () {
expect(mediaWrapper.find(Background)).to.have.lengthOf(1)
})

it('should render the `Introduction` component', function () {
expect(mediaWrapper.find(Introduction)).to.have.lengthOf(1)
})

it('should render the `WorkflowSelector` component', function () {
expect(mediaWrapper.find(WorkflowSelector)).to.have.lengthOf(1)
})
})
})

0 comments on commit 175010f

Please sign in to comment.