- App.tsx: full navigation (Auth stack + Main tabs with 5 screens) - Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen - HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors - MapScreen: interactive map with layer toggles (6 layers) - MarketplaceScreen: categories (6), products (5), search - ChatScreen: AI chat with quick prompts (4), bot responses - ProfileScreen: user info, stats, menu (9 items), logout - AlertsScreen: alert list with severity, acknowledge - SensorsScreen: sensor list with type filters (6 types), search - ZonesScreen: zone cards with stats - SettingsScreen: language picker (FR/EN/ES/DE), privacy, about - Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n - Hooks: useSensors, useAlerts, useNotifications, useLocation - Components: Card, Button, LoadingSpinner, ErrorBoundary, Header - Services: iotService, notificationService (with axios API client) - Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN) - Theme: colors.ts with full design system (Blue Ocean palette) - Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
266 lines
9.5 KiB
HTML
266 lines
9.5 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Smart App City v2 — 11 Bus Tracker</title>
|
|
<link rel="stylesheet" href="shared-blue.css">
|
|
<style>
|
|
.bus-header {
|
|
padding: 16px;
|
|
background: linear-gradient(135deg, var(--ocean-600), var(--primary-500));
|
|
color: white;
|
|
}
|
|
.bus-title { font-size: var(--text-xl); font-weight: var(--weight-bold); margin-bottom: 4px; }
|
|
.bus-sub { font-size: var(--text-sm); opacity: 0.8; }
|
|
|
|
.line-selector {
|
|
display: flex; gap: 8px; padding: 12px 16px;
|
|
overflow-x: auto; scrollbar-width: none;
|
|
}
|
|
.line-badge {
|
|
flex-shrink: 0;
|
|
padding: 8px 16px;
|
|
border-radius: var(--radius-full);
|
|
font-size: var(--text-sm);
|
|
font-weight: var(--weight-bold);
|
|
cursor: pointer;
|
|
border: 2px solid var(--neutral-200);
|
|
background: white;
|
|
color: var(--neutral-600);
|
|
}
|
|
.line-badge.active {
|
|
background: var(--primary-500);
|
|
color: white;
|
|
border-color: var(--primary-500);
|
|
}
|
|
.line-badge .line-dot {
|
|
display: inline-block;
|
|
width: 10px; height: 10px;
|
|
border-radius: 50%;
|
|
margin-right: 6px;
|
|
}
|
|
|
|
.stop-item {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 14px;
|
|
padding: 0 16px;
|
|
position: relative;
|
|
}
|
|
.stop-line {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
width: 24px;
|
|
flex-shrink: 0;
|
|
}
|
|
.stop-dot {
|
|
width: 14px; height: 14px;
|
|
border-radius: 50%;
|
|
border: 3px solid var(--primary-500);
|
|
background: white;
|
|
z-index: 1;
|
|
}
|
|
.stop-dot.active {
|
|
background: var(--primary-500);
|
|
box-shadow: 0 0 0 4px rgba(21,101,192,0.2);
|
|
}
|
|
.stop-dot.past {
|
|
background: var(--neutral-300);
|
|
border-color: var(--neutral-300);
|
|
}
|
|
.stop-connector {
|
|
flex: 1;
|
|
width: 2px;
|
|
background: var(--neutral-200);
|
|
margin-top: -2px;
|
|
}
|
|
.stop-info {
|
|
padding-bottom: 20px;
|
|
flex: 1;
|
|
}
|
|
.stop-name {
|
|
font-size: var(--text-sm);
|
|
font-weight: var(--weight-semibold);
|
|
margin-bottom: 2px;
|
|
}
|
|
.stop-time {
|
|
font-size: var(--text-xs);
|
|
color: var(--neutral-500);
|
|
}
|
|
.bus-eta {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
background: var(--primary-50);
|
|
color: var(--primary-600);
|
|
padding: 3px 10px;
|
|
border-radius: var(--radius-full);
|
|
font-size: 11px;
|
|
font-weight: 700;
|
|
margin-top: 4px;
|
|
}
|
|
.bus-eta.now {
|
|
background: var(--alert-success);
|
|
color: white;
|
|
}
|
|
/* Fixed viewport for PDF/iframe embedding */
|
|
html, body { width: 390px !important; height: 844px !important; overflow: hidden !important; margin: 0 !important; padding: 0 !important; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="mobile-frame">
|
|
<div class="status-bar"><span>9:41</span></div>
|
|
|
|
<!-- Header -->
|
|
<div class="bus-header">
|
|
<div class="bus-title">🚌 Transport en Temps Réel</div>
|
|
<div class="bus-sub">Lignes de bus Martinique · Services Ville</div>
|
|
</div>
|
|
|
|
<!-- Line Selector -->
|
|
<div class="line-selector">
|
|
<div class="line-badge active"><span class="line-dot" style="background:#1565C0;"></span>A1</div>
|
|
<div class="line-badge"><span class="line-dot" style="background:#00ACC1;"></span>B2</div>
|
|
<div class="line-badge"><span class="line-dot" style="background:#F57C00;"></span>C3</div>
|
|
<div class="line-badge"><span class="line-dot" style="background:#2E7D32;"></span>D4</div>
|
|
<div class="line-badge"><span class="line-dot" style="background:#D32F2F;"></span>E5</div>
|
|
</div>
|
|
|
|
<!-- Map Preview -->
|
|
<div style="margin:0 16px 12px;height:120px;background:linear-gradient(135deg,#E3F2FD,#BBDEFB);border-radius:var(--radius-lg);position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;">
|
|
<svg width="100%" height="100%" viewBox="0 0 358 120" style="position:absolute;">
|
|
<!-- Route path -->
|
|
<path d="M30 90 Q80 60 130 50 Q180 40 230 35 Q280 30 330 20" stroke="#1565C0" stroke-width="3" fill="none" stroke-dasharray="6 3" opacity="0.5"/>
|
|
<!-- Stops -->
|
|
<circle cx="30" cy="90" r="5" fill="#1565C0"/>
|
|
<circle cx="80" cy="68" r="4" fill="#1565C0" opacity="0.7"/>
|
|
<circle cx="130" cy="50" r="5" fill="#1565C0">
|
|
<animate attributeName="r" values="5;8;5" dur="2s" repeatCount="indefinite"/>
|
|
</circle>
|
|
<circle cx="180" cy="42" r="4" fill="#1565C0" opacity="0.7"/>
|
|
<circle cx="230" cy="35" r="4" fill="#90CAF9"/>
|
|
<circle cx="280" cy="30" r="4" fill="#90CAF9"/>
|
|
<circle cx="330" cy="20" r="4" fill="#90CAF9"/>
|
|
<!-- Bus icon -->
|
|
<g transform="translate(120, 36)">
|
|
<rect x="-12" y="-8" width="24" height="16" rx="4" fill="#1565C0"/>
|
|
<text x="0" y="4" text-anchor="middle" font-size="10" fill="white">🚌</text>
|
|
</g>
|
|
</svg>
|
|
<div style="position:absolute;bottom:8px;right:10px;background:white;border-radius:8px;padding:4px 10px;font-size:10px;font-weight:600;box-shadow:0 2px 8px rgba(0,0,0,0.1);">
|
|
🟢 3 bus actifs
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Stops list -->
|
|
<div style="padding:0 16px 8px;font-size:var(--text-md);font-weight:700;">Arrêts — Ligne A1</div>
|
|
|
|
<div class="content-area" style="top:290px;bottom:80px;background:var(--neutral-50);overflow-y:auto;">
|
|
<!-- Past stop -->
|
|
<div class="stop-item">
|
|
<div class="stop-line">
|
|
<div class="stop-dot past"></div>
|
|
<div class="stop-connector" style="height:30px;"></div>
|
|
</div>
|
|
<div class="stop-info">
|
|
<div class="stop-name" style="color:var(--neutral-400);">Gare Maritime</div>
|
|
<div class="stop-time">Passé · 09:15</div>
|
|
</div>
|
|
</div>
|
|
<!-- Past stop -->
|
|
<div class="stop-item">
|
|
<div class="stop-line">
|
|
<div class="stop-dot past"></div>
|
|
<div class="stop-connector" style="height:30px;"></div>
|
|
</div>
|
|
<div class="stop-info">
|
|
<div class="stop-name" style="color:var(--neutral-400);">Place Perrinon</div>
|
|
<div class="stop-time">Passé · 09:18</div>
|
|
</div>
|
|
</div>
|
|
<!-- Current stop -->
|
|
<div class="stop-item">
|
|
<div class="stop-line">
|
|
<div class="stop-dot active"></div>
|
|
<div class="stop-connector" style="height:30px;"></div>
|
|
</div>
|
|
<div class="stop-info">
|
|
<div class="stop-name" style="color:var(--primary-600);">Fort-de-France Centre 📍</div>
|
|
<div class="stop-time">Vous êtes ici</div>
|
|
<div class="bus-eta now">🚌 Bus dans 3 min</div>
|
|
</div>
|
|
</div>
|
|
<!-- Next stops -->
|
|
<div class="stop-item">
|
|
<div class="stop-line">
|
|
<div class="stop-dot"></div>
|
|
<div class="stop-connector" style="height:30px;"></div>
|
|
</div>
|
|
<div class="stop-info">
|
|
<div class="stop-name">Schœlcher — UFR</div>
|
|
<div class="stop-time">Estimé 09:28</div>
|
|
<div class="bus-eta">⏱️ 8 min</div>
|
|
</div>
|
|
</div>
|
|
<div class="stop-item">
|
|
<div class="stop-line">
|
|
<div class="stop-dot"></div>
|
|
<div class="stop-connector" style="height:30px;"></div>
|
|
</div>
|
|
<div class="stop-info">
|
|
<div class="stop-name">Campus Schoelcher</div>
|
|
<div class="stop-time">Estimé 09:33</div>
|
|
<div class="bus-eta">⏱️ 13 min</div>
|
|
</div>
|
|
</div>
|
|
<div class="stop-item">
|
|
<div class="stop-line">
|
|
<div class="stop-dot"></div>
|
|
<div class="stop-connector" style="height:30px;"></div>
|
|
</div>
|
|
<div class="stop-info">
|
|
<div class="stop-name">Trinité — Centre</div>
|
|
<div class="stop-time">Estimé 09:45</div>
|
|
<div class="bus-eta">⏱️ 25 min</div>
|
|
</div>
|
|
</div>
|
|
<div class="stop-item">
|
|
<div class="stop-line">
|
|
<div class="stop-dot"></div>
|
|
</div>
|
|
<div class="stop-info">
|
|
<div class="stop-name">Boulevard du Général de Gaulle</div>
|
|
<div class="stop-time">Estimé 09:52</div>
|
|
<div class="bus-eta">⏱️ 32 min</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="height:16px;"></div>
|
|
</div>
|
|
|
|
<!-- Bottom Nav -->
|
|
<div class="bottom-nav">
|
|
<div class="bottom-nav-item">
|
|
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><polyline points="9 22 9 12 15 12 15 22" fill="none" stroke="currentColor" stroke-width="2"/></svg><span>Accueil</span>
|
|
</div>
|
|
<div class="bottom-nav-item active">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="1 6 1 22 8 18 16 22 23 18 23 2 16 6 8 2 1 6"/><line x1="8" y1="2" x2="8" y2="18"/><line x1="16" y1="6" x2="16" y2="22"/></svg><span>Carte</span>
|
|
</div>
|
|
<div class="bottom-nav-item">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M8 14s1.5 2 4 2 4-2 4-2"/><line x1="9" y1="9" x2="9.01" y2="9"/><line x1="15" y1="9" x2="15.01" y2="9"/></svg><span>AI Chat</span>
|
|
</div>
|
|
<div class="bottom-nav-item">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg><span>Marché</span>
|
|
</div>
|
|
<div class="bottom-nav-item">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"/><circle cx="12" cy="7" r="4"/></svg><span>Profil</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="position:absolute;bottom:88px;left:0;right:0;text-align:center;font-size:10px;color:var(--neutral-400);">11 — Bus Tracker v2 / Blue</div>
|
|
</div>
|
|
</body>
|
|
</html>
|