Skip to content

Commit

Permalink
Merge pull request #3 from DISIC/feat/landing-page
Browse files Browse the repository at this point in the history
feat: init landing page with header / homestepper component
  • Loading branch information
ClementNumericite authored Sep 7, 2023
2 parents 929cf01 + 0fb0b4f commit a99ef60
Show file tree
Hide file tree
Showing 17 changed files with 738 additions and 12 deletions.
42 changes: 42 additions & 0 deletions components/home/HomeActionButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { fr } from '@codegouvfr/react-dsfr';
import Button from '@codegouvfr/react-dsfr/Button';
import { tss } from 'tss-react/dsfr';

interface HomeActionButtonProps {
title: string;
buttonText: string;
buttonStyle: 'primary' | 'secondary' | 'tertiary';
}

const HomeActionButton = (props: HomeActionButtonProps) => {
const { cx, classes } = useStyles();

return (
<section className={fr.cx('fr-container', 'fr-py-16v')}>
<div className={cx(classes.container)}>
<h2>{props.title}</h2>
<Button className={cx(fr.cx('fr-my-2v'))} priority={props.buttonStyle}>
{props.buttonText}
</Button>
</div>
</section>
);
};

const useStyles = tss
.withName(HomeActionButton.name)
.withParams()
.create(() => ({
container: {
h2: {
color: fr.colors.decisions.text.title.blueFrance.default,
textAlign: 'center'
},
justifyContent: 'center',
alignItems: 'center',
display: 'flex',
flexDirection: 'column'
}
}));

export default HomeActionButton;
123 changes: 123 additions & 0 deletions components/home/HomeFeatureDisplay/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { fr } from '@codegouvfr/react-dsfr';
import Image from 'next/image';
import React, { ReactElement, ReactNode } from 'react';
import { tss } from 'tss-react';

export interface Feature {
icon: ReactElement<any, any>;
title: string;
description: string;
image: string;
imagePosition: 'left' | 'right';
}

const HomeFeatureDisplay = (props: Feature) => {
const { classes, cx } = useStyles({
imagePosition: props.imagePosition as string
});

return (
<div className={cx(classes.outerContainer)}>
<div className={cx(classes.blueBlock)} />
<section className={cx(classes.container, fr.cx('fr-container'))}>
<div
className={cx(
fr.cx('fr-grid-row', 'fr-grid-row--gutters', 'fr-grid-row--center'),
classes.grid
)}
>
<div className={fr.cx('fr-col-12', 'fr-col-md-6')}>
<div className={cx(classes.textContainer)}>
<div className={cx(classes.iconContainer)}>{props.icon}</div>
<h2>{props.title}</h2>
<p>{props.description}</p>
</div>
</div>
<div
className={cx(
fr.cx('fr-col-12', 'fr-col-md-6'),
classes.imageContainer
)}
>
<Image
src={props.image}
alt=""
width={448}
height={316}
style={{ maxWidth: '100%' }}
/>
</div>
</div>
</section>
</div>
);
};

const useStyles = tss
.withName(HomeFeatureDisplay.name)
.withParams<{ imagePosition: string }>()
.create(({ imagePosition }) => ({
outerContainer: {
position: 'relative'
},
container: {
...fr.spacing('margin', {
topBottom: '16v'
}),
...fr.spacing('padding', {
topBottom: '16v'
}),
h2: {
color: fr.colors.decisions.text.title.blueFrance.default
},
i: {
color: fr.colors.decisions.text.title.blueFrance.default
},
[fr.breakpoints.down('md')]: {
...fr.spacing('margin', {
topBottom: '1v'
})
}
},
blueBlock: {
backgroundColor: fr.colors.decisions.background.alt.blueFrance.default,
width: '70%',
height: '90%',
transform: imagePosition === 'left' ? 'skewY(-5deg)' : 'skewY(5deg)',
zIndex: -1,
position: 'absolute',
left: imagePosition === 'left' ? '30%' : '0',
[fr.breakpoints.down('md')]: {
display: 'none',
left: imagePosition === 'left' ? 100 : '0'
}
},
grid: {
flexDirection: imagePosition === 'left' ? 'row-reverse' : 'initial'
},
imageContainer: {
display: 'flex',
justifyContent: imagePosition === 'left' ? 'flex-start' : 'flex-end',
[fr.breakpoints.down('md')]: {
justifyContent: 'center',
flexDirection: 'column'
}
},
textContainer: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'center'
},
iconContainer: {
...fr.spacing('margin', { bottom: '3w' }),
width: '3rem',
height: '3rem',
borderRadius: '50%',
backgroundColor: '#FFF',
display: 'flex',
justifyContent: 'center',
alignItems: 'center'
}
}));

export default HomeFeatureDisplay;
80 changes: 80 additions & 0 deletions components/home/HomeHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { fr } from '@codegouvfr/react-dsfr';
import Image from 'next/image';
import { tss } from 'tss-react/dsfr';

