127 lines
4.2 KiB
TypeScript
127 lines
4.2 KiB
TypeScript
"use client"
|
||
|
||
import { useState } from "react"
|
||
import { MarkdownRender } from "@/components/markdown"
|
||
import { Card, CardBody, CardHeader, CardIcon, CardTool } from "@/components/window/Card"
|
||
import { createClient } from "@/utils/supabase/client"
|
||
import { NewspaperFolding } from "@icon-park/react"
|
||
import useSWR from "swr"
|
||
import { Chip, Skeleton, Tabs, Tab } from "@heroui/react"
|
||
import { Key } from "@react-types/shared"
|
||
|
||
export default function Page() {
|
||
const [selectedKey, setSelectedKey] = useState<Key>("stable")
|
||
const showTestVersions = selectedKey === "test"
|
||
|
||
return (
|
||
<section className="flex flex-col gap-4 overflow-hidden">
|
||
<Card className="overflow-hidden">
|
||
<CardHeader>
|
||
<CardIcon>
|
||
<NewspaperFolding /> 动态
|
||
</CardIcon>
|
||
<CardTool>
|
||
<Tabs
|
||
selectedKey={selectedKey}
|
||
onSelectionChange={setSelectedKey}
|
||
size="sm"
|
||
radius="full"
|
||
classNames={{
|
||
base: "min-w-0",
|
||
tabList: "gap-0 p-0",
|
||
tab: "min-w-0 px-3",
|
||
tabContent: "text-xs",
|
||
}}
|
||
>
|
||
<Tab key="stable" title="正式版" />
|
||
<Tab key="test" title="测试版" />
|
||
</Tabs>
|
||
</CardTool>
|
||
</CardHeader>
|
||
<CardBody className="overflow-y-hidden">
|
||
<ReleaseNotes showTestVersions={showTestVersions} />
|
||
</CardBody>
|
||
</Card>
|
||
</section>
|
||
)
|
||
}
|
||
|
||
const ReleaseNotes = ({ showTestVersions }: { showTestVersions: boolean }) => {
|
||
const noticeFetcher = async () => {
|
||
const supabase = createClient()
|
||
let query = supabase
|
||
.from("ReleaseNote")
|
||
.select("version, content, created_at, stable")
|
||
|
||
if (!showTestVersions) {
|
||
query = query.eq("stable", true)
|
||
}
|
||
|
||
const { data /* , error */ } = await query
|
||
.order("created_at", { ascending: false })
|
||
.range(0, 10)
|
||
|
||
return data
|
||
}
|
||
|
||
const { data: releases /* , error */, isLoading } = useSWR(
|
||
`/api/release-notes?test=${showTestVersions}`,
|
||
noticeFetcher
|
||
)
|
||
|
||
return (
|
||
<ul
|
||
className="grid h-full grid-cols-1 gap-2 overflow-y-auto rounded-lg grid-flow-dense lg:grid-cols-2 xl:grid-cols-3 pb-9 hide-scrollbar"
|
||
>
|
||
{isLoading ? (
|
||
<>
|
||
<li><Skeleton className="h-32 rounded-lg"></Skeleton></li>
|
||
<li><Skeleton className="h-32 rounded-lg"></Skeleton></li>
|
||
<li><Skeleton className="h-32 rounded-lg"></Skeleton></li>
|
||
</>
|
||
) : (
|
||
releases?.map((release) => {
|
||
const isStable = release.stable === true
|
||
return (
|
||
<li key={release.version}>
|
||
{/* <Link href={`/releases/${release.version}`} className="w-full"> */}
|
||
<Card
|
||
className="w-full h-full pt-3 transition bg-white/60 text-zinc-900 dark:bg-white/5 dark:text-white"
|
||
>
|
||
<CardHeader>
|
||
<div className="flex items-center justify-between w-full gap-2">
|
||
<h3 className="text-2xl font-semibold">CS工具箱 {release.version}</h3>
|
||
<Chip
|
||
size="sm"
|
||
variant="bordered"
|
||
className={
|
||
isStable
|
||
? "border-blue-400 text-blue-600 dark:border-blue-500 dark:text-blue-400"
|
||
: "border-orange-400 text-orange-600 dark:border-orange-500 dark:text-orange-400"
|
||
}
|
||
>
|
||
{isStable ? "正式版" : "测试版"}
|
||
</Chip>
|
||
</div>
|
||
<span className="flex items-center gap-3">
|
||
<Chip size="sm" className="bg-zinc-200 dark:bg-white/10">
|
||
发布时间:
|
||
{release.created_at ? new Date(release.created_at as string).toLocaleString() : "未知时间"}
|
||
</Chip>
|
||
</span>
|
||
</CardHeader>
|
||
<CardBody className="gap-3">
|
||
<div className="">
|
||
<MarkdownRender>{release.content || "无内容"}</MarkdownRender>
|
||
</div>
|
||
</CardBody>
|
||
</Card>
|
||
{/* </Link> */}
|
||
</li>
|
||
)
|
||
})
|
||
)}
|
||
</ul>
|
||
)
|
||
}
|