-
- {citationProducer.map(
+ {citationFull.map(
(
producer: string,
index: number
@@ -158,7 +158,7 @@ export class SourcesTab extends React.Component<{
{content.supertitle} @@ -70,11 +72,11 @@ function OwidArticleHeader({
+
{content.subtitle}
) : null}
-
+
{"By: "}
diff --git a/site/gdocs/centered-article.scss b/site/gdocs/centered-article.scss
index a3dc350f8ff..f8bc14930b1 100644
--- a/site/gdocs/centered-article.scss
+++ b/site/gdocs/centered-article.scss
@@ -30,7 +30,7 @@ $banner-height: 200px;
left: 0;
right: 0;
height: $banner-height;
- background: $blue-10;
+ background: $amber;
z-index: -1;
}
@@ -58,6 +58,11 @@ $banner-height: 200px;
margin: 80px 0 24px;
min-height: calc($banner-height - 80px);
padding-top: 48px;
+
+ @include md-down {
+ margin-top: 48px;
+ padding-top: 24px;
+ }
}
.article-block__text {
@@ -137,6 +142,10 @@ h3.article-block__heading {
text-align: center;
}
+.article-block__chart + .article-block__heading {
+ margin-top: 0;
+}
+
.article-block__heading + .article-block__heading {
margin-top: 0;
}
@@ -187,11 +196,14 @@ h3.article-block__heading.has-supertitle {
// take up exactly: (number of lines - 1) * line-height
// in height, effectively, such that the header is always the same height
// unless the breadcrumbs are longer than a single line.
- $header-breadcrumb-margin-top: 40px;
- margin-top: $header-breadcrumb-margin-top;
- margin-bottom: calc(-1.6em - $header-breadcrumb-margin-top);
- // lh is a relatively recent CSS unit, so we use ems as a fallback in the rule above
- margin-bottom: calc(-1lh - $header-breadcrumb-margin-top);
+ --header-breadcrumb-margin-top: 40px;
+
+ @include md-down {
+ --header-breadcrumb-margin-top: 16px;
+ }
+
+ margin-top: var(--header-breadcrumb-margin-top);
+ margin-bottom: calc(-1.6em - var(--header-breadcrumb-margin-top));
font-size: 1rem;
a {
@@ -223,6 +235,11 @@ h3.article-block__heading.has-supertitle {
margin-top: 0;
margin-bottom: 24px;
color: $blue-90;
+
+ @include md-down {
+ @include h2-bold;
+ margin-top: 0;
+ }
}
}
@@ -230,6 +247,10 @@ h3.article-block__heading.has-supertitle {
@include subtitle-1;
margin-top: 0;
color: $blue-50;
+
+ @include md-down {
+ @include body-1-regular;
+ }
}
.centered-article-header__meta-container {
@@ -262,6 +283,15 @@ h3.article-block__heading.has-supertitle {
border-right: 1px solid $blue-10;
}
}
+
+ @include sm-only {
+ padding: 16px 0;
+ > div:first-child {
+ border-bottom: 1px solid $blue-10;
+ padding-bottom: 16px;
+ margin-bottom: 16px;
+ }
+ }
}
.footnote-container,
@@ -455,6 +485,13 @@ h3.article-block__heading.has-supertitle {
.article-block__explorer {
margin-top: 0;
}
+
+ .article-block__chart,
+ .article-block__image {
+ &:last-child {
+ margin-bottom: 0;
+ }
+ }
}
.article-block__chart,
@@ -647,6 +684,10 @@ h3.article-block__heading.has-supertitle {
.article-block__sticky-left,
.article-block__side-by-side {
margin: 48px 0;
+
+ @include md-down {
+ margin: 0;
+ }
}
.article-block__prominent-link {
From be511a0877ce50b96746c03dab7c1c74071ef9ea Mon Sep 17 00:00:00 2001
From: Ike Saunders
Date: Thu, 14 Sep 2023 14:11:22 -0400
Subject: [PATCH 102/134] =?UTF-8?q?=E2=9C=85=20fix=20lint?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
baker/siteRenderers.tsx | 3 ---
1 file changed, 3 deletions(-)
diff --git a/baker/siteRenderers.tsx b/baker/siteRenderers.tsx
index e72d9bd8de9..05da0c012c0 100644
--- a/baker/siteRenderers.tsx
+++ b/baker/siteRenderers.tsx
@@ -65,9 +65,6 @@ import {
getPostBySlug,
isPostCitable,
getBlockContent,
- getPosts,
- mapGdocsToWordpressPosts,
- getFullPost,
} from "../db/wpdb.js"
import { queryMysql, knexTable } from "../db/db.js"
import { getPageOverrides, isPageOverridesCitable } from "./pageOverrides.js"
From 43efa8dc414071dfb9ee9a877512bb25c22c870a Mon Sep 17 00:00:00 2001
From: Matthieu
Date: Fri, 15 Sep 2023 14:01:12 +0000
Subject: [PATCH 103/134] enhance(tag): throw in case no topics found
---
adminSiteServer/apiRouter.ts | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/adminSiteServer/apiRouter.ts b/adminSiteServer/apiRouter.ts
index 538dd13807b..5028c49efb3 100644
--- a/adminSiteServer/apiRouter.ts
+++ b/adminSiteServer/apiRouter.ts
@@ -2622,11 +2622,13 @@ apiRouter.get(
)
const topics: TagReactTagAutocomplete[] = await db.queryMysql(`
- SELECT t.id, t.name
- FROM tags t
- WHERE t.isTopic IS TRUE
- AND t.parentId IN (${PUBLIC_TAG_PARENT_IDS.join(",")})
- `)
+ SELECT t.id, t.name
+ FROM tags t
+ WHERE t.isTopic IS TRUE
+ AND t.parentId IN (${PUBLIC_TAG_PARENT_IDS.join(",")})
+ `)
+
+ if (!topics.length) throw new JsonError("No topics found", 404)
const prompt = `
You will be provided with the chart metadata (delimited with XML tags),
From 4f6c0fd1dc371f39b5743c5a2f70268f82711f36 Mon Sep 17 00:00:00 2001
From: Matthieu
Date: Tue, 12 Sep 2023 11:12:11 +0000
Subject: [PATCH 104/134] chore(deps): upgrade react-tag-autocomple
---
adminSiteClient/EditTags.tsx | 20 +-
.../styles/react-tag-autocomplete.scss | 192 +++++++++++-------
adminSiteServer/apiRouter.ts | 5 +-
package.json | 2 +-
packages/@ourworldindata/utils/package.json | 2 +-
.../@ourworldindata/utils/src/owidTypes.ts | 4 +-
yarn.lock | 16 +-
7 files changed, 144 insertions(+), 97 deletions(-)
diff --git a/adminSiteClient/EditTags.tsx b/adminSiteClient/EditTags.tsx
index 5c4fbedadf9..33f248ed477 100644
--- a/adminSiteClient/EditTags.tsx
+++ b/adminSiteClient/EditTags.tsx
@@ -2,7 +2,8 @@ import React from "react"
import { action } from "mobx"
import { observer } from "mobx-react"
import { Tag } from "./TagBadge.js"
-import ReactTags from "react-tag-autocomplete"
+import { ReactTags } from "react-tag-autocomplete"
+import { Tag as TagAutocomplete } from "react-tag-autocomplete"
@observer
export class EditTags extends React.Component<{
@@ -23,6 +24,10 @@ export class EditTags extends React.Component<{
this.dismissable = false
}
+ onAdd = (tag: TagAutocomplete) => {
+ this.props.onAdd(convertAutocompleteTotag(tag))
+ }
+
componentDidMount() {
document.addEventListener("click", this.onClickSomewhere)
}
@@ -36,13 +41,18 @@ export class EditTags extends React.Component<{
return (
)
}
}
+
+const convertTagToAutocomplete = (t: Tag) => ({ value: t.id, label: t.name })
+const convertAutocompleteTotag = (t: TagAutocomplete) => ({
+ id: t.value as number,
+ name: t.label,
+})
diff --git a/adminSiteClient/styles/react-tag-autocomplete.scss b/adminSiteClient/styles/react-tag-autocomplete.scss
index e96bf28d7ca..4eb6115e32c 100644
--- a/adminSiteClient/styles/react-tag-autocomplete.scss
+++ b/adminSiteClient/styles/react-tag-autocomplete.scss
@@ -1,134 +1,172 @@
-// Styles taken from https://github.com/i-like-robots/react-tags/blob/main/example/styles.css
+// Styles taken from https://github.com/i-like-robots/react-tag-autocomplete/blob/main/example/src/styles.css
.react-tags {
position: relative;
- padding: 6px 0 0 6px;
- border: 1px solid #d1d1d1;
- background-color: #fff;
- border-radius: 1px;
-
+ padding: 0.25rem 0 0 0.25rem;
+ border: 2px solid #afb8c1;
+ border-radius: 6px;
+ background: #ffffff;
/* shared font styles */
- font-size: 1em;
+ font-size: 1rem;
line-height: 1.2;
-
/* clicking anywhere will focus the input */
cursor: text;
}
-.react-tags.is-focused {
- border-color: #b1b1b1;
+.react-tags.is-active {
+ border-color: #4f46e5;
+}
+
+.react-tags.is-disabled {
+ opacity: 0.75;
+ background-color: #eaeef2;
+ /* Prevent any clicking on the component */
+ pointer-events: none;
+ cursor: not-allowed;
+}
+
+.react-tags.is-invalid {
+ border-color: #fd5956;
+ box-shadow: 0 0 0 2px rgba(253, 86, 83, 0.25);
+}
+
+.react-tags__label {
+ position: absolute;
+ left: -10000px;
+ top: auto;
+ width: 1px;
+ height: 1px;
+ overflow: hidden;
}
-.react-tags__selected {
+.react-tags__list {
+ /* Do not use display: contents, it's too buggy */
display: inline;
+ padding: 0;
}
-.react-tags__selected-tag {
- display: inline-block;
- box-sizing: border-box;
- margin: 0 6px 6px 0;
- padding: 6px 8px;
- border: 1px solid #d1d1d1;
- border-radius: 2px;
- background: #f1f1f1;
+.react-tags__list-item {
+ display: inline;
+ list-style: none;
+}
+.react-tags__tag {
+ margin: 0 0.25rem 0.25rem 0;
+ padding: 0.375rem 0.5rem;
+ border: 0;
+ border-radius: 3px;
+ background: #eaeef2;
/* match the font styles */
font-size: inherit;
line-height: inherit;
}
-.react-tags__selected-tag:after {
- content: "\2715";
- color: #aaa;
- margin-left: 8px;
+.react-tags__tag:hover {
+ color: #ffffff;
+ background-color: #4f46e5;
}
-.react-tags__selected-tag:hover,
-.react-tags__selected-tag:focus {
- border-color: #b1b1b1;
-}
-
-.react-tags__search {
+.react-tags__tag::after {
+ content: "";
+ display: inline-block;
+ width: 0.65rem;
+ height: 0.65rem;
+ clip-path: polygon(
+ 10% 0,
+ 0 10%,
+ 40% 50%,
+ 0 90%,
+ 10% 100%,
+ 50% 60%,
+ 90% 100%,
+ 100% 90%,
+ 60% 50%,
+ 100% 10%,
+ 90% 0,
+ 50% 40%
+ );
+ margin-left: 0.5rem;
+ font-size: 0.875rem;
+ background-color: #7c7d86;
+}
+
+.react-tags__tag:hover::after {
+ background-color: #ffffff;
+}
+
+.react-tags__combobox {
display: inline-block;
-
/* match tag layout */
- padding: 7px 2px;
- margin-bottom: 6px;
-
- /* prevent autoresize overflowing the container */
+ padding: 0.375rem 0.25rem;
+ margin-bottom: 0.25rem;
+ /* prevents autoresize overflowing the container */
max-width: 100%;
}
-@media screen and (min-width: 30em) {
- .react-tags__search {
- /* this will become the offsetParent for suggestions */
- position: relative;
- }
-}
-
-.react-tags__search-input {
+.react-tags__combobox-input {
/* prevent autoresize overflowing the container */
max-width: 100%;
-
/* remove styles and layout from this element */
margin: 0;
padding: 0;
border: 0;
outline: none;
-
+ background: none;
/* match the font styles */
font-size: inherit;
line-height: inherit;
}
-.react-tags__search-input::-ms-clear {
- display: none;
+.react-tags__combobox-input::placeholder {
+ color: #7c7d86;
+ opacity: 1;
}
-.react-tags__suggestions {
+.react-tags__listbox {
position: absolute;
- top: 100%;
- left: 0;
- width: 100%;
+ z-index: 1;
+ top: calc(100% + 5px);
+ /* Negate the border width on the container */
+ left: -2px;
+ right: -2px;
+ max-height: 12.5rem;
+ overflow-y: auto;
+ background: #ffffff;
+ border: 1px solid #afb8c1;
+ border-radius: 6px;
+ box-shadow: rgba(0, 0, 0, 0.1) 0 10px 15px -4px,
+ rgba(0, 0, 0, 0.05) 0 4px 6px -2px;
}
-@media screen and (min-width: 30em) {
- .react-tags__suggestions {
- width: 240px;
- }
+.react-tags__listbox-option {
+ padding: 0.375rem 0.5rem;
}
-.react-tags__suggestions ul {
- margin: 4px -1px;
- padding: 0;
- list-style: none;
- background: white;
- border: 1px solid #d1d1d1;
- border-radius: 2px;
- box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
+.react-tags__listbox-option:hover {
+ cursor: pointer;
+ background: #eaeef2;
}
-.react-tags__suggestions li {
- border-bottom: 1px solid #ddd;
- padding: 6px 8px;
+.react-tags__listbox-option:not([aria-disabled="true"]).is-active {
+ background: #4f46e5;
+ color: #ffffff;
}
-.react-tags__suggestions li mark {
- text-decoration: underline;
- background: none;
- font-weight: 700;
+.react-tags__listbox-option[aria-disabled="true"] {
+ color: #7c7d86;
+ cursor: not-allowed;
+ pointer-events: none;
}
-.react-tags__suggestions li:hover {
- cursor: pointer;
- background: #eee;
+.react-tags__listbox-option[aria-selected="true"]::after {
+ content: "✓";
+ margin-left: 0.5rem;
}
-.react-tags__suggestions li.is-active {
- background: #b7cfe0;
+.react-tags__listbox-option[aria-selected="true"]:not(.is-active)::after {
+ color: #4f46e5;
}
-.react-tags__suggestions li.is-disabled {
- opacity: 0.5;
- cursor: auto;
+.react-tags__listbox-option-highlight {
+ background-color: #ffdd00;
}
diff --git a/adminSiteServer/apiRouter.ts b/adminSiteServer/apiRouter.ts
index 5028c49efb3..5666f90faca 100644
--- a/adminSiteServer/apiRouter.ts
+++ b/adminSiteServer/apiRouter.ts
@@ -98,7 +98,6 @@ import { In } from "typeorm"
import { GIT_CMS_DIR } from "../gitCms/GitCmsConstants.js"
import { logErrorAndMaybeSendToBugsnag } from "../serverUtils/errorLog.js"
import { TaggableType } from "../adminSiteClient/EditableTags.js"
-import { Tag as TagReactTagAutocomplete } from "react-tag-autocomplete"
import { OpenAI } from "openai"
const apiRouter = new FunctionalRouter()
@@ -2621,7 +2620,7 @@ apiRouter.get(
404
)
- const topics: TagReactTagAutocomplete[] = await db.queryMysql(`
+ const topics: Tag[] = await db.queryMysql(`
SELECT t.id, t.name
FROM tags t
WHERE t.isTopic IS TRUE
@@ -2661,7 +2660,7 @@ apiRouter.get(
const json = completion.choices[0]?.message?.content
if (!json) throw new JsonError("No response from GPT", 500)
- const selectedTopics: TagReactTagAutocomplete[] = JSON.parse(json)
+ const selectedTopics: Tag[] = JSON.parse(json)
// We only want to return topics that are in the list of possible
// topics, in case of hallucinations
diff --git a/package.json b/package.json
index faed3733fe5..d158f451253 100644
--- a/package.json
+++ b/package.json
@@ -188,7 +188,7 @@
"react-recaptcha": "^2.3.10",
"react-router-dom": "^5.3.1",
"react-select": "^5.7.3",
- "react-tag-autocomplete": "^6.3.0",
+ "react-tag-autocomplete": "^7.1.0",
"react-zoom-pan-pinch": "^2.1.3",
"reflect-metadata": "^0.1.13",
"rxjs": "6",
diff --git a/packages/@ourworldindata/utils/package.json b/packages/@ourworldindata/utils/package.json
index b98fa39d3cf..d89c65a65e4 100644
--- a/packages/@ourworldindata/utils/package.json
+++ b/packages/@ourworldindata/utils/package.json
@@ -25,7 +25,7 @@
"parsimmon": "^1.18.1",
"react": "^16.14.0",
"react-select": "^5.7.3",
- "react-tag-autocomplete": "^6.3.0",
+ "react-tag-autocomplete": "^7.1.0",
"s-expression": "^3.1.1",
"string-pixel-width": "^1.10.0",
"striptags": "^3.2.0",
diff --git a/packages/@ourworldindata/utils/src/owidTypes.ts b/packages/@ourworldindata/utils/src/owidTypes.ts
index 74c33d4a96a..7fc70336db6 100644
--- a/packages/@ourworldindata/utils/src/owidTypes.ts
+++ b/packages/@ourworldindata/utils/src/owidTypes.ts
@@ -195,7 +195,9 @@ export enum KeyChartLevel {
Top = 3, // chart will show at the top of the all charts block
}
-export interface Tag extends TagReactTagAutocomplete {
+export interface Tag {
+ id: number
+ name: string
keyChartLevel?: KeyChartLevel
isApproved?: boolean
}
diff --git a/yarn.lock b/yarn.lock
index c8718821a6d..ab00bf24974 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5043,7 +5043,7 @@ __metadata:
parsimmon: ^1.18.1
react: ^16.14.0
react-select: ^5.7.3
- react-tag-autocomplete: ^6.3.0
+ react-tag-autocomplete: ^7.1.0
s-expression: ^3.1.1
string-pixel-width: ^1.10.0
striptags: ^3.2.0
@@ -14089,7 +14089,7 @@ __metadata:
react-recaptcha: ^2.3.10
react-router-dom: ^5.3.1
react-select: ^5.7.3
- react-tag-autocomplete: ^6.3.0
+ react-tag-autocomplete: ^7.1.0
react-zoom-pan-pinch: ^2.1.3
reflect-metadata: ^0.1.13
rxjs: 6
@@ -21590,14 +21590,12 @@ __metadata:
languageName: node
linkType: hard
-"react-tag-autocomplete@npm:^6.3.0":
- version: 6.3.0
- resolution: "react-tag-autocomplete@npm:6.3.0"
+"react-tag-autocomplete@npm:^7.1.0":
+ version: 7.1.0
+ resolution: "react-tag-autocomplete@npm:7.1.0"
peerDependencies:
- prop-types: ^15.5.0
- react: ^16.5.0 || ^17.0.0
- react-dom: ^16.5.0 || ^17.0.0
- checksum: c1d76319d0ba9635ad51f1dd0308fbe55ced3b4e2164a5f3055c80c4ae32c0139745ad9ccc2e5c32ce970f3c331445a36f1a5e458a4a93f942019b9848da192d
+ react: ^18.0.0
+ checksum: 9648dc2f3529bfdb330c9481d094fc937f27f1b628ec057c6eb1731365880e3e45cf88b90349d5575ed8944c9c850592c2b094c8caf12b0d84eb329d7f2a60a6
languageName: node
linkType: hard
From 6ec331cfd99062b003ab7a6691274c96988dda93 Mon Sep 17 00:00:00 2001
From: Matthieu
Date: Tue, 12 Sep 2023 11:26:18 +0000
Subject: [PATCH 105/134] enhance(tag): align styles to color chart
---
adminSiteClient/admin.scss | 11 -----------
adminSiteClient/styles/react-tag-autocomplete.scss | 8 ++++----
2 files changed, 4 insertions(+), 15 deletions(-)
diff --git a/adminSiteClient/admin.scss b/adminSiteClient/admin.scss
index af36ad67fce..454181361de 100644
--- a/adminSiteClient/admin.scss
+++ b/adminSiteClient/admin.scss
@@ -894,17 +894,6 @@ main:not(.ChartEditorPage):not(.GdocsEditPage) {
}
}
-.EditableTags {
- button {
- opacity: 0.8;
- }
-
- // Tweak to stop suggestions overlapping "Add new tag" in another tag input below
- .react-tags__suggestions {
- z-index: 10;
- }
-}
-
.EditableTags__action {
padding-left: 6px;
&:focus {
diff --git a/adminSiteClient/styles/react-tag-autocomplete.scss b/adminSiteClient/styles/react-tag-autocomplete.scss
index 4eb6115e32c..d814d121d4e 100644
--- a/adminSiteClient/styles/react-tag-autocomplete.scss
+++ b/adminSiteClient/styles/react-tag-autocomplete.scss
@@ -14,7 +14,7 @@
}
.react-tags.is-active {
- border-color: #4f46e5;
+ border-color: #007bff;
}
.react-tags.is-disabled {
@@ -63,7 +63,7 @@
.react-tags__tag:hover {
color: #ffffff;
- background-color: #4f46e5;
+ background-color: #dc3545;
}
.react-tags__tag::after {
@@ -148,7 +148,7 @@
}
.react-tags__listbox-option:not([aria-disabled="true"]).is-active {
- background: #4f46e5;
+ background: #007bff;
color: #ffffff;
}
@@ -164,7 +164,7 @@
}
.react-tags__listbox-option[aria-selected="true"]:not(.is-active)::after {
- color: #4f46e5;
+ color: #007bff;
}
.react-tags__listbox-option-highlight {
From 3a64ffe5a2473c80e8fdd91fce509d67b4a4f236 Mon Sep 17 00:00:00 2001
From: Matthieu
Date: Tue, 12 Sep 2023 11:35:04 +0000
Subject: [PATCH 106/134] enhance(tag): add autofocus
---
adminSiteClient/EditTags.tsx | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/adminSiteClient/EditTags.tsx b/adminSiteClient/EditTags.tsx
index 33f248ed477..14f64cc09c8 100644
--- a/adminSiteClient/EditTags.tsx
+++ b/adminSiteClient/EditTags.tsx
@@ -1,8 +1,8 @@
-import React from "react"
+import React, { useRef } from "react"
import { action } from "mobx"
import { observer } from "mobx-react"
import { Tag } from "./TagBadge.js"
-import { ReactTags } from "react-tag-autocomplete"
+import { ReactTags, ReactTagsAPI } from "react-tag-autocomplete"
import { Tag as TagAutocomplete } from "react-tag-autocomplete"
@observer
@@ -14,6 +14,7 @@ export class EditTags extends React.Component<{
onSave: () => void
}> {
dismissable: boolean = true
+ reactTagsApi = React.createRef()
@action.bound onClickSomewhere() {
if (this.dismissable) this.props.onSave()
@@ -30,6 +31,7 @@ export class EditTags extends React.Component<{
componentDidMount() {
document.addEventListener("click", this.onClickSomewhere)
+ this.reactTagsApi.current?.input?.focus()
}
componentWillUnmount() {
@@ -45,6 +47,7 @@ export class EditTags extends React.Component<{
suggestions={suggestions.map(convertTagToAutocomplete)}
onAdd={this.onAdd}
onDelete={this.props.onDelete}
+ ref={this.reactTagsApi}
/>
)
From e655dbea8abc8b7e0ceb2eb51a55c3b17f72b8d4 Mon Sep 17 00:00:00 2001
From: Matthieu
Date: Tue, 12 Sep 2023 11:44:54 +0000
Subject: [PATCH 107/134] enhance(tag): highlight styles
---
adminSiteClient/styles/react-tag-autocomplete.scss | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/adminSiteClient/styles/react-tag-autocomplete.scss b/adminSiteClient/styles/react-tag-autocomplete.scss
index d814d121d4e..9ca9357161b 100644
--- a/adminSiteClient/styles/react-tag-autocomplete.scss
+++ b/adminSiteClient/styles/react-tag-autocomplete.scss
@@ -168,5 +168,7 @@
}
.react-tags__listbox-option-highlight {
- background-color: #ffdd00;
+ padding: 0;
+ background-color: transparent;
+ font-weight: bold;
}
From 8e854b6d25f02b67dbb27f52b2a1dca8044c1e05 Mon Sep 17 00:00:00 2001
From: Matthieu
Date: Tue, 12 Sep 2023 12:02:01 +0000
Subject: [PATCH 108/134] enhance(tag): activate first option by default
---
adminSiteClient/EditTags.tsx | 1 +
adminSiteClient/styles/react-tag-autocomplete.scss | 3 +--
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/adminSiteClient/EditTags.tsx b/adminSiteClient/EditTags.tsx
index 14f64cc09c8..f693164322e 100644
--- a/adminSiteClient/EditTags.tsx
+++ b/adminSiteClient/EditTags.tsx
@@ -45,6 +45,7 @@ export class EditTags extends React.Component<{
Date: Tue, 12 Sep 2023 12:18:29 +0000
Subject: [PATCH 109/134] feat(tag): add keyboard shortcuts for validation
---
adminSiteClient/EditTags.tsx | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/adminSiteClient/EditTags.tsx b/adminSiteClient/EditTags.tsx
index f693164322e..d46c4add1ef 100644
--- a/adminSiteClient/EditTags.tsx
+++ b/adminSiteClient/EditTags.tsx
@@ -25,17 +25,25 @@ export class EditTags extends React.Component<{
this.dismissable = false
}
+ @action.bound onKeyDown(e: KeyboardEvent) {
+ if (e.key === "Escape") {
+ this.props.onSave()
+ }
+ }
+
onAdd = (tag: TagAutocomplete) => {
this.props.onAdd(convertAutocompleteTotag(tag))
}
componentDidMount() {
document.addEventListener("click", this.onClickSomewhere)
+ document.addEventListener("keydown", this.onKeyDown)
this.reactTagsApi.current?.input?.focus()
}
componentWillUnmount() {
document.removeEventListener("click", this.onClickSomewhere)
+ document.removeEventListener("keydown", this.onKeyDown)
}
render() {
From fd09fe235ce7cd4a6c3198d6abac0a5ea91bc109 Mon Sep 17 00:00:00 2001
From: Matthieu
Date: Wed, 13 Sep 2023 08:57:19 +0000
Subject: [PATCH 110/134] refactor: fix lint errors
---
adminSiteClient/EditTags.tsx | 9 ++++++---
packages/@ourworldindata/utils/src/owidTypes.ts | 1 -
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/adminSiteClient/EditTags.tsx b/adminSiteClient/EditTags.tsx
index d46c4add1ef..74c6a7dd841 100644
--- a/adminSiteClient/EditTags.tsx
+++ b/adminSiteClient/EditTags.tsx
@@ -1,9 +1,12 @@
-import React, { useRef } from "react"
+import React from "react"
import { action } from "mobx"
import { observer } from "mobx-react"
import { Tag } from "./TagBadge.js"
-import { ReactTags, ReactTagsAPI } from "react-tag-autocomplete"
-import { Tag as TagAutocomplete } from "react-tag-autocomplete"
+import {
+ ReactTags,
+ ReactTagsAPI,
+ Tag as TagAutocomplete,
+} from "react-tag-autocomplete"
@observer
export class EditTags extends React.Component<{
diff --git a/packages/@ourworldindata/utils/src/owidTypes.ts b/packages/@ourworldindata/utils/src/owidTypes.ts
index 7fc70336db6..6371dcc1f3e 100644
--- a/packages/@ourworldindata/utils/src/owidTypes.ts
+++ b/packages/@ourworldindata/utils/src/owidTypes.ts
@@ -1,4 +1,3 @@
-import { Tag as TagReactTagAutocomplete } from "react-tag-autocomplete"
import { ImageMetadata } from "./image.js"
import { Static, Type } from "@sinclair/typebox"
import { gdocUrlRegex } from "./GdocsConstants.js"
From 946282358f61be82c1eb944f29e0851c5a860ce0 Mon Sep 17 00:00:00 2001
From: Ike Saunders
Date: Mon, 18 Sep 2023 14:56:33 +0000
Subject: [PATCH 111/134] =?UTF-8?q?=F0=9F=8E=89=20Add=20owid/summary=20mig?=
=?UTF-8?q?ration?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
db/migrateWpPostsToArchieMl.ts | 137 +++++++++++++++++-
db/model/Gdoc/Gdoc.ts | 1 +
db/model/Gdoc/enrichedToRaw.ts | 9 ++
db/model/Gdoc/exampleEnrichedBlocks.ts | 5 +
db/model/Gdoc/htmlToEnriched.ts | 66 ++++++++-
db/model/Gdoc/rawToArchie.ts | 17 +++
db/model/Gdoc/rawToEnriched.ts | 36 +++++
packages/@ourworldindata/utils/src/Util.ts | 8 +-
packages/@ourworldindata/utils/src/index.ts | 5 +
.../@ourworldindata/utils/src/owidTypes.ts | 24 +++
site/gdocs/ArticleBlock.tsx | 13 ++
11 files changed, 313 insertions(+), 8 deletions(-)
diff --git a/db/migrateWpPostsToArchieMl.ts b/db/migrateWpPostsToArchieMl.ts
index c25cc1fed7e..447efabe8d5 100644
--- a/db/migrateWpPostsToArchieMl.ts
+++ b/db/migrateWpPostsToArchieMl.ts
@@ -17,6 +17,136 @@ import {
adjustHeadingLevels,
} from "./model/Gdoc/htmlToEnriched.js"
+// Hard-coded slugs to avoid WP dependency
+const entries = new Set([
+ "population",
+ "population-change",
+ "age-structure",
+ "gender-ratio",
+ "life-and-death",
+ "life-expectancy",
+ "child-mortality",
+ "fertility-rate",
+ "distribution-of-the-world-population",
+ "urbanization",
+ "health",
+ "health-risks",
+ "air-pollution",
+ "outdoor-air-pollution",
+ "indoor-air-pollution",
+ "obesity",
+ "smoking",
+ "alcohol-consumption",
+ "infectious-diseases",
+ "monkeypox",
+ "coronavirus",
+ "hiv-aids",
+ "malaria",
+ "eradication-of-diseases",
+ "smallpox",
+ "polio",
+ "pneumonia",
+ "tetanus",
+ "health-institutions-and-interventions",
+ "financing-healthcare",
+ "vaccination",
+ "life-death-health",
+ "maternal-mortality",
+ "health-meta",
+ "causes-of-death",
+ "burden-of-disease",
+ "cancer",
+ "environment",
+ "nuclear-energy",
+ "energy-access",
+ "renewable-energy",
+ "fossil-fuels",
+ "waste",
+ "plastic-pollution",
+ "air-and-climate",
+ "co2-and-greenhouse-gas-emissions",
+ "climate-change",
+ "water",
+ "clean-water-sanitation",
+ "water-access",
+ "sanitation",
+ "water-use-stress",
+ "land-and-ecosystems",
+ "forests-and-deforestation",
+ "land-use",
+ "natural-disasters",
+ "food",
+ "nutrition",
+ "famines",
+ "food-supply",
+ "human-height",
+ "micronutrient-deficiency",
+ "diet-compositions",
+ "food-production",
+ "meat-production",
+ "agricultural-inputs",
+ "employment-in-agriculture",
+ "growth-inequality",
+ "public-sector",
+ "government-spending",
+ "taxation",
+ "military-personnel-spending",
+ "financing-education",
+ "poverty-and-prosperity",
+ "economic-inequality",
+ "poverty",
+ "economic-growth",
+ "economic-inequality-by-gender",
+ "labor",
+ "child-labor",
+ "working-hours",
+ "female-labor-supply",
+ "corruption",
+ "trade-migration",
+ "trade-and-globalization",
+ "tourism",
+ "education",
+ "educational-outcomes",
+ "global-education",
+ "literacy",
+ "pre-primary-education",
+ "primary-and-secondary-education",
+ "quality-of-education",
+ "tertiary-education",
+ "inputs-to-education",
+ "teachers-and-professors",
+ "media-education",
+ "technology",
+ "space-exploration-satellites",
+ "transport",
+ "work-life",
+ "culture",
+ "trust",
+ "housing",
+ "homelessness",
+ "time-use",
+ "relationships",
+ "marriages-and-divorces",
+ "social-connections-and-loneliness",
+ "happiness-wellbeing",
+ "happiness-and-life-satisfaction",
+ "human-development-index",
+ "politics",
+ "human-rights",
+ "lgbt-rights",
+ "women-rights",
+ "democracy",
+ "violence-rights",
+ "war-peace",
+ "biological-and-chemical-weapons",
+ "war-and-peace",
+ "terrorism",
+ "nuclear-weapons",
+ "violence",
+ "violence-against-rights-for-children",
+ "homicides",
+])
+
const migrate = async (): Promise => {
const writeToFile = false
const errors = []
@@ -33,7 +163,7 @@ const migrate = async (): Promise => {
"excerpt",
"created_at_in_wordpress",
"updated_at"
- ).from(db.knexTable(Post.postsTable)) //.where("id", "=", "22821"))
+ ).from(db.knexTable(Post.postsTable).where("id", "=", "24961"))
for (const post of posts) {
try {
@@ -83,6 +213,7 @@ const migrate = async (): Promise => {
slug: post.slug,
content: {
body: archieMlBodyElements,
+ toc: [],
title: post.title,
subtitle: post.excerpt,
excerpt: post.excerpt,
@@ -92,7 +223,9 @@ const migrate = async (): Promise => {
dateline: dateline,
// TODO: this discards block level elements - those might be needed?
refs: undefined,
- type: OwidGdocType.Article,
+ type: entries.has(post.slug)
+ ? OwidGdocType.TopicPage
+ : OwidGdocType.Article,
},
published: false,
createdAt:
diff --git a/db/model/Gdoc/Gdoc.ts b/db/model/Gdoc/Gdoc.ts
index 78af8035191..92c075c1ae0 100644
--- a/db/model/Gdoc/Gdoc.ts
+++ b/db/model/Gdoc/Gdoc.ts
@@ -605,6 +605,7 @@ export class Gdoc extends BaseEntity implements OwidGdocInterface {
"aside",
"callout",
"expandable-paragraph",
+ "entry-summary",
"gray-section",
"heading",
"horizontal-rule",
diff --git a/db/model/Gdoc/enrichedToRaw.ts b/db/model/Gdoc/enrichedToRaw.ts
index a80df713323..3d6e4ea9d07 100644
--- a/db/model/Gdoc/enrichedToRaw.ts
+++ b/db/model/Gdoc/enrichedToRaw.ts
@@ -32,6 +32,7 @@ import {
EnrichedBlockResearchAndWritingLink,
RawBlockResearchAndWritingLink,
RawBlockAlign,
+ RawBlockEntrySummary,
} from "@ourworldindata/utils"
import { spanToHtmlString } from "./gdocUtils.js"
import { match, P } from "ts-pattern"
@@ -372,5 +373,13 @@ export function enrichedBlockToRawBlock(
},
}
})
+ .with({ type: "entry-summary" }, (b): RawBlockEntrySummary => {
+ return {
+ type: b.type,
+ value: {
+ items: b.items,
+ },
+ }
+ })
.exhaustive()
}
diff --git a/db/model/Gdoc/exampleEnrichedBlocks.ts b/db/model/Gdoc/exampleEnrichedBlocks.ts
index d852460e6c3..b0de1a27493 100644
--- a/db/model/Gdoc/exampleEnrichedBlocks.ts
+++ b/db/model/Gdoc/exampleEnrichedBlocks.ts
@@ -418,4 +418,9 @@ export const enrichedBlockExamples: Record<
content: [enrichedBlockText],
parseErrors: [],
},
+ "entry-summary": {
+ type: "entry-summary",
+ items: [{ text: "Hello", slug: "#link-to-something" }],
+ parseErrors: [],
+ },
}
diff --git a/db/model/Gdoc/htmlToEnriched.ts b/db/model/Gdoc/htmlToEnriched.ts
index 6670031cc5d..d0b0c3f6333 100644
--- a/db/model/Gdoc/htmlToEnriched.ts
+++ b/db/model/Gdoc/htmlToEnriched.ts
@@ -26,9 +26,21 @@ import {
EnrichedBlockProminentLink,
BlockImageSize,
detailOnDemandRegex,
+ EnrichedBlockEntrySummary,
+ EnrichedBlockEntrySummaryItem,
+ spansToUnformattedPlainText,
+ checkNodeIsSpanLink,
+ Url,
} from "@ourworldindata/utils"
import { match, P } from "ts-pattern"
-import { compact, flatten, isPlainObject, partition } from "lodash"
+import {
+ compact,
+ flatten,
+ get,
+ isArray,
+ isPlainObject,
+ partition,
+} from "lodash"
import cheerio from "cheerio"
import { spansToSimpleString } from "./gdocUtils.js"
@@ -223,6 +235,8 @@ type ErrorNames =
| "unhandled html tag found"
| "prominent link missing title"
| "prominent link missing url"
+ | "summary item isn't text"
+ | "summary item doesn't have link"
interface BlockParseError {
name: ErrorNames
@@ -335,13 +349,14 @@ function isArchieMlComponent(
}
export function convertAllWpComponentsToArchieMLBlocks(
- blocksOrComponents: ArchieBlockOrWpComponent[]
+ blocksOrComponentsOrTocs: ArchieBlockOrWpComponent[]
): OwidEnrichedGdocBlock[] {
- return blocksOrComponents.flatMap((blockOrComponent) => {
- if (isArchieMlComponent(blockOrComponent)) return [blockOrComponent]
+ return blocksOrComponentsOrTocs.flatMap((blockOrComponentOrToc) => {
+ if (isArchieMlComponent(blockOrComponentOrToc))
+ return [blockOrComponentOrToc]
else {
return convertAllWpComponentsToArchieMLBlocks(
- blockOrComponent.childrenResults
+ blockOrComponentOrToc.childrenResults
)
}
})
@@ -596,6 +611,47 @@ function finishWpComponent(
}
} else return { ...content, errors }
})
+ .with("owid/summary", () => {
+ const listItems: unknown = get(content, ["content", 0, "items"])
+ const items: EnrichedBlockEntrySummaryItem[] = []
+ const errors = content.errors
+ if (isArray(listItems)) {
+ listItems.forEach((item) => {
+ if (item.type === "text") {
+ const value = item.value[0]
+ if (checkNodeIsSpanLink(value)) {
+ const { hash } = Url.fromURL(value.url)
+ items.push({
+ // Remove "#" from the beginning of the slug
+ slug: hash.slice(1),
+ text: spansToUnformattedPlainText(
+ value.children
+ ),
+ })
+ } else {
+ errors.push({
+ name: "summary item doesn't have link",
+ details: value
+ ? `spanType is ${value.spanType}`
+ : "No item",
+ })
+ }
+ } else {
+ errors.push({
+ name: "summary item isn't text",
+ details: `item is type: ${item.type}`,
+ })
+ }
+ })
+ }
+
+ const toc: EnrichedBlockEntrySummary = {
+ type: "entry-summary",
+ items,
+ parseErrors: [],
+ }
+ return { errors: [], content: [toc] }
+ })
.otherwise(() => {
return {
errors: [
diff --git a/db/model/Gdoc/rawToArchie.ts b/db/model/Gdoc/rawToArchie.ts
index 8be3b5aac28..ff937053c39 100644
--- a/db/model/Gdoc/rawToArchie.ts
+++ b/db/model/Gdoc/rawToArchie.ts
@@ -30,6 +30,7 @@ import {
RawBlockTopicPageIntro,
RawBlockExpandableParagraph,
RawBlockAlign,
+ RawBlockEntrySummary,
} from "@ourworldindata/utils"
import { match } from "ts-pattern"
@@ -522,6 +523,21 @@ function* rawBlockAlignToArchieMLString(
yield "{}"
}
+function* rawBlockEntrySummaryToArchieMLString(
+ block: RawBlockEntrySummary
+): Generator {
+ yield "{.entry-summary}"
+ yield "[.items]"
+ if (block.value.items) {
+ for (const item of block.value.items) {
+ yield* propertyToArchieMLString("text", item)
+ yield* propertyToArchieMLString("slug", item)
+ }
+ }
+ yield "[]"
+ yield "{}"
+}
+
export function* OwidRawGdocBlockToArchieMLStringGenerator(
block: OwidRawGdocBlock
): Generator {
@@ -581,6 +597,7 @@ export function* OwidRawGdocBlockToArchieMLStringGenerator(
rawResearchAndWritingToArchieMLString
)
.with({ type: "align" }, rawBlockAlignToArchieMLString)
+ .with({ type: "entry-summary" }, rawBlockEntrySummaryToArchieMLString)
.exhaustive()
yield* content
}
diff --git a/db/model/Gdoc/rawToEnriched.ts b/db/model/Gdoc/rawToEnriched.ts
index 41f57bf11e0..50086d8b7ac 100644
--- a/db/model/Gdoc/rawToEnriched.ts
+++ b/db/model/Gdoc/rawToEnriched.ts
@@ -95,6 +95,9 @@ import {
RawBlockAlign,
FaqDictionary,
EnrichedFaq,
+ RawBlockEntrySummary,
+ EnrichedBlockEntrySummary,
+ EnrichedBlockEntrySummaryItem,
} from "@ourworldindata/utils"
import {
extractUrl,
@@ -173,6 +176,7 @@ export function parseRawBlocksToEnrichedBlocks(
)
.with({ type: "expandable-paragraph" }, parseExpandableParagraph)
.with({ type: "align" }, parseAlign)
+ .with({ type: "entry-summary" }, parseEntrySummary)
.exhaustive()
}
@@ -1496,6 +1500,38 @@ function parseAlign(b: RawBlockAlign): EnrichedBlockAlign {
}
}
+function parseEntrySummary(
+ raw: RawBlockEntrySummary
+): EnrichedBlockEntrySummary {
+ const parseErrors: ParseError[] = []
+ const items: EnrichedBlockEntrySummaryItem[] = []
+
+ if (raw.value.items) {
+ raw.value.items.forEach((item, i) => {
+ if (!item.text) {
+ parseErrors.push({
+ message: `entry-summary item ${i} is missing text`,
+ })
+ } else if (!item.slug) {
+ parseErrors.push({
+ message: `Entry summary item with text ${item.text} is missing a url`,
+ })
+ } else {
+ items.push({
+ text: item.text,
+ slug: item.slug,
+ })
+ }
+ })
+ }
+
+ return {
+ type: "entry-summary",
+ items,
+ parseErrors,
+ }
+}
+
export function parseRefs({
refs,
refsByFirstAppearance,
diff --git a/packages/@ourworldindata/utils/src/Util.ts b/packages/@ourworldindata/utils/src/Util.ts
index 59d1e7a458d..5f1b7402950 100644
--- a/packages/@ourworldindata/utils/src/Util.ts
+++ b/packages/@ourworldindata/utils/src/Util.ts
@@ -161,6 +161,7 @@ import {
EnrichedScrollerItem,
EnrichedBlockKeyInsightsSlide,
UserCountryInformation,
+ SpanLink,
} from "./owidTypes.js"
import { OwidVariableWithSource } from "./OwidVariable.js"
import { PointVector } from "./PointVector.js"
@@ -1621,7 +1622,8 @@ export function traverseEnrichedBlocks(
"sdg-grid",
"sdg-toc",
"topic-page-intro",
- "all-charts"
+ "all-charts",
+ "entry-summary"
),
},
callback
@@ -1633,6 +1635,10 @@ export function checkNodeIsSpan(node: NodeWithUrl): node is Span {
return "spanType" in node
}
+export function checkNodeIsSpanLink(node: NodeWithUrl): node is SpanLink {
+ return "spanType" in node && node.spanType === "span-link"
+}
+
export function spansToUnformattedPlainText(spans: Span[]): string {
return spans
.map((span) =>
diff --git a/packages/@ourworldindata/utils/src/index.ts b/packages/@ourworldindata/utils/src/index.ts
index 71d7dc2a93b..4e088544093 100644
--- a/packages/@ourworldindata/utils/src/index.ts
+++ b/packages/@ourworldindata/utils/src/index.ts
@@ -73,6 +73,8 @@ export {
type EnrichedRecircLink,
type EnrichedScrollerItem,
type EnrichedSDGGridItem,
+ type EnrichedBlockEntrySummary,
+ type EnrichedBlockEntrySummaryItem,
type EntryMeta,
type EntryNode,
EPOCH_DATE,
@@ -153,6 +155,8 @@ export {
type RawRecircLink,
type RawDetail,
type RawSDGGridItem,
+ type RawBlockEntrySummary,
+ type RawBlockEntrySummaryItem,
type RelatedChart,
type Ref,
type RefDictionary,
@@ -320,6 +324,7 @@ export {
recursivelyMapArticleContent,
traverseEnrichedBlocks,
checkNodeIsSpan,
+ checkNodeIsSpanLink,
spansToUnformattedPlainText,
findDuplicates,
checkIsOwidGdocType,
diff --git a/packages/@ourworldindata/utils/src/owidTypes.ts b/packages/@ourworldindata/utils/src/owidTypes.ts
index da99c3d146d..afdd0a5a39a 100644
--- a/packages/@ourworldindata/utils/src/owidTypes.ts
+++ b/packages/@ourworldindata/utils/src/owidTypes.ts
@@ -1050,6 +1050,28 @@ export type EnrichedBlockAlign = {
content: OwidEnrichedGdocBlock[]
} & EnrichedBlockWithParseErrors
+export type RawBlockEntrySummaryItem = {
+ text?: string
+ slug?: string
+}
+
+export type RawBlockEntrySummary = {
+ type: "entry-summary"
+ value: {
+ items?: RawBlockEntrySummaryItem[]
+ }
+}
+
+export type EnrichedBlockEntrySummaryItem = {
+ text: string
+ slug: string
+}
+
+export type EnrichedBlockEntrySummary = {
+ type: "entry-summary"
+ items: EnrichedBlockEntrySummaryItem[]
+} & EnrichedBlockWithParseErrors
+
export type Ref = {
id: string
// Can be -1
@@ -1094,6 +1116,7 @@ export type OwidRawGdocBlock =
| RawBlockTopicPageIntro
| RawBlockKeyInsights
| RawBlockAlign
+ | RawBlockEntrySummary
export type OwidEnrichedGdocBlock =
| EnrichedBlockAllCharts
@@ -1127,6 +1150,7 @@ export type OwidEnrichedGdocBlock =
| EnrichedBlockKeyInsights
| EnrichedBlockResearchAndWriting
| EnrichedBlockAlign
+ | EnrichedBlockEntrySummary
export enum OwidGdocPublicationContext {
unlisted = "unlisted",
diff --git a/site/gdocs/ArticleBlock.tsx b/site/gdocs/ArticleBlock.tsx
index 9f9f282cf85..c174f7edf61 100644
--- a/site/gdocs/ArticleBlock.tsx
+++ b/site/gdocs/ArticleBlock.tsx
@@ -501,6 +501,19 @@ export default function ArticleBlock({
/>
) : null
})
+ .with({ type: "entry-summary" }, (block) => {
+ return toc ? (
+ ({
+ ...item,
+ slug: item.slug,
+ isSubheading: false,
+ title: item.text,
+ }))}
+ className={getLayout("sdg-toc", containerType)}
+ />
+ ) : null
+ })
.with({ type: "missing-data" }, () => (
))
From 87070e8c9a33ffdfd6950e52774fd026bf05b010 Mon Sep 17 00:00:00 2001
From: Ike Saunders
Date: Mon, 18 Sep 2023 20:32:19 +0000
Subject: [PATCH 112/134] =?UTF-8?q?=E2=9C=A8=20Make=20the=20SDGTableOfCont?=
=?UTF-8?q?ents=20component=20generic?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
db/migrateWpPostsToArchieMl.ts | 2 +-
packages/@ourworldindata/utils/src/Util.ts | 4 +--
.../@ourworldindata/utils/src/owidTypes.ts | 4 +++
site/gdocs/ArticleBlock.tsx | 17 ++++++-----
...leOfContents.scss => TableOfContents.scss} | 8 ++---
...ableOfContents.tsx => TableOfContents.tsx} | 30 +++++++++----------
site/gdocs/centered-article.scss | 2 +-
site/owid.scss | 2 +-
8 files changed, 36 insertions(+), 33 deletions(-)
rename site/gdocs/{SDGTableOfContents.scss => TableOfContents.scss} (95%)
rename site/gdocs/{SDGTableOfContents.tsx => TableOfContents.tsx} (78%)
diff --git a/db/migrateWpPostsToArchieMl.ts b/db/migrateWpPostsToArchieMl.ts
index 447efabe8d5..2161bccb915 100644
--- a/db/migrateWpPostsToArchieMl.ts
+++ b/db/migrateWpPostsToArchieMl.ts
@@ -163,7 +163,7 @@ const migrate = async (): Promise => {
"excerpt",
"created_at_in_wordpress",
"updated_at"
- ).from(db.knexTable(Post.postsTable).where("id", "=", "24961"))
+ ).from(db.knexTable(Post.postsTable)) // .where("id", "=", "24961"))
for (const post of posts) {
try {
diff --git a/packages/@ourworldindata/utils/src/Util.ts b/packages/@ourworldindata/utils/src/Util.ts
index 5f1b7402950..4cb9bcd8f79 100644
--- a/packages/@ourworldindata/utils/src/Util.ts
+++ b/packages/@ourworldindata/utils/src/Util.ts
@@ -1635,8 +1635,8 @@ export function checkNodeIsSpan(node: NodeWithUrl): node is Span {
return "spanType" in node
}
-export function checkNodeIsSpanLink(node: NodeWithUrl): node is SpanLink {
- return "spanType" in node && node.spanType === "span-link"
+export function checkNodeIsSpanLink(node: unknown): node is SpanLink {
+ return isObject(node) && "spanType" in node && node.spanType === "span-link"
}
export function spansToUnformattedPlainText(spans: Span[]): string {
diff --git a/packages/@ourworldindata/utils/src/owidTypes.ts b/packages/@ourworldindata/utils/src/owidTypes.ts
index afdd0a5a39a..86eb6d45373 100644
--- a/packages/@ourworldindata/utils/src/owidTypes.ts
+++ b/packages/@ourworldindata/utils/src/owidTypes.ts
@@ -1055,6 +1055,10 @@ export type RawBlockEntrySummaryItem = {
slug?: string
}
+// This block renders via the TableOfContents component, same as the sdg-toc block.
+// Because the summary headings can differ from the actual headings in the document,
+// we need to serialize the text and slug explicitly, instead of programmatically generating them
+// by analyzing the document (like we do for the sdg-toc block)
export type RawBlockEntrySummary = {
type: "entry-summary"
value: {
diff --git a/site/gdocs/ArticleBlock.tsx b/site/gdocs/ArticleBlock.tsx
index c174f7edf61..26d46937770 100644
--- a/site/gdocs/ArticleBlock.tsx
+++ b/site/gdocs/ArticleBlock.tsx
@@ -22,7 +22,7 @@ import { BlockErrorBoundary, BlockErrorFallback } from "./BlockErrorBoundary.js"
import { match } from "ts-pattern"
import { renderSpans } from "./utils.js"
import Paragraph from "./Paragraph.js"
-import SDGTableOfContents from "./SDGTableOfContents.js"
+import TableOfContents from "./TableOfContents.js"
import urlSlug from "url-slug"
import { MissingData } from "./MissingData.js"
import { AdditionalCharts } from "./AdditionalCharts.js"
@@ -76,7 +76,7 @@ const layouts: { [key in Container]: Layouts} = {
["research-and-writing"]: "col-start-2 span-cols-12",
["scroller"]: "grid span-cols-12 col-start-2",
["sdg-grid"]: "grid col-start-2 span-cols-12 col-lg-start-3 span-lg-cols-10 span-sm-cols-12 col-sm-start-2",
- ["sdg-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",
+ ["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",
["side-by-side"]: "grid span-cols-12 col-start-2",
["sticky-left-left-column"]: "grid grid-cols-7 span-cols-7 span-md-cols-12 grid-md-cols-12",
["sticky-left-right-column"]: "grid grid-cols-5 span-cols-5 span-md-cols-12 grid-md-cols-12",
@@ -495,22 +495,23 @@ export default function ArticleBlock({
))
.with({ type: "sdg-toc" }, () => {
return toc ? (
-
) : null
})
.with({ type: "entry-summary" }, (block) => {
return toc ? (
- ({
...item,
- slug: item.slug,
- isSubheading: false,
title: item.text,
+ isSubheading: false,
}))}
- className={getLayout("sdg-toc", containerType)}
+ className={getLayout("toc", containerType)}
/>
) : null
})
diff --git a/site/gdocs/SDGTableOfContents.scss b/site/gdocs/TableOfContents.scss
similarity index 95%
rename from site/gdocs/SDGTableOfContents.scss
rename to site/gdocs/TableOfContents.scss
index 6d484b5b5be..9fa51c2c8e8 100644
--- a/site/gdocs/SDGTableOfContents.scss
+++ b/site/gdocs/TableOfContents.scss
@@ -1,4 +1,4 @@
-.sdg-toc {
+.toc {
padding: 40px 0;
margin: 32px 0;
background-color: $beige;
@@ -12,7 +12,7 @@
margin-right: var(--grid-gap);
}
- .sdg-toc-toggle {
+ .toc-toggle {
@include h2-bold;
margin: 0;
padding: 0;
@@ -25,8 +25,8 @@
}
// Have to hard-code this because the span-cols-x overrides col-start-x
- .sdg-toc-toggle,
- .sdg-toc-content {
+ .toc-toggle,
+ .toc-content {
grid-column-start: 2;
}
diff --git a/site/gdocs/SDGTableOfContents.tsx b/site/gdocs/TableOfContents.tsx
similarity index 78%
rename from site/gdocs/SDGTableOfContents.tsx
rename to site/gdocs/TableOfContents.tsx
index fbaa5e726e0..addba3d5e46 100644
--- a/site/gdocs/SDGTableOfContents.tsx
+++ b/site/gdocs/TableOfContents.tsx
@@ -7,12 +7,14 @@ import AnimateHeight from "react-animate-height"
// See ARIA roles: https://w3c.github.io/aria-practices/examples/menu-button/menu-button-links.html
-export default function SDGTableOfContents({
+export default function TableOfContents({
toc,
className = "",
+ title,
}: {
toc: TocHeadingWithTitleSupertitle[]
className?: string
+ title: string
}) {
const [height, setHeight] = useState<"auto" | 0>(0)
const [isOpen, setIsOpen] = useState(false)
@@ -23,28 +25,28 @@ export default function SDGTableOfContents({
return (
)
diff --git a/packages/@ourworldindata/utils/src/GdocsUtils.ts b/packages/@ourworldindata/utils/src/GdocsUtils.ts
index 0848ec4a2ce..052d1cba252 100644
--- a/packages/@ourworldindata/utils/src/GdocsUtils.ts
+++ b/packages/@ourworldindata/utils/src/GdocsUtils.ts
@@ -1,8 +1,14 @@
import { spansToUnformattedPlainText } from "./Util.js"
import { gdocUrlRegex } from "./GdocsConstants.js"
-import { OwidGdocLinkJSON, Span } from "./owidTypes.js"
+import { EnrichedBlockText, OwidGdocLinkJSON, Span } from "./owidTypes.js"
import { Url } from "./urls/Url.js"
import urlSlug from "url-slug"
+import {
+ EveryMarkdownNode,
+ MarkdownRoot,
+ mdParser,
+} from "./MarkdownTextWrap/parser.js"
+import { P, match } from "ts-pattern"
export function getLinkType(urlString: string): OwidGdocLinkJSON["linkType"] {
const url = Url.fromURL(urlString)
@@ -40,3 +46,149 @@ export function getUrlTarget(urlString: string): string {
export function convertHeadingTextToId(headingText: Span[]): string {
return urlSlug(spansToUnformattedPlainText(headingText))
}
+
+const convertMarkdownNodeToSpan = (node: EveryMarkdownNode): Span[] => {
+ return match(node)
+ .with(
+ {
+ type: "text",
+ },
+ (n) => [
+ {
+ spanType: "span-simple-text" as const,
+ text: n.value,
+ } as Span,
+ ]
+ )
+ .with(
+ {
+ type: "textSegments",
+ },
+ (n) => n.children.flatMap(convertMarkdownNodeToSpan) as Span[]
+ )
+ .with(
+ {
+ type: "newline",
+ },
+ () => [
+ {
+ spanType: "span-simple-text" as const,
+ text: "\n",
+ } as Span,
+ ]
+ )
+ .with(
+ {
+ type: "whitespace",
+ },
+ () => [
+ {
+ spanType: "span-simple-text" as const,
+ text: " ",
+ } as Span,
+ ]
+ )
+ .with(
+ {
+ type: "detailOnDemand",
+ },
+ (n) => [
+ {
+ spanType: "span-dod" as const,
+ id: n.term,
+ children: n.children.flatMap(convertMarkdownNodeToSpan),
+ } as Span,
+ ]
+ )
+ .with(
+ {
+ type: "markdownLink",
+ },
+ (n) => [
+ {
+ spanType: "span-link" as const,
+ url: n.href,
+ children: n.children.flatMap(convertMarkdownNodeToSpan),
+ } as Span,
+ ]
+ )
+ .with(
+ {
+ type: "plainUrl",
+ },
+ (n) => [
+ {
+ spanType: "span-link" as const,
+ url: n.href,
+ children: [
+ {
+ spanType: "span-simple-text" as const,
+ text: n.href,
+ },
+ ],
+ } as Span,
+ ]
+ )
+ .with(
+ {
+ type: "bold",
+ },
+ (n) => [
+ {
+ spanType: "span-bold" as const,
+ children: n.children.flatMap(convertMarkdownNodeToSpan),
+ } as Span,
+ ]
+ )
+ .with(
+ {
+ type: P.union("italic", "plainItalic", "italicWithoutBold"),
+ },
+ (n) => [
+ {
+ spanType: "span-italic" as const,
+ children: n.children.flatMap(convertMarkdownNodeToSpan),
+ } as Span,
+ ]
+ )
+ .with(
+ {
+ type: P.union("bold", "plainBold", "boldWithoutItalic"),
+ },
+ (n) => [
+ {
+ spanType: "span-bold" as const,
+ children: n.children.flatMap(convertMarkdownNodeToSpan),
+ } as Span,
+ ]
+ )
+ .exhaustive()
+ //.otherwise(() => ({ spanType: "span-simple-text" as const, text: "" }))
+}
+
+const convertMarkdownNodesToSpans = (nodes: MarkdownRoot) =>
+ nodes.children.flatMap(convertMarkdownNodeToSpan)
+
+export const markdownToEnrichedTextBlock = (
+ markdown: string
+): EnrichedBlockText => {
+ const parsedMarkdown = mdParser.markdown.parse(markdown)
+ if (parsedMarkdown.status) {
+ const spans = convertMarkdownNodesToSpans(parsedMarkdown.value)
+ return {
+ type: "text",
+ value: spans,
+ parseErrors: [],
+ }
+ } else
+ return {
+ type: "text",
+ value: [],
+ parseErrors: [
+ {
+ message: `Failed to parse markdown - expected ${parsedMarkdown.expected} at ${parsedMarkdown.index}`,
+ isWarning: false,
+ },
+ ],
+ }
+}
diff --git a/packages/@ourworldindata/utils/src/index.ts b/packages/@ourworldindata/utils/src/index.ts
index 71d7dc2a93b..2111fbd5bf0 100644
--- a/packages/@ourworldindata/utils/src/index.ts
+++ b/packages/@ourworldindata/utils/src/index.ts
@@ -608,6 +608,7 @@ export {
getUrlTarget,
checkIsInternalLink,
convertHeadingTextToId,
+ markdownToEnrichedTextBlock,
} from "./GdocsUtils.js"
export {
diff --git a/site/DataPageV2Content.tsx b/site/DataPageV2Content.tsx
index c0d0719f23b..8df870f6ebe 100644
--- a/site/DataPageV2Content.tsx
+++ b/site/DataPageV2Content.tsx
@@ -10,13 +10,9 @@ import { ArticleBlocks } from "./gdocs/ArticleBlocks.js"
import { RelatedCharts } from "./blocks/RelatedCharts.js"
import {
DataPageV2ContentFields,
- mdParser,
- MarkdownRoot,
- EveryMarkdownNode,
- Span,
- EnrichedBlockText,
excludeNullish,
slugify,
+ markdownToEnrichedTextBlock,
} from "@ourworldindata/utils"
import { AttachmentsContext, DocumentContext } from "./gdocs/OwidGdoc.js"
import StickyNav from "./blocks/StickyNav.js"
@@ -31,151 +27,6 @@ declare global {
_OWID_GRAPHER_CONFIG: GrapherInterface
}
}
-
-const convertMarkdownNodeToSpan = (node: EveryMarkdownNode): Span[] => {
- return match(node)
- .with(
- {
- type: "text",
- },
- (n) => [
- {
- spanType: "span-simple-text" as const,
- text: n.value,
- } as Span,
- ]
- )
- .with(
- {
- type: "textSegments",
- },
- (n) => n.children.flatMap(convertMarkdownNodeToSpan) as Span[]
- )
- .with(
- {
- type: "newline",
- },
- () => [
- {
- spanType: "span-simple-text" as const,
- text: "\n",
- } as Span,
- ]
- )
- .with(
- {
- type: "whitespace",
- },
- () => [
- {
- spanType: "span-simple-text" as const,
- text: " ",
- } as Span,
- ]
- )
- .with(
- {
- type: "detailOnDemand",
- },
- (n) => [
- {
- spanType: "span-dod" as const,
- id: n.term,
- children: n.children.flatMap(convertMarkdownNodeToSpan),
- } as Span,
- ]
- )
- .with(
- {
- type: "markdownLink",
- },
- (n) => [
- {
- spanType: "span-link" as const,
- url: n.href,
- children: n.children.flatMap(convertMarkdownNodeToSpan),
- } as Span,
- ]
- )
- .with(
- {
- type: "plainUrl",
- },
- (n) => [
- {
- spanType: "span-link" as const,
- url: n.href,
- children: [
- {
- spanType: "span-simple-text" as const,
- text: n.href,
- },
- ],
- } as Span,
- ]
- )
- .with(
- {
- type: "bold",
- },
- (n) => [
- {
- spanType: "span-bold" as const,
- children: n.children.flatMap(convertMarkdownNodeToSpan),
- } as Span,
- ]
- )
- .with(
- {
- type: P.union("italic", "plainItalic", "italicWithoutBold"),
- },
- (n) => [
- {
- spanType: "span-italic" as const,
- children: n.children.flatMap(convertMarkdownNodeToSpan),
- } as Span,
- ]
- )
- .with(
- {
- type: P.union("bold", "plainBold", "boldWithoutItalic"),
- },
- (n) => [
- {
- spanType: "span-bold" as const,
- children: n.children.flatMap(convertMarkdownNodeToSpan),
- } as Span,
- ]
- )
- .exhaustive()
- //.otherwise(() => ({ spanType: "span-simple-text" as const, text: "" }))
-}
-
-const convertMarkdownNodesToSpans = (nodes: MarkdownRoot) =>
- nodes.children.flatMap(convertMarkdownNodeToSpan)
-
-const markdownToEnrichedTextBlock = (markdown: string): EnrichedBlockText => {
- const parsedMarkdown = mdParser.markdown.parse(markdown)
- if (parsedMarkdown.status) {
- const spans = convertMarkdownNodesToSpans(parsedMarkdown.value)
- return {
- type: "text",
- value: spans,
- parseErrors: [],
- }
- } else
- return {
- type: "text",
- value: [],
- parseErrors: [
- {
- message: `Failed to parse markdown - expected ${parsedMarkdown.expected} at ${parsedMarkdown.index}`,
- isWarning: false,
- },
- ],
- }
-}
-
export const OWID_DATAPAGE_CONTENT_ROOT_ID = "owid-datapageJson-root"
export const DataPageV2Content = ({
From d85ec6fb234f3b0e1553c90850af95283065432c Mon Sep 17 00:00:00 2001
From: Daniel Bachler
Date: Tue, 19 Sep 2023 16:40:51 +0200
Subject: [PATCH 116/134] :honeybee: lint issues
---
packages/@ourworldindata/utils/src/GdocsUtils.ts | 2 +-
site/DataPageV2Content.tsx | 1 -
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/packages/@ourworldindata/utils/src/GdocsUtils.ts b/packages/@ourworldindata/utils/src/GdocsUtils.ts
index 052d1cba252..5f3e391e2c7 100644
--- a/packages/@ourworldindata/utils/src/GdocsUtils.ts
+++ b/packages/@ourworldindata/utils/src/GdocsUtils.ts
@@ -166,7 +166,7 @@ const convertMarkdownNodeToSpan = (node: EveryMarkdownNode): Span[] => {
//.otherwise(() => ({ spanType: "span-simple-text" as const, text: "" }))
}
-const convertMarkdownNodesToSpans = (nodes: MarkdownRoot) =>
+const convertMarkdownNodesToSpans = (nodes: MarkdownRoot): Span[] =>
nodes.children.flatMap(convertMarkdownNodeToSpan)
export const markdownToEnrichedTextBlock = (
diff --git a/site/DataPageV2Content.tsx b/site/DataPageV2Content.tsx
index 8df870f6ebe..982e4b0cf96 100644
--- a/site/DataPageV2Content.tsx
+++ b/site/DataPageV2Content.tsx
@@ -20,7 +20,6 @@ import cx from "classnames"
import { DebugProvider } from "./gdocs/DebugContext.js"
import { CodeSnippet } from "./blocks/CodeSnippet.js"
import dayjs from "dayjs"
-import { P, match } from "ts-pattern"
declare global {
interface Window {
_OWID_DATAPAGEV2_PROPS: DataPageV2ContentFields
From 454e407ad7fbf1c16129e99074972c7c3454533d Mon Sep 17 00:00:00 2001
From: Ike Saunders
Date: Tue, 19 Sep 2023 14:58:09 +0000
Subject: [PATCH 117/134] =?UTF-8?q?=E2=9C=A8=20use=20"Data=20Explorers"=20?=
=?UTF-8?q?as=20the=20tab=20name=20in=20search?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
site/search/searchTypes.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/site/search/searchTypes.ts b/site/search/searchTypes.ts
index be78f1906e8..85fc6b50a48 100644
--- a/site/search/searchTypes.ts
+++ b/site/search/searchTypes.ts
@@ -77,7 +77,7 @@ export type SearchCategoryFilter = SearchIndexName | "all"
export const searchCategoryFilters: [string, SearchCategoryFilter][] = [
["All", "all"],
["Research & Writing", SearchIndexName.Pages],
- ["Explorers", SearchIndexName.Explorers],
+ ["Data Explorers", SearchIndexName.Explorers],
["Charts", SearchIndexName.Charts],
]
From 8cf7dad1afa11a43ad80ca36eadded0ff2bcf378 Mon Sep 17 00:00:00 2001
From: Ike Saunders
Date: Tue, 19 Sep 2023 20:54:17 +0000
Subject: [PATCH 118/134] =?UTF-8?q?=F0=9F=90=9B=20restore=20missing=20"ite?=
=?UTF-8?q?ms"=20property=20access=20in=20owid/summary=20migration?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
db/model/Gdoc/htmlToEnriched.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/db/model/Gdoc/htmlToEnriched.ts b/db/model/Gdoc/htmlToEnriched.ts
index f2cb55faf8b..5206c24f4f5 100644
--- a/db/model/Gdoc/htmlToEnriched.ts
+++ b/db/model/Gdoc/htmlToEnriched.ts
@@ -638,7 +638,7 @@ function finishWpComponent(
"type" in content.content[0] &&
content.content[0].type === "list"
if (contentIsList) {
- const listItems = get(content, ["content", 0])
+ const listItems = get(content, ["content", 0, "items"])
const items: EnrichedBlockEntrySummaryItem[] = []
const errors = content.errors
if (isArray(listItems)) {
From 527dc2afeb6e75c54477a16b7388b434810aa741 Mon Sep 17 00:00:00 2001
From: Ike Saunders
Date: Wed, 20 Sep 2023 17:14:28 +0000
Subject: [PATCH 119/134] =?UTF-8?q?=E2=9C=A8=20code=20review=20fixes=20for?=
=?UTF-8?q?=20owid/summary=20migration?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
db/model/Gdoc/htmlToEnriched.ts | 4 ++--
db/model/Gdoc/rawToEnriched.ts | 8 ++------
site/gdocs/ArticleBlock.tsx | 4 ++--
3 files changed, 6 insertions(+), 10 deletions(-)
diff --git a/db/model/Gdoc/htmlToEnriched.ts b/db/model/Gdoc/htmlToEnriched.ts
index 5206c24f4f5..3d5960ec890 100644
--- a/db/model/Gdoc/htmlToEnriched.ts
+++ b/db/model/Gdoc/htmlToEnriched.ts
@@ -239,7 +239,7 @@ type ErrorNames =
| "summary item isn't text"
| "summary item doesn't have link"
| "summary item has DataValue"
- | "Unknown content type inside summary block"
+ | "unknown content type inside summary block"
interface BlockParseError {
name: ErrorNames
@@ -686,7 +686,7 @@ function finishWpComponent(
}
const error: BlockParseError = {
- name: "Unknown content type inside summary block",
+ name: "unknown content type inside summary block",
details:
"Unknown summary content: " +
content.content
diff --git a/db/model/Gdoc/rawToEnriched.ts b/db/model/Gdoc/rawToEnriched.ts
index 50086d8b7ac..1c9c30383a2 100644
--- a/db/model/Gdoc/rawToEnriched.ts
+++ b/db/model/Gdoc/rawToEnriched.ts
@@ -1508,13 +1508,9 @@ function parseEntrySummary(
if (raw.value.items) {
raw.value.items.forEach((item, i) => {
- if (!item.text) {
+ if (!item.text || !item.slug) {
parseErrors.push({
- message: `entry-summary item ${i} is missing text`,
- })
- } else if (!item.slug) {
- parseErrors.push({
- message: `Entry summary item with text ${item.text} is missing a url`,
+ message: `entry-summary item ${i} is not valid. It must have a text and a slug property`,
})
} else {
items.push({
diff --git a/site/gdocs/ArticleBlock.tsx b/site/gdocs/ArticleBlock.tsx
index 26d46937770..37678bd53e2 100644
--- a/site/gdocs/ArticleBlock.tsx
+++ b/site/gdocs/ArticleBlock.tsx
@@ -503,7 +503,7 @@ export default function ArticleBlock({
) : null
})
.with({ type: "entry-summary" }, (block) => {
- return toc ? (
+ return (
({
@@ -513,7 +513,7 @@ export default function ArticleBlock({
}))}
className={getLayout("toc", containerType)}
/>
- ) : null
+ )
})
.with({ type: "missing-data" }, () => (
From 517c9774d0bf3e0d3f70a97952eebe0137fac158 Mon Sep 17 00:00:00 2001
From: Ike Saunders
Date: Mon, 11 Sep 2023 17:29:42 -0400
Subject: [PATCH 120/134] =?UTF-8?q?=E2=9C=A8=20research-and-writing=20basi?=
=?UTF-8?q?c=20redesign?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
site/gdocs/ResearchAndWriting.scss | 44 +++---------------------------
site/gdocs/ResearchAndWriting.tsx | 31 ++++++++++-----------
2 files changed, 19 insertions(+), 56 deletions(-)
diff --git a/site/gdocs/ResearchAndWriting.scss b/site/gdocs/ResearchAndWriting.scss
index 0e8fc9f4ef7..411ad48b44c 100644
--- a/site/gdocs/ResearchAndWriting.scss
+++ b/site/gdocs/ResearchAndWriting.scss
@@ -16,46 +16,10 @@
}
}
-.research-and-writing-more {
- padding: 24px;
- background: $gray-10;
- h5 {
- margin: 0;
- color: $blue-50;
- }
-
- @include md-down {
- margin-top: 24px;
- }
-
- .research-and-writing-link {
- display: block;
- h3 {
- @include h3-bold;
- margin-top: 16px;
- margin-bottom: 8px;
- }
-
- p {
- margin-bottom: 8px;
- }
-
- &:not(:last-child) {
- border-bottom: 1px solid $blue-10;
- }
-
- &:last-child p {
- margin-bottom: 0;
- }
- }
-}
-
-.research-and-writing-row {
- h5 {
- text-align: center;
- margin-top: 40px;
- margin-bottom: 24px;
- }
+.research-and-writing-row h2 {
+ margin-top: 32px;
+ margin-bottom: 24px;
+ color: $blue-50;
}
.research-and-writing-row__link-container {
diff --git a/site/gdocs/ResearchAndWriting.tsx b/site/gdocs/ResearchAndWriting.tsx
index b0760f7d831..edf04dc81f4 100644
--- a/site/gdocs/ResearchAndWriting.tsx
+++ b/site/gdocs/ResearchAndWriting.tsx
@@ -101,25 +101,10 @@ export function ResearchAndWriting(props: ResearchAndWritingProps) {
className="span-cols-3 span-md-cols-6 span-sm-cols-12"
{...secondary}
/>
-
-
- {more.heading}
- {more.articles.map((link, i) => (
-
- ))}
-
-
{rows.map((row, i) => (
- {row.heading}
+ {row.heading}
- {/* center the two thumbnails with a filler element */}
- {row.articles.length === 2 ? : null}
{row.articles.map((link, i) => (
))}
+
+ {more.heading}
+
+ {more.articles.map((link, i) => (
+
+ ))}
+
+
)
}
From 89227232b83684ace7ec7638b63db91e1c96fa5e Mon Sep 17 00:00:00 2001
From: Ike Saunders
Date: Mon, 11 Sep 2023 17:59:12 -0400
Subject: [PATCH 121/134] =?UTF-8?q?=F0=9F=8E=89=20support=20multiple=20pri?=
=?UTF-8?q?mary=20and=20secondary=20research-and-writing=20links?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
db/model/Gdoc/enrichedToRaw.ts | 22 +++++---
db/model/Gdoc/exampleEnrichedBlocks.ts | 25 +++++++---
db/model/Gdoc/gdocUtils.ts | 10 ++--
db/model/Gdoc/rawToArchie.ts | 25 +++++++---
db/model/Gdoc/rawToEnriched.ts | 43 ++++++++++------
.../@ourworldindata/utils/src/owidTypes.ts | 15 ++++--
site/gdocs/ResearchAndWriting.tsx | 50 +++++++++++--------
7 files changed, 122 insertions(+), 68 deletions(-)
diff --git a/db/model/Gdoc/enrichedToRaw.ts b/db/model/Gdoc/enrichedToRaw.ts
index 3d6e4ea9d07..5874eee862c 100644
--- a/db/model/Gdoc/enrichedToRaw.ts
+++ b/db/model/Gdoc/enrichedToRaw.ts
@@ -348,14 +348,20 @@ export function enrichedBlockToRawBlock(
return {
type: b.type,
value: {
- primary: enrichedLinkToRawLink(b.primary),
- secondary: enrichedLinkToRawLink(b.secondary),
- more: {
- heading: b.more.heading,
- articles: b.more.articles.map(
- enrichedLinkToRawLink
- ),
- },
+ primary: b.primary.map((enriched) =>
+ enrichedLinkToRawLink(enriched)
+ ),
+ secondary: b.secondary.map((enriched) =>
+ enrichedLinkToRawLink(enriched)
+ ),
+ more: b.more
+ ? {
+ heading: b.more.heading,
+ articles: b.more.articles.map(
+ enrichedLinkToRawLink
+ ),
+ }
+ : undefined,
rows: b.rows.map(({ heading, articles }) => ({
heading: heading,
articles: articles.map(enrichedLinkToRawLink),
diff --git a/db/model/Gdoc/exampleEnrichedBlocks.ts b/db/model/Gdoc/exampleEnrichedBlocks.ts
index b0de1a27493..78c58d70e1c 100644
--- a/db/model/Gdoc/exampleEnrichedBlocks.ts
+++ b/db/model/Gdoc/exampleEnrichedBlocks.ts
@@ -355,16 +355,25 @@ export const enrichedBlockExamples: Record<
"research-and-writing": {
type: "research-and-writing",
parseErrors: [],
- primary: {
- value: {
- url: "https://docs.google.com/document/d/abcd",
+ primary: [
+ {
+ value: {
+ url: "https://docs.google.com/document/d/abcd",
+ },
},
- },
- secondary: {
- value: {
- url: "https://docs.google.com/document/d/abcd",
+ ],
+ secondary: [
+ {
+ value: {
+ url: "https://docs.google.com/document/d/1234",
+ },
},
- },
+ {
+ value: {
+ url: "https://docs.google.com/document/d/5678",
+ },
+ },
+ ],
more: {
heading: "More Key Articles on Poverty",
articles: [
diff --git a/db/model/Gdoc/gdocUtils.ts b/db/model/Gdoc/gdocUtils.ts
index a74dc8a4b5f..d076ffd1e81 100644
--- a/db/model/Gdoc/gdocUtils.ts
+++ b/db/model/Gdoc/gdocUtils.ts
@@ -139,12 +139,10 @@ export const getAllLinksFromResearchAndWritingBlock = (
): EnrichedBlockResearchAndWritingLink[] => {
const { primary, secondary, more, rows } = block
const rowArticles = rows.flatMap((row) => row.articles)
- const allLinks = excludeNullish([
- primary,
- secondary,
- ...more.articles,
- ...rowArticles,
- ])
+ const allLinks = excludeNullish([...primary, ...secondary, ...rowArticles])
+ if (more) {
+ allLinks.push(...more.articles)
+ }
return allLinks
}
diff --git a/db/model/Gdoc/rawToArchie.ts b/db/model/Gdoc/rawToArchie.ts
index ff937053c39..59a943423dc 100644
--- a/db/model/Gdoc/rawToArchie.ts
+++ b/db/model/Gdoc/rawToArchie.ts
@@ -31,6 +31,7 @@ import {
RawBlockExpandableParagraph,
RawBlockAlign,
RawBlockEntrySummary,
+ isArray,
} from "@ourworldindata/utils"
import { match } from "ts-pattern"
@@ -471,14 +472,26 @@ function* rawResearchAndWritingToArchieMLString(
}
yield "{.research-and-writing}"
if (primary) {
- yield "{.primary}"
- yield* rawLinkToArchie(primary)
- yield "{}"
+ yield "[.primary]"
+ if (isArray(primary)) {
+ for (const link of primary) {
+ yield* rawLinkToArchie(link)
+ }
+ } else {
+ yield* rawLinkToArchie(primary)
+ }
+ yield "[]"
}
if (secondary) {
- yield "{.secondary}"
- yield* rawLinkToArchie(secondary)
- yield "{}"
+ yield "[.secondary]"
+ if (isArray(secondary)) {
+ for (const link of secondary) {
+ yield* rawLinkToArchie(link)
+ }
+ } else {
+ yield* rawLinkToArchie(secondary)
+ }
+ yield "[]"
}
if (more) {
yield "{.more}"
diff --git a/db/model/Gdoc/rawToEnriched.ts b/db/model/Gdoc/rawToEnriched.ts
index 1c9c30383a2..a5a861243f5 100644
--- a/db/model/Gdoc/rawToEnriched.ts
+++ b/db/model/Gdoc/rawToEnriched.ts
@@ -1350,12 +1350,16 @@ function parseResearchAndWritingBlock(
): EnrichedBlockResearchAndWriting {
const createError = (
error: ParseError,
- primary = {
- value: { url: "" },
- },
- secondary = {
- value: { url: "" },
- },
+ primary = [
+ {
+ value: { url: "" },
+ },
+ ],
+ secondary = [
+ {
+ value: { url: "" },
+ },
+ ],
more: EnrichedBlockResearchAndWritingRow = {
heading: "",
articles: [],
@@ -1421,14 +1425,25 @@ function parseResearchAndWritingBlock(
if (!raw.value.primary)
return createError({ message: "Missing primary link" })
- const primary = enrichLink(raw.value.primary)
-
- if (!raw.value.secondary)
- return createError({ message: "Missing secondary link" })
- const secondary = enrichLink(raw.value.secondary)
+ const primary: EnrichedBlockResearchAndWritingLink[] = []
+ if (isArray(raw.value.primary)) {
+ primary.push(...raw.value.primary.map((link) => enrichLink(link)))
+ } else {
+ primary.push(enrichLink(raw.value.primary))
+ }
- if (!raw.value.more)
- return createError({ message: "No 'more' section defined" })
+ const secondary: EnrichedBlockResearchAndWritingLink[] = []
+ if (isArray(raw.value.secondary)) {
+ secondary.push(...raw.value.secondary.map((link) => enrichLink(link)))
+ } else if (raw.value.secondary) {
+ secondary.push(enrichLink(raw.value.secondary))
+ }
+ if (secondary.length && primary.length > 1) {
+ return createError({
+ message:
+ "Secondary links can only be used when there's exactly one primary link",
+ })
+ }
function parseRow(
rawRow: RawBlockResearchAndWritingRow,
@@ -1454,7 +1469,7 @@ function parseResearchAndWritingBlock(
return { heading: "", articles: [] }
}
- const more = parseRow(raw.value.more, true)
+ const more = raw.value.more ? parseRow(raw.value.more, true) : undefined
const rows = raw.value.rows?.map((row) => parseRow(row)) || []
return {
diff --git a/packages/@ourworldindata/utils/src/owidTypes.ts b/packages/@ourworldindata/utils/src/owidTypes.ts
index 969e1e65a0f..a1f87cabe62 100644
--- a/packages/@ourworldindata/utils/src/owidTypes.ts
+++ b/packages/@ourworldindata/utils/src/owidTypes.ts
@@ -966,8 +966,13 @@ export type RawBlockResearchAndWritingRow = {
export type RawBlockResearchAndWriting = {
type: "research-and-writing"
value: {
- primary?: RawBlockResearchAndWritingLink
- secondary?: RawBlockResearchAndWritingLink
+ // We're migrating these to be arrays, but have to support the old use-case until it's done
+ primary?:
+ | RawBlockResearchAndWritingLink
+ | RawBlockResearchAndWritingLink[]
+ secondary?:
+ | RawBlockResearchAndWritingLink
+ | RawBlockResearchAndWritingLink[]
more?: RawBlockResearchAndWritingRow
rows?: RawBlockResearchAndWritingRow[]
}
@@ -990,9 +995,9 @@ export type EnrichedBlockResearchAndWritingRow = {
export type EnrichedBlockResearchAndWriting = {
type: "research-and-writing"
- primary: EnrichedBlockResearchAndWritingLink
- secondary: EnrichedBlockResearchAndWritingLink
- more: EnrichedBlockResearchAndWritingRow
+ primary: EnrichedBlockResearchAndWritingLink[]
+ secondary: EnrichedBlockResearchAndWritingLink[]
+ more?: EnrichedBlockResearchAndWritingRow
rows: EnrichedBlockResearchAndWritingRow[]
} & EnrichedBlockWithParseErrors
diff --git a/site/gdocs/ResearchAndWriting.tsx b/site/gdocs/ResearchAndWriting.tsx
index edf04dc81f4..79027340979 100644
--- a/site/gdocs/ResearchAndWriting.tsx
+++ b/site/gdocs/ResearchAndWriting.tsx
@@ -93,14 +93,20 @@ export function ResearchAndWriting(props: ResearchAndWritingProps) {
Research & Writing
-
-
+ {primary.map((link, i) => (
+
+ ))}
+ {secondary.map((link, i) => (
+
+ ))}
{rows.map((row, i) => (
{row.heading}
@@ -117,20 +123,22 @@ export function ResearchAndWriting(props: ResearchAndWritingProps) {
))}
-
- {more.heading}
-
- {more.articles.map((link, i) => (
-
- ))}
+ {more ? (
+
+ {more.heading}
+
+ {more.articles.map((link, i) => (
+
+ ))}
+
-
+ ) : null}
)
}
From 758f05c797bee804580b14753be86b6eb8c07063 Mon Sep 17 00:00:00 2001
From: Ike Saunders
Date: Tue, 12 Sep 2023 13:37:18 -0400
Subject: [PATCH 122/134] =?UTF-8?q?=E2=9C=A8=20allow=20any=20number=20of?=
=?UTF-8?q?=20primary=20and=20secondary=20articles=20in=20the=20research-a?=
=?UTF-8?q?nd-writing=20block?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
db/model/Gdoc/rawToEnriched.ts | 6 ------
1 file changed, 6 deletions(-)
diff --git a/db/model/Gdoc/rawToEnriched.ts b/db/model/Gdoc/rawToEnriched.ts
index a5a861243f5..74912f0c06d 100644
--- a/db/model/Gdoc/rawToEnriched.ts
+++ b/db/model/Gdoc/rawToEnriched.ts
@@ -1438,12 +1438,6 @@ function parseResearchAndWritingBlock(
} else if (raw.value.secondary) {
secondary.push(enrichLink(raw.value.secondary))
}
- if (secondary.length && primary.length > 1) {
- return createError({
- message:
- "Secondary links can only be used when there's exactly one primary link",
- })
- }
function parseRow(
rawRow: RawBlockResearchAndWritingRow,
From 30f513e4ddccf8813a4ac8dc75cc3856ebb032f8 Mon Sep 17 00:00:00 2001
From: Ike Saunders
Date: Tue, 12 Sep 2023 13:37:31 -0400
Subject: [PATCH 123/134] =?UTF-8?q?=E2=9C=A8=20left-align=20the=20research?=
=?UTF-8?q?-and-writing=20block=20heading?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
site/gdocs/ResearchAndWriting.scss | 1 -
1 file changed, 1 deletion(-)
diff --git a/site/gdocs/ResearchAndWriting.scss b/site/gdocs/ResearchAndWriting.scss
index 411ad48b44c..b037fa47bd4 100644
--- a/site/gdocs/ResearchAndWriting.scss
+++ b/site/gdocs/ResearchAndWriting.scss
@@ -2,7 +2,6 @@
margin-bottom: 40px;
> h1 {
- text-align: center;
font-size: 32px;
margin-bottom: 40px;
From c690c65e30d15de99d178a57a7bd42380313c9ce Mon Sep 17 00:00:00 2001
From: Ike Saunders
Date: Tue, 12 Sep 2023 16:56:42 -0400
Subject: [PATCH 124/134] =?UTF-8?q?=F0=9F=8E=89=20migration=20for=20iterab?=
=?UTF-8?q?le=20research-and-writing?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...694549232436-IterableResearchAndWriting.ts | 55 +++++++++++++++++++
1 file changed, 55 insertions(+)
create mode 100644 db/migration/1694549232436-IterableResearchAndWriting.ts
diff --git a/db/migration/1694549232436-IterableResearchAndWriting.ts b/db/migration/1694549232436-IterableResearchAndWriting.ts
new file mode 100644
index 00000000000..c0c41cf6d61
--- /dev/null
+++ b/db/migration/1694549232436-IterableResearchAndWriting.ts
@@ -0,0 +1,55 @@
+import { OwidGdocContent } from "@ourworldindata/utils"
+import { MigrationInterface, QueryRunner } from "typeorm"
+
+export class IterableResearchAndWriting1694549232436
+ implements MigrationInterface
+{
+ public async up(queryRunner: QueryRunner): Promise {
+ await migrateResearchAndWritingBlocks(queryRunner, (node) => {
+ const primary = node.primary as any
+ const secondary = node.secondary as any
+ node.primary = [primary]
+ node.secondary = [secondary]
+ })
+ }
+
+ public async down(queryRunner: QueryRunner): Promise {
+ await migrateResearchAndWritingBlocks(queryRunner, (node) => {
+ const primary = node.primary as any
+ const secondary = node.secondary as any
+ node.primary = primary[0]
+ node.secondary = secondary[0]
+ })
+ }
+}
+
+async function migrateResearchAndWritingBlocks(
+ queryRunner: QueryRunner,
+ callback: (node: any) => void
+): Promise {
+ const allGdocs = await queryRunner.query(
+ "SELECT id, slug, content FROM posts_gdocs"
+ )
+ for (const gdoc of allGdocs) {
+ const content = JSON.parse(gdoc.content) as OwidGdocContent
+ if (!content.body) continue
+
+ let hasResearchAndWriting = false
+
+ // Not recursively traversing because none of our topic pages have research-and-writing blocks nested inside containers
+ content.body.forEach((node) => {
+ if (node.type === "research-and-writing") {
+ hasResearchAndWriting = true
+ callback(node)
+ }
+ return node
+ })
+
+ if (hasResearchAndWriting) {
+ await queryRunner.query(
+ "UPDATE posts_gdocs SET content = ? WHERE id = ?",
+ [JSON.stringify(content), gdoc.id]
+ )
+ }
+ }
+}
From 917f7e4708173c26280368b37aa176993a6a15ec Mon Sep 17 00:00:00 2001
From: Ike Saunders
Date: Wed, 13 Sep 2023 13:43:47 -0400
Subject: [PATCH 125/134] =?UTF-8?q?=E2=9C=A8=20collapse=20primary=20and=20?=
=?UTF-8?q?secondary=20articles=20in=20research-and-writing=20block?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
site/gdocs/ResearchAndWriting.tsx | 32 +++++++++++++++++--------------
1 file changed, 18 insertions(+), 14 deletions(-)
diff --git a/site/gdocs/ResearchAndWriting.tsx b/site/gdocs/ResearchAndWriting.tsx
index 79027340979..d97f518c9f9 100644
--- a/site/gdocs/ResearchAndWriting.tsx
+++ b/site/gdocs/ResearchAndWriting.tsx
@@ -93,20 +93,24 @@ export function ResearchAndWriting(props: ResearchAndWritingProps) {
Research & Writing
- {primary.map((link, i) => (
-
- ))}
- {secondary.map((link, i) => (
-
- ))}
+
+
+ {primary.map((link, i) => (
+
+ ))}
+ {secondary.map((link, i) => (
+
+ ))}
+
+
{rows.map((row, i) => (
{row.heading}
From 30015a51f5bfaa1ab23ada6adced1b75e7f9b464 Mon Sep 17 00:00:00 2001
From: Ike Saunders
Date: Wed, 20 Sep 2023 17:20:32 +0000
Subject: [PATCH 126/134] =?UTF-8?q?=F0=9F=94=A8=20remove=20redundant=20cla?=
=?UTF-8?q?ssname=20in=20R&W=20block?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
site/gdocs/ResearchAndWriting.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/site/gdocs/ResearchAndWriting.tsx b/site/gdocs/ResearchAndWriting.tsx
index d97f518c9f9..1f740bab7f9 100644
--- a/site/gdocs/ResearchAndWriting.tsx
+++ b/site/gdocs/ResearchAndWriting.tsx
@@ -97,7 +97,7 @@ export function ResearchAndWriting(props: ResearchAndWritingProps) {
{primary.map((link, i) => (
From 30d3cae3058c5c4da05e39ed9f18e46b5f46166c Mon Sep 17 00:00:00 2001
From: Daniel Bachler
Date: Thu, 21 Sep 2023 14:55:28 +0200
Subject: [PATCH 127/134] :hammer: use a heuristic to check if source tab
content is HTML and render it as such
We have switched the ETL to use markdown for both the new origins and the old sources
but there are still some remnants (e.g. backported indciators)
that contain HTML.
This PR adds a temporary fix so that if content seems to be HTML
it is shown as is in the sources tab in Grapher
---
.../grapher/src/sourcesTab/SourcesTab.tsx | 29 +++++++++++++++----
1 file changed, 24 insertions(+), 5 deletions(-)
diff --git a/packages/@ourworldindata/grapher/src/sourcesTab/SourcesTab.tsx b/packages/@ourworldindata/grapher/src/sourcesTab/SourcesTab.tsx
index 812c4791130..ddb13f2b8f2 100644
--- a/packages/@ourworldindata/grapher/src/sourcesTab/SourcesTab.tsx
+++ b/packages/@ourworldindata/grapher/src/sourcesTab/SourcesTab.tsx
@@ -19,6 +19,25 @@ export interface SourcesTabManager {
showAdminControls?: boolean
}
+// TODO: remove this component once all backported indicators
+// etc have switched from HTML to markdown for their sources
+const HtmlOrMarkdownText = (props: {
+ text: string
+ fontSize: number
+}): JSX.Element => {
+ // check the text for closing a, li or p tags. If
+ // one is found, render using dangerouslySetInnerHTML,
+ // othewise use MarkdownTextWrap
+ const { text, fontSize } = props
+ const htmlRegex = /<\/(a|li|p)>/
+ const match = text.match(htmlRegex)
+ if (match) {
+ return
+ } else {
+ return
+ }
+}
+
@observer
export class SourcesTab extends React.Component<{
bounds?: Bounds
@@ -107,7 +126,7 @@ export class SourcesTab extends React.Component<{
Variable description
-
@@ -160,7 +179,7 @@ export class SourcesTab extends React.Component<{
Data published by
-
@@ -171,7 +190,7 @@ export class SourcesTab extends React.Component<{
Data publisher's source
-
@@ -182,7 +201,7 @@ export class SourcesTab extends React.Component<{
Link
-
@@ -199,7 +218,7 @@ export class SourcesTab extends React.Component<{
{source.additionalInfo && (
-
From d92961be05941cd63e31ba67bcc627293d501f5f Mon Sep 17 00:00:00 2001
From: Daniel Bachler
Date: Thu, 21 Sep 2023 19:05:42 +0200
Subject: [PATCH 128/134] :sparkles: render citationFull on sourcesTab as
markdown
---
.../grapher/src/sourcesTab/SourcesTab.tsx | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/packages/@ourworldindata/grapher/src/sourcesTab/SourcesTab.tsx b/packages/@ourworldindata/grapher/src/sourcesTab/SourcesTab.tsx
index ddb13f2b8f2..e740a01958a 100644
--- a/packages/@ourworldindata/grapher/src/sourcesTab/SourcesTab.tsx
+++ b/packages/@ourworldindata/grapher/src/sourcesTab/SourcesTab.tsx
@@ -154,7 +154,12 @@ export class SourcesTab extends React.Component<{
{citationFull.length === 1 ? (
Data published by
- {citationFull[0]}
+
+
+
) : null}
{citationFull.length > 1 ? (
@@ -164,10 +169,15 @@ export class SourcesTab extends React.Component<{
{citationFull.map(
(
- producer: string,
+ citation: string,
index: number
) => (
- - {producer}
+ -
+
+
)
)}
From 57822c6de912507a9451f14d65d32b42b5b8e293 Mon Sep 17 00:00:00 2001
From: Daniel Bachler
Date: Thu, 21 Sep 2023 23:39:31 +0200
Subject: [PATCH 129/134] :bug: crude fix for map color animation resulting in
wrong colors
---
explorer/Explorer.tsx | 1 +
packages/@ourworldindata/grapher/src/core/Grapher.tsx | 8 +++++++-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/explorer/Explorer.tsx b/explorer/Explorer.tsx
index 3c493124e58..d4c01b1a222 100644
--- a/explorer/Explorer.tsx
+++ b/explorer/Explorer.tsx
@@ -573,6 +573,7 @@ export class Explorer
grapher.reset()
this.updateGrapherFromExplorerCommon()
grapher.updateFromObject(config)
+ grapher.forceDisableIntroAnimation = true
await grapher.downloadLegacyDataFromOwidVariableIds()
let grapherTable = grapher.inputTable
diff --git a/packages/@ourworldindata/grapher/src/core/Grapher.tsx b/packages/@ourworldindata/grapher/src/core/Grapher.tsx
index 46efcf99091..7166459c994 100644
--- a/packages/@ourworldindata/grapher/src/core/Grapher.tsx
+++ b/packages/@ourworldindata/grapher/src/core/Grapher.tsx
@@ -398,6 +398,12 @@ export class Grapher
@observable sortBy?: SortBy
@observable sortOrder?: SortOrder
@observable sortColumnSlug?: string
+ // TODO: this is a crude fix that is used to turn off the intro
+ // animation in maps (fading colors in from gray) because
+ // they end up with the wrong target colors (i.e. the colors
+ // are initially correct but then the animation screws them up).
+ // This flag can be removed once the animation bug is properly fixed.
+ @observable forceDisableIntroAnimation: boolean = false
owidDataset?: MultipleOwidVariableDataDimensionsMap = undefined // This is used for passing data for testing
@@ -1608,7 +1614,7 @@ export class Grapher
}
@computed get disableIntroAnimation(): boolean {
- return this.isExportingtoSvgOrPng
+ return this.isExportingtoSvgOrPng || this.forceDisableIntroAnimation
}
@computed get mapConfig(): MapConfig {
From aa8a886d0c2c83f84adcac2eed57265d41ea619d Mon Sep 17 00:00:00 2001
From: Ike Saunders
Date: Fri, 22 Sep 2023 11:15:12 -0400
Subject: [PATCH 130/134] =?UTF-8?q?=F0=9F=94=A8=20include=20status=20in=20?=
=?UTF-8?q?buildkite=20build=20failure=20error=20message?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
baker/BuildkiteTrigger.ts | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/baker/BuildkiteTrigger.ts b/baker/BuildkiteTrigger.ts
index 6ba269f6805..24be01cdb9e 100644
--- a/baker/BuildkiteTrigger.ts
+++ b/baker/BuildkiteTrigger.ts
@@ -78,7 +78,9 @@ export class BuildkiteTrigger {
if (status === "passed") {
return
} else {
- throw new Error("Build failed! See Buildkite for details.")
+ throw new Error(
+ `Build failed with status "${status}". See Buildkite for details.`
+ )
}
}
From b963d7e5e1297f244f4f23762e5cf2b801f31a18 Mon Sep 17 00:00:00 2001
From: Ike Saunders
Date: Fri, 22 Sep 2023 16:02:01 +0000
Subject: [PATCH 131/134] =?UTF-8?q?=F0=9F=90=9B=20use=20MarkdownTextWrap?=
=?UTF-8?q?=20in=20explorer=20subtitle?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
explorer/Explorer.tsx | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/explorer/Explorer.tsx b/explorer/Explorer.tsx
index d4c01b1a222..155a5ba4b86 100644
--- a/explorer/Explorer.tsx
+++ b/explorer/Explorer.tsx
@@ -36,6 +36,7 @@ import {
isInIFrame,
keyBy,
keyMap,
+ MarkdownTextWrap,
omitUndefinedValues,
PromiseCache,
PromiseSwitcher,
@@ -746,12 +747,12 @@ export class Explorer
{this.explorerProgram.explorerTitle}
-
+
+
+
)
}
From 3076289569f8b2434f8011303153a99368d639ed Mon Sep 17 00:00:00 2001
From: Daniel Bachler
Date: Fri, 22 Sep 2023 18:39:07 +0200
Subject: [PATCH 132/134] :honeybee: join attribution fragments with ; instead
of ,
---
packages/@ourworldindata/grapher/src/core/Grapher.tsx | 2 +-
packages/@ourworldindata/utils/src/Util.ts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/@ourworldindata/grapher/src/core/Grapher.tsx b/packages/@ourworldindata/grapher/src/core/Grapher.tsx
index 7166459c994..44add4b5e6b 100644
--- a/packages/@ourworldindata/grapher/src/core/Grapher.tsx
+++ b/packages/@ourworldindata/grapher/src/core/Grapher.tsx
@@ -1481,7 +1481,7 @@ export class Grapher
if (uniqueAttributions.length > 3) return "Multiple sources"
- return uniqueAttributions.join(", ")
+ return uniqueAttributions.join("; ")
}
@computed private get axisDimensions(): ChartDimension[] {
diff --git a/packages/@ourworldindata/utils/src/Util.ts b/packages/@ourworldindata/utils/src/Util.ts
index 8fc385beacc..a2e4a382346 100644
--- a/packages/@ourworldindata/utils/src/Util.ts
+++ b/packages/@ourworldindata/utils/src/Util.ts
@@ -1754,7 +1754,7 @@ export function getAttributionFromVariable(
variable.origins
)
const sourceName = variable.source?.name
- return uniq(compact([sourceName, ...originAttributionFragments])).join(", ")
+ return uniq(compact([sourceName, ...originAttributionFragments])).join("; ")
}
interface ETLPathComponents {
From b439bb8787100f50213c385790d097324337da10 Mon Sep 17 00:00:00 2001
From: Marcel Gerber
Date: Mon, 25 Sep 2023 08:06:59 +0200
Subject: [PATCH 133/134] chore(deps): dedupe lockfile
---
yarn.lock | 105 +++++-------------------------------------------------
1 file changed, 8 insertions(+), 97 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index ab00bf24974..48e3a098abe 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -19,16 +19,6 @@ __metadata:
languageName: node
linkType: hard
-"@algolia/autocomplete-core@npm:1.10.0":
- version: 1.10.0
- resolution: "@algolia/autocomplete-core@npm:1.10.0"
- dependencies:
- "@algolia/autocomplete-plugin-algolia-insights": 1.10.0
- "@algolia/autocomplete-shared": 1.10.0
- checksum: baf7b691b4089e40cab47cf00cce9fc6aa816335845e39f12e6496597fbc965bdbb94f9624b9c693cae1eeb5b45b48c2da6072727f027a26489018afd8792563
- languageName: node
- linkType: hard
-
"@algolia/autocomplete-core@npm:1.11.0":
version: 1.11.0
resolution: "@algolia/autocomplete-core@npm:1.11.0"
@@ -39,7 +29,7 @@ __metadata:
languageName: node
linkType: hard
-"@algolia/autocomplete-js@npm:1.11.0":
+"@algolia/autocomplete-js@npm:1.11.0, @algolia/autocomplete-js@npm:^1.10.0":
version: 1.11.0
resolution: "@algolia/autocomplete-js@npm:1.11.0"
dependencies:
@@ -55,33 +45,6 @@ __metadata:
languageName: node
linkType: hard
-"@algolia/autocomplete-js@npm:^1.10.0":
- version: 1.10.0
- resolution: "@algolia/autocomplete-js@npm:1.10.0"
- dependencies:
- "@algolia/autocomplete-core": 1.10.0
- "@algolia/autocomplete-preset-algolia": 1.10.0
- "@algolia/autocomplete-shared": 1.10.0
- htm: ^3.1.1
- preact: ^10.13.2
- peerDependencies:
- "@algolia/client-search": ">= 4.5.1 < 6"
- algoliasearch: ">= 4.9.1 < 6"
- checksum: a1ea1d904c17ff258b54ccfa22a923835188e50c65315ab41304b522324fdab7b0f05058f6fc0f73773b814005507b884626ce3638653e89db1e6b8f7c180192
- languageName: node
- linkType: hard
-
-"@algolia/autocomplete-plugin-algolia-insights@npm:1.10.0":
- version: 1.10.0
- resolution: "@algolia/autocomplete-plugin-algolia-insights@npm:1.10.0"
- dependencies:
- "@algolia/autocomplete-shared": 1.10.0
- peerDependencies:
- search-insights: ">= 1 < 3"
- checksum: 1008a03a6e8e7ed84644d47e77abfe2fb1b52060911767582a3aa2243e3327fec6e3b5315ff848b3658a051429de26571a7fc4824d9966b017f3be151e44908b
- languageName: node
- linkType: hard
-
"@algolia/autocomplete-plugin-algolia-insights@npm:1.11.0":
version: 1.11.0
resolution: "@algolia/autocomplete-plugin-algolia-insights@npm:1.11.0"
@@ -107,18 +70,6 @@ __metadata:
languageName: node
linkType: hard
-"@algolia/autocomplete-preset-algolia@npm:1.10.0":
- version: 1.10.0
- resolution: "@algolia/autocomplete-preset-algolia@npm:1.10.0"
- dependencies:
- "@algolia/autocomplete-shared": 1.10.0
- peerDependencies:
- "@algolia/client-search": ">= 4.9.1 < 6"
- algoliasearch: ">= 4.9.1 < 6"
- checksum: b9de85fcbcf39b7588dcfa584cd8c2c4fa71fffd73cc356894498724e85e77f9fb02d6a9ab56ffc9a2e568989fee43352be3867cbd53e24c2e3dbaf1ef811e01
- languageName: node
- linkType: hard
-
"@algolia/autocomplete-preset-algolia@npm:1.11.0":
version: 1.11.0
resolution: "@algolia/autocomplete-preset-algolia@npm:1.11.0"
@@ -131,16 +82,6 @@ __metadata:
languageName: node
linkType: hard
-"@algolia/autocomplete-shared@npm:1.10.0":
- version: 1.10.0
- resolution: "@algolia/autocomplete-shared@npm:1.10.0"
- peerDependencies:
- "@algolia/client-search": ">= 4.9.1 < 6"
- algoliasearch: ">= 4.9.1 < 6"
- checksum: cf02ca1173c6257dd86eb50ba30296b467aeac56a9e792a5150a73a1a05fe5156cf943f68e225e49dbdd61c7d00209dc9237ebd86e3a8dd7d3e7da3f81092b8b
- languageName: node
- linkType: hard
-
"@algolia/autocomplete-shared@npm:1.11.0":
version: 1.11.0
resolution: "@algolia/autocomplete-shared@npm:1.11.0"
@@ -1871,7 +1812,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/runtime@npm:^7.0.0":
+"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.10.4, @babel/runtime@npm:^7.11.1, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.14.5, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
version: 7.22.6
resolution: "@babel/runtime@npm:7.22.6"
dependencies:
@@ -1880,15 +1821,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.10.4, @babel/runtime@npm:^7.11.1, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.14.5, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
- version: 7.19.4
- resolution: "@babel/runtime@npm:7.19.4"
- dependencies:
- regenerator-runtime: ^0.13.4
- checksum: 66b7e3c13e9ee1d2c9397ea89144f29a875edee266a0eb2d9971be51b32fdbafc85808c7a45e011e6681899bb804b4e2ee2aed6dc07108dbbd6b11b6cc2afba6
- languageName: node
- linkType: hard
-
"@babel/template@npm:^7.22.5, @babel/template@npm:^7.3.3":
version: 7.22.5
resolution: "@babel/template@npm:7.22.5"
@@ -6148,10 +6080,10 @@ __metadata:
languageName: node
linkType: hard
-"@types/node@npm:*":
- version: 16.11.39
- resolution: "@types/node@npm:16.11.39"
- checksum: bc97b9773ac6b3194800f990b349fad7f66c6126dacef59291b10a2c8b6813d6f67f947b7e12a6c9952790f7065d576fe38355b8fe034a6af60f317cfc570f69
+"@types/node@npm:*, @types/node@npm:^18.11.18":
+ version: 18.17.15
+ resolution: "@types/node@npm:18.17.15"
+ checksum: eed11d4398ccdb999a4c65658ee75de621a4ad57aece48ed2fb8803b1e2711fadf58d8aefbdb0a447d69cf3cba602ca32fe0fc92077575950a796e1dc13baa0f
languageName: node
linkType: hard
@@ -6162,13 +6094,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/node@npm:^18.11.18":
- version: 18.17.15
- resolution: "@types/node@npm:18.17.15"
- checksum: eed11d4398ccdb999a4c65658ee75de621a4ad57aece48ed2fb8803b1e2711fadf58d8aefbdb0a447d69cf3cba602ca32fe0fc92077575950a796e1dc13baa0f
- languageName: node
- linkType: hard
-
"@types/normalize-package-data@npm:^2.4.0, @types/normalize-package-data@npm:^2.4.1":
version: 2.4.1
resolution: "@types/normalize-package-data@npm:2.4.1"
@@ -20165,14 +20090,7 @@ __metadata:
languageName: node
linkType: hard
-"preact@npm:^10.10.0":
- version: 10.16.0
- resolution: "preact@npm:10.16.0"
- checksum: 47a91f47d583b68a4afe971a7f992c06547df6d637cadf56eb3b69fee1fb202659b199af37d0e1a90637385144cadd75aa40acdb4e125cc4b3155e2883c24c07
- languageName: node
- linkType: hard
-
-"preact@npm:^10.13.2":
+"preact@npm:^10.10.0, preact@npm:^10.13.2":
version: 10.17.0
resolution: "preact@npm:10.17.0"
checksum: a106a5dd4e4e38a24f4ab62a42b4e0d9b14f0a0146819f1f2800b7033b316941987f77913893b78fe4ceb6750ec013f407ad98e2f416978fe8aecc8d7f4d086b
@@ -21909,20 +21827,13 @@ __metadata:
languageName: node
linkType: hard
-"regenerator-runtime@npm:^0.13.11":
+"regenerator-runtime@npm:^0.13.11, regenerator-runtime@npm:^0.13.3":
version: 0.13.11
resolution: "regenerator-runtime@npm:0.13.11"
checksum: 27481628d22a1c4e3ff551096a683b424242a216fee44685467307f14d58020af1e19660bf2e26064de946bad7eff28950eae9f8209d55723e2d9351e632bbb4
languageName: node
linkType: hard
-"regenerator-runtime@npm:^0.13.3, regenerator-runtime@npm:^0.13.4":
- version: 0.13.9
- resolution: "regenerator-runtime@npm:0.13.9"
- checksum: 65ed455fe5afd799e2897baf691ca21c2772e1a969d19bb0c4695757c2d96249eb74ee3553ea34a91062b2a676beedf630b4c1551cc6299afb937be1426ec55e
- languageName: node
- linkType: hard
-
"regex-not@npm:^1.0.0, regex-not@npm:^1.0.2":
version: 1.0.2
resolution: "regex-not@npm:1.0.2"
From 64753e3738cf19033fda6dd5c651473717950807 Mon Sep 17 00:00:00 2001
From: Marcel Gerber
Date: Mon, 25 Sep 2023 09:29:17 +0200
Subject: [PATCH 134/134] chore(algolia): disable typo tolerance for explorers
only on `text` attr
---
baker/algolia/configureAlgolia.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/baker/algolia/configureAlgolia.ts b/baker/algolia/configureAlgolia.ts
index f8b5b650e4d..068a7d6f546 100644
--- a/baker/algolia/configureAlgolia.ts
+++ b/baker/algolia/configureAlgolia.ts
@@ -123,7 +123,7 @@ export const configureAlgolia = async () => {
customRanking: ["desc(views_7d)"],
attributeForDistinct: "slug",
attributesForFaceting: [],
- typoTolerance: false,
+ disableTypoToleranceOnAttributes: ["text"],
})
const synonyms = [
{more.heading}
- {more.articles.map((link, i) => ( -{row.heading}
+{row.heading}
{more.heading}
+{row.heading}
@@ -117,20 +123,22 @@ export function ResearchAndWriting(props: ResearchAndWritingProps) {{more.heading}
-{more.heading}
+{row.heading}
From 30015a51f5bfaa1ab23ada6adced1b75e7f9b464 Mon Sep 17 00:00:00 2001 From: Ike Saunders
-
) : null}
{citationFull.length > 1 ? (
@@ -164,10 +169,15 @@ export class SourcesTab extends React.Component<{
Data published by
- {citationFull[0]}
+
+
{citationFull.map(
(
- producer: string,
+ citation: string,
index: number
) => (
-
From 57822c6de912507a9451f14d65d32b42b5b8e293 Mon Sep 17 00:00:00 2001
From: Daniel Bachler