RELEASE V5.0.0 : Voici les modifications apportées :
-> IMPLÉMENTATION DONNÉES GTFS / GTFS-RT / SIRI LTE SNCF -> RESTRUCTURATION DE L'APP. FONCTIONNALITÉS EN COURS DE DÉVELOPPEMENT : -> REFONTE DU DESIGN DES AFFICHEURS CLASSIQUES -> AMÉLIORATION DES
This commit is contained in:
1 parent
0e0d8c435f
commit
72de543dc6
18 files changed
+1550
-544
No files matched your search
+106
-77
@@ -8,8 +8,7 @@ import Displays from './pages/Displays';
|
||||
import ClassiquesDeparts from './pages/afficheurs/classiques/ClassiquesDeparts';
|
||||
import ClassiquesArrivees from './pages/afficheurs/classiques/ClassiquesArrivees';
|
||||
import ClassiquesDepartsQuais from './pages/afficheurs/classiques/quais/ClassiquesDepartsQuais';
|
||||
import sessionMemory from './lib/sessionMemory';
|
||||
import ClassiquesArriveesQuais from "./pages/afficheurs/classiques/quais/ClassiquesArriveesQuais";
|
||||
import ClassiquesArriveesQuais from './pages/afficheurs/classiques/quais/ClassiquesArriveesQuais';
|
||||
import AFLDeparts from './pages/afficheurs/afl/AFLDeparts';
|
||||
import AFLArrivees from './pages/afficheurs/afl/AFLArrivees';
|
||||
import AFLDepartsQuais from './pages/afficheurs/afl/AFLDepartsQuais';
|
||||
@@ -18,19 +17,19 @@ import EVAArrivees from './pages/afficheurs/eva/EVAArrivees';
|
||||
import EVADeparts from './pages/afficheurs/eva/EVADeparts';
|
||||
import SelectAfficheur from './pages/SelectAfficheur';
|
||||
import AfficheurViewportWrapper from './components/AfficheurViewportWrapper';
|
||||
import sessionMemory from './lib/sessionMemory';
|
||||
import { getSourceFromPath } from './services/railwayService';
|
||||
|
||||
applyPolyfills().then(() => defineCustomElements(window));
|
||||
|
||||
// Petit routeur client sans dépendances externes
|
||||
function useSimpleRouter() {
|
||||
function normalizePath(p) {
|
||||
if (!p) return '/';
|
||||
// retirer query string et hash pour normaliser le chemin utilisé en internal route
|
||||
// retirer query string et hash
|
||||
p = String(p).split(/[?#]/)[0];
|
||||
// traiter les cas comme /index.html
|
||||
if (p.indexOf('index.html') !== -1) return '/';
|
||||
// supprimer espaces en début/fin
|
||||
p = p.trim();
|
||||
// supprimer slashs finaux sauf pour la racine
|
||||
if (p !== '/') p = p.replace(/\/+$/, '');
|
||||
return p || '/';
|
||||
}
|
||||
@@ -49,24 +48,16 @@ function useSimpleRouter() {
|
||||
|
||||
function navigate(path) {
|
||||
const target = normalizePath(path);
|
||||
// toujours pousser l'URL complète (path peut contenir query/hash),
|
||||
// mais stocker en internal state la version normalisée (sans query/hash)
|
||||
// comparer l'URL complète (pathname + search + hash) afin de permettre
|
||||
// des navigations qui ne changent que la querystring (ex. ?gare=...)
|
||||
const currentFull = window.location.pathname + (window.location.search || '') + (window.location.hash || '');
|
||||
if (currentFull !== path) {
|
||||
console.debug('[router] navigate ->', path, '(normalized ->', target, ')');
|
||||
try {
|
||||
window.history.pushState({}, '', path);
|
||||
} catch (e) {
|
||||
// fallback si path est invalide
|
||||
try { window.history.pushState({}, '', target); } catch (err) { /* ignore */ }
|
||||
try { window.history.pushState({}, '', target); } catch (err) {}
|
||||
}
|
||||
// mettre à jour la route interne (sans query/hash)
|
||||
setRoute(target);
|
||||
} else {
|
||||
// si l'URL complète est identique, forcer un update de state pour
|
||||
// déclencher un rendu si besoin (rare)
|
||||
setRoute(target);
|
||||
}
|
||||
}
|
||||
@@ -77,122 +68,160 @@ function useSimpleRouter() {
|
||||
function App() {
|
||||
const { route, navigate } = useSimpleRouter();
|
||||
|
||||
const source = getSourceFromPath(route);
|
||||
const prefix = source === 'supabase' ? '/ferrovia' : '';
|
||||
const cleanRoute = (route.replace(/^\/ferrovia/, '') || '/');
|
||||
|
||||
// Composant Home explicite (panels cliquables)
|
||||
function Home({ navigate }) {
|
||||
useEffect(() => {
|
||||
console.debug('[Home] monté, pathname =', window.location.pathname);
|
||||
}, []);
|
||||
function Home({ navigate, prefix, source }) {
|
||||
const panelStyle = {
|
||||
width: '40%',
|
||||
width: '42%',
|
||||
cursor: 'pointer',
|
||||
padding: 24,
|
||||
borderRadius: 8,
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,0.12)',
|
||||
borderRadius: 10,
|
||||
boxShadow: '0 4px 12px rgba(0,0,0,0.08)',
|
||||
background: '#fff',
|
||||
textAlign: 'center'
|
||||
textAlign: 'center',
|
||||
border: '1px solid #e0e8f6',
|
||||
transition: 'transform 0.15s ease'
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', padding: '40px', alignItems: 'center', background: '#e9f0ff', paddingTop: 32, paddingBottom: 32 }}>
|
||||
<div style={{ width: '100%', textAlign: 'center', marginBottom: 16 }}>
|
||||
<h1 style={{ margin: 0, fontSize: 28 }}>Accueil</h1>
|
||||
<p style={{ margin: '8px 0 20px', color: '#333' }}>Choisissez une section ci-dessous</p>
|
||||
</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-around', width: '100%' }}>
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => { try { sessionMemory.set('afficheurMode', 'departs'); } catch (e) {} navigate('/departs'); }}
|
||||
onKeyDown={(e) => (e.key === 'Enter' || e.key === ' ' ? (function(){ try { sessionMemory.set('afficheurMode', 'departs'); } catch (e) {} navigate('/departs'); })() : null)}
|
||||
style={panelStyle}
|
||||
aria-label="Accéder aux départs"
|
||||
>
|
||||
<h2>Départs</h2>
|
||||
<p>Consultez les prochains départs d'une gare. Cliquez pour choisir une gare et voir les horaires.</p>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', padding: '32px 24px', alignItems: 'center', background: '#e9f0ff', borderRadius: '12px' }}>
|
||||
<div style={{ width: '100%', textAlign: 'center', marginBottom: 20 }}>
|
||||
<div style={{ display: 'inline-block', padding: '4px 12px', borderRadius: '20px', background: source === 'supabase' ? '#e6f4ea' : '#e8f0fe', color: source === 'supabase' ? '#137333' : '#1a73e8', fontWeight: 600, fontSize: '13px', marginBottom: '8px' }}>
|
||||
{source === 'supabase' ? 'Mode Base de Données (Ferrovia)' : 'Mode Officiel SNCF (GTFS / Temps Réel)'}
|
||||
</div>
|
||||
<h1 style={{ margin: '8px 0', fontSize: 28, color: '#002257' }}>Accueil</h1>
|
||||
<p style={{ margin: '4px 0 16px', color: '#555' }}>
|
||||
{source === 'supabase'
|
||||
? "Consultez les afficheurs basés sur les données de votre BDD Supabase."
|
||||
: "Consultez les afficheurs connectés aux flux réels GTFS et Open Data SNCF."}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => { try { sessionMemory.set('afficheurMode', 'arrivees'); } catch (e) {} navigate('/arrivees'); }}
|
||||
onKeyDown={(e) => (e.key === 'Enter' || e.key === ' ' ? (function(){ try { sessionMemory.set('afficheurMode', 'arrivees'); } catch (e) {} navigate('/arrivees'); })() : null)}
|
||||
style={panelStyle}
|
||||
aria-label="Accéder aux arrivées"
|
||||
>
|
||||
<h2>Arrivées</h2>
|
||||
<p>Consultez les prochaines arrivées d'une gare. Cliquez pour choisir une gare et voir les informations.</p>
|
||||
</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-around', width: '100%', maxWidth: '800px' }}>
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => { try { sessionMemory.set('afficheurMode', 'departs'); } catch (e) {} navigate(`${prefix}/departs`); }}
|
||||
onKeyDown={(e) => (e.key === 'Enter' || e.key === ' ' ? (function(){ try { sessionMemory.set('afficheurMode', 'departs'); } catch (e) {} navigate(`${prefix}/departs`); })() : null)}
|
||||
style={panelStyle}
|
||||
aria-label="Accéder aux départs"
|
||||
>
|
||||
<h2 style={{ color: '#00439e', marginTop: 0 }}>🚆 Départs</h2>
|
||||
<p style={{ color: '#666', fontSize: '14px' }}>Consultez les prochains départs d'une gare. Choisissez une gare et le style d'afficheur.</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => { try { sessionMemory.set('afficheurMode', 'arrivees'); } catch (e) {} navigate(`${prefix}/arrivees`); }}
|
||||
onKeyDown={(e) => (e.key === 'Enter' || e.key === ' ' ? (function(){ try { sessionMemory.set('afficheurMode', 'arrivees'); } catch (e) {} navigate(`${prefix}/arrivees`); })() : null)}
|
||||
style={panelStyle}
|
||||
aria-label="Accéder aux arrivées"
|
||||
>
|
||||
<h2 style={{ color: '#00439e', marginTop: 0 }}>🏁 Arrivées</h2>
|
||||
<p style={{ color: '#666', fontSize: '14px' }}>Consultez les prochaines arrivées d'une gare en temps réel.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Routes pour afficheurs : format /afficheurs/{mode}/{type}?gare=...
|
||||
// route plus spécifique pour l'afficheur "quais"
|
||||
if (route.startsWith('/afficheurs/departs/classiques/quais')) {
|
||||
// Routes pour afficheurs : supporte le mode racine ET le mode /ferrovia
|
||||
if (cleanRoute.startsWith('/afficheurs/departs/classiques/quais')) {
|
||||
return <AfficheurViewportWrapper><ClassiquesDepartsQuais /></AfficheurViewportWrapper>;
|
||||
}
|
||||
if (route.startsWith('/afficheurs/arrivees/classiques/quais')) {
|
||||
if (cleanRoute.startsWith('/afficheurs/arrivees/classiques/quais')) {
|
||||
return <AfficheurViewportWrapper><ClassiquesArriveesQuais /></AfficheurViewportWrapper>;
|
||||
}
|
||||
if (route.startsWith('/afficheurs/departs/classiques')) {
|
||||
if (cleanRoute.startsWith('/afficheurs/departs/classiques')) {
|
||||
return <AfficheurViewportWrapper><ClassiquesDeparts /></AfficheurViewportWrapper>;
|
||||
}
|
||||
if (route.startsWith('/afficheurs/departs/afl/quais')) {
|
||||
if (cleanRoute.startsWith('/afficheurs/departs/afl/quais')) {
|
||||
return <AfficheurViewportWrapper><AFLDepartsQuais /></AfficheurViewportWrapper>;
|
||||
}
|
||||
if (route.startsWith('/afficheurs/departs/afl')) {
|
||||
if (cleanRoute.startsWith('/afficheurs/departs/afl')) {
|
||||
return <AfficheurViewportWrapper><AFLDeparts /></AfficheurViewportWrapper>;
|
||||
}
|
||||
if (route.startsWith('/afficheurs/departs/eva')) {
|
||||
if (cleanRoute.startsWith('/afficheurs/departs/eva')) {
|
||||
return <AfficheurViewportWrapper><EVADeparts /></AfficheurViewportWrapper>;
|
||||
}
|
||||
if (route.startsWith('/afficheurs/arrivees/afl/quais')) {
|
||||
if (cleanRoute.startsWith('/afficheurs/arrivees/afl/quais')) {
|
||||
return <AfficheurViewportWrapper><AFLArriveesQuais /></AfficheurViewportWrapper>;
|
||||
}
|
||||
if (route.startsWith('/afficheurs/arrivees/afl')) {
|
||||
if (cleanRoute.startsWith('/afficheurs/arrivees/afl')) {
|
||||
return <AfficheurViewportWrapper><AFLArrivees /></AfficheurViewportWrapper>;
|
||||
}
|
||||
if (route.startsWith('/afficheurs/arrivees/eva')) {
|
||||
if (cleanRoute.startsWith('/afficheurs/arrivees/eva')) {
|
||||
return <AfficheurViewportWrapper><EVAArrivees /></AfficheurViewportWrapper>;
|
||||
}
|
||||
if (route.startsWith('/afficheurs/arrivees/classiques')) {
|
||||
if (cleanRoute.startsWith('/afficheurs/arrivees/classiques')) {
|
||||
return <AfficheurViewportWrapper><ClassiquesArrivees /></AfficheurViewportWrapper>;
|
||||
}
|
||||
|
||||
let content;
|
||||
if (route === '/departs') {
|
||||
content = <Departs onBack={() => navigate('/')} navigate={navigate} />;
|
||||
} else if (route === '/arrivees') {
|
||||
content = <Arrivees onBack={() => navigate('/')} navigate={navigate} />;
|
||||
} else if (route === '/select-afficheur') {
|
||||
if (cleanRoute === '/departs') {
|
||||
content = <Departs onBack={() => navigate(prefix || '/')} navigate={navigate} />;
|
||||
} else if (cleanRoute === '/arrivees') {
|
||||
content = <Arrivees onBack={() => navigate(prefix || '/')} navigate={navigate} />;
|
||||
} else if (cleanRoute === '/select-afficheur') {
|
||||
content = <SelectAfficheur onBack={() => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const gare = params.get('gare') || '';
|
||||
const mode = params.get('mode') || 'departs';
|
||||
navigate(`/afficheurs/${encodeURIComponent(gare)}?mode=${mode}`);
|
||||
navigate(`${prefix}/afficheurs/${encodeURIComponent(gare)}?mode=${mode}`);
|
||||
}} navigate={navigate} />;
|
||||
} else if (route.startsWith('/afficheurs')) {
|
||||
content = <Displays onBack={() => navigate('/')} navigate={navigate} />;
|
||||
} else if (cleanRoute.startsWith('/afficheurs')) {
|
||||
content = <Displays onBack={() => navigate(prefix || '/')} navigate={navigate} />;
|
||||
} else {
|
||||
content = <Home navigate={navigate} />;
|
||||
content = <Home navigate={navigate} prefix={prefix} source={source} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="sncf-voyageurs" style={{ minHeight: '100vh', display: 'flex', flexDirection: 'column' }}>
|
||||
<wcs-galactic app-name="Affichage Ferroviaire" version="1.0.0">
|
||||
<wcs-galactic-menu-item>
|
||||
<a href="/departs" onClick={(e) => { e.preventDefault(); navigate('/departs'); }}>Départs</a>
|
||||
<a href={`${prefix}/departs`} onClick={(e) => { e.preventDefault(); navigate(`${prefix}/departs`); }}>Départs</a>
|
||||
</wcs-galactic-menu-item>
|
||||
<wcs-galactic-menu-item>
|
||||
<a href="/arrivees" onClick={(e) => { e.preventDefault(); navigate('/arrivees'); }}>Arrivées</a>
|
||||
<a href={`${prefix}/arrivees`} onClick={(e) => { e.preventDefault(); navigate(`${prefix}/arrivees`); }}>Arrivées</a>
|
||||
</wcs-galactic-menu-item>
|
||||
<wcs-galactic-menu-item>
|
||||
{source === 'supabase' ? (
|
||||
<a
|
||||
href="/"
|
||||
onClick={(e) => { e.preventDefault(); navigate('/'); }}
|
||||
style={{ color: '#008b47', fontWeight: 600 }}
|
||||
title="Basculer vers le mode SNCF GTFS"
|
||||
>
|
||||
🌐 Passer en mode SNCF Live
|
||||
</a>
|
||||
) : (
|
||||
<a
|
||||
href="/ferrovia"
|
||||
onClick={(e) => { e.preventDefault(); navigate('/ferrovia'); }}
|
||||
style={{ color: '#00439e', fontWeight: 600 }}
|
||||
title="Basculer vers la Base de Données Supabase"
|
||||
>
|
||||
🗄️ Passer en mode BDD Ferrovia
|
||||
</a>
|
||||
)}
|
||||
</wcs-galactic-menu-item>
|
||||
</wcs-galactic>
|
||||
|
||||
<header style={{ padding: 12, background: '#00439e', color: '#fff' }}>
|
||||
<div style={{ maxWidth: 1000, margin: '0 auto' }}>
|
||||
<h1 style={{ margin: 0, fontSize: 20 }}>Affichage Ferroviaire — Accueil</h1>
|
||||
<div style={{ fontSize: 12, opacity: 0.9 }}>Route actuelle: {route}</div>
|
||||
<header style={{ padding: 12, background: source === 'supabase' ? '#003366' : '#00439e', color: '#fff', transition: 'background 0.3s' }}>
|
||||
<div style={{ maxWidth: 1000, margin: '0 auto', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<div>
|
||||
<h1 style={{ margin: 0, fontSize: 20 }}>
|
||||
{source === 'supabase' ? 'Affichage Ferroviaire — BDD Supabase (/ferrovia)' : 'Affichage Ferroviaire — SNCF GTFS / Temps Réel'}
|
||||
</h1>
|
||||
<div style={{ fontSize: 12, opacity: 0.9 }}>Route actuelle: {route}</div>
|
||||
</div>
|
||||
<div style={{ fontSize: '13px', background: 'rgba(255,255,255,0.15)', padding: '6px 12px', borderRadius: '6px' }}>
|
||||
Source: <strong>{source === 'supabase' ? 'Supabase Database' : 'SNCF Open Data / GTFS'}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
Reference in new issue
Block a user