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}.`;
};