Import repositories from gitlab

This commit is contained in:
Julien Aldon
2026-01-19 11:43:59 +01:00
commit 68b7405c52
131 changed files with 17192 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
import { BlocksRenderer } from "@strapi/blocks-react-renderer";
import Button from "../button";
import styles from "./style.module.scss";
export default function ArticleBlock({title, content, link, className, ...props}) {
return (
<article {...props} className={`${styles.articleBlock} ${className ?? ''}`}>
<h4>{title}</h4>
{content ? <BlocksRenderer content={content}/> : null}
<Button
type="secondary"
as="a"
href={link}
target="_blank"
>
Lire la suite
</Button>
</article>
);
}

View File

@@ -0,0 +1,17 @@
.articleBlock {
display: flex;
flex-direction: column;
h4 {
margin: 1rem 0;
}
p {
margin: 0;
}
a {
margin-top: 1rem;
align-self: flex-end;
}
}

View File

@@ -0,0 +1,28 @@
import styles from './style.module.scss';
export default function Button({as, type, children, ...props}) {
switch (as ?? 'a') {
case 'a':
return (
<a
tabIndex="0"
{...props}
className={`${styles[type ?? 'secondary']} ${styles.button} not-a-link ${props.className}`}
>
{children}
</a>
);
case 'button':
return (
<button
tabIndex="0"
{...props}
className={`${styles[type ?? 'secondary']} ${styles.button} not-a-link ${props.className}`}
>
{children}
</button>
);
}
return (null);
}

View File

@@ -0,0 +1,47 @@
.button {
appearance: none;
font-size: unset;
background: unset;
font-family: unset;
display: inline-block;
padding: 1.25rem 1.5rem;
border-radius: 2.25rem;
text-decoration: none;
transition: all 0.2s ease;
margin: 0.5rem;
}
.secondary {
color: unset;
border: solid 1px var(--fg-2);
&:hover, &:focus {
background: var(--fg-3);
border: solid 1px var(--fg-3);
box-shadow: 0 0.25rem 0.35rem rgba(0, 0, 0, 0.45);
}
&:visited {
color: unset;
}
}
.primary {
color: white;
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.25);
text-decoration-color: transparent;
background: linear-gradient(175deg, var(--fefan-1) 0%, var(--fefan-1) 45%, var(--fefan-2) 55%, var(--fefan-3) 70%, var(--fefan-4) 85%);
background-size: 250% 100%;
transition: all ease var(--transition-time);
&:hover, &:focus {
text-decoration-color: var(--fefan-1);
background-position-x: 100%;
box-shadow: 0 0.25rem 0.35rem rgba(0, 0, 0, 0.45);
}
&:visited {
color: white;
}
}

View File

@@ -0,0 +1,32 @@
import ImageBlock from "@/components/imageBlock";
import StatBlock from "@/components/statBlock";
import VideoBlock from "@/components/videoBlock";
import styles from './style.module.scss';
export default async function EditionBlock({type, ...props}) {
switch (type) {
case 'stat':
return (
<article className={styles.editionBlock}>
<StatBlock {...props} />
</article>
);
case 'image':
return (
<article className={styles.editionBlock}>
<ImageBlock {...props} src={props.value} alt={props.title}/>
</article>
);
case 'video':
return (
<article className={styles.editionBlock}>
<VideoBlock {...props} src={props.value} title={props.title}/>
</article>
);
}
return null;
}

View File

@@ -0,0 +1,3 @@
.editionBlock {
overflow: hidden;
}

View File

@@ -0,0 +1,31 @@
import ImageBlock from '../imageBlock';
import EditionBlock from './editionBlock';
import styles from './style.module.scss';
export default async function EditionElement(props) {
return (
<section className={`${styles.editionSection} ${props.full ? styles.fullViewport : ''}`}>
{props.href ?
(
<a className={styles.image} href={props.href}>
<img src={props.flyerImg} alt={props.flyerAlt}/>
</a>
) : (
<ImageBlock className={styles.image} alt={props.flyerAlt} src={props.flyerImg} />
)
}
{props.blocks.slice(0, 6).map(block => (
<EditionBlock {...block} key={`${block.type}-${block.id}`} href={props.href} />
))}
{props.full ? <aside className={styles.callToAction}>
<a href={props.href}>
<h2>{props.title}</h2>
<svg width="40px" height="40px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 12H18M18 12L13 7M18 12L13 17" stroke="var(--fefan-1)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
</a>
</aside> : null}
</section>
);
}

