diff --git a/sanityv3/schemas/objects/fullWidthImage.tsx b/sanityv3/schemas/objects/fullWidthImage.tsx
index 5f5c06fe2..4deb362e2 100644
--- a/sanityv3/schemas/objects/fullWidthImage.tsx
+++ b/sanityv3/schemas/objects/fullWidthImage.tsx
@@ -17,6 +17,20 @@ export default {
type: 'imageWithAltAndCaption',
validation: (Rule: Rule) => Rule.required(),
},
+ {
+ name: 'aspectRatio',
+ type: 'number',
+ title: 'Aspect ratio',
+ options: {
+ list: [
+ { title: '10:3', value: 0.3 },
+ { title: '2:1', value: 0.5 },
+ ],
+ layout: 'dropdown',
+ },
+ initialValue: 0.3,
+ validation: (Rule: Rule) => Rule.required(),
+ },
],
preview: {
select: {
diff --git a/sanityv3/scripts/README.md b/sanityv3/scripts/README.md
new file mode 100644
index 000000000..921e27ecb
--- /dev/null
+++ b/sanityv3/scripts/README.md
@@ -0,0 +1,6 @@
+# Description
+
+This folder contains scripts used to migrate content.
+
+- Change the target scripts array with the desired migration scripts.
+- `npx sanity exec 'automateScripts.mjs'` to run the migration scripts.
diff --git a/sanityv3/scripts/aspectRatioDefaults.mjs b/sanityv3/scripts/aspectRatioDefaults.mjs
new file mode 100644
index 000000000..35f338ac5
--- /dev/null
+++ b/sanityv3/scripts/aspectRatioDefaults.mjs
@@ -0,0 +1,55 @@
+/* eslint-disable no-console */
+import { sanityClients } from './getSanityClients.mjs'
+
+// Replace figure with fullWidthImage and set aspectRatio to 0.3
+const fetchDocuments = (client) =>
+ client.fetch(
+ /* groq */ `*[_type in ['page','magazine'] && length(content[_type == 'figure' && aspectRatio == null])>0][0..100]{ _id,"images":content[_type == 'figure'&& aspectRatio == null]} `,
+ )
+
+const buildPatches = (docs) =>
+ docs
+ .map((doc) =>
+ doc.images.map((image) => ({
+ id: doc._id,
+ patch: {
+ set: {
+ [`content[_key =="${image._key}"].aspectRatio`]: 'original',
+ },
+ // this will cause the migration to fail if any of the documents has been
+ // modified since it was fetched.
+ ifRevisionID: doc._rev,
+ },
+ })),
+ )
+ .flat()
+
+const createTransaction = (patches, client) =>
+ patches.reduce((tx, patch) => tx.patch(patch.id, patch.patch), client.transaction())
+
+const commitTransaction = (tx) => tx.commit()
+
+const migrateNextBatch = async (client) => {
+ const documents = await fetchDocuments(client)
+ const patches = buildPatches(documents, client)
+ if (patches.length === 0) {
+ console.log('No more documents to migrate!')
+ return null
+ }
+ console.log(
+ `Migrating batch:\n %s`,
+ patches.map((patch) => `${patch.id} => ${JSON.stringify(patch.patch)}`).join('\n'),
+ )
+ const transaction = createTransaction(patches, client)
+ await commitTransaction(transaction)
+ return migrateNextBatch(client)
+}
+
+export default function script() {
+ sanityClients.map((client) =>
+ migrateNextBatch(client).catch((err) => {
+ console.error(err)
+ process.exit(1)
+ }),
+ )
+}
diff --git a/sanityv3/scripts/automateScripts.mjs b/sanityv3/scripts/automateScripts.mjs
new file mode 100644
index 000000000..f2a581577
--- /dev/null
+++ b/sanityv3/scripts/automateScripts.mjs
@@ -0,0 +1,7 @@
+const targetScripts = ['aspectRatioDefaults.mjs']
+
+targetScripts.map(async (script) => {
+ const migrationScript = await import(`./${script}`)
+ const runScript = migrationScript.default
+ runScript()
+})
diff --git a/sanityv3/scripts/convertToPortableText.mjs b/sanityv3/scripts/convertToPortableText.mjs
new file mode 100644
index 000000000..e01a87f46
--- /dev/null
+++ b/sanityv3/scripts/convertToPortableText.mjs
@@ -0,0 +1,73 @@
+/* eslint-disable no-console */
+
+import { customAlphabet } from 'nanoid'
+import { sanityClients } from './getSanityClients.mjs'
+
+const nanoid = customAlphabet('1234567890abcdef', 12)
+
+const fetchDocuments = (client) =>
+ client.fetch(
+ /* groq */ `*[_type in ['page','magazine'] && length(content[_type == "promoTileArray"].group[count(title)==null])>0][0..100] {_id, _rev, "promotileArray":content[_type == "promoTileArray"].group[count(title)==null] }`,
+ )
+
+const buildPatches = (docs) =>
+ docs
+ .map((doc) =>
+ doc.promotileArray.map((promoTile) => ({
+ id: doc._id,
+ patch: {
+ set: {
+ [`content..[_key =="${promoTile._key}"].title`]: [
+ {
+ style: 'normal',
+ _type: 'block',
+ _key: nanoid(),
+ children: [
+ {
+ _type: 'span',
+ marks: [],
+ _key: nanoid(),
+ text: `${promoTile.title}`,
+ },
+ ],
+ markDefs: [],
+ },
+ ],
+ },
+ // this will cause the migration to fail if any of the documents has been
+ // modified since it was fetched.
+ ifRevisionID: doc._rev,
+ },
+ })),
+ )
+ .flat()
+
+const createTransaction = (patches, client) =>
+ patches.reduce((tx, patch) => tx.patch(patch.id, patch.patch), client.transaction())
+
+const commitTransaction = (tx) => tx.commit()
+
+const migrateNextBatch = async (client) => {
+ const documents = await fetchDocuments(client)
+ const patches = buildPatches(documents, client)
+ if (patches.length === 0) {
+ console.log('No more documents to migrate!')
+ return null
+ }
+ console.log(
+ `Migrating batch:\n %s`,
+ patches.map((patch) => `${patch.id} => ${JSON.stringify(patch.patch)}`).join('\n'),
+ )
+ const transaction = createTransaction(patches, client)
+ await commitTransaction(transaction)
+ return migrateNextBatch(client)
+}
+
+export default function script() {
+ sanityClients.map((client) =>
+ migrateNextBatch(client).catch((err) => {
+ console.error(err)
+ process.exit(1)
+ }),
+ )
+}
diff --git a/sanityv3/scripts/getSanityClients.mjs b/sanityv3/scripts/getSanityClients.mjs
new file mode 100644
index 000000000..2135fdb3c
--- /dev/null
+++ b/sanityv3/scripts/getSanityClients.mjs
@@ -0,0 +1,12 @@
+//eslint-disable-next-line
+import { createClient } from '@sanity/client'
+
+const datasets = ['global-development']
+export const sanityClients = datasets.map((dataset) => {
+ return createClient({
+ apiVersion: '2023-08-29',
+ projectId: process.env.SANITY_STUDIO_API_PROJECT_ID || 'h61q9gi9',
+ token: process.env.SANITY_STUDIO_MUTATION_TOKEN,
+ dataset: dataset,
+ })
+})
diff --git a/sanityv3/scripts/migrateFullWidthImage.mjs b/sanityv3/scripts/migrateFullWidthImage.mjs
new file mode 100644
index 000000000..0e4982824
--- /dev/null
+++ b/sanityv3/scripts/migrateFullWidthImage.mjs
@@ -0,0 +1,60 @@
+/**
+ * This script replaces FullWidthImage from imageWithAlt to imageWithAltAndCaption
+ */
+/* eslint-disable no-console */
+import { sanityClients } from './getSanityClients'
+
+const fetchDocuments = (client) =>
+ client.fetch(
+ /* groq */ `*[_type in ['page','magazine'] && count(content[_type=="fullWidthImage" && image._type == "imageWithAlt"])>0][0..100]{_id,"images":content[_type=="fullWidthImage" && image._type == "imageWithAlt"]}`,
+ )
+
+const buildPatches = (docs) =>
+ docs
+ .map((doc) =>
+ doc.images.map((image) => ({
+ id: doc._id,
+ patch: {
+ set: {
+ [`content[_key =="${image._key}"].image`]: {
+ _type: 'imageWithAltAndCaption',
+ image: image.image,
+ },
+ },
+ // this will cause the migration to fail if any of the documents has been
+ // modified since it was fetched.
+ ifRevisionID: doc._rev,
+ },
+ })),
+ )
+ .flat()
+
+const createTransaction = (patches, client) =>
+ patches.reduce((tx, patch) => tx.patch(patch.id, patch.patch), client.transaction())
+
+const commitTransaction = (tx) => tx.commit()
+
+const migrateNextBatch = async (client) => {
+ const documents = await fetchDocuments(client)
+ const patches = buildPatches(documents, client)
+ if (patches.length === 0) {
+ console.log('No more documents to migrate!')
+ return null
+ }
+ console.log(
+ `Migrating batch:\n %s`,
+ patches.map((patch) => `${patch.id} => ${JSON.stringify(patch.patch)}`).join('\n'),
+ )
+ const transaction = createTransaction(patches, client)
+ await commitTransaction(transaction)
+ return migrateNextBatch(client)
+}
+
+export default function script() {
+ sanityClients.map((client) =>
+ migrateNextBatch(client).catch((err) => {
+ console.error(err)
+ process.exit(1)
+ }),
+ )
+}
diff --git a/web/lib/queries/common/pageContentFields.ts b/web/lib/queries/common/pageContentFields.ts
index 3893d7fe2..2c0692188 100644
--- a/web/lib/queries/common/pageContentFields.ts
+++ b/web/lib/queries/common/pageContentFields.ts
@@ -65,7 +65,10 @@ const pageContentFields = /* groq */ `
_type == "fullWidthImage"=>{
"type": _type,
"id": _key,
- image
+ image,
+ "designOptions": {
+ "aspectRatio": coalesce(aspectRatio, '10:3'),
+ },
},
_type == "fullWidthVideo"=>{
"type": _type,
diff --git a/web/pageComponents/topicPages/FullWidthImage.tsx b/web/pageComponents/topicPages/FullWidthImage.tsx
index 171d23145..8cd90f075 100644
--- a/web/pageComponents/topicPages/FullWidthImage.tsx
+++ b/web/pageComponents/topicPages/FullWidthImage.tsx
@@ -1,6 +1,7 @@
import type { FullWidthImageData } from '../../types/types'
import Image, { Ratios } from '../shared/SanityImage'
import { StyledCaption } from '../shared/image/StyledCaption'
+import useWindowSize from '../../lib/hooks/useWindowSize'
type TeaserProps = {
data: FullWidthImageData
@@ -9,17 +10,15 @@ type TeaserProps = {
const FullWidthImage = ({ data, anchor }: TeaserProps) => {
const { image, attribution, caption } = data.image
+ const { aspectRatio } = data.designOptions
+ const { width } = useWindowSize()
+
+ const ratio = (width && width < 750) || aspectRatio === Ratios.ONE_TO_TWO ? Ratios.ONE_TO_TWO : Ratios.THREE_TO_TEN
+
if (!image) return null
return (
<>
-
+
{image.asset && }
>
)
diff --git a/web/types/types.ts b/web/types/types.ts
index 23ef801ee..005416e9f 100644
--- a/web/types/types.ts
+++ b/web/types/types.ts
@@ -321,6 +321,9 @@ export type FullWidthImageData = {
type: string
id: string
image: ImageWithCaptionData
+ designOptions: {
+ aspectRatio: number
+ }
}
export type FullWidthVideoData = {
@@ -701,7 +704,6 @@ export type VideoPlayerCarouselData = {
title?: PortableTextBlock[]
}
-
export type LoopingVideoRatio = '1:2' | 'narrow'
export type LoopingVideoData = {