Full Code of mozzius/community-handles for AI

main d33bb244e852 cached
53 files
131.2 KB
53.3k tokens
48 symbols
1 requests
Download .txt
Repository: mozzius/community-handles
Branch: main
Commit: d33bb244e852
Files: 53
Total size: 131.2 KB

Directory structure:
gitextract_49tax7zj/

├── .editorconfig
├── .eslintignore
├── .eslintrc.json
├── .gitignore
├── .prettierignore
├── .vscode/
│   └── settings.json
├── README.md
├── app/
│   ├── [domain]/
│   │   ├── [handle]/
│   │   │   ├── .well-known/
│   │   │   │   └── atproto-did/
│   │   │   │       └── route.ts
│   │   │   ├── opengraph-image.tsx
│   │   │   └── page.tsx
│   │   ├── community/
│   │   │   ├── loading.tsx
│   │   │   └── page.tsx
│   │   ├── create-your-own/
│   │   │   └── page.tsx
│   │   ├── layout.tsx
│   │   └── page.tsx
│   └── layout.tsx
├── components/
│   ├── avatar.tsx
│   ├── icons.tsx
│   ├── layout.tsx
│   ├── link.tsx
│   ├── load-more.tsx
│   ├── main-nav.tsx
│   ├── profile.tsx
│   ├── site-header.tsx
│   ├── stage.tsx
│   ├── tailwind-indicator.tsx
│   ├── theme-provider.tsx
│   ├── theme-toggle.tsx
│   └── ui/
│       ├── button.tsx
│       ├── dialog.tsx
│       ├── input.tsx
│       ├── label.tsx
│       └── tabs.tsx
├── config/
│   └── site.ts
├── lib/
│   ├── atproto.ts
│   ├── db.ts
│   ├── fonts.ts
│   ├── slurs.ts
│   └── utils.ts
├── middleware.ts
├── next-env.d.ts
├── next.config.mjs
├── package.json
├── postcss.config.js
├── prettier.config.js
├── prisma/
│   ├── export.ts
│   ├── schema.prisma
│   └── seed.ts
├── styles/
│   └── globals.css
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.tsbuildinfo
└── types/
    └── nav.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# editorconfig.org
root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true


================================================
FILE: .eslintignore
================================================
dist/*
.cache
public
node_modules
*.esm.js


================================================
FILE: .eslintrc.json
================================================
{
  "$schema": "https://json.schemastore.org/eslintrc",
  "root": true,
  "extends": [
    "next/core-web-vitals",
    "prettier",
    "plugin:tailwindcss/recommended"
  ],
  "plugins": ["tailwindcss"],
  "rules": {
    "@next/next/no-html-link-for-pages": "off",
    "react/jsx-key": "off",
    "tailwindcss/no-custom-classname": "off"
  },
  "settings": {
    "tailwindcss": {
      "callees": ["cn"],
      "config": "./tailwind.config.js"
    },
    "next": {
      "rootDir": ["./"]
    }
  },
  "overrides": [
    {
      "files": ["*.ts", "*.tsx"],
      "parser": "@typescript-eslint/parser"
    }
  ]
}


================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
node_modules
.pnp
.pnp.js

# testing
coverage

# next.js
.next/
out/
build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local

# turbo
.turbo

.contentlayer
.env
.vercel

export/


================================================
FILE: .prettierignore
================================================
cache
.cache
package.json
package-lock.json
public
CHANGELOG.md
.yarn
dist
node_modules
.next
build
.contentlayer

================================================
FILE: .vscode/settings.json
================================================
{
  "typescript.tsdk": "node_modules/typescript/lib",
  "typescript.enablePromptUseWorkspaceTsdk": true
}


================================================
FILE: README.md
================================================
# Bluesky Community Handles tool

Get your own community handle for Bluesky!

Go to https://swifties.social to join the swifties.social community.

## What is a community handle?

A domain that other people can have their own subdomain on. For example, [@mozzius.swifties.social](https://mozzius.swifties.social) is a community handle that is part of the https://swifties.social community.

## How do I get a community handle?

This tool lets members of your community easily get a community handle. Simply go to the domain, such as https://swifties.social, and follow the instructions.

## How do I host my own community handle tool?

If you want to set up your own community handle for your own community, you can use this tool. It's free and open source, and you can host it yourself.

> These instructions assume you have a basic understanding of Git, GitHub, and Vercel. It not the only way to host it (it's just a Next.js app) but it is probably the simplest way.

You will need to own a domain you want to use, and have a Vercel account linked to your GitHub.

### 1. Fork this repository

Fork this repository to your own GitHub account, and clone it to your local machine.

### 2. Add the project to Vercel

Add the project to Vercel using the "Add New..." button. You will need to link your GitHub account to Vercel if you haven't already.

It will detect that it's a Next.js project and set up the build settings for you. That's all fine, but you will need to set up the environment variables.

Once that's done, deploy the app

### 3. Set up the domain

Once it's done, go to Settings > Domains and add the domain you want to use. **Don't do the redirect stuff it recommends, just use the plain domain. It's the third option on the list**. It'll give you the nameservers your need to point the domain to - go back to your registrar and do that.

> IMPORTANT: Make sure you use nameservers, not DNS records. If you use DNS records, it won't work.

You'll then want to add a wildcard domain using a `*`, such as `*.swifties.social`. This catches all the requests to subdomains - we use Next.js middleware to route them to the right place.

### 4. Add your database

You'll need to add a database to store the community handles. We recommend using [Railway](https://railway.app), but you can use whatever you want - if it's not Postgres, you'll likely need to modify the Prisma file. Railway will likely be the simply way to set it up.

Create a Postgres database via Railway, then get the connection string once it's ready. You'll need to add the connection strings to the environment variables. Create a file called `.env` in the root of the project, and add the following:

```env
DATABASE_URL=
```

Then run the following commands in your terminal, in the project directory:

```bash
pnpm i
pnpm prisma db push
```

Then, in Vercel, go to Settings > Environment Variables and add the `DATABASE_URL` variable with the connection string. Re-deploy the Vercel app.

### 5. Done!

That's it! You should now be able to go to your domain and use the community handle tool.

> Remember it takes a few minutes for DNS to propagate, so it might not work straight away.

If you like the project, you can [sponsor me](https://github.com/sponsors/mozzius)! It's not required, but it's appreciated :)


================================================
FILE: app/[domain]/[handle]/.well-known/atproto-did/route.ts
================================================
import { type NextRequest } from "next/server"

import { prisma } from "@/lib/db"

const corsHeaders = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Methods": "GET, OPTIONS",
  "Access-Control-Allow-Headers": "*",
}

export const OPTIONS = async () => {
  return new Response(null, {
    status: 204,
    headers: corsHeaders,
  })
}

export const GET = async (
  _req: NextRequest,
  { params }: { params: { domain: string; handle: string } }
) => {
  const { did } = await prisma.user.findFirstOrThrow({
    where: { handle: params.handle, domain: { name: params.domain } },
  })
  return new Response(did, {
    headers: {
      "content-type": "text/plain",
      ...corsHeaders,
    },
  })
}


================================================
FILE: app/[domain]/[handle]/opengraph-image.tsx
================================================
/* eslint-disable @next/next/no-img-element */

import { ImageResponse } from "next/og"

import { agent } from "@/lib/atproto"

export const size = {
  width: 800,
  height: 400,
}
export const contentType = "image/png"
export const runtime = "edge"

export default async function og({
  params,
}: {
  params: { domain: string; handle: string }
}) {
  const { domain, handle } = params

  const {
    data: { did },
  } = await agent.resolveHandle({ handle: `${handle}.${domain}` })

  const profile = await agent.getProfile({
    actor: did,
  })

  const fetchAvatar = profile.data.avatar
    ? fetch(profile.data.avatar).then((res) => res.arrayBuffer())
    : Promise.resolve(null)
  const fetchBanner = profile.data.banner
    ? fetch(profile.data.banner).then((res) => res.arrayBuffer())
    : Promise.resolve(null)

  const [avatar, banner] = await Promise.all([fetchAvatar, fetchBanner])

  return new ImageResponse(
    (
      <div tw="flex flex-col w-full h-full bg-white">
        {banner && (
          <img // @ts-expect-error img behaves differently here
            src={banner}
            height="200"
            width="800"
            alt=""
          />
        )}
        <div tw="flex flex-row items-center flex-1 px-12">
          {avatar ? (
            <img // @ts-expect-error img behaves differently here
              src={avatar}
              height="150"
              width="150"
              tw="rounded-full"
              alt=""
            />
          ) : (
            <div tw="rounded-full bg-neutral-200 h-36 w-36" />
          )}
          <div tw="flex flex-col ml-6">
            {profile.data.displayName && (
              <p tw="m-0 text-4xl font-bold w-[500px]">
                {profile.data.displayName}
              </p>
            )}
            <p tw="m-0 text-neutral-500 text-2xl w-[500px]">
              @{profile.data.handle}
            </p>
          </div>
        </div>
      </div>
    ),
    { ...size }
  )
}


================================================
FILE: app/[domain]/[handle]/page.tsx
================================================
import { Metadata } from "next"

import { agent } from "@/lib/atproto"
import { prisma } from "@/lib/db"
import { Profile } from "@/components/profile"

interface Props {
  params: { handle: string; domain: string }
}

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const domain = params.domain
  const user = await prisma.user.findFirst({
    where: { handle: params.handle, domain: { name: domain } },
  })
  if (!user) {
    return {
      title: "Profile not found",
      description: ":(",
    }
  }

  const profile = await agent.getProfile({
    actor: user.did,
  })
  return {
    title: `${profile.data.displayName} - @${profile.data.handle}`,
    description: profile.data.description,
  }
}

export default async function HandlePage({ params }: Props) {
  const { domain, handle } = params

  try {
    const user = await prisma.user.findFirstOrThrow({
      where: { handle, domain: { name: domain } },
    })

    const profile = await agent.getProfile({
      actor: user.did,
    })
    return (
      <div className="grid flex-1 place-items-center">
        <a href={`https://bsky.app/profile/${profile.data.handle}`}>
          <Profile profile={profile.data} />
        </a>
      </div>
    )
  } catch (e) {
    console.error(e)
    return (
      <div className="grid flex-1 place-items-center">
        <p className="text-center">Profile not found</p>
      </div>
    )
  }
}


================================================
FILE: app/[domain]/community/loading.tsx
================================================
import { LoaderIcon } from "lucide-react"

export default function Loading() {
  return (
    <div className="flex flex-1 items-center justify-center">
      <LoaderIcon className="size-8 animate-spin text-primary" />
    </div>
  )
}


================================================
FILE: app/[domain]/community/page.tsx
================================================
import { type Metadata } from "next"
import { AppBskyActorDefs } from "@atproto/api"

import { agent } from "@/lib/atproto"
import { prisma } from "@/lib/db"
import { Link } from "@/components/link"
import { LoadMore } from "@/components/load-more"
import { Profile } from "@/components/profile"

export const revalidate = 3600

interface Props {
  params: { domain: string }
}

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const domain = params.domain

  return {
    title: `The ${domain} Community`,
    description: `See all the members of the ${domain} community.`,
  }
}

const PAGE_SIZE = 100

export default async function CommunityPage({ params }: Props) {
  const domain = params.domain

  const [count, { profiles: initialProfiles, nextOffset }] = await Promise.all([
    prisma.user.count({
      where: { domain: { name: domain } },
    }),
    getUsers(domain),
  ])

  return (
    <main className="container grid items-center gap-6 pb-8 pt-6 md:py-10">
      <div className="flex max-w-[980px] flex-col items-start gap-4">
        <h1 className="text-3xl font-extrabold leading-tight tracking-tighter sm:text-3xl md:text-5xl lg:text-6xl">
          The {domain} <br className="hidden sm:inline" />
          community
        </h1>
        <p className="max-w-[500px] text-lg text-muted-foreground sm:text-xl">
          Want to join the {count} members of the {domain} community? Get your
          own{" "}
          <Link href="/" className="underline">
            {domain} handle
          </Link>
          .
        </p>

        <LoadMore
          domain={domain}
          className="mt-8 grid w-full grid-cols-1 gap-4 overflow-hidden sm:grid-cols-2 md:grid-cols-3"
          loadMoreAction={loadMoreUsers}
          initialOffset={nextOffset}
        >
          <ProfileListSection profiles={initialProfiles} />
        </LoadMore>
      </div>
    </main>
  )
}

function ProfileListSection({
  profiles,
}: {
  profiles: AppBskyActorDefs.ProfileViewDetailed[]
}) {
  return profiles.map((profile) => (
    <a href={`https://bsky.app/profile/${profile.handle}`} key={profile.did}>
      <Profile profile={profile} />
    </a>
  ))
}

async function getUsers(domain: string, offset = 0) {
  const users = await prisma.user.findMany({
    where: { domain: { name: domain } },
    select: { did: true },
    take: PAGE_SIZE,
    skip: offset,
  })

  const nextOffset = users.length >= PAGE_SIZE ? offset + PAGE_SIZE : null

  if (users.length === 0) {
    return {
      profiles: [],
      nextOffset,
    }
  }

  // fetch profiles in chunks of 25
  const chunks = []
  for (let i = 0; i < PAGE_SIZE; i += 25) {
    const chunk = users.slice(i, i + 25).map(({ did }) => did)
    if (chunk.length > 0) {
      chunks.push(chunk)
    }
  }

  // jealous of postfix await :(
  const responses = await Promise.all(
    chunks.map((actors) => agent.getProfiles({ actors }))
  )
  const profiles = responses
    .flatMap((response) => response.data.profiles)
    .filter(
      (value, index, array) =>
        array.findIndex(({ did }) => did === value.did) === index &&
        value.handle.endsWith(domain)
    )

  return {
    profiles,
    nextOffset,
  }
}

async function loadMoreUsers(domain: string, offset = 0) {
  "use server"
  const { profiles, nextOffset } = await getUsers(domain, offset)

  return [
    <ProfileListSection profiles={profiles} key={offset} />,
    nextOffset,
  ] as const
}


================================================
FILE: app/[domain]/create-your-own/page.tsx
================================================
import { ArrowRight } from "lucide-react"

import { Button, buttonVariants } from "@/components/ui/button"
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"
import { Stage } from "@/components/stage"

export const metadata = {
  title: "Create a Community Handle for your community",
  description: "Host your own tool",
}

export default function CommunityPage() {
  return (
    <main className="container grid items-center gap-6 pb-8 pt-6 md:py-10">
      <div className="flex max-w-[980px] flex-col items-start gap-4">
        <h1 className="text-3xl font-extrabold leading-tight tracking-tighter sm:text-3xl md:text-5xl lg:text-6xl">
          Create a Community Handle <br className="hidden sm:inline" />
          for your community
        </h1>
        <p className="max-w-[700px] text-lg text-muted-foreground sm:text-xl">
          Want a custom community handle for your community, like
          @alex.swifties.social, @jay.army.social, or @jane.kawaii.social? Follow
          these steps to get one.
        </p>
      </div>
      <div>
        <Stage title="Buy a domain" number={1}>
          <p className="max-w-lg">
            Buy a domain from a domain registrar. We use{" "}
            <a
              href="https://namecheap.com"
              className="underline"
              target="_blank"
              rel="noopener noreferrer"
            >
              Namecheap
            </a>
            , but it doesn&apos;t matter which one you use. Just make sure you
            are able to change where you point the nameservers.
          </p>
        </Stage>
        <Stage title="Host the Community Handles tool" number={2} last>
          <p className="max-w-lg">You then need to host the tool.</p>
          <p className="mt-4 max-w-lg">
            If you want to host it yourself,{" "}
            <a
              href="https://github.com/mozzius/community-handles"
              className="underline"
            >
              fork the project on GitHub
            </a>
            . It{"'"}s a Next.js project, so you can deploy it however you like.
            Check out the README for the recommended solution, using Vercel and
            Railway.
          </p>
          <p className="mt-8 max-w-lg text-sm text-muted-foreground">
            Using the hosted version? (no longer available){" "}
            <a
              href="https://billing.stripe.com/p/login/6oEbJccQOh2Rdji4gg"
              className="underline"
            >
              Go to the billing portal
            </a>
            .
          </p>
        </Stage>
      </div>
    </main>
  )
}


================================================
FILE: app/[domain]/layout.tsx
================================================

import NextPlausible from "next-plausible"
import { siteConfig } from "@/config/site"
import { MainNav } from "@/components/main-nav"
import { SiteHeader } from "@/components/site-header"

interface Props {
  children: React.ReactNode
  params: { domain: string }
}

export default function DomainLayout({ children, params }: Props) {
  return (
    <>
      <NextPlausible
        domain={params.domain}
        customDomain={process.env.PLAUSIBLE_CUSTOM_DOMAIN}
        trackOutboundLinks
        selfHosted
      />
      <SiteHeader items={siteConfig.mainNav}>
        <MainNav title={params.domain} items={siteConfig.mainNav} />
      </SiteHeader>
      <div className="flex flex-1 flex-col">{children}</div>
    </>
  )
}


================================================
FILE: app/[domain]/page.tsx
================================================
import { AppBskyActorDefs } from "@atproto/api"
import { Check, X } from "lucide-react"

import { agent } from "@/lib/atproto"
import { prisma } from "@/lib/db"
import { hasExplicitSlur } from "@/lib/slurs"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Profile } from "@/components/profile"
import { Stage } from "@/components/stage"

export function generateMetadata({ params }: { params: { domain: string } }) {
  const domain = params.domain
  return {
    title: `${domain} - get your community handle for Bluesky`,
    description: `get your own ${domain} handle`,
  }
}

