From fb75ee9b6b7d5f2b4d6ad6a832df610b0c0d6c52 Mon Sep 17 00:00:00 2001 From: Ike Saunders Date: Thu, 19 Oct 2023 18:11:28 -0400 Subject: [PATCH 01/12] =?UTF-8?q?=F0=9F=8E=89=20gdocs=20tables=20prelimina?= =?UTF-8?q?ry=20types=20and=20parsing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/model/Gdoc/Gdoc.ts | 1 + db/model/Gdoc/enrichedToRaw.ts | 20 ++ db/model/Gdoc/exampleEnrichedBlocks.ts | 87 ++++++++ db/model/Gdoc/gdocToArchie.ts | 188 +++++++++++------- db/model/Gdoc/rawToArchie.ts | 45 ++++- db/model/Gdoc/rawToEnriched.ts | 103 ++++++++++ packages/@ourworldindata/utils/src/Util.ts | 9 + packages/@ourworldindata/utils/src/index.ts | 7 + .../@ourworldindata/utils/src/owidTypes.ts | 40 ++++ site/gdocs/ArticleBlock.tsx | 5 + 10 files changed, 434 insertions(+), 71 deletions(-) diff --git a/db/model/Gdoc/Gdoc.ts b/db/model/Gdoc/Gdoc.ts index 2f112480df5..2876658e182 100644 --- a/db/model/Gdoc/Gdoc.ts +++ b/db/model/Gdoc/Gdoc.ts @@ -633,6 +633,7 @@ export class Gdoc extends BaseEntity implements OwidGdocInterface { "simple-text", "sticky-left", "sticky-right", + "table", "text" ), }, diff --git a/db/model/Gdoc/enrichedToRaw.ts b/db/model/Gdoc/enrichedToRaw.ts index 0ea822ada83..d4757fdb8ad 100644 --- a/db/model/Gdoc/enrichedToRaw.ts +++ b/db/model/Gdoc/enrichedToRaw.ts @@ -34,6 +34,7 @@ import { RawBlockAlign, RawBlockEntrySummary, RawBlockVideo, + RawBlockTable, } from "@ourworldindata/utils" import { spanToHtmlString } from "./gdocUtils.js" import { match, P } from "ts-pattern" @@ -400,5 +401,24 @@ export function enrichedBlockToRawBlock( }, } }) + .with({ type: "table" }, (b): RawBlockTable => { + return { + type: b.type, + value: { + template: b.template, + rows: b.rows.map((row) => ({ + type: row.type, + value: { + cells: row.cells.map((cell) => ({ + type: cell.type, + value: cell.content.map( + enrichedBlockToRawBlock + ), + })), + }, + })), + }, + } + }) .exhaustive() } diff --git a/db/model/Gdoc/exampleEnrichedBlocks.ts b/db/model/Gdoc/exampleEnrichedBlocks.ts index e63c8169da4..88486d475e9 100644 --- a/db/model/Gdoc/exampleEnrichedBlocks.ts +++ b/db/model/Gdoc/exampleEnrichedBlocks.ts @@ -441,4 +441,91 @@ export const enrichedBlockExamples: Record< items: [{ text: "Hello", slug: "#link-to-something" }], parseErrors: [], }, + table: { + type: "table", + template: "header-row", + rows: [ + { + type: "table-row", + cells: [ + { + type: "table-cell", + content: [ + { + type: "text", + value: [ + { + spanType: "span-simple-text", + text: "City", + }, + ], + parseErrors: [], + }, + { + type: "text", + value: [ + { + spanType: "span-simple-text", + text: "Continent", + }, + ], + parseErrors: [], + }, + ], + }, + { + type: "table-cell", + content: [ + { + type: "text", + value: [ + { + spanType: "span-simple-text", + text: "Wellington", + }, + ], + parseErrors: [], + }, + { + type: "text", + value: [ + { + spanType: "span-simple-text", + text: "Zealandia", + }, + ], + parseErrors: [], + }, + ], + }, + { + type: "table-cell", + content: [ + { + type: "text", + value: [ + { + spanType: "span-simple-text", + text: "Addis Ababa", + }, + ], + parseErrors: [], + }, + { + type: "text", + value: [ + { + spanType: "span-simple-text", + text: "Africa", + }, + ], + parseErrors: [], + }, + ], + }, + ], + }, + ], + parseErrors: [], + }, } diff --git a/db/model/Gdoc/gdocToArchie.ts b/db/model/Gdoc/gdocToArchie.ts index a84c562c683..fb0e9444a68 100644 --- a/db/model/Gdoc/gdocToArchie.ts +++ b/db/model/Gdoc/gdocToArchie.ts @@ -6,95 +6,145 @@ import { RawBlockHorizontalRule, RawBlockHeading, isNil, + RawBlockTable, + RawBlockTableRow, + OwidRawGdocBlock, + RawBlockTableCell, + RawBlockText, } from "@ourworldindata/utils" import { spanToHtmlString } from "./gdocUtils.js" import { OwidRawGdocBlockToArchieMLString } from "./rawToArchie.js" import { match, P } from "ts-pattern" +function paragraphToString(paragraph: docs_v1.Schema$Paragraph): string { + let text = "" + let isInList = false + + // this is a list + const needsBullet = !isNil(paragraph.bullet) + if (needsBullet && !isInList) { + isInList = true + text += `\n[.list]\n` + } else if (!needsBullet && isInList) { + isInList = false + text += `[]\n` + } + + if (paragraph.elements) { + // all values in the element + const values: docs_v1.Schema$ParagraphElement[] = paragraph.elements + + let idx = 0 + + const taggedText = function (text: string): string { + if (paragraph.paragraphStyle?.namedStyleType?.includes("HEADING")) { + const headingLevel = + paragraph.paragraphStyle.namedStyleType.replace( + "HEADING_", + "" + ) + + const heading: RawBlockHeading = { + type: "heading", + value: { + text: text.trim(), + level: headingLevel, + }, + } + return `\n${OwidRawGdocBlockToArchieMLString(heading)}` + } + return text + } + let elementText = "" + for (const value of values) { + // we only need to add a bullet to the first value, so we check + const isFirstValue = idx === 0 + + // prepend an asterisk if this is a list item + const prefix = needsBullet && isFirstValue ? "* " : "" + + // concat the text + const parsedParagraph = parseParagraph(value) + const fragmentText = match(parsedParagraph) + .with( + { type: P.union("horizontal-rule") }, + OwidRawGdocBlockToArchieMLString + ) + .with({ spanType: P.any }, (s) => spanToHtmlString(s)) + .with(P.nullish, () => "") + .exhaustive() + elementText += `${prefix}${fragmentText}` + idx++ + } + text += taggedText(elementText) + } + return text +} + +function tableToString( + table: docs_v1.Schema$StructuralElement["table"] +): string { + if (!table) return "" + let text = "" + const { tableRows = [] } = table + + const rows: RawBlockTableRow[] = [] + + for (const tableRow of tableRows) { + const rawRow: RawBlockTableRow = { + type: "table-row", + value: { + cells: [], + }, + } + const { tableCells = [] } = tableRow + for (const tableCell of tableCells) { + const rawCell: RawBlockTableCell = { + type: "table-cell", + value: [], + } + const { content = [] } = tableCell + for (const item of content) { + if (item.paragraph) { + const text = paragraphToString(item.paragraph) + const rawTextBlock: RawBlockText = { + type: "text", + value: text, + } + rawCell.value!.push(rawTextBlock) + } + } + rawRow.value!.cells!.push(rawCell) + } + rows.push(rawRow) + } + text += "\n[.+rows]" + for (const row of rows) { + text += `\n${OwidRawGdocBlockToArchieMLString(row)}` + } + text += "\n[]" + return text +} + export async function gdocToArchie( document: docs_v1.Schema$Document ): Promise<{ text: string }> { // prepare the text holder let text = "" - let isInList = false // check if the body key and content key exists, and give up if not if (!document.body) return { text } if (!document.body.content) return { text } // loop through each content element in the body - for (const element of document.body.content) { if (element.paragraph) { - // get the paragraph within the element - const paragraph: docs_v1.Schema$Paragraph = element.paragraph - - // this is a list - const needsBullet = !isNil(paragraph.bullet) - if (needsBullet && !isInList) { - isInList = true - text += `\n[.list]\n` - } else if (!needsBullet && isInList) { - isInList = false - text += `[]\n` - } - - if (paragraph.elements) { - // all values in the element - const values: docs_v1.Schema$ParagraphElement[] = - paragraph.elements - - let idx = 0 - - const taggedText = function (text: string): string { - if ( - paragraph.paragraphStyle?.namedStyleType?.includes( - "HEADING" - ) - ) { - const headingLevel = - paragraph.paragraphStyle.namedStyleType.replace( - "HEADING_", - "" - ) - - const heading: RawBlockHeading = { - type: "heading", - value: { - text: text.trim(), - level: headingLevel, - }, - } - return `\n${OwidRawGdocBlockToArchieMLString(heading)}` - } - return text - } - let elementText = "" - for (const value of values) { - // we only need to add a bullet to the first value, so we check - const isFirstValue = idx === 0 - - // prepend an asterisk if this is a list item - const prefix = needsBullet && isFirstValue ? "* " : "" - - // concat the text - const parsedParagraph = parseParagraph(value) - const fragmentText = match(parsedParagraph) - .with( - { type: P.union("horizontal-rule") }, - OwidRawGdocBlockToArchieMLString - ) - .with({ spanType: P.any }, (s) => spanToHtmlString(s)) - .with(P.nullish, () => "") - .exhaustive() - elementText += `${prefix}${fragmentText}` - idx++ - } - text += taggedText(elementText) - } + text += paragraphToString(element.paragraph) + } else if (element.table) { + text += tableToString(element.table) } } - + console.log("text", text) return { text } } diff --git a/db/model/Gdoc/rawToArchie.ts b/db/model/Gdoc/rawToArchie.ts index 59d901d76f4..8f12ad7f416 100644 --- a/db/model/Gdoc/rawToArchie.ts +++ b/db/model/Gdoc/rawToArchie.ts @@ -33,6 +33,8 @@ import { RawBlockAlign, RawBlockEntrySummary, isArray, + RawBlockTable, + RawBlockTableRow, } from "@ourworldindata/utils" import { match } from "ts-pattern" @@ -563,8 +565,45 @@ function* rawBlockEntrySummaryToArchieMLString( yield "{}" } +function* rawBlockRowToArchieMLString( + row: RawBlockTableRow +): Generator { + yield "{.row}" + const cells = row.value.cells + if (cells) { + yield "[.+cells]" + for (const cell of cells) { + const content = cell.value + yield "[.+cell]" + if (content) { + for (const rawBlock of content) + yield* OwidRawGdocBlockToArchieMLStringGenerator(rawBlock) + } + yield "[]" + } + yield "[]" + } + yield "{}" +} + +function* rawBlockTableToArchieMLString( + block: RawBlockTable +): Generator { + yield "{.table}" + yield* propertyToArchieMLString("template", block.value) + const rows = block?.value?.rows + if (rows) { + yield "[.+rows]" + for (const row of rows) { + yield* rawBlockRowToArchieMLString(row) + } + yield "[]" + } + yield "{}" +} + export function* OwidRawGdocBlockToArchieMLStringGenerator( - block: OwidRawGdocBlock + block: OwidRawGdocBlock | RawBlockTableRow ): Generator { const content = match(block) .with( @@ -624,12 +663,14 @@ export function* OwidRawGdocBlockToArchieMLStringGenerator( ) .with({ type: "align" }, rawBlockAlignToArchieMLString) .with({ type: "entry-summary" }, rawBlockEntrySummaryToArchieMLString) + .with({ type: "table" }, rawBlockTableToArchieMLString) + .with({ type: "table-row" }, rawBlockRowToArchieMLString) .exhaustive() yield* content } export function OwidRawGdocBlockToArchieMLString( - block: OwidRawGdocBlock + block: OwidRawGdocBlock | RawBlockTableRow ): string { const lines = [...OwidRawGdocBlockToArchieMLStringGenerator(block)] return [...lines, ""].join("\n") diff --git a/db/model/Gdoc/rawToEnriched.ts b/db/model/Gdoc/rawToEnriched.ts index 35ade73c76e..cd785161346 100644 --- a/db/model/Gdoc/rawToEnriched.ts +++ b/db/model/Gdoc/rawToEnriched.ts @@ -99,6 +99,11 @@ import { RawBlockEntrySummary, EnrichedBlockEntrySummary, EnrichedBlockEntrySummaryItem, + RawBlockTable, + EnrichedBlockTable, + EnrichedBlockTableRow, + TableTemplate, + EnrichedBlockTableCell, } from "@ourworldindata/utils" import { checkIsInternalLink } from "@ourworldindata/components" import { @@ -180,6 +185,7 @@ export function parseRawBlocksToEnrichedBlocks( .with({ type: "expandable-paragraph" }, parseExpandableParagraph) .with({ type: "align" }, parseAlign) .with({ type: "entry-summary" }, parseEntrySummary) + .with({ type: "table" }, parseTable) .exhaustive() } @@ -790,6 +796,103 @@ const parseRecirc = (raw: RawBlockRecirc): EnrichedBlockRecirc => { } } +export const parseTable = (raw: RawBlockTable): EnrichedBlockTable => { + const createError = ( + error: ParseError, + template: TableTemplate = "header-row", + rows: EnrichedBlockTableRow[] = [] + ): EnrichedBlockTable => ({ + type: "table", + template, + rows, + parseErrors: [error], + }) + + const parseErrors: ParseError[] = [] + + const validTemplates: TableTemplate[] = [ + "header-row", + "header-column", + "header-column-row", + ] + function validateTableTemplate( + template: unknown + ): template is TableTemplate { + return validTemplates.includes(template as TableTemplate) + } + + const template = raw.value?.template + if (!validateTableTemplate(template)) + return createError({ + message: `Invalid table template "${template}". Must be one of ${validTemplates.join( + ", " + )}`, + }) + + const rows = raw.value?.rows + const enrichedRows: EnrichedBlockTableRow[] = [] + if (!rows) + return createError({ + message: "Table must have at least one row", + }) + + for (const [rowIndex, row] of rows.entries()) { + const enrichedCells: EnrichedBlockTableCell[] = [] + const cells = row.value.cells + if (!cells) { + parseErrors.push({ + message: `Row ${rowIndex} is missing cells`, + }) + } else { + for (const [cellIndex, cell] of cells.entries()) { + const enrichedCellContent: OwidEnrichedGdocBlock[] = [] + const content = cell.value + if (!content || !content.length) { + parseErrors.push({ + message: `Cell (${rowIndex}, ${cellIndex}) is missing content`, + }) + } else { + for (const [ + contentIndex, + contentItem, + ] of content.entries()) { + const enrichedContent = + parseRawBlocksToEnrichedBlocks(contentItem) + if (!enrichedContent) { + parseErrors.push({ + message: `Cell (${rowIndex}, ${cellIndex}) content item ${contentIndex} is invalid`, + }) + } else if (enrichedContent.parseErrors.length) { + parseErrors.push( + ...enrichedContent.parseErrors.map((error) => ({ + message: `Cell (${rowIndex}, ${cellIndex}) content item ${contentIndex} has error: ${error.message}`, + })) + ) + } else { + enrichedCellContent.push(enrichedContent) + } + } + enrichedCells.push({ + type: "table-cell", + content: enrichedCellContent, + }) + } + } + enrichedRows.push({ + type: "table-row", + cells: enrichedCells, + }) + } + } + + return { + type: "table", + rows: enrichedRows, + template, + parseErrors, + } +} + export const parseText = (raw: RawBlockText): EnrichedBlockText => { const createError = ( error: ParseError, diff --git a/packages/@ourworldindata/utils/src/Util.ts b/packages/@ourworldindata/utils/src/Util.ts index 585f53fbe73..5f3d1641957 100644 --- a/packages/@ourworldindata/utils/src/Util.ts +++ b/packages/@ourworldindata/utils/src/Util.ts @@ -1602,6 +1602,15 @@ export function traverseEnrichedBlocks( traverseEnrichedBlocks(node, callback, spanCallback) }) }) + .with({ type: "table" }, (table) => { + table.rows.forEach((row) => { + row.cells.forEach((cell) => { + cell.content.forEach((node) => { + traverseEnrichedBlocks(node, callback, spanCallback) + }) + }) + }) + }) .with( { type: P.union( diff --git a/packages/@ourworldindata/utils/src/index.ts b/packages/@ourworldindata/utils/src/index.ts index 51f21bb14d7..26394f11221 100644 --- a/packages/@ourworldindata/utils/src/index.ts +++ b/packages/@ourworldindata/utils/src/index.ts @@ -78,6 +78,9 @@ export { type EnrichedBlockEntrySummaryItem, type EntryMeta, type EntryNode, + type EnrichedBlockTable, + type EnrichedBlockTableRow, + type EnrichedBlockTableCell, EPOCH_DATE, type FilterFnPostRestApi, type FormattedPost, @@ -153,6 +156,10 @@ export { type RawBlockText, type RawBlockTopicPageIntro, type RawBlockUrl, + type TableTemplate, + type RawBlockTable, + type RawBlockTableRow, + type RawBlockTableCell, type RawChartStoryValue, type RawRecircLink, type RawDetail, diff --git a/packages/@ourworldindata/utils/src/owidTypes.ts b/packages/@ourworldindata/utils/src/owidTypes.ts index 6e4889d13fb..93c0b148eaa 100644 --- a/packages/@ourworldindata/utils/src/owidTypes.ts +++ b/packages/@ourworldindata/utils/src/owidTypes.ts @@ -1138,6 +1138,44 @@ export type EnrichedBlockEntrySummary = { items: EnrichedBlockEntrySummaryItem[] } & EnrichedBlockWithParseErrors +export type TableTemplate = "header-column" | "header-row" | "header-column-row" + +export type RawBlockTable = { + type: "table" + value?: { + template?: TableTemplate + rows?: RawBlockTableRow[] + } +} + +export interface RawBlockTableRow { + type: "table-row" + value: { + cells?: RawBlockTableCell[] + } +} + +export interface RawBlockTableCell { + type: "table-cell" + value?: OwidRawGdocBlock[] +} + +export type EnrichedBlockTable = { + type: "table" + template: TableTemplate + rows: EnrichedBlockTableRow[] +} & EnrichedBlockWithParseErrors + +export interface EnrichedBlockTableRow { + type: "table-row" + cells: EnrichedBlockTableCell[] +} + +export interface EnrichedBlockTableCell { + type: "table-cell" + content: OwidEnrichedGdocBlock[] +} + export type Ref = { id: string // Can be -1 @@ -1184,6 +1222,7 @@ export type OwidRawGdocBlock = | RawBlockKeyInsights | RawBlockAlign | RawBlockEntrySummary + | RawBlockTable export type OwidEnrichedGdocBlock = | EnrichedBlockAllCharts @@ -1219,6 +1258,7 @@ export type OwidEnrichedGdocBlock = | EnrichedBlockResearchAndWriting | EnrichedBlockAlign | EnrichedBlockEntrySummary + | EnrichedBlockTable export enum OwidGdocPublicationContext { unlisted = "unlisted", diff --git a/site/gdocs/ArticleBlock.tsx b/site/gdocs/ArticleBlock.tsx index ba6e275d21d..e21da6833d3 100644 --- a/site/gdocs/ArticleBlock.tsx +++ b/site/gdocs/ArticleBlock.tsx @@ -575,6 +575,11 @@ export default function ArticleBlock({ ))} )) + .with({ type: "table" }, (block) => ( +
+ I'm a {block.type} +
+ )) .exhaustive() return ( From a0cb378798ea9d4f8ed130f07db2b991a67c7629 Mon Sep 17 00:00:00 2001 From: Ike Saunders Date: Mon, 23 Oct 2023 13:54:34 +0000 Subject: [PATCH 02/12] =?UTF-8?q?=F0=9F=8E=89=20gdocs=20table=20rendering?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/model/Gdoc/gdocToArchie.ts | 1 - db/model/Gdoc/rawToEnriched.ts | 5 +++-- site/gdocs/ArticleBlock.tsx | 12 +++++++++--- site/gdocs/centered-article.scss | 27 +++++++++++++++++++++++++++ 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/db/model/Gdoc/gdocToArchie.ts b/db/model/Gdoc/gdocToArchie.ts index fb0e9444a68..f834c0eea32 100644 --- a/db/model/Gdoc/gdocToArchie.ts +++ b/db/model/Gdoc/gdocToArchie.ts @@ -144,7 +144,6 @@ export async function gdocToArchie( text += tableToString(element.table) } } - console.log("text", text) return { text } } diff --git a/db/model/Gdoc/rawToEnriched.ts b/db/model/Gdoc/rawToEnriched.ts index cd785161346..7d0971ebe6f 100644 --- a/db/model/Gdoc/rawToEnriched.ts +++ b/db/model/Gdoc/rawToEnriched.ts @@ -848,8 +848,9 @@ export const parseTable = (raw: RawBlockTable): EnrichedBlockTable => { const enrichedCellContent: OwidEnrichedGdocBlock[] = [] const content = cell.value if (!content || !content.length) { - parseErrors.push({ - message: `Cell (${rowIndex}, ${cellIndex}) is missing content`, + enrichedCells.push({ + type: "table-cell", + content: [], }) } else { for (const [ diff --git a/site/gdocs/ArticleBlock.tsx b/site/gdocs/ArticleBlock.tsx index e21da6833d3..ce4fecca18a 100644 --- a/site/gdocs/ArticleBlock.tsx +++ b/site/gdocs/ArticleBlock.tsx @@ -33,6 +33,7 @@ import { KeyInsights } from "./KeyInsights.js" import { ResearchAndWriting } from "./ResearchAndWriting.js" import { AllCharts } from "./AllCharts.js" import Video from "./Video.js" +import { Table } from "./Table.js" export type Container = | "default" @@ -84,6 +85,7 @@ const layouts: { [key in Container]: Layouts} = { ["sticky-right-left-column"]: "grid span-cols-5 grid grid-cols-5 span-md-cols-10 grid-md-cols-10 col-md-start-2 span-sm-cols-12 grid-sm-cols-12 col-sm-start-1", ["sticky-right-right-column"]: "span-cols-7 grid-cols-7 span-md-cols-10 grid-md-cols-10 col-md-start-2 span-sm-cols-12 grid-sm-cols-12 col-sm-start-1", ["sticky-right"]: "grid span-cols-12 col-start-2", + ["table"]: "col-start-4 span-cols-8 col-md-start-2 span-md-cols-12", ["text"]: "col-start-5 span-cols-6 col-md-start-3 span-md-cols-10 span-sm-cols-12 col-sm-start-2", ["toc"]: "grid grid-cols-8 col-start-4 span-cols-8 grid-md-cols-10 col-md-start-3 span-md-cols-10 grid-sm-cols-12 span-sm-cols-12 col-sm-start-2", ["topic-page-intro"]: "grid col-start-2 span-cols-12", @@ -576,9 +578,13 @@ export default function ArticleBlock({ )) .with({ type: "table" }, (block) => ( -
- I'm a {block.type} -
+ )) .exhaustive() diff --git a/site/gdocs/centered-article.scss b/site/gdocs/centered-article.scss index c072a01427e..f0538c4c04d 100644 --- a/site/gdocs/centered-article.scss +++ b/site/gdocs/centered-article.scss @@ -460,6 +460,33 @@ h3.article-block__heading.has-supertitle { } } +.article-block__table { + border-collapse: collapse; + margin-bottom: 32px; + + th[scope="col"], + th[scope="row"] { + background-color: $blue-10; + p { + font-weight: 700; + margin-bottom: 0; + } + } + + .table-cell { + border: 1px solid $blue-20; + padding: 8px; + } + + .article-block__text, + .article-block__list { + @include body-3-medium; + &:last-child { + margin-bottom: 0; + } + } +} + .article-block__pull-quote { @include h1-bold-italic; border-bottom: 1px solid #dbe5f0; From e3a97baa2821fd4d52ede67225bf0d273963c6eb Mon Sep 17 00:00:00 2001 From: Ike Saunders Date: Mon, 23 Oct 2023 14:37:07 +0000 Subject: [PATCH 03/12] =?UTF-8?q?=E2=9C=85=20fix=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/model/Gdoc/Gdoc.ts | 1 + db/model/Gdoc/gdocToArchie.ts | 2 -- db/model/Gdoc/rawToArchie.ts | 4 ++-- site/gdocs/ArticleBlock.tsx | 2 +- site/gdocs/centered-article.scss | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/db/model/Gdoc/Gdoc.ts b/db/model/Gdoc/Gdoc.ts index 2876658e182..938e71f5930 100644 --- a/db/model/Gdoc/Gdoc.ts +++ b/db/model/Gdoc/Gdoc.ts @@ -182,6 +182,7 @@ export class Gdoc extends BaseEntity implements OwidGdocInterface { // Convert the doc to ArchieML syntax const { text } = await gdocToArchie(data) + console.log("text", text) // Convert the ArchieML to our enriched JSON structure this.content = archieToEnriched(text) diff --git a/db/model/Gdoc/gdocToArchie.ts b/db/model/Gdoc/gdocToArchie.ts index f834c0eea32..3d84c96cf2a 100644 --- a/db/model/Gdoc/gdocToArchie.ts +++ b/db/model/Gdoc/gdocToArchie.ts @@ -6,9 +6,7 @@ import { RawBlockHorizontalRule, RawBlockHeading, isNil, - RawBlockTable, RawBlockTableRow, - OwidRawGdocBlock, RawBlockTableCell, RawBlockText, } from "@ourworldindata/utils" diff --git a/db/model/Gdoc/rawToArchie.ts b/db/model/Gdoc/rawToArchie.ts index 8f12ad7f416..5706a060d0d 100644 --- a/db/model/Gdoc/rawToArchie.ts +++ b/db/model/Gdoc/rawToArchie.ts @@ -568,13 +568,13 @@ function* rawBlockEntrySummaryToArchieMLString( function* rawBlockRowToArchieMLString( row: RawBlockTableRow ): Generator { - yield "{.row}" + yield "{.table-row}" const cells = row.value.cells if (cells) { yield "[.+cells]" for (const cell of cells) { const content = cell.value - yield "[.+cell]" + yield "[.+table-cell]" if (content) { for (const rawBlock of content) yield* OwidRawGdocBlockToArchieMLStringGenerator(rawBlock) diff --git a/site/gdocs/ArticleBlock.tsx b/site/gdocs/ArticleBlock.tsx index ce4fecca18a..775d498c1db 100644 --- a/site/gdocs/ArticleBlock.tsx +++ b/site/gdocs/ArticleBlock.tsx @@ -85,7 +85,7 @@ const layouts: { [key in Container]: Layouts} = { ["sticky-right-left-column"]: "grid span-cols-5 grid grid-cols-5 span-md-cols-10 grid-md-cols-10 col-md-start-2 span-sm-cols-12 grid-sm-cols-12 col-sm-start-1", ["sticky-right-right-column"]: "span-cols-7 grid-cols-7 span-md-cols-10 grid-md-cols-10 col-md-start-2 span-sm-cols-12 grid-sm-cols-12 col-sm-start-1", ["sticky-right"]: "grid span-cols-12 col-start-2", - ["table"]: "col-start-4 span-cols-8 col-md-start-2 span-md-cols-12", + ["table"]: "col-start-5 span-cols-6 col-md-start-3 span-md-cols-10 span-sm-cols-12 col-sm-start-2", ["text"]: "col-start-5 span-cols-6 col-md-start-3 span-md-cols-10 span-sm-cols-12 col-sm-start-2", ["toc"]: "grid grid-cols-8 col-start-4 span-cols-8 grid-md-cols-10 col-md-start-3 span-md-cols-10 grid-sm-cols-12 span-sm-cols-12 col-sm-start-2", ["topic-page-intro"]: "grid col-start-2 span-cols-12", diff --git a/site/gdocs/centered-article.scss b/site/gdocs/centered-article.scss index f0538c4c04d..c789ce373db 100644 --- a/site/gdocs/centered-article.scss +++ b/site/gdocs/centered-article.scss @@ -475,7 +475,7 @@ h3.article-block__heading.has-supertitle { .table-cell { border: 1px solid $blue-20; - padding: 8px; + padding: 16px; } .article-block__text, From d0a1c99e86afc324f6171c4ac74d801a29b262de Mon Sep 17 00:00:00 2001 From: Ike Saunders Date: Mon, 23 Oct 2023 15:24:26 +0000 Subject: [PATCH 04/12] =?UTF-8?q?=F0=9F=8E=89=20restore=20Table.tsx=20comp?= =?UTF-8?q?onent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- site/gdocs/Table.tsx | 55 ++++++++++++++++++++++++++++++++ site/gdocs/centered-article.scss | 12 +++++++ 2 files changed, 67 insertions(+) create mode 100644 site/gdocs/Table.tsx diff --git a/site/gdocs/Table.tsx b/site/gdocs/Table.tsx new file mode 100644 index 00000000000..db66c440fa1 --- /dev/null +++ b/site/gdocs/Table.tsx @@ -0,0 +1,55 @@ +import React from "react" +import { EnrichedBlockTable } from "@ourworldindata/utils" +import ArticleBlock from "./ArticleBlock.js" + +export type TableProps = { + className?: string +} & EnrichedBlockTable + +export function Table(props: TableProps) { + const { className, rows, template } = props + const isFirstColumnHeader = + template === "header-column-row" || template === "header-column" + const isFirstRowHeader = + template === "header-column-row" || template === "header-row" + + return ( +
+ {rows.map((row, i) => ( + + {row.cells.map((cell, j) => { + if (isFirstColumnHeader && j === 0) { + return ( + + ) + } + if (isFirstRowHeader && i === 0) { + return ( + + ) + } + return ( + + ) + })} + + ))} +
+ {cell.content.map((block, k) => { + return ( + + ) + })} + + {cell.content.map((block, k) => { + return ( + + ) + })} + + {cell.content.map((block, k) => { + return + })} +
+ ) +} diff --git a/site/gdocs/centered-article.scss b/site/gdocs/centered-article.scss index c789ce373db..d2f30cbea8f 100644 --- a/site/gdocs/centered-article.scss +++ b/site/gdocs/centered-article.scss @@ -464,6 +464,18 @@ h3.article-block__heading.has-supertitle { border-collapse: collapse; margin-bottom: 32px; + &.article-block__table--header-column { + th { + text-align: left; + } + } + + &.article-block__table--header-column-row { + th:not([scope="row"]):not([scope="col"]) { + text-align: left; + } + } + th[scope="col"], th[scope="row"] { background-color: $blue-10; From fb5a43df8c5fd9da87cbb4e31466d94b29398397 Mon Sep 17 00:00:00 2001 From: Ike Saunders Date: Mon, 23 Oct 2023 21:58:14 +0000 Subject: [PATCH 05/12] =?UTF-8?q?=F0=9F=90=9B=20fix=20list=20parsing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/model/Gdoc/gdocToArchie.ts | 21 ++++++++++++--------- site/gdocs/centered-article.scss | 13 ++++--------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/db/model/Gdoc/gdocToArchie.ts b/db/model/Gdoc/gdocToArchie.ts index 3d84c96cf2a..8d41c82a39e 100644 --- a/db/model/Gdoc/gdocToArchie.ts +++ b/db/model/Gdoc/gdocToArchie.ts @@ -14,17 +14,19 @@ import { spanToHtmlString } from "./gdocUtils.js" import { OwidRawGdocBlockToArchieMLString } from "./rawToArchie.js" import { match, P } from "ts-pattern" -function paragraphToString(paragraph: docs_v1.Schema$Paragraph): string { +function paragraphToString( + paragraph: docs_v1.Schema$Paragraph, + context: { isInList: boolean } +): string { let text = "" - let isInList = false // this is a list const needsBullet = !isNil(paragraph.bullet) - if (needsBullet && !isInList) { - isInList = true + if (needsBullet && !context.isInList) { + context.isInList = true text += `\n[.list]\n` - } else if (!needsBullet && isInList) { - isInList = false + } else if (!needsBullet && context.isInList) { + context.isInList = false text += `[]\n` } @@ -84,6 +86,7 @@ function tableToString( ): string { if (!table) return "" let text = "" + const context = { isInList: false } const { tableRows = [] } = table const rows: RawBlockTableRow[] = [] @@ -104,7 +107,7 @@ function tableToString( const { content = [] } = tableCell for (const item of content) { if (item.paragraph) { - const text = paragraphToString(item.paragraph) + const text = paragraphToString(item.paragraph, context) const rawTextBlock: RawBlockText = { type: "text", value: text, @@ -129,6 +132,7 @@ export async function gdocToArchie( ): Promise<{ text: string }> { // prepare the text holder let text = "" + const context = { isInList: false } // check if the body key and content key exists, and give up if not if (!document.body) return { text } @@ -137,7 +141,7 @@ export async function gdocToArchie( // loop through each content element in the body for (const element of document.body.content) { if (element.paragraph) { - text += paragraphToString(element.paragraph) + text += paragraphToString(element.paragraph, context) } else if (element.table) { text += tableToString(element.table) } @@ -149,7 +153,6 @@ function parseParagraph( element: docs_v1.Schema$ParagraphElement ): Span | RawBlockHorizontalRule | null { // pull out the text - const textRun = element.textRun // sometimes it's not there, skip this all if so diff --git a/site/gdocs/centered-article.scss b/site/gdocs/centered-article.scss index d2f30cbea8f..488aebb77e0 100644 --- a/site/gdocs/centered-article.scss +++ b/site/gdocs/centered-article.scss @@ -464,15 +464,10 @@ h3.article-block__heading.has-supertitle { border-collapse: collapse; margin-bottom: 32px; - &.article-block__table--header-column { - th { - text-align: left; - } - } - - &.article-block__table--header-column-row { - th:not([scope="row"]):not([scope="col"]) { - text-align: left; + th { + text-align: left; + &[scope="col"] { + text-align: right; } } From 315bfd34830f221f873da44f3c0a80fdb9b9f8b5 Mon Sep 17 00:00:00 2001 From: Ike Saunders Date: Mon, 23 Oct 2023 22:17:46 +0000 Subject: [PATCH 06/12] =?UTF-8?q?=F0=9F=94=A8=20remove=20console.log?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/model/Gdoc/Gdoc.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/db/model/Gdoc/Gdoc.ts b/db/model/Gdoc/Gdoc.ts index 938e71f5930..2876658e182 100644 --- a/db/model/Gdoc/Gdoc.ts +++ b/db/model/Gdoc/Gdoc.ts @@ -182,7 +182,6 @@ export class Gdoc extends BaseEntity implements OwidGdocInterface { // Convert the doc to ArchieML syntax const { text } = await gdocToArchie(data) - console.log("text", text) // Convert the ArchieML to our enriched JSON structure this.content = archieToEnriched(text) From 65df8e928583304abd3c461ab568ff5222dd9a0b Mon Sep 17 00:00:00 2001 From: Ike Saunders Date: Mon, 30 Oct 2023 15:52:37 -0400 Subject: [PATCH 07/12] =?UTF-8?q?=E2=9C=A8=20add=20support=20for=20wide=20?= =?UTF-8?q?tables?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/model/Gdoc/exampleEnrichedBlocks.ts | 1 + db/model/Gdoc/rawToArchie.ts | 1 + db/model/Gdoc/rawToEnriched.ts | 16 +++++ packages/@ourworldindata/utils/src/index.ts | 1 + .../@ourworldindata/utils/src/owidTypes.ts | 4 ++ site/gdocs/ArticleBlock.tsx | 5 +- site/gdocs/Table.tsx | 71 +++++++++---------- site/gdocs/centered-article.scss | 53 +++++++------- 8 files changed, 90 insertions(+), 62 deletions(-) diff --git a/db/model/Gdoc/exampleEnrichedBlocks.ts b/db/model/Gdoc/exampleEnrichedBlocks.ts index 88486d475e9..cac2d4ef7a3 100644 --- a/db/model/Gdoc/exampleEnrichedBlocks.ts +++ b/db/model/Gdoc/exampleEnrichedBlocks.ts @@ -444,6 +444,7 @@ export const enrichedBlockExamples: Record< table: { type: "table", template: "header-row", + size: "narrow", rows: [ { type: "table-row", diff --git a/db/model/Gdoc/rawToArchie.ts b/db/model/Gdoc/rawToArchie.ts index 5706a060d0d..0619718d1fc 100644 --- a/db/model/Gdoc/rawToArchie.ts +++ b/db/model/Gdoc/rawToArchie.ts @@ -591,6 +591,7 @@ function* rawBlockTableToArchieMLString( ): Generator { yield "{.table}" yield* propertyToArchieMLString("template", block.value) + yield* propertyToArchieMLString("size", block.value) const rows = block?.value?.rows if (rows) { yield "[.+rows]" diff --git a/db/model/Gdoc/rawToEnriched.ts b/db/model/Gdoc/rawToEnriched.ts index 7d0971ebe6f..a66afb890dd 100644 --- a/db/model/Gdoc/rawToEnriched.ts +++ b/db/model/Gdoc/rawToEnriched.ts @@ -103,6 +103,7 @@ import { EnrichedBlockTable, EnrichedBlockTableRow, TableTemplate, + TableSize, EnrichedBlockTableCell, } from "@ourworldindata/utils" import { checkIsInternalLink } from "@ourworldindata/components" @@ -800,11 +801,13 @@ export const parseTable = (raw: RawBlockTable): EnrichedBlockTable => { const createError = ( error: ParseError, template: TableTemplate = "header-row", + size: TableSize = "narrow", rows: EnrichedBlockTableRow[] = [] ): EnrichedBlockTable => ({ type: "table", template, rows, + size, parseErrors: [error], }) @@ -829,6 +832,18 @@ export const parseTable = (raw: RawBlockTable): EnrichedBlockTable => { )}`, }) + const validSizes: TableSize[] = ["narrow", "wide"] + function validateTableSize(size: unknown): size is TableSize { + return validSizes.includes(size as TableSize) + } + const size = raw.value?.size || "narrow" + if (!validateTableSize(size)) + return createError({ + message: `Invalid table size "${size}". Must be one of ${validSizes.join( + ", " + )}`, + }) + const rows = raw.value?.rows const enrichedRows: EnrichedBlockTableRow[] = [] if (!rows) @@ -890,6 +905,7 @@ export const parseTable = (raw: RawBlockTable): EnrichedBlockTable => { type: "table", rows: enrichedRows, template, + size, parseErrors, } } diff --git a/packages/@ourworldindata/utils/src/index.ts b/packages/@ourworldindata/utils/src/index.ts index 26394f11221..09f35a4139a 100644 --- a/packages/@ourworldindata/utils/src/index.ts +++ b/packages/@ourworldindata/utils/src/index.ts @@ -157,6 +157,7 @@ export { type RawBlockTopicPageIntro, type RawBlockUrl, type TableTemplate, + type TableSize, type RawBlockTable, type RawBlockTableRow, type RawBlockTableCell, diff --git a/packages/@ourworldindata/utils/src/owidTypes.ts b/packages/@ourworldindata/utils/src/owidTypes.ts index 93c0b148eaa..8b3e637a068 100644 --- a/packages/@ourworldindata/utils/src/owidTypes.ts +++ b/packages/@ourworldindata/utils/src/owidTypes.ts @@ -1140,10 +1140,13 @@ export type EnrichedBlockEntrySummary = { export type TableTemplate = "header-column" | "header-row" | "header-column-row" +export type TableSize = "narrow" | "wide" + export type RawBlockTable = { type: "table" value?: { template?: TableTemplate + size?: TableSize rows?: RawBlockTableRow[] } } @@ -1163,6 +1166,7 @@ export interface RawBlockTableCell { export type EnrichedBlockTable = { type: "table" template: TableTemplate + size: TableSize rows: EnrichedBlockTableRow[] } & EnrichedBlockWithParseErrors diff --git a/site/gdocs/ArticleBlock.tsx b/site/gdocs/ArticleBlock.tsx index 775d498c1db..c5c0c899a5a 100644 --- a/site/gdocs/ArticleBlock.tsx +++ b/site/gdocs/ArticleBlock.tsx @@ -85,7 +85,8 @@ const layouts: { [key in Container]: Layouts} = { ["sticky-right-left-column"]: "grid span-cols-5 grid grid-cols-5 span-md-cols-10 grid-md-cols-10 col-md-start-2 span-sm-cols-12 grid-sm-cols-12 col-sm-start-1", ["sticky-right-right-column"]: "span-cols-7 grid-cols-7 span-md-cols-10 grid-md-cols-10 col-md-start-2 span-sm-cols-12 grid-sm-cols-12 col-sm-start-1", ["sticky-right"]: "grid span-cols-12 col-start-2", - ["table"]: "col-start-5 span-cols-6 col-md-start-3 span-md-cols-10 span-sm-cols-12 col-sm-start-2", + ["table--narrow"]: "col-start-5 span-cols-6 col-md-start-3 span-md-cols-10 span-sm-cols-12 col-sm-start-2", + ["table--wide"]: "col-start-2 span-cols-12", ["text"]: "col-start-5 span-cols-6 col-md-start-3 span-md-cols-10 span-sm-cols-12 col-sm-start-2", ["toc"]: "grid grid-cols-8 col-start-4 span-cols-8 grid-md-cols-10 col-md-start-3 span-md-cols-10 grid-sm-cols-12 span-sm-cols-12 col-sm-start-2", ["topic-page-intro"]: "grid col-start-2 span-cols-12", @@ -580,7 +581,7 @@ export default function ArticleBlock({ .with({ type: "table" }, (block) => ( - {rows.map((row, i) => ( - - {row.cells.map((cell, j) => { - if (isFirstColumnHeader && j === 0) { - return ( - - ) - } - if (isFirstRowHeader && i === 0) { +
+
- {cell.content.map((block, k) => { - return ( - - ) - })} -
+ {rows.map((row, rowIndex) => ( + + {row.cells.map((cell, columnIndex) => { + const scope = + isFirstColumnHeader && columnIndex === 0 + ? "col" + : isFirstRowHeader && rowIndex === 0 + ? "row" + : undefined + const tag = scope ? "th" : "td" + return ( - + + + ) - } - return ( - - ) - })} - - ))} -
- {cell.content.map((block, k) => { - return ( - - ) - })} - - {cell.content.map((block, k) => { - return - })} -
+ })} + + ))} + + ) } diff --git a/site/gdocs/centered-article.scss b/site/gdocs/centered-article.scss index 488aebb77e0..bd3910240d7 100644 --- a/site/gdocs/centered-article.scss +++ b/site/gdocs/centered-article.scss @@ -460,36 +460,41 @@ h3.article-block__heading.has-supertitle { } } -.article-block__table { - border-collapse: collapse; - margin-bottom: 32px; +div.article-block__table--narrow, +div.article-block__table--wide { + overflow-x: auto; + table { + border-collapse: collapse; + margin-bottom: 32px; - th { - text-align: left; - &[scope="col"] { - text-align: right; + th { + text-align: left; + &[scope="col"] { + text-align: right; + } } - } - th[scope="col"], - th[scope="row"] { - background-color: $blue-10; - p { - font-weight: 700; - margin-bottom: 0; + th[scope="col"], + th[scope="row"] { + background-color: $blue-10; + p { + font-weight: 700; + margin-bottom: 0; + } } - } - .table-cell { - border: 1px solid $blue-20; - padding: 16px; - } + td, + th { + border: 1px solid $blue-20; + padding: 16px; + } - .article-block__text, - .article-block__list { - @include body-3-medium; - &:last-child { - margin-bottom: 0; + .article-block__text, + .article-block__list { + @include body-3-medium; + &:last-child { + margin-bottom: 0; + } } } } From e48b3e362c6fd41ce1b42ff00de4b061081b4f2f Mon Sep 17 00:00:00 2001 From: Ike Saunders Date: Mon, 30 Oct 2023 16:15:42 -0400 Subject: [PATCH 08/12] =?UTF-8?q?=F0=9F=94=A8=20enum=20validation=20abstra?= =?UTF-8?q?ction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/model/Gdoc/rawToEnriched.ts | 34 ++++++++----------- packages/@ourworldindata/utils/src/index.ts | 2 ++ .../@ourworldindata/utils/src/owidTypes.ts | 12 +++++-- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/db/model/Gdoc/rawToEnriched.ts b/db/model/Gdoc/rawToEnriched.ts index a66afb890dd..cf1fdfd2529 100644 --- a/db/model/Gdoc/rawToEnriched.ts +++ b/db/model/Gdoc/rawToEnriched.ts @@ -105,6 +105,8 @@ import { TableTemplate, TableSize, EnrichedBlockTableCell, + tableSizes, + tableTemplates, } from "@ourworldindata/utils" import { checkIsInternalLink } from "@ourworldindata/components" import { @@ -797,6 +799,13 @@ const parseRecirc = (raw: RawBlockRecirc): EnrichedBlockRecirc => { } } +function validateRawEnum( + validValues: ReadonlyArray, + value: unknown +): value is T { + return typeof value === "string" && validValues.includes(value as T) +} + export const parseTable = (raw: RawBlockTable): EnrichedBlockTable => { const createError = ( error: ParseError, @@ -813,33 +822,18 @@ export const parseTable = (raw: RawBlockTable): EnrichedBlockTable => { const parseErrors: ParseError[] = [] - const validTemplates: TableTemplate[] = [ - "header-row", - "header-column", - "header-column-row", - ] - function validateTableTemplate( - template: unknown - ): template is TableTemplate { - return validTemplates.includes(template as TableTemplate) - } - - const template = raw.value?.template - if (!validateTableTemplate(template)) + const template = raw.value?.template || "header-row" + if (!validateRawEnum(tableTemplates, template)) return createError({ - message: `Invalid table template "${template}". Must be one of ${validTemplates.join( + message: `Invalid table template "${template}". Must be one of ${tableTemplates.join( ", " )}`, }) - const validSizes: TableSize[] = ["narrow", "wide"] - function validateTableSize(size: unknown): size is TableSize { - return validSizes.includes(size as TableSize) - } const size = raw.value?.size || "narrow" - if (!validateTableSize(size)) + if (!validateRawEnum(tableSizes, size)) return createError({ - message: `Invalid table size "${size}". Must be one of ${validSizes.join( + message: `Invalid table size "${size}". Must be one of ${tableSizes.join( ", " )}`, }) diff --git a/packages/@ourworldindata/utils/src/index.ts b/packages/@ourworldindata/utils/src/index.ts index 09f35a4139a..d990cf8dc4e 100644 --- a/packages/@ourworldindata/utils/src/index.ts +++ b/packages/@ourworldindata/utils/src/index.ts @@ -156,7 +156,9 @@ export { type RawBlockText, type RawBlockTopicPageIntro, type RawBlockUrl, + tableTemplates, type TableTemplate, + tableSizes, type TableSize, type RawBlockTable, type RawBlockTableRow, diff --git a/packages/@ourworldindata/utils/src/owidTypes.ts b/packages/@ourworldindata/utils/src/owidTypes.ts index 8b3e637a068..899093cb21b 100644 --- a/packages/@ourworldindata/utils/src/owidTypes.ts +++ b/packages/@ourworldindata/utils/src/owidTypes.ts @@ -1138,9 +1138,17 @@ export type EnrichedBlockEntrySummary = { items: EnrichedBlockEntrySummaryItem[] } & EnrichedBlockWithParseErrors -export type TableTemplate = "header-column" | "header-row" | "header-column-row" +export const tableTemplates = [ + "header-column", + "header-row", + "header-column-row", +] as const + +export type TableTemplate = (typeof tableTemplates)[number] + +export const tableSizes = ["narrow", "wide"] as const -export type TableSize = "narrow" | "wide" +export type TableSize = (typeof tableSizes)[number] export type RawBlockTable = { type: "table" From c7eb253f57772e825859afaea1078c53463ca36c Mon Sep 17 00:00:00 2001 From: Ike Saunders Date: Mon, 30 Oct 2023 16:18:39 -0400 Subject: [PATCH 09/12] =?UTF-8?q?=F0=9F=90=9B=20show=20table=20parse=20err?= =?UTF-8?q?ors=20on=20preview=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/@ourworldindata/utils/src/Util.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/@ourworldindata/utils/src/Util.ts b/packages/@ourworldindata/utils/src/Util.ts index 5f3d1641957..b2017764411 100644 --- a/packages/@ourworldindata/utils/src/Util.ts +++ b/packages/@ourworldindata/utils/src/Util.ts @@ -1603,6 +1603,7 @@ export function traverseEnrichedBlocks( }) }) .with({ type: "table" }, (table) => { + callback(table) table.rows.forEach((row) => { row.cells.forEach((cell) => { cell.content.forEach((node) => { From 831f7abbd1e4116cac02c02aa193e9f6319ba288 Mon Sep 17 00:00:00 2001 From: Ike Saunders Date: Mon, 30 Oct 2023 16:30:58 -0400 Subject: [PATCH 10/12] =?UTF-8?q?=E2=9C=A8=20min-width=20100%=20for=20tabl?= =?UTF-8?q?es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- site/gdocs/centered-article.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/site/gdocs/centered-article.scss b/site/gdocs/centered-article.scss index bd3910240d7..df1d3557c6f 100644 --- a/site/gdocs/centered-article.scss +++ b/site/gdocs/centered-article.scss @@ -464,6 +464,7 @@ div.article-block__table--narrow, div.article-block__table--wide { overflow-x: auto; table { + min-width: 100%; border-collapse: collapse; margin-bottom: 32px; From 1db33bc8ff8f00a0dd80c9a38d9945a5de2c67d4 Mon Sep 17 00:00:00 2001 From: Ike Saunders Date: Tue, 31 Oct 2023 16:39:34 -0400 Subject: [PATCH 11/12] =?UTF-8?q?=F0=9F=90=9B=20fix=20table=20scope=20mixu?= =?UTF-8?q?p?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- site/gdocs/Table.tsx | 4 ++-- site/gdocs/centered-article.scss | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/site/gdocs/Table.tsx b/site/gdocs/Table.tsx index d2ef0a8f890..67a5c45aa7b 100644 --- a/site/gdocs/Table.tsx +++ b/site/gdocs/Table.tsx @@ -30,9 +30,9 @@ export function Table(props: TableProps) { {row.cells.map((cell, columnIndex) => { const scope = isFirstColumnHeader && columnIndex === 0 - ? "col" - : isFirstRowHeader && rowIndex === 0 ? "row" + : isFirstRowHeader && rowIndex === 0 + ? "col" : undefined const tag = scope ? "th" : "td" diff --git a/site/gdocs/centered-article.scss b/site/gdocs/centered-article.scss index df1d3557c6f..2e6d1c48d29 100644 --- a/site/gdocs/centered-article.scss +++ b/site/gdocs/centered-article.scss @@ -470,7 +470,7 @@ div.article-block__table--wide { th { text-align: left; - &[scope="col"] { + &[scope="row"] { text-align: right; } } From bc1ebfa54d5e1e65953b4d83791ca66f9fb16a87 Mon Sep 17 00:00:00 2001 From: Ike Saunders Date: Tue, 31 Oct 2023 16:56:57 -0400 Subject: [PATCH 12/12] =?UTF-8?q?=F0=9F=90=9B=20close=20lists=20correctly?= =?UTF-8?q?=20when=20table=20cell=20terminates=20with=20a=20list?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/model/Gdoc/gdocToArchie.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/db/model/Gdoc/gdocToArchie.ts b/db/model/Gdoc/gdocToArchie.ts index 8d41c82a39e..73db17e1d91 100644 --- a/db/model/Gdoc/gdocToArchie.ts +++ b/db/model/Gdoc/gdocToArchie.ts @@ -86,7 +86,6 @@ function tableToString( ): string { if (!table) return "" let text = "" - const context = { isInList: false } const { tableRows = [] } = table const rows: RawBlockTableRow[] = [] @@ -105,6 +104,7 @@ function tableToString( value: [], } const { content = [] } = tableCell + const context = { isInList: false } for (const item of content) { if (item.paragraph) { const text = paragraphToString(item.paragraph, context) @@ -115,6 +115,10 @@ function tableToString( rawCell.value!.push(rawTextBlock) } } + // Close the list if paragraphToString didn't close it itself (because the last item was still in a list) + if (context.isInList) { + rawCell.value!.push({ type: "text", value: "[]" }) + } rawRow.value!.cells!.push(rawCell) } rows.push(rawRow)