Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor classifier layout per survey task #6297

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,31 @@ function storeMapper(classifierStore) {
const limitSubjectHeight = workflow?.configuration?.limit_subject_height
const layout = limitSubjectHeight ? 'centered' : workflow?.layout
const separateFramesView = classifierStore.subjectViewer.separateFramesView
const hasSurveyTask = workflow?.hasSurveyTask

return {
layout,
separateFramesView
separateFramesView,
hasSurveyTask
}
}

function Layout() {
const {
layout,
separateFramesView,
hasSurveyTask
} = useStores(storeMapper)

// `getLayout()` will always return the default layout as a fallback
const { layout, separateFramesView } = useStores(storeMapper)
const CurrentLayout = getLayout(layout)
return <CurrentLayout separateFramesView={separateFramesView} />

return (
<CurrentLayout
separateFramesView={separateFramesView}
hasSurveyTask={hasSurveyTask}
/>
)
}

export default observer(Layout)
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,13 @@ export const horizontalLayout = {
justify: 'center'
}

export default function CenteredLayout({ separateFramesView = false }) {
export default function CenteredLayout({
separateFramesView = false,
hasSurveyTask = false
}) {
const size = useContext(ResponsiveContext)
const containerProps = size === 'small' ? verticalLayout : horizontalLayout
const taskAreaWidth = hasSurveyTask ? '33.75rem' : '25rem'

return (
<Relative>
Expand All @@ -75,7 +79,7 @@ export default function CenteredLayout({ separateFramesView = false }) {
)}
</Box>
<StickyTaskArea
width={size === 'small' ? '100%' : '25rem'}
width={size === 'small' ? '100%' : taskAreaWidth}
fill={size === 'small' ? 'horizontal' : 'vertical'}
size={size}
>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Provider } from 'mobx-react'
import { SubjectFactory, WorkflowFactory } from '@test/factories'
import mockStore from '@test/mockStore'
import { task } from '@plugins/tasks/survey/mock-data'

import CenteredLayout from './CenteredLayout'

Expand Down Expand Up @@ -71,3 +72,39 @@ Default.store = mockStore({
subject: subjectSnapshot,
workflow: workflowSnapshot
})

const surveyTaskStrings = {}
const taskEntries = Object.entries(task.strings)
taskEntries.forEach(([key, value]) => {
const translationKey = `tasks.T0.${key}`
surveyTaskStrings[translationKey] = value
})

const surveyWorkflowSnapshot = WorkflowFactory.build({
configuration: {
invert_subject: true,
limit_subject_height: true
},
first_task: 'T0',
strings: surveyTaskStrings,
tasks: { T0: task }
})

export function WithSurveyTask({
separateFramesView,
hasSurveyTask = true
}) {
return (
<Provider classifierStore={WithSurveyTask.store}>
<CenteredLayout
separateFramesView={separateFramesView}
hasSurveyTask={hasSurveyTask}
/>
</Provider>
)
}

WithSurveyTask.store = mockStore({
subject: subjectSnapshot,
workflow: surveyWorkflowSnapshot
})
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useContext } from 'react'
import styled, { css } from 'styled-components'
import { Box, Grid, ResponsiveContext } from 'grommet'
import { Box, Grid } from 'grommet'

import Banners from '@components/Classifier/components/Banners'
import FeedbackModal from '@components/Classifier/components/Feedback'
Expand All @@ -13,21 +12,54 @@ import FieldGuide from '@components/Classifier/components/FieldGuide'

export const ContainerGrid = styled(Grid)`
position: relative;
grid-gap: 1.875rem;
grid-template-areas: 'viewer task';
grid-template-columns: minmax(auto, 100rem) ${props => (props.hasSurveyTask ? '33.75rem' : '25rem')};
margin: auto;

// proportional 9:5 subject/task sizing up to a maximum subject/task width of 45rem/25rem, then the Grommet Grid columns take over
@media screen and (min-width: 769px) and (max-width: 70rem) {
grid-gap: 1.75rem;
grid-template-columns: 9fr 5fr;
${props => props.hasSurveyTask ? css`
@media screen and (min-width: 769px) and (max-width: 70rem) {
grid-gap: 1.25rem;
grid-template-areas:
'viewer'
'task';
grid-template-columns: 100%;
grid-template-rows: auto auto;
margin: 0;
}
` : css`
// proportional 9:5 subject/task sizing up to a maximum subject/task width of 45rem/25rem
@media screen and (min-width: 769px) and (max-width: 70rem) {
grid-gap: 1.25rem;
grid-template-areas: 'viewer task';
grid-template-columns: 9fr 5fr;
}
`}

@media screen and (max-width: 768px) {
grid-gap: 1.25rem;
grid-template-areas:
'viewer'
'task';
grid-template-columns: 100%;
grid-template-rows: auto auto;
margin: 0;
}
`

