💩(frontend) introduce an official footer
Based on Florian's feedbacks, this is mandatory as the project is getting attention. Bad code, needs a refactor.
This commit is contained in:
committed by
aleb_the_flash
parent
819d3784f7
commit
e7e7bb0d09
3
src/frontend/public/assets/link-grey.svg
Normal file
3
src/frontend/public/assets/link-grey.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.66667 4.00098V5.33431H3.33333V12.6676H10.6667V9.33431H12V13.3343C12 13.7025 11.7015 14.001 11.3333 14.001H2.66667C2.29848 14.001 2 13.7025 2 13.3343V4.66764C2 4.29945 2.29848 4.00098 2.66667 4.00098H6.66667ZM14 2.00098V7.33431H12.6667V4.27631L7.47133 9.47231L6.52867 8.52964L11.7233 3.33431H8.66667V2.00098H14Z" fill="#666666"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 484 B |
@@ -7,6 +7,7 @@ import { Center } from '@/styled-system/jsx'
|
||||
export const LoadingScreen = ({
|
||||
delay = 500,
|
||||
header = undefined,
|
||||
footer = undefined,
|
||||
layout = 'centered',
|
||||
}: {
|
||||
delay?: number
|
||||
@@ -15,7 +16,7 @@ export const LoadingScreen = ({
|
||||
|
||||
return (
|
||||
<DelayedRender delay={delay}>
|
||||
<Screen layout={layout} header={header}>
|
||||
<Screen layout={layout} header={header} footer={footer}>
|
||||
<CenteredContent>
|
||||
<Center>
|
||||
<p>{t('loading')}</p>
|
||||
|
||||
@@ -21,7 +21,7 @@ export const QueryAware = ({
|
||||
}
|
||||
|
||||
if (status === 'pending') {
|
||||
return <LoadingScreen header={undefined} />
|
||||
return <LoadingScreen header={undefined} footer={undefined} />
|
||||
}
|
||||
|
||||
return children
|
||||
|
||||
@@ -15,6 +15,6 @@ export const UserAware = ({ children }: { children: React.ReactNode }) => {
|
||||
return isLoggedIn !== undefined ? (
|
||||
children
|
||||
) : (
|
||||
<LoadingScreen header={false} delay={1000} />
|
||||
<LoadingScreen header={false} footer={false} delay={1000} />
|
||||
)
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ export const Conference = ({
|
||||
|
||||
return (
|
||||
<QueryAware status={isFetchError ? createStatus : fetchStatus}>
|
||||
<Screen header={false}>
|
||||
<Screen header={false} footer={false}>
|
||||
<LiveKitRoom
|
||||
room={room}
|
||||
serverUrl={data?.livekit?.url}
|
||||
|
||||
276
src/frontend/src/layout/Footer.tsx
Normal file
276
src/frontend/src/layout/Footer.tsx
Normal file
@@ -0,0 +1,276 @@
|
||||
import { styled } from '@/styled-system/jsx'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { A } from '@/primitives'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
const StyledLi = styled('li', {
|
||||
base: {},
|
||||
variants: {
|
||||
divider: {
|
||||
true: {
|
||||
_after: {
|
||||
content: '""',
|
||||
display: 'inline-block',
|
||||
marginX: '.75rem',
|
||||
verticalAlign: 'middle',
|
||||
boxShadow: 'inset 0 0 0 1px #ddd',
|
||||
height: '1rem',
|
||||
width: '1px',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const InnerContainer = styled('div', {
|
||||
base: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'start',
|
||||
margin: 'auto',
|
||||
maxWidth: '1200px',
|
||||
paddingX: { base: '0.5rem', xs: '1rem', sm: '2rem' },
|
||||
},
|
||||
})
|
||||
|
||||
const MainLinkList = styled('ul', {
|
||||
base: {
|
||||
display: 'flex',
|
||||
gap: '0.5rem 1rem',
|
||||
flexWrap: 'wrap',
|
||||
flexBasis: { base: '100%', md: '50%' },
|
||||
},
|
||||
})
|
||||
|
||||
const FirstRow = styled('div', {
|
||||
base: {
|
||||
display: 'flex',
|
||||
gap: '2rem',
|
||||
flexWrap: { base: 'wrap', md: 'nowrap' },
|
||||
justifyContent: 'space-between',
|
||||
width: '100%',
|
||||
alignItems: 'flex-start',
|
||||
marginBottom: '1.5rem',
|
||||
},
|
||||
})
|
||||
|
||||
const SecondRow = styled('ul', {
|
||||
base: {
|
||||
display: 'flex',
|
||||
borderTop: '1px solid rgb(217 217 217)',
|
||||
paddingTop: '0.5rem',
|
||||
width: '100%',
|
||||
flexWrap: 'wrap',
|
||||
alignItems: 'center',
|
||||
},
|
||||
})
|
||||
|
||||
const ThirdRow = styled('p', {
|
||||
base: {
|
||||
fontSize: '0.75rem',
|
||||
color: 'rgb(77 77 77)',
|
||||
fontFamily: 'Marianne',
|
||||
textWrap: 'wrap',
|
||||
lineHeight: '1rem',
|
||||
marginTop: { base: '1rem', xs: '0.5rem' },
|
||||
},
|
||||
})
|
||||
|
||||
const Marianne = () => {
|
||||
return (
|
||||
<div
|
||||
className={css({
|
||||
_before: {
|
||||
content: '""',
|
||||
display: 'block',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundSize: 'contain',
|
||||
backgroundImage: 'url(/assets/marianne.svg)',
|
||||
height: '1.25rem',
|
||||
marginBottom: '.2rem',
|
||||
width: '3rem',
|
||||
},
|
||||
_after: {
|
||||
content: '""',
|
||||
display: 'block',
|
||||
backgroundImage: 'url(/assets/devise.svg)',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundSize: 'contain',
|
||||
height: '2.313rem',
|
||||
marginTop: '.2rem',
|
||||
width: '3.25rem',
|
||||
},
|
||||
})}
|
||||
>
|
||||
<p
|
||||
className={css({
|
||||
letterSpacing: '-.01em',
|
||||
textTransform: 'uppercase',
|
||||
fontWeight: '600',
|
||||
fontFamily: 'Marianne',
|
||||
fontSize: '1.25rem',
|
||||
lineHeight: '1.75rem',
|
||||
})}
|
||||
>
|
||||
gouvernement
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const Footer = () => {
|
||||
const { t } = useTranslation('global', { keyPrefix: 'footer' })
|
||||
|
||||
return (
|
||||
<footer
|
||||
className={css({
|
||||
borderTop: '2px solid rgb(0 0 145)',
|
||||
paddingY: '2rem',
|
||||
})}
|
||||
>
|
||||
<InnerContainer>
|
||||
<FirstRow>
|
||||
<div
|
||||
className={css({
|
||||
display: 'flex',
|
||||
paddingBottom: '1.5rem',
|
||||
paddingX: '1.5rem',
|
||||
alignItems: 'center',
|
||||
gap: '1.5rem',
|
||||
})}
|
||||
>
|
||||
<Marianne />
|
||||
<span
|
||||
className={css({
|
||||
height: '80px',
|
||||
backgroundColor: 'rgb(77 77 77)',
|
||||
width: '1px',
|
||||
display: { base: 'none', xs: 'block' },
|
||||
})}
|
||||
/>
|
||||
<p
|
||||
className={css({
|
||||
display: 'none',
|
||||
fontWeight: '700',
|
||||
fontFamily: 'Marianne',
|
||||
xs: {
|
||||
display: 'block',
|
||||
fontSize: '0.75rem',
|
||||
lineHeight: '1rem',
|
||||
},
|
||||
xsm: {
|
||||
display: 'block',
|
||||
fontSize: '1rem',
|
||||
lineHeight: '1.5rem',
|
||||
},
|
||||
})}
|
||||
>
|
||||
Direction
|
||||
<br />
|
||||
interministérielle
|
||||
<br />
|
||||
du numérique
|
||||
</p>
|
||||
</div>
|
||||
<MainLinkList>
|
||||
<li>
|
||||
<A
|
||||
externalIcon
|
||||
underline={false}
|
||||
footer="important"
|
||||
href="https://legifrance.gouv.fr"
|
||||
aria-label={
|
||||
t('links.legifrance') + ' - ' + t('links.ariaLabel')
|
||||
}
|
||||
>
|
||||
{t('links.legifrance')}
|
||||
</A>
|
||||
</li>
|
||||
<li>
|
||||
<A
|
||||
externalIcon
|
||||
underline={false}
|
||||
footer="important"
|
||||
href="https://info.gouv.fr"
|
||||
aria-label={t('links.infogouv') + ' - ' + t('links.ariaLabel')}
|
||||
>
|
||||
{t('links.infogouv')}
|
||||
</A>
|
||||
</li>
|
||||
<li>
|
||||
<A
|
||||
externalIcon
|
||||
underline={false}
|
||||
footer="important"
|
||||
href="https://www.service-public.fr/"
|
||||
aria-label={
|
||||
t('links.servicepublic') + ' - ' + t('links.ariaLabel')
|
||||
}
|
||||
>
|
||||
{t('links.servicepublic')}
|
||||
</A>
|
||||
</li>
|
||||
<li>
|
||||
<A
|
||||
externalIcon
|
||||
underline={false}
|
||||
footer="important"
|
||||
href="https://data.gouv.fr"
|
||||
aria-label={t('links.datagouv') + ' - ' + t('links.ariaLabel')}
|
||||
>
|
||||
{t('links.datagouv')}
|
||||
</A>
|
||||
</li>
|
||||
</MainLinkList>
|
||||
</FirstRow>
|
||||
<SecondRow>
|
||||
<StyledLi divider>
|
||||
<A
|
||||
externalIcon
|
||||
underline={false}
|
||||
footer="minor"
|
||||
href="https://docs.numerique.gouv.fr/docs/f88a2eb0-7ce7-4016-b6ee-9f1fd1771951/"
|
||||
aria-label={t('links.legalsTerms') + ' - ' + t('links.ariaLabel')}
|
||||
>
|
||||
{t('links.legalsTerms')}
|
||||
</A>
|
||||
</StyledLi>
|
||||
<StyledLi divider>
|
||||
<A
|
||||
externalIcon
|
||||
underline={false}
|
||||
footer="minor"
|
||||
href="https://docs.numerique.gouv.fr/docs/168d7e8e-3f09-462d-8bbc-ea95dedd3889/"
|
||||
aria-label={t('links.data') + ' - ' + t('links.ariaLabel')}
|
||||
>
|
||||
{t('links.data')}
|
||||
</A>
|
||||
</StyledLi>
|
||||
<StyledLi>
|
||||
<A
|
||||
externalIcon
|
||||
underline={false}
|
||||
footer="minor"
|
||||
href="https://docs.numerique.gouv.fr/docs/94bd1e3b-a44d-4cf5-b7ee-708a5386a111/"
|
||||
aria-label={
|
||||
t('links.accessibility') + ' - ' + t('links.ariaLabel')
|
||||
}
|
||||
>
|
||||
{t('links.accessibility')}
|
||||
</A>
|
||||
</StyledLi>
|
||||
</SecondRow>
|
||||
<ThirdRow>
|
||||
{t('mentions')}{' '}
|
||||
<A
|
||||
externalIcon
|
||||
footer="minor"
|
||||
href="https://github.com/etalab/licence-ouverte/blob/master/LO.md"
|
||||
>
|
||||
{t('license')}
|
||||
</A>
|
||||
</ThirdRow>
|
||||
</InnerContainer>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { css } from '@/styled-system/css'
|
||||
import { Header } from './Header'
|
||||
import { layoutStore } from '@/stores/layout'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { Footer } from '@/layout/Footer'
|
||||
|
||||
export type Layout = 'fullpage' | 'centered'
|
||||
|
||||
@@ -15,28 +16,33 @@ export type Layout = 'fullpage' | 'centered'
|
||||
export const Layout = ({ children }: { children: ReactNode }) => {
|
||||
const layoutSnap = useSnapshot(layoutStore)
|
||||
const showHeader = layoutSnap.showHeader
|
||||
const showFooter = layoutSnap.showFooter
|
||||
|
||||
return (
|
||||
<div
|
||||
className={css({
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
backgroundColor: 'white',
|
||||
color: 'default.text',
|
||||
})}
|
||||
>
|
||||
{showHeader && <Header />}
|
||||
<main
|
||||
<>
|
||||
<div
|
||||
className={css({
|
||||
flexGrow: 1,
|
||||
overflow: 'auto',
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
minHeight: 'fit-content',
|
||||
flexDirection: 'column',
|
||||
backgroundColor: 'white',
|
||||
color: 'default.text',
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
{showHeader && <Header />}
|
||||
<main
|
||||
className={css({
|
||||
flexGrow: 1,
|
||||
overflow: 'auto',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
{showFooter && <Footer />}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -13,18 +13,23 @@ export type ScreenProps = {
|
||||
* True by default. Pass undefined to render the screen without modifying current header visibility
|
||||
*/
|
||||
header?: boolean
|
||||
footer?: boolean
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
export const Screen = ({
|
||||
layout = 'fullpage',
|
||||
header = true,
|
||||
footer = true,
|
||||
children,
|
||||
}: ScreenProps) => {
|
||||
useEffect(() => {
|
||||
if (header !== undefined) {
|
||||
layoutStore.showHeader = header
|
||||
}
|
||||
}, [header])
|
||||
if (footer !== undefined) {
|
||||
layoutStore.showFooter = footer
|
||||
}
|
||||
}, [header, footer])
|
||||
return layout === 'centered' ? <Centered>{children}</Centered> : children
|
||||
}
|
||||
|
||||
@@ -24,5 +24,19 @@
|
||||
"notFound": {
|
||||
"heading": ""
|
||||
},
|
||||
"submit": "OK"
|
||||
"submit": "OK",
|
||||
"footer": {
|
||||
"links": {
|
||||
"legifrance": "",
|
||||
"infogouv": "",
|
||||
"servicepublic": "",
|
||||
"datagouv": "",
|
||||
"legalsTerms": "",
|
||||
"data": "",
|
||||
"accessibility": "",
|
||||
"ariaLabel": ""
|
||||
},
|
||||
"mentions": "",
|
||||
"license": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,5 +24,19 @@
|
||||
"notFound": {
|
||||
"heading": "Page not found"
|
||||
},
|
||||
"submit": "OK"
|
||||
"submit": "OK",
|
||||
"footer": {
|
||||
"links": {
|
||||
"legifrance": "legifrance.gouv.fr",
|
||||
"infogouv": "info.gouv.fr",
|
||||
"servicepublic": "service-public.fr",
|
||||
"datagouv": "data.gouv.fr",
|
||||
"legalsTerms": "Legal Notice",
|
||||
"data": "Personal Data and Cookies",
|
||||
"accessibility": "Accessibility: audit in progress",
|
||||
"ariaLabel": "new window"
|
||||
},
|
||||
"mentions": "Unless otherwise stated, the contents of this site are available under",
|
||||
"license": "etalab 2.0 license"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,5 +24,19 @@
|
||||
"notFound": {
|
||||
"heading": "Page introuvable"
|
||||
},
|
||||
"submit": "OK"
|
||||
"submit": "OK",
|
||||
"footer": {
|
||||
"links": {
|
||||
"legifrance": "legifrance.gouv.fr",
|
||||
"infogouv": "info.gouv.fr",
|
||||
"servicepublic": "service-public.fr",
|
||||
"datagouv": "data.gouv.fr",
|
||||
"legalsTerms": "Mentions légales",
|
||||
"data": "Données personnelles et cookie",
|
||||
"accessibility": "Accessibilités : audit en cours",
|
||||
"ariaLabel": "nouvelle fenêtre"
|
||||
},
|
||||
"mentions": "Sauf mention contraire, les contenus de ce site sont disponibles sous",
|
||||
"license": "licence etalab 2.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,36 @@ const link = cva({
|
||||
textStyle: 'sm',
|
||||
},
|
||||
},
|
||||
externalIcon: {
|
||||
true: {
|
||||
_after: {
|
||||
content: 'url(/assets/link-grey.svg)',
|
||||
verticalAlign: 'middle',
|
||||
paddingLeft: '.25rem',
|
||||
},
|
||||
},
|
||||
},
|
||||
underline: {
|
||||
false: {
|
||||
textDecoration: 'none',
|
||||
},
|
||||
},
|
||||
footer: {
|
||||
important: {
|
||||
fontSize: '0.8rem',
|
||||
lineHeight: '1rem',
|
||||
fontWeight: '700',
|
||||
fontFamily: 'Marianne',
|
||||
textWrap: 'nowrap',
|
||||
},
|
||||
minor: {
|
||||
fontSize: '0.75rem',
|
||||
color: 'rgb(77 77 77)',
|
||||
fontFamily: 'Marianne',
|
||||
textWrap: 'nowrap',
|
||||
lineHeight: '1rem',
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -29,6 +59,17 @@ export type AProps = LinkProps & RecipeVariantProps<typeof link>
|
||||
/**
|
||||
* anchor component styled with underline. Used mostly for external links. Use Link for internal links
|
||||
*/
|
||||
export const A = ({ size, ...props }: AProps) => {
|
||||
return <Link {...props} className={link({ size })} />
|
||||
export const A = ({
|
||||
size,
|
||||
externalIcon,
|
||||
underline,
|
||||
footer,
|
||||
...props
|
||||
}: AProps) => {
|
||||
return (
|
||||
<Link
|
||||
{...props}
|
||||
className={link({ size, externalIcon, underline, footer })}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@ import { PanelId } from '@/features/rooms/livekit/hooks/useSidePanel'
|
||||
|
||||
type State = {
|
||||
showHeader: boolean
|
||||
showFooter: boolean
|
||||
activePanelId: PanelId | null
|
||||
}
|
||||
|
||||
export const layoutStore = proxy<State>({
|
||||
showHeader: false,
|
||||
showFooter: false,
|
||||
activePanelId: null,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user