From 19c78e3909dfc47c4be5ad46d85a755fb753af43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ra=C4=8D=C3=A1k?= Date: Thu, 12 Dec 2024 10:14:18 +0100 Subject: [PATCH] Add code ArchieML component Reuses the existing CodeSnippet component. --- db/model/Gdoc/GdocBase.ts | 1 + db/model/Gdoc/enrichedToMarkdown.ts | 5 +++++ db/model/Gdoc/enrichedToRaw.ts | 8 ++++++++ db/model/Gdoc/exampleEnrichedBlocks.ts | 10 ++++++++++ db/model/Gdoc/gdocUtils.ts | 1 + db/model/Gdoc/rawToArchie.ts | 12 ++++++++++++ db/model/Gdoc/rawToEnriched.ts | 15 +++++++++++++++ .../components/src/CodeSnippet/CodeSnippet.tsx | 9 ++++++++- .../types/src/gdocTypes/ArchieMlComponents.ts | 12 ++++++++++++ packages/@ourworldindata/types/src/index.ts | 2 ++ packages/@ourworldindata/utils/src/Util.ts | 1 + packages/@ourworldindata/utils/src/index.ts | 2 +- packages/@ourworldindata/utils/src/string.ts | 4 ++++ site/gdocs/components/ArticleBlock.tsx | 8 +++++++- site/gdocs/pages/AboutPage.scss | 12 ++++++++---- 15 files changed, 95 insertions(+), 7 deletions(-) diff --git a/db/model/Gdoc/GdocBase.ts b/db/model/Gdoc/GdocBase.ts index df1b60d25ed..5e7a0fb7a33 100644 --- a/db/model/Gdoc/GdocBase.ts +++ b/db/model/Gdoc/GdocBase.ts @@ -544,6 +544,7 @@ export class GdocBase implements OwidGdocBaseInterface { "aside", "blockquote", "callout", + "code", "donors", "expandable-paragraph", "entry-summary", diff --git a/db/model/Gdoc/enrichedToMarkdown.ts b/db/model/Gdoc/enrichedToMarkdown.ts index ae7a4f28498..a186f859300 100644 --- a/db/model/Gdoc/enrichedToMarkdown.ts +++ b/db/model/Gdoc/enrichedToMarkdown.ts @@ -127,6 +127,11 @@ ${items} exportComponents ) ) + .with({ type: "code" }, (b): string | undefined => { + return ( + "```\n" + b.text.map((text) => text.value).join("\n") + "\n```" + ) + }) .with({ type: "donors" }, (_): string | undefined => markdownComponent("DonorList", {}, exportComponents) ) diff --git a/db/model/Gdoc/enrichedToRaw.ts b/db/model/Gdoc/enrichedToRaw.ts index ebc84320256..db819e092e4 100644 --- a/db/model/Gdoc/enrichedToRaw.ts +++ b/db/model/Gdoc/enrichedToRaw.ts @@ -48,6 +48,7 @@ import { RawBlockPeople, RawBlockPeopleRows, RawBlockPerson, + RawBlockCode, } from "@ourworldindata/types" import { spanToHtmlString } from "./gdocUtils.js" import { match, P } from "ts-pattern" @@ -122,6 +123,13 @@ export function enrichedBlockToRawBlock( }, }) ) + .with( + { type: "code" }, + (b): RawBlockCode => ({ + type: b.type, + value: b.text, + }) + ) .with( { type: "donors" }, (b): RawBlockDonorList => ({ diff --git a/db/model/Gdoc/exampleEnrichedBlocks.ts b/db/model/Gdoc/exampleEnrichedBlocks.ts index b059e9ff95c..f6189a6cc4b 100644 --- a/db/model/Gdoc/exampleEnrichedBlocks.ts +++ b/db/model/Gdoc/exampleEnrichedBlocks.ts @@ -92,6 +92,16 @@ export const enrichedBlockExamples: Record< caption: boldLinkExampleText, parseErrors: [], }, + code: { + type: "code", + text: [ + { + type: "text", + value: '', + }, + ], + parseErrors: [], + }, donors: { type: "donors", value: {}, diff --git a/db/model/Gdoc/gdocUtils.ts b/db/model/Gdoc/gdocUtils.ts index d672e9bbe6d..f08dfd85786 100644 --- a/db/model/Gdoc/gdocUtils.ts +++ b/db/model/Gdoc/gdocUtils.ts @@ -222,6 +222,7 @@ export function extractFilenamesFromBlock( "callout", "chart-story", "chart", + "code", "donors", "entry-summary", "expandable-paragraph", diff --git a/db/model/Gdoc/rawToArchie.ts b/db/model/Gdoc/rawToArchie.ts index 852e42ecb43..d151cb0f40e 100644 --- a/db/model/Gdoc/rawToArchie.ts +++ b/db/model/Gdoc/rawToArchie.ts @@ -47,6 +47,7 @@ import { RawBlockPeople, RawBlockPeopleRows, RawBlockPerson, + RawBlockCode, } from "@ourworldindata/types" import { isArray } from "@ourworldindata/utils" import { match } from "ts-pattern" @@ -127,6 +128,16 @@ function* rawBlockChartToArchieMLString( yield "{}" } +function* rawBlockCodeToArchieMLString( + block: RawBlockCode +): Generator { + yield "[.+code]" + for (const text of block.value) { + yield* OwidRawGdocBlockToArchieMLStringGenerator(text) + } + yield "[]" +} + function* rawBlockDonorListToArchieMLString( _block: RawBlockDonorList ): Generator { @@ -819,6 +830,7 @@ export function* OwidRawGdocBlockToArchieMLStringGenerator( .with({ type: "all-charts" }, rawBlockAllChartsToArchieMLString) .with({ type: "aside" }, rawBlockAsideToArchieMLString) .with({ type: "chart" }, rawBlockChartToArchieMLString) + .with({ type: "code" }, rawBlockCodeToArchieMLString) .with({ type: "donors" }, rawBlockDonorListToArchieMLString) .with({ type: "scroller" }, rawBlockScrollerToArchieMLString) .with({ type: "callout" }, rawBlockCalloutToArchieMLString) diff --git a/db/model/Gdoc/rawToEnriched.ts b/db/model/Gdoc/rawToEnriched.ts index 5f74a325b4f..5cb8230ea2a 100644 --- a/db/model/Gdoc/rawToEnriched.ts +++ b/db/model/Gdoc/rawToEnriched.ts @@ -129,6 +129,8 @@ import { EnrichedBlockPerson, RawBlockPeopleRows, EnrichedBlockPeopleRows, + RawBlockCode, + EnrichedBlockCode, } from "@ourworldindata/types" import { traverseEnrichedSpan, @@ -142,6 +144,7 @@ import { isArray, partition, compact, + toAsciiQuotes, } from "@ourworldindata/utils" import { checkIsInternalLink, getLinkType } from "@ourworldindata/components" import { @@ -169,6 +172,7 @@ export function parseRawBlocksToEnrichedBlocks( .with({ type: "blockquote" }, parseBlockquote) .with({ type: "callout" }, parseCallout) .with({ type: "chart" }, parseChart) + .with({ type: "code" }, parseCode) .with({ type: "donors" }, parseDonorList) .with({ type: "scroller" }, parseScroller) .with({ type: "chart-story" }, parseChartStory) @@ -492,6 +496,17 @@ const parseChart = (raw: RawBlockChart): EnrichedBlockChart => { } } +const parseCode = (raw: RawBlockCode): EnrichedBlockCode => { + return { + type: "code", + text: raw.value.map((text) => ({ + type: "text", + value: toAsciiQuotes(text.value), + })), + parseErrors: [], + } +} + const parseDonorList = (raw: RawBlockDonorList): EnrichedBlockDonorList => { return { type: "donors", diff --git a/packages/@ourworldindata/components/src/CodeSnippet/CodeSnippet.tsx b/packages/@ourworldindata/components/src/CodeSnippet/CodeSnippet.tsx index 634c8719eae..50a97ff17ec 100644 --- a/packages/@ourworldindata/components/src/CodeSnippet/CodeSnippet.tsx +++ b/packages/@ourworldindata/components/src/CodeSnippet/CodeSnippet.tsx @@ -8,11 +8,13 @@ import cx from "classnames" import { SimpleMarkdownText } from "../SimpleMarkdownText" export const CodeSnippet = ({ + className, code, theme = "dark", isTruncated = false, useMarkdown = false, }: { + className?: string code: string theme?: "dark" | "light" isTruncated?: boolean @@ -40,7 +42,12 @@ export const CodeSnippet = ({ } return ( -
+
                  // dummy value to unify block shapes
@@ -935,6 +945,7 @@ export type OwidRawGdocBlock =
     | RawBlockAside
     | RawBlockCallout
     | RawBlockChart
+    | RawBlockCode
     | RawBlockDonorList
     | RawBlockScroller
     | RawBlockChartStory
@@ -985,6 +996,7 @@ export type OwidEnrichedGdocBlock =
     | EnrichedBlockAside
     | EnrichedBlockCallout
     | EnrichedBlockChart
+    | EnrichedBlockCode
     | EnrichedBlockDonorList
     | EnrichedBlockScroller
     | EnrichedBlockChartStory
diff --git a/packages/@ourworldindata/types/src/index.ts b/packages/@ourworldindata/types/src/index.ts
index 49ede31ad51..029b936380b 100644
--- a/packages/@ourworldindata/types/src/index.ts
+++ b/packages/@ourworldindata/types/src/index.ts
@@ -170,6 +170,7 @@ export {
     type RawBlockChart,
     type RawBlockChartStory,
     type RawBlockChartValue,
+    type RawBlockCode,
     type RawBlockExpandableParagraph,
     type RawBlockExplorerTiles,
     type RawBlockGraySection,
@@ -226,6 +227,7 @@ export {
     type EnrichedBlockCallout,
     type EnrichedBlockChart,
     type EnrichedBlockChartStory,
+    type EnrichedBlockCode,
     type EnrichedBlockDonorList,
     type EnrichedBlockExpandableParagraph,
     type EnrichedBlockExplorerTiles,
diff --git a/packages/@ourworldindata/utils/src/Util.ts b/packages/@ourworldindata/utils/src/Util.ts
index 1811792dbb7..26a65f6d148 100644
--- a/packages/@ourworldindata/utils/src/Util.ts
+++ b/packages/@ourworldindata/utils/src/Util.ts
@@ -1708,6 +1708,7 @@ export function traverseEnrichedBlock(
                 type: P.union(
                     "chart-story",
                     "chart",
+                    "code",
                     "donors",
                     "horizontal-rule",
                     "html",
diff --git a/packages/@ourworldindata/utils/src/index.ts b/packages/@ourworldindata/utils/src/index.ts
index 752ce632323..d3a9d6e1912 100644
--- a/packages/@ourworldindata/utils/src/index.ts
+++ b/packages/@ourworldindata/utils/src/index.ts
@@ -293,7 +293,7 @@ export { Url, setWindowUrl, getWindowUrl } from "./urls/Url.js"
 
 export { type UrlMigration, performUrlMigrations } from "./urls/UrlMigration.js"
 
-export { camelCaseProperties, titleCase } from "./string.js"
+export { camelCaseProperties, titleCase, toAsciiQuotes } from "./string.js"
 
 export { serializeJSONForHTML, deserializeJSONFromHTML } from "./serializers.js"
 
diff --git a/packages/@ourworldindata/utils/src/string.ts b/packages/@ourworldindata/utils/src/string.ts
index 52353c514dc..b6dae99eaee 100644
--- a/packages/@ourworldindata/utils/src/string.ts
+++ b/packages/@ourworldindata/utils/src/string.ts
@@ -31,3 +31,7 @@ export const titleCase = (str: string): string => {
         })
         .join(" ")
 }
+
+export function toAsciiQuotes(str: string): string {
+    return str.replace(/[“”]/g, '"').replace(/[‘’]/g, "'")
+}
diff --git a/site/gdocs/components/ArticleBlock.tsx b/site/gdocs/components/ArticleBlock.tsx
index a10831d52c9..c644ec1c3cc 100644
--- a/site/gdocs/components/ArticleBlock.tsx
+++ b/site/gdocs/components/ArticleBlock.tsx
@@ -17,7 +17,7 @@ import {
     TocHeadingWithTitleSupertitle,
     Url,
 } from "@ourworldindata/utils"
-import { convertHeadingTextToId } from "@ourworldindata/components"
+import { CodeSnippet, convertHeadingTextToId } from "@ourworldindata/components"
 import SDGGrid from "./SDGGrid.js"
 import { BlockErrorBoundary, BlockErrorFallback } from "./BlockErrorBoundary.js"
 import { match } from "ts-pattern"
@@ -245,6 +245,12 @@ export default function ArticleBlock({
                 />
             )
         })
+        .with({ type: "code" }, (block) => (
+             text.value).join("\n")}
+            />
+        ))
         .with({ type: "donors" }, (_block) => (
             
         ))
diff --git a/site/gdocs/pages/AboutPage.scss b/site/gdocs/pages/AboutPage.scss
index 91651cb23e9..7a32487fd0a 100644
--- a/site/gdocs/pages/AboutPage.scss
+++ b/site/gdocs/pages/AboutPage.scss
@@ -97,14 +97,18 @@
         margin-bottom: 24px;
     }
 
-    .article-block__image {
-        margin: 0 0 24px;
-    }
-
     .article-block__chart {
         margin-bottom: 24px;
     }
 
+    .article-block__code-snippet {
+        margin-bottom: 16px;
+    }
+
+    .article-block__image {
+        margin: 0 0 24px;
+    }
+
     .article-block__prominent-link {
         margin-bottom: 24px;
     }