View File

@@ -0,0 +1,157 @@
.editionSection {
--cell-width: 14.25rem;
display: grid;
scroll-snap-align: center;
flex: none;
grid-template-columns: repeat(4, max-content);
grid-template-rows: repeat(2, max-content);
align-content: center;
justify-content: center;
&.fullViewport {
min-height: calc(2 * var(--cell-width) + 10rem + 4 * var(--border-width));
height: calc(100vh - 2 * var(--border-width) - 5rem - 2rem);
}
.image {
display: block;
grid-row: span 2;
margin: 0.5rem;
img {
display: block;
height: calc(2 * var(--cell-width) + 1rem + 4 * var(--border-width));
}
}
img.image {
display: block;
height: calc(2 * var(--cell-width) + 1rem + 4 * var(--border-width));
}
article {
border: solid 1px var(--fg-2);
width: var(--cell-width);
height: var(--cell-width);
justify-content: center;
display: flex;
align-items: center;
object-fit: fill;
margin: 0.5rem;
}
.callToAction {
grid-row: 3;
grid-column: span 4;
justify-content: flex-end;
display: flex;
align-items: center;
& > a {
justify-content: flex-end;
display: flex;
align-items: center;
}
}
}
.informations {
color: var(--fg-0);
display: flex;
flex-flow: column;
margin-left: 1rem;
text-decoration: none;
h2 {
font-family: var(--font-details);
margin: -0.5rem 0px;
font-size: 2rem;
font-weight: 400;
}
h3 {
margin: 0px;
font-size: 0.75rem;
opacity: 0.75;
font-weight: 700;
text-transform: uppercase;
}
}
@media only screen and (max-width: 70rem) {
.editionSection {
grid-template-columns: repeat(3, max-content);
.callToAction {
grid-column: span 3;
}
article:nth-of-type(n+5) {
display: none;
}
}
}
@media only screen and (max-width: 60rem) {
.editionSection {
grid-template-columns: repeat(2, max-content);
.callToAction {
grid-column: span 2;
}
article:nth-of-type(n+3) {
display: none;
}
}
}
@media only screen and (max-width: 40rem) and (min-width: 30rem) {
.editionSection {
grid-template-columns: repeat(1, max-content);
.callToAction {
grid-column: span 1;
}
article {
display: none;
}
}
}
@media only screen and (max-width: 30rem) {
.editionSection {
--cell-width: calc(50vw - 5rem);
grid-template-columns: repeat(2, max-content);
grid-template-rows: repeat(5, max-content);
&.fullViewport {
height: calc(3.5 * var(--cell-width) + 10rem + 4 * var(--border-width));
min-height: calc(100vh - 2 * var(--border-width) - 4rem - 2rem);
}
.image {
grid-row: 1;
grid-column: span 2;
img {
height: auto;
width: calc(2 * var(--cell-width) + 1rem + 4 * var(--border-width));
}
}
img.image {
height: auto;
width: calc(2 * var(--cell-width) + 1rem + 4 * var(--border-width));
}
.callToAction {
grid-row: 5;
grid-column: span 2;
}
article:nth-of-type(n+3) {
display: none;
}
}
}

View File

@@ -0,0 +1,17 @@
import ImageBlock from "../imageBlock";
import styles from "./style.module.scss";
export default function EditionGallery({ images }) {
return (
<section className={styles.gallery}>
{images.map(({ id, attributes: attr }) => (
<div className={styles.galleryImage} key={id}>
<ImageBlock
alt={attr.alternativeText}
src={`${process.env.NEXT_PUBLIC_IMG_URI}${attr.url}`}
/>
</div>
))}
</section>
);
}

View File

@@ -0,0 +1,34 @@
.gallery {
--gallery-width: 80rem;
--gallery-columns: 3;
grid-template-columns: repeat(var(--gallery-columns), calc(var(--gallery-width) / var(--gallery-columns)));
grid-auto-rows: max-content;
align-items: center;
justify-items: center;
display: grid;
}
.galleryImage {
grid-column: span 1;
margin: 0.5rem;
max-height: calc(((6.5 / 10) * (var(--gallery-width) / var(--gallery-columns))) - 1rem);
overflow: hidden;
& > img {
width: calc((var(--gallery-width) / var(--gallery-columns)) - 1rem);
}
}
@media only screen and (max-width: 80rem) {
.gallery {
--gallery-width: 90vw;
--gallery-columns: 2;
}
}
@media only screen and (max-width: 50rem) {
.gallery {
--gallery-width: 90vw;
--gallery-columns: 1;
}
}