export default async function IndexPage({
  params,
  searchParams,
}: {
  params: {
    domain: string
  }
  searchParams: {
    handle?: string
    "new-handle"?: string
  }
}) {
  const domain = params.domain
  let handle = searchParams.handle
  let newHandle = searchParams["new-handle"]
  let profile: AppBskyActorDefs.ProfileView | undefined
  let error1: string | undefined
  let error2: string | undefined

  if (handle) {
    try {
      if (!handle.includes(".")) {
        handle += ".bsky.social"
      }
      console.log("fetching profile", handle)
      const actor = await agent.getProfile({
        actor: handle,
      })
      if (!actor.success) throw new Error("fetch was not a success")
      profile = actor.data
    } catch (e) {
      console.error(e)
      error1 = (e as Error)?.message ?? "unknown error"
    }

    if (newHandle && profile) {
      newHandle = newHandle.trim().toLowerCase()
      if (!newHandle.includes(".")) {
        newHandle += "." + domain
      }
      if (!error1) {
        // regex: (alphanumeric, -, _).(domain)
        const validHandle = newHandle.match(
          new RegExp(`^[a-zA-Z0-9-_]+.${domain}$`)
        )
        if (validHandle) {
          try {
            const handle = newHandle.replace(`.${domain}`, "")
            if (hasExplicitSlur(handle)) {
              throw new Error("slur")
            }

            if (domain === "army.social" && RESERVED.includes(handle)) {
              throw new Error("reserved")
            }

            const existing = await prisma.user.findFirst({
              where: { handle },
              include: { domain: true },
            })
            if (existing && existing.domain.name === domain) {
              if (existing.did !== profile.did) {
                error2 = "handle taken"
              }
            } else {
              await prisma.user.create({
                data: {
                  handle,
                  did: profile.did,
                  domain: {
                    connectOrCreate: {
                      where: { name: domain },
                      create: { name: domain },
                    },
                  },
                },
              })
            }
          } catch (e) {
            console.error(e)
            error2 = (e as Error)?.message ?? "unknown error"
          }
        } else {
          error2 = "invalid handle"
        }
      }
    }
  }

  return (
    <main className="container grid items-center gap-6 pb-8 pt-6 md:py-10">
      <div className="flex max-w-[980px] flex-col items-start gap-4">
        <h1 className="text-3xl font-extrabold leading-tight tracking-tighter sm:text-3xl md:text-5xl lg:text-6xl">
          Get your own {domain} <br className="hidden sm:inline" />
          handle for Bluesky
        </h1>
        <p className="max-w-[700px] text-lg text-muted-foreground sm:text-xl">
          Follow the instructions below to get your own {domain} handle
        </p>
      </div>
      <div>
        <Stage title="Enter your current handle" number={1}>
          <form>
            <div className="grid w-full max-w-sm items-center gap-1.5">
              <div className="flex w-full max-w-sm items-center space-x-2">
                {newHandle && (
                  <input type="hidden" name="new-handle" value="" />
                )}
                <Input
                  type="text"
                  name="handle"
                  placeholder="example.bsky.social"
                  defaultValue={handle}
                  required
                />
                <Button type="submit">Submit</Button>
              </div>
              <p className="text-sm text-muted-foreground">
                Enter your current handle, not including the @
              </p>
              {error1 && (
                <p className="flex flex-row items-center gap-2 text-sm text-red-500">
                  <X className="size-4" /> Handle not found - please try again
                </p>
              )}
              {profile && (
                <>
                  <p className="text-muted-forground mt-4 flex flex-row items-center gap-2 text-sm">
                    <Check className="size-4 text-green-500" /> Account found
                  </p>
                  <Profile profile={profile} className="mt-4" />
                </>
              )}
            </div>
          </form>
        </Stage>
        <Stage title="Choose your new handle" number={2} disabled={!profile}>
          <form>
            <input type="hidden" name="handle" value={handle} />
            <div className="grid w-full max-w-sm items-center gap-1.5">
              <div className="flex w-full max-w-sm items-center space-x-2">
                <Input
                  type="text"
                  name="new-handle"
                  placeholder={`example.${domain}`}
                  defaultValue={newHandle}
                />
                <Button type="submit">Submit</Button>
              </div>
              <p className="text-sm text-muted-foreground">
                Enter the {domain} handle that you would like to have, not
                including the @
              </p>
              {error2 && (
                <p className="text-sm text-red-500">
                  {(() => {
                    switch (error2) {
                      case "handle taken":
                        return "Handle already taken - please enter a different handle"
                      case "invalid handle":
                      case "slur":
                        return "Invalid handle - please enter a different handle"
                      case "reserved":
                        return "Reserved handle - please enter a different handle"
                      default:
                        return "An error occured - please try again"
                    }
                  })()}
                </p>
              )}
            </div>
          </form>
        </Stage>
        <Stage
          title="Change your handle within the Bluesky app"
          number={3}
          disabled={!newHandle || !!error2}
          last
        >
          <p className="max-w-lg text-sm">
            Go to Settings {">"} Advanced {">"} Change my handle. Select &quot;I
            have my own domain&quot; and enter{" "}
            {newHandle ? `"${newHandle}"` : "your new handle"}. Finally, tap
            &quot;Verify DNS Record&quot;.
          </p>
          <p className="mt-6 max-w-lg text-sm">
            If you like this project, consider{" "}
            <a href="https://github.com/sponsors/mozzius" className="underline">
              sponsoring my work
            </a>
            .
          </p>
        </Stage>
      </div>
    </main>
  )
}

const RESERVED = [
  "Jungkook",
  "JeonJungkook",
  "Jeon",
  "JK",
  "JJK",
  "Kim",
  "KimTaehyung",
  "V",
  "Taehyung",
  "Tae",
  "Jin",
  "Seokjin",
  "KimSeokjin",
  "RM",
  "Namjoon",
  "Nam",
  "KimNamjoon",
  "MinYoongi",
  "Yoongi",
  "Yoon",
  "AgustD",
  "MYG",
  "Suga",
  "PJM",
  "Jimin",
  "ParkJimin",
  "Park",
  "Abcdefghi__lmnopqrsvuxyz",
  "JM",
  "UarMyHope",
  "Rkrive",
  "THV",
  "KTH",
  "SBT",
  "BANGPD",
  "projeto",
  "army",
  "armys ",
  "info",
  "projects",
  "Pic",
  "New",
  "Babys",
].map((x) => x.toLowerCase())


================================================
FILE: app/layout.tsx
================================================
import { type Metadata, type Viewport } from "next"

import { fontSans } from "@/lib/fonts"
import { cn } from "@/lib/utils"
import { TailwindIndicator } from "@/components/tailwind-indicator"
import { ThemeProvider } from "@/components/theme-provider"

import "@/styles/globals.css"

export const metadata: Metadata = {
  icons: {
    icon: "/favicon.ico",
    shortcut: "/favicon-16x16.png",
    apple: "/apple-touch-icon.png",
  },
}

export const viewport: Viewport = {
  themeColor: [
    { media: "(prefers-color-scheme: light)", color: "white" },
    { media: "(prefers-color-scheme: dark)", color: "black" },
  ],
}

interface RootLayoutProps {
  children: React.ReactNode
}

export default function RootLayout({ children }: RootLayoutProps) {
  return (
    <>
      <html lang="en" suppressHydrationWarning>
        <body
          className={cn(
            "min-h-screen bg-background font-sans antialiased",
            fontSans.variable
          )}
        >
          <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
            <div className="relative flex min-h-screen flex-col">
              {children}
            </div>
            <TailwindIndicator />
          </ThemeProvider>
        </body>
      </html>
    </>
  )
}


================================================
FILE: components/avatar.tsx
================================================
/* eslint-disable @next/next/no-img-element */
"use client"

import * as React from "react"

import { cn } from "@/lib/utils"

export function Avatar({
  src,
  alt,
  fallback,
  className,
}: {
  src?: string
  alt: string
  fallback?: string
  className?: string
}) {
  const [loaded, setLoaded] = React.useState(false)
  return (
    <div
      className={cn(
        "relative flex size-10 shrink-0 overflow-hidden rounded-full",
        className
      )}
    >
      {src && (
        <img
          className="aspect-square size-full"
          src={src.replace("avatar", "avatar_thumbnail")}
          alt={alt}
          onLoad={() => setLoaded(true)}
        />
      )}
      {!loaded && (
        <div className="absolute inset-0 flex size-full items-center justify-center rounded-full border bg-muted text-[120%]">
          {fallback}
        </div>
      )}
    </div>
  )
}


================================================
FILE: components/icons.tsx
================================================
import {
  AtSign,
  LucideProps,
  Moon,
  SunMedium,
  type LucideIcon,
} from "lucide-react"

export type Icon = LucideIcon

export const Icons = {
  sun: SunMedium,
  moon: Moon,
  logo: AtSign,
  gitHub: (props: LucideProps) => (
    <svg viewBox="0 0 438.549 438.549" {...props}>
      <path
        fill="currentColor"
        d="M409.132 114.573c-19.608-33.596-46.205-60.194-79.798-79.8-33.598-19.607-70.277-29.408-110.063-29.408-39.781 0-76.472 9.804-110.063 29.408-33.596 19.605-60.192 46.204-79.8 79.8C9.803 148.168 0 184.854 0 224.63c0 47.78 13.94 90.745 41.827 128.906 27.884 38.164 63.906 64.572 108.063 79.227 5.14.954 8.945.283 11.419-1.996 2.475-2.282 3.711-5.14 3.711-8.562 0-.571-.049-5.708-.144-15.417a2549.81 2549.81 0 01-.144-25.406l-6.567 1.136c-4.187.767-9.469 1.092-15.846 1-6.374-.089-12.991-.757-19.842-1.999-6.854-1.231-13.229-4.086-19.13-8.559-5.898-4.473-10.085-10.328-12.56-17.556l-2.855-6.57c-1.903-4.374-4.899-9.233-8.992-14.559-4.093-5.331-8.232-8.945-12.419-10.848l-1.999-1.431c-1.332-.951-2.568-2.098-3.711-3.429-1.142-1.331-1.997-2.663-2.568-3.997-.572-1.335-.098-2.43 1.427-3.289 1.525-.859 4.281-1.276 8.28-1.276l5.708.853c3.807.763 8.516 3.042 14.133 6.851 5.614 3.806 10.229 8.754 13.846 14.842 4.38 7.806 9.657 13.754 15.846 17.847 6.184 4.093 12.419 6.136 18.699 6.136 6.28 0 11.704-.476 16.274-1.423 4.565-.952 8.848-2.383 12.847-4.285 1.713-12.758 6.377-22.559 13.988-29.41-10.848-1.14-20.601-2.857-29.264-5.14-8.658-2.286-17.605-5.996-26.835-11.14-9.235-5.137-16.896-11.516-22.985-19.126-6.09-7.614-11.088-17.61-14.987-29.979-3.901-12.374-5.852-26.648-5.852-42.826 0-23.035 7.52-42.637 22.557-58.817-7.044-17.318-6.379-36.732 1.997-58.24 5.52-1.715 13.706-.428 24.554 3.853 10.85 4.283 18.794 7.952 23.84 10.994 5.046 3.041 9.089 5.618 12.135 7.708 17.705-4.947 35.976-7.421 54.818-7.421s37.117 2.474 54.823 7.421l10.849-6.849c7.419-4.57 16.18-8.758 26.262-12.565 10.088-3.805 17.802-4.853 23.134-3.138 8.562 21.509 9.325 40.922 2.279 58.24 15.036 16.18 22.559 35.787 22.559 58.817 0 16.178-1.958 30.497-5.853 42.966-3.9 12.471-8.941 22.457-15.125 29.979-6.191 7.521-13.901 13.85-23.131 18.986-9.232 5.14-18.182 8.85-26.84 11.136-8.662 2.286-18.415 4.004-29.263 5.146 9.894 8.562 14.842 22.077 14.842 40.539v60.237c0 3.422 1.19 6.279 3.572 8.562 2.379 2.279 6.136 2.95 11.276 1.995 44.163-14.653 80.185-41.062 108.068-79.226 27.88-38.161 41.825-81.126 41.825-128.906-.01-39.771-9.818-76.454-29.414-110.049z"
      ></path>
    </svg>
  ),
}


================================================
FILE: components/layout.tsx
================================================
import { SiteHeader } from "@/components/site-header"

interface LayoutProps {
  children: React.ReactNode
}

export function Layout({ children }: LayoutProps) {
  return (
    <>
      <SiteHeader />
      <main>{children}</main>
    </>
  )
}


================================================
FILE: components/link.tsx
================================================
"use client"

import NextLink, { type LinkProps } from "next/link"

import { getDomain } from "@/lib/utils"

interface Props
  extends LinkProps,
    Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, keyof LinkProps> {}

export function Link({ href, ...props }: Props) {
  if (typeof href === "string" && typeof window !== "undefined") {
    const { subdomain, domain } = getDomain(window.location.hostname)
    if (!!subdomain) {
      return <NextLink href={`https://${domain}${href}`} {...props} />
    } else {
      return <NextLink href={href} {...props} />
    }
  } else {
    return <NextLink href={href} {...props} />
  }
}


================================================
FILE: components/load-more.tsx
================================================
"use client"

import * as React from "react"

import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"

interface Props {
  children: React.ReactNode
  domain: string
  initialOffset: number | null
  loadMoreAction: (
    domain: string,
    offset: number
  ) => Promise<readonly [React.JSX.Element, number | null]>
  className?: string
}

export function LoadMore({
  children,
  domain,
  initialOffset,
  loadMoreAction,
  className,
}: Props) {
  const ref = React.useRef<HTMLButtonElement>(null)
  const [loadMoreNodes, setLoadMoreNodes] = React.useState<
    React.ReactElement[]
  >([])

  const [disabled, setDisabled] = React.useState(initialOffset === null)
  const currentOffsetRef = React.useRef<number | null>(initialOffset)
  const [loading, setLoading] = React.useState(false)

  const loadMore = React.useCallback(
    async (abortController?: AbortController) => {
      if (currentOffsetRef.current === null) {
        setDisabled(true)
        return
      }

      setLoading(true)

      try {
        const [nodes, next] = await loadMoreAction(
          domain,
          currentOffsetRef.current
        )
        if (abortController?.signal.aborted) return

        currentOffsetRef.current = next
        setLoadMoreNodes((prev) => [...prev, nodes])
        if (next === null) {
          setDisabled(true)
          return
        }
      } finally {
        setLoading(false)
      }
    },
    [domain, loadMoreAction]
  )

  React.useEffect(() => {
    const signal = new AbortController()

    const element = ref.current

    const observer = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting && element?.disabled === false) {
        loadMore(signal)
      }
    })

    if (element) {
      observer.observe(element)
    }

    return () => {
      signal.abort()
      observer.disconnect()
    }
  }, [loadMore])

  return (
    <>
      <div className={className}>
        {children}
        {loadMoreNodes}
      </div>
      <Button
        className={cn("mx-auto mt-8", disabled && "invisible")}
        variant="outline"
        size="lg"
        ref={ref}
        disabled={disabled || loading}
        onClick={() => loadMore()}
      >
        {loading ? "Loading..." : "Load More"}
      </Button>
    </>
  )
}


================================================
FILE: components/main-nav.tsx
================================================
"use client"

import * as React from "react"

import { NavItem } from "@/types/nav"
import { cn } from "@/lib/utils"
import { Icons } from "@/components/icons"
import { Link } from "@/components/link"

interface MainNavProps {
  title: string
  items?: NavItem[]
}

export function MainNav({ title, items }: MainNavProps) {
  const base = typeof window !== "undefined" ? window.location.host : ""
  const isLocalhost = base.includes("localhost")
  const prefix = isLocalhost ? "/swifties.social" : ""

  return (
    <div className="flex gap-6 lg:gap-10">
      <Link href={prefix + "/"} className="flex items-center space-x-2">
        <Icons.logo className="size-6" />
        <span className="inline-block font-bold">{title}</span>
      </Link>
      {items?.length ? (
        <nav className="hidden gap-4 md:flex lg:gap-6">
          {items?.map(
            (item, index) =>
              item.href && (
                <Link
                  key={index}
                  href={prefix + item.href}
                  className={cn(
                    "flex items-center text-lg font-semibold text-muted-foreground sm:text-sm",
                    item.disabled && "cursor-not-allowed opacity-80"
                  )}
                >
                  {item.title}
                </Link>
              )
          )}
        </nav>
      ) : null}
    </div>
  )
}


================================================
FILE: components/profile.tsx
================================================
/* eslint-disable @next/next/no-img-element */
import { AppBskyActorDefs } from "@atproto/api"

import { cn } from "@/lib/utils"

import { Avatar } from "./avatar"

interface Props {
  profile: AppBskyActorDefs.ProfileViewDetailed
  className?: string
}

export function Profile({ profile, className }: Props) {
  return (
    <div
      className={cn(
        "flex w-full max-w-lg flex-col overflow-hidden rounded-xl shadow",
        className
      )}
    >
      {profile.banner ? (
        <img
          src={profile.banner}
          alt=""
          className="aspect-[3/1] w-full bg-muted object-cover"
        />
      ) : (
        <div className="aspect-[3/1] w-full bg-muted" />
      )}
      <div className="flex flex-col border-x border-b bg-background px-3 pb-2">
        <Avatar
          className="relative -top-8 -mb-6 size-16"
          src={profile.avatar}
          alt={`@${profile.handle}'s avatar`}
          fallback={profile.handle.toLocaleUpperCase().at(0)}
        />
        <p className="line-clamp-1 text-lg font-semibold leading-5">
          {profile.displayName || profile.handle}
        </p>
        <p className="line-clamp-1 text-sm text-muted-foreground">
          @{profile.handle}
        </p>
      </div>
    </div>
  )
}


================================================
FILE: components/site-header.tsx
================================================
"use client"

import { useState } from "react"
import { Menu, X } from "lucide-react"

import { type NavItem } from "@/types/nav"
import { siteConfig } from "@/config/site"
import { cn } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button"
import { Icons } from "@/components/icons"
import { Link } from "@/components/link"
import { ThemeToggle } from "@/components/theme-toggle"

interface Props {
  children?: React.ReactNode
  items?: NavItem[]
}

export function SiteHeader({ children }: Props) {
  const [showMenu, setShowMenu] = useState(false)

  const links = (
    <nav className="flex items-center gap-4 md:gap-1">
      <Link href={siteConfig.links.github} target="_blank" rel="noreferrer">
        <div
          className={buttonVariants({
            size: "sm",
            variant: "ghost",
          })}
        >
          <Icons.gitHub className="size-5" />
          <span className="sr-only">GitHub</span>
        </div>
      </Link>
      <ThemeToggle />
    </nav>
  )

  const MenuIcon = showMenu ? X : Menu

  return (
    <>
      <header className="sticky top-0 z-40 w-full border-b bg-background">
        <div className="container flex h-16 items-center justify-between space-x-4 sm:space-x-0">
          {children}
          <div>
            <div className="block md:hidden">
              <MenuIcon
                aria-label="Menu"
                className="cursor-pointer"
                size={24}
                onClick={() => setShowMenu((m) => !m)}
              />
            </div>
            <div className="hidden flex-1 items-center justify-end space-x-4 md:flex">
              {links}
            </div>
          </div>
        </div>
      </header>
      <div
        className={cn(
          "fixed top-16 z-30 w-full overflow-hidden border-b bg-background/80 transition-transform duration-500 md:hidden",
          showMenu ? "translate-y-1px" : "-translate-y-full"
        )}
        aria-hidden={!showMenu}
      >
        <div className="container flex h-full flex-col items-center justify-stretch px-4 pb-2">
          <nav className="mb-2 flex w-full flex-col items-stretch gap-1 border-b py-2">
            {siteConfig.mainNav.map(
              (item, index) =>
                item.href && (
                  <Link
                    key={index}
                    href={item.href}
                    className={buttonVariants({
                      variant: "ghost",
                      className:
                        "w-full !justify-start text-left font-semibold text-muted-foreground",
                    })}
                    onClick={() => setShowMenu(false)}
                  >
                    {item.title}
                  </Link>
                )
            )}
          </nav>
          {links}
        </div>
      </div>
      {/* Backdrop */}
      <div
        aria-hidden
        className={cn(
          "fixed inset-0 z-20 transition-all duration-700 md:hidden",
          showMenu ? "backdrop-blur-md" : "pointer-events-none"
        )}
        onClick={() => setShowMenu(false)}
      />
    </>
  )
}


================================================
FILE: components/stage.tsx
================================================
import { cn } from "@/lib/utils"

interface Props {
  number: number
  title: string
  disabled?: boolean
  last?: boolean
  children?: React.ReactNode
}

export function Stage({ number, title, disabled, last, children }: Props) {
  return (
    <section className={cn(disabled && "opacity-50")}>
      <div className="flex h-8 flex-row items-center">
        <div className="mr-4 grid size-8 shrink-0 place-items-center rounded-full bg-slate-100 text-center dark:bg-slate-800">
          {number}
        </div>
        <h2 className="font-semibold">{title}</h2>
      </div>
      <div
        className={cn(
          "border-l-1 ml-4 border-l py-6 pl-8",
          last && "border-transparent"
        )}
      >
        {children}
      </div>
    </section>
  )
}


