fix(web): position map source switcher below navbar and fix missing Flame icon import in ExecutiveShowcase
This commit is contained in:
@@ -22,7 +22,9 @@ import {
|
|||||||
Plane,
|
Plane,
|
||||||
Radar,
|
Radar,
|
||||||
Sparkles,
|
Sparkles,
|
||||||
ExternalLink
|
ExternalLink,
|
||||||
|
Flame,
|
||||||
|
ShieldAlert
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
|
|
||||||
export const ExecutiveShowcase: React.FC = () => {
|
export const ExecutiveShowcase: React.FC = () => {
|
||||||
|
|||||||
@@ -19,17 +19,17 @@ type RefKey =
|
|||||||
| 'osm';
|
| 'osm';
|
||||||
|
|
||||||
const REFS: Record<RefKey, { label: string; tiles: string; attribution: string; maxzoom: number }> = {
|
const REFS: Record<RefKey, { label: string; tiles: string; attribution: string; maxzoom: number }> = {
|
||||||
'google-hybrid': { label: '🛰️ Google Hybrid', tiles: 'https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}', attribution: '© Google', maxzoom: 20 },
|
'google-hybrid': { label: '🛰️ Google Hybrid', tiles: 'https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}', attribution: '© Google', maxzoom: 20 },
|
||||||
'google-topo': { label: '🏔️ Google Topo', tiles: 'https://mt1.google.com/vt/lyrs=p&x={x}&y={y}&z={z}', attribution: '© Google', maxzoom: 20 },
|
'google-topo': { label: '🏔️ Google Topo', tiles: 'https://mt1.google.com/vt/lyrs=p&x={x}&y={y}&z={z}', attribution: '© Google', maxzoom: 20 },
|
||||||
'soviet-military': { label: '🇷🇺 Soviet Military Topo', tiles: 'https://maps.marshruty.ru/ml.ashx?x={x}&y={y}&z={z}&i=1&al=1', attribution: '© Soviet Military Topo 1:100k', maxzoom: 15 },
|
'soviet-military': { label: '🇷🇺 Soviet Military Topo', tiles: 'https://maps.marshruty.ru/ml.ashx?x={x}&y={y}&z={z}&i=1&al=1', attribution: '© Soviet Military Topo 1:100k', maxzoom: 15 },
|
||||||
'opentopo': { label: '🧭 OpenTopoMap', tiles: 'https://tile.opentopomap.org/{z}/{x}/{y}.png', attribution: '© OpenTopoMap', maxzoom: 17 },
|
'opentopo': { label: '🧭 OpenTopoMap', tiles: 'https://tile.opentopomap.org/{z}/{x}/{y}.png', attribution: '© OpenTopoMap', maxzoom: 17 },
|
||||||
'esri-clarity': { label: '✨ Esri Clarity HD', tiles: 'https://clarity.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', attribution: '© Esri', maxzoom: 19 },
|
'esri-clarity': { label: '✨ Esri Clarity HD', tiles: 'https://clarity.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', attribution: '© Esri', maxzoom: 19 },
|
||||||
'google-sat': { label: '🛰️ Google Sat', tiles: 'https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', attribution: '© Google', maxzoom: 20 },
|
'google-sat': { label: '🛰️ Google Sat', tiles: 'https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', attribution: '© Google', maxzoom: 20 },
|
||||||
'google-streets': { label: '🗺️ Google Streets', tiles: 'https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}', attribution: '© Google', maxzoom: 20 },
|
'google-streets': { label: '🗺️ Google Streets', tiles: 'https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}', attribution: '© Google', maxzoom: 20 },
|
||||||
'esri-sat': { label: '🛰️ Esri Satellite', tiles: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', attribution: '© Esri, Maxar', maxzoom: 19 },
|
'esri-sat': { label: '🛰️ Esri Satellite', tiles: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', attribution: '© Esri, Maxar', maxzoom: 19 },
|
||||||
'esri-topo': { label: '🏔️ Esri Topo', tiles: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}', attribution: '© Esri', maxzoom: 19 },
|
'esri-topo': { label: '🏔️ Esri Topo', tiles: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}', attribution: '© Esri', maxzoom: 19 },
|
||||||
'esri-streets': { label: '🗺️ Esri Streets', tiles: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}', attribution: '© Esri', maxzoom: 19 },
|
'esri-streets': { label: '🗺️ Esri Streets', tiles: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}', attribution: '© Esri', maxzoom: 19 },
|
||||||
'osm': { label: '🧭 OSM Standard', tiles: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', attribution: '© OpenStreetMap', maxzoom: 19 },
|
'osm': { label: '🧭 OSM Standard', tiles: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', attribution: '© OpenStreetMap', maxzoom: 19 },
|
||||||
};
|
};
|
||||||
|
|
||||||
const API = (import.meta as any).env.VITE_API_URL || '/api';
|
const API = (import.meta as any).env.VITE_API_URL || '/api';
|
||||||
@@ -42,7 +42,7 @@ const rasterStyle = (ref: any): any => ({
|
|||||||
layers: [{ id: 'ref', type: 'raster', source: 'ref' }],
|
layers: [{ id: 'ref', type: 'raster', source: 'ref' }],
|
||||||
});
|
});
|
||||||
|
|
||||||
const DEFAULT_SYSTEM_KEY = (import.meta as any).env.VITE_API_KEY || 'zP9vL5mK2nQ8xR7jT4wS1yB6hG3fV0cX';
|
const DEFAULT_SYSTEM_KEY = (import.meta as any).env.VITE_API_KEY;
|
||||||
|
|
||||||
const IntelligenceDashboard: React.FC = () => {
|
const IntelligenceDashboard: React.FC = () => {
|
||||||
const [stats, setStats] = useState<any>(null);
|
const [stats, setStats] = useState<any>(null);
|
||||||
@@ -112,8 +112,8 @@ const IntelligenceDashboard: React.FC = () => {
|
|||||||
const lines: [number, number][][] = geom.type === 'LineString'
|
const lines: [number, number][][] = geom.type === 'LineString'
|
||||||
? [geom.coordinates as [number, number][]]
|
? [geom.coordinates as [number, number][]]
|
||||||
: geom.type === 'MultiLineString'
|
: geom.type === 'MultiLineString'
|
||||||
? (geom.coordinates as [number, number][][])
|
? (geom.coordinates as [number, number][][])
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
for (let i = 0; i < line.length - 1; i++) {
|
for (let i = 0; i < line.length - 1; i++) {
|
||||||
@@ -691,8 +691,8 @@ const IntelligenceDashboard: React.FC = () => {
|
|||||||
{/* Left Map: Our Data */}
|
{/* Left Map: Our Data */}
|
||||||
<div style={{ flex: 1, position: 'relative', borderRight: '2px solid #0f172a' }}>
|
<div style={{ flex: 1, position: 'relative', borderRight: '2px solid #0f172a' }}>
|
||||||
<div ref={leftDiv} style={{ width: '100%', height: '100%' }} />
|
<div ref={leftDiv} style={{ width: '100%', height: '100%' }} />
|
||||||
<div style={{ position: 'absolute', top: 10, left: 10, zIndex: 2, background: 'rgba(15,23,42,0.85)', border: '1px solid #334155', padding: '4px 10px', borderRadius: '20px', fontSize: '0.72rem', fontWeight: 600, pointerEvents: 'none' }}>
|
<div style={{ position: 'absolute', top: 62, left: 16, zIndex: 30, background: 'rgba(15,23,42,0.92)', backdropFilter: 'blur(8px)', border: '1px solid #334155', padding: '6px 14px', borderRadius: '20px', fontSize: '0.8rem', fontWeight: 700, color: '#38bdf8', boxShadow: '0 4px 12px rgba(0,0,0,0.4)', pointerEvents: 'none' }}>
|
||||||
Our Map (Intaleq)
|
🗺️ خريطتنا السيادية (Intaleq Map)
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -700,9 +700,9 @@ const IntelligenceDashboard: React.FC = () => {
|
|||||||
<div style={{ flex: 1, position: 'relative' }}>
|
<div style={{ flex: 1, position: 'relative' }}>
|
||||||
<div ref={rightDiv} style={{ width: '100%', height: '100%' }} />
|
<div ref={rightDiv} style={{ width: '100%', height: '100%' }} />
|
||||||
|
|
||||||
<div style={{ position: 'absolute', top: 10, left: 10, right: 280, zIndex: 2, display: 'flex', gap: '6px', overflowX: 'auto', paddingBottom: '4px' }}>
|
<div style={{ position: 'absolute', top: 62, left: 16, right: 20, zIndex: 30, display: 'flex', gap: '8px', overflowX: 'auto', paddingBottom: '4px' }}>
|
||||||
{(Object.keys(REFS) as Array<keyof typeof REFS>).map(k => (
|
{(Object.keys(REFS) as Array<keyof typeof REFS>).map(k => (
|
||||||
<button key={k} onClick={() => setRefKey(k)} style={{ background: refKey === k ? 'rgba(99,102,241,0.95)' : 'rgba(15,23,42,0.85)', border: '1px solid #334155', color: refKey === k ? 'white' : '#e2e8f0', padding: '4px 10px', borderRadius: '20px', fontSize: '0.72rem', fontWeight: 600, cursor: 'pointer', whiteSpace: 'nowrap', flexShrink: 0 }}>
|
<button key={k} onClick={() => setRefKey(k)} style={{ background: refKey === k ? 'linear-gradient(135deg, #6366f1, #3b82f6)' : 'rgba(15,23,42,0.92)', backdropFilter: 'blur(8px)', border: refKey === k ? '1px solid #818cf8' : '1px solid #334155', color: refKey === k ? 'white' : '#cbd5e1', padding: '6px 14px', borderRadius: '20px', fontSize: '0.78rem', fontWeight: 700, cursor: 'pointer', whiteSpace: 'nowrap', flexShrink: 0, boxShadow: '0 4px 12px rgba(0,0,0,0.3)', transition: 'all 0.15s ease' }}>
|
||||||
{REFS[k].label}
|
{REFS[k].label}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
|
|||||||
Reference in New Issue
Block a user