diff --git a/.gitignore b/.gitignore index c28df64b1..4d4c779a2 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,11 @@ yarn-error.log* # external fonts public/fonts/**/Optimistic_*.woff2 +<<<<<<< HEAD # contributors likely have their own workspace settings and shouldn't # version them (e.g. markdownlint tweaks, etc.) .vscode/settings.json +======= +# rss +public/rss.xml +>>>>>>> 53fbed3f676013508fb9cce22a3fc8664b1dc5a1 diff --git a/colors.js b/colors.js index acf8214ee..872f33cac 100644 --- a/colors.js +++ b/colors.js @@ -11,7 +11,7 @@ module.exports = { tertiary: '#5E687E', // gray-50 'tertiary-dark': '#99A1B3', // gray-30 link: '#087EA4', // blue-50 - 'link-dark': '#149ECA', // blue-40 + 'link-dark': '#58C4DC', // blue-40 syntax: '#EBECF0', // gray-10 wash: '#FFFFFF', 'wash-dark': '#23272F', // gray-90 @@ -23,6 +23,8 @@ module.exports = { 'border-dark': '#343A46', // gray-80 'secondary-button': '#EBECF0', // gray-10 'secondary-button-dark': '#404756', // gray-70 + brand: '#087EA4', // blue-40 + 'brand-dark': '#58C4DC', // blue-40 // Gray 'gray-95': '#16181D', diff --git a/package.json b/package.json index d75201780..1f63eb121 100644 --- a/package.json +++ b/package.json @@ -15,17 +15,19 @@ "prettier:diff": "yarn nit:source", "lint-heading-ids": "node scripts/headingIdLinter.js", "fix-headings": "node scripts/headingIdLinter.js --fix", - "ci-check": "npm-run-all prettier:diff --parallel lint tsc lint-heading-ids", + "ci-check": "npm-run-all prettier:diff --parallel lint tsc lint-heading-ids rss", "tsc": "tsc --noEmit", "start": "next start", "postinstall": "patch-package && (is-ci || husky install .husky)", - "check-all": "npm-run-all prettier lint:fix tsc" + "check-all": "npm-run-all prettier lint:fix tsc rss", + "rss": "node scripts/generateRss.js" }, "dependencies": { "@codesandbox/sandpack-react": "2.13.5", "@docsearch/css": "3.0.0-alpha.41", "@docsearch/react": "3.0.0-alpha.41", "@headlessui/react": "^1.7.0", + "@radix-ui/react-context-menu": "^2.1.5", "body-scroll-lock": "^3.1.3", "classnames": "^2.2.6", "date-fns": "^2.16.1", @@ -97,7 +99,7 @@ "webpack-bundle-analyzer": "^4.5.0" }, "engines": { - "node": "^16.8.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0" + "node": ">=16.8.0" }, "nextBundleAnalysis": { "budget": null, diff --git a/public/android-chrome-192x192.png b/public/android-chrome-192x192.png new file mode 100644 index 000000000..5de701e13 Binary files /dev/null and b/public/android-chrome-192x192.png differ diff --git a/public/android-chrome-384x384.png b/public/android-chrome-384x384.png new file mode 100644 index 000000000..f42a6776e Binary files /dev/null and b/public/android-chrome-384x384.png differ diff --git a/public/android-chrome-512x512.png b/public/android-chrome-512x512.png new file mode 100644 index 000000000..2fdbf6902 Binary files /dev/null and b/public/android-chrome-512x512.png differ diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 000000000..baf1332a3 Binary files /dev/null and b/public/apple-touch-icon.png differ diff --git a/public/browserconfig.xml b/public/browserconfig.xml new file mode 100644 index 000000000..f9c2e67fe --- /dev/null +++ b/public/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #2b5797 + + + diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png new file mode 100644 index 000000000..d24cb4f76 Binary files /dev/null and b/public/favicon-16x16.png differ diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png new file mode 100644 index 000000000..953ae4cc3 Binary files /dev/null and b/public/favicon-32x32.png differ diff --git a/public/favicon.ico b/public/favicon.ico index 38fd8641c..519b939a0 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/favicon_old.ico b/public/favicon_old.ico new file mode 100644 index 000000000..20b59d440 Binary files /dev/null and b/public/favicon_old.ico differ diff --git a/public/images/brand/logo_dark.svg b/public/images/brand/logo_dark.svg new file mode 100644 index 000000000..265777fa3 --- /dev/null +++ b/public/images/brand/logo_dark.svg @@ -0,0 +1,12 @@ + + + React-Logo-Filled (1) + + + + + + + + + \ No newline at end of file diff --git a/public/images/brand/logo_light.svg b/public/images/brand/logo_light.svg new file mode 100644 index 000000000..bbe5a8994 --- /dev/null +++ b/public/images/brand/logo_light.svg @@ -0,0 +1,10 @@ + + + React-Logo-Filled (1) + + + + + + + \ No newline at end of file diff --git a/public/images/brand/wordmark_dark.svg b/public/images/brand/wordmark_dark.svg new file mode 100644 index 000000000..ec028ae21 --- /dev/null +++ b/public/images/brand/wordmark_dark.svg @@ -0,0 +1,15 @@ + + + Group + + + + + + + + + + + + \ No newline at end of file diff --git a/public/images/brand/wordmark_light.svg b/public/images/brand/wordmark_light.svg new file mode 100644 index 000000000..2de8f3cc7 --- /dev/null +++ b/public/images/brand/wordmark_light.svg @@ -0,0 +1,11 @@ + + + Group + + + + + + + + \ No newline at end of file diff --git a/public/images/team/lauren.jpg b/public/images/team/lauren.jpg index 1485cf8ff..cb08b9725 100644 Binary files a/public/images/team/lauren.jpg and b/public/images/team/lauren.jpg differ diff --git a/public/images/team/lesiutin.jpg b/public/images/team/lesiutin.jpg new file mode 100644 index 000000000..edfc942e0 Binary files /dev/null and b/public/images/team/lesiutin.jpg differ diff --git a/public/images/uwu.png b/public/images/uwu.png new file mode 100644 index 000000000..a09d245ea Binary files /dev/null and b/public/images/uwu.png differ diff --git a/public/mstile-150x150.png b/public/mstile-150x150.png new file mode 100644 index 000000000..d36e7ee9e Binary files /dev/null and b/public/mstile-150x150.png differ diff --git a/public/safari-pinned-tab.svg b/public/safari-pinned-tab.svg new file mode 100644 index 000000000..7e4874b2f --- /dev/null +++ b/public/safari-pinned-tab.svg @@ -0,0 +1,60 @@ + + + + +Created by potrace 1.14, written by Peter Selinger 2001-2017 + + + + + + diff --git a/public/site.webmanifest b/public/site.webmanifest new file mode 100644 index 000000000..337446d52 --- /dev/null +++ b/public/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "React", + "short_name": "React", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-384x384.png", + "sizes": "384x384", + "type": "image/png" + } + ], + "theme_color": "#23272f", + "background_color": "#23272f", + "display": "standalone" +} diff --git a/scripts/generateRss.js b/scripts/generateRss.js new file mode 100644 index 000000000..e0f3d5561 --- /dev/null +++ b/scripts/generateRss.js @@ -0,0 +1,6 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + */ +const {generateRssFeed} = require('../src/utils/rss'); + +generateRssFeed(); diff --git a/src/components/ButtonLink.tsx b/src/components/ButtonLink.tsx index 15ab83f2b..23c971756 100644 --- a/src/components/ButtonLink.tsx +++ b/src/components/ButtonLink.tsx @@ -26,7 +26,8 @@ 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 hover:bg-opacity-80': type === 'primary', + 'bg-link text-white dark:bg-brand-dark dark:text-secondary 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', 'text-lg py-3 rounded-full px-4 sm:px-6': size === 'lg', diff --git a/src/components/Icon/IconCanary.tsx b/src/components/Icon/IconCanary.tsx index a7782b141..7f584fed7 100644 --- a/src/components/Icon/IconCanary.tsx +++ b/src/components/Icon/IconCanary.tsx @@ -4,29 +4,35 @@ import {memo} from 'react'; -export const IconCanary = memo( - function IconCanary({className, title}) { - return ( - - {title && {title}} - - - - - - - ); +export const IconCanary = memo< + JSX.IntrinsicElements['svg'] & {title?: string; size?: 's' | 'md'} +>(function IconCanary( + {className, title, size} = { + className: undefined, + title: undefined, + size: 'md', } -); +) { + return ( + + {title && {title}} + + + + + + + ); +}); diff --git a/src/components/Layout/Footer.tsx b/src/components/Layout/Footer.tsx index fcfbd00a6..ad97079e2 100644 --- a/src/components/Layout/Footer.tsx +++ b/src/components/Layout/Footer.tsx @@ -285,6 +285,30 @@ export function Footer() { dir="ltr"> ©{new Date().getFullYear()} +
{ + // @ts-ignore + window.__setUwu(false); + }}> + no uwu plz +
+
{ + // @ts-ignore + window.__setUwu(true); + }}> + uwu? +
+
+ Logo by + + @sawaratsuki1004 + +
diff --git a/src/components/Layout/HomeContent.js b/src/components/Layout/HomeContent.js index 9ae138938..cddbe2719 100644 --- a/src/components/Layout/HomeContent.js +++ b/src/components/Layout/HomeContent.js @@ -24,8 +24,13 @@ import CodeBlock from 'components/MDX/CodeBlock'; import Link from 'components/MDX/Link'; import NextLink from 'next/link'; import sidebarBlog from '../../sidebarBlog.json'; +<<<<<<< HEAD import ButtonLink from '../ButtonLink'; import {IconRestart} from '../Icon/IconRestart'; +======= +import * as React from 'react'; +import Image from 'next/image'; +>>>>>>> 53fbed3f676013508fb9cce22a3fc8664b1dc5a1 function Section({children, background = null}) { return ( @@ -115,12 +120,22 @@ export function HomeContent() { <>
+
+ logo by @sawaratsuki1004 +
-

+

React

@@ -507,7 +522,15 @@ export function HomeContent() {

- +
+ logo by @sawaratsuki1004 +
+
Bienvenue dans la
communauté React @@ -1638,7 +1661,7 @@ function Thumbnail({video}) {
- + React Conf
diff --git a/src/components/Layout/Page.tsx b/src/components/Layout/Page.tsx index d1e23027d..dd854169c 100644 --- a/src/components/Layout/Page.tsx +++ b/src/components/Layout/Page.tsx @@ -3,12 +3,22 @@ */ import * as React from 'react'; +<<<<<<< HEAD import ButtonLink from 'components/ButtonLink'; import {DocsPageFooter} from 'components/DocsFooter'; import {Footer} from './Footer'; import {HomeContent} from './HomeContent'; import {IconNavArrow} from 'components/Icon/IconNavArrow'; +======= +import {useRouter} from 'next/router'; +import {SidebarNav} from './SidebarNav'; +import {Footer} from './Footer'; +import {Toc} from './Toc'; +// import SocialBanner from '../SocialBanner'; +import {DocsPageFooter} from 'components/DocsFooter'; +import {Seo} from 'components/Seo'; +>>>>>>> 53fbed3f676013508fb9cce22a3fc8664b1dc5a1 import PageHeading from 'components/PageHeading'; import type {RouteItem} from 'components/Layout/getRouteMeta'; import {Seo} from 'components/Seo'; @@ -17,11 +27,16 @@ import SocialBanner from '../SocialBanner'; import {Suspense} from 'react'; import {Toc} from './Toc'; import {TocContext} from '../MDX/TocContext'; +import {Languages, LanguagesContext} from '../MDX/LanguagesContext'; import type {TocItem} from 'components/MDX/TocContext'; import {TopNav} from './TopNav'; import cn from 'classnames'; +<<<<<<< HEAD import {getRouteMeta} from './getRouteMeta'; import {useRouter} from 'next/router'; +======= +import Head from 'next/head'; +>>>>>>> 53fbed3f676013508fb9cce22a3fc8664b1dc5a1 import(/* webpackPrefetch: true */ '../MDX/CodeBlock/CodeBlock'); @@ -36,9 +51,17 @@ interface PageProps { description?: string; }; section: 'learn' | 'reference' | 'community' | 'blog' | 'home' | 'unknown'; + languages?: Languages | null; } -export function Page({children, toc, routeTree, meta, section}: PageProps) { +export function Page({ + children, + toc, + routeTree, + meta, + section, + languages = null, +}: PageProps) { const {asPath} = useRouter(); const cleanedPath = asPath.split(/[\?\#]/)[0]; const {route, nextRoute, prevRoute, breadcrumbs, order} = getRouteMeta( @@ -75,7 +98,11 @@ export function Page({children, toc, routeTree, meta, section}: PageProps) { 'max-w-7xl mx-auto', section === 'blog' && 'lg:flex lg:flex-col lg:items-center' )}> - {children} + + + {children} + +
{!isBlogIndex && ( - + {(isHomePage || isBlogIndex) && ( + + + + )} + {/**/} {!isHomePage && (
+<<<<<<< HEAD {
} @@ -182,6 +218,9 @@ export function Page({children, toc, routeTree, meta, section}: PageProps) {
)} +======= +
+>>>>>>> 53fbed3f676013508fb9cce22a3fc8664b1dc5a1
)}
+ {index !== 0 && (
  • - {sectionHeader} + {sectionHeaderText} ); diff --git a/src/components/Layout/TopNav/BrandMenu.tsx b/src/components/Layout/TopNav/BrandMenu.tsx new file mode 100644 index 000000000..3bd8776f2 --- /dev/null +++ b/src/components/Layout/TopNav/BrandMenu.tsx @@ -0,0 +1,145 @@ +import * as ContextMenu from '@radix-ui/react-context-menu'; +import {IconCopy} from 'components/Icon/IconCopy'; +import {IconDownload} from 'components/Icon/IconDownload'; +import {IconNewPage} from 'components/Icon/IconNewPage'; +import {ExternalLink} from 'components/ExternalLink'; +import {IconClose} from '../../Icon/IconClose'; + +function MenuItem({ + children, + onSelect, +}: { + children: React.ReactNode; + onSelect?: () => void; +}) { + return ( + + {children} + + ); +} + +function DownloadMenuItem({ + fileName, + href, + children, +}: { + fileName: string; + href: string; + children: React.ReactNode; +}) { + return ( + + {children} + + ); +} + +export default function BrandMenu({children}: {children: React.ReactNode}) { + return ( + + + {children} + + + + + Dark Mode + + + + + + Logo SVG + + + + + + Wordmark SVG + + { + await navigator.clipboard.writeText('#58C4DC'); + }}> + + + + Copy dark mode color + + + Light Mode + + + + + + Logo SVG + + + + + + Wordmark SVG + + { + await navigator.clipboard.writeText('#087EA4'); + }}> + + + + Copy light mode color + +
    + + + uwu + + { + // @ts-ignore + window.__setUwu(false); + }}> + + + + Turn off + + + + + + Logo PNG + + + + + + + + Logo by @sawaratsuki1004 + + +
    +
    +
    +
    + ); +} diff --git a/src/components/Layout/TopNav/TopNav.tsx b/src/components/Layout/TopNav/TopNav.tsx index 870be9e87..3f7a539cd 100644 --- a/src/components/Layout/TopNav/TopNav.tsx +++ b/src/components/Layout/TopNav/TopNav.tsx @@ -12,6 +12,14 @@ import { useRef, useState, } from 'react'; +<<<<<<< HEAD +======= +import Image from 'next/image'; +import * as React from 'react'; +import cn from 'classnames'; +import NextLink from 'next/link'; +import {useRouter} from 'next/router'; +>>>>>>> 53fbed3f676013508fb9cce22a3fc8664b1dc5a1 import {disableBodyScroll, enableBodyScroll} from 'body-scroll-lock'; import {Feedback} from '../Feedback'; @@ -21,10 +29,15 @@ import {IconSearch} from 'components/Icon/IconSearch'; import {Logo} from '../../Logo'; import NextLink from 'next/link'; import type {RouteItem} from '../getRouteMeta'; +<<<<<<< HEAD import {Search} from 'components/Search'; import {SidebarRouteTree} from '../Sidebar/SidebarRouteTree'; import cn from 'classnames'; import {useRouter} from 'next/router'; +======= +import {siteConfig} from 'siteConfig'; +import BrandMenu from './BrandMenu'; +>>>>>>> 53fbed3f676013508fb9cce22a3fc8664b1dc5a1 declare global { interface Window { @@ -78,6 +91,19 @@ const lightIcon = ( ); +const languageIcon = ( + + + +); + const githubIcon = ( (null); const {asPath} = useRouter(); - const [isScrolled, setIsScrolled] = useState(false); // HACK. Fix up the data structures instead. if ((routeTree as any).routes.length === 1) { @@ -155,18 +182,18 @@ export default function TopNav({ // While the overlay is open, disable body scroll. useEffect(() => { - if (isOpen) { + if (isMenuOpen) { const preferredScrollParent = scrollParentRef.current!; disableBodyScroll(preferredScrollParent); return () => enableBodyScroll(preferredScrollParent); } else { return undefined; } - }, [isOpen]); + }, [isMenuOpen]); // Close the overlay on any navigation. useEffect(() => { - setIsOpen(false); + setIsMenuOpen(false); }, [asPath]); // Also close the overlay if the window gets resized past mobile layout. @@ -176,7 +203,7 @@ export default function TopNav({ function closeIfNeeded() { if (!media.matches) { - setIsOpen(false); + setIsMenuOpen(false); } } @@ -205,7 +232,6 @@ export default function TopNav({ return () => observer.disconnect(); }, []); - const [showSearch, setShowSearch] = useState(false); const onOpenSearch = useCallback(() => { startTransition(() => { setShowSearch(true); @@ -225,39 +251,63 @@ export default function TopNav({
    - {isOpen && ( + {isMenuOpen && (