Commit Graph

291 Commits

Author SHA1 Message Date
Hasan AlDoy
02f3fe77a9 feat: Arabic font support and HLS live streaming UI (#1020)
* feat: enhance support for HLS streams and update font styles

* chore: add .vercelignore to exclude large local build artifacts from Vercel deploys

* chore: include node types in tsconfig to fix server type errors on Vercel build

* fix(middleware): guard optional variant OG lookup to satisfy strict TS

* fix: desktop build and live channels handle null safety

- scripts/build-sidecar-sebuf.mjs: Skip building removed [domain]/v1/[rpc].ts (removed in #785)
- src/live-channels-window.ts: Add optional chaining for handle property to prevent null errors
- src-tauri/Cargo.lock: Bump version to 2.5.24

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix: address review issues on PR #1020

- Remove AGENTS.md (project guidelines belong to repo owner)
- Restore tracking script in index.html (accidentally removed)
- Revert tsconfig.json "node" types (leaks Node globals to frontend)
- Add protocol validation to isHlsUrl() (security: block non-http URIs)
- Revert Cargo.lock version bump (release management concern)

* fix: address P2/P3 review findings

- Preserve hlsUrl for HLS-only channels in refreshChannelInfo (was
  incorrectly clearing the stream URL on every refresh cycle)
- Replace deprecated .substr() with .substring()
- Extract duplicated HLS display name logic into getChannelDisplayName()

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Elie Habib <elie.habib@gmail.com>
2026-03-05 10:16:43 +04:00
Elie Habib
27bb5793da fix: raise modal overlay z-index above globe WebGL canvas (#1022)
The settings and signal modal overlays had z-index: 1000, which was
lower than the stacking context created by the globe's WebGL canvas
container. Bump both to z-index: 9999 to match other fullscreen overlays.
2026-03-04 23:33:44 +04:00
Elie Habib
cfc282bd88 fix: hide redundant header search icon on mobile (FAB is primary) (#1008) 2026-03-04 21:16:14 +04:00
ValMtp
6fb227db00 feat: add JSON export and import for settings persistence (#800)
* feat: add JSON export and import for settings persistence

* Update src/components/UnifiedSettings.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/utils/settings-persistence.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/settings-main.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* feat: Add localization for unified settings data management, export, and import.

* fix(settings): address PR feedback on export/import security and i18n

* style(i18n): ensure trailing newline in locale files

* fix: address review feedback on settings export/import

- Replace denylist with allowlist of known settings key prefixes
- Add version check and Array.isArray guard on import
- Remove window.alert/confirm — use inline toast and setActionStatus
- Restore deleted countryBrief.noMarkets and components i18n keys
- Move settings i18n keys to components.settings namespace
- Replace inline styles with CSS classes
- Return ImportResult from importSettings for caller feedback

---------

Co-authored-by: ValMtp3 <ValMtp3@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Elie Habib <elie.habib@gmail.com>
2026-03-04 20:46:50 +04:00
Elie Habib
1e670a08ed feat: add mobile search FAB and cleaner mobile results (#998)
- Add 56px accent-blue floating action button (bottom-right)
- Always visible regardless of scroll or horizontal overflow
- Hide subtitles and type badges on mobile results for cleaner look
- Wire FAB to same openSearch handler as header icon
2026-03-04 20:12:03 +04:00
Elie Habib
05e1e9d6b1 fix: improve mobile search bottom sheet UX (#988)
* feat: add mobile bottom sheet search with trigger bar

Replace the desktop-only Cmd+K search modal with a native-feeling
bottom sheet on mobile (<768px). Adds a fixed pill-shaped trigger
bar at the bottom of the screen, suggestion chips for quick access
to countries/commands, 48px touch targets, and slide-up animation.

Also removes the deprecated MobileWarningModal, adds a community
discussion link in settings, and improves mobile header layout.

* fix: improve mobile search bottom sheet UX

- Remove redundant trigger pill (header search icon is primary entry)
- Reduce sheet height from 75vh to 50vh for half-sheet feel
- Cap mobile results to 5 (2 per type) to avoid overwhelming small screens
- Add visualViewport listener for iOS keyboard-aware sheet resizing
- Replace clipped "Cancel" text with × icon + aria-label
- Hide chips on first keystroke to preserve vertical space
- Show 2 tips instead of 4 on mobile
- Revert panels-grid padding-bottom (no longer needed without pill)
2026-03-04 17:33:00 +04:00
Elie Habib
cdb311ae78 Fix mobile horizontal overflow from deck.gl legend (#987)
* fix(mobile): prevent deckgl legend overflow

* fix: clean up redundant CSS in mobile legend override

Remove redundant max-width (left/right already constrains) and fix
gap shorthand overwriting row-gap (use gap: 6px 8px instead).
2026-03-04 17:31:15 +04:00
Elie Habib
aaf06cae79 fix(webcams): recover from blocked/stuck YouTube embeds (#986)
* enhance supply chain panel

* fix(supply-chain): resolve P1 threat zeroing and P2 geo-first misclassification

P1: threat baseline is now always applied regardless of config
staleness — stale config only adds a review-recommended note,
never zeros the score.

P2: resolveChokepointId now checks text evidence first and only
falls back to proximity when text has no confident match.

Adds regression test: text "Bab el-Mandeb" with location near
Suez correctly resolves to bab_el_mandeb.

* fix(webcams): recover from blocked/stuck youtube embeds

---------

Co-authored-by: fayez bast <fayezbast15@gmail.com>
2026-03-04 15:15:19 +04:00
Elie Habib
ea8d64a042 feat: add mobile bottom sheet search with trigger bar (#985)
Replace the desktop-only Cmd+K search modal with a native-feeling
bottom sheet on mobile (<768px). Adds a fixed pill-shaped trigger
bar at the bottom of the screen, suggestion chips for quick access
to countries/commands, 48px touch targets, and slide-up animation.

Also removes the deprecated MobileWarningModal, adds a community
discussion link in settings, and improves mobile header layout.
2026-03-04 15:12:44 +04:00
Elie Habib
a751af792b feat: add mobile hamburger menu with slide-out drawer and region bottom sheet (#981)
Replace crowded mobile header with clean hamburger-menu pattern:
- Hamburger button + search icon in minimal header row (≤768px)
- Slide-out drawer with variant switching, region, settings, theme toggle
- Region bottom sheet with touch-friendly options
- Proper scroll lock, Escape key, backdrop dismiss
- Theme sync via theme-changed event listener
- i18n support for all labels
2026-03-04 14:12:25 +04:00
Elie Habib
280dca7b49 feat: add search bar to manage channels and AlJazeera Arabic channel (#978)
Add real-time search/filter for available channels in the manage channels
window, with debounced input, per-region match counts, and empty state.
Also adds AlJazeera Arabic to the Middle East region with HLS stream.
2026-03-04 13:21:32 +04:00
Elie Habib
1bbf9c12c1 Revert "Manage channels search bar" (#977) 2026-03-04 12:58:18 +04:00
danielimad
c465771f57 feat: Remove 3D globe mode functionality and the country brief section, while adding new localization strings. 2026-03-04 11:34:10 +04:00
0xDanielimad
7c43db87e7 Merge branch 'koala73:main' into manage-channels-search-bar 2026-03-04 09:19:58 +04:00
danielimad
49697a9ab3 feat: Add search functionality to available channels and include Al Jazeera Arabic. 2026-03-04 09:17:24 +04:00
danielimad
2eee68b23d feat: Add 3D globe mode toggle button with map switching logic, UI synchronization, and localization. 2026-03-04 09:08:18 +04:00
0xDanielimad
2ce9cb6c26 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>
2026-03-04 08:34:02 +04:00
Elie Habib
15f922beda 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
2026-03-04 08:26:19 +04:00
Elie Habib
67c4ef4d9f fix(mobile): swipeable toolbars for live news + webcams (#955) 2026-03-04 07:28:54 +04:00
Elie Habib
35720223e5 feat(globe): add render quality setting (4K pixel ratio) (#951)
* feat(globe): add render quality setting (pixel ratio)

* fix(globe): apply render scale from event payload

* fix(globe): localize quality settings and tune renderer defaults

* refactor(globe): unify resize path for pixel ratio updates
2026-03-04 07:18:52 +04:00
Elie Habib
30e6022959 feat(mobile): full-viewport map with geolocation centering (#942) 2026-03-04 05:24:27 +04:00
sahildhargave-byte
7958636ba2 fix: i18n error strings, hide map overlays in fullscreen (#934)
* fix: i18n error strings, hide map overlays in fullscreen

* fix: update package-lock.json for three library and enhance CSS for fullscreen overlays

* fix: resolve duplicate import, catch block order, property shadowing

- Remove duplicate STORAGE_KEYS/SITE_VARIANT import in LiveNewsPanel
- Restore isConnected guard before DOM write in NewsPanel catch block
- Rename IDLE_PAUSE_MS property to idlePauseMs to avoid shadowing import
- Restore readonly on debouncedUrlSync
- Revert unrelated package-lock.json peer flag changes

---------

Co-authored-by: Elie Habib <elie.habib@gmail.com>
2026-03-04 00:22:30 +04:00
danielimad
d44ab97f54 refactor: Streamline map destruction logic, remove redundant map resizing calls, and format CSS keyframe rules. 2026-03-04 00:15:12 +04:00
0xDanielimad
6f2f9dff79 Merge branch 'main' into instability-country-navigation 2026-03-03 22:38:05 +04:00
danielimad
247c65cc20 feat: enable country clicks in the CII panel to open country briefs and add hover styling for clickable countries on maps. 2026-03-03 22:35:16 +04:00
Elie Habib
8faa1fb046 feat(globe): add glowing Beta badge to 3D globe controls (#927)
* feat(globe): add glowing Beta badge to 3D globe controls

Cyan pulsing badge appears top-right above zoom controls, only when
the globe view is active.

* feat(mobile): replace GitHub icon with settings gear on mobile header

On screens ≤768px, hide the GitHub link and show a gear icon that
opens UnifiedSettings — giving mobile users quick access to settings
from the compact header row.
2026-03-03 21:43:13 +04:00
Elie Habib
034ab9916f feat(globe): add interactive 3D globe view with 28 live data layers (#926)
* feat(globe): add 3D globe view powered by globe.gl

Replicate the Sentinel.axonia.us globe locally and expose it via Settings.

- Add GlobeMap.ts: new globe.gl v2 component with night-sky starfield,
  earth topobathy texture, specular water map, atmosphere glow, auto-rotate
  (pauses on interaction, resumes after 60 s), and HTML marker layer for
  conflict zones, intel hotspots, and other data categories
- Update MapContainer with switchToGlobe() / switchToFlat() runtime
  methods and isGlobeMode() query; constructor accepts preferGlobe param
- Wire globe toggle in UnifiedSettings General tab (MAP section);
  persisted to worldmonitor-map-mode via loadFromStorage/saveToStorage
- Add mapMode storage key to STORAGE_KEYS
- Download earth textures to public/textures/ (topo-bathy, night-sky,
  water specular, day)
- Add globe.gl ^2.45.0 and @types/three dependencies
- Add globe CSS + @keyframes globe-pulse for pulsing conflict markers

* feat(globe): wire region selector & CMD+K navigation to 3D globe

* feat(globe): add zoom controls, layer panel, marker tooltips; fix Vercel build

* feat(globe): expand to all 28 world-variant layers with live data rendering

* refactor(globe): use proper keyof MapLayers types

* fix(globe): route AIS/flight data to globe, implement ship traffic markers, hide dayNight toggle

- MapContainer: add globe guard to setAisData and setFlightDelays (data was silently dropped)
- GlobeMap: implement setAisData with AisDisruptionMarker (typed, no any casts); renders
  disruption events with severity-colored ship icons and full tooltip (name/type/severity)
- GlobeMap: three-point dayNight suppression — disabled in initGlobe(), overridden in
  setLayers(), ignored in enableLayer(); toggle removed from layer panel UI
- MapContainer: add globe guards to 5 happy-variant setters (P3: keep no-op stubs in globe)
- Add tests/globe-2d-3d-parity.test.mjs: 13 static-analysis tests covering routing,
  AIS marker fields, and dayNight suppression (all passing)
2026-03-03 21:08:06 +04:00
Elie Habib
e0a3ca5b62 Revert "feat: widget picker, layout tabs & panel close buttons (#882) (#890)" (#918)
This reverts commit c99314ae09.
2026-03-03 18:26:16 +04:00
Elie Habib
349e4b6017 fix(map): show zoom-in hint on layer toggles hidden by zoom threshold (#913) 2026-03-03 16:02:04 +04:00
Nicolas Dos Santos
c48dede890 fix: enable pinch-to-zoom on Android for map (#868) (#896)
Add `touch-action: none` to .map-container, .deckgl-map-wrapper, and
#deckgl-basemap so the browser does not intercept pinch/pan gestures on
Android. MapLibre (and deck.gl via MapboxOverlay) already handle these
touch interactions internally; the missing CSS property caused the
browser to claim the gestures for native page zoom instead.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 15:26:04 +04:00
Nicolas Dos Santos
c99314ae09 feat: widget picker, layout tabs & panel close buttons (#882) (#890)
* docs: add widget picker & layout presets design for #882

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add widget picker implementation plan (#882)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add layout presets config (#882)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add i18n keys for layout presets (#882)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add LayoutTabs component (#882)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add WidgetPicker popover component (#882)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add close button to panel headers (#882)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: wire LayoutTabs and WidgetPicker into header (#882)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: remove Settings > Panels tab, replaced by widget picker (#882)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add layout presets validation tests (#882)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 14:12:23 +04:00
0xDanielimad
ea6874d6d7 feat: enhance map resizing with automatic container observation, top-edge pinning, and responsive height adjustments (#888)
* 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.
2026-03-03 12:56:14 +04:00
0xDanielimad
2aae0a5065 Merge branch 'koala73:main' into stabilize-map 2026-03-03 12:26:38 +04:00
danielimad
c9af929281 feat: enhance map resizing with automatic container observation, top-edge pinning, and responsive height adjustments. 2026-03-03 12:25:09 +04:00
Nicolas Dos Santos
7373135978 fix: resolve build errors and fullscreen overlay bugs (#857, #859, #860, #829)
Add missing supercluster, preact, @types/geojson, and @types/supercluster dependencies. Remove DOM reparenting in LiveNewsPanel fullscreen toggle that caused iframe reloads and channel switching. Hide sibling panels and map overlays when a panel is in fullscreen mode.
2026-03-03 09:56:25 +04:00
Elie Habib
e444783def feat(country-brief): add native browser share button to small & large briefs (#854)
Add Web Share API button to both CountryDeepDivePanel (small brief) and
CountryBriefPage (large brief). Falls back to clipboard copy with a
checkmark flash when navigator.share is unavailable. Shares the deep
link URL (?c=CODE) with the country name as title.
2026-03-03 03:24:49 +04:00
Vittorio Halfon
fadfe6ffd5 feat: add reset layout button to restore default panel sizes and order (#801)
Adds a "Reset Layout" button in Settings > Panels tab that clears all
saved panel heights, widths, map height, and ordering from localStorage,
then reloads to apply defaults. Includes i18n translations for all 19 locales.

Closes #797

Co-Authored-By: Vittorio Halfon <vittoriohalfon01@gmail.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-03 00:41:32 +04:00
0xDanielimad
f712717943 Extend support for larger screens (#740)
* feat: Implement dynamic map resizing with a bottom panel grid for ultra-wide layouts and double-click resize.

* feat: Dynamically adjust panel layout based on map visibility and screen width, including new CSS for map-hidden state.
2026-03-02 13:18:05 +04:00
Elie Habib
cd9bae7aeb feat(live-news): improve Manage Channels UX — toggle from grid + show all channels (#745)
Make the Available Channels grid the primary way to toggle channels on/off:
- Add 10 default channels (Bloomberg, SkyNews, DW, etc.) to the grid
- Add "All" region tab showing every channel (with i18n for 19 locales)
- Grid cards are now toggleable: click ✓ to remove, click + to add
- Hover on added cards shows ✕ with red tint to signal removal
- Top pills get × close button on hover for quick removal
- Click-to-edit gated to custom channels only (builtins use grid toggle)
- Fix France24 default to use French channel (@FRANCE24)

UX polish:
- Tighten header/content whitespace (padding, gaps, margins reduced)
- Align settings gear icon to top of pill row (flex-start)
- Add ESC dismiss to all modals (channels, story, signal, findings)
- SignalModal ESC listener properly added on show, removed on hide
2026-03-02 12:56:17 +04:00
Elie Habib
acf1390a93 refactor(ui): green download button + retire sliding popup (#747)
The header download button now uses the same green color scheme as the
old "DESKTOP AVAILABLE" popup, making it more visible. The redundant
sliding popup is removed since the header dropdown serves the same purpose.
2026-03-02 12:55:51 +04:00
Elie Habib
8a414228b4 fix: harden windows installer update path and map resize behavior (#739) 2026-03-02 11:33:24 +04:00
Elie Habib
bb31b4312e feat(header): download button dropdown + move system status into settings (#735)
- Download button shows detected platform label (e.g. " Silicon")
- Click opens dropdown with primary platform download + "show all" toggle
- Platform-colored buttons: green/mac, blue/windows, amber/linux
- Move System Status panel from header dropdown into Settings as new tab
- Remove status toggle button from header (settings gear covers it)
- Change "Copy Link" → "Link" in header for brevity
2026-03-02 10:53:06 +04:00
Elie Habib
f4e1159a18 feat(header): add Download App button for web users (#734)
Adds a download button in the header (web-only) that detects the user's
platform via navigator.userAgentData (with navigator.platform fallback)
and opens the correct installer URL. Hidden on mobile viewports.

Co-authored-by: AaronCorkyj <AaronCorkyj@users.noreply.github.com>
2026-03-02 10:12:24 +04:00
Elie Habib
897033570f fix: suppress map renders during resize drag (#728)
* fix: suppress map renders during resize drag for smoother UX

- Add isResizing flag to DeckGLMap and MapComponent
- Suppress ResizeObserver callbacks during active drag
- Set trackResize: false on maplibre to prevent redundant resizes
- Move render() call from mousemove to mouseup (single clean render)
- Add overflow: hidden to .map-section to prevent visual overflow
- Lower minimum map height from 400px to 350px

Co-authored-by: danielimad <daniel_t_air@hotmail.com>

* fix: prevent stuck isResizing via centralized endResize

Extract endResize() and trigger from mouseup, window blur, and
visibilitychange to prevent permanently suppressed ResizeObserver
if mouseup is missed (e.g. alt-tab during drag).

---------

Co-authored-by: danielimad <daniel_t_air@hotmail.com>
2026-03-02 09:56:42 +04:00
Elie Habib
12f481b5b5 fix(panel): live news fullscreen now renders above all UI elements (#708)
Move panel element to document.body when entering fullscreen to escape
the panels-grid stacking context (z-index: 1) that trapped it below
the map legend, DEFCON badge, time selector, and layers panel.
2026-03-02 02:02:37 +04:00
Vittorio Halfon
7d4eeb74d0 fix(web): improve mobile responsiveness — collapsible map, panel sizing, font bump (#688)
* fix(web): improve mobile responsiveness — collapsible map, panel sizing, font bump (#354)

- Add Show/Hide Map toggle on mobile (collapsed by default, persisted in localStorage)
- Increase panel max-height from 400px to 70vh and add iOS smooth scrolling
- Bump mobile font sizes to 13-14px for readability
- All changes scoped to ≤768px media query or isMobile guard

Closes #354

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(mobile): i18n map toggle, cap panel height, reduce !important

- Replace hardcoded "Show Map"/"Hide Map" with t() i18n calls
  and ▶/▼ chevron prefix for universal clarity
- Add components.map.showMap/hideMap keys to all 18 locales
  (ar, de, el, en, es, fr, it, ja, ko, nl, pl, pt, ru, sv, th, tr, vi, zh)
- Clarify localStorage default: explicit null check instead of
  double-negative !== 'false'
- Cap panel max-height at min(70vh, 500px) to prevent single
  panel from consuming full viewport on tall phones
- Reduce !important in collapsed map styles by raising specificity
  via .main-content ancestor selector

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Elie Habib <elie.habib@gmail.com>
2026-03-01 23:04:09 +04:00
Elie Habib
dcd7050078 feat(live-news): add Fox News HLS stream & fullscreen toggle (#689)
* feat(live-news): add Fox News HLS stream & fullscreen toggle for panels/map

- Add Fox News HLS direct stream (247preview.foxnews.com) to bypass
  YouTube embedding restrictions (error 150)
- Remove isDesktopRuntime() gate from resolveChannelVideo so direct HLS
  streams work in browser, not just desktop app
- Remove useFallbackOnly from Fox News channel config
- Add fullscreen maximize button to Live News, Live Webcams, and Global
  Situation map panels — click to expand, ESC to exit

* fix(map): use map-pin-btn style for map fullscreen button visibility

* fix(map): group fullscreen and pin buttons in flex container

Wrap the fullscreen and pin buttons in a flex div so they stay
together on the right side of the map header instead of being
spread apart by justify-content: space-between.
2026-03-01 22:43:40 +04:00
Elie Habib
45b00e9d7d feat(settings): badge pulse animation with settings toggle (#676)
* feat: animate panel count badge on new data arrival

* feat(settings): gate badge pulse animation behind toggle (off by default)

PR #671 adds CSS pulse on panel count badges. This commit gates it
behind a new `badgeAnimation` setting in UnifiedSettings so users
opt-in. Adds i18n keys for all 18 locales.

---------

Co-authored-by: jeronlxj <jeronliaw@u.nus.edu>
2026-03-01 19:21:36 +04:00
Elie Habib
e45a19937b feat(market): add Gulf Economies panel with GCC indices, currencies & oil (#667)
* feat(market): add Gulf Economies panel with GCC indices, currencies & oil

Add a new panel tracking 15 Gulf/GCC financial symbols via Yahoo Finance:
- 7 stock indices (TASI, DFMGI, ADX, QSI, Bahrain, Kuwait, MSM)
- 6 currencies (SAR, AED, QAR, KWD, BHD, OMR vs USD)
- 2 oil benchmarks (WTI, Brent)

Server: new ListGulfQuotes RPC with 3-tier caching (in-memory + Redis
via cachedFetchJson + stale fallback). Uses fetchYahooQuotesBatch for
rate-limit-safe sequential fetching.

Frontend: GulfEconomiesPanel with 3 collapsible sections, sparklines,
8s delayed start, 60s polling. Registered in both full and finance
variants.

Inspired by #641 (credit: @aa5064, commit 684a73c).

* refactor: hoist MarketServiceClient to module scope, clarify memCache closure

* fix(market): register list-gulf-quotes in RPC_CACHE_TIER map

Explicitly set 'medium' cache tier for the new Gulf quotes endpoint,
matching other market RPCs instead of relying on the implicit default.

* refactor: extract shared miniSparkline to @/utils/sparkline

Deduplicates the identical function from MarketPanel and GulfEconomiesPanel
into a single shared utility.

* fix(panels): disable gulf-economies by default on full variant

Panel remains always-on for finance variant. Full variant users can
manually enable it via panel settings.
2026-03-01 18:24:53 +04:00
Elie Habib
3c41417471 feat(telegram): add Telegram Intel panel (#550)
* feat(telegram): add Telegram Intel panel consuming relay feed

- Service layer: fetchTelegramFeed() with 30s cache, types matching relay shape
- Panel component: topic filter tabs, safe DOM rendering via h()+replaceChildren()
- DataLoader + RefreshScheduler pattern (60s interval, hidden-tab aware)
- Handles enabled=false and empty states from relay
- CSS following existing gdelt-intel pattern
- Panel title localized across all 18 locales

* fix(i18n): add components.telegramIntel translations to 10 remaining locales
2026-02-28 18:58:23 +04:00