================================================
FILE: components/tailwind-indicator.tsx
================================================
export function TailwindIndicator() {
  if (process.env.NODE_ENV === "production") return null

  return (
    <div className="fixed bottom-1 left-1 z-50 flex size-6 items-center justify-center rounded-full bg-gray-800 p-3 font-mono text-xs text-white">
      <div className="block sm:hidden">xs</div>
      <div className="hidden sm:block md:hidden lg:hidden xl:hidden 2xl:hidden">
        sm
      </div>
      <div className="hidden md:block lg:hidden xl:hidden 2xl:hidden">md</div>
      <div className="hidden lg:block xl:hidden 2xl:hidden">lg</div>
      <div className="hidden xl:block 2xl:hidden">xl</div>
      <div className="hidden 2xl:block">2xl</div>
    </div>
  )
}


================================================
FILE: components/theme-provider.tsx
================================================
"use client"

import * as React from "react"
import { ThemeProvider as NextThemesProvider } from "next-themes"
import { ThemeProviderProps } from "next-themes/dist/types"

export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
  return <NextThemesProvider {...props}>{children}</NextThemesProvider>
}


================================================
FILE: components/theme-toggle.tsx
================================================
"use client"

import * as React from "react"
import { useTheme } from "next-themes"

import { Button } from "@/components/ui/button"
import { Icons } from "@/components/icons"

export function ThemeToggle() {
  const { setTheme, theme } = useTheme()

  return (
    <Button
      variant="ghost"
      size="sm"
      onClick={() => setTheme(theme === "light" ? "dark" : "light")}
    >
      <Icons.sun className="rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
      <Icons.moon className="absolute rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
      <span className="sr-only">Toggle theme</span>
    </Button>
  )
}


================================================
FILE: components/ui/button.tsx
================================================
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"

import { cn } from "@/lib/utils"

const buttonVariants = cva(
  "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground hover:bg-primary/90",
        destructive:
          "bg-destructive text-destructive-foreground hover:bg-destructive/90",
        outline:
          "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
        secondary:
          "bg-secondary text-secondary-foreground hover:bg-secondary/80",
        ghost: "hover:bg-accent hover:text-accent-foreground",
        link: "text-primary underline-offset-4 hover:underline",
      },
      size: {
        default: "h-10 px-4 py-2",
        sm: "h-9 rounded-md px-3",
        lg: "h-11 rounded-md px-8",
        icon: "h-10 w-10",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
)

export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  asChild?: boolean
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
  ({ className, variant, size, asChild = false, ...props }, ref) => {
    const Comp = asChild ? Slot : "button"
    return (
      <Comp
        className={cn(buttonVariants({ variant, size, className }))}
        ref={ref}
        {...props}
      />
    )
  }
)
Button.displayName = "Button"

export { Button, buttonVariants }


================================================
FILE: components/ui/dialog.tsx
================================================
"use client"

import * as React from "react"
import * as DialogPrimitive from "@radix-ui/react-dialog"
import { X } from "lucide-react"

import { cn } from "@/lib/utils"

const Dialog = DialogPrimitive.Root

const DialogTrigger = DialogPrimitive.Trigger

const DialogPortal = DialogPrimitive.Portal

const DialogClose = DialogPrimitive.Close

const DialogOverlay = React.forwardRef<
  React.ElementRef<typeof DialogPrimitive.Overlay>,
  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
  <DialogPrimitive.Overlay
    ref={ref}
    className={cn(
      "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
      className
    )}
    {...props}
  />
))
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName

const DialogContent = React.forwardRef<
  React.ElementRef<typeof DialogPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
  <DialogPortal>
    <DialogOverlay />
    <DialogPrimitive.Content
      ref={ref}
      className={cn(
        "fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
        className
      )}
      {...props}
    >
      {children}
      <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
        <X className="size-4" />
        <span className="sr-only">Close</span>
      </DialogPrimitive.Close>
    </DialogPrimitive.Content>
  </DialogPortal>
))
DialogContent.displayName = DialogPrimitive.Content.displayName

const DialogHeader = ({
  className,
  ...props
}: React.HTMLAttributes<HTMLDivElement>) => (
  <div
    className={cn(
      "flex flex-col space-y-1.5 text-center sm:text-left",
      className
    )}
    {...props}
  />
)
DialogHeader.displayName = "DialogHeader"

const DialogFooter = ({
  className,
  ...props
}: React.HTMLAttributes<HTMLDivElement>) => (
  <div
    className={cn(
      "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
      className
    )}
    {...props}
  />
)
DialogFooter.displayName = "DialogFooter"

const DialogTitle = React.forwardRef<
  React.ElementRef<typeof DialogPrimitive.Title>,
  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
  <DialogPrimitive.Title
    ref={ref}
    className={cn(
      "text-lg font-semibold leading-none tracking-tight",
      className
    )}
    {...props}
  />
))
DialogTitle.displayName = DialogPrimitive.Title.displayName

const DialogDescription = React.forwardRef<
  React.ElementRef<typeof DialogPrimitive.Description>,
  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
  <DialogPrimitive.Description
    ref={ref}
    className={cn("text-sm text-muted-foreground", className)}
    {...props}
  />
))
DialogDescription.displayName = DialogPrimitive.Description.displayName

export {
  Dialog,
  DialogPortal,
  DialogOverlay,
  DialogClose,
  DialogTrigger,
  DialogContent,
  DialogHeader,
  DialogFooter,
  DialogTitle,
  DialogDescription,
}


================================================
FILE: components/ui/input.tsx
================================================
import * as React from "react"

import { cn } from "@/lib/utils"

export interface InputProps
  extends React.InputHTMLAttributes<HTMLInputElement> {}

const Input = React.forwardRef<HTMLInputElement, InputProps>(
  ({ className, type, ...props }, ref) => {
    return (
      <input
        type={type}
        className={cn(
          "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
          className
        )}
        ref={ref}
        {...props}
      />
    )
  }
)
Input.displayName = "Input"

export { Input }


================================================
FILE: components/ui/label.tsx
================================================
"use client"

import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import { cva, type VariantProps } from "class-variance-authority"

import { cn } from "@/lib/utils"

const labelVariants = cva(
  "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
)

const Label = React.forwardRef<
  React.ElementRef<typeof LabelPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
    VariantProps<typeof labelVariants>
>(({ className, ...props }, ref) => (
  <LabelPrimitive.Root
    ref={ref}
    className={cn(labelVariants(), className)}
    {...props}
  />
))
Label.displayName = LabelPrimitive.Root.displayName

export { Label }


================================================
FILE: components/ui/tabs.tsx
================================================
"use client"

import * as React from "react"
import * as TabsPrimitive from "@radix-ui/react-tabs"

import { cn } from "@/lib/utils"

const Tabs = TabsPrimitive.Root

const TabsList = React.forwardRef<
  React.ElementRef<typeof TabsPrimitive.List>,
  React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
>(({ className, ...props }, ref) => (
  <TabsPrimitive.List
    ref={ref}
    className={cn(
      "inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
      className
    )}
    {...props}
  />
))
TabsList.displayName = TabsPrimitive.List.displayName

const TabsTrigger = React.forwardRef<
  React.ElementRef<typeof TabsPrimitive.Trigger>,
  React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
>(({ className, ...props }, ref) => (
  <TabsPrimitive.Trigger
    ref={ref}
    className={cn(
      "inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
      className
    )}
    {...props}
  />
))
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName

const TabsContent = React.forwardRef<
  React.ElementRef<typeof TabsPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
>(({ className, ...props }, ref) => (
  <TabsPrimitive.Content
    ref={ref}
    className={cn(
      "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
      className
    )}
    {...props}
  />
))
TabsContent.displayName = TabsPrimitive.Content.displayName

export { Tabs, TabsList, TabsTrigger, TabsContent }


================================================
FILE: config/site.ts
================================================
export type SiteConfig = typeof siteConfig

export const siteConfig = {
  mainNav: [
    {
      title: "Join the community",
      href: "/",
    },
    {
      title: "Members",
      href: "/community",
    },
    {
      title: "Create your own community handle",
      href: "/create-your-own",
    },
  ],
  links: {
    github: "https://github.com/mozzius/community-handles",
  },
}


================================================
FILE: lib/atproto.ts
================================================
import { BskyAgent, jsonToLex, stringifyLex } from "@atproto/api"

BskyAgent.configure({
  fetch: async (reqUri, reqMethod, reqHeaders, reqBody) => {
    const reqMimeType = reqHeaders["Content-Type"] || reqHeaders["content-type"]
    if (reqMimeType && reqMimeType.startsWith("application/json")) {
      reqBody = stringifyLex(reqBody)
    }
    const res = await fetch(reqUri, {
      method: reqMethod,
      headers: reqHeaders,
      body: reqBody,
      cache: "no-cache",
    })

    const resStatus = res.status
    const resHeaders: Record<string, string> = {}
    res.headers.forEach((value: string, key: string) => {
      resHeaders[key] = value
    })
    const resMimeType = resHeaders["Content-Type"] || resHeaders["content-type"]
    let resBody
    if (resMimeType) {
      if (resMimeType.startsWith("application/json")) {
        resBody = jsonToLex(await res.json())
      } else if (resMimeType.startsWith("text/")) {
        resBody = await res.text()
      } else {
        throw new Error("TODO: non-textual response body")
      }
    }

    return {
      status: resStatus,
      headers: resHeaders,
      body: resBody,
    }
  },
})

export const agent = new BskyAgent({
  service: "https://public.api.bsky.app",
})


================================================
FILE: lib/db.ts
================================================
import { PrismaClient } from "@prisma/client"

const globalForPrisma = global as unknown as {
  prisma: PrismaClient | undefined
}

export const prisma =
  globalForPrisma.prisma ??
  new PrismaClient({
    log: ["query"],
  })

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma


================================================
FILE: lib/fonts.ts
================================================
import { JetBrains_Mono as FontMono, Inter as FontSans } from "next/font/google"

export const fontSans = FontSans({
  subsets: ["latin"],
  variable: "--font-sans",
})

export const fontMono = FontMono({
  subsets: ["latin"],
  variable: "--font-mono",
})


================================================
FILE: lib/slurs.ts
================================================
// RIPPED STRAIGHT OUT OF ATPROTO
// ALL CREDIT TO THEM ETC

// regexes taken from: https://github.com/Blank-Cheque/Slurs
/* eslint-disable no-misleading-character-class */
const explicitSlurRegexes = [
  /\b[cĆćĈĉČčĊċÇçḈḉȻȼꞒꞓꟄꞔƇƈɕ][hĤĥȞȟḦḧḢḣḨḩḤḥḪḫH̱ẖĦħⱧⱨꞪɦꞕΗНн][iÍíi̇́Ììi̇̀ĬĭÎîǏǐÏïḮḯĨĩi̇̃ĮįĮ́į̇́Į̃į̇̃ĪīĪ̀ī̀ỈỉȈȉI̋i̋ȊȋỊịꞼꞽḬḭƗɨᶖİiIıIi1lĺľļḷḹl̃ḽḻłŀƚꝉⱡɫɬꞎꬷꬸꬹᶅɭȴLl][nŃńǸǹŇňÑñṄṅŅņṆṇṊṋṈṉN̈n̈ƝɲŊŋꞐꞑꞤꞥᵰᶇɳȵꬻꬼИиПпNn][kḰḱǨǩĶķḲḳḴḵƘƙⱩⱪᶄꝀꝁꝂꝃꝄꝅꞢꞣ][sŚśṤṥŜŝŠšṦṧṠṡŞşṢṣṨṩȘșS̩s̩ꞨꞩⱾȿꟅʂᶊᵴ]?\b/,
  /\b[cĆćĈĉČčĊċÇçḈḉȻȼꞒꞓꟄꞔƇƈɕ][ÓóÒòŎŏÔôỐốỒồỖỗỔổǑǒÖöȪȫŐőÕõṌṍṎṏȬȭȮȯO͘o͘ȰȱØøǾǿǪǫǬǭŌōṒṓṐṑỎỏȌȍȎȏƠơỚớỜờỠỡỞởỢợỌọỘộO̩o̩Ò̩ò̩Ó̩ó̩ƟɵꝊꝋꝌꝍⱺOo0]{2}[nŃńǸǹŇňÑñṄṅŅņṆṇṊṋṈṉN̈n̈ƝɲŊŋꞐꞑꞤꞥᵰᶇɳȵꬻꬼИиПпNn][sŚśṤṥŜŝŠšṦṧṠṡŞşṢṣṨṩȘșS̩s̩ꞨꞩⱾȿꟅʂᶊᵴ]?\b/,
  /[fḞḟƑƒꞘꞙᵮᶂ][aÁáÀàĂăẮắẰằẴẵẲẳÂâẤấẦầẪẫẨẩǍǎÅåǺǻÄäǞǟÃãȦȧǠǡĄąĄ́ą́Ą̃ą̃ĀāĀ̀ā̀ẢảȀȁA̋a̋ȂȃẠạẶặẬậḀḁȺⱥꞺꞻᶏẚAa@4][gǴǵĞğĜĝǦǧĠġG̃g̃ĢģḠḡǤǥꞠꞡƓɠᶃꬶGgqꝖꝗꝘꝙɋʠ]{1,2}([ÓóÒòŎŏÔôỐốỒồỖỗỔổǑǒÖöȪȫŐőÕõṌṍṎṏȬȭȮȯO͘o͘ȰȱØøǾǿǪǫǬǭŌōṒṓṐṑỎỏȌȍȎȏƠơỚớỜờỠỡỞởỢợỌọỘộO̩o̩Ò̩ò̩Ó̩ó̩ƟɵꝊꝋꝌꝍⱺOo0e3ЄєЕеÉéÈèĔĕÊêẾếỀềỄễỂểÊ̄ê̄Ê̌ê̌ĚěËëẼẽĖėĖ́ė́Ė̃ė̃ȨȩḜḝĘęĘ́ę́Ę̃ę̃ĒēḖḗḔḕẺẻȄȅE̋e̋ȆȇẸẹỆệḘḙḚḛɆɇE̩e̩È̩è̩É̩é̩ᶒⱸꬴꬳEeiÍíi̇́Ììi̇̀ĬĭÎîǏǐÏïḮḯĨĩi̇̃ĮįĮ́į̇́Į̃į̇̃ĪīĪ̀ī̀ỈỉȈȉI̋i̋ȊȋỊịꞼꞽḬḭƗɨᶖİiIıIi1lĺľļḷḹl̃ḽḻłŀƚꝉⱡɫɬꞎꬷꬸꬹᶅɭȴLl][tŤťṪṫŢţṬṭȚțṰṱṮṯŦŧȾⱦƬƭƮʈT̈ẗᵵƫȶ]{1,2}([rŔŕŘřṘṙŖŗȐȑȒȓṚṛṜṝṞṟR̃r̃ɌɍꞦꞧⱤɽᵲᶉꭉ][yÝýỲỳŶŷY̊ẙŸÿỸỹẎẏȲȳỶỷỴỵɎɏƳƴỾỿ]|[rŔŕŘřṘṙŖŗȐȑȒȓṚṛṜṝṞṟR̃r̃ɌɍꞦꞧⱤɽᵲᶉꭉ][iÍíi̇́Ììi̇̀ĬĭÎîǏǐÏïḮḯĨĩi̇̃ĮįĮ́į̇́Į̃į̇̃ĪīĪ̀ī̀ỈỉȈȉI̋i̋ȊȋỊịꞼꞽḬḭƗɨᶖİiIıIi1lĺľļḷḹl̃ḽḻłŀƚꝉⱡɫɬꞎꬷꬸꬹᶅɭȴLl][e3ЄєЕеÉéÈèĔĕÊêẾếỀềỄễỂểÊ̄ê̄Ê̌ê̌ĚěËëẼẽĖėĖ́ė́Ė̃ė̃ȨȩḜḝĘęĘ́ę́Ę̃ę̃ĒēḖḗḔḕẺẻȄȅE̋e̋ȆȇẸẹỆệḘḙḚḛɆɇE̩e̩È̩è̩É̩é̩ᶒⱸꬴꬳEe])?)?[sŚśṤṥŜŝŠšṦṧṠṡŞşṢṣṨṩȘșS̩s̩ꞨꞩⱾȿꟅʂᶊᵴ]?\b/,
  /\b[kḰḱǨǩĶķḲḳḴḵƘƙⱩⱪᶄꝀꝁꝂꝃꝄꝅꞢꞣ][iÍíi̇́Ììi̇̀ĬĭÎîǏǐÏïḮḯĨĩi̇̃ĮįĮ́į̇́Į̃į̇̃ĪīĪ̀ī̀ỈỉȈȉI̋i̋ȊȋỊịꞼꞽḬḭƗɨᶖİiIıIi1lĺľļḷḹl̃ḽḻłŀƚꝉⱡɫɬꞎꬷꬸꬹᶅɭȴLlyÝýỲỳŶŷY̊ẙŸÿỸỹẎẏȲȳỶỷỴỵɎɏƳƴỾỿ][kḰḱǨǩĶķḲḳḴḵƘƙⱩⱪᶄꝀꝁꝂꝃꝄꝅꞢꞣ][e3ЄєЕеÉéÈèĔĕÊêẾếỀềỄễỂểÊ̄ê̄Ê̌ê̌ĚěËëẼẽĖėĖ́ė́Ė̃ė̃ȨȩḜḝĘęĘ́ę́Ę̃ę̃ĒēḖḗḔḕẺẻȄȅE̋e̋ȆȇẸẹỆệḘḙḚḛɆɇE̩e̩È̩è̩É̩é̩ᶒⱸꬴꬳEe]([rŔŕŘřṘṙŖŗȐȑȒȓṚṛṜṝṞṟR̃r̃ɌɍꞦꞧⱤɽᵲᶉꭉ][yÝýỲỳŶŷY̊ẙŸÿỸỹẎẏȲȳỶỷỴỵɎɏƳƴỾỿ]|[rŔŕŘřṘṙŖŗȐȑȒȓṚṛṜṝṞṟR̃r̃ɌɍꞦꞧⱤɽᵲᶉꭉ][iÍíi̇́Ììi̇̀ĬĭÎîǏǐÏïḮḯĨĩi̇̃ĮįĮ́į̇́Į̃į̇̃ĪīĪ̀ī̀ỈỉȈȉI̋i̋ȊȋỊịꞼꞽḬḭƗɨᶖİiIıIi1lĺľļḷḹl̃ḽḻłŀƚꝉⱡɫɬꞎꬷꬸꬹᶅɭȴLl][e3ЄєЕеÉéÈèĔĕÊêẾếỀềỄễỂểÊ̄ê̄Ê̌ê̌ĚěËëẼẽĖėĖ́ė́Ė̃ė̃ȨȩḜḝĘęĘ́ę́Ę̃ę̃ĒēḖḗḔḕẺẻȄȅE̋e̋ȆȇẸẹỆệḘḙḚḛɆɇE̩e̩È̩è̩É̩é̩ᶒⱸꬴꬳEe])?[sŚśṤṥŜŝŠšṦṧṠṡŞşṢṣṨṩȘșS̩s̩ꞨꞩⱾȿꟅʂᶊᵴ]*\b/,
  /\b([sŚśṤṥŜŝŠšṦṧṠṡŞşṢṣṨṩȘșS̩s̩ꞨꞩⱾȿꟅʂᶊᵴ][a4ÁáÀàĂăẮắẰằẴẵẲẳÂâẤấẦầẪẫẨẩǍǎÅåǺǻÄäǞǟÃãȦȧǠǡĄąĄ́ą́Ą̃ą̃ĀāĀ̀ā̀ẢảȀȁA̋a̋ȂȃẠạẶặẬậḀḁȺⱥꞺꞻᶏẚAa][nŃńǸǹŇňÑñṄṅŅņṆṇṊṋṈṉN̈n̈ƝɲŊŋꞐꞑꞤꞥᵰᶇɳȵꬻꬼИиПпNn][dĎďḊḋḐḑD̦d̦ḌḍḒḓḎḏĐđÐðƉɖƊɗᵭᶁᶑȡ])?[nŃńǸǹŇňÑñṄṅŅņṆṇṊṋṈṉN̈n̈ƝɲŊŋꞐꞑꞤꞥᵰᶇɳȵꬻꬼИиПпNn][iÍíi̇́Ììi̇̀ĬĭÎîǏǐÏïḮḯĨĩi̇̃ĮįĮ́į̇́Į̃į̇̃ĪīĪ̀ī̀ỈỉȈȉI̋i̋ȊȋỊịꞼꞽḬḭƗɨᶖİiIıIi1lĺľļḷḹl̃ḽḻłŀƚꝉⱡɫɬꞎꬷꬸꬹᶅɭȴLloÓóÒòŎŏÔôỐốỒồỖỗỔổǑǒÖöȪȫŐőÕõṌṍṎṏȬȭȮȯO͘o͘ȰȱØøǾǿǪǫǬǭŌōṒṓṐṑỎỏȌȍȎȏƠơỚớỜờỠỡỞởỢợỌọỘộO̩o̩Ò̩ò̩Ó̩ó̩ƟɵꝊꝋꝌꝍⱺOoІіa4ÁáÀàĂăẮắẰằẴẵẲẳÂâẤấẦầẪẫẨẩǍǎÅåǺǻÄäǞǟÃãȦȧǠǡĄąĄ́ą́Ą̃ą̃ĀāĀ̀ā̀ẢảȀȁA̋a̋ȂȃẠạẶặẬậḀḁȺⱥꞺꞻᶏẚAa][gǴǵĞğĜĝǦǧĠġG̃g̃ĢģḠḡǤǥꞠꞡƓɠᶃꬶGgqꝖꝗꝘꝙɋʠ]{1,2}(l[e3ЄєЕеÉéÈèĔĕÊêẾếỀềỄễỂểÊ̄ê̄Ê̌ê̌ĚěËëẼẽĖėĖ́ė́Ė̃ė̃ȨȩḜḝĘęĘ́ę́Ę̃ę̃ĒēḖḗḔḕẺẻȄȅE̋e̋ȆȇẸẹỆệḘḙḚḛɆɇE̩e̩È̩è̩É̩é̩ᶒⱸꬴꬳEe]t|[e3ЄєЕеÉéÈèĔĕÊêẾếỀềỄễỂểÊ̄ê̄Ê̌ê̌ĚěËëẼẽĖėĖ́ė́Ė̃ė̃ȨȩḜḝĘęĘ́ę́Ę̃ę̃ĒēḖḗḔḕẺẻȄȅE̋e̋ȆȇẸẹỆệḘḙḚḛɆɇE̩e̩È̩è̩É̩é̩ᶒⱸꬴꬳEeaÁáÀàĂăẮắẰằẴẵẲẳÂâẤấẦầẪẫẨẩǍǎÅåǺǻÄäǞǟÃãȦȧǠǡĄąĄ́ą́Ą̃ą̃ĀāĀ̀ā̀ẢảȀȁA̋a̋ȂȃẠạẶặẬậḀḁȺⱥꞺꞻᶏẚAa][rŔŕŘřṘṙŖŗȐȑȒȓṚṛṜṝṞṟR̃r̃ɌɍꞦꞧⱤɽᵲᶉꭉ]?|n[ÓóÒòŎŏÔôỐốỒồỖỗỔổǑǒÖöȪȫŐőÕõṌṍṎṏȬȭȮȯO͘o͘ȰȱØøǾǿǪǫǬǭŌōṒṓṐṑỎỏȌȍȎȏƠơỚớỜờỠỡỞởỢợỌọỘộO̩o̩Ò̩ò̩Ó̩ó̩ƟɵꝊꝋꝌꝍⱺOo0][gǴǵĞğĜĝǦǧĠġG̃g̃ĢģḠḡǤǥꞠꞡƓɠᶃꬶGgqꝖꝗꝘꝙɋʠ]|[a4ÁáÀàĂăẮắẰằẴẵẲẳÂâẤấẦầẪẫẨẩǍǎÅåǺǻÄäǞǟÃãȦȧǠǡĄąĄ́ą́Ą̃ą̃ĀāĀ̀ā̀ẢảȀȁA̋a̋ȂȃẠạẶặẬậḀḁȺⱥꞺꞻᶏẚAa]?)?[sŚśṤṥŜŝŠšṦṧṠṡŞşṢṣṨṩȘșS̩s̩ꞨꞩⱾȿꟅʂᶊᵴ]?\b/,
  /\b[tŤťṪṫŢţṬṭȚțṰṱṮṯŦŧȾⱦƬƭƮʈT̈ẗᵵƫȶ][rŔŕŘřṘṙŖŗȐȑȒȓṚṛṜṝṞṟR̃r̃ɌɍꞦꞧⱤɽᵲᶉꭉ][aÁáÀàĂăẮắẰằẴẵẲẳÂâẤấẦầẪẫẨẩǍǎÅåǺǻÄäǞǟÃãȦȧǠǡĄąĄ́ą́Ą̃ą̃ĀāĀ̀ā̀ẢảȀȁA̋a̋ȂȃẠạẶặẬậḀḁȺⱥꞺꞻᶏẚAa4]+[nŃńǸǹŇňÑñṄṅŅņṆṇṊṋṈṉN̈n̈ƝɲŊŋꞐꞑꞤꞥᵰᶇɳȵꬻꬼИиПпNn]{1,2}([iÍíi̇́Ììi̇̀ĬĭÎîǏǐÏïḮḯĨĩi̇̃ĮįĮ́į̇́Į̃į̇̃ĪīĪ̀ī̀ỈỉȈȉI̋i̋ȊȋỊịꞼꞽḬḭƗɨᶖİiIıIi1lĺľļḷḹl̃ḽḻłŀƚꝉⱡɫɬꞎꬷꬸꬹᶅɭȴLl][e3ЄєЕеÉéÈèĔĕÊêẾếỀềỄễỂểÊ̄ê̄Ê̌ê̌ĚěËëẼẽĖėĖ́ė́Ė̃ė̃ȨȩḜḝĘęĘ́ę́Ę̃ę̃ĒēḖḗḔḕẺẻȄȅE̋e̋ȆȇẸẹỆệḘḙḚḛɆɇE̩e̩È̩è̩É̩é̩ᶒⱸꬴꬳEe]|[yÝýỲỳŶŷY̊ẙŸÿỸỹẎẏȲȳỶỷỴỵɎɏƳƴỾỿ]|[e3ЄєЕеÉéÈèĔĕÊêẾếỀềỄễỂểÊ̄ê̄Ê̌ê̌ĚěËëẼẽĖėĖ́ė́Ė̃ė̃ȨȩḜḝĘęĘ́ę́Ę̃ę̃ĒēḖḗḔḕẺẻȄȅE̋e̋ȆȇẸẹỆệḘḙḚḛɆɇE̩e̩È̩è̩É̩é̩ᶒⱸꬴꬳEe][rŔŕŘřṘṙŖŗȐȑȒȓṚṛṜṝṞṟR̃r̃ɌɍꞦꞧⱤɽᵲᶉꭉ])[sŚśṤṥŜŝŠšṦṧṠṡŞşṢṣṨṩȘșS̩s̩ꞨꞩⱾȿꟅʂᶊᵴ]?\b/,
]