const HomeHeader = () => {
const { cx, classes } = useStyles();

return (
<section>
<div className={cx(classes.blueContainer)} />
<div className={fr.cx('fr-container')}>
<div
className={fr.cx('fr-py-16v', 'fr-grid-row', 'fr-grid-row--gutters')}
>
<div className={fr.cx('fr-col', 'fr-col-12', 'fr-col-md-6')}>
<div className={cx(classes.titleContainer)}>
<h1 className={cx(classes.headerTitle)}>
Comment suivre la satisfaction de vos usagers ?
</h1>
<p>
Avec l’outil Je donne mon avis, suivez-vous en temps réel la
satisfaction des usagers de vos services publics numériques.
</p>
</div>
</div>
<div
className={cx(
fr.cx('fr-col', 'fr-col-12', 'fr-col-md-6'),
classes.image
)}
>
<Image
className={cx(classes.headerImage)}
src={'/assets/header_home.png'}
alt=""
width={351}
height={584}
/>
</div>
</div>
</div>
</section>
);
};

export default HomeHeader;

const useStyles = tss.withName('HomeHeader').create(() => ({
titleContainer: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
height: '100%'
},
blueContainer: {
backgroundColor: fr.colors.decisions.background.alt.blueFrance.default,
width: '100%',
height: '100%',
transform: 'translateY(-50%) skewY(-4deg)',
zIndex: -1,
position: 'absolute'
},
headerTitle: {
color: fr.colors.decisions.text.title.blueFrance.default,
marginBottom: '1.5rem',
[fr.breakpoints.down('md')]: {
fontSize: '2rem',
lineHeight: '2.5rem'
}
},
image: {
display: 'flex',
justifyContent: 'flex-end'
},
headerImage: {
[fr.breakpoints.down('md')]: {
display: 'none'
}
}
}));
92 changes: 92 additions & 0 deletions components/home/HomePills/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { fr } from '@codegouvfr/react-dsfr';
import { tss } from 'tss-react/dsfr';

interface HomePillsProps {
pills: Pill[];
}

export interface Pill {
title: string;
description: string;
}

const HomePills = (props: HomePillsProps) => {
const { cx, classes } = useStyles();

return (
<section className={fr.cx('fr-container')}>
<div
className={fr.cx(
'fr-grid-row',
'fr-grid-row--gutters',
'fr-grid-row--center',
'fr-py-12w'
)}
>
{props.pills.map((pill, index) => (
<div
key={index}
className={cx(fr.cx('fr-col', 'fr-col-12', 'fr-col-md-4'))}
>
<div className={cx(classes.badge)}>
<h2 className={cx(classes.title)}>{pill.title}</h2>
<div className={cx(classes.badgeIcon)}>
<i className="ri-check-line"></i>
</div>
</div>
<div className={cx(classes.paragraph)}>
<p>{pill.description}</p>
</div>
</div>
))}
</div>
</section>
);
};

const useStyles = tss
.withName(HomePills.name)
.withParams()
.create(() => ({
badge: {
...fr.spacing('margin', {
rightLeft: '5w'
}),
position: 'relative',
...fr.spacing('padding', {
rightLeft: '3w'
})
},
title: {
color: fr.colors.decisions.text.title.blueFrance.default,
textAlign: 'center',
backgroundColor: fr.colors.decisions.background.alt.blueEcume.default,
...fr.spacing('padding', {
topBottom: '1v'
}),
borderRadius: fr.spacing('3w')
},
badgeIcon: {
position: 'absolute',
top: '0',
right: '0',
transform: 'translate(-50%, -50%)',
color: fr.colors.decisions.background.default.grey.default,
backgroundColor:
fr.colors.decisions.background.actionHigh.success.default,
borderRadius: '50%',
...fr.spacing('padding', {
topBottom: '1v',
rightLeft: '1v'
})
},
paragraph: {
...fr.spacing('padding', {
rightLeft: '4w'
}),
textAlign: 'center',
fontWeight: fr.typography[0].style.fontWeight
}
}));

export default HomePills;
56 changes: 56 additions & 0 deletions components/home/HomeQuestions/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { fr } from '@codegouvfr/react-dsfr';
import { tss } from 'tss-react/dsfr';
import { Accordion } from '@codegouvfr/react-dsfr/Accordion';

interface HomeQuestionProps {
questions: Question[];
}

export interface Question {
question: string;
answer: string;
}

const HomeQuestions = (props: HomeQuestionProps) => {
const { classes, cx } = useStyles();

return (
<section className={cx(fr.cx('fr-container'), classes.root)}>
<h2>Foire aux questions</h2>
<div className={fr.cx('fr-accordions-group')}>
{props.questions.map((question, index) => {
return (
<Accordion
key={question.question + index}
label={question.question}
className={cx(classes.accordion)}
>
{question.answer}
</Accordion>
);
})}
</div>
</section>
);
};

const useStyles = tss
.withName(HomeQuestions.name)
.withParams()
.create(() => ({
root: {
h2: {
color: fr.colors.decisions.text.title.blueFrance.default,
...fr.spacing('margin', { bottom: '6w' }),
[fr.breakpoints.down('md')]: {
...fr.spacing('margin', { bottom: '3w' })
}
},
...fr.spacing('margin', { bottom: '6w' })
},
accordion: {
color: fr.colors.decisions.text.actionHigh.grey.default
}
}));

export default HomeQuestions;
Loading

0 comments on commit a99ef60

Please sign in to comment.