NextJS Demo App

/app/posts/page.tsx

import Link from "next/link";

import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Code } from "@/components/code";
import { Row } from "@/components/row";

import { createPost, getPosts } from "@/lib/actions";

export default async function Page() {
  const posts = await getPosts();

  return (
    <Row>
      <div className="flex flex-col gap-4">
        <ul>
          {posts.map((post) => (
            <li key={post.id}>
              <Link href={`/posts/${post.id}`}>{post.title}</Link>
            </li>
          ))}
        </ul>

        <form action={createPost}>
          <Label htmlFor="title">Title</Label>
          <Input type="text" name="title" />
          <Label htmlFor="content">Content</Label>
          <Input type="text" name="content" />
          <Button type="submit">Create</Button>
        </form>
      </div>
      <div>
        <Code path="/app/posts/page.tsx" />
        <Code path="/app/posts/loading.tsx" />
        <Code path="/lib/actions.ts" sub={[21, 37]} />
      </div>
    </Row>
  );
}

/app/posts/loading.tsx

import { Skeleton } from "@/components/ui/skeleton";

export default function Loading() {
  return <Skeleton className="h-[100px] w-full" />;
}

/lib/actions.ts (lines 22-38)

  await delay(1000);
  return date;
}

const posts = [
  { id: 1, title: "First Post", content: "This is the first post" },
  { id: 2, title: "Second Post", content: "This is the second post" },
];

export async function createPost(formData: FormData) {
  const title = formData.get("title") as string;
  const content = formData.get("content") as string;
  posts.push({ id: posts.length + 1, title, content });
  revalidatePath("/posts");
}