Instability country navigation (#932)

* feat: enhance map resizing with automatic container observation, top-edge pinning, and responsive height adjustments.

* fix: Correct map resizing and prevent duplicate transition end events during height adjustments.

* feat: enable country clicks in the CII panel to open country briefs and add hover styling for clickable countries on maps.

* feat: Add globe map resize support and refactor map resize event handling logic.

* refactor: Streamline map destruction logic, remove redundant map resizing calls, and format CSS keyframe rules.

* fix: revert unintended destroy() behavior change and CSS formatting noise

- destroy(): restore unconditional cleanup of all map instances (safer
  for edge cases where stale refs might exist after mode switches)
- Revert cosmetic CSS changes: combinator spacing, keyframe
  reformatting, missing newline at EOF

---------

Co-authored-by: Elie Habib <elie.habib@gmail.com>
This commit is contained in:
0xDanielimad
2026-03-04 08:34:02 +04:00
committed by GitHub
parent 8840242b88
commit 2ce9cb6c26
6 changed files with 40 additions and 2 deletions

View File

@@ -300,6 +300,10 @@ export class App {
this.panelLayout = new PanelLayoutManager(this.state, {
openCountryStory: (code, name) => this.countryIntel.openCountryStory(code, name),
openCountryBrief: (code) => {
const name = CountryIntelManager.resolveCountryName(code);
void this.countryIntel.openCountryBriefByCode(code, name);
},
loadAllData: () => this.dataLoader.loadAllData(),
updateMonitorResults: () => this.dataLoader.updateMonitorResults(),
loadSecurityAdvisories: () => this.dataLoader.loadSecurityAdvisories(),

View File

@@ -162,6 +162,7 @@ export class CountryIntelManager implements AppModule {
this.ctx.countryBriefPage.show(country, code, score, signals);
this.ctx.map?.highlightCountry(code);
this.ctx.map?.fitCountry(code);
if (opts?.maximize) {
requestAnimationFrame(() => {

View File

@@ -66,6 +66,7 @@ import { trackCriticalBannerAction } from '@/services/analytics';
export interface PanelLayoutCallbacks {
openCountryStory: (code: string, name: string) => void;
openCountryBrief: (code: string) => void;
loadAllData: () => Promise<void>;
updateMonitorResults: () => void;
loadSecurityAdvisories?: () => Promise<void>;
@@ -572,6 +573,9 @@ export class PanelLayoutManager implements AppModule {
ciiPanel.setShareStoryHandler((code, name) => {
this.callbacks.openCountryStory(code, name);
});
ciiPanel.setCountryClickHandler((code) => {
this.callbacks.openCountryBrief(code);
});
this.ctx.panels['cii'] = ciiPanel;
const cascadePanel = new CascadePanel();

View File

@@ -8,6 +8,7 @@ export class CIIPanel extends Panel {
private scores: CountryScore[] = [];
private focalPointsReady = false;
private onShareStory?: (code: string, name: string) => void;
private onCountryClick?: (code: string) => void;
constructor() {
super({
@@ -22,6 +23,10 @@ export class CIIPanel extends Panel {
this.onShareStory = handler;
}
public setCountryClickHandler(handler: (code: string) => void): void {
this.onCountryClick = handler;
}
private getLevelColor(level: CountryScore['level']): string {
switch (level) {
case 'critical': return getCSSColor('--semantic-critical');
@@ -82,14 +87,25 @@ export class CIIPanel extends Panel {
}
private bindShareButtons(): void {
if (!this.onShareStory) return;
if (!this.onShareStory && !this.onCountryClick) return;
this.content.querySelectorAll('.cii-country').forEach(el => {
el.addEventListener('click', (e) => {
const target = e.currentTarget as HTMLElement;
const code = target.dataset.code;
if (code && this.onCountryClick) {
this.onCountryClick(code);
}
});
});
this.content.querySelectorAll('.cii-share-btn').forEach(btn => {
btn.addEventListener('click', (e) => {
e.stopPropagation();
const el = e.currentTarget as HTMLElement;
const code = el.dataset.code || '';
const name = el.dataset.name || '';
if (code && name) this.onShareStory!(code, name);
if (code && name && this.onShareStory) this.onShareStory(code, name);
});
});
}

View File

@@ -196,6 +196,10 @@ export class MapContainer {
}
public resize(): void {
if (this.useGlobe) {
this.globeMap?.resize();
return;
}
if (this.useDeckGL) {
this.deckGLMap?.resize();
} else {

View File

@@ -9933,6 +9933,14 @@ a.prediction-link:hover {
background: var(--darken-medium);
border-radius: 4px;
padding: 8px;
cursor: pointer;
transition: background 0.1s ease, border-color 0.1s ease;
border: 1px solid transparent;
}
.cii-country:hover {
background: var(--surface-hover);
border-color: var(--border);
}
.cii-header {
@@ -16619,6 +16627,7 @@ body.has-breaking-alert .panels-grid {
-webkit-box-orient: vertical;
overflow: hidden;
}
/* ─── Globe Map Styles ──────────────────────────────────────────────────────── */
.globe-mode {