RELEASE V5.5.0 : Voici les modifications apportées :

-> REFONTE TOTALE DE TOUS LES AFFICHEURS CLASSIQUES + QUAIS

FONCTIONNALITÉS EN COURS DE DÉVELOPPEMENT :

-> ADAPTABILITÉ EN FONCTION DES SITUATIONS
This commit is contained in:
mathis committed 2026-08-31 02:02:46 +02:00
1 parent b90c699302
commit 9c6ac798f1
26 files changed
+3040 -2190

No files matched your search

@@ -0,0 +1,202 @@
.aff-attentifs__container {
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
user-select: none;
font-family: 'Achemine', 'Arial', sans-serif;
overflow: hidden;
box-sizing: border-box;
}
/* COLONNE GAUCHE (36%) */
.aff-attentifs__left-col {
flex: 0 0 36%;
background-color: #313131;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 70px 50px;
box-sizing: border-box;
}
.aff-attentifs__title-group {
display: flex;
flex-direction: column;
gap: 12px;
}
.aff-attentifs__title-word {
font-size: 78px;
font-weight: 900;
color: #fdb913;
letter-spacing: 2px;
line-height: 1.05;
text-transform: uppercase;
}
.aff-attentifs__vigipirate-wrap {
display: flex;
align-items: center;
justify-content: flex-start;
margin-top: auto;
}
.aff-attentifs__vigipirate-svg {
width: 270px;
height: auto;
filter: drop-shadow(0 8px 18px rgba(0, 0, 0, 0.45));
}
/* COLONNE DROITE (64%) */
.aff-attentifs__right-col {
flex: 1;
background-color: #4a4a4a;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 60px 80px;
box-sizing: border-box;
gap: 40px;
}
.aff-attentifs__info-section {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
color: #ffffff;
}
.aff-attentifs__info-desc {
font-size: 27px;
font-weight: 500;
line-height: 1.4;
margin: 0 0 36px 0;
color: #f8f8f8;
}
.aff-attentifs__call-action {
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 30px;
}
.aff-attentifs__call-text {
font-size: 44px;
font-weight: 900;
letter-spacing: 0.5px;
color: #ffffff;
}
.aff-attentifs__call-hours {
font-size: 30px;
font-weight: 600;
color: #eaeaea;
}
.aff-attentifs__call-footnote {
font-size: 19px;
font-weight: 400;
color: #d0d0d0;
}
/* SECTION BULLE D'ALERTE 3117 */
.aff-attentifs__bubble-section {
flex: 0 0 460px;
display: flex;
align-items: center;
justify-content: center;
}
.aff-attentifs__bubble-wrap {
position: relative;
display: flex;
align-items: center;
}
.aff-attentifs__bubble-card {
position: relative;
background-color: #ffffff;
border: 7px solid #e2001a;
border-radius: 36px;
padding: 30px 42px;
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: 14px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
min-width: 360px;
}
.aff-attentifs__bubble-title {
font-size: 28px;
font-weight: 900;
color: #e2001a;
letter-spacing: 1px;
}
.aff-attentifs__bubble-rows {
display: flex;
flex-direction: column;
gap: 8px;
}
.aff-attentifs__bubble-line {
display: flex;
align-items: baseline;
gap: 14px;
}
.aff-attentifs__bubble-label {
font-size: 30px;
font-weight: 800;
color: #e2001a;
min-width: 70px;
}
.aff-attentifs__bubble-number {
font-size: 58px;
font-weight: 900;
color: #e2001a;
letter-spacing: -1px;
}
.aff-attentifs__bubble-tail {
position: absolute;
bottom: -32px;
left: 54px;
width: 0;
height: 0;
border-left: 20px solid transparent;
border-right: 20px solid transparent;
border-top: 32px solid #e2001a;
}
.aff-attentifs__bubble-tail::after {
content: '';
position: absolute;
top: -38px;
left: -13px;
width: 0;
height: 0;
border-left: 13px solid transparent;
border-right: 13px solid transparent;
border-top: 24px solid #ffffff;
}
/* SMARTPHONE BADGE */
.aff-attentifs__phone-badge {
position: absolute;
top: -34px;
right: -36px;
z-index: 10;
filter: drop-shadow(0 8px 16px rgba(0, 0, 0, 0.4));
}
.aff-attentifs__phone-svg {
width: 86px;
height: auto;
}
@@ -0,0 +1,112 @@
import React from 'react';
import './AttentifsEnsemble.css';
export default function AttentifsEnsemble() {
return (
<div className="aff-attentifs__container">
{/* COLONNE GAUCHE : ANTHRACITE FONCÉ (ATTENTIFS ENSEMBLE + VIGIPIRATE) */}
<div className="aff-attentifs__left-col">
<div className="aff-attentifs__title-group">
<div className="aff-attentifs__title-word">ATTENTIFS</div>
<div className="aff-attentifs__title-word">ENSEMBLE</div>
</div>
{/* Insigne Vigipirate Officiel */}
<div className="aff-attentifs__vigipirate-wrap">
<svg
viewBox="0 0 280 240"
className="aff-attentifs__vigipirate-svg"
xmlns="http://www.w3.org/2000/svg"
>
{/* Triangle noir extérieur */}
<polygon points="140,12 268,228 12,228" fill="#1e1e1e" stroke="#1e1e1e" strokeWidth="8" strokeLinejoin="round" />
{/* Triangle rouge intérieur */}
<polygon points="140,42 238,206 42,206" fill="#e2001a" />
{/* Bandeau blanc en bas */}
<polygon points="56,182 224,182 238,206 42,206" fill="#ffffff" />
{/* Texte VIGIPIRATE */}
<text
x="140"
y="201"
fill="#1e1e1e"
fontSize="23"
fontWeight="900"
fontFamily="Achemine, Arial, sans-serif"
textAnchor="middle"
letterSpacing="2.5"
>
VIGIPIRATE
</text>
</svg>
</div>
</div>
{/* COLONNE DROITE : GRIS MOYEN (CONSIGNES + BULLE ALERTE 3117) */}
<div className="aff-attentifs__right-col">
{/* Partie gauche des consignes */}
<div className="aff-attentifs__info-section">
<p className="aff-attentifs__info-desc">
Si vous êtes témoin<br />
d'une situation<br />
qui présente un risque<br />
pour votre sécurité<br />
ou celle des autres<br />
voyageurs,
</p>
<div className="aff-attentifs__call-action">
<span className="aff-attentifs__call-text">APPELER* LE 3117</span>
<span className="aff-attentifs__call-hours">24h/24 · 7j/7</span>
</div>
<div className="aff-attentifs__call-footnote">
* Appel non surtaxé et enregistré
</div>
</div>
{/* Partie droite avec la bulle Alerte SNCF 3117 et le smartphone */}
<div className="aff-attentifs__bubble-section">
<div className="aff-attentifs__bubble-wrap">
{/* Bulle blanche à bordure rouge */}
<div className="aff-attentifs__bubble-card">
<div className="aff-attentifs__bubble-title">ALERTE SNCF</div>
<div className="aff-attentifs__bubble-rows">
<div className="aff-attentifs__bubble-line">
<span className="aff-attentifs__bubble-label">TÉL.</span>
<span className="aff-attentifs__bubble-number">3117*</span>
</div>
<div className="aff-attentifs__bubble-line">
<span className="aff-attentifs__bubble-label">SMS</span>
<span className="aff-attentifs__bubble-number">31177**</span>
</div>
</div>
{/* Pointe de la bulle */}
<div className="aff-attentifs__bubble-tail" />
</div>
{/* Smartphone Rouge d'alerte */}
<div className="aff-attentifs__phone-badge">
<svg viewBox="0 0 68 104" className="aff-attentifs__phone-svg" fill="none" xmlns="http://www.w3.org/2000/svg">
{/* Corps de téléphone rouge arrondi */}
<rect x="4" y="4" width="60" height="96" rx="14" fill="#e2001a" stroke="#ffffff" strokeWidth="4.5" />
{/* Écran blanc */}
<rect x="12" y="14" width="44" height="50" rx="6" fill="#ffffff" />
{/* Point d'exclamation rouge d'urgence */}
<rect x="30.5" y="24" width="7" height="20" rx="3.5" fill="#e2001a" />
<circle cx="34" cy="53" r="4" fill="#e2001a" />
{/* Touches du pavé numérique */}
<circle cx="20" cy="74" r="3" fill="#ffffff" />
<circle cx="34" cy="74" r="3" fill="#ffffff" />
<circle cx="48" cy="74" r="3" fill="#ffffff" />
<circle cx="20" cy="85" r="3" fill="#ffffff" />
<circle cx="34" cy="85" r="3" fill="#ffffff" />
<circle cx="48" cy="85" r="3" fill="#ffffff" />
</svg>
</div>
</div>
</div>
</div>
</div>
);
}
@@ -0,0 +1,90 @@
.aff-dep-afl__container {
width: 100%;
height: 100%;
background-color: #d61e38;
color: #ffffff;
display: flex;
flex-direction: column;
user-select: none;
font-family: 'Achemine', 'Arial', sans-serif;
overflow: hidden;
box-sizing: border-box;
}
/* FRISSE SUPÉRIEURE RAYÉE */
.aff-dep-afl__hazard-stripes {
width: 100%;
height: 48px;
background: repeating-linear-gradient(
-45deg,
#ffffff,
#ffffff 28px,
#d61e38 28px,
#d61e38 56px
);
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.25);
flex-shrink: 0;
}
/* CONTENU PRINCIPAL */
.aff-dep-afl__content {
flex: 1;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 40px 100px;
gap: 120px;
box-sizing: border-box;
}
.aff-dep-afl__icon-col {
flex: 0 0 460px;
display: flex;
align-items: center;
justify-content: center;
}
.aff-dep-afl__no-entry-svg {
width: 100%;
max-width: 440px;
height: auto;
filter: drop-shadow(0 10px 24px rgba(0, 0, 0, 0.35));
}
.aff-dep-afl__text-col {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
gap: 48px;
}
.aff-dep-afl__heading-group {
display: flex;
flex-direction: column;
line-height: 1.02;
}
.aff-dep-afl__title-main,
.aff-dep-afl__title-sub {
font-size: 102px;
font-weight: 900;
letter-spacing: 2px;
color: #ffffff;
text-transform: uppercase;
}
.aff-dep-afl__instructions {
display: flex;
flex-direction: column;
gap: 8px;
}
.aff-dep-afl__instruction-line {
font-size: 48px;
font-weight: 600;
line-height: 1.35;
color: #ffffff;
margin: 0;
}
@@ -0,0 +1,63 @@
import React from 'react';
import './DepartEnCoursAFL.css';
export default function DepartEnCoursAFL() {
return (
<div className="aff-dep-afl__container">
{/* RUBAN SUPÉRIEUR RAYÉ BLANC ET ROUGE */}
<div className="aff-dep-afl__hazard-stripes" />
{/* CONTENU PRINCIPAL */}
<div className="aff-dep-afl__content">
{/* Panneau d'interdiction blanc à gauche */}
<div className="aff-dep-afl__icon-col">
<svg
viewBox="0 0 240 240"
className="aff-dep-afl__no-entry-svg"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
{/* Cercle blanc extérieur */}
<circle cx="120" cy="120" r="105" stroke="#ffffff" strokeWidth="18" />
{/* Silhouette du piéton marchant avec valise */}
<g fill="#ffffff">
{/* Tête */}
<circle cx="126" cy="62" r="15" />
{/* Corps marchant */}
<path d="M116 84 C116 84, 134 84, 138 98 L152 144 L140 148 L128 110 L118 132 L112 186 L98 184 L106 126 L96 112 Z" />
{/* Jambe droite enjambant */}
<path d="M122 134 L138 180 C138 180, 146 186, 140 190 C134 194, 126 188, 126 188 L114 148 Z" />
{/* Bras gauche */}
<path d="M128 88 L146 114 L138 120 L122 96 Z" />
{/* Bras droit tenant la valise */}
<path d="M116 86 L98 116 L88 110" stroke="#ffffff" strokeWidth="8" strokeLinecap="round" strokeLinejoin="round" fill="none" />
{/* Valise inclinée */}
<g transform="rotate(-15, 80, 140)">
<rect x="58" y="122" width="38" height="52" rx="7" fill="#ffffff" />
<path d="M70 122 V112 H84 V122" stroke="#ffffff" strokeWidth="6" fill="none" />
</g>
</g>
{/* Barre diagonale blanche d'interdiction */}
<line x1="46" y1="46" x2="194" y2="194" stroke="#ffffff" strokeWidth="18" strokeLinecap="round" />
</svg>
</div>
{/* Textes d'alerte et de consigne à droite */}
<div className="aff-dep-afl__text-col">
<div className="aff-dep-afl__heading-group">
<div className="aff-dep-afl__title-main">DÉPARTS</div>
<div className="aff-dep-afl__title-sub">EN COURS</div>
</div>
<div className="aff-dep-afl__instructions">
<p className="aff-dep-afl__instruction-line">Pour votre sécurité</p>
<p className="aff-dep-afl__instruction-line">merci de vous éloigner</p>
<p className="aff-dep-afl__instruction-line">de la bordure du quai.</p>
</div>
</div>
</div>
</div>
);
}
@@ -0,0 +1,75 @@
.aff-dep-classique__container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
user-select: none;
font-family: 'Achemine', 'Arial', sans-serif;
overflow: hidden;
box-sizing: border-box;
}
/* ZONE DU HAUT : GRIS FONCÉ (~72%) */
.aff-dep-classique__top {
flex: 1;
background-color: #222226;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 160px;
padding: 40px 100px;
box-sizing: border-box;
}
.aff-dep-classique__prohibition-sign {
display: flex;
align-items: center;
justify-content: center;
}
.aff-dep-classique__no-entry-svg {
width: 480px;
height: 480px;
filter: drop-shadow(0 12px 28px rgba(0, 0, 0, 0.45));
}
.aff-dep-classique__train-wrap {
display: flex;
align-items: center;
justify-content: center;
}
.aff-dep-classique__train-gif {
width: 480px;
height: auto;
max-height: 480px;
object-fit: contain;
filter: drop-shadow(0 12px 28px rgba(0, 0, 0, 0.45));
}
.aff-dep-classique__train-svg {
width: 460px;
height: 460px;
filter: drop-shadow(0 12px 28px rgba(0, 0, 0, 0.45));
}
/* BANDEAU ROUGE INFÉRIEUR (~28%) */
.aff-dep-classique__bottom {
flex: 0 0 280px;
background-color: #d0102a;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.35);
}
.aff-dep-classique__banner-text {
font-size: 110px;
font-weight: 900;
color: #ffffff;
margin: 0;
letter-spacing: 1px;
text-align: center;
}
@@ -0,0 +1,81 @@
import React, { useState } from 'react';
import './DepartEnCoursClassique.css';
const GIF_URL = 'https://cdn.discordapp.com/attachments/1265325000290992258/1282018214720835725/SNCF_-_Depart_Train.gif?ex=6a95af01&is=6a945d81&hm=14570f1423217cb52437d767b3125a698ac5955fc088028fbc3d24d820e9a76b&';
export default function DepartEnCoursClassique() {
const [gifError, setGifError] = useState(false);
return (
<div className="aff-dep-classique__container">
{/* ZONE SUPÉRIEURE : PICTOS (FOND GRIS FONCÉ) */}
<div className="aff-dep-classique__top">
{/* Panneau d'interdiction : Ne pas monter (voyageur avec valise barré) */}
<div className="aff-dep-classique__prohibition-sign">
<svg viewBox="0 0 200 200" className="aff-dep-classique__no-entry-svg" xmlns="http://www.w3.org/2000/svg">
{/* Fond blanc du cercle */}
<circle cx="100" cy="100" r="90" fill="#ffffff" stroke="#d0102a" strokeWidth="18" />
{/* Silhouette du voyageur avec valise */}
<g fill="#141416">
{/* Tête */}
<circle cx="92" cy="52" r="14" />
{/* Corps */}
<rect x="76" y="70" width="32" height="52" rx="10" />
{/* Jambe gauche */}
<rect x="80" y="118" width="10" height="38" rx="5" />
{/* Jambe droite */}
<rect x="94" y="118" width="10" height="38" rx="5" />
{/* Bras gauche */}
<rect x="66" y="72" width="9" height="36" rx="4.5" />
{/* Bras droit tenant la poignée */}
<path d="M106 74 L120 102 L120 114" stroke="#141416" strokeWidth="8" strokeLinecap="round" strokeLinejoin="round" fill="none" />
{/* Poignée télescopique de valise */}
<path d="M116 102 V116 H124 V102" stroke="#141416" strokeWidth="4" fill="none" />
{/* Valise à roulettes */}
<rect x="110" y="116" width="24" height="38" rx="4" fill="#141416" />
{/* Roulettes */}
<circle cx="114" cy="156" r="3" fill="#141416" />
<circle cx="130" cy="156" r="3" fill="#141416" />
</g>
{/* Barre diagonale rouge d'interdiction */}
<line x1="36" y1="36" x2="164" y2="164" stroke="#d0102a" strokeWidth="18" strokeLinecap="round" />
</svg>
</div>
{/* Animation du train au départ (GIF ou SVG de secours) */}
<div className="aff-dep-classique__train-wrap">
{!gifError ? (
<img
src={GIF_URL}
alt="Train au départ"
className="aff-dep-classique__train-gif"
onError={() => setGifError(true)}
/>
) : (
<svg viewBox="0 0 240 240" className="aff-dep-classique__train-svg" fill="none" xmlns="http://www.w3.org/2000/svg">
{/* Rails et traverses */}
<path d="M40 200 L95 140 M200 200 L145 140" stroke="#ffffff" strokeWidth="8" strokeLinecap="round" />
<line x1="60" y1="185" x2="180" y2="185" stroke="#ffffff" strokeWidth="8" strokeLinecap="round" />
<line x1="85" y1="160" x2="155" y2="160" stroke="#ffffff" strokeWidth="6" strokeLinecap="round" />
{/* Face avant du train */}
<rect x="55" y="40" width="130" height="110" rx="35" fill="#ffffff" />
{/* Pare-brise */}
<rect x="68" y="52" width="104" height="42" rx="14" fill="#1c1c20" />
{/* Phares rouges */}
<circle cx="82" cy="120" r="10" fill="#d0102a" />
<circle cx="158" cy="120" r="10" fill="#d0102a" />
</svg>
)}
</div>
</div>
{/* BANDEAU INFÉRIEUR ROUGE : DÉPART EN COURS */}
<div className="aff-dep-classique__bottom">
<h1 className="aff-dep-classique__banner-text">Départ en cours</h1>
</div>
</div>
);
}
@@ -0,0 +1,78 @@
.aff-videoprot__container {
width: 100%;
height: 100%;
background-color: #141416;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
padding: 40px 80px;
box-sizing: border-box;
font-family: 'Achemine', 'Arial', sans-serif;
user-select: none;
}
.aff-videoprot__wrapper {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 80px;
width: 100%;
max-width: 1600px;
}
.aff-videoprot__icon-col {
flex: 0 0 420px;
display: flex;
align-items: center;
justify-content: center;
}
.aff-videoprot__camera-svg {
width: 100%;
max-width: 420px;
height: auto;
filter: drop-shadow(0 6px 16px rgba(242, 91, 42, 0.25));
}
.aff-videoprot__text-col {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
.aff-videoprot__title-vigi {
font-size: 52px;
font-weight: 800;
color: #f25b2a;
letter-spacing: 1.5px;
margin-bottom: 24px;
text-transform: uppercase;
}
.aff-videoprot__main-heading {
font-size: 46px;
font-weight: 800;
color: #ffffff;
line-height: 1.28;
letter-spacing: 0.5px;
margin: 0 0 54px 0;
text-transform: uppercase;
}
.aff-videoprot__subtext-group {
display: flex;
flex-direction: column;
gap: 16px;
}
.aff-videoprot__legal-line,
.aff-videoprot__access-line {
font-size: 26px;
font-weight: 600;
line-height: 1.45;
color: #f0f0f0;
margin: 0;
}
@@ -0,0 +1,68 @@
import React from 'react';
import './GareVideoprotection.css';
export default function GareVideoprotection() {
return (
<div className="aff-videoprot__container">
<div className="aff-videoprot__wrapper">
{/* Caméra de surveillance stylisée orange */}
<div className="aff-videoprot__icon-col">
<svg
viewBox="0 0 320 240"
className="aff-videoprot__camera-svg"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
{/* Support mural */}
<rect x="20" y="105" width="22" height="75" rx="5" fill="#f25b2a" />
<path
d="M38 132 H80 L95 105 H125"
stroke="#f25b2a"
strokeWidth="20"
strokeLinecap="round"
strokeLinejoin="round"
/>
{/* Corps de la caméra orienté vers le bas à droite */}
<g transform="rotate(18, 140, 110)">
{/* Corps principal */}
<rect x="35" y="55" width="165" height="70" rx="14" fill="#f25b2a" />
{/* Parasoleil / Visière supérieure */}
<path d="M30 48 L210 48 L195 58 L30 58 Z" fill="#f25b2a" />
{/* Cône avant / Objectif */}
<polygon points="198,62 250,38 250,142 198,118" fill="#f25b2a" />
{/* Fentes d'aération & détails noirs */}
<circle cx="65" cy="88" r="10" fill="#141416" />
<rect x="95" y="78" width="10" height="26" rx="4" fill="#141416" />
<rect x="120" y="78" width="10" height="26" rx="4" fill="#141416" />
<rect x="145" y="78" width="10" height="26" rx="4" fill="#141416" />
{/* Bague optique */}
<rect x="250" y="44" width="14" height="92" rx="3" fill="#f25b2a" />
</g>
</svg>
</div>
{/* Textes d'information et réglementaires */}
<div className="aff-videoprot__text-col">
<div className="aff-videoprot__title-vigi">VIGI360</div>
<h1 className="aff-videoprot__main-heading">
POUR VOTRE SÉCURITÉ, CET ESPACE<br />
EST ÉQUIPÉ DE VIDÉOPROTECTION.
</h1>
<div className="aff-videoprot__subtext-group">
<p className="aff-videoprot__legal-line">
En application des dispositions des textes législatifs et<br />
règlementaires en vigueur.
</p>
<p className="aff-videoprot__access-line">
Pour l'exercice du droit d'accès au enregistrements,<br />
s'adresser à un agent d'accueil de la gare.
</p>
</div>
</div>
</div>
</div>
);
}