From 47eebef6dae67e0ffe47a15cef9b8b5e7a2296ca Mon Sep 17 00:00:00 2001 From: Marcel Gerber Date: Tue, 21 May 2024 17:16:34 +0200 Subject: [PATCH 01/65] feat(multi-dim): prototype --- adminSiteServer/adminRouter.tsx | 21 + adminSiteServer/appClass.tsx | 2 + adminSiteServer/mockSiteRouter.tsx | 1 + baker/siteRenderers.tsx | 10 + .../types/src/domainTypes/Various.ts | 1 + public/multi-dim/energy.yml | 264 +++ public/multi-dim/life-expectancy.json | 193 ++ public/multi-dim/plastic.json | 95 + public/multi-dim/poverty.yml | 226 +++ site/GrapherWithFallback.tsx | 12 +- site/multi-dim/MultiDimDataPage.tsx | 101 + site/multi-dim/MultiDimDataPageConfig.test.ts | 129 ++ site/multi-dim/MultiDimDataPageConfig.ts | 141 ++ site/multi-dim/MultiDimDataPageContent.scss | 257 +++ site/multi-dim/MultiDimDataPageContent.tsx | 1756 +++++++++++++++++ site/multi-dim/MultiDimDataPageTypes.ts | 43 + site/multi-dim/config.json | 75 + site/multi-dim/config.yml | 58 + site/owid.scss | 1 + site/runSiteFooterScripts.ts | 10 + site/tsconfig.json | 1 + 21 files changed, 3395 insertions(+), 2 deletions(-) create mode 100644 public/multi-dim/energy.yml create mode 100644 public/multi-dim/life-expectancy.json create mode 100644 public/multi-dim/plastic.json create mode 100644 public/multi-dim/poverty.yml create mode 100644 site/multi-dim/MultiDimDataPage.tsx create mode 100644 site/multi-dim/MultiDimDataPageConfig.test.ts create mode 100644 site/multi-dim/MultiDimDataPageConfig.ts create mode 100644 site/multi-dim/MultiDimDataPageContent.scss create mode 100644 site/multi-dim/MultiDimDataPageContent.tsx create mode 100644 site/multi-dim/MultiDimDataPageTypes.ts create mode 100644 site/multi-dim/config.json create mode 100644 site/multi-dim/config.yml diff --git a/adminSiteServer/adminRouter.tsx b/adminSiteServer/adminRouter.tsx index bb818314245..da8d45ba57f 100644 --- a/adminSiteServer/adminRouter.tsx +++ b/adminSiteServer/adminRouter.tsx @@ -13,6 +13,7 @@ import { ExplorerAdminServer } from "../explorerAdminServer/ExplorerAdminServer. import { renderExplorerPage, renderGdoc, + renderMultiDimDataPage, renderPreview, } from "../baker/siteRenderers.js" import { GitCmsServer } from "../gitCms/GitCmsServer.js" @@ -49,6 +50,7 @@ import { getPlainRouteNonIdempotentWithRWTransaction, getPlainRouteWithROTransaction, } from "./plainRouterHelpers.js" +import { MultiDimDataPageConfig } from "../site/multi-dim/MultiDimDataPageConfig.js" // Used for rate-limiting important endpoints (login, register) to prevent brute force attacks const limiterMiddleware = ( @@ -355,6 +357,25 @@ getPlainRouteNonIdempotentWithRWTransaction( } ) +getPlainRouteNonIdempotentWithRWTransaction( + adminRouter, + "/multi-dim", + async (req, res, trx) => { + // const reqUrl = new URL(req.url, `http://localhost/`) + // const fetchUrl = reqUrl.searchParams.get("url") + // if (!fetchUrl) return new JsonError("No URL provided", 400) + // const configRaw = await fetch(fetchUrl).catch(() => null) + // if (!configRaw) return new JsonError("Failed to fetch config", 500) + // const config = await configRaw + // .text() + // .then(MultiDimDataPageConfig.fromYaml) + + const page = await renderMultiDimDataPage({} as any) + res.send(page) + return + } +) + const gitCmsServer = new GitCmsServer({ baseDir: GIT_CMS_DIR, shouldAutoPush: true, diff --git a/adminSiteServer/appClass.tsx b/adminSiteServer/appClass.tsx index 09fe4867bb0..e662538cbd7 100644 --- a/adminSiteServer/appClass.tsx +++ b/adminSiteServer/appClass.tsx @@ -100,6 +100,8 @@ export class OwidAdminApp { app.use("/fonts", express.static("public/fonts")) app.use("/assets-admin", express.static("dist/assets-admin")) + app.use("/multi-dim-assets", express.static("public/multi-dim")) + app.use("/api", publicApiRouter.router) app.use("/admin/api", apiRouter.router) app.use("/admin/test", testPageRouter) diff --git a/adminSiteServer/mockSiteRouter.tsx b/adminSiteServer/mockSiteRouter.tsx index ee387e6b8ef..2638a56628c 100644 --- a/adminSiteServer/mockSiteRouter.tsx +++ b/adminSiteServer/mockSiteRouter.tsx @@ -19,6 +19,7 @@ import { renderDataInsightsIndexPage, renderThankYouPage, makeDataInsightsAtomFeed, + renderMultiDimDataPage, } from "../baker/siteRenderers.js" import { BAKED_BASE_URL, diff --git a/baker/siteRenderers.tsx b/baker/siteRenderers.tsx index 547360a807d..97eb0cc380a 100644 --- a/baker/siteRenderers.tsx +++ b/baker/siteRenderers.tsx @@ -7,6 +7,7 @@ import { SearchPage } from "../site/search/SearchPage.js" import { NotFoundPage } from "../site/NotFoundPage.js" import { DonatePage } from "../site/DonatePage.js" import { ThankYouPage } from "../site/ThankYouPage.js" +import { MultiDimDataPage } from "../site/multi-dim/MultiDimDataPage.js" import OwidGdocPage from "../site/gdocs/OwidGdocPage.js" import React from "react" import ReactDOMServer from "react-dom/server.js" @@ -90,6 +91,7 @@ import { transformExplorerProgramToResolveCatalogPaths } from "./ExplorerBaker.j import { AttachmentsContext } from "../site/gdocs/OwidGdoc.js" import AtomArticleBlocks from "../site/gdocs/components/AtomArticleBlocks.js" import { GdocDataInsight } from "../db/model/Gdoc/GdocDataInsight.js" +import { MultiDimDataPageConfig } from "../site/multi-dim/MultiDimDataPageConfig.js" export const renderToHtmlPage = (element: any) => `${ReactDOMServer.renderToStaticMarkup(element)}` @@ -863,3 +865,11 @@ const renderExplorerDefaultThumbnail = (): string => { ) } + +export const renderMultiDimDataPage = async ( + config: MultiDimDataPageConfig +) => { + return renderToHtmlPage( + + ) +} diff --git a/packages/@ourworldindata/types/src/domainTypes/Various.ts b/packages/@ourworldindata/types/src/domainTypes/Various.ts index 946339baa14..fb634a03334 100644 --- a/packages/@ourworldindata/types/src/domainTypes/Various.ts +++ b/packages/@ourworldindata/types/src/domainTypes/Various.ts @@ -27,6 +27,7 @@ export enum SiteFooterContext { gdocsDocument = "gdocsDocument", // the rendered version (on the site) grapherPage = "grapherPage", dataPageV2 = "dataPageV2", + multiDimDataPage = "multiDimDataPage", dynamicCollectionPage = "dynamicCollectionPage", explorerPage = "explorerPage", default = "default", diff --git a/public/multi-dim/energy.yml b/public/multi-dim/energy.yml new file mode 100644 index 00000000000..50890fd238a --- /dev/null +++ b/public/multi-dim/energy.yml @@ -0,0 +1,264 @@ +name: Energy use +dimensions_title: by energy source +dimensions: + - slug: source + name: Energy source + choices: + - slug: all + name: All sources + group: Aggregates + description: Total energy use + - slug: fossil + name: Fossil fuels + group: Aggregates + description: The sum of coal, oil and gas + - slug: coal + name: Coal + group: Fossil fuels + - slug: oil + name: Oil + group: Fossil fuels + - slug: gas + name: Gas + group: Fossil fuels + - slug: low-carbon + name: Low-carbon + group: Aggregates + description: The sum of nuclear and renewable sources + - slug: nuclear + name: Nuclear + group: Low-carbon & renewables + - slug: renewable + name: Renewables (all) + group: Aggregates + description: Includes energy from hydropower, solar, wind, geothermal, wave and tidal, and bioenergy. + - slug: hydro + name: Hydropower + group: Low-carbon & renewables + - slug: solar-wind + name: Solar and wind + group: Low-carbon & renewables + - slug: solar + name: Solar + group: Low-carbon & renewables + - slug: wind + name: Wind + group: Low-carbon & renewables + - slug: metric + name: Metric + choices: + - slug: total + name: Total consumption + description: The amount of energy consumed nationally per year + - slug: per_capita + name: Consumption per capita + description: The average amount of energy each person consumes per year + - slug: share_total + name: Share of total + description: The share of total energy consumption that this source contributes + - slug: proportional_change + name: Proportional change + description: The percentage change from the previous year + - slug: absolute_change + name: Absolute change + description: The absolute change from the previous year +views: + - dimensions: + source: all + metric: total + indicator_path: + 900831: y + - dimensions: + source: all + metric: per_capita + indicator_path: + 900839: y + - dimensions: + source: all + metric: share_total + - dimensions: + source: all + metric: proportional_change + indicator_path: + 900830: y + - dimensions: + source: all + metric: absolute_change + indicator_path: + 900832: y + + - dimensions: + source: fossil + metric: total + - dimensions: + source: fossil + metric: per_capita + - dimensions: + source: fossil + metric: share_total + - dimensions: + source: fossil + metric: proportional_change + - dimensions: + source: fossil + metric: absolute_change + + - dimensions: + source: coal + metric: total + - dimensions: + source: coal + metric: per_capita + - dimensions: + source: coal + metric: share_total + - dimensions: + source: coal + metric: proportional_change + - dimensions: + source: coal + metric: absolute_change + + - dimensions: + source: oil + metric: total + - dimensions: + source: oil + metric: per_capita + - dimensions: + source: oil + metric: share_total + - dimensions: + source: oil + metric: proportional_change + - dimensions: + source: oil + metric: absolute_change + + - dimensions: + source: gas + metric: total + - dimensions: + source: gas + metric: per_capita + - dimensions: + source: gas + metric: share_total + - dimensions: + source: gas + metric: proportional_change + - dimensions: + source: gas + metric: absolute_change + + - dimensions: + source: low-carbon + metric: total + - dimensions: + source: low-carbon + metric: per_capita + - dimensions: + source: low-carbon + metric: share_total + - dimensions: + source: low-carbon + metric: proportional_change + - dimensions: + source: low-carbon + metric: absolute_change + + - dimensions: + source: nuclear + metric: total + - dimensions: + source: nuclear + metric: per_capita + - dimensions: + source: nuclear + metric: share_total + - dimensions: + source: nuclear + metric: proportional_change + - dimensions: + source: nuclear + metric: absolute_change + + - dimensions: + source: renewable + metric: total + - dimensions: + source: renewable + metric: per_capita + - dimensions: + source: renewable + metric: share_total + - dimensions: + source: renewable + metric: proportional_change + - dimensions: + source: renewable + metric: absolute_change + + - dimensions: + source: hydro + metric: total + - dimensions: + source: hydro + metric: per_capita + - dimensions: + source: hydro + metric: share_total + - dimensions: + source: hydro + metric: proportional_change + - dimensions: + source: hydro + metric: absolute_change + + - dimensions: + source: solar-wind + metric: total + - dimensions: + source: solar-wind + metric: per_capita + - dimensions: + source: solar-wind + metric: share_total + - dimensions: + source: solar-wind + metric: proportional_change + - dimensions: + source: solar-wind + metric: absolute_change + + - dimensions: + source: solar + metric: total + - dimensions: + source: solar + metric: per_capita + - dimensions: + source: solar + metric: share_total + - dimensions: + source: solar + metric: proportional_change + - dimensions: + source: solar + metric: absolute_change + + - dimensions: + source: wind + metric: total + - dimensions: + source: wind + metric: per_capita + - dimensions: + source: wind + metric: share_total + - dimensions: + source: wind + metric: proportional_change + - dimensions: + source: wind + metric: absolute_change diff --git a/public/multi-dim/life-expectancy.json b/public/multi-dim/life-expectancy.json new file mode 100644 index 00000000000..082b7270f92 --- /dev/null +++ b/public/multi-dim/life-expectancy.json @@ -0,0 +1,193 @@ +{ + "name": "Life expectancy", + "dimensions_title": "by age and sex", + "dimensions": [ + { + "slug": "age", + "name": "Age", + "description": "The age at which the life expectancy is measured.", + "multi_select": true, + "choices": [ + { + "slug": "0", + "name": "At birth" + }, + { + "slug": "15", + "name": "At age 15", + "description": "The expected age a 15-year-old would reach if current mortality rates continue." + } + ], + "_hidden_choices": [ + { + "slug": "65", + "name": "At age 65", + "description": "The expected age a 65-year-old would reach if current mortality rates continue." + }, + { + "slug": "80", + "name": "At age 80", + "description": "The expected age a 80-year-old would reach if current mortality rates continue. This number will always be higher than 80." + } + ] + }, + { + "slug": "sex", + "name": "Sex", + "choices": [ + { + "slug": "both", + "name": "Both sexes" + }, + { + "slug": "female", + "name": "Female" + }, + { + "slug": "male", + "name": "Male" + } + ] + }, + { + "slug": "projection", + "name": "Projection", + "description": "The UNWPP projection scenario to use", + "choices": [ + { + "slug": "none", + "name": "No projection (estimates only)", + "description": "Only historical data, no projections into the future." + }, + { + "slug": "medium", + "name": "Medium projection scenario", + "description": "Projections into the future based on UNWPP's medium-fertility scenario." + } + ] + } + ], + "views": [ + { + "dimensions": { "age": "0", "sex": "both", "projection": "none" }, + "indicator_path": { "520369": "y" }, + "config": { + "title": "Life expectancy at birth", + "hasMapTab": true + } + }, + { + "dimensions": { "age": "0", "sex": "both", "projection": "medium" }, + "indicator_path": { "520370": "y" }, + "config": { + "title": "Life expectancy at birth, medium projection", + "hasMapTab": true + } + }, + + { + "dimensions": { "age": "0", "sex": "male", "projection": "none" }, + "indicator_path": { "520349": "y" }, + "config": { + "title": "Male life expectancy at birth", + "hasMapTab": true + } + }, + { + "dimensions": { "age": "0", "sex": "male", "projection": "medium" }, + "indicator_path": { "520350": "y" }, + "config": { + "title": "Male life expectancy at birth, medium projection", + "hasMapTab": true + } + }, + + { + "dimensions": { "age": "0", "sex": "female", "projection": "none" }, + "indicator_path": { "520329": "y" }, + "config": { + "title": "Female life expectancy at birth", + "hasMapTab": true + } + }, + { + "dimensions": { + "age": "0", + "sex": "female", + "projection": "medium" + }, + "indicator_path": { "520330": "y" }, + "config": { + "title": "Female life expectancy at birth, medium projection", + "hasMapTab": true + } + }, + + { + "dimensions": { "age": "15", "sex": "both", "projection": "none" }, + "indicator_path": { "520379": "y" }, + "config": { + "title": "Life expectancy at age 15", + "hasMapTab": true + } + }, + { + "dimensions": { + "age": "15", + "sex": "both", + "projection": "medium" + }, + "indicator_path": { "520380": "y" }, + "config": { + "title": "Life expectancy at age 15, medium projection", + "hasMapTab": true + } + }, + + { + "dimensions": { "age": "15", "sex": "male", "projection": "none" }, + "indicator_path": { "520359": "y" }, + "config": { + "title": "Male life expectancy at age 15", + "hasMapTab": true + } + }, + { + "dimensions": { + "age": "15", + "sex": "male", + "projection": "medium" + }, + "indicator_path": { "520360": "y" }, + "config": { + "title": "Male life expectancy at age 15, medium projection", + "hasMapTab": true + } + }, + + { + "dimensions": { + "age": "15", + "sex": "female", + "projection": "none" + }, + "indicator_path": { "520338": "y" }, + "config": { + "title": "Female life expectancy at age 15", + "hasMapTab": true + } + }, + { + "dimensions": { + "age": "15", + "sex": "female", + "projection": "medium" + }, + "indicator_path": { "520340": "y" }, + "config": { + "title": "Female life expectancy at age 15, medium projection", + "hasMapTab": true + } + } + ] +} diff --git a/public/multi-dim/plastic.json b/public/multi-dim/plastic.json new file mode 100644 index 00000000000..1760e20bd70 --- /dev/null +++ b/public/multi-dim/plastic.json @@ -0,0 +1,95 @@ +{ + "name": "Plastic", + "dimensions_title": "waste and pollution", + "dimensions": [ + { + "slug": "metric", + "name": "Metric", + "multi_select": true, + "choices": [ + { + "slug": "waste_gen", + "name": "Plastic waste generation", + "description": "The amount of plastic waste generated. Prior to management, i.e. this also includes waste that is properly incinerated or recycled." + }, + { + "slug": "waste_mismanaged", + "name": "Mismanaged waste", + "description": "Mismanaged plastic waste includes materials burned in open pits, dumped into seas or open waters, or disposed of in unsanitary landfills and dumpsites." + }, + { + "slug": "emitted_to_ocean", + "name": "Plastic emitted to ocean", + "description": "This is an annual estimate of plastic emissions. A country's total does not include waste that is exported overseas, which may be at higher risk of entering the ocean." + }, + { + "slug": "trade_exports", + "name": "Trade: exports", + "description": "Plastic waste that is exported by all modes of transport in a given year." + }, + { + "slug": "trade_imports", + "name": "Trade: imports", + "description": "Plastic waste that is imported by all modes of transport in a given year." + }, + { + "slug": "trade_net_exports", + "name": "Trade: net exports", + "description": "Net exports of plastic waste are calculated as a country's plastic waste exports minus its imports." + } + ] + }, + { + "slug": "measurement", + "name": "Measurement", + "choices": [ + { + "slug": "per_capita", + "name": "Per capita", + "description": "Per capita values are calculated by dividing the total amount by the population of the country." + }, + { + "slug": "total", + "name": "Total" + }, + { + "slug": "share_of_world", + "name": "Share of world total", + "description": "The share of the world total is calculated by dividing the country's total by the global total." + } + ] + } + ], + "views": [ + { + "dimensions": { "metric": "waste_gen", "measurement": "total" }, + "indicator_path": { "97679": "y" }, + "config": { + "title": "Plastic waste generation", + "subtitle": "This measures total plastic waste generation prior to management and therefore does not represent the quantity of plastic at risk of polluting waterways, rivers and the ocean environment." + } + }, + { + "dimensions": { + "metric": "waste_gen", + "measurement": "per_capita" + }, + "indicator_path": { "65358": "y" }, + "config": { + "title": "Plastic waste generation per capita", + "subtitle": "This measures total plastic waste generation prior to management and therefore does not represent the quantity of plastic at risk of polluting waterways, rivers and the ocean environment." + } + }, + { + "dimensions": { + "metric": "waste_gen", + "measurement": "share_of_world" + }, + "indicator_path": { "146456": "y" }, + "config": { + "title": "Plastic waste generation", + "subtitle": "This measures total plastic waste generation prior to management and therefore does not represent the quantity of plastic at risk of polluting waterways, rivers and the ocean environment." + } + } + ] +} diff --git a/public/multi-dim/poverty.yml b/public/multi-dim/poverty.yml new file mode 100644 index 00000000000..8be35f83ea1 --- /dev/null +++ b/public/multi-dim/poverty.yml @@ -0,0 +1,226 @@ +name: Poverty +dimensions_title: by poverty line +dimensions: + - slug: povertyLine + name: Poverty line + description: The poverty line to display, in 2017 international $ + choices: + - slug: "2.15" + name: 2.15 int.$ + - slug: "3.65" + name: 3.65 int.$ + - slug: "6.85" + name: 6.85 int.$ + - slug: "10" + name: 10 int.$ + - slug: "20" + name: 20 int.$ + - slug: "20" + name: 20 int.$ + - slug: "30" + name: 30 int.$ + - slug: "40" + name: 40 int.$ + - slug: all + name: all + description: show all poverty lines at the same time + - slug: metric + name: Metric + choices: + - slug: absolute + name: Number of people + - slug: share + name: Share of population + - slug: shareVsGdp + name: Share of population VS GDP per capita +views: + - dimensions: + povertyLine: "2.15" + metric: share + config: + hasMapTab: true + indicator_path: + 819727: y + - dimensions: + povertyLine: "3.65" + metric: share + indicator_path: + 819729: y + config: + hasMapTab: true + - dimensions: + povertyLine: "6.85" + metric: share + indicator_path: + 819731: y + config: + hasMapTab: true + - dimensions: + povertyLine: "10" + metric: share + indicator_path: + 819725: y + config: + hasMapTab: true + - dimensions: + povertyLine: "20" + metric: share + indicator_path: + 819726: y + config: + hasMapTab: true + - dimensions: + povertyLine: "30" + metric: share + indicator_path: + 819728: y + config: + hasMapTab: true + - dimensions: + povertyLine: "40" + metric: share + indicator_path: + 819730: y + config: + hasMapTab: true + - dimensions: + povertyLine: "2.15" + metric: shareVsGdp + indicator_path: + 819727: y + 539760: x + config: + hasMapTab: true + type: ScatterPlot + xAxis: + scaleType: log + - dimensions: + povertyLine: "3.65" + metric: shareVsGdp + indicator_path: + 819729: y + 539760: x + config: + hasMapTab: true + type: ScatterPlot + xAxis: + scaleType: log + - dimensions: + povertyLine: "6.85" + metric: shareVsGdp + indicator_path: + 819731: y + 539760: x + config: + hasMapTab: true + type: ScatterPlot + xAxis: + scaleType: log + - dimensions: + povertyLine: "10" + metric: shareVsGdp + indicator_path: + 819725: y + 539760: x + config: + hasMapTab: true + type: ScatterPlot + xAxis: + scaleType: log + - dimensions: + povertyLine: "20" + metric: shareVsGdp + indicator_path: + 819726: y + 539760: x + config: + hasMapTab: true + type: ScatterPlot + xAxis: + scaleType: log + - dimensions: + povertyLine: "30" + metric: shareVsGdp + indicator_path: + 819728: y + 539760: x + config: + hasMapTab: true + type: ScatterPlot + xAxis: + scaleType: log + - dimensions: + povertyLine: "40" + metric: shareVsGdp + indicator_path: + 819730: y + 539760: x + config: + hasMapTab: true + type: ScatterPlot + xAxis: + scaleType: log + - dimensions: + povertyLine: "2.15" + metric: absolute + indicator_path: + 819719: y + config: + hasMapTab: true + - dimensions: + povertyLine: "3.65" + metric: absolute + indicator_path: + 819721: y + config: + hasMapTab: true + - dimensions: + povertyLine: "6.85" + metric: absolute + indicator_path: + 819723: y + config: + hasMapTab: true + - dimensions: + povertyLine: "10" + metric: absolute + indicator_path: + 819717: y + config: + hasMapTab: true + - dimensions: + povertyLine: "20" + metric: absolute + indicator_path: + 819718: y + config: + hasMapTab: true + - dimensions: + povertyLine: "30" + metric: absolute + indicator_path: + 819720: y + config: + hasMapTab: true + - dimensions: + povertyLine: "40" + metric: absolute + indicator_path: + 819722: y + config: + hasMapTab: true + - dimensions: + povertyLine: all + metric: share + indicator_path: + - 819811: y + - 819826: y + - 819824: y + - 819822: y + - 819820: y + - 819818: y + - 819816: y + - 819815: y + config: + type: StackedArea + hasMapTab: true diff --git a/site/GrapherWithFallback.tsx b/site/GrapherWithFallback.tsx index 3849df575ff..b9b18acea4e 100644 --- a/site/GrapherWithFallback.tsx +++ b/site/GrapherWithFallback.tsx @@ -1,4 +1,4 @@ -import { Grapher } from "@ourworldindata/grapher" +import { Grapher, GrapherManager } from "@ourworldindata/grapher" import React from "react" import { GrapherFigureView } from "./GrapherFigureView.js" import cx from "classnames" @@ -7,14 +7,18 @@ import GrapherImage from "./GrapherImage.js" export const GrapherWithFallback = ({ grapher, + manager, slug, className, id, + getGrapherInstance, }: { grapher?: Grapher | undefined + manager?: GrapherManager slug?: string className?: string id?: string + getGrapherInstance?: (grapher: Grapher) => void }) => { return (
<> {grapher ? ( - + ) : ( // Render fallback svg when javascript disabled or while // grapher is loading diff --git a/site/multi-dim/MultiDimDataPage.tsx b/site/multi-dim/MultiDimDataPage.tsx new file mode 100644 index 00000000000..b42dbc0326c --- /dev/null +++ b/site/multi-dim/MultiDimDataPage.tsx @@ -0,0 +1,101 @@ +import React from "react" +import { MultiDimDataPageConfig } from "./MultiDimDataPageConfig.js" +import { Head } from "../Head.js" +import { IFrameDetector } from "../IframeDetector.js" +import { SiteHeader } from "../SiteHeader.js" +import { OWID_DATAPAGE_CONTENT_ROOT_ID } from "../DataPageV2Content.js" +import { SiteFooter } from "../SiteFooter.js" +import { SiteFooterContext, serializeJSONForHTML } from "@ourworldindata/utils" + +export const MultiDimDataPage = (props: { + baseUrl: string + config: MultiDimDataPageConfig +}) => { + const canonicalUrl = "" // TODO + const baseUrl = props.baseUrl // TODO + return ( + + + {/* + */} + + + {/* + {variableIds.flatMap((variableId) => + [ + getVariableDataRoute(DATA_API_URL, variableId), + getVariableMetadataRoute(DATA_API_URL, variableId), + ].map((href) => ( + + )) + )} */} + + + + +
+ {/*