diff --git a/baker/formatWordpressPost.tsx b/baker/formatWordpressPost.tsx
index 67db2683f2c..0be77af7b6f 100644
--- a/baker/formatWordpressPost.tsx
+++ b/baker/formatWordpressPost.tsx
@@ -49,7 +49,7 @@ import {
renderAdditionalInformation,
} from "../site/blocks/AdditionalInformation.js"
import { renderHelp } from "../site/blocks/Help.js"
-import { renderCodeSnippets } from "../site/blocks/CodeSnippet.js"
+import { renderCodeSnippets } from "@ourworldindata/components"
import { renderExpandableParagraphs } from "../site/blocks/ExpandableParagraph.js"
import {
formatUrls,
diff --git a/site/blocks/CodeSnippet.stories.tsx b/packages/@ourworldindata/components/src/CodeSnippet/CodeSnippet.stories.tsx
similarity index 100%
rename from site/blocks/CodeSnippet.stories.tsx
rename to packages/@ourworldindata/components/src/CodeSnippet/CodeSnippet.stories.tsx
diff --git a/site/blocks/CodeSnippet.tsx b/packages/@ourworldindata/components/src/CodeSnippet/CodeSnippet.tsx
similarity index 100%
rename from site/blocks/CodeSnippet.tsx
rename to packages/@ourworldindata/components/src/CodeSnippet/CodeSnippet.tsx
diff --git a/site/blocks/code-snippet.scss b/packages/@ourworldindata/components/src/CodeSnippet/code-snippet.scss
similarity index 100%
rename from site/blocks/code-snippet.scss
rename to packages/@ourworldindata/components/src/CodeSnippet/code-snippet.scss
diff --git a/packages/@ourworldindata/components/src/IndicatorBrief/IndicatorBrief.tsx b/packages/@ourworldindata/components/src/IndicatorBrief/IndicatorBrief.tsx
index cec0ada9257..df53055a12b 100644
--- a/packages/@ourworldindata/components/src/IndicatorBrief/IndicatorBrief.tsx
+++ b/packages/@ourworldindata/components/src/IndicatorBrief/IndicatorBrief.tsx
@@ -3,10 +3,8 @@ import { faArrowDown } from "@fortawesome/free-solid-svg-icons/faArrowDown"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome/index.js"
import { ExpandableToggle } from "../ExpandableToggle/ExpandableToggle.js"
import { SimpleMarkdownText } from "../SimpleMarkdownText.js"
-import {
- DATAPAGE_SOURCES_AND_PROCESSING_SECTION_ID,
- dayjs,
-} from "@ourworldindata/utils"
+import { dayjs } from "@ourworldindata/utils"
+import { DATAPAGE_SOURCES_AND_PROCESSING_SECTION_ID } from "../SharedDataPageConstants.js"
interface IndicatorBriefProps {
descriptionShort: string | undefined
diff --git a/packages/@ourworldindata/components/src/IndicatorSources/IndicatorSources.tsx b/packages/@ourworldindata/components/src/IndicatorSources/IndicatorSources.tsx
new file mode 100644
index 00000000000..77a592ac5e3
--- /dev/null
+++ b/packages/@ourworldindata/components/src/IndicatorSources/IndicatorSources.tsx
@@ -0,0 +1,122 @@
+import React from "react"
+import { ExpandableToggle } from "../ExpandableToggle/ExpandableToggle.js"
+import { OwidOrigin } from "@ourworldindata/utils"
+import { SimpleMarkdownText } from "../SimpleMarkdownText.js"
+import { CodeSnippet } from "../CodeSnippet/CodeSnippet.js"
+import { REUSE_THIS_WORK_SECTION_ID } from "../SharedDataPageConstants.js"
+
+export type OriginSubset = Pick<
+ OwidOrigin,
+ | "producer"
+ | "descriptionSnapshot"
+ | "dateAccessed"
+ | "urlMain"
+ | "description"
+ | "citationFull"
+>
+
+export interface IndicatorSourcesProps {
+ origins: OriginSubset[]
+}
+
+export const IndicatorSources = (props: IndicatorSourcesProps) => {
+ const citationFullBlockFn = (source: OriginSubset) => {
+ source.citationFull && (
+
+
Citation
+ This is the citation of the original data obtained from the
+ source, prior to any processing or adaptation by Our World in
+ Data. To cite data downloaded from this page, please use the
+ suggested citation given in{" "}
+
+ Reuse This Work
+ {" "}
+ below.
+
+
+ )
+ }
+ return (
+
+
+ This data is based on the following sources
+
+
+ {props.origins.map((source, idx: number, sources) => {
+ return (
+
+
+ {source.description && (
+
+
+
+ )}
+ {(source.dateAccessed ||
+ source.urlMain) && (
+
+ {source.dateAccessed && (
+
+
+ Retrieved on
+
+
+ {
+ source.dateAccessed
+ }
+
+
+ )}
+ {source.urlMain && (
+
+ )}
+ {citationFullBlockFn(source)}
+
+ )}
+ >
+ }
+ />
+
+ )
+ })}
+
+
+ )
+}
diff --git a/packages/@ourworldindata/utils/src/SharedConstants.ts b/packages/@ourworldindata/components/src/SharedDataPageConstants.ts
similarity index 61%
rename from packages/@ourworldindata/utils/src/SharedConstants.ts
rename to packages/@ourworldindata/components/src/SharedDataPageConstants.ts
index d95b78778fb..9c9be698ec2 100644
--- a/packages/@ourworldindata/utils/src/SharedConstants.ts
+++ b/packages/@ourworldindata/components/src/SharedDataPageConstants.ts
@@ -1,2 +1,3 @@
export const DATAPAGE_SOURCES_AND_PROCESSING_SECTION_ID =
"sources-and-processing" as const
+export const REUSE_THIS_WORK_SECTION_ID = "reuse-this-work"
diff --git a/packages/@ourworldindata/components/src/index.ts b/packages/@ourworldindata/components/src/index.ts
index f9e4e8757f0..249d02cf71a 100644
--- a/packages/@ourworldindata/components/src/index.ts
+++ b/packages/@ourworldindata/components/src/index.ts
@@ -27,3 +27,19 @@ export {
export { ExpandableToggle } from "./ExpandableToggle/ExpandableToggle.js"
export { IndicatorBrief } from "./IndicatorBrief/IndicatorBrief.js"
+
+export {
+ IndicatorSources,
+ type OriginSubset,
+} from "./IndicatorSources/IndicatorSources.js"
+
+export {
+ CodeSnippet,
+ hydrateCodeSnippets,
+ renderCodeSnippets,
+} from "./CodeSnippet/CodeSnippet.js"
+
+export {
+ DATAPAGE_SOURCES_AND_PROCESSING_SECTION_ID,
+ REUSE_THIS_WORK_SECTION_ID,
+} from "./SharedDataPageConstants.js"
diff --git a/packages/@ourworldindata/grapher/src/footer/Footer.tsx b/packages/@ourworldindata/grapher/src/footer/Footer.tsx
index dcb99db62ba..d7d469596bf 100644
--- a/packages/@ourworldindata/grapher/src/footer/Footer.tsx
+++ b/packages/@ourworldindata/grapher/src/footer/Footer.tsx
@@ -2,13 +2,12 @@ import React from "react"
import { observable, computed, action } from "mobx"
import { observer } from "mobx-react"
import parseUrl from "url-parse"
+import { Bounds, DEFAULT_BOUNDS, getRelativeMouse } from "@ourworldindata/utils"
import {
- Bounds,
- DEFAULT_BOUNDS,
- getRelativeMouse,
DATAPAGE_SOURCES_AND_PROCESSING_SECTION_ID,
-} from "@ourworldindata/utils"
-import { MarkdownTextWrap, TextWrap } from "@ourworldindata/components"
+ MarkdownTextWrap,
+ TextWrap,
+} from "@ourworldindata/components"
import { Tooltip } from "../tooltip/Tooltip"
import { FooterManager } from "./FooterManager"
import { ActionButtons } from "../controls/ActionButtons"
diff --git a/packages/@ourworldindata/utils/src/index.ts b/packages/@ourworldindata/utils/src/index.ts
index 5cdf2bd106e..51f21bb14d7 100644
--- a/packages/@ourworldindata/utils/src/index.ts
+++ b/packages/@ourworldindata/utils/src/index.ts
@@ -611,5 +611,3 @@ export {
gdocIdRegex,
detailOnDemandRegex,
} from "./GdocsConstants.js"
-
-export { DATAPAGE_SOURCES_AND_PROCESSING_SECTION_ID } from "./SharedConstants"
diff --git a/site/DataPageContent.tsx b/site/DataPageContent.tsx
index 2d36372cc3c..c08ef7bfaae 100644
--- a/site/DataPageContent.tsx
+++ b/site/DataPageContent.tsx
@@ -2,21 +2,21 @@ import React, { useEffect } from "react"
import { faArrowDown } from "@fortawesome/free-solid-svg-icons/faArrowDown"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome/index.js"
import { Grapher, GrapherInterface } from "@ourworldindata/grapher"
-import { ExpandableToggle } from "@ourworldindata/components"
+import {
+ ExpandableToggle,
+ CodeSnippet,
+ DATAPAGE_SOURCES_AND_PROCESSING_SECTION_ID,
+} from "@ourworldindata/components"
import ReactDOM from "react-dom"
import { GrapherWithFallback } from "./GrapherWithFallback.js"
import { formatAuthors } from "./clientFormatting.js"
import { ArticleBlocks } from "./gdocs/ArticleBlocks.js"
import { RelatedCharts } from "./blocks/RelatedCharts.js"
-import {
- DataPageContentFields,
- DATAPAGE_SOURCES_AND_PROCESSING_SECTION_ID,
-} from "@ourworldindata/utils"
+import { DataPageContentFields } from "@ourworldindata/utils"
import { AttachmentsContext, DocumentContext } from "./gdocs/OwidGdoc.js"
import StickyNav from "./blocks/StickyNav.js"
import cx from "classnames"
import { DebugProvider } from "./gdocs/DebugContext.js"
-import { CodeSnippet } from "./blocks/CodeSnippet.js"
import { DATA_API_URL } from "../settings/clientSettings.js"
declare global {
diff --git a/site/DataPageV2Content.tsx b/site/DataPageV2Content.tsx
index a4e5e3c821d..0b6cebc6839 100644
--- a/site/DataPageV2Content.tsx
+++ b/site/DataPageV2Content.tsx
@@ -1,9 +1,13 @@
import React, { useEffect } from "react"
import { Grapher, GrapherInterface } from "@ourworldindata/grapher"
import {
- ExpandableToggle,
markdownToEnrichedTextBlock,
IndicatorBrief,
+ CodeSnippet,
+ REUSE_THIS_WORK_SECTION_ID,
+ OriginSubset,
+ IndicatorSources,
+ DATAPAGE_SOURCES_AND_PROCESSING_SECTION_ID,
} from "@ourworldindata/components"
import ReactDOM from "react-dom"
import { GrapherWithFallback } from "./GrapherWithFallback.js"
@@ -12,17 +16,14 @@ import { RelatedCharts } from "./blocks/RelatedCharts.js"
import {
DataPageV2ContentFields,
slugify,
- DATAPAGE_SOURCES_AND_PROCESSING_SECTION_ID,
uniq,
pick,
- OwidOrigin,
formatAuthors,
} from "@ourworldindata/utils"
import { AttachmentsContext, DocumentContext } from "./gdocs/OwidGdoc.js"
import StickyNav from "./blocks/StickyNav.js"
import cx from "classnames"
import { DebugProvider } from "./gdocs/DebugContext.js"
-import { CodeSnippet } from "./blocks/CodeSnippet.js"
import dayjs from "dayjs"
declare global {
interface Window {
@@ -85,16 +86,6 @@ export const slugify_topic = (topic: string) => {
return slugify(replaced)
}
-type OriginSubset = Pick<
- OwidOrigin,
- | "producer"
- | "descriptionSnapshot"
- | "dateAccessed"
- | "urlMain"
- | "description"
- | "citationFull"
->
-
export const DataPageV2Content = ({
datapageData,
grapherConfig,
@@ -118,8 +109,6 @@ export const DataPageV2Content = ({
setGrapher(new Grapher(mergedGrapherConfig))
}, [mergedGrapherConfig])
- const REUSE_THIS_WORK_ANCHOR = "#reuse-this-work"
-
const stickyNavLinks = [
{
text: "Explore the Data",
@@ -136,7 +125,7 @@ export const DataPageV2Content = ({
text: "Sources & Processing",
target: "#" + DATAPAGE_SOURCES_AND_PROCESSING_SECTION_ID,
},
- { text: "Reuse This Work", target: REUSE_THIS_WORK_ANCHOR },
+ { text: "Reuse This Work", target: "#" + REUSE_THIS_WORK_SECTION_ID },
]
const hasRelatedDataFeatured = datapageData.relatedData?.some(
@@ -195,25 +184,6 @@ export const DataPageV2Content = ({
relatedCharts = [],
} = faqEntries ?? {}
- const citationFullBlockFn = (source: OriginSubset) => {
- source.citationFull && (
-
-
Citation
- This is the citation of the original data obtained from the
- source, prior to any processing or adaptation by Our World in
- Data. To cite data downloaded from this page, please use the
- suggested citation given in{" "}
-
Reuse This Work below.
-
-
- )
- }
-
const dateRange = getDateRange(datapageData.dateRange)
const citationDatapage = datapageData.primaryTopic
@@ -472,107 +442,7 @@ export const DataPageV2Content = ({
>
Sources and processing
- {origins.length > 0 && (
-
-
- This data is based on the following
- sources
-
-
- {origins.map(
- (
- source,
- idx: number,
- sources
- ) => {
- return (
-
-
- {source.description && (
-
- )}
- {(source.dateAccessed ||
- source.urlMain) && (
-
- {source.dateAccessed && (
-
-
- Retrieved
- on
-
-
- {
- source.dateAccessed
- }
-
-
- )}
- {source.urlMain && (
-
-
- Retrieved
- from
-
-
-
- )}
- {citationFullBlockFn(
- source
- )}
-
- )}
- >
- }
- />
-
- )
- }
- )}
-
-
- )}
+
How we process data at Our World in Data
diff --git a/site/LongFormPage.tsx b/site/LongFormPage.tsx
index be87646c754..79b65812312 100644
--- a/site/LongFormPage.tsx
+++ b/site/LongFormPage.tsx
@@ -21,7 +21,7 @@ import { Byline } from "./Byline.js"
import { PageInfo } from "./PageInfo.js"
import { BackToTopic } from "./BackToTopic.js"
import StickyNav from "./blocks/StickyNav.js"
-import { CodeSnippet } from "./blocks/CodeSnippet.js"
+import { CodeSnippet } from "@ourworldindata/components"
import { formatAuthors } from "./clientFormatting.js"
export interface PageOverrides {
diff --git a/site/gdocs/OwidGdoc.tsx b/site/gdocs/OwidGdoc.tsx
index 990e734e17a..b5a36005043 100644
--- a/site/gdocs/OwidGdoc.tsx
+++ b/site/gdocs/OwidGdoc.tsx
@@ -15,7 +15,7 @@ import {
OwidGdocType,
formatAuthors,
} from "@ourworldindata/utils"
-import { CodeSnippet } from "../blocks/CodeSnippet.js"
+import { CodeSnippet } from "@ourworldindata/components"
import { BAKED_BASE_URL } from "../../settings/clientSettings.js"
import { DebugProvider } from "./DebugContext.js"
import { OwidGdocHeader } from "./OwidGdocHeader.js"
diff --git a/site/owid.scss b/site/owid.scss
index 8630c61388a..6fbc4c351d6 100644
--- a/site/owid.scss
+++ b/site/owid.scss
@@ -70,7 +70,7 @@
@import "./blocks/CookiePreferences.scss";
@import "./blocks/Grid.scss";
@import "./blocks/Card.scss";
-@import "./blocks/code-snippet.scss";
+@import "../packages/@ourworldindata/components/src/CodeSnippet/code-snippet.scss";
@import "./blocks/BiographyCard.scss";
@import "./blocks/KeyInsights.scss";
@import "./blocks/TechnicalText.scss";
diff --git a/site/runSiteFooterScripts.ts b/site/runSiteFooterScripts.ts
index 596419821b5..0c9d6bdf8a0 100644
--- a/site/runSiteFooterScripts.ts
+++ b/site/runSiteFooterScripts.ts
@@ -16,7 +16,7 @@ import { runSearchCountry } from "./SearchCountry.js"
import { hydrate as hydrateAdditionalInformation } from "./blocks/AdditionalInformation.js"
import { hydrateKeyInsights } from "./blocks/KeyInsights.js"
import { hydrateExpandableParagraphs } from "./blocks/ExpandableParagraph.js"
-import { hydrateCodeSnippets } from "./blocks/CodeSnippet.js"
+import { hydrateCodeSnippets } from "@ourworldindata/components"
import { hydrateStickyNav } from "./blocks/StickyNav.js"
export const runSiteFooterScripts = (