Skip to content

Commit cf8d6b4

Browse files
feat(changelog): update changelog view with version details and download links
1 parent 87250b7 commit cf8d6b4

File tree

1 file changed

+99
-27
lines changed

1 file changed

+99
-27
lines changed

apps/web/src/routes/_view/changelog/index.tsx

Lines changed: 99 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import { MDXContent } from "@content-collections/mdx/react";
22
import { Icon } from "@iconify-icon/react";
33
import { createFileRoute, Link } from "@tanstack/react-router";
4+
import { Download } from "lucide-react";
45
import semver from "semver";
56

67
import { cn } from "@hypr/utils";
78

89
import { type ChangelogWithMeta, getChangelogList } from "@/changelog";
910
import { defaultMDXComponents } from "@/components/mdx";
11+
import { getDownloadLinks, groupDownloadLinks } from "@/utils/download";
1012

1113
export const Route = createFileRoute("/_view/changelog/")({
1214
component: Component,
@@ -43,17 +45,20 @@ function Component() {
4345
<div className="max-w-6xl mx-auto border-x border-neutral-100 bg-white">
4446
<div className="px-6 py-16 lg:py-24">
4547
<HeroSection />
46-
<div className="mt-16 max-w-4xl mx-auto">
47-
{changelogs.map((changelog, index) => (
48-
<ChangelogSection
49-
key={changelog.slug}
50-
changelog={changelog}
51-
isFirst={index === 0}
52-
isLast={index === changelogs.length - 1}
53-
/>
54-
))}
55-
</div>
5648
</div>
49+
<div className="mt-16">
50+
{changelogs.map((changelog, index) => (
51+
<div key={changelog.slug}>
52+
<div className="max-w-4xl mx-auto px-6">
53+
<ChangelogSection changelog={changelog} isFirst={index === 0} />
54+
</div>
55+
{index < changelogs.length - 1 && (
56+
<div className="border-b border-neutral-100 my-12" />
57+
)}
58+
</div>
59+
))}
60+
</div>
61+
<div className="px-6 pb-16 lg:pb-24"></div>
5762
</div>
5863
</main>
5964
);
@@ -75,38 +80,48 @@ function HeroSection() {
7580
function ChangelogSection({
7681
changelog,
7782
isFirst,
78-
isLast,
7983
}: {
8084
changelog: ChangelogWithMeta;
8185
isFirst: boolean;
82-
isLast: boolean;
8386
}) {
8487
const currentVersion = semver.parse(changelog.version);
8588
const isPrerelease = currentVersion && currentVersion.prerelease.length > 0;
89+
const nightlyNumber =
90+
isPrerelease && currentVersion?.prerelease[0] === "nightly"
91+
? currentVersion.prerelease[1]
92+
: null;
8693

8794
return (
88-
<section
89-
className={cn([
90-
"grid grid-cols-1 md:grid-cols-[200px_1fr] gap-6 md:gap-12",
91-
!isLast && "border-b border-neutral-100 pb-12 mb-12",
92-
])}
93-
>
94-
<div className="md:sticky md:top-24 md:self-start">
95-
<div className="flex items-center gap-2">
96-
<h2 className="text-lg font-semibold text-stone-700">
97-
{changelog.version}
98-
</h2>
95+
<section className="grid grid-cols-1 md:grid-cols-[160px_1fr] gap-6 md:gap-12">
96+
<div className="md:sticky md:top-24 md:self-start space-y-6">
97+
<div className="flex flex-col gap-1">
9998
{isFirst && (
100-
<span className="inline-flex items-center gap-1 px-1.5 py-0.5 text-xs font-medium bg-linear-to-t from-amber-200 to-amber-100 text-amber-900 rounded-full">
99+
<span className="inline-flex items-center gap-1 px-1.5 py-0.5 text-xs font-medium bg-linear-to-t from-amber-200 to-amber-100 text-amber-900 rounded-full w-fit">
101100
<Icon icon="ri:rocket-fill" className="text-xs" />
101+
Stable
102102
</span>
103103
)}
104104
{isPrerelease && (
105-
<span className="inline-flex items-center gap-1 px-1.5 py-0.5 text-xs font-medium bg-linear-to-b from-[#03BCF1] to-[#127FE5] text-white rounded-full">
106-
<Icon icon="ri:moon-fill" className="text-xs" />
107-
</span>
105+
<div className="flex items-center gap-1.5">
106+
<span className="inline-flex items-center gap-1 px-1.5 py-0.5 text-xs font-medium bg-linear-to-b from-[#03BCF1] to-[#127FE5] text-white rounded-full">
107+
<Icon icon="ri:moon-fill" className="text-xs" />
108+
Beta
109+
</span>
110+
{nightlyNumber !== null && (
111+
<span className="inline-flex items-center px-1.5 py-0.5 text-xs font-medium bg-stone-100 text-stone-600 rounded-full">
112+
#{nightlyNumber}
113+
</span>
114+
)}
115+
</div>
108116
)}
117+
<h2 className="text-4xl font-mono font-medium text-stone-700">
118+
{currentVersion
119+
? `${currentVersion.major}.${currentVersion.minor}.${currentVersion.patch}`
120+
: changelog.version}
121+
</h2>
109122
</div>
123+
124+
<DownloadLinks version={changelog.version} />
110125
</div>
111126

112127
<div>
@@ -126,3 +141,60 @@ function ChangelogSection({
126141
</section>
127142
);
128143
}
144+
145+
function DownloadLinks({ version }: { version: string }) {
146+
const links = getDownloadLinks(version);
147+
const grouped = groupDownloadLinks(links);
148+
149+
return (
150+
<div className="space-y-6">
151+
<div>
152+
<h3 className="flex items-center gap-1.5 text-xs font-medium text-stone-500 uppercase tracking-wider mb-2">
153+
<Icon icon="simple-icons:apple" className="text-sm" />
154+
macOS
155+
</h3>
156+
<div className="space-y-1.5">
157+
{grouped.macos.map((link) => (
158+
<a
159+
key={link.url}
160+
href={link.url}
161+
className={cn([
162+
"flex items-center gap-2 px-4 h-8 text-sm rounded-full transition-all",
163+
"bg-linear-to-b from-white to-stone-50 text-neutral-700",
164+
"border border-neutral-300",
165+
"hover:shadow-sm hover:scale-[102%] active:scale-[98%]",
166+
])}
167+
>
168+
<Download className="size-3.5 shrink-0" />
169+
<span className="truncate">{link.label}</span>
170+
</a>
171+
))}
172+
</div>
173+
</div>
174+
175+
<div>
176+
<h3 className="flex items-center gap-1.5 text-xs font-medium text-stone-500 uppercase tracking-wider mb-2">
177+
<Icon icon="simple-icons:linux" className="text-sm" />
178+
Linux
179+
</h3>
180+
<div className="space-y-1.5">
181+
{grouped.linux.map((link) => (
182+
<a
183+
key={link.url}
184+
href={link.url}
185+
className={cn([
186+
"flex items-center gap-2 px-4 h-8 text-sm rounded-full transition-all",
187+
"bg-linear-to-b from-white to-stone-50 text-neutral-700",
188+
"border border-neutral-300",
189+
"hover:shadow-sm hover:scale-[102%] active:scale-[98%]",
190+
])}
191+
>
192+
<Download className="size-3.5 shrink-0" />
193+
<span className="truncate">{link.label}</span>
194+
</a>
195+
))}
196+
</div>
197+
</div>
198+
</div>
199+
);
200+
}

0 commit comments

Comments
 (0)