View File

@@ -0,0 +1,63 @@
'use client';
import qs from 'qs';
import { useEffect, useState } from "react";
import Button from "../button";
import styles from "./style.module.scss";
function fetchEmail(query) {
const queryString = qs.stringify(query);
return fetch(`${process.env.NEXT_PUBLIC_CONTENT_URI}/site?${queryString}`).then((data) => data.json());
}
export default function Email() {
const [email, setEmail] = useState("");
const [displayEmail, setDisplayEmail] = useState(false);
const [copied, setCopied] = useState(false);
const toggleEmail = () => {
if (email === "") {
fetchEmail({
fields: ['contact_mail']
}).then((res) => {
setEmail(res.data.attributes.contact_mail);
setDisplayEmail(true)
})
return;
} else if (displayEmail === false) {
setDisplayEmail(true)
} else {
navigator.clipboard.writeText(email);
setCopied(true);
}
}
useEffect(() => {
setTimeout(() => {
setDisplayEmail(false);
}, 5000);
}, [displayEmail])
useEffect(() => {
setTimeout(() => {
setCopied(false);
}, 2000);
}, [copied])
return (
<Button
as="button"
type="secondary"
onClick={toggleEmail}
className={styles.emailButton}
title={displayEmail ? "Cliquez pour copier le mail" : null}
>
<label className={displayEmail ? styles.copy : null}>
{displayEmail ? email : "Cliquez pour afficher le mail"}
</label>
<label className={copied ? styles.showLabel : styles.hideLabel}>
{copied ? "copié" : null}
</label>
</Button>
);
}

View File

@@ -0,0 +1,20 @@
.emailButton {
display: flex;
flex-direction: column;
label {
transition: all ease-in-out var(--transition-time);
}
}
.copy {
cursor: copy;
}
.showLabel {
opacity: 1;
}
.hideLabel {
opacity: 0;
}

View File

@@ -0,0 +1,15 @@
import Button from "../button";
import styles from "./style.module.scss";
export default function Empty({message, ...props}) {
return <section className={styles.empty}>
<h2 {...props}>{message ?? "Il n'y a rien ici."}</h2>
<Button
as="a"
type="secondary"
href="/"
>
Retour à la page d&apos;accueil
</Button>
</section>
}

View File

@@ -0,0 +1,9 @@
.empty {
display: flex;
flex-direction: column;
align-items: center;
h2 {
font-family: var(--font-details);
}
}

View File

@@ -0,0 +1,10 @@
import styles from './style.module.scss';
export default async function Fanfare(props) {
return (
<div className={styles.band}>
<h4>{props.name}</h4>
<h5>{props.location}</h5>
</div>
);
}

View File

@@ -0,0 +1,22 @@
.band {
padding: 0.75rem 0.25rem;
max-width: 30vw;
h4, h5 {
margin: 0px;
}
h4 {
font-family: var(--font-body);
font-weight: 500;
margin: 0px;
font-size: 1rem;
text-decoration: none;
}
h5 {
font-size: 0.75rem;
opacity: 0.75;
font-weight: 700;
text-transform: uppercase;
}
}

View File

@@ -0,0 +1,14 @@
import Link from "next/link";
import styles from "./style.module.scss";
export default async function Footer() {
return (
<footer className={styles.footer}>
<Link href="/legal">Mentions légales</Link>
<span className={styles.separator}> · </span>
<Link href="/sponsor">Ils nous soutiennent</Link>
<span className={styles.separator}> · </span>
<Link href="/contact">Contact</Link>
</footer>
);
}

View File

@@ -0,0 +1,13 @@
.footer {
border-top: var(--fg-3) solid var(--border-width);
text-align: center;
padding: 0.25rem;
span {
white-space: nowrap;
}
a {
}
}

View File

@@ -0,0 +1,34 @@
import getData from '@/api';
import NavigationDrawer from './navigationDrawer';
export default async function Header() {
const site = await getData('site', {
populate: {
edition: {
fields: [],
populate: {
programs: {
fields: ['type', 'title'],
}
}
}
}
});
const editionId = site.data?.attributes.edition.data?.id;
const programs = editionId ? site.data.attributes.edition.data.attributes.programs.data : null
const socialLinkQuery = editionId ? {
filters: {
$or: [
{ edition: { id: { $null: true } } },
{ edition: { id: { $eq: editionId } } },
]
}
} : {
filters: { edition: { id: { $null: true } } },
}
const socialLinks = await getData('social-links', socialLinkQuery)
const links = socialLinks.data ?? []
return (
<NavigationDrawer programs={programs} links={links}/>
);
}

