78 lines
2.9 KiB
TypeScript
78 lines
2.9 KiB
TypeScript
|
|
import { useEffect, useState } from "react"
|
||
|
|
import AdaptableCard from "@/components/shared/AdaptableCard"
|
||
|
|
import Container from "@/components/shared/Container"
|
||
|
|
import { HiTag, HiCheckCircle } from "react-icons/hi"
|
||
|
|
import { useLocalization } from "@/utils/hooks/useLocalization"
|
||
|
|
import { Helmet } from "react-helmet"
|
||
|
|
|
||
|
|
type Release = {
|
||
|
|
version: string
|
||
|
|
buildDate: string
|
||
|
|
changeLog: string[]
|
||
|
|
}
|
||
|
|
|
||
|
|
const Log = ({ version, date, children }: { version: string; date: string; children?: React.ReactNode }) => {
|
||
|
|
return (
|
||
|
|
<div className="relative pl-4 sm:pl-32 py-4 group">
|
||
|
|
<div className="flex flex-col sm:flex-row items-start mb-1 group-last:before:hidden before:absolute before:left-2 sm:before:left-0 before:h-full before:px-px before:bg-slate-200 sm:before:ml-[6.5rem] before:self-start before:-translate-x-1/2 before:translate-y-3 after:absolute after:left-2 sm:after:left-0 after:w-2 after:h-2 after:bg-indigo-600 after:border-4 after:box-content after:border-slate-50 after:rounded-full sm:after:ml-[6.5rem] after:-translate-x-1/2 after:translate-y-1.5">
|
||
|
|
<time className="sm:absolute left-0 translate-y-0.5 inline-flex items-center justify-center text-xs font-semibold uppercase w-20 h-6 mb-3 sm:mb-0 text-emerald-600 bg-emerald-100 rounded-full">
|
||
|
|
{date}
|
||
|
|
</time>
|
||
|
|
<div className="flex items-center text-xl font-bold text-gray-900">
|
||
|
|
<HiTag className="mr-2 text-indigo-500" />
|
||
|
|
v{version}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div className="text-slate-500">{children}</div>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
const Changelog = () => {
|
||
|
|
const { translate } = useLocalization()
|
||
|
|
const [releases, setReleases] = useState<Release[]>([])
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
fetch("/version.json?ts=" + Date.now())
|
||
|
|
.then((res) => res.json())
|
||
|
|
.then((data) => {
|
||
|
|
if (data?.releases) {
|
||
|
|
setReleases(data.releases)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
.catch(() => setReleases([]))
|
||
|
|
}, [])
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Container>
|
||
|
|
<Helmet
|
||
|
|
titleTemplate="%s | Sözsoft Kurs Platform"
|
||
|
|
title={translate("::App.ChangeLog")}
|
||
|
|
defaultTitle="Sözsoft Kurs Platform"
|
||
|
|
/>
|
||
|
|
<AdaptableCard>
|
||
|
|
<div className="p-2">
|
||
|
|
<div className="space-y-1">
|
||
|
|
{releases.map((rel) => (
|
||
|
|
<Log key={rel.version} version={rel.version} date={rel.buildDate}>
|
||
|
|
{rel.changeLog?.length > 0 && (
|
||
|
|
<ul className="list-none mt-2 space-y-2">
|
||
|
|
{rel.changeLog.map((item, i) => (
|
||
|
|
<li key={i} className="flex items-start">
|
||
|
|
<HiCheckCircle className="w-4 h-4 text-emerald-500 mr-2 flex-shrink-0" />
|
||
|
|
<span>{item}</span>
|
||
|
|
</li>
|
||
|
|
))}
|
||
|
|
</ul>
|
||
|
|
)}
|
||
|
|
</Log>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</AdaptableCard>
|
||
|
|
</Container>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
export default Changelog
|