Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e377252
Add no-trailing-spaces ESLint rule (#8356)
mattcarrollcode Apr 8, 2026
abe931a
fix: replace Imgur-hosted images with self-hosted assets (#8402)
travisbreaks Apr 9, 2026
47e64bf
docs: Update Vite React Compiler setup for @vitejs/plugin-react@6.0.0…
MorikawaSouma May 14, 2026
6ec6134
Update conferences list (#8450)
dai-shi May 26, 2026
8bb31ac
Expand FragmentInstance reference docs (#8309)
jackpope Jun 17, 2026
b4610fb
Clarify useLayoutEffect setup timing (#8488)
MakenRosa Jun 22, 2026
ecf6c2f
Increase dark-mode button contrast (#8494)
aurorascharff Jun 24, 2026
fb3854a
Rewrite `use()` docs (#8305)
rickhanlonii Jun 24, 2026
b6e9b3c
[form] Document onSubmit event handler alongside action
aurorascharff Jun 24, 2026
1f48fb4
[form] Refine onSubmit/action framing and address review
aurorascharff Jun 24, 2026
93f6c27
fix: update use.md pitfall to make conditional calling clearer (#8499)
MaxwellCohen Jun 25, 2026
12181ae
Fix broken internal link in Component reference (anchor) (#8344)
Srijan-D Jun 27, 2026
152a471
Fix incorrect links on versions page (#8461)
hanityx Jun 27, 2026
71654a3
fix: remove unused useContext import in sandbox examples (#8509)
DakshSinghDhami Jun 29, 2026
853a7f7
Update version entries (#8507)
DakshSinghDhami Jun 29, 2026
d2f7153
Rewrite React Developer Tools section in tutorial-tic-tac-toe to use …
vintas Jun 30, 2026
2639f36
Tweak tutorial DevTools instructions (#8514)
gaearon Jul 1, 2026
15299e5
Fix startTransition example to wrap setState after await (#8520)
Nabeel-akk Jul 8, 2026
831150c
[use] Rework await vs use DeepDive to fix inaccurate framing (#8521)
aurorascharff Jul 8, 2026
e998664
Fix slow demo preview height (#8517)
TunaDev0 Jul 8, 2026
c3c956b
Update React repo owner (#8524)
eps1lon Jul 9, 2026
efaa3e5
[Suspense] Document what activates a boundary, with live examples (#8…
aurorascharff Jul 9, 2026
26906f2
[Suspense] Polish activation examples (#8525)
aurorascharff Jul 9, 2026
ac61e37
[Suspense] Tune demo heights and section copy (#8526)
aurorascharff Jul 9, 2026
e51fc36
docs: wrap state updates after await in startTransition (#8443)
Dotify71 Jul 9, 2026
ef208e1
Dynamic OG images for docs pages (#8527)
aurorascharff Jul 9, 2026
1dcc709
fix server functions page crashing on loading (#8531)
MaxwellCohen Jul 10, 2026
6be2b02
Restructure the Meet the Team page around React's working groups and …
mattcarrollcode Jul 10, 2026
994a8ed
merging all conflicts
react-translations-bot Jul 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .claude/skills/docs-writer-blog/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ See [How to Upgrade to React X.Y](/blog/YYYY/MM/DD/react-xy-upgrade-guide) for s

### React {/*react*/}

* Add `useNewHook` for [purpose]. ([#12345](https://github.com/facebook/react/pull/12345) by [@contributor](https://github.com/contributor))
* Add `useNewHook` for [purpose]. ([#12345](https://github.com/react/react/pull/12345) by [@contributor](https://github.com/contributor))

---

Expand Down Expand Up @@ -603,7 +603,7 @@ npm install react@latest react-dom@latest

| Type | Pattern |
|------|---------|
| GitHub PR | `[#12345](https://github.com/facebook/react/pull/12345)` |
| GitHub PR | `[#12345](https://github.com/react/react/pull/12345)` |
| GitHub user | `[@username](https://github.com/username)` |
| Twitter/X | `[@username](https://x.com/username)` |
| Bluesky | `[Name](https://bsky.app/profile/handle)` |
Expand All @@ -623,8 +623,8 @@ For more information, see the docs for [`useActionState`](/reference/react/useAc
### Bullet Pattern

```markdown
* Add `useTransition` for concurrent rendering. ([#10426](https://github.com/facebook/react/pull/10426) by [@acdlite](https://github.com/acdlite))
* Fix `useReducer` observing incorrect props. ([#22445](https://github.com/facebook/react/pull/22445) by [@josephsavona](https://github.com/josephsavona))
* Add `useTransition` for concurrent rendering. ([#10426](https://github.com/react/react/pull/10426) by [@acdlite](https://github.com/acdlite))
* Fix `useReducer` observing incorrect props. ([#22445](https://github.com/react/react/pull/22445) by [@josephsavona](https://github.com/josephsavona))
```

**Structure:** `Verb` + backticked API + description + `([#PR](url) by [@user](url))`
Expand Down
16 changes: 8 additions & 8 deletions .claude/skills/react-expert/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ This skill produces exhaustive documentation research on any React API or concep
2. **React Source Code** - Warnings, errors, implementation details
3. **Git History** - Commit messages with context
4. **GitHub PRs & Comments** - Design rationale (via `gh` CLI)
5. **GitHub Issues** - Confusion/questions (facebook/react + reactjs/react.dev)
5. **GitHub Issues** - Confusion/questions (react/react + reactjs/react.dev)
6. **React Working Group** - Design discussions for newer APIs
7. **Flow Types** - Source of truth for type signatures
8. **TypeScript Types** - Note discrepancies with Flow
Expand All @@ -51,7 +51,7 @@ First, ensure the React repo is available locally:
if [ -d ".claude/react" ]; then
cd .claude/react && git pull origin main
else
git clone --depth=100 https://github.com/facebook/react.git .claude/react
git clone --depth=100 https://github.com/react/react.git .claude/react
fi
```

Expand All @@ -71,8 +71,8 @@ Spawn these agents IN PARALLEL using the Task tool. Each agent receives the skep
| test-explorer | Explore | Test files for usage patterns | Search `.claude/react/packages/*/src/__tests__/` for test files mentioning the topic. Extract actual usage examples WITH file paths and line numbers. |
| source-explorer | Explore | Warnings/errors in source | Search `.claude/react/packages/*/src/` for console.error, console.warn, and error messages mentioning the topic. Document trigger conditions. |
| git-historian | Explore | Commit messages | Run `git log --all --grep="<topic>" --oneline -50` in `.claude/react`. Read full commit messages for context. |
| pr-researcher | Explore | PRs introducing/modifying API | Run `gh pr list -R facebook/react --search "<topic>" --state all --limit 20`. Read key PR descriptions and comments. |
| issue-hunter | Explore | Issues showing confusion | Search issues in both `facebook/react` and `reactjs/react.dev` repos. Look for common questions and misunderstandings. |
| pr-researcher | Explore | PRs introducing/modifying API | Run `gh pr list -R react/react --search "<topic>" --state all --limit 20`. Read key PR descriptions and comments. |
| issue-hunter | Explore | Issues showing confusion | Search issues in both `react/react` and `reactjs/react.dev` repos. Look for common questions and misunderstandings. |
| types-inspector | Explore | Flow + TypeScript signatures | Find Flow types in `.claude/react/packages/*/src/*.js` (look for `@flow` annotations). Find TS types in `.claude/react/packages/*/index.d.ts`. Note discrepancies. |

### Step 3: Agent Prompts
Expand Down Expand Up @@ -164,8 +164,8 @@ CRITICAL: Do NOT rely on your prior knowledge. Only report what you find in PRs.

Your task: Find PRs that introduced or modified <TOPIC>.

1. Run: gh pr list -R facebook/react --search "<topic>" --state all --limit 20 --json number,title,url
2. For promising PRs, read details: gh pr view <number> -R facebook/react
1. Run: gh pr list -R react/react --search "<topic>" --state all --limit 20 --json number,title,url
2. For promising PRs, read details: gh pr view <number> -R react/react
3. Look for:
- The original RFC/motivation
- Design discussions in comments
Expand All @@ -189,7 +189,7 @@ CRITICAL: Do NOT rely on your prior knowledge. Only report what you find in issu

Your task: Find issues that reveal common confusion about <TOPIC>.

1. Search facebook/react: gh issue list -R facebook/react --search "<topic>" --state all --limit 20 --json number,title,url
1. Search react/react: gh issue list -R react/react --search "<topic>" --state all --limit 20 --json number,title,url
2. Search reactjs/react.dev: gh issue list -R reactjs/react.dev --search "<topic>" --state all --limit 20 --json number,title,url
3. For each issue, identify:
- What the user was confused about
Expand All @@ -199,7 +199,7 @@ Your task: Find issues that reveal common confusion about <TOPIC>.
Format your output as:
## Common Confusion
### Issue #<number>: <title>
**Repo:** <facebook/react or reactjs/react.dev>
**Repo:** <react/react or reactjs/react.dev>
**Confusion:** <what they misunderstood>
**Resolution:** <correct understanding>
**Gotcha:** <if applicable>
Expand Down
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"react-hooks/exhaustive-deps": "error",
"react/no-unknown-property": ["error", {"ignore": ["meta"]}],
"react-compiler/react-compiler": "error",
"local-rules/lint-markdown-code-blocks": "error"
"local-rules/lint-markdown-code-blocks": "error",
"no-trailing-spaces": "error"
},
"env": {
"node": true,
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
contact_links:
- name: 📃 Bugs in React
url: https://github.com/facebook/react/issues/new/choose
url: https://github.com/react/react/issues/new/choose
about: This issue tracker is not for bugs in React. Please file React issues here.
- name: 🤔 Questions and Help
url: https://reactjs.org/community/support.html
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/discord_notify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ permissions: {}

jobs:
check_maintainer:
uses: facebook/react/.github/workflows/shared_check_maintainer.yml@main
uses: react/react/.github/workflows/shared_check_maintainer.yml@main
permissions:
# Used by check_maintainer
contents: read
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/label_core_team_prs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ env:

jobs:
check_maintainer:
uses: facebook/react/.github/workflows/shared_check_maintainer.yml@main
uses: react/react/.github/workflows/shared_check_maintainer.yml@main
permissions:
# Used by check_maintainer
contents: read
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,6 @@ public/rss.xml

# worktrees
.worktrees/

# Generated OG images (scripts/generateOgImages.mjs)
public/images/og/
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"analyze": "ANALYZE=true next build",
"dev": "next-remote-watch ./src/content",
"prebuild:rsc": "node scripts/buildRscWorker.mjs",
"build": "node scripts/buildRscWorker.mjs && next build && node --experimental-modules ./scripts/downloadFonts.mjs",
"build": "node scripts/buildRscWorker.mjs && next build && node --experimental-modules ./scripts/downloadFonts.mjs && node ./scripts/generateOgImages.mjs",
"lint": "next lint && eslint \"src/content/**/*.md\"",
"lint:fix": "next lint --fix && eslint \"src/content/**/*.md\" --fix",
"format:source": "prettier --config .prettierrc --write \"{plugins,src}/**/*.{js,ts,jsx,tsx,css}\"",
Expand Down Expand Up @@ -51,6 +51,7 @@
"@babel/plugin-transform-modules-commonjs": "^7.18.6",
"@babel/preset-react": "^7.18.6",
"@mdx-js/mdx": "^2.1.3",
"@resvg/resvg-js": "^2.6.2",
"@types/body-scroll-lock": "^2.6.1",
"@types/classnames": "^2.2.10",
"@types/debounce": "^1.2.1",
Expand Down Expand Up @@ -102,6 +103,7 @@
"retext": "^7.0.1",
"retext-smartypants": "^4.0.0",
"rss": "^1.2.2",
"satori": "^0.26.0",
"tailwindcss": "^3.4.1",
"typescript": "^5.7.2",
"unist-util-visit": "^2.0.3",
Expand Down
Binary file added public/fonts/Optimistic_Display_W_Bd.ttf
Binary file not shown.
Binary file added public/fonts/Optimistic_Display_W_Md.ttf
Binary file not shown.
Binary file added public/images/docs/scientists/1bX5QH6.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/1bX5QH6b.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/1bX5QH6s.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/2heNQDcm.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/3aIiwfm.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/5qwVYb1.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/6o5Vuyu.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/7vQD0fPb.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/7vQD0fPs.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/9EAYZrtl.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/AlHTAdDm.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/DgXHVwul.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/FJeJR8M.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/HMFmH6m.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/IOjWm71s.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/JBbMpWY.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/K9HVAGHl.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/MK3eW3Am.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/MK3eW3As.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/Mx7dA2Y.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/OKS67lhb.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/OKS67lhm.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/OKS67lhs.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/QIrZWGIs.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/QwUKKmF.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docs/scientists/RCwLEoQm.jpg
Binary file added public/images/docs/scientists/Sd1AgUOm.jpg
Binary file added public/images/docs/scientists/Y3utgTi.jpg
Binary file added public/images/docs/scientists/YfeOqp2b.jpg
Binary file added public/images/docs/scientists/YfeOqp2s.jpg
Binary file added public/images/docs/scientists/ZF6s192.jpg
Binary file added public/images/docs/scientists/ZF6s192m.jpg
Binary file added public/images/docs/scientists/ZfQOOzfl.jpg
Binary file added public/images/docs/scientists/aTtVpES.jpg
Binary file added public/images/docs/scientists/aeO3rpIl.jpg
Binary file added public/images/docs/scientists/bE7W1jis.jpg
Binary file added public/images/docs/scientists/dB2LRbj.jpg
Binary file added public/images/docs/scientists/jA8hHMpm.jpg
Binary file added public/images/docs/scientists/kxsph5Cl.jpg
Binary file added public/images/docs/scientists/lICfvbD.jpg
Binary file added public/images/docs/scientists/lrWQx8ls.jpg
Binary file added public/images/docs/scientists/mynHUSas.jpg
Binary file added public/images/docs/scientists/okTpbHhm.jpg
Binary file added public/images/docs/scientists/rN7hY6om.jpg
Binary file added public/images/docs/scientists/rTqKo46l.jpg
Binary file added public/images/docs/scientists/szV5sdGb.jpg
Binary file added public/images/docs/scientists/szV5sdGs.jpg
Binary file added public/images/docs/scientists/wIdGuZwm.png
Binary file added public/images/docs/scientists/yXOvdOSs.jpg
Binary file added public/images/docs/scientists/z08o2TS.jpg
Binary file added public/images/team/gh-aurorascharff.jpg
Binary file added public/images/team/gh-brentvatne.jpg
Binary file added public/images/team/gh-captbaritone.jpg
Binary file added public/images/team/gh-cipolleschi.png
Binary file added public/images/team/gh-cortinico.jpg
Binary file added public/images/team/gh-fbmal7.jpg
Binary file added public/images/team/gh-fkgozali.jpg
Binary file added public/images/team/gh-huntie.jpg
Binary file added public/images/team/gh-javache.jpg
Binary file added public/images/team/gh-khalef1.jpg
Binary file added public/images/team/gh-kmagiera.jpg
Binary file added public/images/team/gh-motiz88.jpg
Binary file added public/images/team/gh-rh389.jpg
Binary file added public/images/team/gh-rubennorte.jpg
Binary file added public/images/team/gh-samselikoff.jpg
Binary file added public/images/team/gh-simek.png
Binary file added public/images/team/gh-stmoy.jpg
Binary file added public/images/team/gh-thymikee.jpg
Binary file added public/images/team/gh-vzaidman.jpg
Binary file added public/images/team/jimmy-lai.jpg
Binary file removed public/images/tutorial/codesandbox-devtools.png
Diff not rendered.
Binary file added public/images/tutorial/components-tab.png
Binary file added public/images/tutorial/devtools-inspect.gif
Binary file removed public/images/tutorial/devtools-select.gif
Diff not rendered.
Binary file added public/images/tutorial/sandbox-new-tab.png
2 changes: 1 addition & 1 deletion scripts/deadLinkChecker.js
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ async function buildContributorMap() {
async function fetchErrorCodes() {
try {
const response = await fetch(
'https://raw.githubusercontent.com/facebook/react/main/scripts/error-codes/codes.json'
'https://raw.githubusercontent.com/react/react/main/scripts/error-codes/codes.json'
);
if (!response.ok) {
throw new Error(`Failed to fetch error codes: ${response.status}`);
Expand Down
219 changes: 219 additions & 0 deletions scripts/generateOgImages.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

// Generates a static OG image for every content page, so social
// cards show the page title without any runtime image generation.
// Run after `next build` (see the `build` script in package.json).

import fs from 'fs';
import path from 'path';
import satori from 'satori';
import {Resvg} from '@resvg/resvg-js';
import matter from 'gray-matter';

const ROOT = process.cwd();
const CONTENT_DIR = path.join(ROOT, 'src', 'content');
const OUT_DIR = path.join(ROOT, 'public', 'images', 'og');
const CONCURRENCY = 8;

const SECTION_LABELS = {
learn: 'Learn React',
reference: 'API Reference',
community: 'Community',
blog: 'Blog',
};

const bold = fs.readFileSync(
path.join(ROOT, 'public', 'fonts', 'Optimistic_Display_W_Bd.ttf')
);
const medium = fs.readFileSync(
path.join(ROOT, 'public', 'fonts', 'Optimistic_Display_W_Md.ttf')
);

function el(type, style, children) {
return {type, props: {style, children}};
}

function card(title, pagePath) {
const section = pagePath.split('/')[1] ?? '';
const label = SECTION_LABELS[section] ?? 'React';
const logo = {
type: 'svg',
props: {
width: 80,
height: 72,
viewBox: '-10.5 -9.45 21 18.9',
fill: 'none',
children: [
{type: 'circle', props: {cx: 0, cy: 0, r: 2, fill: '#58c4dc'}},
{
type: 'g',
props: {
stroke: '#58c4dc',
strokeWidth: 1,
fill: 'none',
children: [
{type: 'ellipse', props: {rx: 10, ry: 4.5}},
{
type: 'ellipse',
props: {rx: 10, ry: 4.5, transform: 'rotate(60)'},
},
{
type: 'ellipse',
props: {rx: 10, ry: 4.5, transform: 'rotate(120)'},
},
],
},
},
],
},
};
return el(
'div',
{
width: '100%',
height: '100%',
display: 'flex',
flexDirection: 'column',
padding: '72px 80px',
backgroundColor: '#23272f',
backgroundImage:
'radial-gradient(circle at 25% 30%, #343a46 0%, #23272f 55%)',
},
[
el('div', {display: 'flex', alignItems: 'center', gap: '20px'}, [
logo,
el(
'div',
{
fontSize: 48,
fontFamily: 'Optimistic Display Bold',
color: '#f6f7f9',
},
'React'
),
]),
el(
'div',
{
flexGrow: 1,
display: 'flex',
alignItems: 'center',
fontSize: title.length > 24 ? 72 : 96,
fontFamily: 'Optimistic Display Bold',
color: '#f6f7f9',
lineHeight: 1.1,
wordBreak: 'break-word',
},
title
),
el(
'div',
{
fontSize: 40,
fontFamily: 'Optimistic Display Medium',
color: '#99a1b3',
},
label
),
]
);
}

async function renderCard(title, pagePath) {
const svg = await satori(card(title, pagePath), {
width: 1200,
height: 630,
fonts: [
{
name: 'Optimistic Display Bold',
data: bold,
weight: 700,
style: 'normal',
},
{
name: 'Optimistic Display Medium',
data: medium,
weight: 500,
style: 'normal',
},
],
});
return new Resvg(svg, {fitTo: {mode: 'width', value: 1200}}).render().asPng();
}

function collectSidebarTitles() {
const titles = new Map();
for (const name of fs.readdirSync(path.join(ROOT, 'src'))) {
if (!/^sidebar.*\.json$/.test(name)) continue;
const walk = (node) => {
if (node.path && node.title) {
titles.set(node.path, node.title);
}
for (const child of node.routes ?? []) walk(child);
};
walk(JSON.parse(fs.readFileSync(path.join(ROOT, 'src', name), 'utf8')));
}
return titles;
}

const sidebarTitles = collectSidebarTitles();

function collectPages(dir, out) {
for (const entry of fs.readdirSync(dir, {withFileTypes: true})) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) {
collectPages(full, out);
} else if (entry.name.endsWith('.md')) {
const rel = path.relative(CONTENT_DIR, full).replace(/\.md$/, '');
const segments = rel.split(path.sep);
if (segments[segments.length - 1] === 'index') {
segments.pop();
}
const pagePath = '/' + segments.join('/');
if (pagePath === '/' || pagePath.startsWith('/errors')) {
continue;
}
const {data} = matter(fs.readFileSync(full, 'utf8'));
const title = data.title ?? sidebarTitles.get(pagePath);
if (title) {
out.push({title: String(title), pagePath});
}
}
}
return out;
}

export function ogImageFileName(pagePath) {
return pagePath.replace(/^\//, '').replace(/\//g, '-') + '.png';
}

async function main() {
const pages = collectPages(CONTENT_DIR, []);
fs.mkdirSync(OUT_DIR, {recursive: true});
let done = 0;
const queue = [...pages];
async function worker() {
for (;;) {
const page = queue.shift();
if (!page) return;
const png = await renderCard(page.title, page.pagePath);
fs.writeFileSync(path.join(OUT_DIR, ogImageFileName(page.pagePath)), png);
done++;
if (done % 100 === 0) {
console.log(`og-images: ${done}/${pages.length}`);
}
}
}
await Promise.all(Array.from({length: CONCURRENCY}, worker));
console.log(`og-images: generated ${done} images in public/images/og`);
}

main().catch((error) => {
console.error(error);
process.exit(1);
});
2 changes: 1 addition & 1 deletion src/components/ButtonLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ function ButtonLink({
className,
'active:scale-[.98] transition-transform inline-flex font-bold items-center outline-none focus:outline-none focus-visible:outline focus-visible:outline-link focus:outline-offset-2 focus-visible:dark:focus:outline-link-dark leading-snug',
{
'bg-link text-white dark:bg-brand-dark dark:text-secondary hover:bg-opacity-80':
'bg-link text-white dark:bg-brand-dark dark:text-gray-90 hover:bg-opacity-80':
type === 'primary',
'text-primary dark:text-primary-dark shadow-secondary-button-stroke dark:shadow-secondary-button-stroke-dark hover:bg-gray-40/5 active:bg-gray-40/10 hover:dark:bg-gray-60/5 active:dark:bg-gray-60/10':
type === 'secondary',
Expand Down
Loading
Loading