export const ViewerGrid = styled(Grid)`
${props =>
props.size !== 'small' &&
css`
${props => props.hasSurveyTask ? css`
@media screen and (min-width: 70rem) {
position: sticky;
top: 10px;
}
` : css`
@media screen and (min-width: 769px) {
position: sticky;
top: 10px;
`}
}
`}

height: fit-content;
grid-area: viewer;
grid-template-columns: auto clamp(3rem, 10%, 4.5rem);
Expand All @@ -40,12 +72,17 @@ const StyledTaskAreaContainer = styled.div`
`

const StyledTaskArea = styled(Box)`
${props =>
props.size !== 'small' &&
css`
${props => props.hasSurveyTask ? css`
@media screen and (min-width: 70rem) {
position: sticky;
top: 10px;
}
` : css`
@media screen and (min-width: 769px) {
position: sticky;
top: 10px;
`}
}
`}
`

const StyledImageToolbarContainer = styled.div`
Expand All @@ -57,40 +94,27 @@ const StyledImageToolbar = styled(ImageToolbar)`
top: 10px;
`

export const verticalLayout = {
areas: [['viewer'], ['task']],
columns: ['100%'],
gap: 'small',
margin: 'none',
rows: ['auto', 'auto']
}

export const horizontalLayout = {
areas: [['viewer', 'task']],
columns: ['minmax(auto,100rem)', '25rem'],
gap: 'medium',
margin: 'auto',
rows: ['auto']
}

export default function MaxWidth({
className = '',
separateFramesView = false
separateFramesView = false,
hasSurveyTask = false
}) {
const size = useContext(ResponsiveContext)
const containerGridProps =
size === 'small' ? verticalLayout : horizontalLayout

return (
<ContainerGrid className={className} {...containerGridProps}>
<ContainerGrid
className={className}
hasSurveyTask={hasSurveyTask}
>
{separateFramesView ? (
<Box>
<Banners />
<SubjectViewer />
<MetaTools />
</Box>
) : (
<ViewerGrid forwardedAs='section' size={size}>
<ViewerGrid
forwardedAs='section'
hasSurveyTask={hasSurveyTask}
>
<Box gridArea='subject'>
<Banners />
<SubjectViewer />
Expand All @@ -102,7 +126,7 @@ export default function MaxWidth({
</ViewerGrid>
)}
<StyledTaskAreaContainer>
<StyledTaskArea size={size}>
<StyledTaskArea hasSurveyTask={hasSurveyTask}>
<TaskArea />
{separateFramesView && <FieldGuide />}
</StyledTaskArea>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Provider } from 'mobx-react'
import { SubjectFactory, WorkflowFactory } from '@test/factories'
import mockStore from '@test/mockStore'
import { task } from '@plugins/tasks/survey/mock-data'

import MaxWidth from './MaxWidth'

Expand Down Expand Up @@ -68,3 +69,39 @@ Default.store = mockStore({
subject: subjectSnapshot,
workflow: workflowSnapshot
})

const surveyTaskStrings = {}
const taskEntries = Object.entries(task.strings)
taskEntries.forEach(([key, value]) => {
const translationKey = `tasks.T0.${key}`
surveyTaskStrings[translationKey] = value
})

const surveyWorkflowSnapshot = WorkflowFactory.build({
configuration: {
invert_subject: true,
limit_subject_height: true
},
first_task: 'T0',
strings: surveyTaskStrings,
tasks: { T0: task }
})

export function WithSurveyTask({
separateFramesView,
hasSurveyTask = true
}) {
return (
<Provider classifierStore={WithSurveyTask.store}>
<MaxWidth
separateFramesView={separateFramesView}
hasSurveyTask={hasSurveyTask}
/>
</Provider>
)
}

WithSurveyTask.store = mockStore({
subject: subjectSnapshot,
workflow: surveyWorkflowSnapshot
})
Loading