Increase dark-mode button contrast#8494
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adjusts dark-mode button styling for improved contrast, but it also includes a broad Next.js/React/TypeScript + routing migration (Pages Router → App Router) and related infrastructure updates across the site.
Changes:
- Increase dark-mode button contrast by updating primary button text color and secondary button stroke token.
- Migrate major routes and supporting logic from Next.js Pages Router to App Router (new
src/app/*pages/routes, new server helpers undersrc/lib/*, removal of severalsrc/pages/*entrypoints). - Update build/tooling configuration (Next/React versions, TS config, Next config, lint scripts, and type declarations).
Reviewed changes
Copilot reviewed 46 out of 54 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.json | Updates TS module resolution / JSX mode and includes additional .next type paths. |
| tailwind.config.js | Raises dark-mode secondary button stroke token value. |
| src/utils/compileMDX.ts | Switches MDX component-name enumeration to a server-safe list and bumps disk cache breaker; expands return type. |
| src/types/jsx-bridge.d.ts | Adds global JSX namespace bridge for React 19 type changes. |
| src/types/css.d.ts | Adds module declarations for CSS side-effect imports. |
| src/pages/errors/index.tsx | Removes Pages Router error decoder index entrypoint. |
| src/pages/errors/[errorCode].tsx | Removes Pages Router error decoder page and SSG logic. |
| src/pages/api/md/[...path].ts | Removes Pages Router API endpoint for serving markdown. |
| src/pages/[[...markdownPath]].js | Removes Pages Router catch-all markdown rendering page. |
| src/pages/_document.tsx | Removes custom Pages Router Document in favor of App Router layout/head. |
| src/pages/_app.tsx | Removes Pages Router App wrapper; client effects moved to App Router equivalents. |
| src/lib/readMarkdownPage.ts | Adds server-only helper to read/compile MDX with cache semantics. |
| src/lib/loadErrorDecoderData.ts | Adds server-only error decoder data loader + caching and code listing. |
| src/lib/collectPaths.ts | Adds cached filesystem traversal utilities for static params generation. |
| src/lib/buildPageMetadata.ts | Adds App Router metadata builder replacing old Seo behavior. |
| src/hooks/usePendingRoute.ts | Removes pending-route tracking (no App Router router.events equivalent). |
| src/components/Seo.tsx | Removes old Pages Router <Head>-based SEO component. |
| src/components/Search.tsx | Migrates navigation from next/router to next/navigation and removes per-component <Head> preconnect. |
| src/components/PageHeading.tsx | Switches from useRouter().asPath to usePathname() for markdown-copy behavior. |
| src/components/MDX/MDXComponentsList.ts | Adds server-safe constant list of MDX component names. |
| src/components/MDX/MDXComponents.tsx | Marks MDX components module as client and notes sync requirement with the new names list. |
| src/components/MDX/ExpandableExample.tsx | Replaces asPath hash parsing with window.location.hash. |
| src/components/MDX/Challenges/Challenges.tsx | Migrates from next/router to usePathname() and uses window.location.hash for initial selection. |
| src/components/Layout/useDeserializedMDX.tsx | Introduces shared client hook for deserializing MDX JSON to React nodes. |
| src/components/Layout/TopNav/TopNav.tsx | Migrates from next/router to usePathname() for route-change reactions. |
| src/components/Layout/Sidebar/SidebarRouteTree.tsx | Migrates current-slug detection from next/router to usePathname(). |
| src/components/Layout/Page.tsx | Converts Page to a client component, adds pathname prop, lazy-loads HomeContent, and removes old SEO/RSS <Head> usage. |
| src/components/Layout/HomeContent.js | Switches to React’s built-in use and removes local polyfill. |
| src/components/ErrorDecoderContext.tsx | Updates comment to reflect App Router usage (context populated by route’s server component). |
| src/components/ButtonLink.tsx | Updates primary button dark-mode text class to dark:text-gray-95. |
| src/app/warnings/[slug]/page.tsx | Adds App Router page for warnings slugs using shared section renderer. |
| src/app/versions/page.tsx | Adds App Router page for /versions using shared section renderer. |
| src/app/renderSectionPage.tsx | Adds shared section page renderer + metadata helper for App Router. |
| src/app/reference/[[...slug]]/page.tsx | Adds App Router reference catch-all page with static params generation. |
| src/app/page.tsx | Adds App Router home page using MDX read + metadata builder. |
| src/app/not-found.tsx | Adds App Router not-found UI using the shared Page component API. |
| src/app/llms.txt/route.ts | Migrates llms.txt generation from SSR to an App Router route handler. |
| src/app/learn/[[...slug]]/page.tsx | Adds App Router learn catch-all page with static params generation. |
| src/app/layout.tsx | Adds App Router root layout including metadata, scripts, preloads, RSS link, and client effects. |
| src/app/errors/page.tsx | Adds App Router errors index page backed by server data loader. |
| src/app/errors/ErrorDecoderView.tsx | Adds client view component to render error decoder content within the shared Page. |
| src/app/errors/[errorCode]/page.tsx | Adds App Router error code page with static params + metadata. |
| src/app/error.tsx | Adds App Router global error boundary UI. |
| src/app/DocsPage.tsx | Adds client wrapper to render MDX content/toc into Page. |
| src/app/community/[[...slug]]/page.tsx | Adds App Router community catch-all page with static params generation. |
| src/app/clientEffects.tsx | Adds App Router client effects for analytics + scroll restoration. |
| src/app/blog/[[...slug]]/page.tsx | Adds App Router blog catch-all page with static params generation. |
| src/app/api/md/[...path]/route.ts | Adds App Router route handler to serve raw markdown with static params prerendering. |
| package.json | Updates scripts, upgrades Next/React/types, removes next-remote-watch, updates engines, and adds resolutions. |
| next.config.js | Enables cache components, adjusts config for Next 16/webpack usage, and lists server external packages. |
| next-env.d.ts | Adds an import of a generated .next routes type file (currently problematic). |
| CLAUDE.md | Updates repo structure docs to include src/app/ and src/lib/, and adds a Next.js agent rules block. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
07c8232 to
b04a4ae
Compare
Size changesDetails📦 Next.js Bundle Analysis for react-devThis analysis was generated by the Next.js Bundle Analysis action. 🤖
|
| Page | Size (compressed) |
|---|---|
global |
115.14 KB (🟡 +5 B) |
Details
The global bundle is the javascript bundle that loads alongside every page. It is in its own category because its impact is much higher - an increase to its size means that every page on your website loads slower, and a decrease means every page loads faster.
Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis
If you want further insight into what is behind the changes, give @next/bundle-analyzer a try!
Five Pages Changed Size
The following pages changed size from the code in this PR compared to its base branch:
| Page | Size (compressed) | First Load |
|---|---|---|
/404 |
127.02 KB (🟡 +6 B) |
242.16 KB |
/500 |
127.03 KB (🟡 +6 B) |
242.17 KB |
/[[...markdownPath]] |
129.46 KB (🟡 +6 B) |
244.61 KB |
/errors |
127.27 KB (🟡 +6 B) |
242.42 KB |
/errors/[errorCode] |
127.25 KB (🟡 +6 B) |
242.39 KB |
Details
Only the gzipped size is provided here based on an expert tip.
First Load is the size of the global bundle plus the bundle for the individual page. If a user were to show up to your website and land on a given page, the first load size represents the amount of javascript that user would need to download. If next/link is used, subsequent page loads would only need to download that page's bundle (the number in the "Size" column), since the global bundle has already been downloaded.
Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis
Next to the size is how much the size has increased or decreased compared with the base branch of this PR. If this percentage has increased by 10% or more, there will be a red status indicator applied, indicating that special attention should be given to this.
Bumps button contrast to match the treatment on reactnative.dev. Dark mode: - primary text: dark:text-secondary (#404756) -> dark:text-gray-90 (#23272F) - secondary border: #404756 -> #4E5769 (matches RN's rgb(78,86,104)) Light mode: - secondary border: #D9DBE3 -> #BCC1CD (matches RN's rgb(188,193,205)) gray-90 keeps a subtle cyan tint on the teal button, per review feedback (gray-95 was too flat).
b04a4ae to
28b3855
Compare


Bumps button contrast to match the treatment on reactnative.dev, in both dark and light mode.
In dark mode the primary button's text (
dark:text-secondary, #404756) and the secondary button's border (#404756) were both low-contrast against the teal and dark backgrounds. This raises the primary text to near-black (gray-95, #16181D) and lifts the secondary border to #4E5769, the same value React Native uses (rgb(78, 86, 104)). Primary text contrast goes from about 4.6:1 to about 8.9:1.In light mode the buttons already nearly matched React Native; the only gap was the secondary border, which was a touch lighter (#D9DBE3) than React Native's (#BCC1CD). This nudges it to #BCC1CD so the two are consistent.
Token changes:
dark:text-secondarytodark:text-gray-95secondary-button-stroke-dark#404756 to #4E5769 (dark), andsecondary-button-stroke#D9DBE3 to #BCC1CD (light)Screenshots
React Native reference: https://reactnative.dev/
Notes