mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-04-25 17:14:57 +02:00
Variant/commodity (#1040)
* commod variants * mining map layers complete * metal news feed * commod variant final * readme update * fix: clean up commodity variant for merge readiness - Remove duplicate FEEDS definition (central feeds.ts is source of truth) - Remove duplicate inline ALLOWED_DOMAINS in rss-proxy.js (use shared module) - Add 14 commodity RSS domains to shared/rss-allowed-domains.json - Remove invalid geopoliticalBoundaries property (not in MapLayers type) - Fix broken mobile-map-integration-harness imports - Remove Substack credit link from app header - Rename i18n key commod → commodity - Extract mineralColor() helper for DRY color mapping - Add XSS-safe tooltips for mining sites, processing plants, commodity ports - Add missing interface fields (annualOutput, materials, capacityTpa, annualVolumeMt) - Comment out unused COMMODITY_MINERS export - Isolate commodity DeckGL changes from unrelated basemap refactor * fix: hide commodity variant from selector until testing complete Only show the commodity option in the variant switcher when the user is already on the commodity variant (same pattern as happy variant). Other variants (full, tech, finance) won't see the commodity link. --------- Co-authored-by: jroachell <jianyin.roachell@siriusxm.com> Co-authored-by: Elie Habib <elie.habib@gmail.com>
This commit is contained in:
59
README.md
59
README.md
@@ -13,6 +13,7 @@
|
||||
<a href="https://worldmonitor.app"><img src="https://img.shields.io/badge/Web_App-worldmonitor.app-blue?style=for-the-badge&logo=googlechrome&logoColor=white" alt="Web App"></a>
|
||||
<a href="https://tech.worldmonitor.app"><img src="https://img.shields.io/badge/Tech_Variant-tech.worldmonitor.app-0891b2?style=for-the-badge&logo=googlechrome&logoColor=white" alt="Tech Variant"></a>
|
||||
<a href="https://finance.worldmonitor.app"><img src="https://img.shields.io/badge/Finance_Variant-finance.worldmonitor.app-059669?style=for-the-badge&logo=googlechrome&logoColor=white" alt="Finance Variant"></a>
|
||||
<a href="https://commodity.worldmonitor.app"><img src="https://img.shields.io/badge/Commodity_Variant-commodity.worldmonitor.app-b45309?style=for-the-badge&logo=googlechrome&logoColor=white" alt="Commodity Variant"></a>
|
||||
<a href="https://happy.worldmonitor.app"><img src="https://img.shields.io/badge/Happy_Variant-happy.worldmonitor.app-f59e0b?style=for-the-badge&logo=googlechrome&logoColor=white" alt="Happy Variant"></a>
|
||||
</p>
|
||||
|
||||
@@ -44,7 +45,7 @@
|
||||
| Static news feeds | **Real-time updates** with live video streams and AI-powered deductions |
|
||||
| Cloud-dependent AI tools | **Run AI locally** with Ollama/LM Studio — no API keys, no data leaves your machine. Opt-in **Headline Memory** builds a local semantic index of every headline for RAG-powered queries |
|
||||
| Web-only dashboards | **Native desktop app** (Tauri) for macOS, Windows, and Linux + installable PWA with offline map support |
|
||||
| Flat 2D maps | **Dual map engine** — photorealistic 3D globe (globe.gl + Three.js) and WebGL flat map (deck.gl) with 45 toggleable data layers, runtime-switchable. Choose from free tile providers or self-host your own |
|
||||
| Flat 2D maps | **Dual map engine** — photorealistic 3D globe (globe.gl + Three.js) and WebGL flat map (deck.gl) with 45 toggleable data layers, runtime-switchable |
|
||||
| English-only OSINT tools | **21 languages** with native-language RSS feeds, AI-translated summaries, and RTL support for Arabic |
|
||||
| Siloed financial data | **Finance variant** with 92 stock exchanges, 19 financial centers, 13 central banks, BIS data, WTO trade policy, and Gulf FDI tracking |
|
||||
| Undocumented, fragile APIs | **Proto-first API contracts** — 22 typed services with auto-generated clients, servers, and OpenAPI docs |
|
||||
@@ -58,24 +59,23 @@
|
||||
| **World Monitor** | [worldmonitor.app](https://worldmonitor.app) | Geopolitics, military, conflicts, infrastructure |
|
||||
| **Tech Monitor** | [tech.worldmonitor.app](https://tech.worldmonitor.app) | Startups, AI/ML, cloud, cybersecurity |
|
||||
| **Finance Monitor** | [finance.worldmonitor.app](https://finance.worldmonitor.app) | Global markets, trading, central banks, Gulf FDI |
|
||||
| **Commodity Monitor** | [commodity.worldmonitor.app](https://commodity.worldmonitor.app) | Mining, metals, energy commodities, critical minerals |
|
||||
| **Happy Monitor** | [happy.worldmonitor.app](https://happy.worldmonitor.app) | Good news, positive trends, uplifting stories |
|
||||
|
||||
All four variants run from a single codebase — switch between them with one click via the header bar.
|
||||
All five variants run from a single codebase — switch between them with one click via the header bar.
|
||||
|
||||
---
|
||||
|
||||
## Key Features
|
||||
|
||||
### Maps & Visualization
|
||||
|
||||
- **Dual Map Engine** — 3D globe (globe.gl + Three.js) and WebGL flat map (deck.gl), runtime-switchable with 45 shared data layers. Multiple tile providers (OpenFreeMap, CARTO, self-hosted PMTiles) selectable in Settings. [Details →](./docs/MAP_ENGINE.md)
|
||||
- **Dual Map Engine** — 3D globe (globe.gl + Three.js) and WebGL flat map (deck.gl), runtime-switchable with 45 shared data layers. [Details →](./docs/MAP_ENGINE.md)
|
||||
- **45 toggleable data layers** — conflicts, bases, cables, pipelines, flights, vessels, protests, fires, earthquakes, datacenters, and more across all variants
|
||||
- **8 regional presets** — Global, Americas, Europe, MENA, Asia, Africa, Oceania, Latin America with time filtering (1h–7d)
|
||||
- **CII choropleth heatmap** — five-stop color gradient paints every country by instability score on both map engines
|
||||
- **URL state sharing** — map center, zoom, active layers, and time range encoded in shareable URLs
|
||||
|
||||
### AI & Intelligence
|
||||
|
||||
- **World Brief** — LLM-synthesized summary with 4-tier fallback: Ollama (local) → Groq → OpenRouter → browser T5. [Details →](./docs/AI_INTELLIGENCE.md)
|
||||
- **AI Deduction & Forecasting** — free-text geopolitical analysis grounded in live headlines. [Details →](./docs/AI_INTELLIGENCE.md#ai-deduction--forecasting)
|
||||
- **Headline Memory (RAG)** — opt-in browser-local semantic index using ONNX embeddings in IndexedDB. [Details →](./docs/AI_INTELLIGENCE.md#client-side-headline-memory-rag)
|
||||
@@ -121,14 +121,12 @@ All four variants run from a single codebase — switch between them with one cl
|
||||
</details>
|
||||
|
||||
### Live News & Video
|
||||
|
||||
- **435+ RSS feeds** across geopolitics, defense, energy, tech, and finance with server-side aggregation (95% fewer edge invocations). [Details →](./docs/DATA_SOURCES.md#server-side-aggregation)
|
||||
- **30+ live video streams** — Bloomberg, Sky News, Al Jazeera, and more with HLS native streaming, idle-aware playback, and fullscreen mode
|
||||
- **22 live webcams** — geopolitical hotspot streams across 5 regions with Iran/Attacks dedicated tab
|
||||
- **Custom keyword monitors** — user-defined alerts with word-boundary matching and auto-coloring
|
||||
|
||||
### Scoring & Detection
|
||||
|
||||
- **Country Instability Index (CII)** — real-time stability scores using weighted multi-signal blend across 23 tier-1 nations + universal scoring for all countries. [Details →](./docs/ALGORITHMS.md#country-instability-index-cii)
|
||||
- **Hotspot Escalation** — dynamic scoring blending news activity, CII, geo-convergence, and military signals. [Details →](./docs/ALGORITHMS.md#hotspot-escalation-scoring)
|
||||
- **Strategic Risk Score** — composite geopolitical risk from convergence, CII, infrastructure, theater, and breaking news. [Details →](./docs/ALGORITHMS.md#strategic-risk-score-algorithm)
|
||||
@@ -136,7 +134,6 @@ All four variants run from a single codebase — switch between them with one cl
|
||||
- **Cross-Stream Correlation** — 14 signal types detecting patterns across news, markets, military, and predictions. [Details →](./docs/ALGORITHMS.md#cross-stream-correlation-engine)
|
||||
|
||||
### Finance & Markets
|
||||
|
||||
- **Macro Signal Analysis** — 7-signal market radar with composite BUY/CASH verdict. [Details →](./docs/FINANCE_DATA.md#macro-signal-analysis-market-radar)
|
||||
- **Gulf FDI** — 64 Saudi/UAE investments plotted globally. [Details →](./docs/FINANCE_DATA.md#gulf-fdi-investment-database)
|
||||
- **Stablecoin & BTC ETF** — peg health monitoring and spot ETF flow tracking. [Details →](./docs/FINANCE_DATA.md)
|
||||
@@ -144,14 +141,12 @@ All four variants run from a single codebase — switch between them with one cl
|
||||
- **BIS & WTO** — central bank rates, trade policy intelligence. [Details →](./docs/FINANCE_DATA.md)
|
||||
|
||||
### Desktop & Mobile
|
||||
|
||||
- **Native desktop app** (Tauri) — macOS, Windows, Linux with OS keychain, local sidecar, and cloud fallback. [Details →](./docs/DESKTOP_APP.md)
|
||||
- **Progressive Web App** — installable with offline map support and configurable tile providers (OpenFreeMap, CARTO, or self-hosted PMTiles)
|
||||
- **Progressive Web App** — installable with offline map support (CacheFirst tiles, 500-tile cap)
|
||||
- **Mobile-optimized map** — touch pan with inertia, pinch-to-zoom, bottom-sheet popups, GPS centering
|
||||
- **Responsive layout** — ultra-wide L-shaped layout on 2000px+, collapsible panels, mobile search sheet
|
||||
|
||||
### Platform Features
|
||||
|
||||
- **21 languages** — lazy-loaded bundles with native-language RSS feeds, AI translation, and RTL support
|
||||
- **Cmd+K command palette** — fuzzy search across 24 result types, layer presets, ~250 country commands
|
||||
- **Proto-first API contracts** — 92 proto files, 22 services, auto-generated TypeScript + OpenAPI docs
|
||||
@@ -214,20 +209,20 @@ All four variants run from a single codebase — switch between them with one cl
|
||||
|
||||
---
|
||||
|
||||
## Tri-Variant Architecture
|
||||
## Multi-Variant Architecture
|
||||
|
||||
A single codebase produces four specialized dashboards, each with distinct feeds, panels, map layers, and branding:
|
||||
A single codebase produces five specialized dashboards, each with distinct feeds, panels, map layers, and branding:
|
||||
|
||||
| Aspect | World Monitor | Tech Monitor | Finance Monitor | Happy Monitor |
|
||||
| --------------------- | ---------------------------------------------------- | ----------------------------------------------- | ------------------------------------------------ | ----------------------------------------------------- |
|
||||
| **Domain** | worldmonitor.app | tech.worldmonitor.app | finance.worldmonitor.app | happy.worldmonitor.app |
|
||||
| **Focus** | Geopolitics, military, conflicts | AI/ML, startups, cybersecurity | Markets, trading, central banks | Good news, conservation, human progress |
|
||||
| **RSS Feeds** | 15 categories, 200+ feeds (politics, MENA, Africa, think tanks) | 21 categories, 152 feeds (AI, VC blogs, startups, GitHub) | 14 categories, 55 feeds (forex, bonds, commodities, IPOs) | 5 categories, 21 positive-news sources (GNN, Positive.News, Upworthy) |
|
||||
| **Panels** | 45 (strategic posture, CII, cascade, trade policy, airline intel, predictions) | 28 (AI labs, unicorns, accelerators, tech readiness) | 27 (forex, bonds, derivatives, trade policy, gulf economies) | 10 (good news, breakthroughs, conservation, renewables, giving) |
|
||||
| **Unique Map Layers** | Military bases, nuclear facilities, hotspots | Tech HQs, cloud regions, startup hubs | Stock exchanges, central banks, Gulf investments | Positive events, kindness, species recovery, renewables |
|
||||
| **Desktop App** | World Monitor.app / .exe / .AppImage | Tech Monitor.app / .exe / .AppImage | Finance Monitor.app / .exe / .AppImage | (web-only) |
|
||||
| Aspect | World Monitor | Tech Monitor | Finance Monitor | Commodity Monitor | Happy Monitor |
|
||||
| --------------------- | ---------------------------------------------------- | ----------------------------------------------- | ------------------------------------------------ | --------------------------------------------------------- | ----------------------------------------------------- |
|
||||
| **Domain** | worldmonitor.app | tech.worldmonitor.app | finance.worldmonitor.app | commodity.worldmonitor.app | happy.worldmonitor.app |
|
||||
| **Focus** | Geopolitics, military, conflicts | AI/ML, startups, cybersecurity | Markets, trading, central banks | Mining, metals, energy commodities, critical minerals | Good news, conservation, human progress |
|
||||
| **RSS Feeds** | 15 categories, 200+ feeds (politics, MENA, Africa, think tanks) | 21 categories, 152 feeds (AI, VC blogs, startups, GitHub) | 14 categories, 55 feeds (forex, bonds, commodities, IPOs) | 10 categories, 50+ feeds (gold/silver, energy, mining, critical minerals, base metals) | 5 categories, 21 positive-news sources (GNN, Positive.News, Upworthy) |
|
||||
| **Panels** | 45 (strategic posture, CII, cascade, trade policy, airline intel, predictions) | 28 (AI labs, unicorns, accelerators, tech readiness) | 27 (forex, bonds, derivatives, trade policy, gulf economies) | 16 (live prices, sector heatmap, gold/silver, energy, mining, critical minerals, base metals, supply chain) | 10 (good news, breakthroughs, conservation, renewables, giving) |
|
||||
| **Unique Map Layers** | Military bases, nuclear facilities, hotspots | Tech HQs, cloud regions, startup hubs | Stock exchanges, central banks, Gulf investments | Mine sites, processing plants, commodity ports, commodity hubs, pipelines, trade routes | Positive events, kindness, species recovery, renewables |
|
||||
| **Desktop App** | World Monitor.app / .exe / .AppImage | Tech Monitor.app / .exe / .AppImage | Finance Monitor.app / .exe / .AppImage | (web-only) | (web-only) |
|
||||
|
||||
Single-deployment consolidation — all four variants serve from one Vercel deployment, determined by hostname. Build-time `VITE_VARIANT` tree-shakes unused data. Runtime variant selector in the header bar.
|
||||
Single-deployment consolidation — all five variants serve from one Vercel deployment, determined by hostname. Build-time `VITE_VARIANT` tree-shakes unused data. Runtime variant selector in the header bar.
|
||||
|
||||
---
|
||||
|
||||
@@ -334,7 +329,6 @@ The `.env.example` file documents every variable with descriptions and registrat
|
||||
| **Tracking** | `WINGBITS_API_KEY`, `AISSTREAM_API_KEY` | Free |
|
||||
| **Geopolitical** | `ACLED_ACCESS_TOKEN`, `CLOUDFLARE_API_TOKEN`, `NASA_FIRMS_API_KEY` | Free for researchers |
|
||||
| **Relay** | `WS_RELAY_URL`, `VITE_WS_RELAY_URL`, `OPENSKY_CLIENT_ID/SECRET` | Self-hosted |
|
||||
| **Map Tiles** | `VITE_PMTILES_URL` (optional — self-hosted PMTiles for offline/custom tiles) | Free without it (OpenFreeMap default) |
|
||||
| **UI** | `VITE_VARIANT`, `VITE_MAP_INTERACTION_MODE` (`flat` or `3d`, default `3d`) | N/A |
|
||||
| **Observability** | `VITE_SENTRY_DSN` (optional, empty disables reporting) | N/A |
|
||||
|
||||
@@ -415,7 +409,7 @@ Set `WS_RELAY_URL` (server-side, HTTPS) and `VITE_WS_RELAY_URL` (client-side, WS
|
||||
|
||||
| Category | Technologies |
|
||||
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Frontend** | Vanilla TypeScript (no framework), Vite, globe.gl + Three.js (3D globe), deck.gl + MapLibre GL + PMTiles (flat map), vite-plugin-pwa (service worker + manifest) |
|
||||
| **Frontend** | Vanilla TypeScript (no framework), Vite, globe.gl + Three.js (3D globe), deck.gl + MapLibre GL (flat map), vite-plugin-pwa (service worker + manifest) |
|
||||
| **Desktop** | Tauri 2 (Rust) with Node.js sidecar, OS keychain integration (keyring crate), native TLS (reqwest) |
|
||||
| **AI/ML** | Ollama / LM Studio (local, OpenAI-compatible), Groq (Llama 3.1 8B), OpenRouter (fallback), Transformers.js (browser-side T5, NER, embeddings), IndexedDB vector store (5K headline RAG) |
|
||||
| **Caching** | Redis (Upstash) — 3-tier cache with in-memory + Redis + upstream, cross-user AI deduplication. Vercel CDN (s-maxage). Service worker (Workbox) |
|
||||
@@ -442,14 +436,16 @@ Contributions welcome! See [CONTRIBUTING.md](./CONTRIBUTING.md) for detailed gui
|
||||
# Development
|
||||
npm run dev # Full variant (worldmonitor.app)
|
||||
npm run dev:tech # Tech variant (tech.worldmonitor.app)
|
||||
npm run dev:finance # Finance variant (finance.worldmonitor.app)
|
||||
npm run dev:happy # Happy variant (happy.worldmonitor.app)
|
||||
npm run dev:finance # Finance variant (finance.worldmonitor.app)
|
||||
npm run dev:commodity # Commodity variant (commodity.worldmonitor.app)
|
||||
npm run dev:happy # Happy variant (happy.worldmonitor.app)
|
||||
|
||||
# Production builds
|
||||
npm run build:full # Build full variant
|
||||
npm run build:tech # Build tech variant
|
||||
npm run build:finance # Build finance variant
|
||||
npm run build:happy # Build happy variant
|
||||
npm run build:full # Build full variant
|
||||
npm run build:tech # Build tech variant
|
||||
npm run build:finance # Build finance variant
|
||||
npm run build:commodity # Build commodity variant
|
||||
npm run build:happy # Build happy variant
|
||||
|
||||
# Quality (also runs automatically on PRs via GitHub Actions)
|
||||
npm run typecheck # TypeScript type checking (tsc --noEmit)
|
||||
@@ -534,7 +530,8 @@ If you discover a vulnerability, please see our [Security Policy](./SECURITY.md)
|
||||
<p align="center">
|
||||
<a href="https://worldmonitor.app">worldmonitor.app</a> ·
|
||||
<a href="https://tech.worldmonitor.app">tech.worldmonitor.app</a> ·
|
||||
<a href="https://finance.worldmonitor.app">finance.worldmonitor.app</a>
|
||||
<a href="https://finance.worldmonitor.app">finance.worldmonitor.app</a> ·
|
||||
<a href="https://commodity.worldmonitor.app">commodity.worldmonitor.app</a>
|
||||
</p>
|
||||
|
||||
## Star History
|
||||
|
||||
@@ -279,5 +279,18 @@ export default [
|
||||
"onemileatatime.com",
|
||||
"viewfromthewing.com",
|
||||
"www.aviationpros.com",
|
||||
"www.aviationweek.com"
|
||||
"www.aviationweek.com",
|
||||
"www.kitco.com",
|
||||
"www.mining.com",
|
||||
"www.commoditytrademantra.com",
|
||||
"oilprice.com",
|
||||
"www.rigzone.com",
|
||||
"www.eia.gov",
|
||||
"www.mining-journal.com",
|
||||
"www.northernminer.com",
|
||||
"www.miningweekly.com",
|
||||
"www.mining-technology.com",
|
||||
"www.australianmining.com.au",
|
||||
"news.goldseek.com",
|
||||
"news.silverseek.com"
|
||||
];
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"dev:tech": "cross-env VITE_VARIANT=tech vite",
|
||||
"dev:finance": "cross-env VITE_VARIANT=finance vite",
|
||||
"dev:happy": "cross-env VITE_VARIANT=happy vite",
|
||||
"dev:commodity": "cross-env VITE_VARIANT=commodity vite",
|
||||
"build": "tsc && vite build",
|
||||
"build:sidecar-sebuf": "node scripts/build-sidecar-sebuf.mjs",
|
||||
"build:desktop": "node scripts/build-sidecar-sebuf.mjs && tsc && vite build",
|
||||
@@ -19,6 +20,7 @@
|
||||
"build:tech": "cross-env-shell VITE_VARIANT=tech \"tsc && vite build\"",
|
||||
"build:finance": "cross-env-shell VITE_VARIANT=finance \"tsc && vite build\"",
|
||||
"build:happy": "cross-env-shell VITE_VARIANT=happy \"tsc && vite build\"",
|
||||
"build:commodity": "cross-env-shell VITE_VARIANT=commodity \"tsc && vite build\"",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"typecheck:api": "tsc --noEmit -p tsconfig.api.json",
|
||||
"typecheck:all": "tsc --noEmit && tsc --noEmit -p tsconfig.api.json",
|
||||
|
||||
@@ -261,6 +261,88 @@ export const VARIANT_FEEDS: Record<string, Record<string, ServerFeed[]>> = {
|
||||
],
|
||||
},
|
||||
|
||||
// ── Commodity variant (Mining, Metals, Energy) ─────────────────────────────
|
||||
commodity: {
|
||||
'commodity-news': [
|
||||
{ name: 'Kitco News', url: gn('site:kitco.com gold OR silver OR commodity OR metals when:1d') },
|
||||
{ name: 'Mining.com', url: 'https://www.mining.com/feed/' },
|
||||
{ name: 'Bloomberg Commodities', url: gn('site:bloomberg.com commodities OR metals OR mining when:1d') },
|
||||
{ name: 'Reuters Commodities', url: gn('site:reuters.com commodities OR metals OR mining when:1d') },
|
||||
{ name: 'S&P Global Commodity', url: gn('site:spglobal.com commodities metals when:3d') },
|
||||
{ name: 'Commodity Trade Mantra', url: gn('commodities trading metals energy gold silver when:1d') },
|
||||
{ name: 'CNBC Commodities', url: gn('site:cnbc.com (commodities OR metals OR gold OR copper) when:1d') },
|
||||
],
|
||||
'gold-silver': [
|
||||
{ name: 'Kitco Gold', url: gn('site:kitco.com gold price OR "gold market" OR "silver price" when:2d') },
|
||||
{ name: 'Gold Price News', url: gn('(gold price OR "gold market" OR bullion OR LBMA) when:1d') },
|
||||
{ name: 'Silver Price News', url: gn('(silver price OR "silver market" OR "silver futures") when:2d') },
|
||||
{ name: 'Precious Metals', url: gn('("precious metals" OR platinum OR palladium OR "gold ETF" OR GLD OR SLV) when:2d') },
|
||||
{ name: 'World Gold Council', url: gn('"World Gold Council" OR "central bank gold" OR "gold reserves" when:7d') },
|
||||
],
|
||||
energy: [
|
||||
{ name: 'OilPrice.com', url: 'https://oilprice.com/rss/main' },
|
||||
{ name: 'Rigzone', url: 'https://www.rigzone.com/news/rss/rigzone_latest.aspx' },
|
||||
{ name: 'EIA Reports', url: gn('site:eia.gov energy oil gas when:14d') },
|
||||
{ name: 'OPEC News', url: gn('(OPEC OR "oil price" OR "crude oil" OR WTI OR Brent OR "oil production") when:1d') },
|
||||
{ name: 'Natural Gas News', url: gn('("natural gas" OR LNG OR "gas price" OR "Henry Hub") when:1d') },
|
||||
{ name: 'Energy Intel', url: gn('(energy commodities OR "energy market" OR "energy prices") when:2d') },
|
||||
{ name: 'Reuters Energy', url: gn('site:reuters.com (oil OR gas OR energy) when:1d') },
|
||||
],
|
||||
'mining-news': [
|
||||
{ name: 'Mining Journal', url: gn('site:mining-journal.com when:7d') },
|
||||
{ name: 'Northern Miner', url: gn('site:northernminer.com when:7d') },
|
||||
{ name: 'Mining Weekly', url: gn('site:miningweekly.com when:7d') },
|
||||
{ name: 'Mining Technology', url: 'https://www.mining-technology.com/feed/' },
|
||||
{ name: 'Australian Mining', url: 'https://www.australianmining.com.au/feed/' },
|
||||
{ name: 'Mine Web (SNL)', url: gn('("mining company" OR "mine production" OR "mining operations") when:2d') },
|
||||
{ name: 'Resource World', url: gn('("mining project" OR "mineral exploration" OR "mine development") when:3d') },
|
||||
],
|
||||
'critical-minerals': [
|
||||
{ name: 'Benchmark Mineral', url: gn('("critical minerals" OR "battery metals" OR lithium OR cobalt OR "rare earths") when:2d') },
|
||||
{ name: 'Lithium Market', url: gn('(lithium price OR "lithium market" OR "lithium supply" OR spodumene OR LCE) when:2d') },
|
||||
{ name: 'Cobalt Market', url: gn('(cobalt price OR "cobalt market" OR "DRC cobalt" OR "battery cobalt") when:3d') },
|
||||
{ name: 'Rare Earths News', url: gn('("rare earth" OR "rare earths" OR REE OR neodymium OR praseodymium) when:3d') },
|
||||
{ name: 'EV Battery Supply', url: gn('("EV battery" OR "battery supply chain" OR "battery materials") when:3d') },
|
||||
{ name: 'IEA Critical Minerals', url: gn('site:iea.org (minerals OR critical OR battery) when:14d') },
|
||||
{ name: 'Uranium Market', url: gn('(uranium price OR "uranium market" OR U3O8 OR nuclear fuel) when:3d') },
|
||||
],
|
||||
'base-metals': [
|
||||
{ name: 'LME Metals', url: gn('(LME OR "London Metal Exchange") copper OR aluminum OR zinc OR nickel when:2d') },
|
||||
{ name: 'Copper Market', url: gn('(copper price OR "copper market" OR "copper supply" OR COMEX copper) when:2d') },
|
||||
{ name: 'Nickel News', url: gn('(nickel price OR "nickel market" OR "nickel supply" OR Indonesia nickel) when:3d') },
|
||||
{ name: 'Aluminum & Zinc', url: gn('(aluminum price OR aluminium OR zinc price OR "base metals") when:3d') },
|
||||
{ name: 'Iron Ore Market', url: gn('("iron ore" price OR "iron ore market" OR "steel raw materials") when:2d') },
|
||||
{ name: 'Metals Bulletin', url: gn('("metals market" OR "base metals" OR SHFE OR "Shanghai Futures") when:2d') },
|
||||
],
|
||||
'mining-companies': [
|
||||
{ name: 'BHP News', url: gn('BHP (mining OR production OR results OR copper OR "iron ore") when:7d') },
|
||||
{ name: 'Rio Tinto News', url: gn('"Rio Tinto" (mining OR production OR results OR Pilbara) when:7d') },
|
||||
{ name: 'Glencore & Vale', url: gn('(Glencore OR Vale) (mining OR production OR cobalt OR "iron ore") when:7d') },
|
||||
{ name: 'Gold Majors', url: gn('(Newmont OR Barrick OR AngloGold OR Agnico) (gold mine OR production OR results) when:7d') },
|
||||
{ name: 'Freeport & Copper Miners', url: gn('(Freeport McMoRan OR Southern Copper OR Teck OR Antofagasta) when:7d') },
|
||||
{ name: 'Critical Mineral Companies', url: gn('(Albemarle OR SQM OR "MP Materials" OR Lynas OR Cameco) when:7d') },
|
||||
],
|
||||
'supply-chain': [
|
||||
{ name: 'Shipping & Freight', url: gn('("bulk carrier" OR "dry bulk" OR "commodity shipping" OR "Port Hedland" OR "Strait of Hormuz") when:3d') },
|
||||
{ name: 'Trade Routes', url: gn('("trade route" OR "supply chain" OR "commodity export" OR "mineral export") when:3d') },
|
||||
{ name: 'China Commodity Imports', url: gn('China imports copper OR "iron ore" OR lithium OR cobalt OR "rare earth" when:3d') },
|
||||
{ name: 'Port & Logistics', url: gn('("iron ore port" OR "copper port" OR "commodity port" OR "mineral logistics") when:7d') },
|
||||
],
|
||||
'commodity-regulation': [
|
||||
{ name: 'Mining Regulation', url: gn('("mining regulation" OR "mining policy" OR "mining permit" OR "mining ban") when:7d') },
|
||||
{ name: 'ESG in Mining', url: gn('("mining ESG" OR "responsible mining" OR "mine closure" OR tailings) when:7d') },
|
||||
{ name: 'Trade & Tariffs', url: gn('("mineral tariff" OR "metals tariff" OR "critical mineral policy" OR "mining export ban") when:7d') },
|
||||
{ name: 'Indonesia Nickel Policy', url: gn('(Indonesia nickel OR "nickel export" OR "nickel ban" OR "nickel processing") when:7d') },
|
||||
{ name: 'China Mineral Policy', url: gn('China "rare earth" OR "mineral export" OR "critical mineral" policy OR restriction when:7d') },
|
||||
],
|
||||
markets: [
|
||||
{ name: 'Yahoo Finance Commodities', url: 'https://finance.yahoo.com/rss/topstories' },
|
||||
{ name: 'CNBC Markets', url: 'https://www.cnbc.com/id/100003114/device/rss/rss.html' },
|
||||
{ name: 'Seeking Alpha Metals', url: gn('site:seekingalpha.com (gold OR silver OR copper OR mining) when:2d') },
|
||||
{ name: 'Commodity Futures', url: gn('(COMEX OR NYMEX OR "commodity futures" OR CME commodities) when:2d') },
|
||||
],
|
||||
},
|
||||
|
||||
happy: {
|
||||
positive: [
|
||||
{ name: 'Good News Network', url: 'https://www.goodnewsnetwork.org/feed/' },
|
||||
|
||||
@@ -32,7 +32,7 @@ function getRelayHeaders(): Record<string, string> {
|
||||
return headers;
|
||||
}
|
||||
|
||||
const VALID_VARIANTS = new Set(['full', 'tech', 'finance', 'happy']);
|
||||
const VALID_VARIANTS = new Set(['full', 'tech', 'finance', 'happy', 'commodity']);
|
||||
const fallbackDigestCache = new Map<string, { data: ListFeedDigestResponse; ts: number }>();
|
||||
const ITEMS_PER_FEED = 5;
|
||||
const MAX_ITEMS_PER_CATEGORY = 20;
|
||||
|
||||
@@ -276,5 +276,18 @@
|
||||
"onemileatatime.com",
|
||||
"viewfromthewing.com",
|
||||
"www.aviationpros.com",
|
||||
"www.aviationweek.com"
|
||||
"www.aviationweek.com",
|
||||
"www.kitco.com",
|
||||
"www.mining.com",
|
||||
"www.commoditytrademantra.com",
|
||||
"oilprice.com",
|
||||
"www.rigzone.com",
|
||||
"www.eia.gov",
|
||||
"www.mining-journal.com",
|
||||
"www.northernminer.com",
|
||||
"www.miningweekly.com",
|
||||
"www.mining-technology.com",
|
||||
"www.australianmining.com.au",
|
||||
"news.goldseek.com",
|
||||
"news.silverseek.com"
|
||||
]
|
||||
|
||||
@@ -143,6 +143,15 @@ export class PanelLayoutManager implements AppModule {
|
||||
<span class="variant-icon">📈</span>
|
||||
<span class="variant-label">${t('header.finance')}</span>
|
||||
</a>
|
||||
${SITE_VARIANT === 'commodity' ? `<span class="variant-divider"></span>
|
||||
<a href="${vHref('commodity', 'https://commodity.worldmonitor.app')}"
|
||||
class="variant-option active"
|
||||
data-variant="commodity"
|
||||
${vTarget('commodity')}
|
||||
title="${t('header.commodity')} ${t('common.currentVariant')}">
|
||||
<span class="variant-icon">⛏️</span>
|
||||
<span class="variant-label">${t('header.commodity')}</span>
|
||||
</a>` : ''}
|
||||
${SITE_VARIANT === 'happy' ? `<span class="variant-divider"></span>
|
||||
<a href="${vHref('happy', 'https://happy.worldmonitor.app')}"
|
||||
class="variant-option active"
|
||||
|
||||
@@ -81,6 +81,9 @@ import {
|
||||
CENTRAL_BANKS,
|
||||
COMMODITY_HUBS,
|
||||
GULF_INVESTMENTS,
|
||||
MINING_SITES,
|
||||
PROCESSING_PLANTS,
|
||||
COMMODITY_PORTS as COMMODITY_GEO_PORTS,
|
||||
} from '@/config';
|
||||
import type { GulfInvestment } from '@/types';
|
||||
import { resolveTradeRouteSegments, TRADE_ROUTES as TRADE_ROUTES_LIST, type TradeRouteSegment } from '@/config/trade-routes';
|
||||
@@ -1346,6 +1349,17 @@ export class DeckGLMap {
|
||||
layers.push(this.createMineralsLayer());
|
||||
}
|
||||
|
||||
// Commodity variant layers — mine sites, processing plants, export ports
|
||||
if (mapLayers.miningSites) {
|
||||
layers.push(this.createMiningSitesLayer());
|
||||
}
|
||||
if (mapLayers.processingPlants) {
|
||||
layers.push(this.createProcessingPlantsLayer());
|
||||
}
|
||||
if (mapLayers.commodityPorts) {
|
||||
layers.push(this.createCommodityPortsLayer());
|
||||
}
|
||||
|
||||
// APT Groups layer (geopolitical variant only - always shown, no toggle)
|
||||
if (SITE_VARIANT !== 'tech' && SITE_VARIANT !== 'happy') {
|
||||
layers.push(this.createAPTGroupsLayer());
|
||||
@@ -2222,6 +2236,81 @@ export class DeckGLMap {
|
||||
});
|
||||
}
|
||||
|
||||
private mineralColor(mineral: string): [number, number, number, number] {
|
||||
switch (mineral) {
|
||||
case 'Gold': return [255, 215, 0, 210];
|
||||
case 'Silver': return [192, 192, 192, 200];
|
||||
case 'Copper': return [184, 115, 51, 210];
|
||||
case 'Lithium': return [0, 200, 255, 200];
|
||||
case 'Cobalt': return [100, 100, 255, 200];
|
||||
case 'Rare Earths': return [255, 100, 200, 200];
|
||||
case 'Nickel': return [100, 220, 100, 200];
|
||||
case 'Platinum': return [210, 210, 255, 200];
|
||||
case 'Palladium': return [180, 220, 180, 200];
|
||||
case 'Iron Ore': return [139, 69, 19, 210];
|
||||
case 'Uranium': return [50, 255, 80, 200];
|
||||
case 'Coal': return [80, 80, 80, 200];
|
||||
default: return [200, 200, 200, 200];
|
||||
}
|
||||
}
|
||||
|
||||
// Commodity variant layers
|
||||
private createMiningSitesLayer(): ScatterplotLayer {
|
||||
return new ScatterplotLayer({
|
||||
id: 'mining-sites-layer',
|
||||
data: MINING_SITES,
|
||||
getPosition: (d) => [d.lon, d.lat],
|
||||
getRadius: (d) => d.status === 'producing' ? 10000 : d.status === 'development' ? 8000 : 6000,
|
||||
getFillColor: (d) => this.mineralColor(d.mineral),
|
||||
radiusMinPixels: 5,
|
||||
radiusMaxPixels: 14,
|
||||
pickable: true,
|
||||
stroked: true,
|
||||
getLineColor: [255, 255, 255, 60] as [number, number, number, number],
|
||||
lineWidthMinPixels: 1,
|
||||
});
|
||||
}
|
||||
|
||||
private createProcessingPlantsLayer(): ScatterplotLayer {
|
||||
return new ScatterplotLayer({
|
||||
id: 'processing-plants-layer',
|
||||
data: PROCESSING_PLANTS,
|
||||
getPosition: (d) => [d.lon, d.lat],
|
||||
getRadius: 8000,
|
||||
getFillColor: (d) => {
|
||||
switch (d.type) {
|
||||
case 'smelter': return [255, 80, 30, 210] as [number, number, number, number];
|
||||
case 'refinery': return [255, 160, 50, 200] as [number, number, number, number];
|
||||
case 'separation': return [160, 100, 255, 200] as [number, number, number, number];
|
||||
case 'processing': return [100, 200, 150, 200] as [number, number, number, number];
|
||||
default: return [200, 150, 100, 200] as [number, number, number, number];
|
||||
}
|
||||
},
|
||||
radiusMinPixels: 5,
|
||||
radiusMaxPixels: 12,
|
||||
pickable: true,
|
||||
stroked: true,
|
||||
getLineColor: [255, 255, 255, 80] as [number, number, number, number],
|
||||
lineWidthMinPixels: 1,
|
||||
});
|
||||
}
|
||||
|
||||
private createCommodityPortsLayer(): ScatterplotLayer {
|
||||
return new ScatterplotLayer({
|
||||
id: 'commodity-ports-layer',
|
||||
data: COMMODITY_GEO_PORTS,
|
||||
getPosition: (d) => [d.lon, d.lat],
|
||||
getRadius: 12000,
|
||||
getFillColor: (d) => this.mineralColor(d.commodities[0]),
|
||||
radiusMinPixels: 6,
|
||||
radiusMaxPixels: 14,
|
||||
pickable: true,
|
||||
stroked: true,
|
||||
getLineColor: [255, 255, 255, 100] as [number, number, number, number],
|
||||
lineWidthMinPixels: 1.5,
|
||||
});
|
||||
}
|
||||
|
||||
// Tech variant layers
|
||||
private createStartupHubsLayer(): ScatterplotLayer {
|
||||
return new ScatterplotLayer({
|
||||
@@ -3008,6 +3097,22 @@ export class DeckGLMap {
|
||||
return { html: `<div class="deckgl-tooltip"><strong>${text(obj.name)}</strong><br/>${text(obj.aka)}<br/>${t('popups.sponsor')}: ${text(obj.sponsor)}</div>` };
|
||||
case 'minerals-layer':
|
||||
return { html: `<div class="deckgl-tooltip"><strong>${text(obj.name)}</strong><br/>${text(obj.mineral)} - ${text(obj.country)}<br/>${text(obj.operator)}</div>` };
|
||||
case 'mining-sites-layer': {
|
||||
const statusLabel = obj.status === 'producing' ? '⛏️ Producing' : obj.status === 'development' ? '🔧 Development' : '🔍 Exploration';
|
||||
const outputStr = obj.annualOutput ? `<br/><span style="opacity:.75">${text(obj.annualOutput)}</span>` : '';
|
||||
return { html: `<div class="deckgl-tooltip"><strong>${text(obj.name)}</strong><br/>${text(obj.mineral)} · ${text(obj.country)}<br/>${statusLabel}${outputStr}</div>` };
|
||||
}
|
||||
case 'processing-plants-layer': {
|
||||
const typeLabel = obj.type === 'smelter' ? '🏭 Smelter' : obj.type === 'refinery' ? '⚗️ Refinery' : obj.type === 'separation' ? '🧪 Separation' : '🏗️ Processing';
|
||||
const capacityStr = obj.capacityTpa ? `<br/><span style="opacity:.75">${text(String((obj.capacityTpa / 1000).toFixed(0)))}k t/yr</span>` : '';
|
||||
const mineralLabel = obj.mineral ?? (Array.isArray(obj.materials) ? obj.materials.join(', ') : '');
|
||||
return { html: `<div class="deckgl-tooltip"><strong>${text(obj.name)}</strong><br/>${text(mineralLabel)} · ${text(obj.country)}<br/>${typeLabel}${capacityStr}</div>` };
|
||||
}
|
||||
case 'commodity-ports-layer': {
|
||||
const commoditiesStr = Array.isArray(obj.commodities) ? obj.commodities.join(', ') : '';
|
||||
const volumeStr = obj.annualVolumeMt ? `<br/><span style="opacity:.75">${text(String(obj.annualVolumeMt))}Mt/yr</span>` : '';
|
||||
return { html: `<div class="deckgl-tooltip"><strong>⚓ ${text(obj.name)}</strong><br/>${text(obj.country)}<br/>${text(commoditiesStr)}${volumeStr}</div>` };
|
||||
}
|
||||
case 'ais-disruptions-layer':
|
||||
return { html: `<div class="deckgl-tooltip"><strong>AIS ${text(obj.type || t('components.deckgl.tooltip.disruption'))}</strong><br/>${text(obj.severity)} ${t('popups.severity')}<br/>${text(obj.description)}</div>` };
|
||||
case 'gps-jamming-layer':
|
||||
|
||||
1138
src/config/commodity-geo.ts
Normal file
1138
src/config/commodity-geo.ts
Normal file
File diff suppressed because it is too large
Load Diff
88
src/config/commodity-markets.ts
Normal file
88
src/config/commodity-markets.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
// Commodity variant: Expanded commodity and mining company market symbols
|
||||
// Replaces the generic COMMODITIES and MARKET_SYMBOLS for the commodity variant
|
||||
|
||||
import type { Commodity, MarketSymbol, Sector } from '@/types';
|
||||
|
||||
// Commodity-focused sector ETFs
|
||||
export const COMMODITY_SECTORS: Sector[] = [
|
||||
{ symbol: 'GDX', name: 'Gold Miners' },
|
||||
{ symbol: 'GDXJ', name: 'Jr Gold Miners' },
|
||||
{ symbol: 'XLE', name: 'Energy' },
|
||||
{ symbol: 'XLB', name: 'Materials' },
|
||||
{ symbol: 'COPX', name: 'Copper Miners' },
|
||||
{ symbol: 'LIT', name: 'Lithium & Battery' },
|
||||
{ symbol: 'REMX', name: 'Rare Earth/Strat' },
|
||||
{ symbol: 'URA', name: 'Uranium' },
|
||||
{ symbol: 'SIL', name: 'Silver Miners' },
|
||||
{ symbol: 'PICK', name: 'Diversified Metals' },
|
||||
{ symbol: 'PALL', name: 'Palladium' },
|
||||
{ symbol: 'PPLT', name: 'Platinum' },
|
||||
];
|
||||
|
||||
// Expanded commodity futures and proxies
|
||||
export const COMMODITY_PRICES: Commodity[] = [
|
||||
// Precious Metals
|
||||
{ symbol: 'GC=F', name: 'Gold', display: 'GOLD' },
|
||||
{ symbol: 'SI=F', name: 'Silver', display: 'SILVER' },
|
||||
{ symbol: 'PL=F', name: 'Platinum', display: 'PLAT' },
|
||||
{ symbol: 'PA=F', name: 'Palladium', display: 'PALL' },
|
||||
// Industrial Metals
|
||||
{ symbol: 'HG=F', name: 'Copper', display: 'COPPER' },
|
||||
{ symbol: 'ALI=F', name: 'Aluminum', display: 'ALUM' },
|
||||
{ symbol: 'ZNC=F', name: 'Zinc', display: 'ZINC' },
|
||||
{ symbol: 'NI=F', name: 'Nickel', display: 'NICKEL' },
|
||||
// Energy
|
||||
{ symbol: 'CL=F', name: 'Crude Oil', display: 'WTI' },
|
||||
{ symbol: 'BZ=F', name: 'Brent Crude', display: 'BRENT' },
|
||||
{ symbol: 'NG=F', name: 'Natural Gas', display: 'NATGAS' },
|
||||
// Battery / Critical Minerals (ETF proxies)
|
||||
{ symbol: 'LIT', name: 'Lithium ETF', display: 'LI-ETF' },
|
||||
{ symbol: 'URA', name: 'Uranium ETF', display: 'URAN' },
|
||||
// Volatility reference
|
||||
{ symbol: '^VIX', name: 'VIX', display: 'VIX' },
|
||||
];
|
||||
|
||||
// Mining companies and commodity ETFs for the markets panel
|
||||
export const COMMODITY_MARKET_SYMBOLS: MarketSymbol[] = [
|
||||
// === Diversified Major Miners ===
|
||||
{ symbol: 'BHP', name: 'BHP Group', display: 'BHP' },
|
||||
{ symbol: 'RIO', name: 'Rio Tinto', display: 'RIO' },
|
||||
{ symbol: 'VALE', name: 'Vale', display: 'VALE' },
|
||||
{ symbol: 'GLEN.L', name: 'Glencore', display: 'GLEN' },
|
||||
{ symbol: 'AAL.L', name: 'Anglo American', display: 'AAL' },
|
||||
{ symbol: 'TECK', name: 'Teck Resources', display: 'TECK' },
|
||||
// === Copper Specialists ===
|
||||
{ symbol: 'FCX', name: 'Freeport-McMoRan', display: 'FCX' },
|
||||
{ symbol: 'SCCO', name: 'Southern Copper', display: 'SCCO' },
|
||||
// === Gold Majors ===
|
||||
{ symbol: 'NEM', name: 'Newmont', display: 'NEM' },
|
||||
{ symbol: 'GOLD', name: 'Barrick Gold', display: 'GOLD' },
|
||||
{ symbol: 'AEM', name: 'Agnico Eagle', display: 'AEM' },
|
||||
{ symbol: 'KGC', name: 'Kinross Gold', display: 'KGC' },
|
||||
{ symbol: 'GFI', name: 'Gold Fields', display: 'GFI' },
|
||||
{ symbol: 'AU', name: 'AngloGold Ashanti', display: 'AU' },
|
||||
// === Silver ===
|
||||
{ symbol: 'PAAS', name: 'Pan American Silver', display: 'PAAS' },
|
||||
// === Royalty & Streaming ===
|
||||
{ symbol: 'RGLD', name: 'Royal Gold', display: 'RGLD' },
|
||||
{ symbol: 'WPM', name: 'Wheaton Precious Metals', display: 'WPM' },
|
||||
{ symbol: 'FNV', name: 'Franco-Nevada', display: 'FNV' },
|
||||
// === Lithium ===
|
||||
{ symbol: 'ALB', name: 'Albemarle', display: 'ALB' },
|
||||
{ symbol: 'SQM', name: 'SQM', display: 'SQM' },
|
||||
// === Rare Earths ===
|
||||
{ symbol: 'MP', name: 'MP Materials', display: 'MP' },
|
||||
// === Uranium ===
|
||||
{ symbol: 'CCJ', name: 'Cameco', display: 'CCJ' },
|
||||
{ symbol: 'KAP', name: 'Kazatomprom', display: 'KAP' },
|
||||
// === Energy Majors (commodity context) ===
|
||||
{ symbol: 'XOM', name: 'ExxonMobil', display: 'XOM' },
|
||||
{ symbol: 'CVX', name: 'Chevron', display: 'CVX' },
|
||||
{ symbol: 'SLB', name: 'SLB (Schlumberger)', display: 'SLB' },
|
||||
// === Commodity ETFs ===
|
||||
{ symbol: 'GLD', name: 'SPDR Gold Shares', display: 'GLD' },
|
||||
{ symbol: 'SLV', name: 'iShares Silver', display: 'SLV' },
|
||||
{ symbol: 'GDX', name: 'VanEck Gold Miners ETF', display: 'GDX' },
|
||||
{ symbol: 'USO', name: 'US Oil ETF', display: 'USO' },
|
||||
{ symbol: 'DBB', name: 'Invesco Base Metals ETF', display: 'DBB' },
|
||||
];
|
||||
530
src/config/commodity-miners.ts
Normal file
530
src/config/commodity-miners.ts
Normal file
@@ -0,0 +1,530 @@
|
||||
// Commodity variant: Major mining companies and their key locations
|
||||
// Covers headquarters, regional offices, and major mine sites for top operators
|
||||
|
||||
export interface CommodityMiner {
|
||||
id: string;
|
||||
name: string;
|
||||
lat: number;
|
||||
lon: number;
|
||||
country: string;
|
||||
city: string;
|
||||
siteType: 'headquarters' | 'mine' | 'processing' | 'regional-office';
|
||||
sector: 'Gold' | 'Silver' | 'Copper' | 'Lithium' | 'Cobalt' | 'Rare Earths' | 'Nickel' | 'PGMs' | 'Iron Ore' | 'Uranium' | 'Diversified' | 'Coal' | 'Aluminum' | 'Zinc';
|
||||
operator: string;
|
||||
mineralTypes: string[];
|
||||
status: 'operating' | 'development' | 'care-and-maintenance' | 'exploration';
|
||||
stockSymbol?: string;
|
||||
productionCapacity?: string;
|
||||
description?: string;
|
||||
employees?: number;
|
||||
marketCapUSD?: number; // in billions
|
||||
}
|
||||
|
||||
export const COMMODITY_MINERS: CommodityMiner[] = [
|
||||
// ============================================================
|
||||
// DIVERSIFIED MEGA-MINERS (Headquarters)
|
||||
// ============================================================
|
||||
{
|
||||
id: 'bhp-hq',
|
||||
name: 'BHP',
|
||||
lat: -37.8136,
|
||||
lon: 144.9631,
|
||||
country: 'Australia',
|
||||
city: 'Melbourne',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Diversified',
|
||||
operator: 'BHP',
|
||||
mineralTypes: ['Iron Ore', 'Copper', 'Nickel', 'Coal', 'Potash'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'BHP',
|
||||
description: 'World\'s largest mining company by market cap. Major iron ore, copper, and coal producer.',
|
||||
employees: 80000,
|
||||
marketCapUSD: 130,
|
||||
},
|
||||
{
|
||||
id: 'bhp-london',
|
||||
name: 'BHP London',
|
||||
lat: 51.5074,
|
||||
lon: -0.1278,
|
||||
country: 'United Kingdom',
|
||||
city: 'London',
|
||||
siteType: 'regional-office',
|
||||
sector: 'Diversified',
|
||||
operator: 'BHP',
|
||||
mineralTypes: ['Iron Ore', 'Copper', 'Nickel', 'Coal'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'BHP',
|
||||
description: 'BHP London dual-listed office (LSE: BHP).',
|
||||
},
|
||||
{
|
||||
id: 'rio-tinto-hq',
|
||||
name: 'Rio Tinto',
|
||||
lat: 51.5074,
|
||||
lon: -0.1278,
|
||||
country: 'United Kingdom',
|
||||
city: 'London',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Diversified',
|
||||
operator: 'Rio Tinto',
|
||||
mineralTypes: ['Iron Ore', 'Aluminum', 'Copper', 'Diamonds', 'Lithium'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'RIO',
|
||||
description: 'Anglo-Australian mining giant. World\'s second-largest iron ore producer.',
|
||||
employees: 55000,
|
||||
marketCapUSD: 100,
|
||||
},
|
||||
{
|
||||
id: 'glencore-hq',
|
||||
name: 'Glencore',
|
||||
lat: 47.1663,
|
||||
lon: 8.5159,
|
||||
country: 'Switzerland',
|
||||
city: 'Baar',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Diversified',
|
||||
operator: 'Glencore',
|
||||
mineralTypes: ['Copper', 'Cobalt', 'Zinc', 'Nickel', 'Coal', 'Oil'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'GLEN.L',
|
||||
description: 'World\'s largest commodities trading and mining company. Dominant in cobalt and zinc.',
|
||||
employees: 135000,
|
||||
marketCapUSD: 60,
|
||||
},
|
||||
{
|
||||
id: 'vale-hq',
|
||||
name: 'Vale',
|
||||
lat: -22.9068,
|
||||
lon: -43.1729,
|
||||
country: 'Brazil',
|
||||
city: 'Rio de Janeiro',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Iron Ore',
|
||||
operator: 'Vale',
|
||||
mineralTypes: ['Iron Ore', 'Nickel', 'Copper', 'Cobalt', 'Manganese'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'VALE',
|
||||
description: 'World\'s largest iron ore and nickel producer. Critical supply chain for steel and batteries.',
|
||||
employees: 125000,
|
||||
marketCapUSD: 50,
|
||||
},
|
||||
{
|
||||
id: 'angloamerican-hq',
|
||||
name: 'Anglo American',
|
||||
lat: 51.5074,
|
||||
lon: -0.1278,
|
||||
country: 'United Kingdom',
|
||||
city: 'London',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Diversified',
|
||||
operator: 'Anglo American',
|
||||
mineralTypes: ['Platinum', 'Diamonds', 'Copper', 'Iron Ore', 'Nickel', 'Coal'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'AAL.L',
|
||||
description: 'Global diversified miner. Largest PGM producer through Anglo American Platinum (Amplats).',
|
||||
employees: 90000,
|
||||
marketCapUSD: 30,
|
||||
},
|
||||
{
|
||||
id: 'freeport-hq',
|
||||
name: 'Freeport-McMoRan',
|
||||
lat: 33.4484,
|
||||
lon: -112.0740,
|
||||
country: 'USA',
|
||||
city: 'Phoenix',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Copper',
|
||||
operator: 'Freeport-McMoRan',
|
||||
mineralTypes: ['Copper', 'Gold', 'Molybdenum'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'FCX',
|
||||
description: 'World\'s largest publicly traded copper producer. Operates Grasberg (Indonesia) and Morenci (US).',
|
||||
employees: 25000,
|
||||
marketCapUSD: 55,
|
||||
},
|
||||
{
|
||||
id: 'teck-hq',
|
||||
name: 'Teck Resources',
|
||||
lat: 49.2827,
|
||||
lon: -123.1207,
|
||||
country: 'Canada',
|
||||
city: 'Vancouver',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Diversified',
|
||||
operator: 'Teck Resources',
|
||||
mineralTypes: ['Copper', 'Zinc', 'Steelmaking Coal'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'TECK',
|
||||
description: 'Canada\'s largest diversified mining company. Major copper growth pipeline (QB2, Highland Valley).',
|
||||
employees: 10000,
|
||||
marketCapUSD: 18,
|
||||
},
|
||||
|
||||
// ============================================================
|
||||
// GOLD / SILVER MAJORS (Headquarters)
|
||||
// ============================================================
|
||||
{
|
||||
id: 'newmont-hq',
|
||||
name: 'Newmont',
|
||||
lat: 39.7392,
|
||||
lon: -104.9903,
|
||||
country: 'USA',
|
||||
city: 'Denver',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Gold',
|
||||
operator: 'Newmont',
|
||||
mineralTypes: ['Gold', 'Copper', 'Silver', 'Zinc', 'Lead'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'NEM',
|
||||
description: 'World\'s largest gold mining company by production. Operations on 6 continents.',
|
||||
employees: 38000,
|
||||
marketCapUSD: 35,
|
||||
},
|
||||
{
|
||||
id: 'barrick-hq',
|
||||
name: 'Barrick Gold',
|
||||
lat: 43.6532,
|
||||
lon: -79.3832,
|
||||
country: 'Canada',
|
||||
city: 'Toronto',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Gold',
|
||||
operator: 'Barrick Gold',
|
||||
mineralTypes: ['Gold', 'Copper'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'GOLD',
|
||||
description: 'World\'s second-largest gold miner. Major Tier One assets in Nevada, Nevada, Mali, DRC.',
|
||||
employees: 36000,
|
||||
marketCapUSD: 30,
|
||||
},
|
||||
{
|
||||
id: 'agnico-eagle-hq',
|
||||
name: 'Agnico Eagle',
|
||||
lat: 43.6532,
|
||||
lon: -79.3832,
|
||||
country: 'Canada',
|
||||
city: 'Toronto',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Gold',
|
||||
operator: 'Agnico Eagle',
|
||||
mineralTypes: ['Gold', 'Silver'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'AEM',
|
||||
description: 'Senior gold producer with operations in Canada, Finland, Mexico, and Australia.',
|
||||
employees: 15000,
|
||||
marketCapUSD: 35,
|
||||
},
|
||||
{
|
||||
id: 'goldfields-hq',
|
||||
name: 'Gold Fields',
|
||||
lat: -26.2041,
|
||||
lon: 28.0473,
|
||||
country: 'South Africa',
|
||||
city: 'Johannesburg',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Gold',
|
||||
operator: 'Gold Fields',
|
||||
mineralTypes: ['Gold'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'GFI',
|
||||
description: 'South African gold major with assets in SA, Ghana, Australia, Peru, and Chile.',
|
||||
employees: 25000,
|
||||
marketCapUSD: 15,
|
||||
},
|
||||
{
|
||||
id: 'anglogold-hq',
|
||||
name: 'AngloGold Ashanti',
|
||||
lat: -26.2041,
|
||||
lon: 28.0473,
|
||||
country: 'South Africa',
|
||||
city: 'Johannesburg',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Gold',
|
||||
operator: 'AngloGold Ashanti',
|
||||
mineralTypes: ['Gold'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'AU',
|
||||
description: 'Third-largest gold producer. Operations across Africa, Americas, and Australia.',
|
||||
employees: 30000,
|
||||
marketCapUSD: 12,
|
||||
},
|
||||
{
|
||||
id: 'kinross-hq',
|
||||
name: 'Kinross Gold',
|
||||
lat: 43.6532,
|
||||
lon: -79.3832,
|
||||
country: 'Canada',
|
||||
city: 'Toronto',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Gold',
|
||||
operator: 'Kinross Gold',
|
||||
mineralTypes: ['Gold', 'Silver'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'KGC',
|
||||
description: 'Senior gold producer with mines in USA, Brazil, Chile, West Africa, and Mauritania.',
|
||||
employees: 9000,
|
||||
marketCapUSD: 9,
|
||||
},
|
||||
{
|
||||
id: 'fresnillo-hq',
|
||||
name: 'Fresnillo plc',
|
||||
lat: 19.4326,
|
||||
lon: -99.1332,
|
||||
country: 'Mexico',
|
||||
city: 'Mexico City',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Silver',
|
||||
operator: 'Fresnillo',
|
||||
mineralTypes: ['Silver', 'Gold', 'Lead', 'Zinc'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'FRES.L',
|
||||
description: 'World\'s largest primary silver producer. Operating in Mexico since 1554.',
|
||||
employees: 12000,
|
||||
marketCapUSD: 6,
|
||||
},
|
||||
{
|
||||
id: 'pan-american-silver-hq',
|
||||
name: 'Pan American Silver',
|
||||
lat: 49.2827,
|
||||
lon: -123.1207,
|
||||
country: 'Canada',
|
||||
city: 'Vancouver',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Silver',
|
||||
operator: 'Pan American Silver',
|
||||
mineralTypes: ['Silver', 'Gold', 'Zinc', 'Lead', 'Copper'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'PAAS',
|
||||
description: 'Leading primary silver mining company with operations across Latin America.',
|
||||
employees: 14000,
|
||||
marketCapUSD: 5,
|
||||
},
|
||||
|
||||
// ============================================================
|
||||
// BATTERY METALS / CRITICAL MINERALS (Headquarters)
|
||||
// ============================================================
|
||||
{
|
||||
id: 'albemarle-hq',
|
||||
name: 'Albemarle',
|
||||
lat: 35.2271,
|
||||
lon: -80.8431,
|
||||
country: 'USA',
|
||||
city: 'Charlotte',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Lithium',
|
||||
operator: 'Albemarle',
|
||||
mineralTypes: ['Lithium', 'Bromine', 'Refining Catalysts'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'ALB',
|
||||
description: 'World\'s largest lithium producer. Operates Greenbushes (Australia) and Chilean brine assets.',
|
||||
employees: 6600,
|
||||
marketCapUSD: 8,
|
||||
},
|
||||
{
|
||||
id: 'sqm-hq',
|
||||
name: 'SQM (Sociedad Química)',
|
||||
lat: -33.4569,
|
||||
lon: -70.6483,
|
||||
country: 'Chile',
|
||||
city: 'Santiago',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Lithium',
|
||||
operator: 'SQM',
|
||||
mineralTypes: ['Lithium', 'Potassium', 'Iodine', 'Nitrates'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'SQM',
|
||||
description: 'World\'s second-largest lithium producer. Primary operator at Salar de Atacama.',
|
||||
employees: 5400,
|
||||
marketCapUSD: 12,
|
||||
},
|
||||
{
|
||||
id: 'pilbara-minerals-hq',
|
||||
name: 'Pilbara Minerals',
|
||||
lat: -31.9505,
|
||||
lon: 115.8605,
|
||||
country: 'Australia',
|
||||
city: 'Perth',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Lithium',
|
||||
operator: 'Pilbara Minerals',
|
||||
mineralTypes: ['Lithium (Spodumene)'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'PLS.AX',
|
||||
description: 'Pure-play lithium miner operating Pilgangoora in Western Australia.',
|
||||
employees: 900,
|
||||
marketCapUSD: 3,
|
||||
},
|
||||
{
|
||||
id: 'mp-materials-hq',
|
||||
name: 'MP Materials',
|
||||
lat: 34.0522,
|
||||
lon: -118.2437,
|
||||
country: 'USA',
|
||||
city: 'Los Angeles',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Rare Earths',
|
||||
operator: 'MP Materials',
|
||||
mineralTypes: ['Neodymium', 'Praseodymium', 'Lanthanum', 'Cerium'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'MP',
|
||||
description: 'Operator of Mountain Pass, the only US rare earth mining and processing facility.',
|
||||
employees: 550,
|
||||
marketCapUSD: 2,
|
||||
},
|
||||
{
|
||||
id: 'lynas-hq',
|
||||
name: 'Lynas Rare Earths',
|
||||
lat: -31.9505,
|
||||
lon: 115.8605,
|
||||
country: 'Australia',
|
||||
city: 'Perth',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Rare Earths',
|
||||
operator: 'Lynas',
|
||||
mineralTypes: ['Neodymium', 'Praseodymium', 'Heavy Rare Earths'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'LYC.AX',
|
||||
description: 'Largest rare earth producer outside China. Operates Mt Weld mine and Kalgoorlie processing.',
|
||||
employees: 1400,
|
||||
marketCapUSD: 3,
|
||||
},
|
||||
{
|
||||
id: 'cmoc-hq',
|
||||
name: 'CMOC Group',
|
||||
lat: 31.2304,
|
||||
lon: 121.4737,
|
||||
country: 'China',
|
||||
city: 'Shanghai',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Cobalt',
|
||||
operator: 'CMOC',
|
||||
mineralTypes: ['Cobalt', 'Copper', 'Molybdenum', 'Tungsten', 'Niobium'],
|
||||
status: 'operating',
|
||||
stockSymbol: '603993.SS',
|
||||
description: 'World\'s largest cobalt producer. Major DRC copper/cobalt operations (Tenke Fungurume).',
|
||||
employees: 25000,
|
||||
marketCapUSD: 20,
|
||||
},
|
||||
{
|
||||
id: 'cameco-hq',
|
||||
name: 'Cameco',
|
||||
lat: 52.1332,
|
||||
lon: -106.6700,
|
||||
country: 'Canada',
|
||||
city: 'Saskatoon',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Uranium',
|
||||
operator: 'Cameco',
|
||||
mineralTypes: ['Uranium'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'CCJ',
|
||||
description: 'World\'s largest publicly traded uranium producer. Operates Cigar Lake and McArthur River.',
|
||||
employees: 3700,
|
||||
marketCapUSD: 18,
|
||||
},
|
||||
{
|
||||
id: 'kazatomprom-hq',
|
||||
name: 'Kazatomprom',
|
||||
lat: 51.1694,
|
||||
lon: 71.4491,
|
||||
country: 'Kazakhstan',
|
||||
city: 'Astana',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Uranium',
|
||||
operator: 'Kazatomprom',
|
||||
mineralTypes: ['Uranium'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'KAP',
|
||||
description: 'World\'s largest uranium producer (~23% of global supply). State-owned Kazakh company.',
|
||||
employees: 22000,
|
||||
marketCapUSD: 8,
|
||||
},
|
||||
|
||||
// ============================================================
|
||||
// NICKEL / PGM MAJORS (Headquarters)
|
||||
// ============================================================
|
||||
{
|
||||
id: 'nornickel-hq',
|
||||
name: 'Nornickel (Norilsk Nickel)',
|
||||
lat: 55.7558,
|
||||
lon: 37.6173,
|
||||
country: 'Russia',
|
||||
city: 'Moscow',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Nickel',
|
||||
operator: 'Nornickel',
|
||||
mineralTypes: ['Nickel', 'Palladium', 'Platinum', 'Copper', 'Cobalt'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'GMKN.ME',
|
||||
description: 'World\'s largest producer of palladium and high-grade nickel. Major platinum producer.',
|
||||
employees: 80000,
|
||||
marketCapUSD: 25,
|
||||
},
|
||||
{
|
||||
id: 'southern-copper-hq',
|
||||
name: 'Southern Copper',
|
||||
lat: 33.4484,
|
||||
lon: -112.0740,
|
||||
country: 'USA',
|
||||
city: 'Phoenix',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Copper',
|
||||
operator: 'Grupo México / Southern Copper',
|
||||
mineralTypes: ['Copper', 'Molybdenum', 'Zinc', 'Silver', 'Gold'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'SCCO',
|
||||
description: 'Largest copper reserves globally. Major operations in Mexico and Peru.',
|
||||
employees: 14000,
|
||||
marketCapUSD: 60,
|
||||
},
|
||||
{
|
||||
id: 'royalgold-hq',
|
||||
name: 'Royal Gold',
|
||||
lat: 39.7392,
|
||||
lon: -104.9903,
|
||||
country: 'USA',
|
||||
city: 'Denver',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Gold',
|
||||
operator: 'Royal Gold',
|
||||
mineralTypes: ['Gold', 'Silver', 'Copper'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'RGLD',
|
||||
description: 'Precious metals royalty and streaming company. Portfolio of 190+ royalties globally.',
|
||||
employees: 30,
|
||||
marketCapUSD: 10,
|
||||
},
|
||||
{
|
||||
id: 'wheaton-precious-hq',
|
||||
name: 'Wheaton Precious Metals',
|
||||
lat: 49.2827,
|
||||
lon: -123.1207,
|
||||
country: 'Canada',
|
||||
city: 'Vancouver',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Gold',
|
||||
operator: 'Wheaton Precious Metals',
|
||||
mineralTypes: ['Gold', 'Silver', 'Palladium', 'Cobalt'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'WPM',
|
||||
description: 'World\'s largest precious metals streaming company. Agreements on 40+ mines.',
|
||||
employees: 50,
|
||||
marketCapUSD: 22,
|
||||
},
|
||||
{
|
||||
id: 'newcrest-hq',
|
||||
name: 'Newcrest Mining',
|
||||
lat: -37.8136,
|
||||
lon: 144.9631,
|
||||
country: 'Australia',
|
||||
city: 'Melbourne',
|
||||
siteType: 'headquarters',
|
||||
sector: 'Gold',
|
||||
operator: 'Newmont/Newcrest',
|
||||
mineralTypes: ['Gold', 'Copper'],
|
||||
status: 'operating',
|
||||
stockSymbol: 'NCM.AX',
|
||||
description: 'Australia\'s largest gold miner (acquired by Newmont 2023). Cadia, Lihir, Brucejack.',
|
||||
employees: 16000,
|
||||
marketCapUSD: 20,
|
||||
},
|
||||
];
|
||||
@@ -1081,6 +1081,90 @@ const HAPPY_FEEDS: Record<string, Feed[]> = {
|
||||
],
|
||||
};
|
||||
|
||||
// Commodity variant feeds (from commodity.ts)
|
||||
const COMMODITY_FEEDS: Record<string, Feed[]> = {
|
||||
'commodity-news': [
|
||||
{ name: 'Kitco News', url: rss('https://www.kitco.com/rss/KitcoNews.xml') },
|
||||
{ name: 'Mining.com', url: rss('https://www.mining.com/feed/') },
|
||||
{ name: 'Bloomberg Commodities', url: rss('https://news.google.com/rss/search?q=site:bloomberg.com+commodities+OR+metals+OR+mining+when:1d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Reuters Commodities', url: rss('https://news.google.com/rss/search?q=site:reuters.com+commodities+OR+metals+OR+mining+when:1d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'S&P Global Commodity', url: rss('https://news.google.com/rss/search?q=site:spglobal.com+commodities+metals+when:3d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Commodity Trade Mantra', url: rss('https://www.commoditytrademantra.com/feed/') },
|
||||
{ name: 'CNBC Commodities', url: rss('https://news.google.com/rss/search?q=site:cnbc.com+(commodities+OR+metals+OR+gold+OR+copper)+when:1d&hl=en-US&gl=US&ceid=US:en') },
|
||||
],
|
||||
'gold-silver': [
|
||||
{ name: 'Kitco Gold', url: rss('https://www.kitco.com/rss/KitcoGold.xml') },
|
||||
{ name: 'Gold Price News', url: rss('https://news.google.com/rss/search?q=(gold+price+OR+"gold+market"+OR+bullion+OR+LBMA)+when:1d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Silver Price News', url: rss('https://news.google.com/rss/search?q=(silver+price+OR+"silver+market"+OR+"silver+futures")+when:2d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Precious Metals', url: rss('https://news.google.com/rss/search?q=("precious+metals"+OR+platinum+OR+palladium+OR+"gold+ETF"+OR+GLD+OR+SLV)+when:2d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'World Gold Council', url: rss('https://news.google.com/rss/search?q="World+Gold+Council"+OR+"central+bank+gold"+OR+"gold+reserves"+when:7d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'GoldSeek', url: rss('https://news.goldseek.com/GoldSeek/rss.xml') },
|
||||
{ name: 'SilverSeek', url: rss('https://news.silverseek.com/SilverSeek/rss.xml') },
|
||||
],
|
||||
energy: [
|
||||
{ name: 'OilPrice.com', url: rss('https://oilprice.com/rss/main') },
|
||||
{ name: 'Rigzone', url: rss('https://www.rigzone.com/news/rss/rigzone_latest.aspx') },
|
||||
{ name: 'EIA Reports', url: rss('https://www.eia.gov/rss/press_room.xml') },
|
||||
{ name: 'OPEC News', url: rss('https://news.google.com/rss/search?q=(OPEC+OR+"oil+price"+OR+"crude+oil"+OR+WTI+OR+Brent+OR+"oil+production")+when:1d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Natural Gas News', url: rss('https://news.google.com/rss/search?q=("natural+gas"+OR+LNG+OR+"gas+price"+OR+"Henry+Hub")+when:1d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Energy Intel', url: rss('https://news.google.com/rss/search?q=(energy+commodities+OR+"energy+market"+OR+"energy+prices")+when:2d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Reuters Energy', url: rss('https://news.google.com/rss/search?q=site:reuters.com+(oil+OR+gas+OR+energy)+when:1d&hl=en-US&gl=US&ceid=US:en') },
|
||||
],
|
||||
'mining-news': [
|
||||
{ name: 'Mining Journal', url: rss('https://www.mining-journal.com/feed/') },
|
||||
{ name: 'Northern Miner', url: rss('https://www.northernminer.com/feed/') },
|
||||
{ name: 'Mining Weekly', url: rss('https://www.miningweekly.com/rss/') },
|
||||
{ name: 'Mining Technology', url: rss('https://www.mining-technology.com/feed/') },
|
||||
{ name: 'Australian Mining', url: rss('https://www.australianmining.com.au/feed/') },
|
||||
{ name: 'Mine Web (SNL)', url: rss('https://news.google.com/rss/search?q=("mining+company"+OR+"mine+production"+OR+"mining+operations")+when:2d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Resource World', url: rss('https://news.google.com/rss/search?q=("mining+project"+OR+"mineral+exploration"+OR+"mine+development")+when:3d&hl=en-US&gl=US&ceid=US:en') },
|
||||
],
|
||||
'critical-minerals': [
|
||||
{ name: 'Benchmark Mineral', url: rss('https://news.google.com/rss/search?q=("critical+minerals"+OR+"battery+metals"+OR+lithium+OR+cobalt+OR+"rare+earths")+when:2d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Lithium Market', url: rss('https://news.google.com/rss/search?q=(lithium+price+OR+"lithium+market"+OR+"lithium+supply"+OR+spodumene+OR+LCE)+when:2d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Cobalt Market', url: rss('https://news.google.com/rss/search?q=(cobalt+price+OR+"cobalt+market"+OR+"DRC+cobalt"+OR+"battery+cobalt")+when:3d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Rare Earths News', url: rss('https://news.google.com/rss/search?q=("rare+earth"+OR+"rare+earths"+OR+"REE"+OR+neodymium+OR+praseodymium)+when:3d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'EV Battery Supply', url: rss('https://news.google.com/rss/search?q=("EV+battery"+OR+"battery+supply+chain"+OR+"battery+materials")+when:3d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'IEA Critical Minerals', url: rss('https://news.google.com/rss/search?q=site:iea.org+(minerals+OR+critical+OR+battery)+when:14d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Uranium Market', url: rss('https://news.google.com/rss/search?q=(uranium+price+OR+"uranium+market"+OR+U3O8+OR+nuclear+fuel)+when:3d&hl=en-US&gl=US&ceid=US:en') },
|
||||
],
|
||||
'base-metals': [
|
||||
{ name: 'LME Metals', url: rss('https://news.google.com/rss/search?q=(LME+OR+"London+Metal+Exchange")+copper+OR+aluminum+OR+zinc+OR+nickel+when:2d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Copper Market', url: rss('https://news.google.com/rss/search?q=(copper+price+OR+"copper+market"+OR+"copper+supply"+OR+COMEX+copper)+when:2d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Nickel News', url: rss('https://news.google.com/rss/search?q=(nickel+price+OR+"nickel+market"+OR+"nickel+supply"+OR+Indonesia+nickel)+when:3d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Aluminum & Zinc', url: rss('https://news.google.com/rss/search?q=(aluminum+price+OR+aluminium+OR+zinc+price+OR+"base+metals")+when:3d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Iron Ore Market', url: rss('https://news.google.com/rss/search?q=("iron+ore"+price+OR+"iron+ore+market"+OR+"steel+raw+materials")+when:2d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Metals Bulletin', url: rss('https://news.google.com/rss/search?q=("metals+market"+OR+"base+metals"+OR+SHFE+OR+"Shanghai+Futures")+when:2d&hl=en-US&gl=US&ceid=US:en') },
|
||||
],
|
||||
'mining-companies': [
|
||||
{ name: 'BHP News', url: rss('https://news.google.com/rss/search?q=BHP+(mining+OR+production+OR+results+OR+copper+OR+"iron+ore")+when:7d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Rio Tinto News', url: rss('https://news.google.com/rss/search?q="Rio+Tinto"+(mining+OR+production+OR+results+OR+Pilbara)+when:7d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Glencore & Vale', url: rss('https://news.google.com/rss/search?q=(Glencore+OR+Vale)+(mining+OR+production+OR+cobalt+OR+"iron+ore")+when:7d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Gold Majors', url: rss('https://news.google.com/rss/search?q=(Newmont+OR+Barrick+OR+AngloGold+OR+Agnico)+(gold+mine+OR+production+OR+results)+when:7d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Freeport & Copper Miners', url: rss('https://news.google.com/rss/search?q=(Freeport+McMoRan+OR+Southern+Copper+OR+Teck+OR+Antofagasta)+when:7d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Critical Mineral Companies', url: rss('https://news.google.com/rss/search?q=(Albemarle+OR+SQM+OR+"MP+Materials"+OR+Lynas+OR+Cameco)+when:7d&hl=en-US&gl=US&ceid=US:en') },
|
||||
],
|
||||
'supply-chain': [
|
||||
{ name: 'Shipping & Freight', url: rss('https://news.google.com/rss/search?q=("bulk+carrier"+OR+"dry+bulk"+OR+"commodity+shipping"+OR+"Port+Hedland"+OR+"Strait+of+Hormuz")+when:3d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Trade Routes', url: rss('https://news.google.com/rss/search?q=("trade+route"+OR+"supply+chain"+OR+"commodity+export"+OR+"mineral+export")+when:3d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'China Commodity Imports', url: rss('https://news.google.com/rss/search?q=(China+imports+copper+OR+iron+ore+OR+lithium+OR+cobalt+OR+"rare+earth")+when:3d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Port & Logistics', url: rss('https://news.google.com/rss/search?q=("iron+ore+port"+OR+"copper+port"+OR+"commodity+port"+OR+"mineral+logistics")+when:7d&hl=en-US&gl=US&ceid=US:en') },
|
||||
],
|
||||
'commodity-regulation': [
|
||||
{ name: 'Mining Regulation', url: rss('https://news.google.com/rss/search?q=("mining+regulation"+OR+"mining+policy"+OR+"mining+permit"+OR+"mining+ban")+when:7d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'ESG in Mining', url: rss('https://news.google.com/rss/search?q=("mining+ESG"+OR+"responsible+mining"+OR+"mine+closure"+OR+"tailings")+when:7d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Trade & Tariffs', url: rss('https://news.google.com/rss/search?q=("mineral+tariff"+OR+"metals+tariff"+OR+"critical+mineral+policy"+OR+"mining+export+ban")+when:7d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Indonesia Nickel Policy', url: rss('https://news.google.com/rss/search?q=(Indonesia+nickel+OR+"nickel+export"+OR+"nickel+ban"+OR+"nickel+processing")+when:7d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'China Mineral Policy', url: rss('https://news.google.com/rss/search?q=(China+"rare+earth"+OR+"mineral+export"+OR+"critical+mineral")+policy+OR+restriction+when:7d&hl=en-US&gl=US&ceid=US:en') },
|
||||
],
|
||||
markets: [
|
||||
{ name: 'Yahoo Finance Commodities', url: rss('https://finance.yahoo.com/rss/topstories') },
|
||||
{ name: 'CNBC Markets', url: rss('https://www.cnbc.com/id/100003114/device/rss/rss.html') },
|
||||
{ name: 'Seeking Alpha Metals', url: rss('https://news.google.com/rss/search?q=site:seekingalpha.com+(gold+OR+silver+OR+copper+OR+mining)+when:2d&hl=en-US&gl=US&ceid=US:en') },
|
||||
{ name: 'Commodity Futures', url: rss('https://news.google.com/rss/search?q=(COMEX+OR+NYMEX+OR+"commodity+futures"+OR+CME+commodities)+when:2d&hl=en-US&gl=US&ceid=US:en') },
|
||||
],
|
||||
};
|
||||
|
||||
// Variant-aware exports
|
||||
export const FEEDS = SITE_VARIANT === 'tech'
|
||||
? TECH_FEEDS
|
||||
@@ -1088,7 +1172,9 @@ export const FEEDS = SITE_VARIANT === 'tech'
|
||||
? FINANCE_FEEDS
|
||||
: SITE_VARIANT === 'happy'
|
||||
? HAPPY_FEEDS
|
||||
: FULL_FEEDS;
|
||||
: SITE_VARIANT === 'commodity'
|
||||
? COMMODITY_FEEDS
|
||||
: FULL_FEEDS;
|
||||
|
||||
export const SOURCE_REGION_MAP: Record<string, { labelKey: string; feedKeys: string[] }> = {
|
||||
// Full (geopolitical) variant regions
|
||||
|
||||
@@ -117,3 +117,19 @@ export {
|
||||
|
||||
// Gulf FDI investment database
|
||||
export { GULF_INVESTMENTS } from './gulf-fdi';
|
||||
|
||||
// Commodity variant - these are included in commodity builds
|
||||
export {
|
||||
COMMODITY_PRICES,
|
||||
COMMODITY_MARKET_SYMBOLS,
|
||||
} from './commodity-markets';
|
||||
|
||||
export {
|
||||
MINING_SITES,
|
||||
PROCESSING_PLANTS,
|
||||
COMMODITY_PORTS,
|
||||
} from './commodity-geo';
|
||||
|
||||
// COMMODITY_MINERS: 30+ mining company HQs — not yet rendered on map.
|
||||
// Uncomment when a miners layer is added to DeckGLMap.ts.
|
||||
// export { COMMODITY_MINERS, type CommodityMiner } from './commodity-miners';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { MapLayers } from '@/types';
|
||||
|
||||
export type MapRenderer = 'flat' | 'globe';
|
||||
export type MapVariant = 'full' | 'tech' | 'finance' | 'happy';
|
||||
export type MapVariant = 'full' | 'tech' | 'finance' | 'happy' | 'commodity';
|
||||
|
||||
export interface LayerDefinition {
|
||||
key: keyof MapLayers;
|
||||
@@ -66,6 +66,9 @@ export const LAYER_REGISTRY: Record<keyof MapLayers, LayerDefinition> = {
|
||||
happiness: def('happiness', '😊', 'happiness', 'World Happiness'),
|
||||
speciesRecovery: def('speciesRecovery', '🐾', 'speciesRecovery', 'Species Recovery'),
|
||||
renewableInstallations: def('renewableInstallations', '⚡', 'renewableInstallations', 'Clean Energy'),
|
||||
miningSites: def('miningSites', '🔭', 'miningSites', 'Mining Sites'),
|
||||
processingPlants: def('processingPlants', '🏭', 'processingPlants', 'Processing Plants'),
|
||||
commodityPorts: def('commodityPorts', '⛵', 'commodityPorts', 'Commodity Ports'),
|
||||
};
|
||||
|
||||
const VARIANT_LAYER_ORDER: Record<MapVariant, Array<keyof MapLayers>> = {
|
||||
@@ -94,6 +97,11 @@ const VARIANT_LAYER_ORDER: Record<MapVariant, Array<keyof MapLayers>> = {
|
||||
'positiveEvents', 'kindness', 'happiness',
|
||||
'speciesRecovery', 'renewableInstallations',
|
||||
],
|
||||
commodity: [
|
||||
'miningSites', 'processingPlants', 'commodityPorts', 'commodityHubs',
|
||||
'minerals', 'pipelines', 'waterways', 'tradeRoutes',
|
||||
'natural', 'weather', 'outages', 'dayNight',
|
||||
],
|
||||
};
|
||||
|
||||
const I18N_PREFIX = 'components.deckgl.layers.';
|
||||
|
||||
@@ -112,6 +112,10 @@ const FULL_MAP_LAYERS: MapLayers = {
|
||||
tradeRoutes: false,
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
// Commodity layers (disabled in full variant)
|
||||
miningSites: false,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
};
|
||||
|
||||
const FULL_MOBILE_MAP_LAYERS: MapLayers = {
|
||||
@@ -165,6 +169,10 @@ const FULL_MOBILE_MAP_LAYERS: MapLayers = {
|
||||
tradeRoutes: false,
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
// Commodity layers (disabled in full variant)
|
||||
miningSites: false,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
};
|
||||
|
||||
// ============================================
|
||||
@@ -260,6 +268,10 @@ const TECH_MAP_LAYERS: MapLayers = {
|
||||
iranAttacks: false,
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
// Commodity layers (disabled in tech variant)
|
||||
miningSites: false,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
};
|
||||
|
||||
const TECH_MOBILE_MAP_LAYERS: MapLayers = {
|
||||
@@ -313,6 +325,10 @@ const TECH_MOBILE_MAP_LAYERS: MapLayers = {
|
||||
iranAttacks: false,
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
// Commodity layers (disabled in tech variant)
|
||||
miningSites: false,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
};
|
||||
|
||||
// ============================================
|
||||
@@ -406,6 +422,10 @@ const FINANCE_MAP_LAYERS: MapLayers = {
|
||||
iranAttacks: false,
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
// Commodity layers (disabled in finance variant)
|
||||
miningSites: false,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
};
|
||||
|
||||
const FINANCE_MOBILE_MAP_LAYERS: MapLayers = {
|
||||
@@ -459,6 +479,10 @@ const FINANCE_MOBILE_MAP_LAYERS: MapLayers = {
|
||||
iranAttacks: false,
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
// Commodity layers (disabled in finance variant)
|
||||
miningSites: false,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
};
|
||||
|
||||
// ============================================
|
||||
@@ -528,6 +552,10 @@ const HAPPY_MAP_LAYERS: MapLayers = {
|
||||
iranAttacks: false,
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
// Commodity layers (disabled)
|
||||
miningSites: false,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
};
|
||||
|
||||
const HAPPY_MOBILE_MAP_LAYERS: MapLayers = {
|
||||
@@ -581,14 +609,188 @@ const HAPPY_MOBILE_MAP_LAYERS: MapLayers = {
|
||||
iranAttacks: false,
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
// Commodity layers (disabled)
|
||||
miningSites: false,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
};
|
||||
|
||||
// ============================================
|
||||
// COMMODITY VARIANT (Mining, Metals, Energy)
|
||||
// ============================================
|
||||
const COMMODITY_PANELS: Record<string, PanelConfig> = {
|
||||
map: { name: 'Commodity Map', enabled: true, priority: 1 },
|
||||
'live-news': { name: 'Commodity Headlines', enabled: true, priority: 1 },
|
||||
'live-webcams': { name: 'Live Webcams', enabled: true, priority: 2 },
|
||||
insights: { name: 'AI Commodity Insights', enabled: true, priority: 1 },
|
||||
'commodity-news': { name: 'Commodity News', enabled: true, priority: 1 },
|
||||
'gold-silver': { name: 'Gold & Silver', enabled: true, priority: 1 },
|
||||
energy: { name: 'Energy Markets', enabled: true, priority: 1 },
|
||||
'mining-news': { name: 'Mining News', enabled: true, priority: 1 },
|
||||
'critical-minerals': { name: 'Critical Minerals', enabled: true, priority: 1 },
|
||||
'base-metals': { name: 'Base Metals', enabled: true, priority: 1 },
|
||||
'mining-companies': { name: 'Mining Companies', enabled: true, priority: 1 },
|
||||
'supply-chain': { name: 'Supply Chain & Logistics', enabled: true, priority: 1 },
|
||||
'commodity-regulation': { name: 'Regulation & Policy', enabled: true, priority: 1 },
|
||||
markets: { name: 'Commodity Markets', enabled: true, priority: 1 },
|
||||
'macro-signals': { name: 'Market Radar', enabled: true, priority: 1 },
|
||||
'trade-policy': { name: 'Trade Policy', enabled: true, priority: 1 },
|
||||
economic: { name: 'Economic Indicators', enabled: true, priority: 1 },
|
||||
finance: { name: 'Financial News', enabled: true, priority: 2 },
|
||||
crypto: { name: 'Crypto', enabled: true, priority: 2 },
|
||||
'etf-flows': { name: 'Gold ETF Tracker', enabled: true, priority: 2 },
|
||||
stablecoins: { name: 'Stablecoins', enabled: true, priority: 2 },
|
||||
polymarket: { name: 'Commodity Predictions', enabled: true, priority: 2 },
|
||||
'world-clock': { name: 'World Clock', enabled: true, priority: 2 },
|
||||
monitors: { name: 'My Monitors', enabled: true, priority: 2 },
|
||||
};
|
||||
|
||||
const COMMODITY_MAP_LAYERS: MapLayers = {
|
||||
gpsJamming: false,
|
||||
|
||||
conflicts: false,
|
||||
bases: false,
|
||||
cables: true,
|
||||
pipelines: true,
|
||||
hotspots: false,
|
||||
ais: false,
|
||||
nuclear: false,
|
||||
irradiators: false,
|
||||
sanctions: true,
|
||||
weather: true,
|
||||
economic: true,
|
||||
waterways: true,
|
||||
outages: true,
|
||||
cyberThreats: false,
|
||||
datacenters: false,
|
||||
protests: false,
|
||||
flights: false,
|
||||
military: false,
|
||||
natural: true,
|
||||
spaceports: false,
|
||||
minerals: true,
|
||||
fires: false,
|
||||
// Data source layers
|
||||
ucdpEvents: false,
|
||||
displacement: false,
|
||||
climate: false,
|
||||
// Tech layers (disabled)
|
||||
startupHubs: false,
|
||||
cloudRegions: false,
|
||||
accelerators: false,
|
||||
techHQs: false,
|
||||
techEvents: false,
|
||||
// Finance layers (enabled for commodity hubs)
|
||||
stockExchanges: false,
|
||||
financialCenters: false,
|
||||
centralBanks: false,
|
||||
commodityHubs: true,
|
||||
gulfInvestments: false,
|
||||
// Happy variant layers (disabled)
|
||||
positiveEvents: false,
|
||||
kindness: false,
|
||||
happiness: false,
|
||||
speciesRecovery: false,
|
||||
renewableInstallations: false,
|
||||
tradeRoutes: true,
|
||||
iranAttacks: false,
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
// Commodity layers (enabled)
|
||||
miningSites: true,
|
||||
processingPlants: true,
|
||||
commodityPorts: true,
|
||||
};
|
||||
|
||||
const COMMODITY_MOBILE_MAP_LAYERS: MapLayers = {
|
||||
gpsJamming: false,
|
||||
|
||||
conflicts: false,
|
||||
bases: false,
|
||||
cables: false,
|
||||
pipelines: false,
|
||||
hotspots: false,
|
||||
ais: false,
|
||||
nuclear: false,
|
||||
irradiators: false,
|
||||
sanctions: false,
|
||||
weather: false,
|
||||
economic: true,
|
||||
waterways: false,
|
||||
outages: true,
|
||||
cyberThreats: false,
|
||||
datacenters: false,
|
||||
protests: false,
|
||||
flights: false,
|
||||
military: false,
|
||||
natural: true,
|
||||
spaceports: false,
|
||||
minerals: true,
|
||||
fires: false,
|
||||
// Data source layers
|
||||
ucdpEvents: false,
|
||||
displacement: false,
|
||||
climate: false,
|
||||
// Tech layers (disabled)
|
||||
startupHubs: false,
|
||||
cloudRegions: false,
|
||||
accelerators: false,
|
||||
techHQs: false,
|
||||
techEvents: false,
|
||||
// Finance layers (limited on mobile)
|
||||
stockExchanges: false,
|
||||
financialCenters: false,
|
||||
centralBanks: false,
|
||||
commodityHubs: true,
|
||||
gulfInvestments: false,
|
||||
// Happy variant layers (disabled)
|
||||
positiveEvents: false,
|
||||
kindness: false,
|
||||
happiness: false,
|
||||
speciesRecovery: false,
|
||||
renewableInstallations: false,
|
||||
tradeRoutes: false,
|
||||
iranAttacks: false,
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
// Commodity layers (limited on mobile)
|
||||
miningSites: true,
|
||||
processingPlants: false,
|
||||
commodityPorts: true,
|
||||
};
|
||||
|
||||
// ============================================
|
||||
// VARIANT-AWARE EXPORTS
|
||||
// ============================================
|
||||
export const DEFAULT_PANELS = SITE_VARIANT === 'happy' ? HAPPY_PANELS : SITE_VARIANT === 'tech' ? TECH_PANELS : SITE_VARIANT === 'finance' ? FINANCE_PANELS : FULL_PANELS;
|
||||
export const DEFAULT_MAP_LAYERS = SITE_VARIANT === 'happy' ? HAPPY_MAP_LAYERS : SITE_VARIANT === 'tech' ? TECH_MAP_LAYERS : SITE_VARIANT === 'finance' ? FINANCE_MAP_LAYERS : FULL_MAP_LAYERS;
|
||||
export const MOBILE_DEFAULT_MAP_LAYERS = SITE_VARIANT === 'happy' ? HAPPY_MOBILE_MAP_LAYERS : SITE_VARIANT === 'tech' ? TECH_MOBILE_MAP_LAYERS : SITE_VARIANT === 'finance' ? FINANCE_MOBILE_MAP_LAYERS : FULL_MOBILE_MAP_LAYERS;
|
||||
export const DEFAULT_PANELS = SITE_VARIANT === 'happy'
|
||||
? HAPPY_PANELS
|
||||
: SITE_VARIANT === 'tech'
|
||||
? TECH_PANELS
|
||||
: SITE_VARIANT === 'finance'
|
||||
? FINANCE_PANELS
|
||||
: SITE_VARIANT === 'commodity'
|
||||
? COMMODITY_PANELS
|
||||
: FULL_PANELS;
|
||||
|
||||
export const DEFAULT_MAP_LAYERS = SITE_VARIANT === 'happy'
|
||||
? HAPPY_MAP_LAYERS
|
||||
: SITE_VARIANT === 'tech'
|
||||
? TECH_MAP_LAYERS
|
||||
: SITE_VARIANT === 'finance'
|
||||
? FINANCE_MAP_LAYERS
|
||||
: SITE_VARIANT === 'commodity'
|
||||
? COMMODITY_MAP_LAYERS
|
||||
: FULL_MAP_LAYERS;
|
||||
|
||||
export const MOBILE_DEFAULT_MAP_LAYERS = SITE_VARIANT === 'happy'
|
||||
? HAPPY_MOBILE_MAP_LAYERS
|
||||
: SITE_VARIANT === 'tech'
|
||||
? TECH_MOBILE_MAP_LAYERS
|
||||
: SITE_VARIANT === 'finance'
|
||||
? FINANCE_MOBILE_MAP_LAYERS
|
||||
: SITE_VARIANT === 'commodity'
|
||||
? COMMODITY_MOBILE_MAP_LAYERS
|
||||
: FULL_MOBILE_MAP_LAYERS;
|
||||
|
||||
/** Maps map-layer toggle keys to their data-freshness source IDs (single source of truth). */
|
||||
export const LAYER_TO_SOURCE: Partial<Record<keyof MapLayers, DataSourceId[]>> = {
|
||||
|
||||
@@ -104,4 +104,27 @@ export const VARIANT_META: { full: VariantMeta; [k: string]: VariantMeta } = {
|
||||
'Market radar signals',
|
||||
],
|
||||
},
|
||||
commodity: {
|
||||
title: 'Commodity Monitor - Real-Time Commodity Markets & Supply Chain Dashboard',
|
||||
description: 'Real-time commodity markets dashboard tracking mining sites, processing plants, commodity ports, supply chains, and global commodity trade flows.',
|
||||
keywords: 'commodity dashboard, mining sites, processing plants, commodity ports, supply chain, commodity markets, oil, gas, metals, agriculture, mining operations, commodity trade, logistics, infrastructure, resource tracking, commodity prices, futures markets',
|
||||
url: 'https://commodity.worldmonitor.app/',
|
||||
siteName: 'Commodity Monitor',
|
||||
shortName: 'CommodityMonitor',
|
||||
subject: 'Commodity Markets, Mining, and Supply Chain Intelligence',
|
||||
classification: 'Commodity Dashboard, Supply Chain Tracker, Resource Intelligence',
|
||||
categories: ['finance', 'business'],
|
||||
features: [
|
||||
'Mining site tracking',
|
||||
'Processing plant monitoring',
|
||||
'Commodity port mapping',
|
||||
'Supply chain visualization',
|
||||
'Commodity price tracking',
|
||||
'Trade flow analysis',
|
||||
'Resource extraction monitoring',
|
||||
'Logistics infrastructure',
|
||||
'Commodity market news',
|
||||
'Futures market data',
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@ export const SITE_VARIANT: string = (() => {
|
||||
const isTauri = '__TAURI_INTERNALS__' in window || '__TAURI__' in window;
|
||||
if (isTauri) {
|
||||
const stored = localStorage.getItem('worldmonitor-variant');
|
||||
if (stored === 'tech' || stored === 'full' || stored === 'finance' || stored === 'happy') return stored;
|
||||
if (stored === 'tech' || stored === 'full' || stored === 'finance' || stored === 'happy' || stored === 'commodity') return stored;
|
||||
return import.meta.env.VITE_VARIANT || 'full';
|
||||
}
|
||||
|
||||
@@ -12,10 +12,11 @@ export const SITE_VARIANT: string = (() => {
|
||||
if (h.startsWith('tech.')) return 'tech';
|
||||
if (h.startsWith('finance.')) return 'finance';
|
||||
if (h.startsWith('happy.')) return 'happy';
|
||||
if (h.startsWith('commodity.')) return 'commodity';
|
||||
|
||||
if (h === 'localhost' || h === '127.0.0.1') {
|
||||
const stored = localStorage.getItem('worldmonitor-variant');
|
||||
if (stored === 'tech' || stored === 'full' || stored === 'finance' || stored === 'happy') return stored;
|
||||
if (stored === 'tech' || stored === 'full' || stored === 'finance' || stored === 'happy' || stored === 'commodity') return stored;
|
||||
return import.meta.env.VITE_VARIANT || 'full';
|
||||
}
|
||||
|
||||
|
||||
175
src/config/variants/commodity.ts
Normal file
175
src/config/variants/commodity.ts
Normal file
@@ -0,0 +1,175 @@
|
||||
// Commodity variant - commodity.worldmonitor.app -- Focused on mining, metals, energy commodities, and critical minerals
|
||||
import type { PanelConfig, MapLayers } from '@/types';
|
||||
import type { VariantConfig } from './base';
|
||||
|
||||
// Re-export base config
|
||||
export * from './base';
|
||||
|
||||
// Commodity-specific data exports (explicit named re-exports avoid VS Code language-server path issues)
|
||||
export { COMMODITY_SECTORS, COMMODITY_PRICES, COMMODITY_MARKET_SYMBOLS } from '@/config/commodity-markets';
|
||||
export type { MineralType, MineSiteStatus, MineSite, ProcessingPlant, CommodityPort } from '@/config/commodity-geo';
|
||||
export { MINING_SITES, PROCESSING_PLANTS, COMMODITY_PORTS } from '@/config/commodity-geo';
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// PANEL CONFIGURATION — Commodity-only panels
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
export const DEFAULT_PANELS: Record<string, PanelConfig> = {
|
||||
// Core
|
||||
map: { name: 'Commodity & Mining Map', enabled: true, priority: 1 },
|
||||
'live-news': { name: 'Commodity Headlines', enabled: true, priority: 1 },
|
||||
// Markets
|
||||
markets: { name: 'Mining & Commodity Stocks', enabled: true, priority: 1 },
|
||||
commodities: { name: 'Live Commodity Prices', enabled: true, priority: 1 },
|
||||
heatmap: { name: 'Sector Heatmap', enabled: true, priority: 1 },
|
||||
'macro-signals': { name: 'Market Radar', enabled: true, priority: 1 },
|
||||
// Commodity news feeds
|
||||
'gold-silver': { name: 'Gold & Silver', enabled: true, priority: 1 },
|
||||
energy: { name: 'Energy Markets', enabled: true, priority: 1 },
|
||||
'mining-news': { name: 'Mining Industry', enabled: true, priority: 1 },
|
||||
'critical-minerals': { name: 'Critical Minerals & Battery Metals', enabled: true, priority: 1 },
|
||||
'base-metals': { name: 'Base Metals (Cu, Al, Zn, Ni)', enabled: true, priority: 1 },
|
||||
'mining-companies': { name: 'Major Miners', enabled: true, priority: 1 },
|
||||
'commodity-news': { name: 'Commodity News', enabled: true, priority: 1 },
|
||||
// Operations & supply
|
||||
'supply-chain': { name: 'Supply Chain & Shipping', enabled: true, priority: 2 },
|
||||
'commodity-regulation': { name: 'Mining Policy & ESG', enabled: true, priority: 2 },
|
||||
// Tracking
|
||||
monitors: { name: 'My Monitors', enabled: true, priority: 2 },
|
||||
};
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// MAP LAYERS — Commodity-focused (mirrors Finance variant pattern)
|
||||
// Only commodity-relevant layers are enabled; all others are explicitly false.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
export const DEFAULT_MAP_LAYERS: MapLayers = {
|
||||
// ── Core commodity map layers (ENABLED) ───────────────────────────────────
|
||||
minerals: true, // Critical minerals projects (existing layer)
|
||||
miningSites: true, // ~70 major mine sites from commodity-geo.ts
|
||||
processingPlants: true, // Smelters, refineries, separation plants
|
||||
commodityPorts: true, // Mineral export/import ports
|
||||
commodityHubs: true, // Commodity exchanges (LME, CME, SHFE, etc.)
|
||||
pipelines: true, // Oil & gas pipelines (energy commodity context)
|
||||
waterways: true, // Strategic shipping chokepoints
|
||||
tradeRoutes: true, // Commodity trade routes
|
||||
natural: true, // Earthquakes/natural events (affect mine operations)
|
||||
weather: true, // Weather impacting operations
|
||||
|
||||
// ── All non-commodity layers (DISABLED) ───────────────────────────────────
|
||||
// Geopolitical / military
|
||||
gpsJamming: false,
|
||||
iranAttacks: false,
|
||||
conflicts: false,
|
||||
bases: false,
|
||||
hotspots: false,
|
||||
nuclear: false,
|
||||
irradiators: false,
|
||||
military: false,
|
||||
spaceports: false,
|
||||
ucdpEvents: false,
|
||||
displacement: false,
|
||||
// Protests / civil unrest
|
||||
protests: false,
|
||||
// Transport / tracking
|
||||
ais: false,
|
||||
flights: false,
|
||||
// Infrastructure (non-commodity)
|
||||
cables: false,
|
||||
outages: false,
|
||||
datacenters: false,
|
||||
// Sanctions / financial context
|
||||
sanctions: false,
|
||||
economic: false,
|
||||
// Environmental
|
||||
fires: false,
|
||||
climate: false,
|
||||
// Tech variant layers
|
||||
startupHubs: false,
|
||||
cloudRegions: false,
|
||||
accelerators: false,
|
||||
techHQs: false,
|
||||
techEvents: false,
|
||||
// Finance variant layers
|
||||
stockExchanges: false,
|
||||
financialCenters: false,
|
||||
centralBanks: false,
|
||||
gulfInvestments: false,
|
||||
// Happy variant layers
|
||||
positiveEvents: false,
|
||||
kindness: false,
|
||||
happiness: false,
|
||||
speciesRecovery: false,
|
||||
renewableInstallations: false,
|
||||
// Overlay
|
||||
dayNight: false,
|
||||
cyberThreats: false,
|
||||
// Additional required properties
|
||||
|
||||
ciiChoropleth: false,
|
||||
};
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// MOBILE MAP LAYERS — Minimal set for commodity mobile view
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
export const MOBILE_DEFAULT_MAP_LAYERS: MapLayers = {
|
||||
// Core commodity layers (limited on mobile for performance)
|
||||
minerals: true,
|
||||
miningSites: true,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
commodityHubs: true,
|
||||
pipelines: false,
|
||||
waterways: false,
|
||||
tradeRoutes: false,
|
||||
natural: true,
|
||||
weather: false,
|
||||
|
||||
// All others disabled on mobile
|
||||
gpsJamming: false,
|
||||
iranAttacks: false,
|
||||
conflicts: false,
|
||||
bases: false,
|
||||
hotspots: false,
|
||||
nuclear: false,
|
||||
irradiators: false,
|
||||
military: false,
|
||||
spaceports: false,
|
||||
ucdpEvents: false,
|
||||
displacement: false,
|
||||
protests: false,
|
||||
ais: false,
|
||||
flights: false,
|
||||
cables: false,
|
||||
outages: false,
|
||||
datacenters: false,
|
||||
sanctions: false,
|
||||
economic: false,
|
||||
fires: false,
|
||||
climate: false,
|
||||
startupHubs: false,
|
||||
cloudRegions: false,
|
||||
accelerators: false,
|
||||
techHQs: false,
|
||||
techEvents: false,
|
||||
stockExchanges: false,
|
||||
financialCenters: false,
|
||||
centralBanks: false,
|
||||
gulfInvestments: false,
|
||||
positiveEvents: false,
|
||||
kindness: false,
|
||||
happiness: false,
|
||||
speciesRecovery: false,
|
||||
renewableInstallations: false,
|
||||
dayNight: false,
|
||||
cyberThreats: false,
|
||||
// Additional required properties
|
||||
|
||||
ciiChoropleth: false,
|
||||
};
|
||||
|
||||
export const VARIANT_CONFIG: VariantConfig = {
|
||||
name: 'commodity',
|
||||
description: 'Commodity, mining & critical minerals intelligence dashboard',
|
||||
panels: DEFAULT_PANELS,
|
||||
mapLayers: DEFAULT_MAP_LAYERS,
|
||||
mobileMapLayers: MOBILE_DEFAULT_MAP_LAYERS,
|
||||
};
|
||||
@@ -222,6 +222,10 @@ export const DEFAULT_MAP_LAYERS: MapLayers = {
|
||||
iranAttacks: false,
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
// Commodity variant layers (disabled in finance variant)
|
||||
miningSites: false,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
};
|
||||
|
||||
// Mobile defaults for finance variant
|
||||
@@ -275,6 +279,10 @@ export const MOBILE_DEFAULT_MAP_LAYERS: MapLayers = {
|
||||
iranAttacks: false,
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
// Commodity variant layers (disabled in finance variant)
|
||||
miningSites: false,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
};
|
||||
|
||||
export const VARIANT_CONFIG: VariantConfig = {
|
||||
|
||||
@@ -101,6 +101,10 @@ export const DEFAULT_MAP_LAYERS: MapLayers = {
|
||||
iranAttacks: true,
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
// Commodity variant layers (disabled in full variant)
|
||||
miningSites: false,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
};
|
||||
|
||||
// Mobile-specific defaults for geopolitical
|
||||
@@ -154,6 +158,10 @@ export const MOBILE_DEFAULT_MAP_LAYERS: MapLayers = {
|
||||
iranAttacks: true,
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
// Commodity variant layers (disabled in full variant)
|
||||
miningSites: false,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
};
|
||||
|
||||
export const VARIANT_CONFIG: VariantConfig = {
|
||||
|
||||
@@ -70,6 +70,10 @@ export const DEFAULT_MAP_LAYERS: MapLayers = {
|
||||
iranAttacks: false,
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
// Commodity variant layers (disabled in happy variant)
|
||||
miningSites: false,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
};
|
||||
|
||||
// Mobile defaults — same as desktop for happy variant
|
||||
@@ -124,6 +128,10 @@ export const MOBILE_DEFAULT_MAP_LAYERS: MapLayers = {
|
||||
iranAttacks: false,
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
// Commodity variant layers (disabled in happy variant)
|
||||
miningSites: false,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
};
|
||||
|
||||
export const VARIANT_CONFIG: VariantConfig = {
|
||||
|
||||
@@ -263,6 +263,10 @@ export const DEFAULT_MAP_LAYERS: MapLayers = {
|
||||
iranAttacks: false,
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
// Commodity variant layers (disabled in tech variant)
|
||||
miningSites: false,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
};
|
||||
|
||||
// Mobile defaults for tech variant
|
||||
@@ -316,6 +320,10 @@ export const MOBILE_DEFAULT_MAP_LAYERS: MapLayers = {
|
||||
iranAttacks: false,
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
// Commodity variant layers (disabled in tech variant)
|
||||
miningSites: false,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
};
|
||||
|
||||
export const VARIANT_CONFIG: VariantConfig = {
|
||||
|
||||
@@ -182,6 +182,9 @@ const allLayersEnabled: MapLayers = {
|
||||
iranAttacks: false,
|
||||
ciiChoropleth: false,
|
||||
dayNight: true,
|
||||
miningSites: false,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
};
|
||||
|
||||
const allLayersDisabled: MapLayers = {
|
||||
@@ -231,6 +234,9 @@ const allLayersDisabled: MapLayers = {
|
||||
iranAttacks: false,
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
miningSites: false,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
};
|
||||
|
||||
const SEEDED_NEWS_LOCATIONS: Array<{
|
||||
|
||||
@@ -131,6 +131,9 @@ const layers = {
|
||||
|
||||
ciiChoropleth: false,
|
||||
dayNight: false,
|
||||
miningSites: false,
|
||||
processingPlants: false,
|
||||
commodityPorts: false,
|
||||
};
|
||||
|
||||
await initI18n();
|
||||
|
||||
@@ -137,6 +137,7 @@
|
||||
"filterSources": "Filter sources...",
|
||||
"sourcesEnabled": "{{enabled}}/{{total}} enabled",
|
||||
"finance": "FINANCE",
|
||||
"commodity": "COMMODITY",
|
||||
"toggleTheme": "Toggle dark/light mode",
|
||||
"panelDisplayCaption": "Choose which panels to show on the dashboard",
|
||||
"tabGeneral": "General",
|
||||
|
||||
@@ -557,6 +557,10 @@ export interface MapLayers {
|
||||
ciiChoropleth: boolean;
|
||||
// Overlay layers
|
||||
dayNight: boolean;
|
||||
// Commodity variant layers
|
||||
miningSites: boolean;
|
||||
processingPlants: boolean;
|
||||
commodityPorts: boolean;
|
||||
}
|
||||
|
||||
export interface AIDataCenter {
|
||||
|
||||
Reference in New Issue
Block a user