diff --git a/src/app/event-handlers.ts b/src/app/event-handlers.ts index 4930c01a7..feb398b1e 100644 --- a/src/app/event-handlers.ts +++ b/src/app/event-handlers.ts @@ -262,6 +262,9 @@ export class EventHandlerManager implements AppModule { (panel as unknown as { refreshChannelsFromStorage: () => void }).refreshChannelsFromStorage(); } } + if (e.key === STORAGE_KEYS.mapMode) { + this.syncMapModeUI(); + } }; window.addEventListener('storage', this.boundStorageHandler); @@ -311,6 +314,7 @@ export class EventHandlerManager implements AppModule { this.setupMapResize(); this.setupMapPin(); + this.setupMap3D(); this.boundVisibilityHandler = () => { document.body?.classList.toggle('animations-paused', document.hidden); @@ -648,14 +652,7 @@ export class EventHandlerManager implements AppModule { isDesktopApp: this.ctx.isDesktopApp, statusPanel: this.ctx.statusPanel, isGlobeMode: () => this.ctx.map?.isGlobeMode() ?? false, - onMapModeChange: (useGlobe: boolean) => { - saveToStorage(STORAGE_KEYS.mapMode, useGlobe ? 'globe' : 'flat'); - if (useGlobe) { - this.ctx.map?.switchToGlobe(); - } else { - this.ctx.map?.switchToFlat(); - } - }, + onMapModeChange: (useGlobe: boolean) => this.setMapMode(useGlobe), }); if (this.ctx.statusPanel) { @@ -950,6 +947,34 @@ export class EventHandlerManager implements AppModule { this.setupMapFullscreen(mapSection); } + setupMap3D(): void { + const btn = document.getElementById('map3dBtn'); + if (!btn) return; + + this.syncMapModeUI(); + + btn.addEventListener('click', () => { + const isGlobe = this.ctx.map?.isGlobeMode(); + this.setMapMode(!isGlobe); + }); + } + + private setMapMode(useGlobe: boolean): void { + if (useGlobe) { + this.ctx.map?.switchToGlobe(); + } else { + this.ctx.map?.switchToFlat(); + } + saveToStorage(STORAGE_KEYS.mapMode, useGlobe ? 'globe' : 'flat'); + this.syncMapModeUI(); + } + + private syncMapModeUI(): void { + const isGlobe = this.ctx.map?.isGlobeMode(); + document.getElementById('map3dBtn')?.classList.toggle('active', isGlobe); + this.ctx.unifiedSettings?.refreshMapMode(); + } + private setupMapFullscreen(mapSection: HTMLElement): void { const btn = document.getElementById('mapFullscreenBtn'); if (!btn) return; diff --git a/src/app/panel-layout.ts b/src/app/panel-layout.ts index fdbfa404d..7248d05be 100644 --- a/src/app/panel-layout.ts +++ b/src/app/panel-layout.ts @@ -214,6 +214,9 @@ export class PanelLayoutManager implements AppModule {
+ diff --git a/src/components/UnifiedSettings.ts b/src/components/UnifiedSettings.ts index 62e7ad9fd..d8dc76183 100644 --- a/src/components/UnifiedSettings.ts +++ b/src/components/UnifiedSettings.ts @@ -217,6 +217,13 @@ export class UnifiedSettings { if (this.activeTab === 'panels') this.renderPanelsTab(); } + public refreshMapMode(): void { + if (this.activeTab === 'general') { + const cb = this.overlay.querySelector('#us-globe-mode') as HTMLInputElement; + if (cb) cb.checked = this.config.isGlobeMode?.() ?? false; + } + } + public getButton(): HTMLButtonElement { const btn = document.createElement('button'); btn.className = 'unified-settings-btn'; diff --git a/src/locales/en.json b/src/locales/en.json index 1f75d61d7..680b5d378 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -80,14 +80,7 @@ "noSignals": "No recent high-severity signals.", "assessmentUnavailable": "Assessment unavailable.", "noNews": "No recent country-specific coverage.", - "noMarkets": "No active markets for this country.", "noIndicators": "No country-specific indicators available.", - "components": { - "unrest": "Unrest", - "conflict": "Conflict", - "security": "Security", - "information": "Information" - }, "nearbyPorts": "Nearby Ports", "detected": "Detected", "notDetected": "No", @@ -139,6 +132,7 @@ "downloadApp": "Download App", "fullscreen": "Fullscreen", "pinMap": "Pin map to top", + "globeMode": "3D Globe Mode", "viewOnGitHub": "View on GitHub", "filterSources": "Filter sources...", "sourcesEnabled": "{{enabled}}/{{total}} enabled", @@ -2305,4 +2299,4 @@ "refresh": "Refresh", "all": "All" } -} +} \ No newline at end of file diff --git a/src/styles/main.css b/src/styles/main.css index f2df3b582..b7d1bd547 100644 --- a/src/styles/main.css +++ b/src/styles/main.css @@ -952,13 +952,21 @@ canvas, background: transparent; border: 1px solid var(--border); color: var(--text-dim); - padding: 4px 8px; + width: 26px; + height: 26px; + padding: 0; border-radius: 4px; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 0.2s; + flex-shrink: 0; +} + +#map3dBtn { + font-size: 9px; + font-weight: bold; } .map-pin-btn:hover { @@ -2212,7 +2220,7 @@ body.live-news-fullscreen-active .map-legend { display: none !important; } -body.live-news-fullscreen-active .panels-grid > *:not(.live-news-fullscreen) { +body.live-news-fullscreen-active .panels-grid>*:not(.live-news-fullscreen) { visibility: hidden !important; } @@ -12511,8 +12519,15 @@ a.prediction-link:hover { } @keyframes globe-beta-pulse { - 0%, 100% { box-shadow: 0 0 6px rgba(0, 229, 255, 0.3), 0 0 20px rgba(0, 229, 255, 0.15), inset 0 0 8px rgba(0, 229, 255, 0.05); } - 50% { box-shadow: 0 0 10px rgba(0, 229, 255, 0.5), 0 0 30px rgba(0, 229, 255, 0.25), inset 0 0 12px rgba(0, 229, 255, 0.1); } + + 0%, + 100% { + box-shadow: 0 0 6px rgba(0, 229, 255, 0.3), 0 0 20px rgba(0, 229, 255, 0.15), inset 0 0 8px rgba(0, 229, 255, 0.05); + } + + 50% { + box-shadow: 0 0 10px rgba(0, 229, 255, 0.5), 0 0 30px rgba(0, 229, 255, 0.25), inset 0 0 12px rgba(0, 229, 255, 0.1); + } } /* deck.gl Controls */ @@ -16561,7 +16576,18 @@ body.has-breaking-alert .panels-grid { } @keyframes globe-pulse { - 0% { transform: scale(1); opacity: 0.6; } - 70% { transform: scale(2.5); opacity: 0; } - 100% { transform: scale(2.5); opacity: 0; } -} + 0% { + transform: scale(1); + opacity: 0.6; + } + + 70% { + transform: scale(2.5); + opacity: 0; + } + + 100% { + transform: scale(2.5); + opacity: 0; + } +} \ No newline at end of file