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.alt} + {image.alt} {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 = {