From e11d71a45043b0aa54a25ad9b00a8d3646da6b9e Mon Sep 17 00:00:00 2001 From: alexandre Date: Mon, 19 Feb 2024 17:17:28 +0100 Subject: [PATCH 01/28] Make edge function work --- netlify/edge-functions/og-image.tsx | 292 ++++++++++++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100644 netlify/edge-functions/og-image.tsx diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx new file mode 100644 index 00000000000000..64dc1b2a3605d5 --- /dev/null +++ b/netlify/edge-functions/og-image.tsx @@ -0,0 +1,292 @@ +import React from 'https://esm.sh/react@18.2.0'; + +import type { ReactElement } from 'https://esm.sh/react@18.2.0'; + +import type { SatoriOptions } from 'https://esm.sh/satori@0.10.13'; + +import satori, { init as initSatori } from 'https://esm.sh/satori@0.10.13/wasm'; +import { initStreaming } from 'https://esm.sh/yoga-wasm-web@0.3.0'; + +import { initWasm, Resvg } from 'https://esm.sh/@resvg/resvg-wasm@2.0.0-alpha.4'; + +const resvg_wasm = fetch( + 'https://cdn.jsdelivr.net/npm/@vercel/og@0.1.0/vendor/resvg.simd.wasm', +).then((res) => res.arrayBuffer()); + +const yoga_wasm = fetch('https://cdn.jsdelivr.net/npm/@vercel/og@0.1.0/vendor/yoga.wasm'); + +const fallbackFont = fetch( + 'https://cdn.jsdelivr.net/npm/@vercel/og@0.1.0/vendor/noto-sans-v27-latin-regular.ttf', +).then((a) => a.arrayBuffer()); + +const apis = { + twemoji: (code: string) => + `https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/${code.toLowerCase()}.svg`, + openmoji: 'https://cdn.jsdelivr.net/npm/@svgmoji/openmoji@2.0.0/svg/', + blobmoji: 'https://cdn.jsdelivr.net/npm/@svgmoji/blob@2.0.0/svg/', + noto: 'https://cdn.jsdelivr.net/gh/svgmoji/svgmoji/packages/svgmoji__noto/svg/', + fluent: (code: string) => + `https://cdn.jsdelivr.net/gh/shuding/fluentui-emoji-unicode/assets/${code.toLowerCase()}_color.svg`, + fluentFlat: (code: string) => + `https://cdn.jsdelivr.net/gh/shuding/fluentui-emoji-unicode/assets/${code.toLowerCase()}_flat.svg`, +}; + +export type EmojiType = keyof typeof apis; + +const n = String.fromCharCode(8205); +const O = /\uFE0F/g; + +export function loadEmoji(code: string, type?: EmojiType): Promise { + (!type || !apis[type]) && (type = 'twemoji'); + const A = apis[type]; + return fetch(typeof A === 'function' ? A(code) : `${A}${code.toUpperCase()}.svg`); +} + +export function getIconCode(char: string): string { + return d(char.indexOf(n) < 0 ? char.replace(O, '') : char); +} + +function d(j: string) { + const t = []; + let A = 0; + let k = 0; + for (let E = 0; E < j.length; ) { + (A = j.charCodeAt(E++)), + k + ? (t.push((65536 + ((k - 55296) << 10) + (A - 56320)).toString(16)), (k = 0)) + : A >= 55296 && A <= 56319 + ? (k = A) + : t.push(A.toString(16)); + } + return t.join('-'); +} + +const initializedResvg = initWasm(resvg_wasm); +const initializedYoga = initStreaming(yoga_wasm).then((yoga: unknown) => initSatori(yoga)); + +type ImageResponseOptions = ConstructorParameters[1] & { + /** + * The width of the image. + * + * @type {number} + * @default 1200 + */ + width?: number; + /** + * The height of the image. + * + * @type {number} + * @default 630 + */ + height?: number; + /** + * Display debug information on the image. + * + * @type {boolean} + * @default false + */ + debug?: boolean; + /** + * A list of fonts to use. + * + * @type {{ data: ArrayBuffer; name: string; weight?: 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900; style?: 'normal' | 'italic' }[]} + * @default Noto Sans Latin Regular. + */ + fonts?: SatoriOptions['fonts']; + /** + * Using a specific Emoji style. Defaults to `twemoji`. + * + * @link https://github.com/vercel/og#emoji + * @type {EmojiType} + * @default 'twemoji' + */ + emoji?: EmojiType; +}; + +// @TODO: Support font style and weights, and make this option extensible rather +// than built-in. +// @TODO: Cover most languages with Noto Sans. +const languageFontMap = { + 'ja-JP': 'Noto+Sans+JP', + 'ko-KR': 'Noto+Sans+KR', + 'zh-CN': 'Noto+Sans+SC', + 'zh-TW': 'Noto+Sans+TC', + 'zh-HK': 'Noto+Sans+HK', + 'th-TH': 'Noto+Sans+Thai', + 'bn-IN': 'Noto+Sans+Bengali', + 'ar-AR': 'Noto+Sans+Arabic', + 'ta-IN': 'Noto+Sans+Tamil', + 'ml-IN': 'Noto+Sans+Malayalam', + 'he-IL': 'Noto+Sans+Hebrew', + 'te-IN': 'Noto+Sans+Telugu', + devanagari: 'Noto+Sans+Devanagari', + kannada: 'Noto+Sans+Kannada', + symbol: ['Noto+Sans+Symbols', 'Noto+Sans+Symbols+2'], + math: 'Noto+Sans+Math', + unknown: 'Noto+Sans', +}; + +async function loadGoogleFont(fonts: string | string[], text: string) { + // @TODO: Support multiple fonts. + const font = Array.isArray(fonts) ? fonts.at(-1) : fonts; + if (!font || !text) { + return; + } + + const API = `https://fonts.googleapis.com/css2?family=${font}&text=${encodeURIComponent(text)}`; + + const css = await ( + await fetch(API, { + headers: { + // Make sure it returns TTF. + 'User-Agent': + 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1', + }, + }) + ).text(); + + const resource = css.match(/src: url\((.+)\) format\('(opentype|truetype)'\)/); + if (!resource) { + throw new Error('Failed to load font'); + } + + // eslint-disable-next-line consistent-return + return fetch(resource[1]).then((res) => res.arrayBuffer()); +} + +type Asset = SatoriOptions['fonts'][0] | string; + +const assetCache = new Map(); +const loadDynamicAsset = ({ emoji }: { emoji?: EmojiType }) => { + const fn = async ( + code: keyof typeof languageFontMap | 'emoji', + text: string, + ): Promise => { + if (code === 'emoji') { + // It's an emoji, load the image. + return `data:image/svg+xml;base64,${btoa( + await (await loadEmoji(getIconCode(text), emoji)).text(), + )}`; + } + // Try to load from Google Fonts. + if (!languageFontMap[code]) { + code = 'unknown'; + } + + try { + const data = await loadGoogleFont(languageFontMap[code], text); + + if (data) { + return { + name: `satori_${code}_fallback_${text}`, + data, + weight: 400, + style: 'normal', + }; + } + } catch (e) { + console.error('Failed to load dynamic font for', text, '. Error:', e); + } + }; + + return async (...args: Parameters) => { + const key = JSON.stringify(args); + const cache = assetCache.get(key); + if (cache) { + return cache; + } + + const asset = await fn(...args); + assetCache.set(key, asset); + return asset; + }; +}; + +class ImageResponse extends Response { + constructor(element: ReactElement, options: ImageResponseOptions = {}) { + const extendedOptions = { + width: 1200, + height: 630, + debug: false, + ...options, + }; + + const result = new ReadableStream({ + async start(controller) { + await initializedYoga; + await initializedResvg; + const fontData = await fallbackFont; + + const svg = await satori(element, { + width: extendedOptions.width, + height: extendedOptions.height, + debug: extendedOptions.debug, + fonts: extendedOptions.fonts || [ + { + name: 'sans serif', + data: fontData, + weight: 700, + style: 'normal', + }, + ], + loadAdditionalAsset: loadDynamicAsset({ + emoji: 'twemoji', + }), + }); + + const resvgJS = new Resvg(svg, { + fitTo: { + mode: 'width', + value: extendedOptions.width, + }, + }); + + controller.enqueue(resvgJS.render()); + controller.close(); + }, + }); + + super(result, { + headers: { + 'content-type': 'image/png', + 'cache-control': 'no-cache, no-store', + ...extendedOptions.headers, + }, + status: extendedOptions.status, + statusText: extendedOptions.statusText, + }); + } +} + +export default async function handler(req: Request) { + const params = new URL(req.url).searchParams; + + try { + return new ImageResponse( + ( +
+ {params.get('title')} +
+ ), + { + width: 1200, + height: 630, + }, + ); + // eslint-disable-next-line no-empty + } catch {} + return null; +} +export const config = { path: '/api/og-image' }; From 7012f884a95cbe5418d63c2be0cfea8b234f0bd9 Mon Sep 17 00:00:00 2001 From: alexandre Date: Fri, 23 Feb 2024 16:53:35 +0100 Subject: [PATCH 02/28] blog template --- netlify/edge-functions/og-image.tsx | 329 +++++++++++++++++++++++----- 1 file changed, 279 insertions(+), 50 deletions(-) diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx index 64dc1b2a3605d5..f67b3c4c5c5e04 100644 --- a/netlify/edge-functions/og-image.tsx +++ b/netlify/edge-functions/og-image.tsx @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ import React from 'https://esm.sh/react@18.2.0'; import type { ReactElement } from 'https://esm.sh/react@18.2.0'; @@ -128,7 +129,7 @@ const languageFontMap = { async function loadGoogleFont(fonts: string | string[], text: string) { // @TODO: Support multiple fonts. - const font = Array.isArray(fonts) ? fonts.at(-1) : fonts; + const font = Array.isArray(fonts) ? fonts[fonts.length - 1] : fonts; if (!font || !text) { return; } @@ -216,33 +217,37 @@ class ImageResponse extends Response { await initializedYoga; await initializedResvg; const fontData = await fallbackFont; - - const svg = await satori(element, { - width: extendedOptions.width, - height: extendedOptions.height, - debug: extendedOptions.debug, - fonts: extendedOptions.fonts || [ - { - name: 'sans serif', - data: fontData, - weight: 700, - style: 'normal', + try { + const svg = await satori(element, { + width: extendedOptions.width, + height: extendedOptions.height, + debug: extendedOptions.debug, + fonts: extendedOptions.fonts || [ + { + name: 'sans serif', + data: fontData, + weight: 700, + style: 'normal', + }, + ], + loadAdditionalAsset: loadDynamicAsset({ + emoji: 'twemoji', + }), + }); + + const resvgJS = new Resvg(svg, { + fitTo: { + mode: 'width', + value: extendedOptions.width, }, - ], - loadAdditionalAsset: loadDynamicAsset({ - emoji: 'twemoji', - }), - }); - - const resvgJS = new Resvg(svg, { - fitTo: { - mode: 'width', - value: extendedOptions.width, - }, - }); - - controller.enqueue(resvgJS.render()); - controller.close(); + }); + + controller.enqueue(resvgJS.render()); + controller.close(); + } catch (error) { + console.log('satori error'); + console.log(error); + } }, }); @@ -258,35 +263,259 @@ class ImageResponse extends Response { } } +/** + * The matching from github user to their full name + */ +const fullName = { + mikailaread: 'Mikaila Read', + joserodolfofreitas: 'José Freitas', + samuelsycamore: 'Sam Sycamore', + flaviendelangle: 'Flavien Delangle', + richbustos: 'Rich Bustos', + prakhargupta1: 'Prakhar Gupta', + alexfauquette: 'Alexandre Fauquette', + siriwatknp: 'Siriwat Kunaporn', + cherniavskii: 'Andrew Cherniavskyi', + 'danilo-leal': 'Danilo Leal', + mnajdova: 'Marija Najdova', + oliviertassinari: 'Olivier Tassinari', + m4theushw: 'Matheus Wichman', + DanailH: 'Danail Hadjiatanasov', + mbrookes: 'Matt Brookes', + eps1lon: 'Sebastian Silbermann', + michaldudak: 'Michał Dudak', + colmtuite: 'Colm Tuite', +}; + export default async function handler(req: Request) { const params = new URL(req.url).searchParams; - - try { - return new ImageResponse( - ( + const title = params.get('title'); + const authors = params.get('authors'); + + let starCount = 0; + const R = new ImageResponse( + ( +
+
- {params.get('title')} + + + +
+

+ BLOG +

