V1.1.0 //

-> Refonte du design de sélection d'afficheurs
-> Ajout du Mode PiP
-> Patch du bug du logo de l'horaire pas affiché. Corrigé pour les Horaires TER à 6 numéros.
This commit is contained in:
AdminGit committed 2026-10-07 15:32:21 +02:00
1 parent c30a0e9002
commit 6cc1e1820d
14 files changed
+1143 -849

No files matched your search

+63 -87
View File
@@ -1,5 +1,5 @@
import React from 'react';
import WcsButton from '../components/WcsButton';
import { WcsCard, WcsCardBody, WcsButton, WcsBadge, WcsHorizontalStepper } from 'wcs-react';
import sessionMemory from '../lib/sessionMemory';
import { getSourceFromPath } from '../services/railwayService';
@@ -21,6 +21,7 @@ export default function Displays({ onBack, navigate }) {
id: 'classiques',
label: 'Classiques',
sublabel: 'Téléaffichage Historique',
sublabel: 'Téléaffichage Historique',
tag: 'Rétro / Vintage',
tagType: 'retro',
icon: '📺',
@@ -33,7 +34,7 @@ export default function Displays({ onBack, navigate }) {
tag: 'Gares Connectées',
tagType: 'modern',
icon: '📱',
desc: 'Écrans d\'information enrichis avec multimédia, infogare et dessertes complètes.'
desc: "Écrans d'information enrichis avec multimédia, infogare et dessertes complètes."
},
{
id: 'transilien',
@@ -46,8 +47,7 @@ export default function Displays({ onBack, navigate }) {
}
];
// Nettoyage du chemin pour extraire la gare même avec /ferrovia
const cleanPath = (typeof window !== 'undefined' ? window.location.pathname : '').replace(/^\/ferrovia/, '');
const cleanPath = (typeof window !== 'undefined' ? window.location.pathname : '').replace(/ferrovia/, '');
const parts = cleanPath.split('/').filter(Boolean);
const typeIds = types.map(t => t.id);
let gare = null;
@@ -63,14 +63,13 @@ export default function Displays({ onBack, navigate }) {
const g = paramsForGare.get('gare');
if (g) {
try {
gare = decodeURIComponent(String(g).replace(/\+/g, ' ')).replace(/-/g, ' ');
gare = decodeURIComponent(String(g).replace(/\\+/g, ' ')).replace(/-/g, ' ');
} catch (e) {
gare = String(g).replace(/-/g, ' ');
}
}
}
// Déterminer le mode (departs/arrivees)
const params = new URLSearchParams(window.location.search || '');
let mode = params.get('mode');
if (!mode) {
@@ -83,96 +82,73 @@ export default function Displays({ onBack, navigate }) {
const formattedGareName = gare ? gare.replace(/-/g, ' ') : 'Non sélectionnée';
const steps = [
{ text: formattedGareName, button: { kind: 'Icon', iconName: 'check' }, complete: true },
{ text: "Type d'afficheur", button: { kind: 'Text', text: '2' }, complete: false },
{ text: 'Options & Affichage', button: { kind: 'Text', text: '3' }, disable: true }
];
return (
<div className="launcher-container">
{/* Stepper */}
<div className="launcher-stepper">
<div className="launcher-step launcher-step--completed">
<span className="launcher-step-num">✓</span>
<span>{formattedGareName}</span>
</div>
<span className="launcher-step-separator">›</span>
<div className="launcher-step launcher-step--active">
<span className="launcher-step-num">2</span>
<span>Type d'afficheur</span>
</div>
<span className="launcher-step-separator">›</span>
<div className="launcher-step">
<span className="launcher-step-num">3</span>
<span>Options & Affichage</span>
</div>
</div>
<div style={{ maxWidth: '900px', margin: '0 auto', padding: '24px', overflowY: 'auto', maxHeight: 'calc(100vh - 120px)' }}>
<WcsHorizontalStepper steps={steps} currentStep={1} style={{ marginBottom: '24px' }} />
<div className="launcher-card">
{/* Header */}
<div className="launcher-header">
<div>
<h1 className="launcher-title">Sélectionnez le style d'afficheur</h1>
<p className="launcher-subtitle">
Gare : <strong style={{ color: '#002257' }}>{formattedGareName}</strong> • Mode : <strong style={{ color: '#00439e' }}>{mode === 'arrivees' ? '🏁 Arrivées' : '🚆 Départs'}</strong>
</p>
</div>
<span className={`launcher-badge ${source === 'supabase' ? 'launcher-badge--supabase' : ''}`}>
{source === 'supabase' ? '🗄️ BDD Ferrovia' : '🌐 SNCF GTFS'}
</span>
</div>
{/* Grille de sélection tactile des styles d'afficheurs */}
<div className="launcher-grid launcher-grid--4col">
{types.map((t) => (
<div
key={t.id}
className="launcher-select-card"
role="button"
tabIndex={0}
onClick={() => {
if (typeof navigate === 'function') {
const kebab = gare ? String(gare).trim().replace(/\s+/g, '-').replace(/\//g, '/') : '';
navigate(`${prefix}/select-afficheur?gare=${encodeURIComponent(kebab)}&mode=${mode}&type=${t.id}`);
}
}}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
const kebab = gare ? String(gare).trim().replace(/\s+/g, '-').replace(/\//g, '/') : '';
navigate(`${prefix}/select-afficheur?gare=${encodeURIComponent(kebab)}&mode=${mode}&type=${t.id}`);
}
}}
>
<div>
<span className="launcher-card-icon">{t.icon}</span>
<span className={`launcher-card-tag ${t.tagType === 'retro' ? 'launcher-card-tag--retro' : 'launcher-card-tag--modern'}`}>
{t.tag}
</span>
<h2 className="launcher-card-title">{t.label}</h2>
<div style={{ fontSize: '13px', fontWeight: 600, color: '#00439e', marginBottom: '8px' }}>{t.sublabel}</div>
<p className="launcher-card-desc">{t.desc}</p>
</div>
<div style={{ marginTop: 12 }}>
<span className="launcher-btn launcher-btn--secondary" style={{ padding: '8px 12px', fontSize: '14px' }}>
Choisir ce style ›
</span>
</div>
<WcsCard mode="raised">
<WcsCardBody>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: '24px' }}>
<div>
<h1 style={{ margin: '0 0 8px 0', fontSize: '24px', color: 'var(--wcs-primary)' }}>Sélectionnez le style d'afficheur</h1>
<p style={{ margin: 0, color: 'var(--wcs-text-light)' }}>
Gare : <strong>{formattedGareName}</strong> • Mode : <strong>{mode === 'arrivees' ? '🏁 Arrivées' : '🚆 Départs'}</strong>
</p>
</div>
))}
</div>
<WcsBadge className={source === 'supabase' ? 'wcs-secondary' : 'wcs-primary'} shape="rounded">
{source === 'supabase' ? '🗄️ BDD Ferrovia' : '🌐 SNCF GTFS'}
</WcsBadge>
</div>
{/* Navigation retour */}
<div className="launcher-footer-nav">
<WcsButton
mode="plain"
onClick={() => {
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))', gap: '16px', marginBottom: '24px' }}>
{types.map((t) => (
<WcsCard
key={t.id}
mode="flat"
style={{ cursor: 'pointer', border: '1px solid var(--wcs-light)' }}
onClick={() => {
if (typeof navigate === 'function') {
const kebab = gare ? String(gare).trim().replace(/\\s+/g, '-').replace(/\\/g, '/') : '';
navigate(`${prefix}/select-afficheur?gare=${encodeURIComponent(kebab)}&mode=${mode}&type=${t.id}`);
}
}}
>
<WcsCardBody style={{ padding: '16px', display: 'flex', flexDirection: 'column', height: '100%' }}>
<div style={{ marginBottom: '12px' }}>
<span style={{ fontSize: '32px', marginRight: '8px' }}>{t.icon}</span>
<WcsBadge className={t.tagType === 'retro' ? 'wcs-secondary' : 'wcs-success'}>{t.tag}</WcsBadge>
</div>
<h2 style={{ fontSize: '18px', margin: '0 0 4px 0', color: 'var(--wcs-primary)' }}>{t.label}</h2>
<div style={{ fontSize: '13px', fontWeight: 'bold', color: 'var(--wcs-primary)', marginBottom: '8px' }}>{t.sublabel}</div>
<p style={{ fontSize: '14px', color: 'var(--wcs-text-light)', flexGrow: 1, marginBottom: '16px' }}>{t.desc}</p>
<WcsButton className="wcs-secondary" style={{ width: '100%', marginTop: 'auto' }}>
Choisir ce style
</WcsButton>
</WcsCardBody>
</WcsCard>
))}
</div>
<div style={{ borderTop: '1px solid var(--wcs-light)', paddingTop: '16px' }}>
<WcsButton mode="clear" onClick={() => {
if (typeof onBack === 'function') {
onBack();
} else if (navigate) {
navigate(`${prefix}/${mode}`);
}
}}
label="← Changer de gare"
/>
</div>
</div>
}}>
← Changer de gare
</WcsButton>
</div>
</WcsCardBody>
</WcsCard>
</div>
);
}