Files
smart-city-digital-twin-mar…/smart-app-city/design/03-carte-interactive-blue.html
Eric FELIXINE e30ae8ed09 feat(smart-app): implement complete mobile app MVP
- 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
2026-06-01 18:00:35 -04:00

198 lines
9.9 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 — 03 Carte Interactive (Blue v2)</title>
<link rel="stylesheet" href="shared-blue.css">
<style>
.map-container {
position: absolute;
top: 44px; bottom: 80px; left: 0; right: 0;
background: #D4EEF7;
overflow: hidden;
}
.map-toolbar {
position: absolute;
top: 12px; left: 12px; right: 12px;
z-index: 20;
display: flex;
gap: 8px;
align-items: center;
}
.map-search {
flex: 1;
background: white;
border-radius: var(--radius-full);
padding: 10px 16px;
display: flex; align-items: center; gap: 8px;
box-shadow: var(--shadow-md);
font-size: var(--text-sm);
color: var(--neutral-500);
}
.map-fab {
width: 44px; height: 44px;
border-radius: var(--radius-full);
background: white;
box-shadow: var(--shadow-md);
display: flex; align-items: center; justify-content: center;
cursor: pointer;
font-size: 20px;
}
.map-overlay-info {
position: absolute;
bottom: 16px; left: 12px; right: 12px;
z-index: 20;
}
.sensor-marker {
position: absolute;
cursor: pointer;
transition: transform 0.2s;
}
.sensor-marker:hover { transform: scale(1.2); }
.legend {
position: absolute;
top: 70px; right: 12px;
z-index: 20;
background: white;
border-radius: var(--radius-lg);
padding: 12px;
box-shadow: var(--shadow-md);
font-size: var(--text-xs);
}
.legend-item {
display: flex; align-items: center; gap: 6px;
margin-bottom: 6px;
}
.legend-dot {
width: 10px; height: 10px;
border-radius: 50%;
}
.filter-chips {
position: absolute;
top: 68px; left: 12px;
z-index: 20;
display: flex; gap: 6px;
}
/* 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 style="display:flex;gap:4px;align-items:center;">
<svg width="16" height="12" viewBox="0 0 16 12"><rect x="0" y="4" width="3" height="8" rx="1" fill="#333"/><rect x="4.5" y="2.5" width="3" height="9.5" rx="1" fill="#333"/><rect x="9" y="0" width="3" height="12" rx="1" fill="#333"/><rect x="13.5" y="0" width="2.5" height="12" rx="1" fill="#ccc"/></svg>
</div>
</div>
<div class="map-container">
<svg width="100%" height="100%" viewBox="0 0 390 580" preserveAspectRatio="xMidYMid slice">
<rect width="390" height="580" fill="#D4EEF7"/>
<path d="M60 420 Q80 350 130 310 Q170 275 220 265 Q270 255 310 280 Q340 300 350 340 Q360 370 340 400 Q320 430 280 440 Q240 455 200 445 Q160 440 120 435 Q80 435 60 420Z" fill="#BBDEFB" stroke="#64B5F6" stroke-width="1.5"/>
<path d="M120 340 Q140 320 170 315 Q200 310 230 320" stroke="#90CAF9" stroke-width="1" fill="none" stroke-dasharray="4 2"/>
<path d="M100 430 L130 435 L160 430 L190 435 L220 425 L250 430" stroke="white" stroke-width="2.5" fill="none" opacity="0.6"/>
<path d="M130 310 Q150 330 160 360 Q165 380 155 400" stroke="white" stroke-width="2.5" fill="none" opacity="0.7"/>
<path d="M220 265 Q230 290 235 320 Q238 350 240 380" stroke="white" stroke-width="2.5" fill="none" opacity="0.7"/>
<text x="155" y="295" font-size="10" fill="#0D47A1" font-weight="600" text-anchor="middle">Fort-de-France</text>
<text x="260" y="320" font-size="9" fill="#1565C0" font-weight="500" text-anchor="middle">Schœlcher</text>
<text x="120" y="370" font-size="8" fill="#1976D2" text-anchor="middle">Lamentin</text>
</svg>
<!-- Sensor markers -->
<div style="position:absolute;top:35%;left:38%;z-index:10;">
<div style="width:14px;height:14px;background:#1565C0;border-radius:50%;border:2px solid white;box-shadow:0 2px 6px rgba(0,0,0,0.3);position:relative;">
<div style="position:absolute;top:-30px;left:50%;transform:translateX(-50%);background:#1565C0;color:white;font-size:9px;padding:3px 8px;border-radius:6px;white-space:nowrap;font-weight:600;">🌡️ 24.3°</div>
</div>
</div>
<div style="position:absolute;top:42%;left:58%;z-index:10;">
<div style="width:14px;height:14px;background:#00ACC1;border-radius:50%;border:2px solid white;box-shadow:0 2px 6px rgba(0,0,0,0.3);"></div>
</div>
<div style="position:absolute;top:50%;left:45%;z-index:10;">
<div style="width:14px;height:14px;background:#3949AB;border-radius:50%;border:2px solid white;box-shadow:0 2px 6px rgba(0,0,0,0.3);"></div>
</div>
<div style="position:absolute;top:38%;left:30%;z-index:10;">
<div style="width:14px;height:14px;background:#00838F;border-radius:50%;border:2px solid white;box-shadow:0 2px 6px rgba(0,0,0,0.3);"></div>
</div>
<div style="position:absolute;top:55%;left:62%;z-index:10;">
<div style="width:12px;height:12px;background:#D32F2F;border-radius:50%;border:2px solid white;box-shadow:0 2px 6px rgba(0,0,0,0.3);"></div>
</div>
<!-- User location -->
<div style="position:absolute;top:44%;left:42%;z-index:15;">
<div style="width:20px;height:20px;background:#1565C0;border-radius:50%;border:3px solid white;box-shadow:0 0 0 4px rgba(21,101,192,0.2), 0 2px 8px rgba(0,0,0,0.3);"></div>
</div>
<!-- Toolbar -->
<div class="map-toolbar">
<div class="map-search">
<svg class="icon-sm" viewBox="0 0 24 24"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
Rechercher un lieu...
</div>
<div class="map-fab">📍</div>
<div class="map-fab">🔄</div>
</div>
<!-- Filter chips -->
<div class="filter-chips">
<div class="chip" style="background:var(--primary-500);color:white;border:none;">Tous</div>
<div class="chip">🌡️ Temp</div>
<div class="chip">💨 Air</div>
<div class="chip">💡 Lumière</div>
</div>
<!-- Legend -->
<div class="legend">
<div style="font-weight:600;margin-bottom:8px;font-size:11px;">Légende</div>
<div class="legend-item"><div class="legend-dot" style="background:#1565C0"></div> Température</div>
<div class="legend-item"><div class="legend-dot" style="background:#00ACC1"></div> Qualité air</div>
<div class="legend-item"><div class="legend-dot" style="background:#3949AB"></div> Énergie</div>
<div class="legend-item"><div class="legend-dot" style="background:#00838F"></div> Humidité</div>
<div class="legend-item"><div class="legend-dot" style="background:#D32F2F"></div> Alerte</div>
</div>
<!-- Bottom info card -->
<div class="map-overlay-info">
<div class="card" style="padding:14px;">
<div style="display:flex;justify-content:space-between;align-items:center;">
<div>
<div style="font-weight:700;font-size:var(--text-base);">Capteur sélectionné</div>
<div style="font-size:var(--text-sm);color:var(--neutral-500);">Temp-001 · Fort-de-France Centre</div>
</div>
<div style="text-align:right;">
<div style="font-size:var(--text-xl);font-weight:700;color:var(--primary-500);">24.3°C</div>
<div style="font-size:10px;color:var(--alert-success);font-weight:600;">● En ligne</div>
</div>
</div>
<div style="display:flex;gap:8px;margin-top:10px;">
<div style="flex:1;background:var(--neutral-50);border-radius:8px;padding:8px;text-align:center;">
<div style="font-size:var(--text-sm);font-weight:700;color:var(--ocean-500);">42%</div>
<div style="font-size:9px;color:var(--neutral-500);">Humidité</div>
</div>
<div style="flex:1;background:var(--neutral-50);border-radius:8px;padding:8px;text-align:center;">
<div style="font-size:var(--text-sm);font-weight:700;color:var(--alert-success);">Bon</div>
<div style="font-size:9px;color:var(--neutral-500);">Qualité air</div>
</div>
<div style="flex:1;background:var(--neutral-50);border-radius:8px;padding:8px;text-align:center;">
<div style="font-size:var(--text-sm);font-weight:700;color:var(--neutral-700);">12 min</div>
<div style="font-size:9px;color:var(--neutral-500);">Dernière MAJ</div>
</div>
</div>
</div>
</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);">03 — Carte Interactive · Blue v2</div>
</div>
</body>
</html>