const indianSlurs = [
  "Hijra",
  "Bhangi",
  "Kutta",
  "Malech",
  "Dhobi",
  "Chamar",
  "Chandaal",
  "Pariah",
  "Mahar",
  "Kanjar",
  "Bajaari",
  "Avusaari",
  "Avisaari",
  "Thevadiya",
  "Chappri",
  "Bhand",
  "Chinki",
  "Kallu",
  "Chuhra",
  "Harijan",
  "Dhedhgujari",
  "Kasai",
  "Jungli",
  "Mala Mokam",
  "Madiga Chestalu",
  "Wadar",
  "Poramboke",
  "Kameena",
  "Kameeni",
  "Yanaadibuddulu",
  "Budabukkaladana",
  "Nakkalollapanulu",
  "Lambadi",
  "ChambarChoukashi",
  "Yerukalollu",
  "Kachra",
  "Maharki",
  "Ricebag",
]

export const hasExplicitSlur = (handle: string): boolean => {
  const lowercaseHandle = handle.toLowerCase()
  return (
    explicitSlurRegexes.some((reg) => reg.test(lowercaseHandle)) ||
    indianSlurs.map((x) => x.toLowerCase()).includes(lowercaseHandle)
  )
}


================================================
FILE: lib/utils.ts
================================================
import { clsx, type ClassValue } from "clsx"
import psl from "psl"
import { twMerge } from "tailwind-merge"

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

export function getDomain(host: string) {
  const domain = psl.parse(host)
  if (domain.error) throw new Error(domain.error.message)
  return domain
}


================================================
FILE: middleware.ts
================================================
import { NextResponse, type NextRequest } from "next/server"

import { getDomain } from "./lib/utils"

export function middleware(request: NextRequest) {
  const url = new URL(request.url)

  const { domain, subdomain } = getDomain(url.hostname)

  if (domain) {
    if (subdomain && subdomain !== process.env.LANDING_SUBDOMAIN) {
      return NextResponse.rewrite(
        new URL(`/${domain}/${subdomain}${url.pathname}${url.search}`, url)
      )
    } else {
      return NextResponse.rewrite(
        new URL(`/${domain}${url.pathname}${url.search}`, url)
      )
    }
  }
}

export const config = {
  matcher: [
    /*
     * Match all paths except for:
     * 1. /api routes
     * 2. /_next (Next.js internals)
     * 3. all root files inside /public (e.g. /favicon.ico)
     * 4. opengraph images (e.g. /[a-z0-9-_.]/[a-z0-9-_]/opengraph-image)
     * 5. Plausible analytics script
     */
    "/((?!api/|_next/|_static/|js/|proxy/|[\\w-]+\\.\\w+|[a-zA-Z0-9-_.]+/[a-zA-Z0-9-_]+/opengraph-image).*)",
  ],
}


================================================
FILE: next-env.d.ts
================================================
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.


================================================
FILE: next.config.mjs
================================================
import { withPlausibleProxy } from "next-plausible"

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
}

export default withPlausibleProxy({
  customDomain: "https://plausible.mozzius.dev",
})(nextConfig)


================================================
FILE: package.json
================================================
{
  "name": "next-template",
  "version": "0.0.2",
  "private": true,
  "packageManager": "pnpm@10.25.0",
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "lint:fix": "next lint --fix",
    "preview": "next build && next start",
    "typecheck": "tsc --noEmit",
    "format:write": "prettier --write \"**/*.{ts,tsx,mdx}\" --cache",
    "format:check": "prettier --check \"**/*.{ts,tsx,mdx}\" --cache",
    "postinstall": "prisma generate",
    "studio": "prisma studio",
    "export": "tsx prisma/export.ts"
  },
  "dependencies": {
    "@atproto/api": "^0.12.29",
    "@prisma/client": "5.18.0",
    "@radix-ui/react-avatar": "^1.1.0",
    "@radix-ui/react-dialog": "^1.1.1",
    "@radix-ui/react-label": "^2.1.0",
    "@radix-ui/react-slot": "^1.1.0",
    "@radix-ui/react-tabs": "^1.1.0",
    "@types/psl": "^1.1.3",
    "@vercel/kv": "^2.0.0",
    "class-variance-authority": "^0.7.0",
    "clsx": "^2.1.1",
    "cmdk": "^1.0.0",
    "lucide-react": "0.427.0",
    "next": "14.2.35",
    "next-plausible": "^3.12.4",
    "next-themes": "^0.3.0",
    "prettier-plugin-tailwindcss": "^0.6.6",
    "psl": "^1.9.0",
    "react": "^18.3.1",
    "react-day-picker": "^9.0.8",
    "react-dom": "^18.3.1",
    "sharp": "^0.33.4",
    "tailwind-merge": "^2.4.0",
    "tailwindcss-animate": "^1.0.7"
  },
  "devDependencies": {
    "@ianvs/prettier-plugin-sort-imports": "^4.3.1",
    "@types/node": "^22.2.0",
    "@types/react": "^18.3.3",
    "@types/react-dom": "^18.3.0",
    "@typescript-eslint/parser": "^8.0.1",
    "autoprefixer": "^10.4.20",
    "eslint": "^8.57.0",
    "eslint-config-next": "14.2.5",
    "eslint-config-prettier": "^9.1.0",
    "eslint-plugin-react": "^7.35.0",
    "eslint-plugin-tailwindcss": "^3.17.4",
    "postcss": "^8.4.41",
    "prettier": "^3.3.3",
    "prisma": "^5.18.0",
    "tailwindcss": "^3.4.9",
    "tsx": "^4.17.0",
    "typescript": "^5.5.4"
  },
  "prisma": {
    "seed": "tsx prisma/seed.ts"
  }
}


================================================
FILE: postcss.config.js
================================================
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}


================================================
FILE: prettier.config.js
================================================
/** @type {import('prettier').Config} */
module.exports = {
  endOfLine: "lf",
  semi: false,
  singleQuote: false,
  tabWidth: 2,
  trailingComma: "es5",
  importOrder: [
    "^(react/(.*)$)|^(react$)",
    "^(next/(.*)$)|^(next$)",
    "<THIRD_PARTY_MODULES>",
    "",
    "^types$",
    "^@/types/(.*)$",
    "^@/config/(.*)$",
    "^@/lib/(.*)$",
    "^@/hooks/(.*)$",
    "^@/components/ui/(.*)$",
    "^@/components/(.*)$",
    "^@/styles/(.*)$",
    "^@/app/(.*)$",
    "",
    "^[./]",
  ],
  importOrderParserPlugins: ["typescript", "jsx", "decorators-legacy"],
  plugins: [
    "@ianvs/prettier-plugin-sort-imports",
    "prettier-plugin-tailwindcss",
  ],
}


================================================
FILE: prisma/export.ts
================================================
import fs from "node:fs"
import { PrismaClient } from "@prisma/client"

const prisma = new PrismaClient()

async function main() {
  if (!fs.existsSync("./export")) {
    fs.mkdirSync("./export")
  }
  for (const domain of await prisma.domain.findMany()) {
    console.log(domain.name)
    let csv: string[][] = [["handle", "did", "createdAt"]]
    const users = await prisma.user.findMany({
      where: { domainId: domain.id },
    })
    for (const user of users) {
      csv.push([user.handle, user.did, user.createdAt.toISOString()])
    }
    fs.writeFileSync(
      `./export/${domain.name.replace(".", "_")}.csv`,
      csv.map((row) => row.join(",")).join("\n")
    )
  }
}

main()
  .then(async () => {
    await prisma.$disconnect()
  })
  .catch(async (e) => {
    console.error(e)
    await prisma.$disconnect()
    process.exit(1)
  })


================================================
FILE: prisma/schema.prisma
================================================
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Domain {
  id    String @id @default(uuid())
  name  String @unique
  users User[]

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

model User {
  id       String @id @default(uuid())
  did      String
  handle   String
  domainId String
  domain   Domain @relation(fields: [domainId], references: [id])

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@unique([handle, domainId])
}


================================================
FILE: prisma/seed.ts
================================================
import { PrismaClient } from "@prisma/client"
import { kv } from "@vercel/kv"

const prisma = new PrismaClient()

async function main() {
  const keys = await kv.keys("*")

  for (const key of keys) {
    const did = (await kv.get(key)) as string

    const [handle, ...rest] = key.split(".")
    const domain = rest.join(".")

    await prisma.user.create({
      data: {
        did,
        handle,
        domain: {
          connectOrCreate: {
            where: {
              name: domain,
            },
            create: {
              name: domain,
            },
          },
        },
      },
    })

    console.log("Added", key, did)
  }
}

main()
  .then(async () => {
    await prisma.$disconnect()
  })

  .catch(async (e) => {
    console.error(e)
    await prisma.$disconnect()
    process.exit(1)
  })


================================================
FILE: styles/globals.css
================================================
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 222.2 47.4% 11.2%;

    --muted: 210 40% 96.1%;
    --muted-foreground: 215.4 16.3% 46.9%;

    --popover: 0 0% 100%;
    --popover-foreground: 222.2 47.4% 11.2%;

    --border: 214.3 31.8% 91.4%;
    --input: 214.3 31.8% 91.4%;

    --card: 0 0% 100%;
    --card-foreground: 222.2 47.4% 11.2%;

    --primary: 222.2 47.4% 11.2%;
    --primary-foreground: 210 40% 98%;

    --secondary: 210 40% 96.1%;
    --secondary-foreground: 222.2 47.4% 11.2%;

    --accent: 210 40% 96.1%;
    --accent-foreground: 222.2 47.4% 11.2%;

    --destructive: 0 100% 50%;
    --destructive-foreground: 210 40% 98%;

    --ring: 215 20.2% 65.1%;

    --radius: 0.5rem;
  }

  .dark {
    --background: 224 71% 4%;
    --foreground: 213 31% 91%;

    --muted: 223 47% 11%;
    --muted-foreground: 215.4 16.3% 56.9%;

    --accent: 216 34% 17%;
    --accent-foreground: 210 40% 98%;

    --popover: 224 71% 4%;
    --popover-foreground: 215 20.2% 65.1%;

    --border: 216 34% 17%;
    --input: 216 34% 17%;

    --card: 224 71% 4%;
    --card-foreground: 213 31% 91%;

    --primary: 210 40% 98%;
    --primary-foreground: 222.2 47.4% 1.2%;

    --secondary: 222.2 47.4% 11.2%;
    --secondary-foreground: 210 40% 98%;

    --destructive: 0 63% 31%;
    --destructive-foreground: 210 40% 98%;

    --ring: 216 34% 17%;

    --radius: 0.5rem;
  }
}

@layer base {
  * {
    @apply border-border;
  }
  body {
    @apply bg-background text-foreground;
    font-feature-settings: "rlig" 1, "calt" 1;
  }
}


================================================
FILE: tailwind.config.js
================================================
const { fontFamily } = require("tailwindcss/defaultTheme")