- ), - { - width: 1200, - height: 630, - }, - ); - // eslint-disable-next-line no-empty - } catch {} - return null; +
+ {title && + title.split('\\n').map((line) => ( +

+ {line.split('*').flatMap((text, index) => { + if (index > 0) { + starCount += 1; + } + + const isBlue = starCount % 2 === 1; + return text.split(' ').map((word) => ( + 0 ? 15 : 0, + }} + > + {word} + + )); + })} +

+ ))} +
+ +
+ {authors && + authors.split(',').map((author) => { + const githubUser = author.trim(); + return ( +
+
+ +
+
+ + {fullName[githubUser]} + + + @{githubUser} + +
+
+ ); + })} +
+
+ ), + { + width: 1280, + height: 640, + fonts: [ + { + name: 'General Sans', + data: await fetch('https://fonts.cdnfonts.com/s/85793/GeneralSans-Medium.woff').then( + (a) => a.arrayBuffer(), + ), + weight: 1000, + style: 'normal', + }, + { + name: 'General Sans', + data: await fetch('https://fonts.cdnfonts.com/s/85793/GeneralSans-Semibold.woff').then( + (a) => a.arrayBuffer(), + ), + weight: 600, + style: 'normal', + }, + { + name: 'General Sans', + data: await fetch('https://fonts.cdnfonts.com/s/85793/GeneralSans-Bold.woff').then((a) => + a.arrayBuffer(), + ), + weight: 700, + style: 'normal', + }, + ], + }, + ); + + return R; } -export const config = { path: '/api/og-image' }; +export const config = { path: '/' }; From e2785b6da2fe38a1d2636473e9a85e9ae5f2c5e4 Mon Sep 17 00:00:00 2001 From: alexandre Date: Fri, 23 Feb 2024 17:04:16 +0100 Subject: [PATCH 03/28] git api url --- netlify/edge-functions/og-image.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx index f67b3c4c5c5e04..9e8f5f2511d663 100644 --- a/netlify/edge-functions/og-image.tsx +++ b/netlify/edge-functions/og-image.tsx @@ -518,4 +518,4 @@ export default async function handler(req: Request) { return R; } -export const config = { path: '/' }; +export const config = { path: '/api/og-image' }; From c437d42bfd4cb078aceb6c215b3f6202cbc7d196 Mon Sep 17 00:00:00 2001 From: alexandre Date: Tue, 27 Feb 2024 12:57:22 +0100 Subject: [PATCH 04/28] test --- .../experiments/blog/blog-custom-card.js | 7 + .../experiments/blog/blog-custom-card.md | 30 ++ docs/src/modules/components/TopLayoutBlog.js | 2 +- netlify/edge-functions/og-image.tsx | 372 +++--------------- 4 files changed, 95 insertions(+), 316 deletions(-) create mode 100644 docs/pages/experiments/blog/blog-custom-card.js create mode 100644 docs/pages/experiments/blog/blog-custom-card.md diff --git a/docs/pages/experiments/blog/blog-custom-card.js b/docs/pages/experiments/blog/blog-custom-card.js new file mode 100644 index 00000000000000..661ce999fcca2a --- /dev/null +++ b/docs/pages/experiments/blog/blog-custom-card.js @@ -0,0 +1,7 @@ +import * as React from 'react'; +import TopLayoutBlog from 'docs/src/modules/components/TopLayoutBlog'; +import { docs } from './blog-custom-card.md?@mui/markdown'; + +export default function Page() { + return ; +} diff --git a/docs/pages/experiments/blog/blog-custom-card.md b/docs/pages/experiments/blog/blog-custom-card.md new file mode 100644 index 00000000000000..9cfadc7361b997 --- /dev/null +++ b/docs/pages/experiments/blog/blog-custom-card.md @@ -0,0 +1,30 @@ +--- +title: Blog post title +description: Our internationally distributed startup gathered on a remote island to get to know each other better. Here's what happened! +date: 2022-07-28T00:00:00.000Z +authors: ['alexfauquette'] +tags: ['Company'] +card: false +cardTitle: blog with\n*custom* card +--- + +## Description + +### Image + +Satellite image of Tenerife + +

An image description with a link.

+ +More text below. + +### Code + +```jsx +// add margin: 8px 0px; + +``` + +

CodeSandbox

