RELEASE V5.6.0 : Voici les modifications apportées :
-> REFONTE TOTALE DE TOUS LES AFFICHEURS CLASSIQUES + QUAIS + OPTION TGV FONCTIONNALITÉS EN COURS DE DÉVELOPPEMENT : -> ADAPTABILITÉ EN FONCTION DES SITUATIONS
This commit is contained in:
1 parent
9c6ac798f1
commit
d8f8ceaa9f
18 files changed
+2324
-533
No files matched your search
@@ -0,0 +1,298 @@
|
||||
/* =========================================================
|
||||
BANDEAU COMPOSITION TGV (SNCF QUAI - Conforme Image 1 & 2)
|
||||
========================================================= */
|
||||
|
||||
.aff-tgv-comp__container {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 1920px;
|
||||
height: 240px;
|
||||
background-color: #4a0e4e; /* Couleur Prune / Aubergine SNCF authentique */
|
||||
color: #ffffff;
|
||||
font-family: 'Achemine', 'Avenir', 'Helvetica Neue', Arial, sans-serif;
|
||||
box-sizing: border-box;
|
||||
padding: 10px 35px 8px 35px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
z-index: 25;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
TOP ROW : BOX VOIE + RAMES TGV
|
||||
========================================================= */
|
||||
.aff-tgv-comp__top-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 135px;
|
||||
}
|
||||
|
||||
/* Box Voie à gauche */
|
||||
.aff-tgv-comp__track-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 120px;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.aff-tgv-comp__track-pill {
|
||||
background-color: #ffffff;
|
||||
color: #4a0e4e;
|
||||
font-size: 19px;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
padding: 2px 14px;
|
||||
border-radius: 12px;
|
||||
line-height: 1.1;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.aff-tgv-comp__track-letter {
|
||||
color: #ffffff;
|
||||
font-size: 64px;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.aff-tgv-comp__track-underline {
|
||||
width: 65px;
|
||||
height: 3.5px;
|
||||
background-color: #ffffff;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* Conteneur des rames TGV */
|
||||
.aff-tgv-comp__rames-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 40px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Bloc d'une Rame */
|
||||
.aff-tgv-comp__rame-block {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Titre Destination au-dessus de la rame (jaune doré) */
|
||||
.aff-tgv-comp__dest-title {
|
||||
color: #f5d130;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
line-height: 1.1;
|
||||
margin-bottom: 6px;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Ligne des numéros de voitures */
|
||||
.aff-tgv-comp__coaches-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.aff-tgv-comp__coach-num-motrice {
|
||||
width: 44px;
|
||||
min-width: 44px;
|
||||
}
|
||||
|
||||
.aff-tgv-comp__coach-num-box {
|
||||
flex: 1;
|
||||
min-width: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #ffffff;
|
||||
font-size: 19px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
/* Graphic de la rame TGV */
|
||||
.aff-tgv-comp__train-graphic {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 32px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Motrice avant */
|
||||
.aff-tgv-comp__loco-front {
|
||||
width: 44px;
|
||||
height: 30px;
|
||||
background: linear-gradient(180deg, #813988 0%, #5d1d64 100%);
|
||||
border-top-left-radius: 16px;
|
||||
border-bottom-left-radius: 12px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
/* Corps des voitures */
|
||||
.aff-tgv-comp__coaches-body {
|
||||
display: flex;
|
||||
height: 30px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.aff-tgv-comp__coach-segment {
|
||||
flex: 1;
|
||||
min-width: 44px;
|
||||
height: 30px;
|
||||
background-color: #b776bd;
|
||||
border-right: 2px solid #ffffff;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.aff-tgv-comp__coach-segment:first-child {
|
||||
border-top-left-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
|
||||
.aff-tgv-comp__coach-segment:last-child {
|
||||
border-right: none;
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
|
||||
.aff-tgv-comp__coach-segment--bar {
|
||||
background-color: #c98cd0;
|
||||
}
|
||||
|
||||
/* Motrice arrière */
|
||||
.aff-tgv-comp__loco-rear {
|
||||
width: 44px;
|
||||
height: 30px;
|
||||
background: linear-gradient(180deg, #813988 0%, #5d1d64 100%);
|
||||
border-top-right-radius: 16px;
|
||||
border-bottom-right-radius: 12px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
LIGNE POINTILLÉE AVEC REPÈRES DE QUAI (Conforme Image 2)
|
||||
========================================================= */
|
||||
.aff-tgv-comp__reperes-line-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 2px 0 4px 0;
|
||||
}
|
||||
|
||||
.aff-tgv-comp__dotted-line {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
border-bottom: 2.5px dotted #f5d130;
|
||||
transform: translateY(-50%);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.aff-tgv-comp__reperes-row {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 36px;
|
||||
width: 100%;
|
||||
padding-right: 40px;
|
||||
box-sizing: border-box;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.aff-tgv-comp__repere-box {
|
||||
background-color: #00337f;
|
||||
border: 1.5px solid #ffffff;
|
||||
border-radius: 4px;
|
||||
color: #ffffff;
|
||||
font-weight: 800;
|
||||
font-size: 21px;
|
||||
line-height: 1;
|
||||
width: 32px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
BOTTOM ROW : MARQUEE + DIGITAL CLOCK
|
||||
========================================================= */
|
||||
.aff-tgv-comp__bottom-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 52px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.aff-tgv-comp__marquee-wrapper {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
.aff-tgv-comp__marquee-text {
|
||||
display: inline-block;
|
||||
color: #ffffff;
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-size: 29px;
|
||||
letter-spacing: 1px;
|
||||
text-transform: uppercase;
|
||||
animation: affTgvMarquee 25s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes affTgvMarquee {
|
||||
0% {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
}
|
||||
|
||||
/* Horloge TGV */
|
||||
.aff-tgv-comp__clock-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.aff-tgv-comp__clock {
|
||||
background-color: #00337f;
|
||||
border: 2px solid #ffffff;
|
||||
border-radius: 4px;
|
||||
padding: 3px 14px;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 4px;
|
||||
font-family: 'Achemine', 'Helvetica Neue', Arial, sans-serif;
|
||||
font-size: 34px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.aff-tgv-comp__clock-hm {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.aff-tgv-comp__clock-s {
|
||||
color: #f5a623;
|
||||
margin-left: 2px;
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import './TgvCompositionQuai.css';
|
||||
|
||||
/**
|
||||
* Icône Bar / Coupe de verre
|
||||
*/
|
||||
function BarGlassIcon({ size = 20, color = '#ffffff' }) {
|
||||
return (
|
||||
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 4L12 14L20 4H4Z" stroke={color} strokeWidth="2.2" strokeLinejoin="round" fill={color} />
|
||||
<path d="M12 14V21M8 21H16" stroke={color} strokeWidth="2.2" strokeLinecap="round" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Horloge digitale avec secondes (conformité Image 1 & 2)
|
||||
*/
|
||||
function TgvDigitalClock() {
|
||||
const [now, setNow] = useState(new Date());
|
||||
useEffect(() => {
|
||||
const id = setInterval(() => setNow(new Date()), 1000);
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
const hh = String(now.getHours()).padStart(2, '0');
|
||||
const mm = String(now.getMinutes()).padStart(2, '0');
|
||||
const ss = String(now.getSeconds()).padStart(2, '0');
|
||||
return (
|
||||
<div className="aff-tgv-comp__clock">
|
||||
<span className="aff-tgv-comp__clock-hm">{hh}:{mm}</span>
|
||||
<span className="aff-tgv-comp__clock-s">{ss}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dessin d'une rame TGV de 8 voitures avec motrice avant, arrière et voiture Bar en position 4
|
||||
*/
|
||||
function TgvRameShape({ destination, coaches = ['01', '02', '03', 'bar', '05', '06', '07', '08'] }) {
|
||||
return (
|
||||
<div className="aff-tgv-comp__rame-block">
|
||||
{destination && (
|
||||
<div className="aff-tgv-comp__dest-title">
|
||||
{destination}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Numéros des voitures */}
|
||||
<div className="aff-tgv-comp__coaches-row">
|
||||
{/* Espace motrice avant */}
|
||||
<div className="aff-tgv-comp__coach-num-motrice" />
|
||||
|
||||
{coaches.map((c, idx) => (
|
||||
<div key={idx} className="aff-tgv-comp__coach-num-box">
|
||||
{c === 'bar' ? (
|
||||
<BarGlassIcon size={20} color="#ffffff" />
|
||||
) : (
|
||||
<span>{c}</span>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Espace motrice arrière */}
|
||||
<div className="aff-tgv-comp__coach-num-motrice" />
|
||||
</div>
|
||||
|
||||
{/* Silhouette du train TGV */}
|
||||
<div className="aff-tgv-comp__train-graphic">
|
||||
{/* Motrice avant arrondie */}
|
||||
<div className="aff-tgv-comp__loco-front" />
|
||||
|
||||
{/* Voitures 1 à 8 */}
|
||||
<div className="aff-tgv-comp__coaches-body">
|
||||
{coaches.map((c, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className={`aff-tgv-comp__coach-segment ${c === 'bar' ? 'aff-tgv-comp__coach-segment--bar' : ''}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Motrice arrière arrondie */}
|
||||
<div className="aff-tgv-comp__loco-rear" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function TgvCompositionQuai({
|
||||
platform = '',
|
||||
destination = '',
|
||||
destination2 = '',
|
||||
marqueeMessage = '',
|
||||
composition = null,
|
||||
reperes = ['R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
|
||||
}) {
|
||||
const cleanTrack = String(platform || '').replace(/^(?:voie|quai|track|platform)\s*/i, '').trim();
|
||||
|
||||
// Détermination des tranches (Rame 1 et Rame 2)
|
||||
const isMultiDest = Boolean(destination2 && destination2.trim() !== '' && destination2.toLowerCase() !== destination.toLowerCase());
|
||||
|
||||
const rame1Coaches = (composition && composition.rame1) || ['01', '02', '03', 'bar', '05', '06', '07', '08'];
|
||||
const rame2Coaches = (composition && composition.rame2) || ['11', '12', '13', 'bar', '15', '16', '17', '18'];
|
||||
|
||||
const defaultMarquee = marqueeMessage || 'MERCI DE VOTRE COMPRÉHENSION..........................................................................................';
|
||||
|
||||
return (
|
||||
<div className="aff-tgv-comp__container">
|
||||
{/* LIGNE DU HAUT : BOX VOIE + VISUALISATION DU TRAIN */}
|
||||
<div className="aff-tgv-comp__top-row">
|
||||
{/* Indicateur Voie à gauche */}
|
||||
<div className="aff-tgv-comp__track-box">
|
||||
<div className="aff-tgv-comp__track-pill">Voie</div>
|
||||
<div className="aff-tgv-comp__track-letter">{cleanTrack ? cleanTrack.toUpperCase() : '-'}</div>
|
||||
<div className="aff-tgv-comp__track-underline" />
|
||||
</div>
|
||||
|
||||
{/* Visualisation Composition des Rames */}
|
||||
<div className="aff-tgv-comp__rames-container">
|
||||
<TgvRameShape
|
||||
destination={destination}
|
||||
coaches={rame1Coaches}
|
||||
/>
|
||||
<TgvRameShape
|
||||
destination={isMultiDest ? destination2 : destination}
|
||||
coaches={rame2Coaches}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* LIGNE POINTILLÉE AVEC REPÈRES DE QUAI (Conforme Image 2) */}
|
||||
<div className="aff-tgv-comp__reperes-line-wrapper">
|
||||
<div className="aff-tgv-comp__dotted-line" />
|
||||
{reperes && reperes.length > 0 && (
|
||||
<div className="aff-tgv-comp__reperes-row">
|
||||
{reperes.map((rep, idx) => (
|
||||
<div key={idx} className="aff-tgv-comp__repere-box">
|
||||
{rep}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* LIGNE DU BAS : DÉFILEMENT MESSAGE + HORLOGE */}
|
||||
<div className="aff-tgv-comp__bottom-row">
|
||||
<div className="aff-tgv-comp__marquee-wrapper">
|
||||
<div className="aff-tgv-comp__marquee-text">
|
||||
{defaultMarquee}
|
||||
</div>
|
||||
</div>
|
||||
<div className="aff-tgv-comp__clock-wrapper">
|
||||
<TgvDigitalClock />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user