Files
react.dev/beta/src/components/Layout/HomeContent.js
2023-02-04 20:51:45 -08:00

1040 lines
40 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/
import {createContext, useState, useContext, Suspense} from 'react';
import ButtonLink from '../ButtonLink';
import {IconRestart} from '../Icon/IconRestart';
import {Logo} from 'components/Logo';
import Link from 'components/MDX/Link';
import CodeBlock from 'components/MDX/CodeBlock';
import cn from 'classnames';
export function HomeContent() {
return (
<>
<div className="pl-0">
<div className="mx-5 mt-12 mb-20 flex flex-col justify-center">
<Logo className="mt-4 mb-3 text-link dark:text-link-dark w-24 lg:w-28 self-center" />
<h1 className="text-5xl lg:text-6xl self-center flex font-bold leading-snug text-primary dark:text-primary-dark">
React
</h1>
<p className="text-4xl py-1 text-center text-secondary dark:text-primary-dark leading-snug self-center">
The library for web and native user interfaces
</p>
<div className="my-5 self-center flex gap-2 w-full sm:w-auto flex-col sm:flex-row">
<ButtonLink
href={'/learn'}
type="primary"
size="lg"
className="w-full sm:w-auto justify-center"
label="Take the Tutorial">
Learn React
</ButtonLink>
<ButtonLink
href={'/reference/react'}
type="secondary"
size="lg"
className="w-full sm:w-auto justify-center"
label="Take the Tutorial">
API Reference
</ButtonLink>
</div>
</div>
<div className="">
<div className="mx-auto bg-card dark:bg-card-dark shadow-inner mt-8 flex flex-col w-full">
<div className="flex-col gap-2 flex grow w-full my-16 lg:my-20 mx-auto items-center">
<div className="px-5 lg:px-0 max-w-4xl text-center text-white text-opacity-80">
<h3 className="leading-tight text-primary dark:text-primary-dark font-semibold text-4xl lg:text-5xl mb-6">
Create user interfaces from components
</h3>
<p className="text-xl lg:text-2xl text-secondary dark:text-secondary-dark leading-normal">
React lets you build user interfaces out of individual pieces
called components. Create your own React components like a
button, a panel, or an avatar. Then combine them into entire
screens, pages, and apps.
</p>
</div>
<Example1 />
<div className="px-5 lg:px-0 max-w-4xl text-center text-white text-opacity-80">
<p className="text-xl lg:text-2xl text-secondary dark:text-secondary-dark leading-normal">
Whether you work on your own or with thousands of other
developers, using React feels the same. It is designed to let
you seamlessly combine components written by independent
people, teams, and organizations.
</p>
</div>
</div>
</div>
</div>
<div className="">
<div className="max-w-6xl mx-auto flex flex-col w-full">
<div className="flex-col gap-2 flex grow w-full my-16 lg:my-20 mx-auto items-center">
<div className="px-5 lg:px-0 max-w-4xl text-center text-opacity-80">
<h3 className="leading-tight dark:text-primary-dark text-primary font-bold text-4xl lg:text-5xl mb-6">
Write components with code and markup
</h3>
<p className="text-xl lg:text-2xl leading-normal">
React components are JavaScript functions. Want to show
something conditionally? Use an <Code>if</Code> statement.
Need to display a list? Use a <Code>for</Code> loop or array{' '}
<Code>map()</Code>. Learning React is learning programming.
</p>
</div>
<div className="max-w-6xl mx-auto flex flex-col w-full">
<Example2 />
</div>
<div className="px-5 lg:px-0 max-w-4xl text-center text-opacity-80">
<p className="text-xl lg:text-2xl leading-normal">
This markup syntax is called JSX. It is a JavaScript syntax
extension popularized by React. Putting JSX markup close to
related rendering logic makes React components easy to create,
maintain, and delete.
</p>
</div>
</div>
</div>
</div>
<div className="shadow-inner bg-card dark:bg-card-dark">
<div className="max-w-6xl mx-auto flex flex-col w-full">
<div className="flex-col gap-2 flex grow w-full my-16 lg:my-20 mx-auto items-center">
<div className="px-5 lg:px-0 max-w-4xl text-center text-opacity-80">
<h3 className="leading-tight dark:text-primary-dark text-primary font-bold text-4xl lg:text-5xl mb-6">
Go full-stack with a framework
</h3>
<p className="text-xl lg:text-2xl text-secondary dark:text-secondary-dark leading-normal">
React is a library. It lets you put components together, but
it doesnt prescribe solutions for routing and data fetching.
To get the most out of React, we recommend a React framework
like{' '}
<Link href="https://github.com/vercel/next.js">Next.js</Link>,{' '}
<Link href="https://remix.run/">Remix</Link>, and{' '}
<Link href="https://expo.dev/">Expo</Link>. Frameworks let you
create full-stack apps with very little configuration.
</p>
</div>
<div className="max-w-6xl mx-auto flex flex-col w-full">
<Example3 />
</div>
<div className="px-5 lg:px-0 max-w-4xl text-center text-secondary dark:text-secondary-dark">
<p className="text-xl lg:text-2xl text-secondary dark:text-secondary-dark leading-normal">
To frameworks, React is more than a libraryReact is an
architecture. React provides a unified programming model that
spans across client and server so that you can use both of
them for what they are best at.
</p>
</div>
</div>
</div>
</div>
<div className="">
<div className="max-w-6xl mx-auto flex flex-col w-full">
<div className="flex-col gap-2 flex grow w-full my-16 lg:my-20 mx-auto items-center">
<div className="px-5 lg:px-0 max-w-4xl text-center text-opacity-80">
<h3 className="leading-tight dark:text-primary-dark text-primary font-bold text-4xl lg:text-5xl mb-6">
Make the best use of the platform
</h3>
<p className="text-xl lg:text-2xl leading-normal text-secondary dark:text-secondary-dark">
Web users expect pages to load fast. React can render into an
HTML stream on the server, gradually revealing more content
even before React itself has loaded on the client. React
relies on modern web standards to keep the page responsive
even during rendering.
</p>
</div>
<br />
<div className="px-5 lg:px-0 max-w-4xl text-center text-opacity-80">
<p className="text-xl lg:text-2xl text-secondary dark:text-secondary-dark leading-normal">
Mobile app users expect native look-and-feel. With{' '}
<Link href="https://reactnative.dev">React Native</Link>, you
can create Android and iOS apps with React. These user
interfaces can feel truly native because they <i>are</i> truly
native. Your React components render real Android and iOS
views natively provided by the platform.
</p>
</div>
</div>
</div>
</div>
<div className="">
<div className="max-w-6xl mx-auto flex flex-col w-full">
<div className="flex-col gap-2 flex grow w-full my-16 lg:my-20 mx-auto items-center">
<div className="px-5 lg:px-0 max-w-4xl text-center text-opacity-80">
<h3 className="leading-tight dark:text-primary-dark text-primary font-bold text-4xl lg:text-5xl mb-6">
Use as little or as much React as you need
</h3>
<p className="text-xl lg:text-2xl leading-normal text-secondary dark:text-secondary-dark">
Many teams build their entire user interface with React. For
example, the web experiences of
<Link href="https://facebook.com"> Facebook</Link>,
<Link href="https://instagram.com"> Instagram</Link>,
<Link href="https://www.tiktok.com/en/"> TikTok</Link>,
<Link href="https://twitter.com/"> Twitter</Link>,
<Link href="https://airbnb.com/"> Airbnb</Link>,
<Link href="https://spotify.com/"> Spotify</Link>,
<Link href="https://trello.com/"> Trello</Link>, and
<Link href="https://www.nytimes.com/">
The New York Times
</Link>{' '}
are fully powered by React.
</p>
</div>
</div>
</div>
</div>
<div className="">
<div className="max-w-6xl mx-auto flex flex-col w-full">
<div className="flex-col gap-2 flex grow w-full my-16 lg:my-20 mx-auto items-center">
<div className="px-5 lg:px-0 max-w-4xl text-center text-opacity-80">
<h3 className="leading-tight dark:text-primary-dark text-primary font-bold text-4xl lg:text-5xl mb-6">
Stability without stagnation
</h3>
<p className="text-xl lg:text-2xl leading-normal text-secondary dark:text-secondary-dark">
React approaches changes with care. Every React commit is
tested on business-critical surfaces with hundreds of millions
of users. When an API is deprecated, we add warnings and
publish automatic scripts to assist with the migration. The
100,000 React components in the Meta codebase help validate
every migration strategy. The React team is also always
researching how to improve React. React has a high bar for
taking an idea from research to production. Only proven
approaches become part of React.
<br />
<Link href="#">Learn about our latest research</Link>
</p>
</div>
</div>
</div>
</div>
<div className="overflow-hidden relative px-5">
<div className="border-2 border-link dark:border-link-dark rounded-lg absolute h-full border left-1/2"></div>
<div className="-mb-12 flex justify-between flex-row-reverse items-center w-full left-timeline">
<div className="order-1 w-5/12"></div>
<div className="order-1 w-5/12 px-1 py-4 text-right">
<p className="mb-2 text-base text-link dark:text-link-dark">
Q1 2022
</p>
<h4 className="mb-3 font-bold text-xl sm:text-2xl lg:text-3xl">
React v18
</h4>
<p className="text-base lg:text-md leading-normal text-secondary-text dark:text-secondary-text-dark">
Lorem ipsum dolor
</p>
</div>
</div>
<div className="-mb-12 flex justify-between items-center w-full right-timeline">
<div className="order-1 w-5/12"></div>
<div className="order-1 w-5/12 px-1 py-4 text-left">
<p className="mb-2 text-base text-link dark:text-link-dark">
Q4 2020
</p>
<h4 className="mb-3 font-bold text-xl sm:text-2xl lg:text-3xl">
Server components
</h4>
<p className="text-base lg:text-md leading-normal text-secondary-text dark:text-secondary-text-dark">
Lorem ipsum dolor
</p>
</div>
</div>
<div className="-mb-12 flex justify-between flex-row-reverse items-center w-full left-timeline">
<div className="order-1 w-5/12"></div>
<div className="order-1 w-5/12 px-1 py-4 text-right">
<p className="mb-2 text-base text-link dark:text-link-dark">
Q4 2020
</p>
<h4 className="mb-3 font-bold text-xl sm:text-2xl lg:text-3xl">
React v17
</h4>
<p className="text-base lg:text-md leading-normal text-secondary-text dark:text-secondary-text-dark">
Lorem ipsum dolor
</p>
</div>
</div>
<div className="-mb-12 flex justify-between items-center w-full right-timeline">
<div className="order-1 w-5/12"></div>
<div className="order-1 w-5/12 px-1 py-4 text-left">
<p className="mb-2 text-base text-link dark:text-link-dark">
Q1 2019
</p>
<h4 className="mb-3 font-bold text-xl sm:text-2xl lg:text-3xl">
Hooks
</h4>
<p className="text-base lg:text-md leading-normal text-secondary-text dark:text-secondary-text-dark">
Lorem ipsum dolor
</p>
</div>
</div>
<div className="flex justify-between flex-row-reverse items-center w-full left-timeline">
<div className="order-1 w-5/12"></div>
<div className="order-1 w-5/12 px-1 py-4 text-right">
<p className="mb-2 text-base text-link dark:text-link-dark">
Q4 2017
</p>
<h4 className="mb-3 font-bold text-xl sm:text-2xl lg:text-3xl">
React v16
</h4>
<p className="text-base lg:text-md leading-normal text-secondary-text dark:text-secondary-text-dark">
Lorem ipsum dolor
</p>
</div>
</div>
</div>
<div className="mx-5">
<div className="mx-auto my-40 max-w-6xl bg-blue-80 rounded-3xl flex-col-reverse lg:flex-row flex items-center">
<div className="w-full lg:w-6/12 p-12 flex-col text-white flex grow items-end justify-start my-0 mx-auto">
<h3 className="w-full leading-tight font-bold text-4xl mb-6 text-left">
Stability without stagnation
</h3>
<p className="text-xl leading-normal text-secondary-dark w-full text-left">
React approaches changes with care. Every React commit is tested
on business-critical surfaces with hundreds of millions of
users.
</p>
</div>
<div className="text-secondary-dark w-full lg:w-6/12 px-20 py-60 rounded-tl-3xl rounded-tr-3xl lg:rounded-r-3xl lg:rounded-tl-none justify-center leading-6 overflow-x-auto flex items-center bg-blue-60 overflow-hidden">
Illustration goes here
</div>
</div>
</div>
<div className="my-16 lg:my-20 px-12 flex flex-col w-full">
<h3 className="w-full leading-tight font-bold text-5xl text-primary dark:text-primary-dark mt-20 text-center">
React homepage section header
</h3>
<div className="mb-20 mt-12 gap-8 mx-auto flex flex-col max-w-6xl">
<div className="lg:gap-20 w-full rounded-3xl flex-col lg:flex-row flex items-center">
<div className="w-full lg:w-6/12 px-20 py-40 rounded-lg my-8 justify-center leading-6 overflow-x-auto flex items-center bg-wash dark:bg-gray-95 shadow-lg overflow-hidden">
Illustration goes here
</div>
<div className="w-full lg:w-6/12 p-8 flex-col text-primary dark:text-primary-dark flex grow items-end justify-start my-0 mx-auto">
<h3 className="w-full leading-tight font-bold text-4xl mb-6 text-left">
Use as little or as much <br />
React as you need
</h3>
<p className="text-xl leading-normal text-secondary dark:text-secondary-dark w-full text-left">
Many teams build their entire user interface with React.
</p>
</div>
</div>
<div className="w-full lg:gap-20 rounded-3xl flex-col-reverse lg:flex-row flex items-center">
<div className="w-full lg:w-6/12 p-8 flex-col text-primary dark:text-primary-dark flex grow items-end justify-start my-0 mx-auto">
<h3 className="w-full leading-tight font-bold text-4xl mb-6 text-left">
Stability without stagnation
</h3>
<p className="text-xl leading-normal text-secondary dark:text-secondary-dark w-full text-left">
React approaches changes with care. Every React commit is
tested on business-critical surfaces with hundreds of millions
of users.
</p>
</div>
<div className="w-full lg:w-6/12 px-20 py-40 rounded-lg my-8 justify-center leading-6 overflow-x-auto flex items-center bg-wash dark:bg-gray-95 shadow-lg overflow-hidden">
Illustration goes here
</div>
</div>
<div className="w-full rounded-3xl lg:gap-20 flex-col lg:flex-row flex items-center">
<div className="w-full lg:w-6/12 rounded-lg px-20 py-40 my-8 justify-center leading-6 overflow-x-auto flex items-center bg-wash dark:bg-gray-95 shadow-lg overflow-hidden">
Illustration goes here
</div>
<div className="flex-col p-8 w-full lg:w-6/12 text-primary dark:text-primary-dark flex grow items-end justify-start mx-auto">
<h3 className="w-full leading-tight font-bold text-4xl mb-6 text-left">
Let a framework take care of the rest
</h3>
<p className="text-xl text-secondary dark:text-secondary-dark text-opacity-80 leading-normal text-left">
React is a library. It lets you create components and put them
together, but it doesn&apos;t prescribe solutions for routing
and data fetching.
</p>
</div>
</div>
</div>
</div>
<div className="bg-link bg-opacity-8 my-16 lg:my-20 max-w-6xl mx-auto rounded-3xl p-20 text-base text-secondary dark:text-secondary-dark flex flex-col w-full justify-center items-center">
<Logo className="text-link dark:text-link-dark w-36 mt-12 h-auto mx-auto self-start" />
<div className="flex flex-wrap">
<div className="mb-8 mt-4">
<h1 className="text-center text-6xl mr-4 flex wrap font-bold leading-tight text-primary dark:text-primary-dark">
Welcome to the React community
</h1>
<p className="text-4xl w-full text-center text-secondary dark:text-secondary-dark leading-relaxed self-center my-2">
Get started today.
</p>
</div>
</div>
</div>
<div className="my-16 lg:my-20 px-12 flex flex-col w-full">
<div className="p-20 text-base text-secondary dark:text-secondary-dark flex flex-col w-full justify-center items-center">
<Logo className="text-link dark:text-link-dark w-36 mt-12 h-auto mx-auto self-start" />
<div className="flex flex-wrap">
<div className="mb-8 mt-4">
<h1 className="text-center text-6xl mr-4 flex wrap font-bold leading-tight text-primary dark:text-primary-dark">
Welcome to the React community
</h1>
<p className="text-4xl w-full text-center text-secondary dark:text-secondary-dark leading-relaxed self-center my-2">
Get started today.
</p>
</div>
</div>
</div>
</div>
</div>
</>
);
}
function Example1() {
return (
<div className="lg:pl-10 lg:pr-5 w-full">
<div className="my-16 lg:my-20 max-w-6xl mx-auto flex flex-col w-full border-t lg:border border-border dark:border-opacity-10 lg:rounded-2xl bg-card dark:bg-card-dark">
<div className="flex-col-reverse gap-5 lg:rounded-xl bg-secondary-button dark:bg-secondary-button-dark shadow-inner lg:flex-row gap-8 flex grow w-full mx-auto items-center">
<div className="-m-5 h-full shadow-xl lg:rounded-2xl bg-wash dark:bg-gray-95 w-full flex grow flex-col border-t lg:border border-border dark:border-border-dark">
<div className="w-full bg-card dark:bg-wash-dark lg:rounded-t-2xl border-b border-border dark:border-border-dark">
<h3 className="text-sm my-1 mx-5 text-gray-50 dark:text-gray-30 select-none">
Comment.js
</h3>
</div>
<CodeBlock
isFromPackageImport={false}
noShadow={true}
noMargin={true}>
<div>{`function Comment({ comment }) {
return (
<div>
<Avatar user={comment.author} />
<ProfileLink to={comment.author} />
<Timestamp time={comment.postedAt} />
<p>{comment.text}</p>
</div>
);
}
`}</div>
</CodeBlock>
</div>
<div className="w-full p-5 flex grow justify-center">
<ExamplePanel>
<Comment
comment={{
text: 'The quick brown fox jumps over the lazy dog',
postedAt: '2m ago',
author: {
name: 'First name',
image: null,
},
}}
/>
</ExamplePanel>
</div>
</div>
</div>
</div>
);
}
const PostContext = createContext(null);
const author = {
name: 'First name',
image: null,
};
function Example2() {
const [comments, setComments] = useState([
{
id: 0,
text: 'The quick brown fox jumps over the lazy dog',
postedAt: '10m ago',
author,
},
{
id: 1,
text: 'The quick brown fox jumps over the lazy dog',
postedAt: '4m ago',
author,
},
{
id: 2,
text: 'The quick brown fox jumps over the lazy dog',
postedAt: '2m ago',
author,
},
]);
function handleAddComment(text) {
setComments((c) => [
...c,
{
id: c.length,
text,
postedAt: 'just now',
author,
},
]);
}
return (
<div className="lg:pl-10 lg:pr-5 w-full">
<div className="my-16 lg:my-20 max-w-6xl mx-auto flex flex-col w-full border-t lg:border border-border dark:border-opacity-10 lg:rounded-xl bg-card dark:bg-card-dark">
<div className="flex-col-reverse gap-5 bg-secondary-button dark:bg-secondary-button-dark shadow-inner lg:rounded-xl lg:flex-row gap-8 flex grow w-full mx-auto items-center">
<div className="-m-5 h-full shadow-xl lg:rounded-xl bg-wash dark:bg-gray-95 w-full flex grow flex-col border-t lg:border border-border dark:border-border-dark">
<div className="w-full bg-card dark:bg-wash-dark lg:rounded-t-xl border-b border-border dark:border-border-dark">
<h3 className="text-sm my-1 mx-5 text-gray-50 dark:text-gray-30 select-none">
CommentList.js
</h3>
</div>
<CodeBlock
isFromPackageImport={false}
noShadow={true}
noMargin={true}>
<div>{`function CommentList({ comments }) {
let heading = 'Be the first to comment';
if (comments.length > 0) {
heading = comments.length + ' Comments';
}
return (
<section>
<h1>{heading}</h1>
{comments.map(comment =>
<Comment key={comment.id} comment={comment} />
)}
</section>
);
}`}</div>
</CodeBlock>
</div>
<div className="w-full p-5 flex grow justify-center">
<ExamplePanel noShadow={false} noPadding={true} height={310}>
<PostContext.Provider
value={{
currentUser: author,
onAddComment: handleAddComment,
}}>
<CommentList comments={comments} />
</PostContext.Provider>
</ExamplePanel>
</div>
</div>
</div>
</div>
);
}
function Example3() {
const [postPromise, setPostPromise] = useState(null);
const [commentsPromise, setCommentsPromise] = useState(null);
const [comments, setComments] = useState([
{
id: 0,
text: 'fika :D',
postedAt: '1h ago',
author: {
name: 'Luna',
image: {
url: 'https://i.imgur.com/B3E9zDz.jpg',
},
},
},
{
id: 1,
text: `ok, I have to ask. What is FIKA?`,
postedAt: '12m ago',
author: {
name: 'Samuel',
image: {
url: 'https://i.imgur.com/OUkVY2C.jpg',
},
},
},
{
id: 2,
text:
`It's a thing the core team used to do, I believe (never been to one). ` +
`Basically grab a drink and/or snack and just chill for a bit together`,
postedAt: '7m ago',
author: {
name: 'Lauren',
image: {
url: 'https://i.imgur.com/8ayW9oH.jpg',
},
},
},
{
id: 3,
text: `When I ask to get cofee, I really mean "fika".`,
postedAt: '4m ago',
author: {
name: 'Sebastian',
image: {
url: 'https://i.imgur.com/FX7DZbQ.jpg',
},
},
},
{
id: 4,
text: `There's no english word for it.`,
postedAt: '4m ago',
author: {
name: 'Sebastian',
image: {
url: 'https://i.imgur.com/FX7DZbQ.jpg',
},
},
},
{
id: 5,
text: `we need more sweets to go with the coffee!`,
postedAt: '2m ago',
author: {
name: 'Yuzhi',
image: {
url: 'https://i.imgur.com/jxLrU8B.jpg',
},
},
},
]);
function handleAddComment(text) {
setComments((c) => [
...c,
{
id: c.length,
text,
postedAt: 'just now',
author,
},
]);
}
return (
<div className="lg:pl-10 lg:pr-5 w-full">
<div className="my-16 lg:my-20 max-w-6xl mx-auto flex flex-col w-full border-t lg:border border-border dark:border-opacity-10 lg:rounded-2xl bg-card dark:bg-card-dark">
<div className="flex-col-reverse gap-5 lg:rounded-xl bg-secondary-button dark:bg-secondary-button-dark shadow-inner lg:flex-row gap-8 flex grow w-full mx-auto items-center">
<div className="-m-5 h-full shadow-xl lg:rounded-2xl bg-wash dark:bg-gray-95 w-full flex grow flex-col border-t lg:border border-border dark:border-border-dark">
<div className="w-full bg-card dark:bg-wash-dark lg:rounded-t-2xl border-b border-border dark:border-border-dark">
<h3 className="text-sm my-1 mx-5 text-gray-50 dark:text-gray-30 select-none">
PostPage.js
</h3>
</div>
<CodeBlock
isFromPackageImport={false}
noShadow={true}
noMargin={true}>
<div>{`async function PostPage({ slug }) {
const post = await db.findPost({ slug });
return (
<PostLayout coverUrl={post.coverUrl}>
<Suspense fallback={<CommentsSkeleton />}>
<PostComments postId={post.id} />
</Suspense>
</PostLayout>
);
}
async function PostComments({ postId }) {
const comments = await db.findComments({ postId });
return (
<>
<CommentList comments={comments} />
<AddComment postId={postId} />
</>
);
}`}</div>
</CodeBlock>
</div>
<div className="w-full p-5 sm:p-5 flex grow justify-center">
<BrowserChrome
setPostPromise={setPostPromise}
setCommentsPromise={setCommentsPromise}>
<ExamplePanel noPadding={true} noShadow={true} height={475}>
<Suspense fallback={null}>
<div style={{animation: 'fadein 200ms'}}>
<PostContext.Provider
value={{
currentUser: author,
onAddComment: handleAddComment,
}}>
<PostPage
post={{
coverUrl: 'https://i.imgur.com/Q7TJkPm.jpg',
comments,
}}
postPromise={postPromise}
commentsPromise={commentsPromise}
/>
</PostContext.Provider>
</div>
</Suspense>
</ExamplePanel>
</BrowserChrome>
</div>
</div>
</div>
</div>
);
}
function ExamplePanel({children, noPadding, noShadow, height}) {
return (
<div
style={{
padding: noPadding ? 0 : '20px 20px 0 20px',
boxShadow: noShadow
? 'none'
: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
borderRadius: 20,
margin: '0 auto',
color: '#404756',
fontSize: 15,
lineHeight: 1.5,
backgroundColor: '#fefefe',
minHeight: 40,
overflow: 'hidden',
width: '100%',
height,
}}>
{children}
</div>
);
}
function BrowserChrome({children, setPostPromise, setCommentsPromise}) {
function handleRestart() {
const postPromise = new Promise((resolve) => {
setTimeout(() => {
postPromise._resolved = true;
resolve();
}, 200);
});
const commentsPromise = new Promise((resolve) => {
setTimeout(() => {
commentsPromise._resolved = true;
resolve();
}, 2200);
});
setPostPromise(postPromise);
setCommentsPromise(commentsPromise);
}
return (
<div className="bg-wash dark:bg-gray-95 shadow-xl relative overflow-hidden w-full border border-border dark:border-opacity-10 rounded-2xl">
<div className="w-full h-16 border-b border-border backdrop-filter rounded-t-2xl overflow-hidden backdrop-blur-lg backdrop-saturate-200 bg-white bg-opacity-90 z-10 absolute top-0 py-4 px-4 gap-2 flex flex-row items-center">
<div className="bg-gray-10 text-sm text-gray-50 text-center rounded-full p-1 w-full flex-row flex space-between items-center">
<div className="h-6 w-6" />
<div className="w-full leading-snug">
<span className="text-gray-30">example.com</span>
/posts/its-fika-time
</div>
<button
onClick={handleRestart}
className="flex items-center p-1.5 rounded-full hover:bg-gray-20 hover:bg-opacity-50 cursor-pointer justify-center">
<IconRestart className="text-primary text-lg" />
</button>
</div>
</div>
<div className="">{children}</div>
</div>
);
}
function PostPage({post, postPromise, commentsPromise}) {
if (postPromise && !postPromise._resolved) {
throw postPromise;
}
return (
<PostCover imageUrl={post.coverUrl}>
<Suspense fallback={<CommentsSkeleton />}>
<PostComments post={post} commentsPromise={commentsPromise} />
</Suspense>
</PostCover>
);
}
function CommentsSkeleton() {
return (
<div className="flex flex-col items-center h-[320px] overflow-hidden">
<div className="w-full">
<div className="relative overflow-hidden before:-skew-x-12 before:absolute before:inset-0 before:-translate-x-full before:animate-[shimmer_1.75s_infinite] before:bg-gradient-to-r before:from-transparent before:via-white/50 before:to-transparent">
<div className="space-y-3 space-x-5">
<div />
<div className="pt-3.5">
<div className="h-5 w-32 rounded-lg bg-gray-10"></div>
</div>
<div className="flex flex-row items-center gap-3 pt-2">
<div className="h-8 w-8 rounded-full bg-gray-10"></div>
<div className="h-3 w-12 rounded-lg bg-gray-10"></div>
</div>
<div className="h-3.5 w-2/5 rounded-lg bg-gray-10"></div>
<div className="flex flex-row items-center gap-3 pt-3">
<div className="h-8 w-8 rounded-full bg-gray-10"></div>
<div className="h-3 w-20 rounded-lg bg-gray-10"></div>
</div>
<div className="h-3.5 w-3/5 rounded-lg bg-gray-10"></div>
<div className="flex flex-row items-center gap-3 pt-3">
<div className="h-8 w-8 rounded-full bg-gray-10"></div>
<div className="h-3 w-20 rounded-lg bg-gray-10"></div>
</div>
<div className="h-3.5 w-3/5 rounded-lg bg-gray-10"></div>
</div>
</div>
</div>
</div>
);
}
function PostComments({post, commentsPromise}) {
if (commentsPromise && !commentsPromise._resolved) {
throw commentsPromise;
}
return (
<CommentList comments={post.comments}>
<AddComment />
</CommentList>
);
}
function CommentList({comments, children}) {
let headingText = 'Be the first to comment';
if (comments.length > 0) {
headingText = comments.length + ' Comments';
}
return (
<div
style={{
maxHeight: 250,
position: 'relative',
paddingTop: 20,
paddingLeft: 20,
paddingRight: 20,
}}>
<Stack gap={0}>
<Heading>{headingText}</Heading>
{comments.map((comment) => (
<Comment key={comment.id} comment={comment} />
))}
{children}
</Stack>
</div>
);
}
function PostCover({imageUrl, children}) {
return (
<>
<div style={{overflowY: 'scroll'}}>
<div
style={{
height: 160,
marginTop: 64,
overflow: 'hidden',
}}>
<img
src={imageUrl}
alt="Cover image"
width="100%"
style={{maxWidth: '100%'}}
/>
</div>
{children}
</div>
</>
);
}
function Heading({children}) {
return (
<h1
style={{
fontWeight: 'bold',
fontSize: 20,
color: '#23272F',
lineHeight: '100%',
paddingBottom: 20,
}}>
{children}
</h1>
);
}
function AddComment() {
const {currentUser, onAddComment} = useContext(PostContext);
return (
<div
style={{
position: 'sticky',
bottom: 0,
zIndex: 10,
paddingBottom: 15,
background: 'white',
width: '100%',
}}>
<hr style={{paddingTop: 15}} />
<Row>
<Avatar user={currentUser} />
<form
style={{width: '100%', display: 'flex', alignItems: 'center'}}
onSubmit={(e) => {
e.preventDefault();
const formData = new FormData(e.target);
const json = Object.fromEntries(formData.entries());
onAddComment(json.text);
e.target.reset();
}}>
<input
name="text"
placeholder="Add a comment..."
autoComplete="off"
style={{
backgroundColor: 'transparent',
outline: 'none',
width: '100%',
}}
/>
</form>
</Row>
</div>
);
}
function Comment({comment}) {
const {author} = comment;
return (
<div style={{margin: '0 0 20px 0'}}>
<Stack gap={8}>
<Row>
<Avatar user={author} />
<ExampleLink to={author.url}>{author.name}</ExampleLink>
<Timestamp time={comment.postedAt} />
</Row>
{comment.text}
</Stack>
</div>
);
}
function Stack({children, gap}) {
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
gap,
}}>
{children}
</div>
);
}
function Code({children}) {
return (
<span className="font-mono inline rounded-lg bg-secondary-button dark:bg-secondary-button-dark py-0.5 px-1">
{children}
</span>
);
}
function Row({children}) {
return <div style={{display: 'flex', flexDirection: 'row'}}>{children}</div>;
}
function ExampleLink({children}) {
return (
<div
style={{
fontSize: 17,
marginTop: 3,
marginRight: 10,
color: '#23272F',
fontWeight: 'bold',
}}>
{children}
</div>
);
}
function Avatar({user}) {
return (
<div
style={{
marginRight: 10,
minHeight: 32,
minWidth: 32,
borderRadius: '50%',
position: 'relative',
display: 'flex',
alignItems: 'end',
overflow: 'hidden',
justifyContent: 'center',
verticalAlign: 'middle',
transition: 'all 0.4s ease-in-out',
backgroundColor: '#EBECF0',
backgroundImage: user.image ? `url(${user.image.url})` : null,
backgroundSize: 'cover',
}}>
{user.image ? null : <AvatarPlaceholder />}
<div
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
borderRadius: '50%',
boxShadow: 'inset 0 0 0 1px rgba(0,0,0,.1)',
}}
/>
</div>
);
}
function AvatarPlaceholder() {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
style={{marginBottom: -1}}
width="24"
height="24"
viewBox="0 0 24 24">
<g fill="none" fillRule="evenodd" transform="translate(-444 -156)">
<g fill="#99A1B3" transform="translate(353 156)">
<path d="M106.75,5.75 C106.75,8.2355 105.0715,10.25 103,10.25 C100.9285,10.25 99.25,8.2355 99.25,5.75 C99.25,3.2645 100.3215,1.25 103,1.25 C105.6785,1.25 106.75,3.2645 106.75,5.75" />
<path
fillRule="nonzero"
d="M107.5,5.75 C107.5,8.62264765 105.518964,11 103,11 C100.481036,11 98.5,8.62264765 98.5,5.75 C98.5,2.60742209 100.059741,0.5 103,0.5 C105.940259,0.5 107.5,2.60742209 107.5,5.75 Z M106,5.75 C106,3.35481964 104.997273,2 103,2 C101.002727,2 100,3.35481964 100,5.75 C100,7.84855959 101.376137,9.5 103,9.5 C104.623863,9.5 106,7.84855959 106,5.75 Z"
/>
<path d="M110.3008,22.75 L95.6993,22.75 C94.6268,22.75 93.7498,21.873 93.7498,20.801 L93.7498,19.601 C93.7498,16.108 96.6078,13.25 100.1013,13.25 L105.8988,13.25 C109.3923,13.25 112.2498,16.108 112.2498,19.601 L112.2498,20.801 C112.2498,21.873 111.3733,22.75 110.3008,22.75" />
<path
fillRule="nonzero"
d="M110.3008,23.5 L95.6993,23.5 C94.2126937,23.5 92.9998,22.2873208 92.9998,20.801 L92.9998,19.601 C92.9998,15.6936997 96.1936731,12.5 100.1013,12.5 L105.8988,12.5 C109.80635,12.5 112.9998,15.6936231 112.9998,19.601 L112.9998,20.801 C112.9998,22.2873563 111.787371,23.5 110.3008,23.5 Z M110.3008,22 C110.958884,22 111.4998,21.4589886 111.4998,20.801 L111.4998,19.601 C111.4998,16.522032 108.977905,14 105.8988,14 L100.1013,14 C97.022082,14 94.4998,16.5221451 94.4998,19.601 L94.4998,20.801 C94.4998,21.4588343 95.0410614,22 95.6993,22 L110.3008,22 Z"
/>
</g>
<polygon points="444 180 468 180 468 156 444 156" />
</g>
</svg>
);
}
function Timestamp({time}) {
return (
<span
style={{
color: '#99A1B3',
marginTop: 5,
fontSize: 15,
}}>
{time}
</span>
);
}