+ +More text below. diff --git a/docs/src/modules/components/TopLayoutBlog.js b/docs/src/modules/components/TopLayoutBlog.js index 6967b303d03692..c8b6e3fa76148a 100644 --- a/docs/src/modules/components/TopLayoutBlog.js +++ b/docs/src/modules/components/TopLayoutBlog.js @@ -267,7 +267,7 @@ export default function TopLayoutBlog(props) { const card = headers.card === 'true' ? `https://mui.com/static/blog/${slug}/card.png` - : 'https://mui.com/static/logo.png'; + : `/api/og-image/?title=${headers.cardTitle || finalTitle}&authors=${headers.authors.join(',')}`; if (process.env.NODE_ENV !== 'production') { if (headers.card === undefined) { diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx index 9e8f5f2511d663..e184871d423fc2 100644 --- a/netlify/edge-functions/og-image.tsx +++ b/netlify/edge-functions/og-image.tsx @@ -1,272 +1,10 @@ /* eslint-disable no-console */ import React from 'https://esm.sh/react@18.2.0'; - -import type { ReactElement } from 'https://esm.sh/react@18.2.0'; - -import type { SatoriOptions } from 'https://esm.sh/satori@0.10.13'; - -import satori, { init as initSatori } from 'https://esm.sh/satori@0.10.13/wasm'; -import { initStreaming } from 'https://esm.sh/yoga-wasm-web@0.3.0'; - -import { initWasm, Resvg } from 'https://esm.sh/@resvg/resvg-wasm@2.0.0-alpha.4'; - -const resvg_wasm = fetch( - 'https://cdn.jsdelivr.net/npm/@vercel/og@0.1.0/vendor/resvg.simd.wasm', -).then((res) => res.arrayBuffer()); - -const yoga_wasm = fetch('https://cdn.jsdelivr.net/npm/@vercel/og@0.1.0/vendor/yoga.wasm'); - -const fallbackFont = fetch( - 'https://cdn.jsdelivr.net/npm/@vercel/og@0.1.0/vendor/noto-sans-v27-latin-regular.ttf', -).then((a) => a.arrayBuffer()); - -const apis = { - twemoji: (code: string) => - `https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/${code.toLowerCase()}.svg`, - openmoji: 'https://cdn.jsdelivr.net/npm/@svgmoji/openmoji@2.0.0/svg/', - blobmoji: 'https://cdn.jsdelivr.net/npm/@svgmoji/blob@2.0.0/svg/', - noto: 'https://cdn.jsdelivr.net/gh/svgmoji/svgmoji/packages/svgmoji__noto/svg/', - fluent: (code: string) => - `https://cdn.jsdelivr.net/gh/shuding/fluentui-emoji-unicode/assets/${code.toLowerCase()}_color.svg`, - fluentFlat: (code: string) => - `https://cdn.jsdelivr.net/gh/shuding/fluentui-emoji-unicode/assets/${code.toLowerCase()}_flat.svg`, -}; - -export type EmojiType = keyof typeof apis; - -const n = String.fromCharCode(8205); -const O = /\uFE0F/g; - -export function loadEmoji(code: string, type?: EmojiType): Promise { - (!type || !apis[type]) && (type = 'twemoji'); - const A = apis[type]; - return fetch(typeof A === 'function' ? A(code) : `${A}${code.toUpperCase()}.svg`); -} - -export function getIconCode(char: string): string { - return d(char.indexOf(n) < 0 ? char.replace(O, '') : char); -} - -function d(j: string) { - const t = []; - let A = 0; - let k = 0; - for (let E = 0; E < j.length; ) { - (A = j.charCodeAt(E++)), - k - ? (t.push((65536 + ((k - 55296) << 10) + (A - 56320)).toString(16)), (k = 0)) - : A >= 55296 && A <= 56319 - ? (k = A) - : t.push(A.toString(16)); - } - return t.join('-'); -} - -const initializedResvg = initWasm(resvg_wasm); -const initializedYoga = initStreaming(yoga_wasm).then((yoga: unknown) => initSatori(yoga)); - -type ImageResponseOptions = ConstructorParameters[1] & { - /** - * The width of the image. - * - * @type {number} - * @default 1200 - */ - width?: number; - /** - * The height of the image. - * - * @type {number} - * @default 630 - */ - height?: number; - /** - * Display debug information on the image. - * - * @type {boolean} - * @default false - */ - debug?: boolean; - /** - * A list of fonts to use. - * - * @type {{ data: ArrayBuffer; name: string; weight?: 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900; style?: 'normal' | 'italic' }[]} - * @default Noto Sans Latin Regular. - */ - fonts?: SatoriOptions['fonts']; - /** - * Using a specific Emoji style. Defaults to `twemoji`. - * - * @link https://github.com/vercel/og#emoji - * @type {EmojiType} - * @default 'twemoji' - */ - emoji?: EmojiType; -}; - -// @TODO: Support font style and weights, and make this option extensible rather -// than built-in. -// @TODO: Cover most languages with Noto Sans. -const languageFontMap = { - 'ja-JP': 'Noto+Sans+JP', - 'ko-KR': 'Noto+Sans+KR', - 'zh-CN': 'Noto+Sans+SC', - 'zh-TW': 'Noto+Sans+TC', - 'zh-HK': 'Noto+Sans+HK', - 'th-TH': 'Noto+Sans+Thai', - 'bn-IN': 'Noto+Sans+Bengali', - 'ar-AR': 'Noto+Sans+Arabic', - 'ta-IN': 'Noto+Sans+Tamil', - 'ml-IN': 'Noto+Sans+Malayalam', - 'he-IL': 'Noto+Sans+Hebrew', - 'te-IN': 'Noto+Sans+Telugu', - devanagari: 'Noto+Sans+Devanagari', - kannada: 'Noto+Sans+Kannada', - symbol: ['Noto+Sans+Symbols', 'Noto+Sans+Symbols+2'], - math: 'Noto+Sans+Math', - unknown: 'Noto+Sans', -}; - -async function loadGoogleFont(fonts: string | string[], text: string) { - // @TODO: Support multiple fonts. - const font = Array.isArray(fonts) ? fonts[fonts.length - 1] : fonts; - if (!font || !text) { - return; - } - - const API = `https://fonts.googleapis.com/css2?family=${font}&text=${encodeURIComponent(text)}`; - - const css = await ( - await fetch(API, { - headers: { - // Make sure it returns TTF. - 'User-Agent': - 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1', - }, - }) - ).text(); - - const resource = css.match(/src: url\((.+)\) format\('(opentype|truetype)'\)/); - if (!resource) { - throw new Error('Failed to load font'); - } - - // eslint-disable-next-line consistent-return - return fetch(resource[1]).then((res) => res.arrayBuffer()); -} - -type Asset = SatoriOptions['fonts'][0] | string; - -const assetCache = new Map(); -const loadDynamicAsset = ({ emoji }: { emoji?: EmojiType }) => { - const fn = async ( - code: keyof typeof languageFontMap | 'emoji', - text: string, - ): Promise => { - if (code === 'emoji') { - // It's an emoji, load the image. - return `data:image/svg+xml;base64,${btoa( - await (await loadEmoji(getIconCode(text), emoji)).text(), - )}`; - } - // Try to load from Google Fonts. - if (!languageFontMap[code]) { - code = 'unknown'; - } - - try { - const data = await loadGoogleFont(languageFontMap[code], text); - - if (data) { - return { - name: `satori_${code}_fallback_${text}`, - data, - weight: 400, - style: 'normal', - }; - } - } catch (e) { - console.error('Failed to load dynamic font for', text, '. Error:', e); - } - }; - - return async (...args: Parameters) => { - const key = JSON.stringify(args); - const cache = assetCache.get(key); - if (cache) { - return cache; - } - - const asset = await fn(...args); - assetCache.set(key, asset); - return asset; - }; -}; - -class ImageResponse extends Response { - constructor(element: ReactElement, options: ImageResponseOptions = {}) { - const extendedOptions = { - width: 1200, - height: 630, - debug: false, - ...options, - }; - - const result = new ReadableStream({ - async start(controller) { - await initializedYoga; - await initializedResvg; - const fontData = await fallbackFont; - try { - const svg = await satori(element, { - width: extendedOptions.width, - height: extendedOptions.height, - debug: extendedOptions.debug, - fonts: extendedOptions.fonts || [ - { - name: 'sans serif', - data: fontData, - weight: 700, - style: 'normal', - }, - ], - loadAdditionalAsset: loadDynamicAsset({ - emoji: 'twemoji', - }), - }); - - const resvgJS = new Resvg(svg, { - fitTo: { - mode: 'width', - value: extendedOptions.width, - }, - }); - - controller.enqueue(resvgJS.render()); - controller.close(); - } catch (error) { - console.log('satori error'); - console.log(error); - } - }, - }); - - super(result, { - headers: { - 'content-type': 'image/png', - 'cache-control': 'no-cache, no-store', - ...extendedOptions.headers, - }, - status: extendedOptions.status, - statusText: extendedOptions.statusText, - }); - } -} - +import { ImageResponse } from 'https://deno.land/x/og_edge/mod.ts'; /** * The matching from github user to their full name */ -const fullName = { +const fullName: Record = { mikailaread: 'Mikaila Read', joserodolfofreitas: 'José Freitas', samuelsycamore: 'Sam Sycamore', @@ -418,69 +156,73 @@ export default async function handler(req: Request) { }} > {authors && - authors.split(',').map((author) => { - const githubUser = author.trim(); - return ( -
+ authors + .split(',') + .map((author) => author.trim()) + .filter((githubUser) => fullName[githubUser]) + .map((githubUser) => { + return (
- -
-
- - {fullName[githubUser]} - - +
+
- @{githubUser} - + + {fullName[githubUser]} + + + @{githubUser} + +
-
- ); - })} + ); + })}
), From 4f341fd91feb9ccd27f42d658ecee12595e9d8ce Mon Sep 17 00:00:00 2001 From: alexandre Date: Tue, 27 Feb 2024 13:12:30 +0100 Subject: [PATCH 05/28] fix --- docs/src/modules/components/TopLayoutBlog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/modules/components/TopLayoutBlog.js b/docs/src/modules/components/TopLayoutBlog.js index c8b6e3fa76148a..ddd36e099e4a1b 100644 --- a/docs/src/modules/components/TopLayoutBlog.js +++ b/docs/src/modules/components/TopLayoutBlog.js @@ -267,7 +267,7 @@ export default function TopLayoutBlog(props) { const card = headers.card === 'true' ? `https://mui.com/static/blog/${slug}/card.png` - : `/api/og-image/?title=${headers.cardTitle || finalTitle}&authors=${headers.authors.join(',')}`; + : `https://deploy-preview-41188--material-ui-apps.netlify.app/api/og-image/?title=${headers.cardTitle || finalTitle}&authors=${headers.authors.join(',')}`; if (process.env.NODE_ENV !== 'production') { if (headers.card === undefined) { From 017c3737e9bea74f93b83c5a4792e28445b7cac8 Mon Sep 17 00:00:00 2001 From: alexandre Date: Tue, 27 Feb 2024 14:23:03 +0100 Subject: [PATCH 06/28] update --- docs/src/modules/components/AppLayoutDocs.js | 6 +- docs/src/modules/components/Head.tsx | 1 + docs/src/modules/components/TopLayoutBlog.js | 2 +- netlify/edge-functions/docs-image.tsx | 134 +++++++++++++++++++ netlify/edge-functions/og-image.tsx | 7 +- 5 files changed, 144 insertions(+), 6 deletions(-) create mode 100644 netlify/edge-functions/docs-image.tsx diff --git a/docs/src/modules/components/AppLayoutDocs.js b/docs/src/modules/components/AppLayoutDocs.js index 3070ad0f1d3a56..b67a9dee1f5a98 100644 --- a/docs/src/modules/components/AppLayoutDocs.js +++ b/docs/src/modules/components/AppLayoutDocs.js @@ -120,16 +120,19 @@ export default function AppLayoutDocs(props) { const { canonicalAs } = pathnameToLanguage(router.asPath); let productName = 'MUI'; + let teamName = 'Core'; if (canonicalAs.startsWith('/material-ui/')) { productName = 'Material UI'; } else if (canonicalAs.startsWith('/base-ui/')) { productName = 'Base UI'; } else if (canonicalAs.startsWith('/x/')) { productName = 'MUI X'; + teamName = 'X'; } else if (canonicalAs.startsWith('/system/')) { productName = 'MUI System'; } else if (canonicalAs.startsWith('/toolpad/')) { productName = 'MUI Toolpad'; + teamName = 'Toolpad'; } else if (canonicalAs.startsWith('/joy-ui/')) { productName = 'Joy UI'; } @@ -137,6 +140,7 @@ export default function AppLayoutDocs(props) { const Layout = disableLayout ? React.Fragment : AppFrame; const layoutProps = disableLayout ? {} : { BannerComponent }; + const card = `https://deploy-preview-41188--material-ui-apps.netlify.app/og-docs?product=${teamName}&folder=${productName}&page=${title}`; return (
{/* diff --git a/docs/src/modules/components/Head.tsx b/docs/src/modules/components/Head.tsx index c203562c298e73..b74f41022e9755 100644 --- a/docs/src/modules/components/Head.tsx +++ b/docs/src/modules/components/Head.tsx @@ -4,6 +4,7 @@ import { useRouter } from 'next/router'; import { LANGUAGES_SSR } from 'docs/config'; import { useUserLanguage, useTranslate } from 'docs/src/modules/utils/i18n'; import { pathnameToLanguage } from 'docs/src/modules/utils/helpers'; +import getProductInfoFromUrl from '../utils/getProductInfoFromUrl'; // #major-version-switch const HOST = 'https://mui.com'; diff --git a/docs/src/modules/components/TopLayoutBlog.js b/docs/src/modules/components/TopLayoutBlog.js index ddd36e099e4a1b..2be170c5069470 100644 --- a/docs/src/modules/components/TopLayoutBlog.js +++ b/docs/src/modules/components/TopLayoutBlog.js @@ -267,7 +267,7 @@ export default function TopLayoutBlog(props) { const card = headers.card === 'true' ? `https://mui.com/static/blog/${slug}/card.png` - : `https://deploy-preview-41188--material-ui-apps.netlify.app/api/og-image/?title=${headers.cardTitle || finalTitle}&authors=${headers.authors.join(',')}`; + : `https://deploy-preview-41188--material-ui-apps.netlify.app/og-blog/?title=${headers.cardTitle || finalTitle}&authors=${headers.authors.join(',')}`; if (process.env.NODE_ENV !== 'production') { if (headers.card === undefined) { diff --git a/netlify/edge-functions/docs-image.tsx b/netlify/edge-functions/docs-image.tsx new file mode 100644 index 00000000000000..80d96259e0b828 --- /dev/null +++ b/netlify/edge-functions/docs-image.tsx @@ -0,0 +1,134 @@ +import React from 'https://esm.sh/react@18.2.0'; +import { ImageResponse } from 'https://deno.land/x/og_edge/mod.ts'; + +export default async function handler(req: Request) { + const params = new URL(req.url).searchParams; + + const product = params.get('product'); + const folder = params.get('folder'); + const page = params.get('page'); + + return new ImageResponse( + ( +
+
+ + + +
+

+ {product} +

+
+
+
{folder}
+
+ {page} +
+
+
+ ), + { + width: 1280, + height: 640, + fonts: [ + { + name: 'General Sans', + data: await fetch('https://fonts.cdnfonts.com/s/85793/GeneralSans-Medium.woff').then( + (a) => a.arrayBuffer(), + ), + weight: 1000, + style: 'normal', + }, + { + name: 'General Sans', + data: await fetch('https://fonts.cdnfonts.com/s/85793/GeneralSans-Semibold.woff').then( + (a) => a.arrayBuffer(), + ), + weight: 600, + style: 'normal', + }, + { + name: 'General Sans', + data: await fetch('https://fonts.cdnfonts.com/s/85793/GeneralSans-Bold.woff').then((a) => + a.arrayBuffer(), + ), + weight: 700, + style: 'normal', + }, + ], + }, + ); +} +export const config = { path: '/og-docs' }; diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx index e184871d423fc2..3d99fc3e0fd445 100644 --- a/netlify/edge-functions/og-image.tsx +++ b/netlify/edge-functions/og-image.tsx @@ -31,7 +31,8 @@ export default async function handler(req: Request) { const authors = params.get('authors'); let starCount = 0; - const R = new ImageResponse( + + return new ImageResponse( (
Date: Tue, 5 Mar 2024 17:08:51 -0300 Subject: [PATCH 07/28] add small design tweaks --- netlify/edge-functions/og-image.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx index 3d99fc3e0fd445..ec627e6e2ba5da 100644 --- a/netlify/edge-functions/og-image.tsx +++ b/netlify/edge-functions/og-image.tsx @@ -56,7 +56,6 @@ export default async function handler(req: Request) { filter: 'blur(210px)', transform: 'skew(70deg, 20deg)', borderRadius: '50%', - // transform: 'matrix(1, 0, -0.05, 1, 0, 0)', }} />
@@ -165,8 +164,10 @@ export default async function handler(req: Request) { return (
@@ -199,9 +200,8 @@ export default async function handler(req: Request) { Date: Tue, 5 Mar 2024 17:49:32 -0300 Subject: [PATCH 08/28] tweak scope identifier text element --- netlify/edge-functions/og-image.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx index ec627e6e2ba5da..983d7558bef167 100644 --- a/netlify/edge-functions/og-image.tsx +++ b/netlify/edge-functions/og-image.tsx @@ -94,14 +94,13 @@ export default async function handler(req: Request) {

- BLOG + Blog

Date: Wed, 6 Mar 2024 14:39:03 +0100 Subject: [PATCH 09/28] feedbacks --- docs/src/modules/components/AppLayoutDocs.js | 5 +- docs/src/modules/components/Head.tsx | 5 +- docs/src/modules/components/TopLayoutBlog.js | 2 +- .../modules/utils/getProductInfoFromUrl.ts | 1 + netlify/edge-functions/docs-image.tsx | 134 ------------------ netlify/edge-functions/og-image.tsx | 7 +- 6 files changed, 10 insertions(+), 144 deletions(-) delete mode 100644 netlify/edge-functions/docs-image.tsx diff --git a/docs/src/modules/components/AppLayoutDocs.js b/docs/src/modules/components/AppLayoutDocs.js index b67a9dee1f5a98..c3477cec1cec4f 100644 --- a/docs/src/modules/components/AppLayoutDocs.js +++ b/docs/src/modules/components/AppLayoutDocs.js @@ -120,19 +120,16 @@ export default function AppLayoutDocs(props) { const { canonicalAs } = pathnameToLanguage(router.asPath); let productName = 'MUI'; - let teamName = 'Core'; if (canonicalAs.startsWith('/material-ui/')) { productName = 'Material UI'; } else if (canonicalAs.startsWith('/base-ui/')) { productName = 'Base UI'; } else if (canonicalAs.startsWith('/x/')) { productName = 'MUI X'; - teamName = 'X'; } else if (canonicalAs.startsWith('/system/')) { productName = 'MUI System'; } else if (canonicalAs.startsWith('/toolpad/')) { productName = 'MUI Toolpad'; - teamName = 'Toolpad'; } else if (canonicalAs.startsWith('/joy-ui/')) { productName = 'Joy UI'; } @@ -140,7 +137,7 @@ export default function AppLayoutDocs(props) { const Layout = disableLayout ? React.Fragment : AppFrame; const layoutProps = disableLayout ? {} : { BannerComponent }; - const card = `https://deploy-preview-41188--material-ui-apps.netlify.app/og-docs?product=${teamName}&folder=${productName}&page=${title}`; + const card = `/edge-functions/og-image?product=${productName}&title=${title}`; return ( -
- - - -
-

- {product} -

-
-
-
{folder}
-
- {page} -
-
-
- ), - { - width: 1280, - height: 640, - fonts: [ - { - name: 'General Sans', - data: await fetch('https://fonts.cdnfonts.com/s/85793/GeneralSans-Medium.woff').then( - (a) => a.arrayBuffer(), - ), - weight: 1000, - style: 'normal', - }, - { - name: 'General Sans', - data: await fetch('https://fonts.cdnfonts.com/s/85793/GeneralSans-Semibold.woff').then( - (a) => a.arrayBuffer(), - ), - weight: 600, - style: 'normal', - }, - { - name: 'General Sans', - data: await fetch('https://fonts.cdnfonts.com/s/85793/GeneralSans-Bold.woff').then((a) => - a.arrayBuffer(), - ), - weight: 700, - style: 'normal', - }, - ], - }, - ); -} -export const config = { path: '/og-docs' }; diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx index 983d7558bef167..1affc696d9feb2 100644 --- a/netlify/edge-functions/og-image.tsx +++ b/netlify/edge-functions/og-image.tsx @@ -29,6 +29,7 @@ export default async function handler(req: Request) { const params = new URL(req.url).searchParams; const title = params.get('title'); const authors = params.get('authors'); + const product = params.get('product'); let starCount = 0; @@ -100,7 +101,7 @@ export default async function handler(req: Request) { color: '#007FFF', }} > - Blog + {product}

{title && title.split('\\n').map((line) => ( -

+

{line.split('*').flatMap((text, index) => { if (index > 0) { starCount += 1; @@ -257,4 +258,4 @@ export default async function handler(req: Request) { }, ); } -export const config = { path: '/og-blog' }; +export const config = { path: '/edge-functions/og-image' }; From f5bdae34ba30f80919d507e387b55be7f28a8db3 Mon Sep 17 00:00:00 2001 From: alexandre Date: Wed, 6 Mar 2024 15:57:08 +0100 Subject: [PATCH 10/28] fix --- docs/pages/experiments/blog/blog-custom-card.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/experiments/blog/blog-custom-card.js b/docs/pages/experiments/blog/blog-custom-card.js index 661ce999fcca2a..57dfbb8a95e4d0 100644 --- a/docs/pages/experiments/blog/blog-custom-card.js +++ b/docs/pages/experiments/blog/blog-custom-card.js @@ -1,6 +1,6 @@ import * as React from 'react'; import TopLayoutBlog from 'docs/src/modules/components/TopLayoutBlog'; -import { docs } from './blog-custom-card.md?@mui/markdown'; +import { docs } from './blog-custom-card.md?muiMarkdown'; export default function Page() { return ; From 5f5e34264fb33f73a80258f552d62eadc92592db Mon Sep 17 00:00:00 2001 From: alexandre Date: Wed, 6 Mar 2024 15:58:35 +0100 Subject: [PATCH 11/28] lint fix --- netlify/edge-functions/og-image.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx index 1affc696d9feb2..ef512f9cdd7aaf 100644 --- a/netlify/edge-functions/og-image.tsx +++ b/netlify/edge-functions/og-image.tsx @@ -1,5 +1,5 @@ -/* eslint-disable no-console */ import React from 'https://esm.sh/react@18.2.0'; +// eslint-disable-next-line import/extensions import { ImageResponse } from 'https://deno.land/x/og_edge/mod.ts'; /** * The matching from github user to their full name From 14c47c0eedc0729a6c847527f731858f9770cf7e Mon Sep 17 00:00:00 2001 From: alexandre Date: Mon, 11 Mar 2024 11:27:03 +0100 Subject: [PATCH 12/28] fix missing product --- netlify/edge-functions/og-image.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx index ef512f9cdd7aaf..ffdf8afa8e71c6 100644 --- a/netlify/edge-functions/og-image.tsx +++ b/netlify/edge-functions/og-image.tsx @@ -97,7 +97,7 @@ export default async function handler(req: Request) { fontFamily: 'General Sans', fontSize: '24px', fontWeight: 600, - lineHeight: 'normal', + lineHeight: '40px', color: '#007FFF', }} > @@ -229,6 +229,7 @@ export default async function handler(req: Request) { { width: 1280, height: 640, + // debug: true, fonts: [ { name: 'General Sans', From fcbcfa0da436c36585fce80ce18e68b187bcea42 Mon Sep 17 00:00:00 2001 From: alexandre Date: Mon, 11 Mar 2024 11:27:09 +0100 Subject: [PATCH 13/28] add cache --- netlify/edge-functions/og-image.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx index ffdf8afa8e71c6..24132edffed005 100644 --- a/netlify/edge-functions/og-image.tsx +++ b/netlify/edge-functions/og-image.tsx @@ -256,7 +256,15 @@ export default async function handler(req: Request) { style: 'normal', }, ], + // Manage the caching + headers: { + // Cach control is already done by the package (https://github.com/ascorbic/og-edge/blob/d533ef878801d7f808eb004f254e782ec6ba1e3c/mod.ts#L233-L240) + 'Netlify-Vary': 'query', + }, }, ); } -export const config = { path: '/edge-functions/og-image' }; +export const config = { + cache: 'manual', + path: '/edge-functions/og-image', +}; From 04ea2089ba63c8d76ff57926c29e186e12e5b6f8 Mon Sep 17 00:00:00 2001 From: alexandre Date: Fri, 22 Mar 2024 13:42:52 +0100 Subject: [PATCH 14/28] feedbacks --- docs/src/modules/components/TopLayoutBlog.js | 7 +- netlify/edge-functions/og-image.tsx | 232 +++++++++---------- 2 files changed, 110 insertions(+), 129 deletions(-) diff --git a/docs/src/modules/components/TopLayoutBlog.js b/docs/src/modules/components/TopLayoutBlog.js index cd5c610cf6dcda..1d5dafe1db4425 100644 --- a/docs/src/modules/components/TopLayoutBlog.js +++ b/docs/src/modules/components/TopLayoutBlog.js @@ -267,7 +267,12 @@ export default function TopLayoutBlog(props) { const card = headers.card === 'true' ? `https://mui.com/static/blog/${slug}/card.png` - : `/edge-functions/og-image/?title=${headers.cardTitle || finalTitle}&authors=${headers.authors.join(',')}&product=BLOG`; + : `/edge-functions/og-image/?title=${headers.cardTitle || finalTitle}&authors=${headers.authors + .map((author) => { + const { github, name } = authors[author]; + return `${name} @${github}`; + }) + .join(',')}&product=Blog`; if (process.env.NODE_ENV !== 'production') { if (headers.card === undefined) { diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx index 24132edffed005..aee86114801eab 100644 --- a/netlify/edge-functions/og-image.tsx +++ b/netlify/edge-functions/og-image.tsx @@ -1,36 +1,25 @@ import React from 'https://esm.sh/react@18.2.0'; // eslint-disable-next-line import/extensions import { ImageResponse } from 'https://deno.land/x/og_edge/mod.ts'; -/** - * The matching from github user to their full name - */ -const fullName: Record = { - mikailaread: 'Mikaila Read', - joserodolfofreitas: 'José Freitas', - samuelsycamore: 'Sam Sycamore', - flaviendelangle: 'Flavien Delangle', - richbustos: 'Rich Bustos', - prakhargupta1: 'Prakhar Gupta', - alexfauquette: 'Alexandre Fauquette', - siriwatknp: 'Siriwat Kunaporn', - cherniavskii: 'Andrew Cherniavskyi', - 'danilo-leal': 'Danilo Leal', - mnajdova: 'Marija Najdova', - oliviertassinari: 'Olivier Tassinari', - m4theushw: 'Matheus Wichman', - DanailH: 'Danail Hadjiatanasov', - mbrookes: 'Matt Brookes', - eps1lon: 'Sebastian Silbermann', - michaldudak: 'Michał Dudak', - colmtuite: 'Colm Tuite', -}; +const MAX_AUTHORS = 5; export default async function handler(req: Request) { const params = new URL(req.url).searchParams; const title = params.get('title'); const authors = params.get('authors'); const product = params.get('product'); + const parsedAuthors = + authors && + authors + .split(',') + .map((author) => { + const [name, github] = author.split('@'); + return { name: name.trim(), github: github.trim() }; + }) + .filter(({ name, github }) => name && github); + + const withAuthors = parsedAuthors && parsedAuthors.length > 0; let starCount = 0; return new ImageResponse( @@ -47,120 +36,106 @@ export default async function handler(req: Request) { >

-
- - -
-

+ + + +

+

+ {product} +

+
+
- {product} -

-
-
- {title && - title.split('\\n').map((line) => ( -

- {line.split('*').flatMap((text, index) => { - if (index > 0) { - starCount += 1; - } + {title && + title.split('\\n').map((line) => ( +

+ {line.split('*').flatMap((text, index) => { + if (index > 0) { + starCount += 1; + } - const isBlue = starCount % 2 === 1; - return text.split(' ').map((word) => ( - 0 ? 15 : 0, - }} - > - {word} - - )); - })} -

- ))} -
+ const isBlue = starCount % 2 === 1; + return text.split(' ').map((word) => ( + 0 ? 15 : 0, + }} + > + {word} + + )); + })} +

+ ))} +
-
- {authors && - authors - .split(',') - .map((author) => author.trim()) - .filter((githubUser) => fullName[githubUser]) - .map((githubUser) => { +
+ {withAuthors && + parsedAuthors.slice(0, MAX_AUTHORS).map(({ name, github }) => { return (
@@ -183,7 +158,7 @@ export default async function handler(req: Request) { }} > - {fullName[githubUser]} + {name} - @{githubUser} + @{github}
); })} +
), { width: 1280, height: 640, - // debug: true, + debug: true, fonts: [ { name: 'General Sans', From 9d0018028d8306027345b4d3dbd9dc532b27a44b Mon Sep 17 00:00:00 2001 From: alexandre Date: Fri, 22 Mar 2024 13:44:47 +0100 Subject: [PATCH 15/28] small feedback --- docs/pages/experiments/blog/blog-custom-card.md | 2 +- docs/pages/experiments/blog/blog.md | 2 +- netlify/edge-functions/og-image.tsx | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/pages/experiments/blog/blog-custom-card.md b/docs/pages/experiments/blog/blog-custom-card.md index 9cfadc7361b997..5751e17acac0cf 100644 --- a/docs/pages/experiments/blog/blog-custom-card.md +++ b/docs/pages/experiments/blog/blog-custom-card.md @@ -12,7 +12,7 @@ cardTitle: blog with\n*custom* card ### Image -Satellite image of Tenerife +Satellite image of Tenerife

An image description with a link.

diff --git a/docs/pages/experiments/blog/blog.md b/docs/pages/experiments/blog/blog.md index 0579a43e8f4eff..eb2972c6bbe833 100644 --- a/docs/pages/experiments/blog/blog.md +++ b/docs/pages/experiments/blog/blog.md @@ -11,7 +11,7 @@ card: false ### Image -Satellite image of Tenerife +Satellite image of Tenerife

An image description with a link.

diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx index aee86114801eab..8fe71c17b54936 100644 --- a/netlify/edge-functions/og-image.tsx +++ b/netlify/edge-functions/og-image.tsx @@ -123,7 +123,6 @@ export default async function handler(req: Request) {

))}
-
Date: Fri, 22 Mar 2024 17:46:50 +0100 Subject: [PATCH 16/28] remove debug --- netlify/edge-functions/og-image.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx index 8fe71c17b54936..de81982427e0a7 100644 --- a/netlify/edge-functions/og-image.tsx +++ b/netlify/edge-functions/og-image.tsx @@ -204,7 +204,7 @@ export default async function handler(req: Request) { { width: 1280, height: 640, - debug: true, + // debug: true, fonts: [ { name: 'General Sans', From 8fcc08e3ac67406531a16738a8b95653d409d4a1 Mon Sep 17 00:00:00 2001 From: Olivier Tassinari Date: Tue, 26 Mar 2024 21:57:55 +0100 Subject: [PATCH 17/28] Fix typo Signed-off-by: Olivier Tassinari --- netlify/edge-functions/og-image.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx index de81982427e0a7..03293e00b770b7 100644 --- a/netlify/edge-functions/og-image.tsx +++ b/netlify/edge-functions/og-image.tsx @@ -233,7 +233,7 @@ export default async function handler(req: Request) { ], // Manage the caching headers: { - // Cach control is already done by the package (https://github.com/ascorbic/og-edge/blob/d533ef878801d7f808eb004f254e782ec6ba1e3c/mod.ts#L233-L240) + // Cache control is already done by the package (https://github.com/ascorbic/og-edge/blob/d533ef878801d7f808eb004f254e782ec6ba1e3c/mod.ts#L233-L240) 'Netlify-Vary': 'query', }, }, From 1629679e8592f24127381230b797277302093196 Mon Sep 17 00:00:00 2001 From: alexandre Date: Fri, 29 Mar 2024 14:45:17 +0100 Subject: [PATCH 18/28] move headers to manual card --- docs/pages/blog/2019-developer-survey-results.md | 2 +- docs/pages/blog/2019.md | 2 +- docs/pages/blog/2020-developer-survey-results.md | 2 +- docs/pages/blog/2020-introducing-sketch.md | 2 +- docs/pages/blog/2020-q1-update.md | 2 +- docs/pages/blog/2020-q2-update.md | 2 +- docs/pages/blog/2020-q3-update.md | 2 +- docs/pages/blog/2020.md | 2 +- docs/pages/blog/2021-developer-survey-results.md | 2 +- docs/pages/blog/2021-q1-update.md | 2 +- docs/pages/blog/2021-q2-update.md | 2 +- docs/pages/blog/2021-q3-update.md | 2 +- docs/pages/blog/2021.md | 2 +- docs/pages/blog/2022-tenerife-retreat.md | 2 +- docs/pages/blog/2023-chamonix-retreat.md | 2 +- docs/pages/blog/2023-material-ui-v6-and-beyond.md | 2 +- docs/pages/blog/2023-mui-values.md | 2 +- docs/pages/blog/2023-phuket-retreat.md | 2 +- docs/pages/blog/2023-toolpad-beta-announcement.md | 2 +- docs/pages/blog/aggregation-functions.md | 2 +- docs/pages/blog/april-2019-update.md | 2 +- docs/pages/blog/august-2019-update.md | 2 +- docs/pages/blog/base-ui-2024-plans.md | 2 +- docs/pages/blog/benny-joo-joining.md | 2 +- .../bringing-consistency-to-material-ui-customization-apis.md | 2 +- docs/pages/blog/build-layouts-faster-with-grid-v2.md | 2 +- docs/pages/blog/callback-support-in-style-overrides.md | 2 +- docs/pages/blog/danail-hadjiatanasov-joining.md | 2 +- docs/pages/blog/danilo-leal-joining.md | 2 +- docs/pages/blog/date-pickers-stable-v5.md | 2 +- docs/pages/blog/december-2019-update.md | 2 +- docs/pages/blog/discord-announcement.md | 2 +- docs/pages/blog/docs-restructure-2022.md | 2 +- docs/pages/blog/first-look-at-joy.md | 2 +- docs/pages/blog/introducing-base-ui.md | 2 +- docs/pages/blog/introducing-the-row-grouping-feature.md | 2 +- docs/pages/blog/july-2019-update.md | 2 +- docs/pages/blog/june-2019-update.md | 2 +- docs/pages/blog/lab-date-pickers-to-mui-x.md | 2 +- docs/pages/blog/lab-tree-view-to-mui-x.md | 2 +- docs/pages/blog/making-customizable-components.md | 2 +- docs/pages/blog/march-2019-update.md | 2 +- docs/pages/blog/marija-najdova-joining.md | 2 +- docs/pages/blog/material-ui-is-now-mui.md | 2 +- docs/pages/blog/material-ui-v1-is-out.md | 2 +- docs/pages/blog/material-ui-v4-is-out.md | 2 +- docs/pages/blog/matheus-wichman-joining.md | 2 +- docs/pages/blog/may-2019-update.md | 2 +- docs/pages/blog/michal-dudak-joining.md | 2 +- docs/pages/blog/mui-core-v5-migration-update.md | 2 +- docs/pages/blog/mui-core-v5.md | 2 +- docs/pages/blog/mui-next-js-app-router.md | 2 +- docs/pages/blog/mui-product-comparison.md | 2 +- docs/pages/blog/mui-x-end-v6-features.md | 2 +- docs/pages/blog/mui-x-mid-v6-features.md | 2 +- docs/pages/blog/mui-x-v5.md | 2 +- docs/pages/blog/mui-x-v6-alpha-zero.md | 2 +- docs/pages/blog/mui-x-v6.md | 2 +- docs/pages/blog/mui-x-v7-beta.md | 2 +- docs/pages/blog/mui-x-v7.md | 2 +- docs/pages/blog/november-2019-update.md | 2 +- docs/pages/blog/october-2019-update.md | 2 +- docs/pages/blog/premium-plan-release.md | 2 +- docs/pages/blog/remote-award-win-2024.md | 2 +- docs/pages/blog/september-2019-update.md | 2 +- docs/pages/blog/siriwat-kunaporn-joining.md | 2 +- docs/pages/blog/spotlight-damien-tassone.md | 2 +- docs/pages/blog/toolpad-use-cases.md | 2 +- docs/pages/blog/v6-beta-pickers.md | 2 +- docs/pages/experiments/blog/blog-custom-card.md | 2 +- docs/pages/experiments/blog/blog.md | 2 +- 71 files changed, 71 insertions(+), 71 deletions(-) diff --git a/docs/pages/blog/2019-developer-survey-results.md b/docs/pages/blog/2019-developer-survey-results.md index 392206d8f8c1d9..98e98cdb6c3bbe 100644 --- a/docs/pages/blog/2019-developer-survey-results.md +++ b/docs/pages/blog/2019-developer-survey-results.md @@ -4,7 +4,7 @@ description: Your feedback helps us to build better products. Here's what we lea date: 2019-03-16T00:00:00.000Z authors: ['oliviertassinari', 'mbrookes'] tags: ['Developer Survey'] -card: true +manualCard: true --- While we are currently working on the upcoming release of Material UI v4, we need to prioritize our diff --git a/docs/pages/blog/2019.md b/docs/pages/blog/2019.md index a528508030a330..200cf9280ef1ca 100644 --- a/docs/pages/blog/2019.md +++ b/docs/pages/blog/2019.md @@ -4,7 +4,7 @@ date: 2020-01-25T00:00:00.000Z description: 2019 was a great year for Material UI. It puts us on an exciting path to solve even greater challenges in the coming years! authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- 2019 was a great year for Material UI. diff --git a/docs/pages/blog/2020-developer-survey-results.md b/docs/pages/blog/2020-developer-survey-results.md index 9c89e737c62c3c..42f611ecce9484 100644 --- a/docs/pages/blog/2020-developer-survey-results.md +++ b/docs/pages/blog/2020-developer-survey-results.md @@ -4,7 +4,7 @@ description: Your feedback helps us to build better products. Here's what we lea date: 2020-06-27T00:00:00.000Z authors: ['mnajdova', 'oliviertassinari', 'mbrookes'] tags: ['Developer Survey'] -card: true +manualCard: true --- Continuing the tradition from last year, we launched a Developer Survey a few months ago, to which we received 1488 responses. This is twice as many as last year (734), so we thank you all for your participation! diff --git a/docs/pages/blog/2020-introducing-sketch.md b/docs/pages/blog/2020-introducing-sketch.md index 731b1ee9549a67..783370d31d57b6 100644 --- a/docs/pages/blog/2020-introducing-sketch.md +++ b/docs/pages/blog/2020-introducing-sketch.md @@ -4,7 +4,7 @@ description: Today, we're excited to announce the introduction of official Sketc date: 2020-03-30T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Material UI', 'Product'] -card: true +manualCard: true --- Today, we're excited to introduce the Sketch symbols 💎 for Material UI. diff --git a/docs/pages/blog/2020-q1-update.md b/docs/pages/blog/2020-q1-update.md index ca6e353e94c685..74974a32703f13 100644 --- a/docs/pages/blog/2020-q1-update.md +++ b/docs/pages/blog/2020-q1-update.md @@ -4,7 +4,7 @@ description: An update on our mission for Q1 2020. date: 2020-04-14T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- Welcome to the new format of our mission update. We are moving from monthly to quarterly updates. diff --git a/docs/pages/blog/2020-q2-update.md b/docs/pages/blog/2020-q2-update.md index 09fc6ee3dc1b4c..6d34a639194694 100644 --- a/docs/pages/blog/2020-q2-update.md +++ b/docs/pages/blog/2020-q2-update.md @@ -4,7 +4,7 @@ description: An update on our mission for Q2 2020. date: 2020-07-17T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- This update covers our progress over the last three months, and what we aim to achieve in the coming months. diff --git a/docs/pages/blog/2020-q3-update.md b/docs/pages/blog/2020-q3-update.md index 54e67b4bcb6b8b..f819f177ff06dc 100644 --- a/docs/pages/blog/2020-q3-update.md +++ b/docs/pages/blog/2020-q3-update.md @@ -4,7 +4,7 @@ description: An update on our mission for Q3 2020. date: 2020-10-14T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- This update covers our progress over the last three months, and what we aim to achieve in the coming months. diff --git a/docs/pages/blog/2020.md b/docs/pages/blog/2020.md index 97e953f791cd04..45db0f45fd33be 100644 --- a/docs/pages/blog/2020.md +++ b/docs/pages/blog/2020.md @@ -4,7 +4,7 @@ description: 2020 has been another great year, not only for MUI, but also for th date: 2020-12-31T00:00:00.000Z authors: ['oliviertassinari', 'mbrookes'] tags: ['Company'] -card: true +manualCard: true --- 2020 has been another great year, not only for MUI, but also for the ecosystem. diff --git a/docs/pages/blog/2021-developer-survey-results.md b/docs/pages/blog/2021-developer-survey-results.md index e6b3eba54ff130..93bb07ccb79477 100644 --- a/docs/pages/blog/2021-developer-survey-results.md +++ b/docs/pages/blog/2021-developer-survey-results.md @@ -4,7 +4,7 @@ description: Your feedback helps us to build better products. Here's what we lea date: 2022-03-15T00:00:00.000Z authors: ['danilo-leal', 'samuelsycamore', 'oliviertassinari'] tags: ['Developer Survey'] -card: true +manualCard: true --- Keeping up with tradition, a few months ago we opened the 2021 MUI Developer Survey. diff --git a/docs/pages/blog/2021-q1-update.md b/docs/pages/blog/2021-q1-update.md index 2c7bf644eed777..6c430546ecb0a2 100644 --- a/docs/pages/blog/2021-q1-update.md +++ b/docs/pages/blog/2021-q1-update.md @@ -4,7 +4,7 @@ description: An update on our mission for Q1 2021. date: 2021-04-12T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- This update covers our progress over the last three months, and what we aim to achieve in the months ahead. diff --git a/docs/pages/blog/2021-q2-update.md b/docs/pages/blog/2021-q2-update.md index a7650185843a22..e624f680837326 100644 --- a/docs/pages/blog/2021-q2-update.md +++ b/docs/pages/blog/2021-q2-update.md @@ -4,7 +4,7 @@ description: An update on our mission for Q2 2021. date: 2021-07-12T00:00:00.000Z authors: ['oliviertassinari', 'mbrookes'] tags: ['Company'] -card: true +manualCard: true --- This update covers our progress over the last three months. diff --git a/docs/pages/blog/2021-q3-update.md b/docs/pages/blog/2021-q3-update.md index dbb57c07d4ea15..d5562955c1db4e 100644 --- a/docs/pages/blog/2021-q3-update.md +++ b/docs/pages/blog/2021-q3-update.md @@ -4,7 +4,7 @@ description: An update on our mission for Q3 2021. date: 2021-10-26T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- This update covers our progress over the last three months. diff --git a/docs/pages/blog/2021.md b/docs/pages/blog/2021.md index 61d81f432e1b7b..8bc67f99a863b9 100644 --- a/docs/pages/blog/2021.md +++ b/docs/pages/blog/2021.md @@ -4,7 +4,7 @@ description: 2021 has been another great year, not only for MUI but also for the date: 2021-12-31T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- diff --git a/docs/pages/blog/2022-tenerife-retreat.md b/docs/pages/blog/2022-tenerife-retreat.md index b111d056ac85e3..1402e4240838c4 100644 --- a/docs/pages/blog/2022-tenerife-retreat.md +++ b/docs/pages/blog/2022-tenerife-retreat.md @@ -4,7 +4,7 @@ description: Our internationally distributed startup gathered on a remote island date: 2022-07-28T00:00:00.000Z authors: ['samuelsycamore'] tags: ['Company'] -card: true +manualCard: true --- One of the toughest challenges to overcome as a fully remote team is fostering a supportive and inclusive company culture. diff --git a/docs/pages/blog/2023-chamonix-retreat.md b/docs/pages/blog/2023-chamonix-retreat.md index 19b8559a739580..d6bccc7e15406f 100644 --- a/docs/pages/blog/2023-chamonix-retreat.md +++ b/docs/pages/blog/2023-chamonix-retreat.md @@ -4,7 +4,7 @@ description: The MUI team spent five days in the French Alps team-building, prob date: 2023-03-16T00:00:00.000Z authors: ['mikailaread'] tags: ['Company'] -card: true +manualCard: true --- ## Why the Chamonix gathering? diff --git a/docs/pages/blog/2023-material-ui-v6-and-beyond.md b/docs/pages/blog/2023-material-ui-v6-and-beyond.md index 24bebf7f41ee2f..aee8654af71152 100644 --- a/docs/pages/blog/2023-material-ui-v6-and-beyond.md +++ b/docs/pages/blog/2023-material-ui-v6-and-beyond.md @@ -3,7 +3,7 @@ title: The road to Material UI v6 and beyond description: We're tightening up the Material UI release schedule and shipping two major versions in 2024. Here's what to expect. date: 2023-12-23T00:00:00.000Z authors: ['mnajdova'] -card: true +manualCard: true tags: ['Material UI', 'Product'] --- diff --git a/docs/pages/blog/2023-mui-values.md b/docs/pages/blog/2023-mui-values.md index 79668d65b69148..27e3dd49b1d642 100644 --- a/docs/pages/blog/2023-mui-values.md +++ b/docs/pages/blog/2023-mui-values.md @@ -4,7 +4,7 @@ description: After significant growth, we united as a team to rediscover the val date: 2023-09-26T00:00:00.000Z authors: ['mikailaread'] tags: ['Company'] -card: true +manualCard: true --- ## Why we chose to revise our core values diff --git a/docs/pages/blog/2023-phuket-retreat.md b/docs/pages/blog/2023-phuket-retreat.md index 2b9b1d338e2446..35bf504c9ba842 100644 --- a/docs/pages/blog/2023-phuket-retreat.md +++ b/docs/pages/blog/2023-phuket-retreat.md @@ -4,7 +4,7 @@ description: The latest team retreat left MUIers feeling more connected and invi date: 2023-12-13T00:00:00.000Z authors: ['mikailaread'] tags: ['Company'] -card: true +manualCard: true --- ## What is MUI's Together Week? diff --git a/docs/pages/blog/2023-toolpad-beta-announcement.md b/docs/pages/blog/2023-toolpad-beta-announcement.md index 318dfe94bfe1e9..ae5e5305477224 100644 --- a/docs/pages/blog/2023-toolpad-beta-announcement.md +++ b/docs/pages/blog/2023-toolpad-beta-announcement.md @@ -3,7 +3,7 @@ title: Introducing Toolpad: MUI's low-code admin builder description: Assemble admin panels and internal tools faster than ever before with Toolpad—now in beta. date: 2023-07-24T00:00:00.000Z authors: ['prakhargupta'] -card: true +manualCard: true tags: ['Product', 'Toolpad'] --- diff --git a/docs/pages/blog/aggregation-functions.md b/docs/pages/blog/aggregation-functions.md index 68ddfb0d169974..58254350d5292a 100644 --- a/docs/pages/blog/aggregation-functions.md +++ b/docs/pages/blog/aggregation-functions.md @@ -4,7 +4,7 @@ description: Aggregation functions and summary rows are now available in the MUI date: 2022-08-01T00:00:00.000Z authors: ['josefreitas', 'flaviendelangle', 'cherniavskii'] tags: ['MUI X', 'Product'] -card: true +manualCard: true --- If you've ever worked with a data-heavy grid, then you understand how important it is for the end user to be able to set different perspectives on the data to gather the information they're looking for. diff --git a/docs/pages/blog/april-2019-update.md b/docs/pages/blog/april-2019-update.md index 4b6a76792a9db7..c4a81e258dba49 100644 --- a/docs/pages/blog/april-2019-update.md +++ b/docs/pages/blog/april-2019-update.md @@ -4,7 +4,7 @@ description: Here are the most significant improvements in April. date: 2019-05-07T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- Here are the most significant improvements in April: diff --git a/docs/pages/blog/august-2019-update.md b/docs/pages/blog/august-2019-update.md index 5bde138036b660..77fa9cbb761278 100644 --- a/docs/pages/blog/august-2019-update.md +++ b/docs/pages/blog/august-2019-update.md @@ -4,7 +4,7 @@ description: Here are the most significant improvements in August. date: 2019-09-07T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- Here are the most significant improvements in August: diff --git a/docs/pages/blog/base-ui-2024-plans.md b/docs/pages/blog/base-ui-2024-plans.md index 12d33c4406a1b6..8298409dbe85f2 100644 --- a/docs/pages/blog/base-ui-2024-plans.md +++ b/docs/pages/blog/base-ui-2024-plans.md @@ -4,7 +4,7 @@ description: The unstyled component library will get a stable release, lots of n date: 2024-02-13T00:00:00.000Z authors: ['danilo-leal', 'michaldudak', 'colmtuite', 'oliviertassinari'] tags: ['Base UI', 'Product'] -card: true +manualCard: true --- The [story of Base UI](/blog/introducing-base-ui/) began several years ago—long before headless React component libraries skyrocketed in popularity—when we started to imagine a world in which Material UI could exist without Material Design. diff --git a/docs/pages/blog/benny-joo-joining.md b/docs/pages/blog/benny-joo-joining.md index 4fac8d9b5f4338..bcecb2de2b043e 100644 --- a/docs/pages/blog/benny-joo-joining.md +++ b/docs/pages/blog/benny-joo-joining.md @@ -4,7 +4,7 @@ description: We are excited to share that Benny Joo has joined MUI. He has start date: 2021-11-16T00:00:00.000Z authors: ['mnajdova'] tags: ['Company'] -card: true +manualCard: true --- We are excited to share that [Benny Joo](https://github.com/hbjORbj) has joined MUI. diff --git a/docs/pages/blog/bringing-consistency-to-material-ui-customization-apis.md b/docs/pages/blog/bringing-consistency-to-material-ui-customization-apis.md index dc43c0bb98c9aa..c3f1b7330f0cee 100644 --- a/docs/pages/blog/bringing-consistency-to-material-ui-customization-apis.md +++ b/docs/pages/blog/bringing-consistency-to-material-ui-customization-apis.md @@ -4,7 +4,7 @@ description: We're standardizing two key areas of the Material UI customization date: 2024-03-18T10:00:00.000Z authors: ['diegoandai'] tags: ['Material UI', 'Product'] -card: true +manualCard: true --- The Material UI team is working on two initiatives to standardize the Material UI API: The first applies to overriding inner elements, and the second applies to component CSS classes. diff --git a/docs/pages/blog/build-layouts-faster-with-grid-v2.md b/docs/pages/blog/build-layouts-faster-with-grid-v2.md index b40ad11e25f25f..b2b6a5834b37ce 100644 --- a/docs/pages/blog/build-layouts-faster-with-grid-v2.md +++ b/docs/pages/blog/build-layouts-faster-with-grid-v2.md @@ -4,7 +4,7 @@ description: The new Grid v2 features simplified logic, support for offsetting a date: 2022-08-20T00:00:00.000Z authors: ['siriwatknp'] tags: ['Material UI', 'Guide'] -card: true +manualCard: true --- You can now use the new `Grid` component, shipped with [Material UI v5.9.0](https://github.com/mui/material-ui/releases/tag/v5.9.0), for updated features and a better developer experience when building layouts. diff --git a/docs/pages/blog/callback-support-in-style-overrides.md b/docs/pages/blog/callback-support-in-style-overrides.md index 77325f31e9dfbc..42019929c4721f 100644 --- a/docs/pages/blog/callback-support-in-style-overrides.md +++ b/docs/pages/blog/callback-support-in-style-overrides.md @@ -4,7 +4,7 @@ description: We're excited to introduce callback support for global theme overri date: 2022-01-31T00:00:00.000Z authors: ['siriwatknp'] tags: ['Material UI', 'Product'] -card: true +manualCard: true --- [Material UI v5.3.0](https://github.com/mui/material-ui/releases/tag/v5.3.0) introduces the ability to write a callback in style overrides (global theming), giving you full control of component customization at the theme level. diff --git a/docs/pages/blog/danail-hadjiatanasov-joining.md b/docs/pages/blog/danail-hadjiatanasov-joining.md index 5f0904549b960e..b39eeb6a65ce42 100644 --- a/docs/pages/blog/danail-hadjiatanasov-joining.md +++ b/docs/pages/blog/danail-hadjiatanasov-joining.md @@ -4,7 +4,7 @@ description: We are excited to share that Danail Hadjiatanasov has joined MUI as date: 2020-10-23T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- We are excited to share that [Danail Hadjiatanasov](https://twitter.com/danail_h) has joined MUI as part of the enterprise team. This was his first full-time week. diff --git a/docs/pages/blog/danilo-leal-joining.md b/docs/pages/blog/danilo-leal-joining.md index e18707c8f16947..55e6c3032a036c 100644 --- a/docs/pages/blog/danilo-leal-joining.md +++ b/docs/pages/blog/danilo-leal-joining.md @@ -4,7 +4,7 @@ description: We are excited to share that Danilo Leal has joined MUI. date: 2021-07-15T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- We are excited to share that [Danilo Leal](https://daniloleal.co/) has joined MUI! diff --git a/docs/pages/blog/date-pickers-stable-v5.md b/docs/pages/blog/date-pickers-stable-v5.md index 306637c250c28c..61b15bc7f59f2f 100644 --- a/docs/pages/blog/date-pickers-stable-v5.md +++ b/docs/pages/blog/date-pickers-stable-v5.md @@ -4,7 +4,7 @@ description: Migrate to the latest version for improved DX, customizability, and date: 2022-09-19T00:00:00.000Z authors: ['alexfauquette', 'josefreitas'] tags: ['MUI X', 'Product'] -card: true +manualCard: true --- About four months ago, we moved the date and time pickers from `@mui/lab` and released the first alpha version of the date pickers package. diff --git a/docs/pages/blog/december-2019-update.md b/docs/pages/blog/december-2019-update.md index 28cb4694f2c35d..e747320df73cf6 100644 --- a/docs/pages/blog/december-2019-update.md +++ b/docs/pages/blog/december-2019-update.md @@ -4,7 +4,7 @@ description: Here are the most significant improvements in December. date: 2020-01-07T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- Here are the most significant improvements in December: diff --git a/docs/pages/blog/discord-announcement.md b/docs/pages/blog/discord-announcement.md index 4a58bb279a84c7..fc0cd949e5a01f 100644 --- a/docs/pages/blog/discord-announcement.md +++ b/docs/pages/blog/discord-announcement.md @@ -4,7 +4,7 @@ description: Come join our community to engage in lively discussions, share your date: 2023-08-02T00:00:00.000Z authors: ['richbustos'] tags: ['Company'] -card: true +manualCard: true --- Discord banner with link diff --git a/docs/pages/blog/docs-restructure-2022.md b/docs/pages/blog/docs-restructure-2022.md index 6fe7e34853094e..1ea829b42c889f 100644 --- a/docs/pages/blog/docs-restructure-2022.md +++ b/docs/pages/blog/docs-restructure-2022.md @@ -4,7 +4,7 @@ description: Each of MUI's products now has its own dedicated documentation, mak date: 2022-04-06T00:00:00.000Z authors: ['danilo-leal'] tags: ['Product'] -card: true +manualCard: true --- As MUI continues to grow beyond our flagship product, Material UI (we [rebranded the company](/blog/material-ui-is-now-mui/) last year as a first step), it has become clear that the documentation for our products can no longer all live under one roof. diff --git a/docs/pages/blog/first-look-at-joy.md b/docs/pages/blog/first-look-at-joy.md index e8f541cfff3b40..56a77bd1dc57d3 100644 --- a/docs/pages/blog/first-look-at-joy.md +++ b/docs/pages/blog/first-look-at-joy.md @@ -4,7 +4,7 @@ description: A sneak peek at MUI's new starting point for your design system. date: 2022-06-08T00:00:00.000Z authors: ['danilo-leal', 'siriwatknp'] tags: ['Joy UI', 'Product'] -card: true +manualCard: true --- First look at Joy UI: a new starting point for your design system. diff --git a/docs/pages/blog/introducing-base-ui.md b/docs/pages/blog/introducing-base-ui.md index 54af0f0943df7a..44a2ea20312ae7 100644 --- a/docs/pages/blog/introducing-base-ui.md +++ b/docs/pages/blog/introducing-base-ui.md @@ -4,7 +4,7 @@ description: The Base UI component library gives you complete control over the date: 2022-09-07T00:00:00.000Z authors: ['michaldudak', 'samuelsycamore'] tags: ['Base UI', 'Product'] -card: true +manualCard: true --- Demo components built with Base UI, a newly introduced library of unstyled components and hooks diff --git a/docs/pages/blog/introducing-the-row-grouping-feature.md b/docs/pages/blog/introducing-the-row-grouping-feature.md index 817909ca6361e9..f4a7aae089a900 100644 --- a/docs/pages/blog/introducing-the-row-grouping-feature.md +++ b/docs/pages/blog/introducing-the-row-grouping-feature.md @@ -4,7 +4,7 @@ description: The new row grouping feature gives your users more customization op date: 2022-01-20T00:00:00.000Z authors: ['alexfauquette'] tags: ['MUI X', 'Product'] -card: true +manualCard: true --- After an incredible year fully focused on improving our Data Grid component, we are moving forward by launching the first feature of our new Premium plan: [row grouping](/x/react-data-grid/row-grouping/), released in [v5.3.0](https://github.com/mui/mui-x/releases/tag/v5.3.0). diff --git a/docs/pages/blog/july-2019-update.md b/docs/pages/blog/july-2019-update.md index 26f0470b57f311..9ee2ae7e852852 100644 --- a/docs/pages/blog/july-2019-update.md +++ b/docs/pages/blog/july-2019-update.md @@ -4,7 +4,7 @@ description: Here are the most significant improvements in July. date: 2019-08-04T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- Here are the most significant improvements in July: diff --git a/docs/pages/blog/june-2019-update.md b/docs/pages/blog/june-2019-update.md index 92e81c2dbdaabe..5781f76514ce57 100644 --- a/docs/pages/blog/june-2019-update.md +++ b/docs/pages/blog/june-2019-update.md @@ -4,7 +4,7 @@ description: Here are the most significant improvements in June. date: 2019-07-08T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- Here are the most significant improvements in June: diff --git a/docs/pages/blog/lab-date-pickers-to-mui-x.md b/docs/pages/blog/lab-date-pickers-to-mui-x.md index 9d7ddc8dfacb24..e8ab79741f5006 100644 --- a/docs/pages/blog/lab-date-pickers-to-mui-x.md +++ b/docs/pages/blog/lab-date-pickers-to-mui-x.md @@ -4,7 +4,7 @@ description: Migrate to the new package to start building with our powerful Date date: 2022-04-03T00:00:00.000Z authors: ['flaviendelangle'] tags: ['MUI X', 'Product'] -card: true +manualCard: true --- After more than 18 months in the lab, the Date and Time Picker components have found a new home as part of MUI X. diff --git a/docs/pages/blog/lab-tree-view-to-mui-x.md b/docs/pages/blog/lab-tree-view-to-mui-x.md index 7a35a33f599044..cb876949ef5087 100644 --- a/docs/pages/blog/lab-tree-view-to-mui-x.md +++ b/docs/pages/blog/lab-tree-view-to-mui-x.md @@ -4,7 +4,7 @@ description: Migrate to the new package to start building with our powerful Tree date: 2023-08-21T00:00:00.000Z authors: ['flaviendelangle'] tags: ['MUI X', 'Product'] -card: true +manualCard: true --- After more than 4 years in the lab, the [Tree View](https://mui.com/x/react-tree-view/) components have found a new home as part of MUI X. diff --git a/docs/pages/blog/making-customizable-components.md b/docs/pages/blog/making-customizable-components.md index 071e08af31bf0c..fb170deb030d07 100644 --- a/docs/pages/blog/making-customizable-components.md +++ b/docs/pages/blog/making-customizable-components.md @@ -4,7 +4,7 @@ description: Explore the tradeoffs between different customization techniques, a date: 2022-08-22T00:00:00.000Z authors: ['alexfauquette'] tags: ['MUI X', 'Material UI', 'Guide'] -card: true +manualCard: true --- Material UI's components are used by hundreds of thousands of developers worldwide, encompassing the full range of implementation from minor side projects to massive company websites. diff --git a/docs/pages/blog/march-2019-update.md b/docs/pages/blog/march-2019-update.md index 743c1d67f13d0f..1ea42cd92ed75e 100644 --- a/docs/pages/blog/march-2019-update.md +++ b/docs/pages/blog/march-2019-update.md @@ -4,7 +4,7 @@ description: Here are the most significant improvements in March. date: 2019-04-05T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- Here are the most significant improvements in March: diff --git a/docs/pages/blog/marija-najdova-joining.md b/docs/pages/blog/marija-najdova-joining.md index 344a665e26b27e..003b0880ef8b59 100644 --- a/docs/pages/blog/marija-najdova-joining.md +++ b/docs/pages/blog/marija-najdova-joining.md @@ -4,7 +4,7 @@ description: We are excited to share that Marija Najdova has joined MUI. She has date: 2020-09-15T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- We are excited to share that [Marija Najdova](https://twitter.com/marijanajdova) has joined MUI. She has started this week full-time, and is now part of the community team. diff --git a/docs/pages/blog/material-ui-is-now-mui.md b/docs/pages/blog/material-ui-is-now-mui.md index b956024eae46cd..926d85ea2a8fb2 100644 --- a/docs/pages/blog/material-ui-is-now-mui.md +++ b/docs/pages/blog/material-ui-is-now-mui.md @@ -4,7 +4,7 @@ description: Starting today, we are evolving our brand identity. We are clarifyi date: 2021-09-16T00:00:00.000Z authors: ['oliviertassinari', 'danilo-leal', 'mbrookes'] tags: ['Material UI'] -card: true +manualCard: true --- The new Material UI logo diff --git a/docs/pages/blog/material-ui-v1-is-out.md b/docs/pages/blog/material-ui-v1-is-out.md index d88daf681f8ec3..29f0325a218ac9 100644 --- a/docs/pages/blog/material-ui-v1-is-out.md +++ b/docs/pages/blog/material-ui-v1-is-out.md @@ -4,7 +4,7 @@ description: It has taken us two years to do it, but Material UI v1 has finally date: 2018-05-18T00:00:00.000Z authors: ['oliviertassinari', 'mbrookes'] tags: ['Material UI', 'Product'] -card: true +manualCard: true --- > React components that implement Google's Material Design. diff --git a/docs/pages/blog/material-ui-v4-is-out.md b/docs/pages/blog/material-ui-v4-is-out.md index dfefd5a27ec56a..1dc63490f2f542 100644 --- a/docs/pages/blog/material-ui-v4-is-out.md +++ b/docs/pages/blog/material-ui-v4-is-out.md @@ -4,7 +4,7 @@ description: Material UI v4 has finally arrived. We are so excited about this r date: 2019-05-23T00:00:00.000Z authors: ['oliviertassinari', 'mbrookes', 'eps1lon'] tags: ['Material UI', 'Product'] -card: true +manualCard: true --- > React components for faster and simpler web development. Build your own design system, or start with Material Design. diff --git a/docs/pages/blog/matheus-wichman-joining.md b/docs/pages/blog/matheus-wichman-joining.md index 17ac52ad24e52b..8d9579d01873f0 100644 --- a/docs/pages/blog/matheus-wichman-joining.md +++ b/docs/pages/blog/matheus-wichman-joining.md @@ -4,7 +4,7 @@ description: We are excited to share that Matheus Wichman has joined MUI. date: 2021-04-05T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- We are excited to share that [Matheus Wichman](https://github.com/m4theushw) has joined MUI. diff --git a/docs/pages/blog/may-2019-update.md b/docs/pages/blog/may-2019-update.md index f8cf8fa3e259a1..9707d0f28b783d 100644 --- a/docs/pages/blog/may-2019-update.md +++ b/docs/pages/blog/may-2019-update.md @@ -4,7 +4,7 @@ description: Here are the most significant improvements in May. date: 2019-06-08T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- Here are the most significant improvements in May: diff --git a/docs/pages/blog/michal-dudak-joining.md b/docs/pages/blog/michal-dudak-joining.md index fe4c351bd27a09..4186fbcfc08548 100644 --- a/docs/pages/blog/michal-dudak-joining.md +++ b/docs/pages/blog/michal-dudak-joining.md @@ -4,7 +4,7 @@ description: We are excited to share that Michał Dudak has joined MUI. date: 2021-06-14T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- We are excited to share that [Michał Dudak](https://twitter.com/michaldudak) has joined MUI! diff --git a/docs/pages/blog/mui-core-v5-migration-update.md b/docs/pages/blog/mui-core-v5-migration-update.md index 04a9be054133ad..f050089780ec73 100644 --- a/docs/pages/blog/mui-core-v5-migration-update.md +++ b/docs/pages/blog/mui-core-v5-migration-update.md @@ -3,7 +3,7 @@ title: Why you should migrate to Material UI v5 today description: We have completely revamped our Migration guide to reduce friction when upgrading to v5. Get started now! date: 2022-06-20T00:00:00.000Z authors: ['samuelsycamore'] -card: true +manualCard: true tags: ['Material UI'] --- diff --git a/docs/pages/blog/mui-core-v5.md b/docs/pages/blog/mui-core-v5.md index 3692acffd9c502..7ebf76c989fdde 100644 --- a/docs/pages/blog/mui-core-v5.md +++ b/docs/pages/blog/mui-core-v5.md @@ -12,7 +12,7 @@ authors: 'danilo-leal', 'mbrookes', ] -card: true +manualCard: true tags: ['Product', 'Material UI'] --- diff --git a/docs/pages/blog/mui-next-js-app-router.md b/docs/pages/blog/mui-next-js-app-router.md index 344fc0faa7b52c..2c00e3dc372be3 100644 --- a/docs/pages/blog/mui-next-js-app-router.md +++ b/docs/pages/blog/mui-next-js-app-router.md @@ -3,7 +3,7 @@ title: MUI Core libraries support the Next.js App Router description: Material UI, Base UI, and Joy UI are now compatible with the App Router as Client Components. Get started using the latest Next.js features with MUI! date: 2023-07-18T00:00:00.000Z authors: ['samuelsycamore'] -card: true +manualCard: true tags: ['Product'] --- diff --git a/docs/pages/blog/mui-product-comparison.md b/docs/pages/blog/mui-product-comparison.md index 5268b3104d6e57..dfb8c4b542f939 100644 --- a/docs/pages/blog/mui-product-comparison.md +++ b/docs/pages/blog/mui-product-comparison.md @@ -3,7 +3,7 @@ title: An introduction to the MUI ecosystem description: MUI is more than just Material UI. Consider Joy UI, Base UI, MUI X, and Toolpad for your next project. date: 2022-11-01T00:00:00.000Z authors: ['samuelsycamore'] -card: true +manualCard: true tags: ['Product'] --- diff --git a/docs/pages/blog/mui-x-end-v6-features.md b/docs/pages/blog/mui-x-end-v6-features.md index 19dd6b95f107bc..e350c4af838be7 100644 --- a/docs/pages/blog/mui-x-end-v6-features.md +++ b/docs/pages/blog/mui-x-end-v6-features.md @@ -3,7 +3,7 @@ title: MUI X v6.18.0 and the latest features before the next major description: New components, polished features, better performance and more. date: 2023-11-13T00:00:00.000Z authors: ['josefreitas'] -card: true +manualCard: true tags: ['MUI X', 'Product'] --- diff --git a/docs/pages/blog/mui-x-mid-v6-features.md b/docs/pages/blog/mui-x-mid-v6-features.md index 64c7da76591a52..8348b66c7e2baa 100644 --- a/docs/pages/blog/mui-x-mid-v6-features.md +++ b/docs/pages/blog/mui-x-mid-v6-features.md @@ -3,7 +3,7 @@ title: MUI X v6.11.0. A roundup of all new features description: Support for time zones, Charts in alpha, Data Grid filtering, and more. date: 2023-08-14T00:00:00.000Z authors: ['richbustos', 'josefreitas'] -card: true +manualCard: true tags: ['MUI X', 'Product'] --- diff --git a/docs/pages/blog/mui-x-v5.md b/docs/pages/blog/mui-x-v5.md index 3e68847e5763e1..8ca2616041f276 100644 --- a/docs/pages/blog/mui-x-v5.md +++ b/docs/pages/blog/mui-x-v5.md @@ -4,7 +4,7 @@ description: We are excited to introduce MUI X v5.0.0! date: 2021-11-22T00:00:00.000Z authors: ['oliviertassinari', 'm4theushw', 'flaviendelangle', 'DanailH', 'alexfauquette'] -card: true +manualCard: true tags: ['MUI X', 'Product'] --- diff --git a/docs/pages/blog/mui-x-v6-alpha-zero.md b/docs/pages/blog/mui-x-v6-alpha-zero.md index eefcf84e50348f..de7976f967cfe6 100644 --- a/docs/pages/blog/mui-x-v6-alpha-zero.md +++ b/docs/pages/blog/mui-x-v6-alpha-zero.md @@ -4,7 +4,7 @@ description: Let us know what you want to see in MUI X v6 as we begin the alpha date: 2022-09-30T00:00:00.000Z authors: ['josefreitas'] tags: ['MUI X', 'Product'] -card: true +manualCard: true --- We're kicking off the development of [MUI X v6](https://github.com/mui/mui-x/releases/tag/v6.0.0-alpha.0). diff --git a/docs/pages/blog/mui-x-v6.md b/docs/pages/blog/mui-x-v6.md index 4b666d5c82b42a..06e97177a0f0c7 100644 --- a/docs/pages/blog/mui-x-v6.md +++ b/docs/pages/blog/mui-x-v6.md @@ -3,7 +3,7 @@ title: Introducing MUI X v6 description: Introducing the new major version of the advanced components. date: 2023-03-06T00:00:00.000Z authors: ['josefreitas'] -card: true +manualCard: true tags: ['MUI X', 'Product'] --- diff --git a/docs/pages/blog/mui-x-v7-beta.md b/docs/pages/blog/mui-x-v7-beta.md index 258a29b7fc57e7..f32df9cab0212e 100644 --- a/docs/pages/blog/mui-x-v7-beta.md +++ b/docs/pages/blog/mui-x-v7-beta.md @@ -4,7 +4,7 @@ description: Check out what's new and what's next for v7 stable. date: 2024-01-29T00:00:00.000Z authors: ['josefreitas'] tags: ['MUI X', 'Product'] -card: true +manualCard: true ---
diff --git a/docs/pages/blog/mui-x-v7.md b/docs/pages/blog/mui-x-v7.md index 78c117c40bfb6f..0339fd10e632af 100644 --- a/docs/pages/blog/mui-x-v7.md +++ b/docs/pages/blog/mui-x-v7.md @@ -4,7 +4,7 @@ description: Check out all the newest additions to the next major of the advance date: 2024-03-22T08:00:00.000Z authors: ['josefreitas'] tags: ['MUI X', 'Product'] -card: true +manualCard: true ---
diff --git a/docs/pages/blog/november-2019-update.md b/docs/pages/blog/november-2019-update.md index fc9f1bf498ab4d..afb3cbff843fc9 100644 --- a/docs/pages/blog/november-2019-update.md +++ b/docs/pages/blog/november-2019-update.md @@ -4,7 +4,7 @@ description: Here are the most significant improvements in November. date: 2019-12-12T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- Here are the most significant improvements in November: diff --git a/docs/pages/blog/october-2019-update.md b/docs/pages/blog/october-2019-update.md index 7644683613f25d..d5b3c21f260dda 100644 --- a/docs/pages/blog/october-2019-update.md +++ b/docs/pages/blog/october-2019-update.md @@ -4,7 +4,7 @@ description: Here are the most significant improvements in October. date: 2019-11-08T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- Here are the most significant improvements in October: diff --git a/docs/pages/blog/premium-plan-release.md b/docs/pages/blog/premium-plan-release.md index 4d5166c36c263f..d7ab992827f551 100644 --- a/docs/pages/blog/premium-plan-release.md +++ b/docs/pages/blog/premium-plan-release.md @@ -4,7 +4,7 @@ description: Introducing the MUI X Premium plan, and a new licensing model. date: 2022-05-12T00:00:00.000Z authors: ['josefreitas', 'alexfauquette'] tags: ['MUI X', 'Product'] -card: true +manualCard: true --- We're happy to announce that the Premium plan is [finally out](https://mui.com/pricing/)! diff --git a/docs/pages/blog/remote-award-win-2024.md b/docs/pages/blog/remote-award-win-2024.md index d41c7702449788..47dc8fc0c426a6 100644 --- a/docs/pages/blog/remote-award-win-2024.md +++ b/docs/pages/blog/remote-award-win-2024.md @@ -4,7 +4,7 @@ description: We're delighted to be honored with this global recognition for our date: 2024-03-20T12:00:00.000Z authors: ['mikailaread'] tags: ['Company'] -card: true +manualCard: true --- MUI has been named a **winner** in the first-ever [Remote Excellence Awards](https://remote.com/remote-excellence-awards/), in the Small & Mighty category! 🎉 diff --git a/docs/pages/blog/september-2019-update.md b/docs/pages/blog/september-2019-update.md index 851cda97d166b7..55c9c442b742f5 100644 --- a/docs/pages/blog/september-2019-update.md +++ b/docs/pages/blog/september-2019-update.md @@ -4,7 +4,7 @@ description: Here are the most significant improvements in September. date: 2019-10-12T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- Here are the most significant improvements in September: diff --git a/docs/pages/blog/siriwat-kunaporn-joining.md b/docs/pages/blog/siriwat-kunaporn-joining.md index c858b89ccf4e33..2150a1835d1760 100644 --- a/docs/pages/blog/siriwat-kunaporn-joining.md +++ b/docs/pages/blog/siriwat-kunaporn-joining.md @@ -4,7 +4,7 @@ description: We are excited to share that Siriwat Kunaporn has joined MUI. date: 2021-05-17T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- We are excited to share that [Siriwat Kunaporn](https://twitter.com/siriwatknp) (Jun) has joined MUI. diff --git a/docs/pages/blog/spotlight-damien-tassone.md b/docs/pages/blog/spotlight-damien-tassone.md index 6952fe623e1c35..8dc08dd0c823e6 100644 --- a/docs/pages/blog/spotlight-damien-tassone.md +++ b/docs/pages/blog/spotlight-damien-tassone.md @@ -4,7 +4,7 @@ description: Damien Tassone has joined MUI. He's the first full-time member to f date: 2020-09-15T00:00:00.000Z authors: ['oliviertassinari'] tags: ['Company'] -card: true +manualCard: true --- A few months ago, right in the middle of the COVID-19 outbreak, [Damien Tassone](https://twitter.com/madKakoO) joined MUI. He's the first full-time member to focus on enterprise components. Back then, we only made a quick mention of it. It's never too late to introduce him properly. diff --git a/docs/pages/blog/toolpad-use-cases.md b/docs/pages/blog/toolpad-use-cases.md index 30879950a648e4..30cc0ffd7ddd26 100644 --- a/docs/pages/blog/toolpad-use-cases.md +++ b/docs/pages/blog/toolpad-use-cases.md @@ -3,7 +3,7 @@ title: How does MUI use Toolpad? description: Explore how we use Toolpad for production use cases at MUI. date: 2024-03-04T00:00:00.000Z authors: ['prakhargupta'] -card: true +manualCard: true tags: ['Product', 'Toolpad'] --- diff --git a/docs/pages/blog/v6-beta-pickers.md b/docs/pages/blog/v6-beta-pickers.md index 8ceeca29aa63cf..22f03ed385fd00 100644 --- a/docs/pages/blog/v6-beta-pickers.md +++ b/docs/pages/blog/v6-beta-pickers.md @@ -4,7 +4,7 @@ description: Check out the new features coming in v6 beta. date: 2023-01-22T00:00:00.000Z authors: ['josefreitas'] tags: ['MUI X', 'Product'] -card: true +manualCard: true --- There's a lot of exciting news in [MUI X v6.0.0-beta.0](https://github.com/mui/mui-x/releases/v6.0.0-beta.0), but there's hardly anything comparable to the revamp we're delivering for the Date and Time Pickers. diff --git a/docs/pages/experiments/blog/blog-custom-card.md b/docs/pages/experiments/blog/blog-custom-card.md index 5751e17acac0cf..1c26c97454e62d 100644 --- a/docs/pages/experiments/blog/blog-custom-card.md +++ b/docs/pages/experiments/blog/blog-custom-card.md @@ -4,7 +4,7 @@ description: Our internationally distributed startup gathered on a remote island date: 2022-07-28T00:00:00.000Z authors: ['alexfauquette'] tags: ['Company'] -card: false +manualCard: false cardTitle: blog with\n*custom* card --- diff --git a/docs/pages/experiments/blog/blog.md b/docs/pages/experiments/blog/blog.md index eb2972c6bbe833..42c229e45f99c0 100644 --- a/docs/pages/experiments/blog/blog.md +++ b/docs/pages/experiments/blog/blog.md @@ -4,7 +4,7 @@ description: Our internationally distributed startup gathered on a remote island date: 2022-07-28T00:00:00.000Z authors: ['samuelsycamore'] tags: ['Company'] -card: false +manualCard: false --- ## Description From ab4d35dd07f1dad74a69d88ad5da3e90a68fdfa8 Mon Sep 17 00:00:00 2001 From: alexandre Date: Fri, 29 Mar 2024 14:45:39 +0100 Subject: [PATCH 19/28] always use large card for blog post --- docs/src/modules/components/TopLayoutBlog.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/src/modules/components/TopLayoutBlog.js b/docs/src/modules/components/TopLayoutBlog.js index 92cadaf5996c9f..3290a6ce10894c 100644 --- a/docs/src/modules/components/TopLayoutBlog.js +++ b/docs/src/modules/components/TopLayoutBlog.js @@ -270,7 +270,7 @@ export default function TopLayoutBlog(props) { const slug = router.pathname.replace(/(.*)\/(.*)/, '$2'); const { canonicalAsServer } = pathnameToLanguage(router.asPath); const card = - headers.card === 'true' + headers.manualCard === 'true' ? `https://mui.com/static/blog/${slug}/card.png` : `/edge-functions/og-image/?title=${headers.cardTitle || finalTitle}&authors=${headers.authors .map((author) => { @@ -280,11 +280,11 @@ export default function TopLayoutBlog(props) { .join(',')}&product=Blog`; if (process.env.NODE_ENV !== 'production') { - if (headers.card === undefined) { + if (headers.manualCard === undefined) { throw new Error( [ - `MUI: the "card" markdown header for the blog post "${slug}" is missing.`, - `Set card: true or card: false header in docs/pages/blog/${slug}.md.`, + `MUI: the "manualCard" markdown header for the blog post "${slug}" is missing.`, + `Set manualCard: true or manualCard: false header in docs/pages/blog/${slug}.md.`, ].join('\n'), ); } @@ -296,7 +296,7 @@ export default function TopLayoutBlog(props) { Date: Fri, 29 Mar 2024 15:16:28 +0100 Subject: [PATCH 20/28] Add description --- docs/src/modules/components/AppLayoutDocs.js | 2 +- netlify/edge-functions/og-image.tsx | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/src/modules/components/AppLayoutDocs.js b/docs/src/modules/components/AppLayoutDocs.js index c3477cec1cec4f..8b4bae84ac5650 100644 --- a/docs/src/modules/components/AppLayoutDocs.js +++ b/docs/src/modules/components/AppLayoutDocs.js @@ -137,7 +137,7 @@ export default function AppLayoutDocs(props) { const Layout = disableLayout ? React.Fragment : AppFrame; const layoutProps = disableLayout ? {} : { BannerComponent }; - const card = `/edge-functions/og-image?product=${productName}&title=${title}`; + const card = `/edge-functions/og-image?product=${productName}&title=${title}&description=${description}`; return ( ))} + {description && ( +

+ {description} +

+ )}
Date: Fri, 29 Mar 2024 16:04:57 +0100 Subject: [PATCH 21/28] add IBM font Co-authored-by: Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Signed-off-by: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> --- netlify/edge-functions/og-image.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx index e8666e15f89535..61a30feaa9e7b4 100644 --- a/netlify/edge-functions/og-image.tsx +++ b/netlify/edge-functions/og-image.tsx @@ -126,10 +126,12 @@ export default async function handler(req: Request) { {description && (

a.arrayBuffer(), ), - weight: 1000, + weight: 600, style: 'normal', }, { From b20e681b3ee32d17e0f1c299913e5216d0ddd2a2 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:30:24 +0200 Subject: [PATCH 22/28] Update netlify/edge-functions/og-image.tsx Signed-off-by: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> --- netlify/edge-functions/og-image.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx index 61a30feaa9e7b4..868f056b2d0a0e 100644 --- a/netlify/edge-functions/og-image.tsx +++ b/netlify/edge-functions/og-image.tsx @@ -226,7 +226,7 @@ export default async function handler(req: Request) { // debug: true, fonts: [ { - name: 'General Sans', + name: 'IBM Plex Sans', data: await fetch('https://fonts.cdnfonts.com/s/15449/IBMPlexSans-SemiBold.woff').then( (a) => a.arrayBuffer(), ), From 50f3802ccae2c7cc46b84b83d3b6a92bc13fb710 Mon Sep 17 00:00:00 2001 From: alexandre Date: Wed, 3 Apr 2024 08:25:39 +0200 Subject: [PATCH 23/28] modify font-size --- netlify/edge-functions/og-image.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx index 868f056b2d0a0e..7ec42e849b965a 100644 --- a/netlify/edge-functions/og-image.tsx +++ b/netlify/edge-functions/og-image.tsx @@ -93,8 +93,8 @@ export default async function handler(req: Request) { fontFamily: 'General Sans', fontStyle: 'normal', fontWeight: 600, - fontSize: '68px', - lineHeight: '82px', + fontSize: '46px', + lineHeight: '70px', color: '#0B0D0E', display: 'flex', flexDirection: 'column', @@ -127,10 +127,10 @@ export default async function handler(req: Request) {

Date: Wed, 3 Apr 2024 08:55:45 +0200 Subject: [PATCH 24/28] refine the card generation docs --- docs/pages/experiments/docs/og-card.js | 7 +++++ docs/pages/experiments/docs/og-card.md | 29 +++++++++++++++++++ docs/src/modules/components/AppLayoutDocs.js | 7 ++++- docs/src/modules/components/MarkdownDocs.js | 4 +++ docs/src/modules/components/MarkdownDocsV2.js | 4 +++ .../modules/utils/getProductInfoFromUrl.ts | 1 - 6 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 docs/pages/experiments/docs/og-card.js create mode 100644 docs/pages/experiments/docs/og-card.md diff --git a/docs/pages/experiments/docs/og-card.js b/docs/pages/experiments/docs/og-card.js new file mode 100644 index 00000000000000..3c3ab187e0adcf --- /dev/null +++ b/docs/pages/experiments/docs/og-card.js @@ -0,0 +1,7 @@ +import * as React from 'react'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import * as pageProps from './og-card.md?muiMarkdown'; + +export default function Page() { + return ; +} diff --git a/docs/pages/experiments/docs/og-card.md b/docs/pages/experiments/docs/og-card.md new file mode 100644 index 00000000000000..76d39d966c08e1 --- /dev/null +++ b/docs/pages/experiments/docs/og-card.md @@ -0,0 +1,29 @@ +--- +title: OG card generation +cardDescription: A quick overview of available options. +--- + +# OG card + +

How the docs generate og-cards

+ +## The edge function + +The url `mui.com/edge-functions/og-image` can be query with 4 search parameters: + +- product: The text displayed next to the MUI logo +- title: the title which can contains \* to delimit the highlighted text sections +- description: a paragraph added under the main title +- authors: the GitHub username of the authors, divided by a coma. + +## Usage with markdown + +By default the card will be generated by using the page title and its description. +You can override this behavior by providing `cardTitle` and `cardDescription` in the markdown header. + +```markup +--- +cardTitle: A *custom* title to use +cardDecription: The word "custom" is highlighted with blue +--- +``` diff --git a/docs/src/modules/components/AppLayoutDocs.js b/docs/src/modules/components/AppLayoutDocs.js index 8b4bae84ac5650..c343c6b3338147 100644 --- a/docs/src/modules/components/AppLayoutDocs.js +++ b/docs/src/modules/components/AppLayoutDocs.js @@ -101,6 +101,7 @@ export default function AppLayoutDocs(props) { const router = useRouter(); const { BannerComponent, + cardOptions, children, description, disableAd = false, @@ -137,7 +138,7 @@ export default function AppLayoutDocs(props) { const Layout = disableLayout ? React.Fragment : AppFrame; const layoutProps = disableLayout ? {} : { BannerComponent }; - const card = `/edge-functions/og-image?product=${productName}&title=${title}&description=${description}`; + const card = `/edge-functions/og-image?product=${productName}&title=${cardOptions?.title ?? title}&description=${cardOptions?.description ?? description}`; return ( Date: Wed, 3 Apr 2024 09:20:22 +0200 Subject: [PATCH 25/28] fix typos --- docs/pages/experiments/docs/og-card.md | 4 ++-- docs/src/modules/components/MarkdownDocs.js | 2 +- docs/src/modules/components/MarkdownDocsV2.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/pages/experiments/docs/og-card.md b/docs/pages/experiments/docs/og-card.md index 76d39d966c08e1..b1fb453afc89c2 100644 --- a/docs/pages/experiments/docs/og-card.md +++ b/docs/pages/experiments/docs/og-card.md @@ -22,8 +22,8 @@ By default the card will be generated by using the page title and its descriptio You can override this behavior by providing `cardTitle` and `cardDescription` in the markdown header. ```markup ---- +-- cardTitle: A *custom* title to use cardDecription: The word "custom" is highlighted with blue ---- +-- ``` diff --git a/docs/src/modules/components/MarkdownDocs.js b/docs/src/modules/components/MarkdownDocs.js index 6333567f4aff1f..b0d0d72b4f7f3b 100644 --- a/docs/src/modules/components/MarkdownDocs.js +++ b/docs/src/modules/components/MarkdownDocs.js @@ -54,7 +54,7 @@ export default function MarkdownDocs(props) { return ( Date: Wed, 3 Apr 2024 09:22:06 +0200 Subject: [PATCH 26/28] add in the nav bar --- docs/data/docs-infra/pages.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/data/docs-infra/pages.ts b/docs/data/docs-infra/pages.ts index 0cd74435bba91f..a4c653c9a39f86 100644 --- a/docs/data/docs-infra/pages.ts +++ b/docs/data/docs-infra/pages.ts @@ -7,6 +7,7 @@ const pages: readonly MuiPage[] = [ children: [ { pathname: '/experiments/docs/headers' }, { pathname: '/experiments/docs/markdown' }, + { pathname: '/experiments/docs/og-card' }, ], }, { From 0e9d920ee8f1f15d18a1b0f2b8fb64ed43bda342 Mon Sep 17 00:00:00 2001 From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Date: Wed, 3 Apr 2024 19:46:28 -0300 Subject: [PATCH 27/28] tweak documentation --- docs/pages/experiments/docs/og-card.md | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/docs/pages/experiments/docs/og-card.md b/docs/pages/experiments/docs/og-card.md index b1fb453afc89c2..4a169ff15df2f4 100644 --- a/docs/pages/experiments/docs/og-card.md +++ b/docs/pages/experiments/docs/og-card.md @@ -5,25 +5,29 @@ cardDescription: A quick overview of available options. # OG card -

How the docs generate og-cards

+

How the docs platform generate Open Graph card images

## The edge function -The url `mui.com/edge-functions/og-image` can be query with 4 search parameters: +The URL `mui.com/edge-functions/og-image` can be queried with 4 search parameters: -- product: The text displayed next to the MUI logo -- title: the title which can contains \* to delimit the highlighted text sections -- description: a paragraph added under the main title -- authors: the GitHub username of the authors, divided by a coma. +- `product`: the text element displayed next to the MUI logo +- `title`: the title which can contains `\*` to delimit the highlighted (in blue) text sections +- `description`: a paragraph added under the main title +- `authors`: the GitHub username of the authors. It should be divided by a coma. -## Usage with markdown +## Usage with Markdown -By default the card will be generated by using the page title and its description. -You can override this behavior by providing `cardTitle` and `cardDescription` in the markdown header. +By default, the card is generated using the page title and description. +You can override this behavior by providing different/specific `cardTitle` and `cardDescription` in the Markdown header, like so: ```markup -- -cardTitle: A *custom* title to use -cardDecription: The word "custom" is highlighted with blue +cardTitle: A *different* title than the page title +cardDecription: The word "different" on the title is highlighted -- ``` + +## Card design preview + +Visit [this StackBlitz demo](https://stackblitz.com/edit/vitejs-vite-ukeejd?file=src%2FApp.tsx) to see how the card looks like without having to run a random page on an OG preview site. From a570b9a5c43cdce0716511d103c5bde7418676db Mon Sep 17 00:00:00 2001 From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Date: Wed, 3 Apr 2024 19:46:34 -0300 Subject: [PATCH 28/28] fine-tune the OG card design --- netlify/edge-functions/og-image.tsx | 48 ++++++++++++++++------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx index 7ec42e849b965a..43c6eab58a42e7 100644 --- a/netlify/edge-functions/og-image.tsx +++ b/netlify/edge-functions/og-image.tsx @@ -54,18 +54,14 @@ export default async function handler(req: Request) { alignItems: 'center', }} > - + +
{title && title.split('\\n').map((line) => ( -

+

{line.split('*').flatMap((text, index) => { if (index > 0) { starCount += 1; @@ -129,9 +131,9 @@ export default async function handler(req: Request) { fontFamily: 'IBM Plex Sans', fontSize: '28px', fontWeight: 600, - color: '#434D5B', + color: '#303740', lineHeight: '50px', - marginTop: 24, + marginTop: 12, marginBottom: 0, marginLeft: 0, marginRight: 0, @@ -192,9 +194,10 @@ export default async function handler(req: Request) { >