diff --git a/packages/dev/s2-docs/pages/error.mdx b/packages/dev/s2-docs/pages/error.mdx index 82201a6dc99..fbffab8eeab 100644 --- a/packages/dev/s2-docs/pages/error.mdx +++ b/packages/dev/s2-docs/pages/error.mdx @@ -5,5 +5,6 @@ export default Layout; import docs from 'docs:@react-spectrum/s2'; export const hideFromSearch = true; +export const description = 'Page not found'; diff --git a/packages/dev/s2-docs/pages/internationalized/date/index.mdx b/packages/dev/s2-docs/pages/internationalized/date/index.mdx index 338e75aae47..a1b76f4d827 100644 --- a/packages/dev/s2-docs/pages/internationalized/date/index.mdx +++ b/packages/dev/s2-docs/pages/internationalized/date/index.mdx @@ -13,6 +13,8 @@ export default Layout; import {InstallCommand} from '../../../src/InstallCommand'; export const section = 'Date and Time'; +export const pageTitle = 'Internationalized | Date and Time'; +export const description = 'Introduction to @internationalized/date'; # Introduction diff --git a/packages/dev/s2-docs/pages/internationalized/number/index.mdx b/packages/dev/s2-docs/pages/internationalized/number/index.mdx index 67db911d372..4d91a1c507d 100644 --- a/packages/dev/s2-docs/pages/internationalized/number/index.mdx +++ b/packages/dev/s2-docs/pages/internationalized/number/index.mdx @@ -13,6 +13,8 @@ export default Layout; import {InstallCommand} from '../../../src/InstallCommand'; export const section = 'Numbers'; +export const pageTitle = 'Internationalized | Numbers'; +export const description = 'Introduction to @internationalized/number'; # Introduction diff --git a/packages/dev/s2-docs/pages/react-aria/collections.mdx b/packages/dev/s2-docs/pages/react-aria/collections.mdx index 820768f3fc7..733241582e9 100644 --- a/packages/dev/s2-docs/pages/react-aria/collections.mdx +++ b/packages/dev/s2-docs/pages/react-aria/collections.mdx @@ -5,6 +5,7 @@ import docs from 'docs:react-aria-components'; import {InlineAlert, Heading, Content} from '@react-spectrum/s2' export const section = 'Guides'; +export const description = 'Implementing collections in React Aria'; # Collections diff --git a/packages/dev/s2-docs/pages/react-aria/dnd.mdx b/packages/dev/s2-docs/pages/react-aria/dnd.mdx index ef95686aefd..7c4eea7874c 100644 --- a/packages/dev/s2-docs/pages/react-aria/dnd.mdx +++ b/packages/dev/s2-docs/pages/react-aria/dnd.mdx @@ -13,6 +13,7 @@ import {PokemonListBox} from './PokemonListBox'; import {PokemonGridList} from './PokemonGridList'; export const section = 'Guides'; +export const description = 'Implementing drag and drop in React Aria'; # Drag and Drop diff --git a/packages/dev/s2-docs/pages/react-aria/selection.mdx b/packages/dev/s2-docs/pages/react-aria/selection.mdx index 44ee6a777f8..c7800d9ed3e 100644 --- a/packages/dev/s2-docs/pages/react-aria/selection.mdx +++ b/packages/dev/s2-docs/pages/react-aria/selection.mdx @@ -4,6 +4,7 @@ export default Layout; import docs from 'docs:react-aria-components'; export const section = 'Guides'; +export const description = 'Implementing selection in React Aria'; # Selection diff --git a/packages/dev/s2-docs/pages/react-aria/styling.mdx b/packages/dev/s2-docs/pages/react-aria/styling.mdx index bbe1422e335..1c11d96bf68 100644 --- a/packages/dev/s2-docs/pages/react-aria/styling.mdx +++ b/packages/dev/s2-docs/pages/react-aria/styling.mdx @@ -5,6 +5,7 @@ export default Layout; import {Disclosure, DisclosureTitle, DisclosurePanel} from '@react-spectrum/s2'; export const section = 'Guides'; +export const description = 'Styling in React Aria'; # Styling diff --git a/packages/dev/s2-docs/pages/s2/collections.mdx b/packages/dev/s2-docs/pages/s2/collections.mdx index 8dacb61c5c7..8c41d643502 100644 --- a/packages/dev/s2-docs/pages/s2/collections.mdx +++ b/packages/dev/s2-docs/pages/s2/collections.mdx @@ -3,8 +3,8 @@ import {InlineAlert, Heading, Content} from '@react-spectrum/s2'; export default Layout; export const section = 'Guides'; - export const tags = ['lists']; +export const description = 'Implementing collections in React Spectrum'; # Collections diff --git a/packages/dev/s2-docs/pages/s2/dnd.mdx b/packages/dev/s2-docs/pages/s2/dnd.mdx index 63b2ecfd2df..f96c8231499 100644 --- a/packages/dev/s2-docs/pages/s2/dnd.mdx +++ b/packages/dev/s2-docs/pages/s2/dnd.mdx @@ -3,8 +3,8 @@ import {InlineAlert, Heading, Content} from '@react-spectrum/s2'; export default Layout; export const section = 'Guides'; - export const tags = ['drag', 'drop']; +export const description = 'Implementing drag and drop in React Spectrum'; # Drag and Drop diff --git a/packages/dev/s2-docs/pages/s2/getting-started.mdx b/packages/dev/s2-docs/pages/s2/getting-started.mdx index 87741997513..13ea383c07f 100644 --- a/packages/dev/s2-docs/pages/s2/getting-started.mdx +++ b/packages/dev/s2-docs/pages/s2/getting-started.mdx @@ -6,6 +6,7 @@ import {SegmentedControl, SegmentedControlItem} from '@react-spectrum/s2'; export const section = 'Getting started'; export const tags = ['introduction', 'installation']; +export const description = 'Getting started with React Spectrum'; # Getting started diff --git a/packages/dev/s2-docs/pages/s2/migrating.mdx b/packages/dev/s2-docs/pages/s2/migrating.mdx index 1b42d053070..be6cd9cb4c9 100644 --- a/packages/dev/s2-docs/pages/s2/migrating.mdx +++ b/packages/dev/s2-docs/pages/s2/migrating.mdx @@ -6,6 +6,7 @@ export default Layout; export const section = 'Guides'; export const tags = ['codemod', 'upgrade', 'update']; +export const description = 'Migrating to Spectrum 2 in React Spectrum'; # Migrating to Spectrum 2 diff --git a/packages/dev/s2-docs/pages/s2/release-notes.mdx b/packages/dev/s2-docs/pages/s2/release-notes.mdx index 1f6cc33097d..70f73c8765e 100644 --- a/packages/dev/s2-docs/pages/s2/release-notes.mdx +++ b/packages/dev/s2-docs/pages/s2/release-notes.mdx @@ -3,6 +3,7 @@ export default Layout; export const section = 'Releases'; export const tags = ['changelog', 'versions', 'updates']; +export const description = 'Release notes for React Spectrum'; # Release Notes diff --git a/packages/dev/s2-docs/pages/s2/selection.mdx b/packages/dev/s2-docs/pages/s2/selection.mdx index 2bc589dd40e..7a54a0897d4 100644 --- a/packages/dev/s2-docs/pages/s2/selection.mdx +++ b/packages/dev/s2-docs/pages/s2/selection.mdx @@ -4,6 +4,7 @@ export default Layout; export const section = 'Guides'; export const tags = ['collections']; +export const description = 'Implementing selection in React Spectrum'; # Selection diff --git a/packages/dev/s2-docs/pages/s2/styling.mdx b/packages/dev/s2-docs/pages/s2/styling.mdx index 59e257b206d..3735835c868 100644 --- a/packages/dev/s2-docs/pages/s2/styling.mdx +++ b/packages/dev/s2-docs/pages/s2/styling.mdx @@ -7,6 +7,7 @@ export default Layout; export const section = 'Guides'; export const tags = ['style', 'macro', 'spectrum', 'custom']; +export const description = 'Styling in React Spectrum'; # Styling diff --git a/packages/dev/s2-docs/scripts/generateOGImages.mjs b/packages/dev/s2-docs/scripts/generateOGImages.mjs index 3d99587262b..aac8b044589 100644 --- a/packages/dev/s2-docs/scripts/generateOGImages.mjs +++ b/packages/dev/s2-docs/scripts/generateOGImages.mjs @@ -10,26 +10,6 @@ const __dirname = path.dirname(__filename); const pagesDir = path.resolve(__dirname, '../pages'); const outputDir = path.resolve(__dirname, '../dist/og'); -const illustrationsDir = path.resolve(__dirname, '../../docs/pages/assets/component-illustrations'); - -const cssVariables = { - '--anatomy-gray-50': '#FFFFFF', - '--anatomy-gray-75': '#FDFDFE', - '--anatomy-gray-100': '#f4f6fc', - '--anatomy-gray-200': '#E5EBF7', - '--anatomy-gray-300': '#DAE2F4', - '--anatomy-gray-400': '#beccea', - '--anatomy-gray-500': '#a2b6e1', - '--anatomy-gray-600': '#718dcf', - '--anatomy-gray-700': '#4a6fc3', - '--anatomy-gray-800': '#496EC2', - '--anatomy-gray-900': '#486EC2', - '--spectrum-global-color-gray-300': '#d3d3d3', - '--spectrum-global-color-gray-400': '#bcbcbc', - '--spectrum-global-color-gray-700': '#464646', - '--spectrum-alias-border-color-focus': '#0f62fe', - '--anatomy-font': 'adobe-clean' -}; async function getMdxFiles(dir) { let entries = await fs.readdir(dir, {withFileTypes: true}); @@ -53,7 +33,11 @@ async function getTitle(filePath) { } let match = parsed.content.match(/^#\s+(.+)$/m); if (match) { - return match[1].trim(); + let title = match[1].trim(); + // Strip out any React components (like ) + title = title.replace(/<[A-Z]\w*[^>]*\/>/g, '').trim(); + title = title.replace(/<[A-Z]\w*[^>]*>.*?<\/[A-Z]\w*>/g, '').trim(); + return title; } return path.basename(filePath, path.extname(filePath)); } @@ -89,42 +73,149 @@ const [adobeCleanRegular, adobeCleanBold] = await Promise.all([ loadFont('https://use.typekit.net/af/eaf09c/000000000000000000017703/27/d?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=n7&v=3') ]); -// Mappings for components that don't match their SVG file names -const componentSvgExceptions = { - 'GridList': 'ListView.svg', - 'Select': 'Picker.svg', - 'Drag and Drop': 'DragAndDrop.svg' -}; - -async function getComponentSvg(title) { - // First try exception mappings - let svgFileName = componentSvgExceptions[title]; - - // If no exception mapping, try automatic name matching - if (!svgFileName) { - svgFileName = `${title}.svg`; - } - - try { - const svgPath = path.join(illustrationsDir, svgFileName); - let svgContent = await fs.readFile(svgPath, 'utf8'); - - // Replace CSS variables with actual colors - for (const [variable, color] of Object.entries(cssVariables)) { - svgContent = svgContent.replace(new RegExp(`var\\(${variable.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\)`, 'g'), color); - } - - // Replace SVG background to match container background - svgContent = svgContent.replace(/background:\s*var\(--anatomy-gray-100\)/g, 'background: #f8f8f8'); - svgContent = svgContent.replace(/background:\s*#f4f6fc/g, 'background: #f8f8f8'); - svgContent = svgContent.replace(/var\(--anatomy-font\)/g, 'adobe-clean'); - - // Convert SVG to data URI for use as image source - const svgBase64 = Buffer.from(svgContent).toString('base64'); - return `data:image/svg+xml;base64,${svgBase64}`; - } catch (error) { - console.warn(`Could not load SVG for ${title}: ${error.message}`); - return null; +function getLibraryLogo(subtitle) { + if (subtitle === 'React Aria') { + return { + type: 'svg', + props: { + width: 156, + height: 150, + viewBox: '15.79 17.64 131.21 126.14', + xmlns: 'http://www.w3.org/2000/svg', + children: [ + { + type: 'defs', + props: { + children: { + type: 'clipPath', + props: { + id: 'a', + children: { + type: 'path', + props: { + d: 'M80 136c30.93 0 56-25.07 56-56s-25.07-56-56-56-56 25.07-56 56 25.07 56 56 56Zm8.48-86.3c0 4.69-3.8 8.48-8.48 8.48s-8.48-3.8-8.48-8.48 3.8-8.48 8.48-8.48 8.48 3.8 8.48 8.48ZM51.09 61.78c.52-1.8 2.39-2.85 4.2-2.33a89.865 89.865 0 0 0 48.82.17l.64-.18c1.81-.5 3.68.55 4.18 2.36a3.39 3.39 0 0 1-2.36 4.18l-.64.18a97.139 97.139 0 0 1-15.51 2.98c-1.03.11-1.82.97-1.82 2.01v14.89c0 .18.03.37.08.55 1.37 4.83 2.94 10.39 4.32 15.27.98 3.46 1.86 6.58 2.49 8.85.32 1.14.58 2.06.76 2.71l.04.15c.13.48.27.97.31 1.16a3.38 3.38 0 0 1-2.66 3.99 3.38 3.38 0 0 1-3.99-2.66c.02.09 0 .04-.08-.27-.04-.13-.09-.31-.15-.54-.18-.65-.44-1.57-.76-2.7-.64-2.27-1.52-5.39-2.49-8.85l-3.74-13.21a1.992 1.992 0 0 0-1.92-1.45h-1.6c-.89 0-1.68.59-1.92 1.45-1.22 4.3-2.55 9.01-3.74 13.21-.98 3.46-1.85 6.58-2.49 8.85-.32 1.13-.58 2.06-.76 2.7-.06.23-.11.41-.15.54-.09.31-.1.36-.08.27a3.39 3.39 0 1 1-6.65-1.33c.04-.18.18-.68.31-1.16l.04-.15c.18-.65.44-1.58.76-2.71.64-2.27 1.52-5.39 2.49-8.85 1.38-4.88 2.95-10.44 4.32-15.27.05-.18.08-.36.08-.55V71.16c0-1.04-.79-1.9-1.82-2.01a96.504 96.504 0 0 1-16.17-3.17 3.395 3.395 0 0 1-2.33-4.2Z', + fill: 'none' + } + } + } + } + } + }, + { + type: 'circle', + props: { + cx: 80, + cy: 80, + r: 50.83, + fill: '#fff' + } + }, + { + type: 'g', + props: { + clipPath: 'url(#a)', + children: { + type: 'path', + props: { + d: 'M15.79 17.64H147v126.14H15.79z', + fill: '#269ff4' + } + } + } + } + ] + } + }; + } else if (subtitle === 'Internationalized') { + return { + type: 'svg', + props: { + width: 156, + height: 148, + viewBox: '15 17 135 128', + xmlns: 'http://www.w3.org/2000/svg', + children: [ + { + type: 'defs', + props: { + children: [ + { + type: 'clipPath', + props: { + id: 'b', + children: { + type: 'path', + props: { + d: 'M23.98 79.99c0-17.01 7.58-32.25 19.54-42.52.92 2.02 2.32 4.67 4 7.13 1.05 1.54 2.28 3.1 3.65 4.41 1.33 1.27 3.04 2.55 5.08 3.13 3.29.94 7.1.8 9.98.7l.88-.03c1.63-.05 2.94-.07 4.03.05 1.11.11 1.57.33 1.71.42.31.2.39.37.41.43.03.08.07.22.03.46-.09.52-.53 1.28-1.4 1.76-2.07 1.15-4.14 2.6-5.69 4.59-1.63 2.09-2.54 4.6-2.54 7.55 0 .86-.07 1.4-.15 1.72v.03c-.28.06-.81.1-1.7.03-.27-.02-.55-.05-.86-.07-2.32-.21-5.69-.5-8.87-.17-3.54.37-8.1 1.64-10.56 5.96-1.08 1.89-2.33 5.04-2.03 8.8.31 3.92 2.27 7.99 6.71 11.55 5.12 4.1 10.75 4.98 18.12 5.8 4.2.47 6.58 1.37 7.94 2.33 1.19.84 1.85 1.9 2.18 3.55.58 2.88-.4 7.19-2.43 12.45-.97 2.52-2.11 5.05-3.24 7.52-.25.54-.5 1.08-.74 1.61-.81 1.76-1.61 3.47-2.27 5.03C41.73 127.9 24 106.03 24 80.02Zm26.36-46.91c-.07-.17-.15-.33-.24-.49a55.64 55.64 0 0 1 12.37-5.84c.05.3.14.6.26.89 2.06 4.9 8.3 10.94 16.68 10.94 4.33 0 7.8-1.86 10.35-3.97 2.53-2.1 4.34-4.6 5.47-6.33.41-.63.62-1.34.65-2.04.69.2 1.37.42 2.05.65-.06.18-.1.37-.13.57-.67 4.46-1.44 10.7-.74 16.34.69 5.54 3.01 11.91 9.76 14.25 5.36 1.86 10.66.94 14.8-.9 2.74-1.22 5.23-2.96 7.07-4.9 2.11 3.7 3.81 7.65 5.04 11.81l-1.75-.36c-3.01-.59-7.06-1.26-11.28-1.54-4.16-.28-8.77-.19-12.78.91-4.02 1.1-8.1 3.44-9.84 8.13-4.86 13.11 1.7 21.06 3.39 22.75 2.55 2.55 5.17 3.75 7.1 4.62.23.11.46.21.67.31 1.86.87 3.19 1.63 4.54 3.58.47.67.94 1.89 1.3 3.74.34 1.8.52 3.89.58 6.11.07 2.2.02 4.41-.04 6.43l-.06 1.63c-.04 1.08-.07 2.1-.09 2.95a55.775 55.775 0 0 1-35.48 12.67c-2.09 0-4.15-.11-6.18-.34.44-.97.91-1.99 1.41-3.08.26-.55.52-1.12.79-1.71 1.15-2.49 2.37-5.21 3.44-7.97 2.05-5.28 3.89-11.54 2.82-16.9-.67-3.35-2.3-6.32-5.41-8.51-2.94-2.07-6.85-3.21-11.67-3.74-7.46-.83-10.89-1.6-14.01-4.09-2.9-2.32-3.62-4.43-3.74-5.93-.13-1.67.44-3.21 1-4.2.51-.9 1.72-1.68 4.44-1.97 2.35-.25 4.9-.03 7.3.18.31.03.62.05.93.08 2.86.24 5.98-.1 8.18-2.42 2.06-2.18 2.33-5.13 2.33-7.33 0-1.17.32-1.95.86-2.64.61-.79 1.63-1.6 3.26-2.51 2.83-1.57 4.87-4.32 5.4-7.4.56-3.26-.64-6.73-3.89-8.9-1.72-1.14-3.68-1.55-5.33-1.72-1.68-.17-3.48-.13-5.1-.08-.22 0-.44.01-.65.02-3.22.11-5.75.19-7.75-.38-.27-.08-.86-.38-1.74-1.22-.84-.8-1.72-1.89-2.58-3.15-1.73-2.53-3.12-5.37-3.79-7Zm73.36 81.97a55.79 55.79 0 0 0 12.32-35.06c0-2.49-.16-4.94-.48-7.34-.05 0-.09-.02-.12-.02-.14-.03-.29-.06-.42-.09-.2-.04-.45-.1-.74-.16l-.35-.08c-.87-.2-2.06-.46-3.47-.73-2.84-.56-6.52-1.16-10.27-1.41-3.81-.25-7.38-.11-10.13.64-2.73.75-3.97 1.89-4.45 3.2-3.38 9.13 1.14 13.91 1.55 14.32 1.49 1.49 2.84 2.11 4.77 3 .23.11.47.22.73.34 2.42 1.13 5.22 2.64 7.73 6.27 1.39 2 2.14 4.47 2.58 6.79.46 2.38.65 4.94.72 7.37.03 1 .04 1.99.03 2.96Zm.28-69.78a56.276 56.276 0 0 0-18.47-15.18c-.57 4.1-.99 8.75-.5 12.73.56 4.56 2.1 6.86 4.44 7.68 2.96 1.03 6.11.6 8.92-.65 2.91-1.3 4.85-3.21 5.46-4.32.05-.09.1-.18.16-.26ZM80 23.96c2.75 0 5.46.2 8.11.58-.9 1.31-2.06 2.75-3.46 3.91-1.61 1.33-3.33 2.13-5.24 2.13-4.39 0-7.99-3.27-9.19-5.78 3.17-.56 6.44-.85 9.78-.85Z', + fill: 'none' + } + } + } + }, + { + type: 'clipPath', + props: { + id: 'c', + children: { + type: 'path', + props: { + d: 'M23.98 80c0-17.01 7.58-32.25 19.54-42.52.92 2.02 2.32 4.67 4 7.13 1.05 1.54 2.28 3.1 3.65 4.41 1.33 1.27 3.04 2.55 5.08 3.13 3.29.94 7.1.8 9.98.7l.88-.03c1.63-.05 2.94-.07 4.03.05 1.11.11 1.57.33 1.71.42.31.2.39.37.41.43.03.08.07.22.03.46-.09.52-.53 1.28-1.4 1.76-2.07 1.15-4.14 2.6-5.69 4.59-1.63 2.09-2.54 4.6-2.54 7.55 0 .86-.07 1.4-.15 1.72v.03c-.28.06-.81.1-1.7.03-.27-.02-.55-.05-.86-.07-2.32-.21-5.69-.5-8.87-.17-3.54.37-8.1 1.64-10.56 5.96-1.08 1.89-2.33 5.04-2.03 8.8.31 3.92 2.27 7.99 6.71 11.55 5.12 4.1 10.75 4.98 18.12 5.8 4.2.47 6.58 1.37 7.94 2.33 1.19.84 1.85 1.9 2.18 3.55.58 2.88-.4 7.19-2.43 12.45-.97 2.52-2.11 5.05-3.24 7.52-.25.54-.5 1.08-.74 1.61-.81 1.76-1.61 3.47-2.27 5.03C41.73 127.91 24 106.04 24 80.03Zm99.72 35.06A55.79 55.79 0 0 0 136.02 80c0-2.49-.16-4.94-.48-7.34-.05 0-.09-.02-.12-.02-.14-.03-.29-.06-.42-.09-.2-.04-.45-.1-.74-.16l-.35-.08c-.87-.2-2.06-.46-3.47-.73-2.84-.56-6.52-1.16-10.27-1.41-3.81-.25-7.38-.11-10.13.64-2.73.75-3.97 1.89-4.45 3.2-3.38 9.13 1.14 13.91 1.55 14.32 1.49 1.49 2.84 2.11 4.77 3 .23.11.47.22.73.34 2.42 1.13 5.22 2.64 7.73 6.27 1.39 2 2.14 4.47 2.58 6.79.46 2.38.65 4.94.72 7.37.03 1 .04 1.99.03 2.96Zm.28-69.77a56.276 56.276 0 0 0-18.47-15.18c-.57 4.1-.99 8.75-.5 12.73.56 4.56 2.1 6.86 4.44 7.68 2.96 1.03 6.11.6 8.92-.65 2.91-1.3 4.85-3.21 5.46-4.32.05-.09.1-.18.16-.26ZM80 23.98c2.75 0 5.46.2 8.11.58-.9 1.31-2.06 2.75-3.46 3.91-1.61 1.33-3.33 2.13-5.24 2.13-4.39 0-7.99-3.27-9.19-5.78 3.17-.56 6.44-.85 9.78-.85Z', + fill: 'none' + } + } + } + } + ] + } + }, + { + type: 'g', + props: { + clipPath: 'url(#b)', + children: { + type: 'path', + props: { + d: 'M15 17h135v128H15z', + fill: '#6995fe' + } + } + } + }, + { + type: 'g', + props: { + clipPath: 'url(#c)', + children: { + type: 'path', + props: { + d: 'M15 17.01h135v128H15z', + fill: '#099d59' + } + } + } + } + ] + } + }; + } else { + // Adobe logo for React Spectrum + return { + type: 'svg', + props: { + width: 156, + height: 138, + viewBox: '0 0 501.71 444.05', + xmlns: 'http://www.w3.org/2000/svg', + children: { + type: 'polygon', + props: { + fill: '#eb1000', + strokeWidth: 0, + points: '297.58 444.05 261.13 342.65 169.67 342.65 246.54 149.12 363.19 444.05 501.71 444.05 316.8 0 186.23 0 0 444.05 297.58 444.05 297.58 444.05' + } + } + } + }; } } @@ -138,137 +229,130 @@ for (let file of files) { .relative(pagesDir, file) .replace(/\\/g, '/') .replace(/\.mdx?$/, ''); - let subtitle = getSubtitle(slug); - - // Get component SVG if available - const componentSvg = await getComponentSvg(title); - if (!componentSvg) { + + // Skip the error page + if (slug === 'error') { continue; } + + let subtitle = getSubtitle(slug); + let isIndexPage = slug === 'index' || slug.endsWith('/index'); - let svg = await satori( - { + // Determine layout type + let layout; + if (isIndexPage) { + // Index page layout: Centered logo and library name + layout = { type: 'div', props: { style: { display: 'flex', - flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', width: '100%', height: '100%', backgroundColor: '#ffffff', fontFamily: 'adobe-clean', color: '#000000' }, - children: [ - // Top section: Component illustration - { - type: 'div', - props: { - style: { - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - width: '100%', - height: '394px', // 10/16 of 630px total height - backgroundColor: '#f8f8f8', - padding: '40px', - borderBottom: '1px solid #e5e5e5' - }, - children: componentSvg ? { - type: 'img', + children: { + type: 'div', + props: { + style: { + display: 'flex', + alignItems: 'center', + gap: 44 + }, + children: [ + // Library logo + getLibraryLogo(subtitle), + // Library name + { + type: 'div', props: { - src: componentSvg, style: { - width: '340px', - height: '320px', - objectFit: 'contain' - } + fontSize: 84, + fontWeight: 700, + lineHeight: 1.1 + }, + children: subtitle } - } : { + } + ] + } + } + } + }; + } else { + // Regular page layout: Centered logo + page title + library name + layout = { + type: 'div', + props: { + style: { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + width: '100%', + height: '100%', + backgroundColor: '#ffffff', + fontFamily: 'adobe-clean', + color: '#000000' + }, + children: { + type: 'div', + props: { + style: { + display: 'flex', + alignItems: 'center', + gap: 44 + }, + children: [ + // Library logo + getLibraryLogo(subtitle), + // Text content + { type: 'div', props: { style: { - fontSize: 72, - fontWeight: 400, - color: '#464646' + display: 'flex', + flexDirection: 'column', + gap: 0 }, - children: title - } - } - } - }, - // Bottom section: Adobe logo + text - { - type: 'div', - props: { - style: { - display: 'flex', - alignItems: 'center', - width: '100%', - height: '236px', // 6/16 of 630px total height - padding: '0 60px', - gap: 40 - }, - children: [ - // Adobe logo - { - type: 'svg', - props: { - width: 156, - height: 138, - viewBox: '0 0 501.71 444.05', - xmlns: 'http://www.w3.org/2000/svg', - children: { - type: 'polygon', + children: [ + { + type: 'div', props: { - fill: '#eb1000', - strokeWidth: 0, - points: '297.58 444.05 261.13 342.65 169.67 342.65 246.54 149.12 363.19 444.05 501.71 444.05 316.8 0 186.23 0 0 444.05 297.58 444.05 297.58 444.05' + style: { + fontSize: 84, + fontWeight: 700, + lineHeight: 1.1 + }, + children: title } - } - } - }, - // Text content - { - type: 'div', - props: { - style: { - display: 'flex', - flexDirection: 'column', - gap: 8 }, - children: [ - { - type: 'div', - props: { - style: { - fontSize: 84, - fontWeight: 700, - lineHeight: 1.1 - }, - children: title - } - }, - { - type: 'div', - props: { - style: { - fontSize: 56, - fontWeight: 400, - color: '#464646' - }, - children: subtitle - } + { + type: 'div', + props: { + style: { + fontSize: 56, + fontWeight: 400, + color: '#464646' + }, + children: subtitle } - ] - } + } + ] } - ] - } + } + ] } - ] + } } - }, + }; + } + + let svg = await satori( + layout, { width: 1200, height: 630, diff --git a/packages/dev/s2-docs/src/Layout.tsx b/packages/dev/s2-docs/src/Layout.tsx index 4a1d57ec982..66ba59a9936 100644 --- a/packages/dev/s2-docs/src/Layout.tsx +++ b/packages/dev/s2-docs/src/Layout.tsx @@ -7,6 +7,7 @@ import {ClassAPI} from './ClassAPI'; import {Code} from './Code'; import {CodeBlock} from './CodeBlock'; import {ExampleSwitcher} from './ExampleSwitcher'; +import {getLibraryFromPage, getLibraryLabel} from './library'; import {H2, H3, H4} from './Headings'; import Header from './Header'; import {Link} from './Link'; @@ -46,31 +47,45 @@ function anchorId(children) { return children.replace(/\s/g, '-').replace(/[^a-zA-Z0-9-_]/g, '').toLowerCase(); } -const getLibraryName = (currentPage: Page): string => { - if (currentPage.name.startsWith('react-aria/')) { - return 'React Aria'; - } - return 'React Spectrum'; -}; - const getTitle = (currentPage: Page): string => { - let library = getLibraryName(currentPage); - const pageTitle = currentPage.exports?.title ?? currentPage.tableOfContents?.[0]?.title ?? currentPage.name; - return library ? `${pageTitle} - ${library}` : pageTitle; + const explicitTitle = (currentPage as any).pageTitle || currentPage.exports?.pageTitle; + if (explicitTitle && explicitTitle !== currentPage.tableOfContents?.[0]?.title && explicitTitle !== currentPage.name) { + return explicitTitle as string; + } + + let library = getLibraryLabel(getLibraryFromPage(currentPage)); + const pageTitle = currentPage.tableOfContents?.[0]?.title ?? currentPage.name; + + if (currentPage.name === 'index.html' || currentPage.name.endsWith('/index.html')) { + return library || 'React Spectrum'; + } + + return library ? `${pageTitle} | ${library}` : pageTitle; }; const getOgImageUrl = (currentPage: Page): string => { const slug = currentPage.url.replace(/^\//, '').replace(/\.html$/, ''); + + if (slug.includes('s2-docs/')) { + // For build links, use the full URL + const ogPath = slug.replace(/s2-docs\//, 's2-docs/og/'); + return `https://reactspectrum.blob.core.windows.net/${ogPath}.png`; + } + + // For production, use relative path with /og/ prefix return `/og/${slug}.png`; }; const getDescription = (currentPage: Page): string => { - let library = getLibraryName(currentPage); + let library = getLibraryLabel(getLibraryFromPage(currentPage)); const pageTitle = currentPage.exports?.title ?? currentPage.tableOfContents?.[0]?.title ?? currentPage.name; const explicitDescription = (currentPage as any).description || currentPage.exports?.description; if (explicitDescription) { return explicitDescription as string; } + if (currentPage.name === 'index.html' || currentPage.name.endsWith('/index.html')) { + return `Documentation for ${library || 'React Spectrum'}`; + } return library ? `Documentation for ${pageTitle} in ${library}.` : `Documentation for ${pageTitle}.`; };