View File

@@ -0,0 +1,46 @@
"use client";
import Link from "next/link";
import SocialIcon from "../social-icon";
import { useState } from "react";
import styles from "./style.module.scss";
export default function NavigationDrawer({programs, links , ...props}) {
const [isOpen, setIsOpen] = useState(false);
const toggleDrawer = () => {
setIsOpen(prev => !prev);
}
return (
<header className={`${styles.header} ${isOpen ? styles.drawerOpen : ""}`}>
<div className={`${styles.backdrop}`} onClick={toggleDrawer}/>
<button className={`${styles.social} ${styles.burgerIcon}`} onClick={toggleDrawer}>
<svg className={`feather feather-menu`} xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="#1B519E" strokeWidth="1" strokeLinecap="round" strokeLinejoin="round"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
</button>
<Link href="/" className={`not-a-link ${styles.logo}`}>
<img src="/fefan.png" alt="Fefan" />
<h1>Festival de fanfare</h1>
</Link>
<a className={`${styles.social} ${styles.programIcon}`} href="/prog/city-wide">
<svg className={`feather feather-calendar`} xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="#1B519E" strokeWidth="1" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line></svg>
</a>
<nav className={`${styles.navigation}`}>
<div className={styles.spacer} />
<Link href="/">Accueil</Link>
{programs ? programs.map(({ id, attributes: attr }) => (
<Link href={`/prog/${attr.type}`} key={id}>{attr.title}</Link>
)): null}
<Link href="/editions">Éditions précédentes</Link>
<Link href="/contact">Contact</Link>
<div className={styles.spacer} />
<nav className={styles.socialLinks}>
{links.map(({ id, attributes: attr }) => (
<Link aria-label={attr.type} target="_blank" href={attr.uri} key={id} className={`${styles.social} not-a-link`}>
<SocialIcon name={attr.type} />
</Link>
))}
</nav>
</nav>
</header>
);
}

View File

@@ -0,0 +1,156 @@
.header {
display: flex;
position: fixed;
left: 0;
right: 0;
top: 0;
z-index: 200;
flex-flow: row;
border-bottom: var(--fg-3) solid var(--border-width);
background: var(--bg-0);
}
.header + * {
margin-top: calc(5rem + var(--border-width));
}
.logo {
display: flex;
margin: 0.5rem 1rem;
flex-flow: column;
text-decoration: none;
text-align: right;
color: var(--fefan-4);
h1 {
font-family: var(--font-details);
font-weight: 500;
font-size: 0.75rem;
margin: -0.10rem 0.35rem;
}
img:first-child {
height: 3rem;
}
}
.social {
appearance: none;
border: none;
background: unset;
font-size: unset;
margin: 0;
border-radius: 100%;
padding: 0.5rem;
text-decoration: none;
color: var(--fefan-1);
display: flex;
align-self: center;
justify-content: center;
box-shadow: inset 0 0 6px 3px var(--background);
transition: all 0.2s ease;
}
.spacer {
flex: 1;
}
.spacer:first-of-type {
display: none;
}
.navigation {
display: flex;
align-items: center;
flex: 1;
a {
margin: 0 0.35rem;
}
.socialLinks {
align-items: center;
display: flex;
margin-right: 1rem;
justify-content: flex-end;
}
}
.backdrop {
position: fixed;
content: '';
top: 0;
left: 0;
right: 0;
bottom: 100vh;
z-index: 250;
background: rgba(0, 0, 0, 0);
transition: background-color 0.2s ease;
}
.burgerIcon {
display: none;
align-self: center;
cursor: pointer;
}
.drawerOpen .navigation {
left: 0%;
}
.drawerOpen .backdrop {
bottom: 0vh;
background: rgba(0, 0, 0, 0.25);
}
.programIcon {
display: none;
}
@media only screen and (max-width: 992px) {
.header {
justify-content: space-between;
padding: 0 1.5rem;
}
.burgerIcon {
display: block;
}
.programIcon {
display: block;
}
.navigation {
padding: 1rem 0;
flex-flow: column;
position: fixed;
z-index: 300;
align-items: stretch;
top: 0;
max-width: 80vw;
width: 20rem;
left: -100%;
bottom: 0;
background: var(--bg-0);
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.25);
transition: all 0.2s ease;
a {
padding: 0.5rem;
text-align: left;
}
.spacer:first-of-type {
display: block;
}
.socialLinks {
justify-content: space-around;
}
}
.drawerOpen {
left: 0%;
}
}

