2025-03-27 21:13:59 +08:00
|
|
|
|
"use client"
|
|
|
|
|
|
|
2025-11-05 11:19:43 +08:00
|
|
|
|
import { useState } from "react"
|
2025-03-27 21:13:59 +08:00
|
|
|
|
import { MarkdownRender } from "@/components/markdown"
|
2025-11-05 11:19:43 +08:00
|
|
|
|
import { Card, CardBody, CardHeader, CardIcon, CardTool } from "@/components/window/Card"
|
2025-03-27 21:13:59 +08:00
|
|
|
|
import { createClient } from "@/utils/supabase/client"
|
|
|
|
|
|
import { NewspaperFolding } from "@icon-park/react"
|
|
|
|
|
|
import useSWR from "swr"
|
2025-11-05 11:19:43 +08:00
|
|
|
|
import { Chip, Skeleton, Tabs, Tab } from "@heroui/react"
|
|
|
|
|
|
import { Key } from "@react-types/shared"
|
2025-03-27 21:13:59 +08:00
|
|
|
|
|
|
|
|
|
|
export default function Page() {
|
2025-11-05 11:19:43 +08:00
|
|
|
|
const [selectedKey, setSelectedKey] = useState<Key>("stable")
|
|
|
|
|
|
const showTestVersions = selectedKey === "test"
|
|
|
|
|
|
|
2025-03-27 21:13:59 +08:00
|
|
|
|
return (
|
|
|
|
|
|
<section className="flex flex-col gap-4 overflow-hidden">
|
|
|
|
|
|
<Card className="overflow-hidden">
|
|
|
|
|
|
<CardHeader>
|
|
|
|
|
|
<CardIcon>
|
|
|
|
|
|
<NewspaperFolding /> 动态
|
|
|
|
|
|
</CardIcon>
|
2025-11-05 11:19:43 +08:00
|
|
|
|
<CardTool>
|
|
|
|
|
|
<Tabs
|
|
|
|
|
|
selectedKey={selectedKey}
|
|
|
|
|
|
onSelectionChange={setSelectedKey}
|
|
|
|
|
|
size="sm"
|
|
|
|
|
|
radius="full"
|
|
|
|
|
|
classNames={{
|
|
|
|
|
|
base: "min-w-0",
|
|
|
|
|
|
tabList: "gap-1",
|
|
|
|
|
|
tab: "min-w-0 px-3",
|
|
|
|
|
|
tabContent: "text-xs",
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Tab key="stable" title="正式版" />
|
|
|
|
|
|
<Tab key="test" title="测试版" />
|
|
|
|
|
|
</Tabs>
|
|
|
|
|
|
</CardTool>
|
2025-03-27 21:13:59 +08:00
|
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardBody className="overflow-y-hidden">
|
2025-11-05 11:19:43 +08:00
|
|
|
|
<ReleaseNotes showTestVersions={showTestVersions} />
|
2025-03-27 21:13:59 +08:00
|
|
|
|
</CardBody>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
</section>
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 11:19:43 +08:00
|
|
|
|
const ReleaseNotes = ({ showTestVersions }: { showTestVersions: boolean }) => {
|
2025-03-27 21:13:59 +08:00
|
|
|
|
const noticeFetcher = async () => {
|
|
|
|
|
|
const supabase = createClient()
|
2025-11-05 11:19:43 +08:00
|
|
|
|
let query = supabase
|
2025-03-27 21:13:59 +08:00
|
|
|
|
.from("ReleaseNote")
|
2025-11-05 11:19:43 +08:00
|
|
|
|
.select("version, content, created_at, stable")
|
|
|
|
|
|
|
|
|
|
|
|
if (!showTestVersions) {
|
|
|
|
|
|
query = query.eq("stable", true)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const { data /* , error */ } = await query
|
2025-03-27 21:13:59 +08:00
|
|
|
|
.order("created_at", { ascending: false })
|
|
|
|
|
|
.range(0, 10)
|
|
|
|
|
|
|
|
|
|
|
|
return data
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 11:19:43 +08:00
|
|
|
|
const { data: releases /* , error */, isLoading } = useSWR(
|
|
|
|
|
|
`/api/release-notes?test=${showTestVersions}`,
|
|
|
|
|
|
noticeFetcher
|
2025-03-27 21:13:59 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
2025-11-05 11:19:43 +08:00
|
|
|
|
<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>
|
|
|
|
|
|
)
|
|
|
|
|
|
})
|
|
|
|
|
|
)}
|
2025-03-27 21:13:59 +08:00
|
|
|
|
</ul>
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|