[feat] better installer + changelog test version switch + better video config view
This commit is contained in:
@@ -1,13 +1,18 @@
|
||||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
import { MarkdownRender } from "@/components/markdown"
|
||||
import { Card, CardBody, CardHeader, CardIcon } from "@/components/window/Card"
|
||||
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 } from "@heroui/react"
|
||||
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">
|
||||
@@ -15,68 +20,107 @@ export default function Page() {
|
||||
<CardIcon>
|
||||
<NewspaperFolding /> 动态
|
||||
</CardIcon>
|
||||
{/* <CardTool>
|
||||
<ToolButton onClick={async () => {}}>读取</ToolButton>
|
||||
</CardTool> */}
|
||||
<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>
|
||||
</CardHeader>
|
||||
<CardBody className="overflow-y-hidden">
|
||||
<ReleaseNotes />
|
||||
<ReleaseNotes showTestVersions={showTestVersions} />
|
||||
</CardBody>
|
||||
</Card>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
const ReleaseNotes = () => {
|
||||
const ReleaseNotes = ({ showTestVersions }: { showTestVersions: boolean }) => {
|
||||
const noticeFetcher = async () => {
|
||||
const supabase = createClient()
|
||||
const { data /* , error */ } = await supabase
|
||||
let query = supabase
|
||||
.from("ReleaseNote")
|
||||
.select("version, content, created_at")
|
||||
.eq("stable", true)
|
||||
.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", noticeFetcher)
|
||||
|
||||
if (isLoading) return (
|
||||
<div 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">
|
||||
<Skeleton className="h-32 rounded-lg"></Skeleton>
|
||||
<Skeleton className="h-32 rounded-lg"></Skeleton>
|
||||
<Skeleton className="h-32 rounded-lg"></Skeleton>
|
||||
</div>
|
||||
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">
|
||||
{releases?.map((release, index) => (
|
||||
<li key={index}>
|
||||
{/* <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>
|
||||
<h3 className="w-full text-2xl font-semibold">CS工具箱 {release.version}</h3>
|
||||
<span className="flex items-center gap-3">
|
||||
{/* <Chip size="sm" className="bg-zinc-200">
|
||||
版本:{release?.version}
|
||||
</Chip> */}
|
||||
<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
|
||||
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>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,37 +1,53 @@
|
||||
"use client"
|
||||
import { useAppStore } from "@/store/app"
|
||||
import { Switch } from "@heroui/react"
|
||||
import { UpdateChecker } from "@/components/cstb/UpdateChecker"
|
||||
|
||||
export default function Page() {
|
||||
const app = useAppStore()
|
||||
|
||||
// 从环境变量或配置中获取更新服务器地址
|
||||
// 这里可以改为从 store 或配置文件中读取
|
||||
const customEndpoint = process.env.NEXT_PUBLIC_UPDATE_ENDPOINT || ""
|
||||
const githubRepo = process.env.NEXT_PUBLIC_GITHUB_REPO || ""
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-start gap-3 pt-2 pb-1">
|
||||
<p>版本号:{app.state.version}</p>
|
||||
<p>是否有更新:{app.state.hasUpdate ? "有" : "无"}</p>
|
||||
<p>是否使用镜像源:{app.state.useMirror ? "是" : "否"}</p>
|
||||
<Switch
|
||||
isSelected={app.state.autoStart}
|
||||
size="sm"
|
||||
onChange={(e) => app.setAutoStart(e.target.checked)}
|
||||
>
|
||||
开机自启动 {app.state.autoStart ? "开" : "关"}
|
||||
</Switch>
|
||||
<Switch
|
||||
isSelected={app.state.startHidden}
|
||||
size="sm"
|
||||
onChange={(e) => app.setStartHidden(e.target.checked)}
|
||||
>
|
||||
静默启动 {app.state.startHidden ? "开" : "关"}
|
||||
</Switch>
|
||||
{/* hiddenOnClose */}
|
||||
<Switch
|
||||
isSelected={app.state.hiddenOnClose}
|
||||
size="sm"
|
||||
onChange={(e) => app.setHiddenOnClose(e.target.checked)}
|
||||
>
|
||||
关闭时最小化到托盘 {app.state.hiddenOnClose ? "开" : "关"}
|
||||
</Switch>
|
||||
<div className="flex flex-col items-start gap-4 pt-2 pb-1">
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm">版本号:{app.state.version}</p>
|
||||
<p className="text-sm">是否有更新:{app.state.hasUpdate ? "有" : "无"}</p>
|
||||
<p className="text-sm">是否使用镜像源:{app.state.useMirror ? "是" : "否"}</p>
|
||||
</div>
|
||||
|
||||
<div className="w-full border-t border-zinc-200 dark:border-zinc-800 pt-4">
|
||||
<h3 className="text-sm font-semibold mb-3">更新检查</h3>
|
||||
<UpdateChecker customEndpoint={customEndpoint} githubRepo={githubRepo} />
|
||||
</div>
|
||||
|
||||
<div className="w-full border-t border-zinc-200 dark:border-zinc-800 pt-4 space-y-3">
|
||||
<h3 className="text-sm font-semibold mb-3">启动设置</h3>
|
||||
<Switch
|
||||
isSelected={app.state.autoStart}
|
||||
size="sm"
|
||||
onChange={(e) => app.setAutoStart(e.target.checked)}
|
||||
>
|
||||
开机自启动 {app.state.autoStart ? "开" : "关"}
|
||||
</Switch>
|
||||
<Switch
|
||||
isSelected={app.state.startHidden}
|
||||
size="sm"
|
||||
onChange={(e) => app.setStartHidden(e.target.checked)}
|
||||
>
|
||||
静默启动 {app.state.startHidden ? "开" : "关"}
|
||||
</Switch>
|
||||
<Switch
|
||||
isSelected={app.state.hiddenOnClose}
|
||||
size="sm"
|
||||
onChange={(e) => app.setHiddenOnClose(e.target.checked)}
|
||||
>
|
||||
关闭时最小化到托盘 {app.state.hiddenOnClose ? "开" : "关"}
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user