View File

@@ -0,0 +1,38 @@
export default function SocialIcon(props) {
if (props.name === 'youtube')
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="36" height="36" viewBox="0 0 24 24"
fill="none" stroke="currentColor"
strokeWidth="1" strokeLinecap="round" strokeLinejoin="round"
>
<path d="M22.54 6.42a2.78 2.78 0 0 0-1.94-2C18.88 4 12 4 12 4s-6.88 0-8.6.46a2.78 2.78 0 0 0-1.94 2A29 29 0 0 0 1 11.75a29 29 0 0 0 .46 5.33A2.78 2.78 0 0 0 3.4 19c1.72.46 8.6.46 8.6.46s6.88 0 8.6-.46a2.78 2.78 0 0 0 1.94-2 29 29 0 0 0 .46-5.25 29 29 0 0 0-.46-5.33z" />
<polygon points="9.75 15.02 15.5 11.75 9.75 8.48 9.75 15.02" />
</svg>
);
else if (props.name === 'instagram')
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="36" height="36" viewBox="0 0 24 24"
fill="none" stroke="currentColor"
strokeWidth="1" strokeLinecap="round" strokeLinejoin="round"
>
<rect x="2" y="2" width="20" height="20" rx="5" ry="5" />
<path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z" />
<line x1="17.5" y1="6.5" x2="17.51" y2="6.5" />
</svg>
);
else if (props.name === 'facebook')
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="36" height="36" viewBox="0 0 24 24"
fill="none" stroke="currentColor"
strokeWidth="1" strokeLinecap="round" strokeLinejoin="round"
>
<path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z" />
</svg>
);
}

View File

View File

@@ -0,0 +1,33 @@
'use client';
import { useState } from 'react';
import styles from './style.module.scss';
import ImagePopup from '../imagePopup';
export default function ImageBlock({alt, src, ...props}) {
const [showPopup, setShowPopup] = useState(false);
const toggleShowPopup = () => {
setShowPopup(prev => !prev);
}
return (
<>
<img
{...props}
onClick={toggleShowPopup}
src={src}
alt={alt}
className={`${styles.imageBlock} ${props.className}`}
/>
{
showPopup ?
<ImagePopup
toggleShowPopup={toggleShowPopup}
alt={alt}
src={src}
/>
: null
}
</>
);
}

View File

@@ -0,0 +1,4 @@
.imageBlock {
cursor: pointer;
max-height: 100%;
}

View File

@@ -0,0 +1,32 @@
import styles from './style.module.scss';
export default function ImagePopup({toggleShowPopup, src, alt, ...props}) {
return (
<div className={styles.modal}>
<button onClick={toggleShowPopup} className={styles.close}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="36"
height="36"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="1"
strokeLinecap="round"
strokeLinejoin="round"
className="feather feather-x"
>
<line x1="18" y1="6" x2="6" y2="18" />
<line x1="6" y1="6" x2="18" y2="18" />
</svg>
</button>
<div onClick={toggleShowPopup} className={styles.imgModal} />
<img
{...props}
src={src}
alt={alt}
className={styles.popupImage}
/>
</div>
);
}

View File

@@ -0,0 +1,92 @@
.modal {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: 220;
display: flex;
align-items: center;
overflow: scroll;
overscroll-behavior: contain;
cursor: pointer;
& > div {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: var(--fg-0);
opacity: 0.65;
z-index: 220;
}
}
.popupImage {
margin: auto;
display: block;
max-width: 80vw;
max-height: 80vh;
animation-name: zoom;
animation-duration: 0.6s;
animation-fill-mode: both;
z-index: 230;
cursor: auto;
}
.close {
position: fixed;
display: flex;
align-items: center;
justify-content: center;
top: 3.6rem;
right: 4rem;
height: 3rem;
width: 3rem;
padding: 0.25rem;
appearance: none;
border: unset;
font-size: unset;
font-family: unset;
color: var(--bg-0);
background: var(--fg-0-translucid);
font-weight: bold;
transition: 0.3s;
cursor: pointer;
border-radius: 100%;
z-index: 230;
svg {
height: 3rem;
width: 3rem;
}
}
.close:hover {
top: 3.2rem;
right: 3.6rem;
height: 3.8rem;
width: 3.8rem;
svg {
height: 3.8rem;
width: 3.8rem;
}
}
@keyframes zoom {
from {
transform:scale(0);
box-shadow: 0 0 0.2rem rgba(0,0,0,0.5);
}
to {
transform:scale(1);
box-shadow: 0 0 1rem rgba(0,0,0,0.5);
}
}