/** @type {import('tailwindcss').Config} */
module.exports = {
  darkMode: ["class"],
  content: ["app/**/*.{ts,tsx}", "components/**/*.{ts,tsx}"],
  theme: {
    container: {
      center: true,
      padding: "2rem",
      screens: {
        "2xl": "1400px",
      },
    },
    extend: {
      colors: {
        border: "hsl(var(--border))",
        input: "hsl(var(--input))",
        ring: "hsl(var(--ring))",
        background: "hsl(var(--background))",
        foreground: "hsl(var(--foreground))",
        primary: {
          DEFAULT: "hsl(var(--primary))",
          foreground: "hsl(var(--primary-foreground))",
        },
        secondary: {
          DEFAULT: "hsl(var(--secondary))",
          foreground: "hsl(var(--secondary-foreground))",
        },
        destructive: {
          DEFAULT: "hsl(var(--destructive))",
          foreground: "hsl(var(--destructive-foreground))",
        },
        muted: {
          DEFAULT: "hsl(var(--muted))",
          foreground: "hsl(var(--muted-foreground))",
        },
        accent: {
          DEFAULT: "hsl(var(--accent))",
          foreground: "hsl(var(--accent-foreground))",
        },
        popover: {
          DEFAULT: "hsl(var(--popover))",
          foreground: "hsl(var(--popover-foreground))",
        },
        card: {
          DEFAULT: "hsl(var(--card))",
          foreground: "hsl(var(--card-foreground))",
        },
      },
      borderRadius: {
        lg: `var(--radius)`,
        md: `calc(var(--radius) - 2px)`,
        sm: "calc(var(--radius) - 4px)",
      },
      fontFamily: {
        sans: ["var(--font-sans)", ...fontFamily.sans],
      },
      keyframes: {
        "accordion-down": {
          from: { height: 0 },
          to: { height: "var(--radix-accordion-content-height)" },
        },
        "accordion-up": {
          from: { height: "var(--radix-accordion-content-height)" },
          to: { height: 0 },
        },
      },
      animation: {
        "accordion-down": "accordion-down 0.2s ease-out",
        "accordion-up": "accordion-up 0.2s ease-out",
      },
    },
  },
  plugins: [require("tailwindcss-animate")],
}


