๐Ÿ“ฆ hyoban / kodoku

๐Ÿ“„ page.tsx ยท 93 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93import Image from "next/image"
import { Suspense } from "react"

import Link from "~/components/link"
import Loading from "~/components/loading"
import { NewFeedDialog } from "~/components/new-feed"
import { Avatar, AvatarFallback, AvatarImage } from "~/components/ui/avatar"
import { Separator } from "~/components/ui/separator"
import { env } from "~/env"
import { getFeedInfoList } from "~/lib/unsafe"
import { getPlatformIcon } from "~/lib/utils"

export const revalidate = 3600

function IconLink({ link }: { link: string }) {
  const icon = getPlatformIcon(link)
  if (!icon) return null

  return (
    <Link href={link} className="flex items-center text-sm">
      <div className={icon}></div>
    </Link>
  )
}

async function FeedInfoList() {
  const feedInfoList = await getFeedInfoList()

  return (
    <>
      <NewFeedDialog
        existingFeedUrls={feedInfoList
          .map((feedInfo) => feedInfo.feedUrl)
          .filter(Boolean)}
      />
      {feedInfoList
        .sort((a, b) =>
          env.NODE_ENV === "development"
            ? a.title.localeCompare(b.title)
            : Math.random() - 0.5,
        )
        .map((feedInfo) => (
          <div
            key={feedInfo.id}
            className="group w-full mx-auto my-4 flex items-center rounded-md px-4 py-3 hover:bg-accent"
          >
            <Avatar>
              <AvatarImage asChild src={feedInfo.avatar ?? ""}>
                <Image
                  src={feedInfo.avatar ?? ""}
                  className="size-12 shrink-0 grow-0 rounded-full bg-white object-cover"
                  alt="avatar"
                  width={48}
                  height={48}
                />
              </AvatarImage>
              <AvatarFallback>
                {feedInfo.title.slice(0, 2).toUpperCase()}
              </AvatarFallback>
            </Avatar>
            <div className="ml-4 flex w-full flex-col self-stretch">
              <div className="flex grow flex-col sm:flex-row sm:items-center sm:justify-between">
                {feedInfo.url ? (
                  <Link href={feedInfo.url} className="flex items-center">
                    <h3 className="text-lg font-semibold">{feedInfo.title}</h3>
                  </Link>
                ) : (
                  <h3 className="text-lg font-semibold">{feedInfo.title}</h3>
                )}
                <span className="my-2 flex gap-3">
                  {feedInfo.socials.filter(Boolean).map((link) => (
                    <IconLink key={link} link={link} />
                  ))}
                </span>
              </div>
              <Separator className="group-hover:bg-accent" />
            </div>
          </div>
        ))}
    </>
  )
}

export default function Page() {
  return (
    <div className="m-5 sm:m-10 self-center md:min-w-[30rem] flex flex-col">
      <Suspense fallback={<Loading />}>
        <FeedInfoList />
      </Suspense>
    </div>
  )
}