View File

@@ -0,0 +1,25 @@
import ArticleBlock from "../articleBlock";
import ImageBlock from "../imageBlock";
import styles from "./style.module.scss";
export default function PressBlock({
left: {type: leftType, ...left},
right: {type: rightType, ...right},
...props
}) {
return (
<section {...props} className={styles.pressBlock}>
{
leftType ? leftType === 'article' ?
<ArticleBlock {...left} className={styles.pressArticle}/> :
<ImageBlock {...left} className={styles.pressImage}/> : null
}
{
rightType ? rightType === 'article' ?
<ArticleBlock {...right} className={styles.pressArticle}/> :
<ImageBlock {...right} className={styles.pressImage}/> : null
}
</section>
);
}

View File

@@ -0,0 +1,36 @@
.pressBlock {
--element-width: 30vw;
display: flex;
.pressArticle, .pressImage {
width: var(--element-width);
margin: 1rem;
}
.pressImage {
align-self: center;
}
&:nth-of-type(2n+1) {
flex-flow: row-reverse;
}
}
@media only screen and (max-width: 80rem) {
.pressBlock {
--element-width: 45vw;
.pressImage {
width: calc(var(--element-width) - 10vw);
}
}
}
@media only screen and (max-width: 60rem) {
.pressBlock {
--element-width: 90vw;
&, &:nth-child(2n) {
flex-flow: column;
}
}
}

View File

@@ -0,0 +1,10 @@
import styles from './style.module.scss';
export default async function StatBlock(props) {
return (
<a href={props.href} className={styles.statBox}>
<span>{props.value}</span>
<h3>{props.title}</h3>
</a>
);
}

View File

@@ -0,0 +1,33 @@
.statBox {
width: 100%;
justify-content: center;
align-items: center;
text-align: center;
display: flex;
flex-direction: column;
text-decoration: none;
transition: none;
&:hover {
text-decoration: none;
}
span {
font-size: 4rem;
color: var(--fg-0);
}
h3 {
padding: 0px;
margin: 0px;
color: var(--fg-1);
}
}
@media only screen and (max-width: 30rem) {
.statBox {
span {
font-size: 2.2rem;
}
}
}

View File

@@ -0,0 +1,23 @@
import { BlocksRenderer } from '@strapi/blocks-react-renderer';
import styles from './style.module.scss';
export default async function TimeSlot(props) {
const date_begin = new Date(props.start)
const date_end = new Date(props.end)
const date_format = new Intl.DateTimeFormat('fr', {
weekday: 'long',
month: "long",
day: "numeric"
}).format(date_begin)
return (
<article className={styles.timeSlot}>
<h4>
{date_format} - {date_begin.getHours()}h
{date_begin.getMinutes() !== 0 ? date_begin.getMinutes() : ""} à&nbsp;
{date_end.getHours()}h{date_end.getMinutes() !== 0 ? date_end.getMinutes() : ""}
</h4>
<BlocksRenderer content={props.content}/>
</article>
);
}

View File

@@ -0,0 +1,17 @@
.timeSlot {
h4::first-letter {
text-transform: capitalize;
}
h4 {
font-family: var(--font-details);
margin: 0px;
font-size: 1.5rem;
font-weight: 400;
color: var(--fefan-3);
}
margin-bottom: 2rem;
padding-right: 1rem;
padding-left: 1rem;
}

View File

@@ -0,0 +1,15 @@
import styles from "./style.module.scss";
export default async function VideoBlock(props) {
return (
<iframe
className={`${props.className} ${styles.videoBlock}`}
width={ props.mode ==='thumbnail' ? "220" : "560" }
height={props.mode ==='thumbnail' ? "220" : "315"}
src={props.src}
title={props.title}
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowFullScreen
/>
);
}

View File

@@ -0,0 +1,3 @@
.videoBlock {
max-width: 90vw;
}