================================================
FILE: tsconfig.json
================================================
{
  "compilerOptions": {
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "incremental": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "baseUrl": ".",
    "paths": {
      "@/*": ["./*"]
    },
    "plugins": [
      {
        "name": "next"
      }
    ],
    "strictNullChecks": true
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}


================================================
FILE: tsconfig.tsbuildinfo
================================================
{"program":{"fileNames":["../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2021.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2022.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.esnext.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.dom.iterable.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2021.promise.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2021.string.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2021.intl.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2022.array.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2022.error.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2022.intl.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2022.object.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2022.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es2022.string.d.ts","../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.esnext.intl.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/styled-jsx/types/css.d.ts","../../node_modules/.pnpm/@types+react@18.0.22/node_modules/@types/react/global.d.ts","../../node_modules/.pnpm/csstype@3.1.2/node_modules/csstype/index.d.ts","../../node_modules/.pnpm/@types+prop-types@15.7.5/node_modules/@types/prop-types/index.d.ts","../../node_modules/.pnpm/@types+scheduler@0.16.3/node_modules/@types/scheduler/tracing.d.ts","../../node_modules/.pnpm/@types+react@18.0.22/node_modules/@types/react/index.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/styled-jsx/types/index.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/styled-jsx/types/macro.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/styled-jsx/types/style.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/styled-jsx/types/global.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/shared/lib/amp.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/amp.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/assert.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/assert/strict.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/globals.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/async_hooks.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/buffer.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/child_process.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/cluster.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/console.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/constants.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/crypto.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/dgram.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/diagnostics_channel.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/dns.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/dns/promises.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/domain.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/events.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/fs.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/fs/promises.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/http.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/http2.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/https.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/inspector.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/module.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/net.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/os.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/path.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/perf_hooks.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/process.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/punycode.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/querystring.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/readline.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/repl.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/stream.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/stream/promises.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/stream/consumers.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/stream/web.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/string_decoder.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/timers.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/timers/promises.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/tls.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/trace_events.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/tty.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/url.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/util.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/v8.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/vm.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/wasi.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/worker_threads.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/zlib.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/globals.global.d.ts","../../node_modules/.pnpm/@types+node@17.0.12/node_modules/@types/node/index.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/get-page-files.d.ts","../../node_modules/.pnpm/@types+react-dom@18.0.7/node_modules/@types/react-dom/index.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/webpack/webpack.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/config.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/lib/load-custom-routes.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/shared/lib/image-config.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/webpack/plugins/subresource-integrity-plugin.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/body-streams.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/shared/lib/router/utils/route-regex.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/shared/lib/router/utils/route-matcher.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/route-kind.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/route-definitions/route-definition.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/route-matches/route-match.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/request-meta.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/config-shared.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/base-http/index.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/api-utils/index.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/initialize-require-hook.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/node-polyfill-fetch.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/node-polyfill-web-streams.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/route-matchers/route-matcher.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/route-matcher-providers/route-matcher-provider.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/helpers/i18n-provider.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/route-matcher-managers/route-matcher-manager.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/router.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/analysis/get-page-static-info.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/webpack/loaders/get-module-build-info.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/webpack/plugins/middleware-plugin.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/render-result.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/web/next-url.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/@edge-runtime/cookies/index.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/web/spec-extension/cookies.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/web/spec-extension/request.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/web/spec-extension/fetch-event.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/web/spec-extension/response.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/web/types.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/lib/setup-exception-listeners.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/index.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/webpack/plugins/pages-manifest-plugin.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/send-payload/revalidate-headers.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/send-payload/index.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/base-http/node.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/font-utils.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/webpack/plugins/flight-manifest-plugin.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/load-components.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/webpack/plugins/next-font-manifest-plugin.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/render.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/shared/lib/router/utils/parse-url.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/shared/lib/router/utils/middleware-route-matcher.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/response-cache/types.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/response-cache/index.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/helpers/module-loader/module-loader.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/route-definitions/app-route-route-definition.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/webpack/plugins/app-build-manifest-plugin.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/lib/coalesced-function.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/lib/incremental-cache/index.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/static-generation-async-storage.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/hooks-server-context.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/lib/patch-fetch.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/utils.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/web/spec-extension/adapters/headers.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/web/spec-extension/adapters/request-cookies.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/request-async-storage.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/headers.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/static-generation-bailout.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/route-modules/route-module.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/async-storage/async-storage-wrapper.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/async-storage/static-generation-async-storage-wrapper.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/web/http.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/route-modules/app-route/module.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/route-handler-managers/route-handler-manager.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/normalizers/normalizer.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/normalizers/locale-route-normalizer.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/base-server.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/route-definitions/locale-route-definition.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/route-definitions/pages-api-route-definition.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/route-matches/pages-api-route-match.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/lib/render-server.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/image-optimizer.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/next-server.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/route-matcher-managers/default-route-matcher-manager.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/future/route-matcher-managers/dev-route-matcher-manager.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/dev/static-paths-worker.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/dev/next-dev-server.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/next.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/lib/metadata/types/alternative-urls-types.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/lib/metadata/types/extra-types.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/lib/metadata/types/metadata-types.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/lib/metadata/types/manifest-types.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/lib/metadata/types/opengraph-types.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/lib/metadata/types/twitter-types.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/lib/metadata/types/metadata-interface.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/types/index.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/shared/lib/html-context.d.ts","../../node_modules/.pnpm/@next+env@13.3.0/node_modules/@next/env/types/index.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/shared/lib/mitt.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/with-router.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/router.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/route-loader.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/page-loader.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/shared/lib/bloom-filter/hashing.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/shared/lib/bloom-filter/base-filter.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/shared/lib/bloom-filter/bit-set.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/shared/lib/bloom-filter/index.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/shared/lib/router/router.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/shared/lib/constants.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/shared/lib/utils.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/pages/_app.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/app.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/shared/lib/runtime-config.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/config.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/pages/_document.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/document.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/shared/lib/dynamic.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dynamic.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/pages/_error.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/error.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/shared/lib/head.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/head.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/image.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/image.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/link.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/link.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/router.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/script.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/script.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/web/spec-extension/user-agent.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/@edge-runtime/primitives/url.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/@vercel/og/satori/index.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/@vercel/og/emoji/index.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/@vercel/og/types.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/@vercel/og/index.node.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/web/spec-extension/image-response.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/server.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/types/global.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/index.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/image-types/global.d.ts","./next-env.d.ts","./config/site.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/@next/font/dist/types.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/@next/font/dist/google/index.d.ts","../../node_modules/.pnpm/next@13.3.0_@babel+core@7.20.7_react-dom@18.2.0_react@18.2.0/node_modules/next/font/google/index.d.ts","./lib/fonts.ts","../../node_modules/.pnpm/clsx@1.2.1/node_modules/clsx/clsx.d.ts","../../node_modules/.pnpm/tailwind-merge@1.12.0/node_modules/tailwind-merge/dist/lib/tw-join.d.ts","../../node_modules/.pnpm/tailwind-merge@1.12.0/node_modules/tailwind-merge/dist/lib/tw-merge.d.ts","../../node_modules/.pnpm/tailwind-merge@1.12.0/node_modules/tailwind-merge/dist/lib/validators.d.ts","../../node_modules/.pnpm/tailwind-merge@1.12.0/node_modules/tailwind-merge/dist/lib/types.d.ts","../../node_modules/.pnpm/tailwind-merge@1.12.0/node_modules/tailwind-merge/dist/lib/default-config.d.ts","../../node_modules/.pnpm/tailwind-merge@1.12.0/node_modules/tailwind-merge/dist/lib/extend-tailwind-merge.d.ts","../../node_modules/.pnpm/tailwind-merge@1.12.0/node_modules/tailwind-merge/dist/lib/create-tailwind-merge.d.ts","../../node_modules/.pnpm/tailwind-merge@1.12.0/node_modules/tailwind-merge/dist/lib/merge-configs.d.ts","../../node_modules/.pnpm/tailwind-merge@1.12.0/node_modules/tailwind-merge/dist/lib/from-theme.d.ts","../../node_modules/.pnpm/tailwind-merge@1.12.0/node_modules/tailwind-merge/dist/index.d.ts","./lib/utils.ts","./types/nav.ts","../../node_modules/.pnpm/class-variance-authority@0.4.0_typescript@4.9.5/node_modules/class-variance-authority/dist/types.d.ts","../../node_modules/.pnpm/class-variance-authority@0.4.0_typescript@4.9.5/node_modules/class-variance-authority/dist/index.d.ts","./components/ui/button.tsx","../../node_modules/.pnpm/lucide-react@0.105.0-alpha.4_react@18.2.0/node_modules/lucide-react/dist/lucide-react.d.ts","./components/icons.tsx","./components/main-nav.tsx","../../node_modules/.pnpm/next-themes@0.2.1_next@13.3.0_react-dom@18.2.0_react@18.2.0/node_modules/next-themes/dist/types.d.ts","../../node_modules/.pnpm/next-themes@0.2.1_next@13.3.0_react-dom@18.2.0_react@18.2.0/node_modules/next-themes/dist/index.d.ts","./components/theme-toggle.tsx","./components/site-header.tsx","./components/tailwind-indicator.tsx","./components/theme-provider.tsx","./app/layout.tsx","./app/page.tsx","./components/layout.tsx"],"fileInfos":[{"version":"8730f4bf322026ff5229336391a18bcaa1f94d4f82416c8b2f3954e2ccaae2ba","affectsGlobalScope":true},"dc47c4fa66b9b9890cf076304de2a9c5201e94b740cffdf09f87296d877d71f6","7a387c58583dfca701b6c85e0adaf43fb17d590fb16d5b2dc0a2fbd89f35c467","8a12173c586e95f4433e0c6dc446bc88346be73ffe9ca6eec7aa63c8f3dca7f9","5f4e733ced4e129482ae2186aae29fde948ab7182844c3a5a51dd346182c7b06","4b421cbfb3a38a27c279dec1e9112c3d1da296f77a1a85ddadf7e7a425d45d18","1fc5ab7a764205c68fa10d381b08417795fc73111d6dd16b5b1ed36badb743d9","746d62152361558ea6d6115cf0da4dd10ede041d14882ede3568bce5dc4b4f1f","d11a03592451da2d1065e09e61f4e2a9bf68f780f4f6623c18b57816a9679d17","aea179452def8a6152f98f63b191b84e7cbd69b0e248c91e61fb2e52328abe8c",{"version":"3aafcb693fe5b5c3bd277bd4c3a617b53db474fe498fc5df067c5603b1eebde7","affectsGlobalScope":true},{"version":"f3d4da15233e593eacb3965cde7960f3fddf5878528d882bcedd5cbaba0193c7","affectsGlobalScope":true},{"version":"adb996790133eb33b33aadb9c09f15c2c575e71fb57a62de8bf74dbf59ec7dfb","affectsGlobalScope":true},{"version":"8cc8c5a3bac513368b0157f3d8b31cfdcfe78b56d3724f30f80ed9715e404af8","affectsGlobalScope":true},{"version":"cdccba9a388c2ee3fd6ad4018c640a471a6c060e96f1232062223063b0a5ac6a","affectsGlobalScope":true},{"version":"c5c05907c02476e4bde6b7e76a79ffcd948aedd14b6a8f56e4674221b0417398","affectsGlobalScope":true},{"version":"5f406584aef28a331c36523df688ca3650288d14f39c5d2e555c95f0d2ff8f6f","affectsGlobalScope":true},{"version":"22f230e544b35349cfb3bd9110b6ef37b41c6d6c43c3314a31bd0d9652fcec72","affectsGlobalScope":true},{"version":"7ea0b55f6b315cf9ac2ad622b0a7813315bb6e97bf4bb3fbf8f8affbca7dc695","affectsGlobalScope":true},{"version":"3013574108c36fd3aaca79764002b3717da09725a36a6fc02eac386593110f93","affectsGlobalScope":true},{"version":"eb26de841c52236d8222f87e9e6a235332e0788af8c87a71e9e210314300410a","affectsGlobalScope":true},{"version":"3be5a1453daa63e031d266bf342f3943603873d890ab8b9ada95e22389389006","affectsGlobalScope":true},{"version":"17bb1fc99591b00515502d264fa55dc8370c45c5298f4a5c2083557dccba5a2a","affectsGlobalScope":true},{"version":"7ce9f0bde3307ca1f944119f6365f2d776d281a393b576a18a2f2893a2d75c98","affectsGlobalScope":true},{"version":"6a6b173e739a6a99629a8594bfb294cc7329bfb7b227f12e1f7c11bc163b8577","affectsGlobalScope":true},{"version":"81cac4cbc92c0c839c70f8ffb94eb61e2d32dc1c3cf6d95844ca099463cf37ea","affectsGlobalScope":true},{"version":"b0124885ef82641903d232172577f2ceb5d3e60aed4da1153bab4221e1f6dd4e","affectsGlobalScope":true},{"version":"0eb85d6c590b0d577919a79e0084fa1744c1beba6fd0d4e951432fa1ede5510a","affectsGlobalScope":true},{"version":"da233fc1c8a377ba9e0bed690a73c290d843c2c3d23a7bd7ec5cd3d7d73ba1e0","affectsGlobalScope":true},{"version":"d154ea5bb7f7f9001ed9153e876b2d5b8f5c2bb9ec02b3ae0d239ec769f1f2ae","affectsGlobalScope":true},{"version":"bb2d3fb05a1d2ffbca947cc7cbc95d23e1d053d6595391bd325deb265a18d36c","affectsGlobalScope":true},{"version":"c80df75850fea5caa2afe43b9949338ce4e2de086f91713e9af1a06f973872b8","affectsGlobalScope":true},{"version":"9d57b2b5d15838ed094aa9ff1299eecef40b190722eb619bac4616657a05f951","affectsGlobalScope":true},{"version":"6c51b5dd26a2c31dbf37f00cfc32b2aa6a92e19c995aefb5b97a3a64f1ac99de","affectsGlobalScope":true},{"version":"6e7997ef61de3132e4d4b2250e75343f487903ddf5370e7ce33cf1b9db9a63ed","affectsGlobalScope":true},{"version":"2ad234885a4240522efccd77de6c7d99eecf9b4de0914adb9a35c0c22433f993","affectsGlobalScope":true},{"version":"5e5e095c4470c8bab227dbbc61374878ecead104c74ab9960d3adcccfee23205","affectsGlobalScope":true},{"version":"09aa50414b80c023553090e2f53827f007a301bc34b0495bfb2c3c08ab9ad1eb","affectsGlobalScope":true},{"version":"d7f680a43f8cd12a6b6122c07c54ba40952b0c8aa140dcfcf32eb9e6cb028596","affectsGlobalScope":true},{"version":"3787b83e297de7c315d55d4a7c546ae28e5f6c0a361b7a1dcec1f1f50a54ef11","affectsGlobalScope":true},{"version":"e7e8e1d368290e9295ef18ca23f405cf40d5456fa9f20db6373a61ca45f75f40","affectsGlobalScope":true},{"version":"faf0221ae0465363c842ce6aa8a0cbda5d9296940a8e26c86e04cc4081eea21e","affectsGlobalScope":true},{"version":"06393d13ea207a1bfe08ec8d7be562549c5e2da8983f2ee074e00002629d1871","affectsGlobalScope":true},{"version":"2768ef564cfc0689a1b76106c421a2909bdff0acbe87da010785adab80efdd5c","affectsGlobalScope":true},{"version":"b248e32ca52e8f5571390a4142558ae4f203ae2f94d5bac38a3084d529ef4e58","affectsGlobalScope":true},{"version":"6c55633c733c8378db65ac3da7a767c3cf2cf3057f0565a9124a16a3a2019e87","affectsGlobalScope":true},{"version":"fb4416144c1bf0323ccbc9afb0ab289c07312214e8820ad17d709498c865a3fe","affectsGlobalScope":true},{"version":"5b0ca94ec819d68d33da516306c15297acec88efeb0ae9e2b39f71dbd9685ef7","affectsGlobalScope":true},{"version":"34c839eaaa6d78c8674ae2c37af2236dee6831b13db7b4ef4df3ec889a04d4f2","affectsGlobalScope":true},{"version":"34478567f8a80171f88f2f30808beb7da15eac0538ae91282dd33dce928d98ed","affectsGlobalScope":true},{"version":"ab7d58e6161a550ff92e5aff755dc37fe896245348332cd5f1e1203479fe0ed1","affectsGlobalScope":true},{"version":"6bda95ea27a59a276e46043b7065b55bd4b316c25e70e29b572958fa77565d43","affectsGlobalScope":true},{"version":"aedb8de1abb2ff1095c153854a6df7deae4a5709c37297f9d6e9948b6806fa66","affectsGlobalScope":true},{"version":"a4da0551fd39b90ca7ce5f68fb55d4dc0c1396d589b612e1902f68ee090aaada","affectsGlobalScope":true},{"version":"11ffe3c281f375fff9ffdde8bbec7669b4dd671905509079f866f2354a788064","affectsGlobalScope":true},{"version":"52d1bb7ab7a3306fd0375c8bff560feed26ed676a5b0457fa8027b563aecb9a4","affectsGlobalScope":true},"0990a7576222f248f0a3b888adcb7389f957928ce2afb1cd5128169086ff4d29",{"version":"bbdf156fea2fabed31a569445835aeedcc33643d404fcbaa54541f06c109df3f","affectsGlobalScope":true},"4c68749a564a6facdf675416d75789ee5a557afda8960e0803cf6711fa569288","6a386ff939f180ae8ef064699d8b7b6e62bc2731a62d7fbf5e02589383838dea","f5a8b384f182b3851cec3596ccc96cb7464f8d3469f48c74bf2befb782a19de5",{"version":"5917af4ff931b050dba49a1dedd9c00f15f7b3dc4345ad8491bfacd2ec68ed32","affectsGlobalScope":true},"cc69795d9954ee4ad57545b10c7bf1a7260d990231b1685c147ea71a6faa265c","8bc6c94ff4f2af1f4023b7bb2379b08d3d7dd80c698c9f0b07431ea16101f05f","1b61d259de5350f8b1e5db06290d31eaebebc6baafd5f79d314b5af9256d7153","57194e1f007f3f2cbef26fa299d4c6b21f4623a2eddc63dfeef79e38e187a36e","0f6666b58e9276ac3a38fdc80993d19208442d6027ab885580d93aec76b4ef00","05fd364b8ef02fb1e174fbac8b825bdb1e5a36a016997c8e421f5fab0a6da0a0","0cba3a5d7b81356222594442753cf90dd2892e5ccfe1d262aaca6896ba6c1380","a69c09dbea52352f479d3e7ac949fde3d17b195abe90b045d619f747b38d6d1a",{"version":"c2ab70bbc7a24c42a790890739dd8a0ba9d2e15038b40dff8163a97a5d148c00","affectsGlobalScope":true},"422dbb183fdced59425ca072c8bd09efaa77ce4e2ab928ec0d8a1ce062d2a45a",{"version":"2a801b0322994c3dd7f0ef30265d19b3dd3bae6d793596879166ed6219c3da68","affectsGlobalScope":true},"1dab5ab6bcf11de47ab9db295df8c4f1d92ffa750e8f095e88c71ce4c3299628","f71f46ccd5a90566f0a37b25b23bc4684381ab2180bdf6733f4e6624474e1894",{"version":"54e65985a3ee3cec182e6a555e20974ea936fc8b8d1738c14e8ed8a42bd921d4","affectsGlobalScope":true},"82408ed3e959ddc60d3e9904481b5a8dc16469928257af22a3f7d1a3bc7fd8c4","bcc8caf03ee65fe8610d258752f255fbdddbb2e4de7b6c5628956a5a0d859ec8","34e5de87d983bc6aefef8b17658556e3157003e8d9555d3cb098c6bef0b5fbc8","cc0b61316c4f37393f1f9595e93b673f4184e9d07f4c127165a490ec4a928668","f27371653aded82b2b160f7a7033fb4a5b1534b6f6081ef7be1468f0f15327d3","c762cd6754b13a461c54b59d0ae0ab7aeef3c292c6cf889873f786ee4d8e75c9","f4ea7d5df644785bd9fbf419930cbaec118f0d8b4160037d2339b8e23c059e79",{"version":"bfea28e6162ed21a0aeed181b623dcf250aa79abf49e24a6b7e012655af36d81","affectsGlobalScope":true},"7a5459efa09ea82088234e6533a203d528c594b01787fb90fba148885a36e8b6","ae97e20f2e10dbeec193d6a2f9cd9a367a1e293e7d6b33b68bacea166afd7792","10d4796a130577d57003a77b95d8723530bbec84718e364aa2129fa8ffba0378","ad41bb744149e92adb06eb953da195115620a3f2ad48e7d3ae04d10762dae197","bf73c576885408d4a176f44a9035d798827cc5020d58284cb18d7573430d9022","7ae078ca42a670445ae0c6a97c029cb83d143d62abd1730efb33f68f0b2c0e82",{"version":"e8b18c6385ff784228a6f369694fcf1a6b475355ba89090a88de13587a9391d5","affectsGlobalScope":true},"5d0a9ea09d990b5788f867f1c79d4878f86f7384cb7dab38eecbf22f9efd063d","12eea70b5e11e924bb0543aea5eadc16ced318aa26001b453b0d561c2fd0bd1e","08777cd9318d294646b121838574e1dd7acbb22c21a03df84e1f2c87b1ad47f2","08a90bcdc717df3d50a2ce178d966a8c353fd23e5c392fd3594a6e39d9bb6304",{"version":"8207e7e6db9aa5fc7e61c8f17ba74cf9c115d26f51f91ee93f790815a7ea9dfb","affectsGlobalScope":true},"2a12d2da5ac4c4979401a3f6eaafa874747a37c365e4bc18aa2b171ae134d21b","002b837927b53f3714308ecd96f72ee8a053b8aeb28213d8ec6de23ed1608b66","1dc9c847473bb47279e398b22c740c83ea37a5c88bf66629666e3cf4c5b9f99c","a9e4a5a24bf2c44de4c98274975a1a705a0abbaad04df3557c2d3cd8b1727949","00fa7ce8bc8acc560dc341bbfdf37840a8c59e6a67c9bfa3fa5f36254df35db2","1b952304137851e45bc009785de89ada562d9376177c97e37702e39e60c2f1ff",{"version":"806ef4cac3b3d9fa4a48d849c8e084d7c72fcd7b16d76e06049a9ed742ff79c0","affectsGlobalScope":true},"cfe724f7c694aab65a9bdd1acb05997848c504548c9d4c71645c187a091cfa2a","5f0ed51db151c2cdc4fa3bb0f44ce6066912ad001b607a34e65a96c52eb76248",{"version":"3345c276cab0e76dda86c0fb79104ff915a4580ba0f3e440870e183b1baec476","affectsGlobalScope":true},"664d8f2d59164f2e08c543981453893bc7e003e4dfd29651ce09db13e9457980","e383ff72aabf294913f8c346f5da1445ae6ad525836d28efd52cbadc01a361a6","f52fbf64c7e480271a9096763c4882d356b05cab05bf56a64e68a95313cd2ce2","59bdb65f28d7ce52ccfc906e9aaf422f8b8534b2d21c32a27d7819be5ad81df7","1835259a20b9fa6b1882931375b69ae5978195f2b139b4e0db51ec8319261649","28a2e7383fd898c386ffdcacedf0ec0845e5d1a86b5a43f25b86bc315f556b79","3aff9c8c36192e46a84afe7b926136d520487155154ab9ba982a8b544ea8fc95","a880cf8d85af2e4189c709b0fea613741649c0e40fffb4360ec70762563d5de0","85bbf436a15bbeda4db888be3062d47f99c66fd05d7c50f0f6473a9151b6a070","9f9c49c95ecd25e0cb2587751925976cf64fd184714cb11e213749c80cf0f927","f0c75c08a71f9212c93a719a25fb0320d53f2e50ca89a812640e08f8ad8c408c",{"version":"ab9b9a36e5284fd8d3bf2f7d5fcbc60052f25f27e4d20954782099282c60d23e","affectsGlobalScope":true},"0b3eba6dca8c6e534d16ef7b7d76cb546cd3cbab616c8f71daa0a151b5412b9e","30a1b56068b3820c91a055425a6af2294f8ef2bb10a59dcda413f6437093620d","e4dd91dd4789a109aab51d8a0569a282369fcda9ba6f2b2297bc61bacfb1a042","db6d2d9daad8a6d83f281af12ce4355a20b9a3e71b82b9f57cddcca0a8964a96","5d97586646b92d2c7d8013e7078d7e06662db89d1155d2903e7ef893665dbd16","625e5d5e9e25017d53e65c62ff944d812d48ec1bbaaf7395c8f8cdf6c9218061","f307044185ce95a12cd54318863a9c56ed9271a4fc45df9e0c4d47db4285c3c2","39a3fc61a65aee8c90cd81bb2c9b508be6c5cc745cd40eaed95954a07c11bb82","6ceac05c32f579adbed2f1a9c98cd297de3c00a3caaffc423385d00e82bce4ce","973b59a17aaa817eb205baf6c132b83475a5c0a44e8294a472af7793b1817e89","ada39cbb2748ab2873b7835c90c8d4620723aedf323550e8489f08220e477c7f","fa5bbc7ab4130dd8cdc55ea294ec39f76f2bc507a0f75f4f873e38631a836ca7","f7c024ce0f73f3a0e56f35826bed34dd9743ad7daa19068acca653dd7d45f010","0b8c260ba3dce2d948222ddb53abb6d2de7692cca77ee8433507b0de0b8ff98d","d0a911a97b9eaf51bb8307ad2399e795790bb4fe2b247d7574bd5479fb5bd87e","43612765af269faa0548381af60886fdd78c507412bbcb3b676ba986b2e90bba","efc234c21b905df4553132cc604830f2aab1c0e492a6f7de5c0ea7fb22fbc2c1","c10a063aa725e3279752833d3661d6c5403b3dcddf339e82ac5aa36f104abc0d","8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","99549a6392ef52a5a1c5e8a9d3a449d9a518d25af22e5a4c31bdd11b61ded010","741c438ec079a077b08d37d9c0466924b68e98ed47224e83fcb125c5863eb355","649d4c4855a24d8f7cbe4977a0733c405b8ab00f87774359987e4648d0d9da1e","98435f5eaadf367fa5b29e886f6265456219dbbb05e075d135aa5938f7ffc46d","1b82026434e469addbcb287a1f2c6e81eab7e9c461714543ea37715763f45ef8","3fcd21b8633fd84dc57ba6e4a17d13f68946fb1702e1e68ca5b6412dcaa20275","9e588ebf03931ac4de811943fdecf605bea04e2060fafae0bf4529a4c9351607","403f280e4101791df0e67aaf1f52c23391390a9535aa597df533e6fe74c2bb75","aed65bf7421ea3b799066d0560878aa28f6728bd648a2cd33859eca4c1b8e3ac","ca1b882a105a1972f82cc58e3be491e7d750a1eb074ffd13b198269f57ed9e1b","c56cba491c0f32b78198af0ac7471c1cceca57db4e0a2c23c0b2659063bfae53","737d402374f91fad8f0928daf76e9ee9fd5912aeb35b351e44eb7ecea2dcb87c","fc7214ff37161bf1e89c52b11fc7dddceccab809e36ea0ee26353c7502b0b27b","58902668adae2e5eb67efbccb4048afa02308fa684f1a4e4c7d47668ecf58c1b","3d365237792d79384c1315ad7fba7505b4355ba88d2032349ab437bf7b22e2e8","ee9461f976caf518f336892f101a85109686d1fcfecee8d9079b81e9c68dc86e","e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","c3624afffa46c8cd4c775a9578a627277e9b06cddfbc3fdb14cc0f4673f45ae7","cace786bf8078d7cb640d94f97c2f47e5c4f979c6a2e3c9168e54a0d79a6ac0a","17937316a2f7f362dd6375251a9ce9e4960cfdc0aa7ba6cbd00656f7ab92334b","575bc12d93a33c09e803375cd99a77f50c9272d01abe26d5de27af637c7427a3","7d7ce795ac82a239ce89b7088e6fcf8a406b1ebb6c4ff75ae3970beafba35585","e01ed711d76cfe84c7d099d75306323fa1ebc27ce02a742fab271e82a1da4dee","7d1b37284c9a4c58e2954aa21485d37881b5ab25937b29ebfb63c4d37fc3ae3d","1efe66d15fb19a2e8f3aff712fdfd1b9f7b19e7c3603ee188b13a9572ff9a7d8","f0e480e327dd94c30c7003c7ca188b401ab451396f40e4ec5ae2f9b3a944a7be","2a130020150086164f429b0ba507ad66a729f2cbaee14ed4348fdb2504bdd49e","6e5f5cee603d67ee1ba6120815497909b73399842254fc1e77a0d5cdc51d8c9c","f6404e7837b96da3ea4d38c4f1a3812c96c9dcdf264e93d5bdb199f983a3ef4b","4a3fb0f285c6bd13500366e3023d90b40bd2fbafcfe6e1ffaa8e6ab62bba4907","3cd0346fc79e262233785d9fe2cbad08fc3fe6339af3419791687152ddfe5596","9f3c4349b19905df8e6977106894cb01cbb5ebd6f2a8da64bddaae8b1b3e1c04","2652448ac55a2010a1f71dd141f828b682298d39728f9871e1cdf8696ef443fd","1e7fb60ac7ae5365d12ec98b3efbcb9130c400ad3ccc07f2db6f26ff24d62ccf","0aef0a60e229dfeff49f68bf941d24b8338fc3d55aa7c64b1c9acbf9d3a67b46","c4277bc74428f8b8c3ffb5a3bc6684d6bda2ce66e7428e4a99df7ebaedf0f708","5b2e8cec02a40770a0c3f953d78dce6632f345638f85af4b24fd16fcfbaf0019","d23518a5f155f1a3e07214baf0295687507122ae2e6e9bd5e772551ebd4b3157","53a99fb41040b64c6bc8aa5b231547439d205e61f7f022a43a6a1da65657cbf6","3a083cc0c3bd0346304a0de0568a2cec000bed4cd7885bab3be70bfecef50e96","c8556b8716fc69ab436b340f8a5171d56cf9f03b3017f345fda4876174608080","c2299e6708a155e6c156ef9e92c83e074dbd32611fd84d6b07648d34cd35209a","fb480794b12bbe2cdce8a9e6759e3045208765278f248c6a6135c6993aa9683f","b0423e07b18195c4a276f95b30b464ee0816dc5e4fc59c262f60afe189930516","8317f1d2e04f181eca793161466a31d3082d3af6eb6516ba1fead9fe66037431","3ca193730b6d9fbb08cee1241b648297527dfa64a86853f7a1384e9943d76726","88961917ec908f9fde57b86b8038b8b30766ba14cfdcc214c7c5498d7c9f7924","6d8e12183e7baed15513970482d9cca86954bb7dfaef8ca862718ca144aadb3b","45e5c75f8ddf51eff85961cf1912a9a745809957f8b57a0a7d859e20b19ae260","5279f50f5711aaad3894a016eb905fa50d75bcba30bd652f8be73ab5f3037a73","1366638c25b6ce477f6394c584cc0e2364ff72ffaeec3ceb7dde1c7b939fade9","e927c2c13c4eaf0a7f17e6022eee8519eb29ef42c4c13a31e81a611ab8c95577","1822b69406252b606dc1aec3231a7104ac1d456cfa2c0a9041e61061895ae348","0d05309199fe921b0b7dc131104f5dd2957a024072781a8393ea5357c8ce9a49","c1ac179620434b59c1569f2964a5c7354037ac91a212a1fb281673589965c893","9f891dc96f3e9343c4e823ba28195fd77e59c84199696a8bdfe7b67925732409","63f50c44294385846e5deed7d9d056b3b3bad04ebaa63e1fdca149e1627f5d40","7a5df736ff13c4981f10fe29ab73e61a6c3f8e4cfc30224e73566725b601d802","98b94a34fe1138e1d59d138dbf0d7b19592d6540393a1b4653d4ad7271d2f64d","b9de430616a42e94268dc62720d46bc80e04350efed18fc04be7a12974cfb84d","2c6f043430f24bde409ed1e70d197b3ef70607cd656817bfd6cf02e630bb7a39","495a5da35b04cd142d1301921ce8776c3bd8eab85bbf0ea694e631bc5cd35338","9d20a77883a17070169ea0f80ba2cd27575df30510f5bf4d6d292b3ea547f681","b0967cf27e8a3c05a82ca58cc96bb2e1443b03d400d5b19b85735cac81adb2ca","5cab8fa167ee711e4dfcd22ed632c60be36bd49dc6eea8cfdd3613c59d00c43d","6176b9f450623c979d65630c243971e4348b39f9c2b3052f4b1b2f2d558c13c7","06bcd1f53ae68951411b1649b45fdea22d87db52d2dbeeb8b0af44d47a186c3f","b65c4ff9cd4815c5f1855e8702740c8bbb4921140e3c415c5affe3e376e322dc","69b1a4767d6249cc8fa88110fbcee746684f9159c7c9d4f14f6ea3bf11ab8bd5","be90dde0efc4ce2544606fa5bd2cf15660f43175f49daae067c53a16d7cbf024","15e84dd6d50ef02f936e7bf8f32f71e7469d486df900955e6f8c152266e4b801","0efea28e99af48ea75df7cccb178ba8030aad78fdf04c884bde983a95b5b4545",{"version":"1fe4972a8ec31134aec90e9dba4073616d21464820c780774e156fa7ccb32bf7","affectsGlobalScope":true},"c31eabb9cbf9582fb62ceccaaae17d03768ec31b1dda9b9b258ee999500ce1ca","070187a9132cd795f971a1c22b75000c0a73bbdfc49c8d3091e763df8c80b002","2766dee26ea113e9b491b7842cb44df57c4d79b17057b42607e09fc174bd411d","cb4047ce260c2f4585b2d592d04a1d9a9c2a1ba32679a688523ec314a977989a","0511c61c22d677da1b6bab4d3844aead1d7e27028d2f0ed1ed315e0860ed5357",{"version":"b4610d904ab939109aa8bcee6f795de8da780b6b4a4d8ff2ff9d2e3b699f55b7","affectsGlobalScope":true},{"version":"6707b2ff066e782f676f90ba7abfca7d6f321eececbbecf3d42eebb7a8c28da2","affectsGlobalScope":true},"b87389fa915955221ff512128d9bad0b60fa922b6b29a358c032b3c5a1754ebd","7f9daeb92677b8461e7d64e05cb7a4fadcc4f1df15352fc41a7e9493fa9ae7ff","2ebe37d9476d15f0541dd5d79267db6e30d6491ed349254ee68a0de25620c577","2d3c25f508407607500045c74c69b5b6abe74838807f4dc2ef5c4bbf1cc642e6",{"version":"3cf72817794f1152e41b704c8f6072c099f0e676bcd704a967901220873fec94","affectsGlobalScope":true},"8e0579532322778ab89c3c61228588e08093aa2d698dcff9be3215e0dbc70be7","49d1d55994ac37a756bd332aad59ef68d89ae15a2b79c3c343f8432c468e09bc","06dfd2ebf571b3df2cc23a70f031417eb77f7702f0ce727cec99a296242d6929","65c24a8baa2cca1de069a0ba9fba82a173690f52d7e2d0f1f7542d59d5eb4db0","b7fff2d004c5879cae335db8f954eb1d61242d9f2d28515e67902032723caeab","8303df69e9d100e3df8f2d67ec77348cb6494dc406356fdd9b56e61aa7c3c758","8de50542d92f9ac659c30ead0a97e9c107dd3404a3b4fd4bf3504589a026221a","4545c1a1ceca170d5d83452dd7c4994644c35cf676a671412601689d9a62da35","a80e3207332979fcd48223790af48f61192c1d348162adb7e4f30f23085dc0e1","a2d648d333cf67b9aeac5d81a1a379d563a8ffa91ddd61c6179f68de724260ff","c3a905a7fa93ca648349e934fb19356cf7b40e48d65658de3e0c77d67696fd40","a3f41ed1b4f2fc3049394b945a68ae4fdefd49fa1739c32f149d32c0545d67f5","c2489c80994d62e5b51370a6f02f537db4c37af5f914fcb5b2755b81f1906cae","47699512e6d8bebf7be488182427189f999affe3addc1c87c882d36b7f2d0b0e","da5f632f5f82f60322089dc4f73fde31ba4c51d599d920d1cad0eef686c71f7c","42c686ce08bf5576ed178f4a6a62d1b580d941334fb53bdff7054e0980f2dc75","605b66155b4f222c5f5a48bf19224815e4bceb2966dfb1c5704692ed07e5fa0a","cdf21eee8007e339b1b9945abf4a7b44930b1d695cc528459e68a3adc39a622e","1d079c37fa53e3c21ed3fa214a27507bda9991f2a41458705b19ed8c2b61173d","26a451bf3a5f87ebaaa7694c5b664c3d9cec296f3fa8b797b872aee0f302b3a0","5835a6e0d7cd2738e56b671af0e561e7c1b4fb77751383672f4b009f4e161d70","c0eeaaa67c85c3bb6c52b629ebbfd3b2292dc67e8c0ffda2fc6cd2f78dc471e6","4b7f74b772140395e7af67c4841be1ab867c11b3b82a51b1aeb692822b76c872","25c4bd23e828e865868722c7a1d01876ed891ddfbd92cb6f006e747f56eee0c9","c2008605e78208cfa9cd70bd29856b72dda7ad89df5dc895920f8e10bcb9cd0a","ec61ebac4d71c4698318673efbb5c481a6c4d374da8d285f6557541a5bd318d0","10ec84e648ffc7654868ca02c21a851bc211c8e4d50fd68131c1afa9afd96a33","b5934ca186f498c83e9a663d3df019d82290303fd86b1658cf27cf892b50aaf9",{"version":"90c89a318a59d6b3decbc0bc476210548eba1c3668037058b0a6e6cc363d47dd","affectsGlobalScope":true},{"version":"57ad3ef8cd87e876021acbcabcc6457f21a721cb0c5388de700bd57ea32030c1","affectsGlobalScope":true},"9c00f78ac4e60d1c34d0fb415df6b2fea5f6eea200076dff4d782256a4c2802d","79d056984a8964d3917c7587067447d7565d9da696fcf6ecaa5e8437a214f04e","9269d492817e359123ac64c8205e5d05dab63d71a3a7a229e68b5d9a0e8150bf","2bf8d68be6cfc43093d8e9961a77958ba6a406b2af4fbc04ae5c301fad5aef55","807535f4e95ebccc1eae3d675289b1be5c23e6aaa6fd624f2be485e3e1e6f23d","1d1872677306b44559ce09926b9eab6a34507d5f5dd465324d94f34cf7a36872","1e00b8bf9e3766c958218cd6144ffe08418286f89ff44ba5a2cc830c03dd22c7","f3c253f3833841eb9dd65d6b99a2f357debfdeef5f85c85c291a465bbf03bc6b","7a129438cedf12b5f1b5f773a3e96242b7569c95243432dcf12618f80fca5cdc","0165115e3c8788801fb59e9c3cca0c7ba573515a8b7ce010c7d75deba92b455f","0e000fd63bd08abc96dbd4746c371b8a0368f351629590ee7ba12c9787cdc8e6","463ed32d194c6bd58c35083d76af0170ad1b04f7b3ef91c9803593bd089c2864","84936ce43e5e01db3ee57c205d244181d85cd0e1fadbc6e1f94b3d9bd9a3aae5","802417aed26cb50faf8b7176fa00279bdb5acbb53bf4a63ae00d47d25d904516","bc1899efe6dcdce9c9c8bd9ce97d58b197facb7f4a516e5d13a804fa5f77cf4f","4d080c54c10ec25e6e84337dbaff7953066150baf94fd48db6c70a37cdd43a8a","3ad4660add51c3c3adf49524d61cc1e3ed57e16274c62c6cfb047b64aab973aa","22f25ec27fa1c1ca03010aa71b8077c742ab5bf6a08a44663a287a296be34481","74ac2c0b3fa70bb0cf47f80fabc73f6b868ba177ced233e294068fc099cf5a06","7c8c3dfc0cdd370d44932828eb067ef771c8fe7996693221d5d4b90af6d54f2d","fce3be25a64ca64c47d90887b7055580ad97976c00d1e3b9bac188cc381f05a6","951a918a753179bf5c018065e3302c8e2d899600ac1e7e5dfc1c2d9867a643c5","842454d0222fa151b62f4f18c893335993829311367f4502270d449bd32c1b72","ca8d9484968d464e3779ac344132494f8a41084d74ece61e5b19ec86e73bb0ad","894711d8c2e76012cc3258ab90fc6339b19a792349f94c16e1b4801709e0eb94","dc45760b1f08ebb5d24b69ddc2ea2a42b724e17c643cd73ef52128d992a62cc9","94caf997b590e006b84f927275ddddfb84bbf8539535b0888bd83eea867e88c4","ae0d70b4f8a3a43cb0a5a89859aca3611f2789a3bca6a387f9deab912b7605b0","966b0f7789547bb149ad553f5a8c0d7b4406eceac50991aaad8a12643f3aec71","8063cff815975c1dceb2f9cdba3cffa6afd97b084d71acc0264b7af00ef31d76","d78bd0f8ac7d8de2d80a0ca8818216f4f7d94abfea6c7f3a2581252ba110938d","3dbad0bac309b341e0f1a930e0a163b1bd041f5375975a0f9ecca9b4783ad8f0","de749e7f86ee33a1874c595c605a45746138ef46b7d35b1699043abb01f1e7c3","f7ff7b1534fec1cc87e8063745cb140dcfe2014c5e559994093d986b93274f69","29f43c6639fe1f2302cbc29a4362f15bb40fe1e5e88fb9d7cdf1e2ccb8102826","fa70bdc67035c981fcb92927c0964016a5d731937b51767e12b596dc53c2471d"],"options":{"esModuleInterop":true,"jsx":1,"module":99,"skipLibCheck":true,"strict":false,"strictNullChecks":true},"fileIdsList":[[112],[69,112],[72,112],[73,78,112],[74,84,85,92,101,111,112],[74,75,84,92,112],[76,112],[77,78,85,93,112],[78,101,108,112],[79,81,84,92,112],[80,112],[81,82,112],[83,84,112],[84,112],[84,85,86,101,111,112],[84,85,86,101,112],[87,92,101,111,112],[84,85,87,88,92,101,108,111,112],[87,89,101,108,111,112],[69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118],[84,90,112],[91,111,112],[81,84,92,101,112],[93,112],[94,112],[72,95,112],[96,110,112,116],[97,112],[98,112],[84,99,112],[99,100,112,114],[84,101,102,103,112],[101,103,112],[101,102,112],[104,112],[105,112],[84,106,107,112],[106,107,112],[78,92,101,108,112],[109,112],[92,110,112],[73,87,98,111,112],[78,112],[101,112,113],[112,114],[112,115],[73,78,84,86,95,101,111,112,114,116],[101,112,117],[62,112],[58,59,60,61,112],[112,276],[62,112,282],[67,112],[112,227],[112,229],[112,124,134,146,212],[112,136],[98,112,119,120,124,134,147,173,174,175,178,212],[112,122,145],[112,122],[112,122,145,146],[112,180,181,212],[72,112,119,180,181,212],[72,112,119,175],[62,112,125],[62,111,112,119],[62,112,145,218],[62,112,145],[112,216,224],[62,112,217,226],[112,259],[62,101,112,119,250],[62,66,87,112,119,212,248,249],[112,123],[112,205,206,207,208,209,210],[112,207],[62,112,213,226],[62,112,226],[87,112,119,135,226],[72,112,119],[112,175,176,186],[87,112,119,134,136],[87,101,112,119,133,135,136,212],[87,98,111,112,119,123,124,125,129,133,134,135,136,142,143,144,145,148,157,158,160,162,163,164,165,166,168,170,175,190,192,212],[87,101,112,119],[112,122,124,125,126,133,212,226],[112,134],[98,111,112,119,124,129,132,133,134,135,136,142,143,144,155,158,161,164,167,175,190,193,199,201,202],[112,134,175],[112,133,134],[112,142,191],[112,130,131],[112,130,194],[112,130],[112,132,135,171,189],[112,130,131,132,140,141,143],[112,130,131,132,140,143,200],[112,132,141,142],[112,140],[112,129,131,132],[112,132,195],[112,129,131],[112,129,134,152,172,179,185,187,188],[112,129,131,152,176,177,182,183,184],[87,111,112,119,125,133,134,170],[112,157,170,226],[112,176,177],[112,120,163,212,226],[87,98,111,112,119,124,129,133,135,137,139,144,147,148,155,157,158,160,161,162,166,167,170,175,193,196,197,198,226],[87,112,119,133,199,203],[62,87,98,112,119,123,125,133,136,148,162,163,164,165,212],[87,98,111,112,119,127,132,135],[112,169],[87,112,119,148],[98,112,119,123,124,129,133,135,142,143],[87,112,119,148,159],[87,112,119,135,160],[87,112,119,134,142],[87,112,119],[112,151],[112,150],[112,152],[112,251],[112,134,149,151,155],[112,134,149,151],[87,112,119,127,134,152,153,154],[112,220],[112,220,221,222],[62,112,120,162,165,212,226],[62,98,111,112,119,123,215,217,219,223,226],[112,129,135,145],[98,112,119],[112,128],[62,87,98,112,119,123,212,213,214,224,225],[57,62,63,64,65,112,212,250],[112,231],[112,233],[112,235],[112,260],[112,237],[112,239],[66,68,112,212,228,230,232,234,236,238,240,242,243,245,253,254],[112,241],[112,217],[112,244],[72,112,152,153,154,155,246,247,252],[112,119],[62,66,87,98,112,119,121,123,136,204,211,226,250],[112,264,265,266,267,268,269,270,271,272],[112,264,267],[112,266,267],[112,267],[112,264],[112,255,258,262,274,285,286,287],[112,242,258,278],[112,279],[112,285],[62,112,242,258,274,275,280],[112,242,258,278,280,281,284],[62,112,282,283],[62,112,278,280,283],[62,112,274,277],[112,261],[112,263,273],[112,255,256]],"referencedMap":[[214,1],[69,2],[70,2],[72,3],[73,4],[74,5],[75,6],[76,7],[77,8],[78,9],[79,10],[80,11],[81,12],[82,12],[83,13],[84,14],[85,15],[86,16],[71,1],[118,1],[87,17],[88,18],[89,19],[119,20],[90,21],[91,22],[92,23],[93,24],[94,25],[95,26],[96,27],[97,28],[98,29],[99,30],[100,31],[101,32],[103,33],[102,34],[104,35],[105,36],[106,37],[107,38],[108,39],[109,40],[110,41],[111,42],[112,43],[113,44],[114,45],[115,46],[116,47],[117,48],[60,1],[121,49],[58,1],[62,50],[61,1],[277,51],[276,1],[263,1],[59,1],[279,49],[283,52],[282,49],[68,53],[228,54],[230,55],[145,56],[157,57],[179,58],[146,59],[173,1],[163,60],[147,61],[165,60],[158,60],[126,60],[183,62],[177,1],[182,63],[176,64],[184,1],[239,65],[241,66],[219,67],[218,68],[217,69],[244,49],[216,70],[150,1],[247,1],[260,71],[259,1],[249,1],[251,72],[248,49],[250,73],[122,1],[174,1],[124,74],[205,1],[206,1],[208,1],[211,75],[207,1],[209,76],[210,76],[156,1],[227,70],[231,77],[235,78],[136,79],[186,80],[187,81],[135,82],[161,83],[193,84],[127,85],[134,86],[123,87],[203,88],[202,89],[162,1],[142,90],[171,1],[192,91],[191,1],[172,92],[194,92],[195,93],[131,94],[190,95],[130,1],[200,96],[201,97],[143,98],[141,99],[140,100],[196,101],[132,102],[189,103],[185,104],[120,1],[198,105],[137,1],[175,106],[178,107],[197,1],[164,108],[199,109],[204,110],[138,1],[139,1],[148,85],[166,111],[133,112],[170,113],[169,114],[144,115],[160,116],[159,117],[188,1],[149,118],[180,119],[181,120],[151,121],[153,122],[252,123],[152,124],[154,125],[246,1],[155,126],[67,1],[221,127],[222,1],[220,1],[223,128],[225,1],[233,49],[237,49],[213,129],[125,1],[215,1],[224,130],[168,131],[167,132],[129,133],[128,1],[229,1],[226,134],[57,1],[66,135],[63,49],[64,1],[65,1],[232,136],[234,137],[236,138],[261,139],[238,140],[256,141],[240,141],[255,142],[242,143],[243,144],[245,145],[253,146],[254,147],[212,148],[273,149],[270,150],[268,151],[269,150],[272,152],[271,152],[264,1],[265,153],[267,1],[266,1],[11,1],[12,1],[14,1],[13,1],[2,1],[15,1],[16,1],[17,1],[18,1],[19,1],[20,1],[21,1],[22,1],[3,1],[4,1],[26,1],[23,1],[24,1],[25,1],[27,1],[28,1],[29,1],[5,1],[30,1],[31,1],[32,1],[33,1],[6,1],[37,1],[34,1],[35,1],[36,1],[38,1],[7,1],[39,1],[44,1],[45,1],[40,1],[41,1],[42,1],[43,1],[8,1],[49,1],[46,1],[47,1],[48,1],[50,1],[9,1],[51,1],[52,1],[53,1],[54,1],[55,1],[1,1],[10,1],[56,1],[288,154],[289,155],[280,156],[290,157],[281,158],[285,159],[286,1],[287,160],[284,161],[278,162],[258,1],[262,163],[274,164],[257,165],[275,1]],"exportedModulesMap":[[214,1],[69,2],[70,2],[72,3],[73,4],[74,5],[75,6],[76,7],[77,8],[78,9],[79,10],[80,11],[81,12],[82,12],[83,13],[84,14],[85,15],[86,16],[71,1],[118,1],[87,17],[88,18],[89,19],[119,20],[90,21],[91,22],[92,23],[93,24],[94,25],[95,26],[96,27],[97,28],[98,29],[99,30],[100,31],[101,32],[103,33],[102,34],[104,35],[105,36],[106,37],[107,38],[108,39],[109,40],[110,41],[111,42],[112,43],[113,44],[114,45],[115,46],[116,47],[117,48],[60,1],[121,49],[58,1],[62,50],[61,1],[277,51],[276,1],[263,1],[59,1],[279,49],[283,52],[282,49],[68,53],[228,54],[230,55],[145,56],[157,57],[179,58],[146,59],[173,1],[163,60],[147,61],[165,60],[158,60],[126,60],[183,62],[177,1],[182,63],[176,64],[184,1],[239,65],[241,66],[219,67],[218,68],[217,69],[244,49],[216,70],[150,1],[247,1],[260,71],[259,1],[249,1],[251,72],[248,49],[250,73],[122,1],[174,1],[124,74],[205,1],[206,1],[208,1],[211,75],[207,1],[209,76],[210,76],[156,1],[227,70],[231,77],[235,78],[136,79],[186,80],[187,81],[135,82],[161,83],[193,84],[127,85],[134,86],[123,87],[203,88],[202,89],[162,1],[142,90],[171,1],[192,91],[191,1],[172,92],[194,92],[195,93],[131,94],[190,95],[130,1],[200,96],[201,97],[143,98],[141,99],[140,100],[196,101],[132,102],[189,103],[185,104],[120,1],[198,105],[137,1],[175,106],[178,107],[197,1],[164,108],[199,109],[204,110],[138,1],[139,1],[148,85],[166,111],[133,112],[170,113],[169,114],[144,115],[160,116],[159,117],[188,1],[149,118],[180,119],[181,120],[151,121],[153,122],[252,123],[152,124],[154,125],[246,1],[155,126],[67,1],[221,127],[222,1],[220,1],[223,128],[225,1],[233,49],[237,49],[213,129],[125,1],[215,1],[224,130],[168,131],[167,132],[129,133],[128,1],[229,1],[226,134],[57,1],[66,135],[63,49],[64,1],[65,1],[232,136],[234,137],[236,138],[261,139],[238,140],[256,141],[240,141],[255,142],[242,143],[243,144],[245,145],[253,146],[254,147],[212,148],[273,149],[270,150],[268,151],[269,150],[272,152],[271,152],[264,1],[265,153],[267,1],[266,1],[11,1],[12,1],[14,1],[13,1],[2,1],[15,1],[16,1],[17,1],[18,1],[19,1],[20,1],[21,1],[22,1],[3,1],[4,1],[26,1],[23,1],[24,1],[25,1],[27,1],[28,1],[29,1],[5,1],[30,1],[31,1],[32,1],[33,1],[6,1],[37,1],[34,1],[35,1],[36,1],[38,1],[7,1],[39,1],[44,1],[45,1],[40,1],[41,1],[42,1],[43,1],[8,1],[49,1],[46,1],[47,1],[48,1],[50,1],[9,1],[51,1],[52,1],[53,1],[54,1],[55,1],[1,1],[10,1],[56,1],[288,154],[289,155],[280,156],[290,157],[281,158],[285,159],[286,1],[287,160],[284,161],[278,162],[258,1],[262,163],[274,164],[257,165],[275,1]],"semanticDiagnosticsPerFile":[214,69,70,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,71,118,87,88,89,119,90,91,92,93,94,95,96,97,98,99,100,101,103,102,104,105,106,107,108,109,110,111,112,113,114,115,116,117,60,121,58,62,61,277,276,263,59,279,283,282,68,228,230,145,157,179,146,173,163,147,165,158,126,183,177,182,176,184,239,241,219,218,217,244,216,150,247,260,259,249,251,248,250,122,174,124,205,206,208,211,207,209,210,156,227,231,235,136,186,187,135,161,193,127,134,123,203,202,162,142,171,192,191,172,194,195,131,190,130,200,201,143,141,140,196,132,189,185,120,198,137,175,178,197,164,199,204,138,139,148,166,133,170,169,144,160,159,188,149,180,181,151,153,252,152,154,246,155,67,221,222,220,223,225,233,237,213,125,215,224,168,167,129,128,229,226,57,66,63,64,65,232,234,236,261,238,256,240,255,242,243,245,253,254,212,273,270,268,269,272,271,264,265,267,266,11,12,14,13,2,15,16,17,18,19,20,21,22,3,4,26,23,24,25,27,28,29,5,30,31,32,33,6,37,34,35,36,38,7,39,44,45,40,41,42,43,8,49,46,47,48,50,9,51,52,53,54,55,1,10,56,288,289,280,290,281,285,286,287,284,278,258,262,274,257,275],"affectedFilesPendingEmit":[[214,1],[69,1],[70,1],[72,1],[73,1],[74,1],[75,1],[76,1],[77,1],[78,1],[79,1],[80,1],[81,1],[82,1],[83,1],[84,1],[85,1],[86,1],[71,1],[118,1],[87,1],[88,1],[89,1],[119,1],[90,1],[91,1],[92,1],[93,1],[94,1],[95,1],[96,1],[97,1],[98,1],[99,1],[100,1],[101,1],[103,1],[102,1],[104,1],[105,1],[106,1],[107,1],[108,1],[109,1],[110,1],[111,1],[112,1],[113,1],[114,1],[115,1],[116,1],[117,1],[60,1],[121,1],[58,1],[62,1],[61,1],[277,1],[276,1],[263,1],[59,1],[279,1],[283,1],[282,1],[68,1],[228,1],[230,1],[145,1],[157,1],[179,1],[146,1],[173,1],[163,1],[147,1],[165,1],[158,1],[126,1],[183,1],[177,1],[182,1],[176,1],[184,1],[239,1],[241,1],[219,1],[218,1],[217,1],[244,1],[216,1],[150,1],[247,1],[260,1],[259,1],[249,1],[251,1],[248,1],[250,1],[122,1],[174,1],[124,1],[205,1],[206,1],[208,1],[211,1],[207,1],[209,1],[210,1],[156,1],[227,1],[231,1],[235,1],[136,1],[186,1],[187,1],[135,1],[161,1],[193,1],[127,1],[134,1],[123,1],[203,1],[202,1],[162,1],[142,1],[171,1],[192,1],[191,1],[172,1],[194,1],[195,1],[131,1],[190,1],[130,1],[200,1],[201,1],[143,1],[141,1],[140,1],[196,1],[132,1],[189,1],[185,1],[120,1],[198,1],[137,1],[175,1],[178,1],[197,1],[164,1],[199,1],[204,1],[138,1],[139,1],[148,1],[166,1],[133,1],[170,1],[169,1],[144,1],[160,1],[159,1],[188,1],[149,1],[180,1],[181,1],[151,1],[153,1],[252,1],[152,1],[154,1],[246,1],[155,1],[67,1],[221,1],[222,1],[220,1],[223,1],[225,1],[233,1],[237,1],[213,1],[125,1],[215,1],[224,1],[168,1],[167,1],[129,1],[128,1],[229,1],[226,1],[57,1],[66,1],[63,1],[64,1],[65,1],[232,1],[234,1],[236,1],[261,1],[238,1],[256,1],[240,1],[255,1],[242,1],[243,1],[245,1],[253,1],[254,1],[212,1],[273,1],[270,1],[268,1],[269,1],[272,1],[271,1],[264,1],[265,1],[267,1],[266,1],[2,1],[3,1],[4,1],[5,1],[6,1],[7,1],[8,1],[9,1],[10,1],[288,1],[289,1],[280,1],[290,1],[281,1],[285,1],[286,1],[287,1],[284,1],[278,1],[258,1],[262,1],[274,1],[257,1],[275,1]]},"version":"4.9.5"}

================================================
FILE: types/nav.ts
================================================
export interface NavItem {
  title: string
  href?: string
  disabled?: boolean
  external?: boolean
}
Download .txt
gitextract_49tax7zj/

├── .editorconfig
├── .eslintignore
├── .eslintrc.json
├── .gitignore
├── .prettierignore
├── .vscode/
│   └── settings.json
├── README.md
├── app/
│   ├── [domain]/
│   │   ├── [handle]/
│   │   │   ├── .well-known/
│   │   │   │   └── atproto-did/
│   │   │   │       └── route.ts
│   │   │   ├── opengraph-image.tsx
│   │   │   └── page.tsx
│   │   ├── community/
│   │   │   ├── loading.tsx
│   │   │   └── page.tsx
│   │   ├── create-your-own/
│   │   │   └── page.tsx
│   │   ├── layout.tsx
│   │   └── page.tsx
│   └── layout.tsx
├── components/
│   ├── avatar.tsx
│   ├── icons.tsx
│   ├── layout.tsx
│   ├── link.tsx
│   ├── load-more.tsx
│   ├── main-nav.tsx
│   ├── profile.tsx
│   ├── site-header.tsx
│   ├── stage.tsx
│   ├── tailwind-indicator.tsx
│   ├── theme-provider.tsx
│   ├── theme-toggle.tsx
│   └── ui/
│       ├── button.tsx
│       ├── dialog.tsx
│       ├── input.tsx
│       ├── label.tsx
│       └── tabs.tsx
├── config/
│   └── site.ts
├── lib/
│   ├── atproto.ts
│   ├── db.ts
│   ├── fonts.ts
│   ├── slurs.ts
│   └── utils.ts
├── middleware.ts
├── next-env.d.ts
├── next.config.mjs
├── package.json
├── postcss.config.js
├── prettier.config.js
├── prisma/
│   ├── export.ts
│   ├── schema.prisma
│   └── seed.ts
├── styles/
│   └── globals.css
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.tsbuildinfo
└── types/
    └── nav.ts
Download .txt
SYMBOL INDEX (48 symbols across 28 files)

FILE: app/[domain]/[handle]/opengraph-image.tsx
  function og (line 14) | async function og({

FILE: app/[domain]/[handle]/page.tsx
  type Props (line 7) | interface Props {
  function generateMetadata (line 11) | async function generateMetadata({ params }: Props): Promise<Metadata> {
  function HandlePage (line 32) | async function HandlePage({ params }: Props) {

FILE: app/[domain]/community/loading.tsx
  function Loading (line 3) | function Loading() {

FILE: app/[domain]/community/page.tsx
  type Props (line 12) | interface Props {
  function generateMetadata (line 16) | async function generateMetadata({ params }: Props): Promise<Metadata> {
  constant PAGE_SIZE (line 25) | const PAGE_SIZE = 100
  function CommunityPage (line 27) | async function CommunityPage({ params }: Props) {
  function ProfileListSection (line 66) | function ProfileListSection({
  function getUsers (line 78) | async function getUsers(domain: string, offset = 0) {
  function loadMoreUsers (line 122) | async function loadMoreUsers(domain: string, offset = 0) {

FILE: app/[domain]/create-your-own/page.tsx
  function CommunityPage (line 18) | function CommunityPage() {

FILE: app/[domain]/layout.tsx
  type Props (line 7) | interface Props {
  function DomainLayout (line 12) | function DomainLayout({ children, params }: Props) {

FILE: app/[domain]/page.tsx
  function generateMetadata (line 12) | function generateMetadata({ params }: { params: { domain: string } }) {
  function IndexPage (line 20) | async function IndexPage({
  constant RESERVED (line 218) | const RESERVED = [

FILE: app/layout.tsx
  type RootLayoutProps (line 25) | interface RootLayoutProps {
  function RootLayout (line 29) | function RootLayout({ children }: RootLayoutProps) {

FILE: components/avatar.tsx
  function Avatar (line 8) | function Avatar({

FILE: components/icons.tsx
  type Icon (line 9) | type Icon = LucideIcon

FILE: components/layout.tsx
  type LayoutProps (line 3) | interface LayoutProps {
  function Layout (line 7) | function Layout({ children }: LayoutProps) {

FILE: components/link.tsx
  type Props (line 7) | interface Props
  function Link (line 11) | function Link({ href, ...props }: Props) {

FILE: components/load-more.tsx
  type Props (line 8) | interface Props {
  function LoadMore (line 19) | function LoadMore({

FILE: components/main-nav.tsx
  type MainNavProps (line 10) | interface MainNavProps {
  function MainNav (line 15) | function MainNav({ title, items }: MainNavProps) {

FILE: components/profile.tsx
  type Props (line 8) | interface Props {
  function Profile (line 13) | function Profile({ profile, className }: Props) {

FILE: components/site-header.tsx
  type Props (line 14) | interface Props {
  function SiteHeader (line 19) | function SiteHeader({ children }: Props) {

FILE: components/stage.tsx
  type Props (line 3) | interface Props {
  function Stage (line 11) | function Stage({ number, title, disabled, last, children }: Props) {

FILE: components/tailwind-indicator.tsx
  function TailwindIndicator (line 1) | function TailwindIndicator() {

FILE: components/theme-provider.tsx
  function ThemeProvider (line 7) | function ThemeProvider({ children, ...props }: ThemeProviderProps) {

FILE: components/theme-toggle.tsx
  function ThemeToggle (line 9) | function ThemeToggle() {

FILE: components/ui/button.tsx
  type ButtonProps (line 36) | interface ButtonProps

FILE: components/ui/input.tsx
  type InputProps (line 5) | interface InputProps

FILE: config/site.ts
  type SiteConfig (line 1) | type SiteConfig = typeof siteConfig

FILE: lib/utils.ts
  function cn (line 5) | function cn(...inputs: ClassValue[]) {
  function getDomain (line 9) | function getDomain(host: string) {

FILE: middleware.ts
  function middleware (line 5) | function middleware(request: NextRequest) {

FILE: prisma/export.ts
  function main (line 6) | async function main() {

FILE: prisma/seed.ts
  function main (line 6) | async function main() {

FILE: types/nav.ts
  type NavItem (line 1) | interface NavItem {
Condensed preview — 53 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (147K chars).
[
  {
    "path": ".editorconfig",
    "chars": 166,
    "preview": "# editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 2\nindent_style = space\ninsert_final_n"
  },
  {
    "path": ".eslintignore",
    "chars": 43,
    "preview": "dist/*\n.cache\npublic\nnode_modules\n*.esm.js\n"
  },
  {
    "path": ".eslintrc.json",
    "chars": 612,
    "preview": "{\n  \"$schema\": \"https://json.schemastore.org/eslintrc\",\n  \"root\": true,\n  \"extends\": [\n    \"next/core-web-vitals\",\n    \""
  },
  {
    "path": ".gitignore",
    "chars": 418,
    "preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\nnode_modules\n.pnp\n"
  },
  {
    "path": ".prettierignore",
    "chars": 113,
    "preview": "cache\n.cache\npackage.json\npackage-lock.json\npublic\nCHANGELOG.md\n.yarn\ndist\nnode_modules\n.next\nbuild\n.contentlayer"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 106,
    "preview": "{\n  \"typescript.tsdk\": \"node_modules/typescript/lib\",\n  \"typescript.enablePromptUseWorkspaceTsdk\": true\n}\n"
  },
  {
    "path": "README.md",
    "chars": 3301,
    "preview": "# Bluesky Community Handles tool\n\nGet your own community handle for Bluesky!\n\nGo to https://swifties.social to join the "
  },
  {
    "path": "app/[domain]/[handle]/.well-known/atproto-did/route.ts",
    "chars": 716,
    "preview": "import { type NextRequest } from \"next/server\"\n\nimport { prisma } from \"@/lib/db\"\n\nconst corsHeaders = {\n  \"Access-Contr"
  },
  {
    "path": "app/[domain]/[handle]/opengraph-image.tsx",
    "chars": 1979,
    "preview": "/* eslint-disable @next/next/no-img-element */\n\nimport { ImageResponse } from \"next/og\"\n\nimport { agent } from \"@/lib/at"
  },
  {
    "path": "app/[domain]/[handle]/page.tsx",
    "chars": 1435,
    "preview": "import { Metadata } from \"next\"\n\nimport { agent } from \"@/lib/atproto\"\nimport { prisma } from \"@/lib/db\"\nimport { Profil"
  },
  {
    "path": "app/[domain]/community/loading.tsx",
    "chars": 235,
    "preview": "import { LoaderIcon } from \"lucide-react\"\n\nexport default function Loading() {\n  return (\n    <div className=\"flex flex-"
  },
  {
    "path": "app/[domain]/community/page.tsx",
    "chars": 3468,
    "preview": "import { type Metadata } from \"next\"\nimport { AppBskyActorDefs } from \"@atproto/api\"\n\nimport { agent } from \"@/lib/atpro"
  },
  {
    "path": "app/[domain]/create-your-own/page.tsx",
    "chars": 2684,
    "preview": "import { ArrowRight } from \"lucide-react\"\n\nimport { Button, buttonVariants } from \"@/components/ui/button\"\nimport {\n  Di"
  },
  {
    "path": "app/[domain]/layout.tsx",
    "chars": 730,
    "preview": "\nimport NextPlausible from \"next-plausible\"\nimport { siteConfig } from \"@/config/site\"\nimport { MainNav } from \"@/compon"
  },
  {
    "path": "app/[domain]/page.tsx",
    "chars": 7975,
    "preview": "import { AppBskyActorDefs } from \"@atproto/api\"\nimport { Check, X } from \"lucide-react\"\n\nimport { agent } from \"@/lib/at"
  },
  {
    "path": "app/layout.tsx",
    "chars": 1268,
    "preview": "import { type Metadata, type Viewport } from \"next\"\n\nimport { fontSans } from \"@/lib/fonts\"\nimport { cn } from \"@/lib/ut"
  },
  {
    "path": "components/avatar.tsx",
    "chars": 891,
    "preview": "/* eslint-disable @next/next/no-img-element */\n\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/u"
  },
  {
    "path": "components/icons.tsx",
    "chars": 2487,
    "preview": "import {\n  AtSign,\n  LucideProps,\n  Moon,\n  SunMedium,\n  type LucideIcon,\n} from \"lucide-react\"\n\nexport type Icon = Luci"
  },
  {
    "path": "components/layout.tsx",
    "chars": 245,
    "preview": "import { SiteHeader } from \"@/components/site-header\"\n\ninterface LayoutProps {\n  children: React.ReactNode\n}\n\nexport fun"
  },
  {
    "path": "components/link.tsx",
    "chars": 636,
    "preview": "\"use client\"\n\nimport NextLink, { type LinkProps } from \"next/link\"\n\nimport { getDomain } from \"@/lib/utils\"\n\ninterface P"
  },
  {
    "path": "components/load-more.tsx",
    "chars": 2303,
    "preview": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/components/ui/b"
  },
  {
    "path": "components/main-nav.tsx",
    "chars": 1376,
    "preview": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { NavItem } from \"@/types/nav\"\nimport { cn } from \"@/lib/utils\"\nimp"
  },
  {
    "path": "components/profile.tsx",
    "chars": 1269,
    "preview": "/* eslint-disable @next/next/no-img-element */\nimport { AppBskyActorDefs } from \"@atproto/api\"\n\nimport { cn } from \"@/li"
  },
  {
    "path": "components/site-header.tsx",
    "chars": 3128,
    "preview": "\"use client\"\n\nimport { useState } from \"react\"\nimport { Menu, X } from \"lucide-react\"\n\nimport { type NavItem } from \"@/t"
  },
  {
    "path": "components/stage.tsx",
    "chars": 770,
    "preview": "import { cn } from \"@/lib/utils\"\n\ninterface Props {\n  number: number\n  title: string\n  disabled?: boolean\n  last?: boole"
  },
  {
    "path": "components/tailwind-indicator.tsx",
    "chars": 681,
    "preview": "export function TailwindIndicator() {\n  if (process.env.NODE_ENV === \"production\") return null\n\n  return (\n    <div clas"
  },
  {
    "path": "components/theme-provider.tsx",
    "chars": 322,
    "preview": "\"use client\"\n\nimport * as React from \"react\"\nimport { ThemeProvider as NextThemesProvider } from \"next-themes\"\nimport { "
  },
  {
    "path": "components/theme-toggle.tsx",
    "chars": 658,
    "preview": "\"use client\"\n\nimport * as React from \"react\"\nimport { useTheme } from \"next-themes\"\n\nimport { Button } from \"@/component"
  },
  {
    "path": "components/ui/button.tsx",
    "chars": 1835,
    "preview": "import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class"
  },
  {
    "path": "components/ui/dialog.tsx",
    "chars": 3839,
    "preview": "\"use client\"\n\nimport * as React from \"react\"\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\"\nimport { X } from"
  },
  {
    "path": "components/ui/input.tsx",
    "chars": 824,
    "preview": "import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport interface InputProps\n  extends React.InputHTMLA"
  },
  {
    "path": "components/ui/label.tsx",
    "chars": 724,
    "preview": "\"use client\"\n\nimport * as React from \"react\"\nimport * as LabelPrimitive from \"@radix-ui/react-label\"\nimport { cva, type "
  },
  {
    "path": "components/ui/tabs.tsx",
    "chars": 1897,
    "preview": "\"use client\"\n\nimport * as React from \"react\"\nimport * as TabsPrimitive from \"@radix-ui/react-tabs\"\n\nimport { cn } from \""
  },
  {
    "path": "config/site.ts",
    "chars": 390,
    "preview": "export type SiteConfig = typeof siteConfig\n\nexport const siteConfig = {\n  mainNav: [\n    {\n      title: \"Join the commun"
  },
  {
    "path": "lib/atproto.ts",
    "chars": 1247,
    "preview": "import { BskyAgent, jsonToLex, stringifyLex } from \"@atproto/api\"\n\nBskyAgent.configure({\n  fetch: async (reqUri, reqMeth"
  },
  {
    "path": "lib/db.ts",
    "chars": 304,
    "preview": "import { PrismaClient } from \"@prisma/client\"\n\nconst globalForPrisma = global as unknown as {\n  prisma: PrismaClient | u"
  },
  {
    "path": "lib/fonts.ts",
    "chars": 257,
    "preview": "import { JetBrains_Mono as FontMono, Inter as FontSans } from \"next/font/google\"\n\nexport const fontSans = FontSans({\n  s"
  },
  {
    "path": "lib/slurs.ts",
    "chars": 4782,
    "preview": "// RIPPED STRAIGHT OUT OF ATPROTO\n// ALL CREDIT TO THEM ETC\n\n// regexes taken from: https://github.com/Blank-Cheque/Slur"
  },
  {
    "path": "lib/utils.ts",
    "chars": 340,
    "preview": "import { clsx, type ClassValue } from \"clsx\"\nimport psl from \"psl\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport func"
  },
  {
    "path": "middleware.ts",
    "chars": 1016,
    "preview": "import { NextResponse, type NextRequest } from \"next/server\"\n\nimport { getDomain } from \"./lib/utils\"\n\nexport function m"
  },
  {
    "path": "next-env.d.ts",
    "chars": 201,
    "preview": "/// <reference types=\"next\" />\n/// <reference types=\"next/image-types/global\" />\n\n// NOTE: This file should not be edite"
  },
  {
    "path": "next.config.mjs",
    "chars": 243,
    "preview": "import { withPlausibleProxy } from \"next-plausible\"\n\n/** @type {import('next').NextConfig} */\nconst nextConfig = {\n  rea"
  },
  {
    "path": "package.json",
    "chars": 2014,
    "preview": "{\n  \"name\": \"next-template\",\n  \"version\": \"0.0.2\",\n  \"private\": true,\n  \"packageManager\": \"pnpm@10.25.0\",\n  \"scripts\": {"
  },
  {
    "path": "postcss.config.js",
    "chars": 82,
    "preview": "module.exports = {\n  plugins: {\n    tailwindcss: {},\n    autoprefixer: {},\n  },\n}\n"
  },
  {
    "path": "prettier.config.js",
    "chars": 669,
    "preview": "/** @type {import('prettier').Config} */\nmodule.exports = {\n  endOfLine: \"lf\",\n  semi: false,\n  singleQuote: false,\n  ta"
  },
  {
    "path": "prisma/export.ts",
    "chars": 850,
    "preview": "import fs from \"node:fs\"\nimport { PrismaClient } from \"@prisma/client\"\n\nconst prisma = new PrismaClient()\n\nasync functio"
  },
  {
    "path": "prisma/schema.prisma",
    "chars": 675,
    "preview": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\ngenerator clien"
  },
  {
    "path": "prisma/seed.ts",
    "chars": 828,
    "preview": "import { PrismaClient } from \"@prisma/client\"\nimport { kv } from \"@vercel/kv\"\n\nconst prisma = new PrismaClient()\n\nasync "
  },
  {
    "path": "styles/globals.css",
    "chars": 1615,
    "preview": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@layer base {\n  :root {\n    --background: 0 0% 100%;\n    --f"
  },
  {
    "path": "tailwind.config.js",
    "chars": 2198,
    "preview": "const { fontFamily } = require(\"tailwindcss/defaultTheme\")\n\n/** @type {import('tailwindcss').Config} */\nmodule.exports ="
  },
  {
    "path": "tsconfig.json",
    "chars": 667,
    "preview": "{\n  \"compilerOptions\": {\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n  "
  },
  {
    "path": "tsconfig.tsbuildinfo",
    "chars": 66712,
    "preview": "{\"program\":{\"fileNames\":[\"../../node_modules/.pnpm/typescript@4.9.5/node_modules/typescript/lib/lib.es5.d.ts\",\"../../nod"
  },
  {
    "path": "types/nav.ts",
    "chars": 103,
    "preview": "export interface NavItem {\n  title: string\n  href?: string\n  disabled?: boolean\n  external?: boolean\n}\n"
  }
]

About this extraction

This page contains the full source code of the mozzius/community-handles GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 53 files (131.2 KB), approximately 53.3k tokens, and a symbol index with 48 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!