Skip to content

Commit 32ddf36

Browse files
committed
docs: add version history page with styling and functionality to display release information and download links
1 parent 4a79ecd commit 32ddf36

6 files changed

Lines changed: 439 additions & 9 deletions

File tree

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
.root {
2+
max-width: 920px;
3+
margin: 0 auto;
4+
padding: 56px 24px 96px;
5+
}
6+
7+
.header {
8+
margin-bottom: 32px;
9+
}
10+
11+
.eyebrow {
12+
display: inline-flex;
13+
align-items: center;
14+
gap: 6px;
15+
font-size: 12px;
16+
font-weight: 600;
17+
letter-spacing: 0.08em;
18+
text-transform: uppercase;
19+
color: var(--accent);
20+
margin-bottom: 12px;
21+
}
22+
23+
.heading {
24+
font-size: clamp(28px, 4vw, 40px);
25+
font-weight: 600;
26+
letter-spacing: -0.02em;
27+
margin: 0 0 12px;
28+
color: var(--text);
29+
}
30+
31+
.subhead {
32+
font-size: 16px;
33+
color: var(--text-secondary);
34+
margin: 0;
35+
line-height: 1.5;
36+
max-width: 640px;
37+
}
38+
39+
.list {
40+
display: flex;
41+
flex-direction: column;
42+
gap: 12px;
43+
margin: 32px 0 0;
44+
padding: 0;
45+
list-style: none;
46+
}
47+
48+
.item {
49+
display: grid;
50+
grid-template-columns: minmax(0, 1fr) auto;
51+
align-items: center;
52+
gap: 16px;
53+
padding: 18px 20px;
54+
background: var(--bg-elevated);
55+
border: 1px solid var(--border);
56+
border-radius: 12px;
57+
transition:
58+
border-color 150ms ease,
59+
transform 150ms ease;
60+
}
61+
62+
.item:hover {
63+
border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
64+
}
65+
66+
.itemLatest {
67+
border-color: color-mix(in srgb, var(--accent) 50%, var(--border));
68+
background: linear-gradient(
69+
180deg,
70+
color-mix(in srgb, var(--accent) 6%, var(--bg-elevated)) 0%,
71+
var(--bg-elevated) 100%
72+
);
73+
}
74+
75+
.meta {
76+
min-width: 0;
77+
}
78+
79+
.versionRow {
80+
display: flex;
81+
align-items: baseline;
82+
flex-wrap: wrap;
83+
gap: 10px;
84+
margin-bottom: 6px;
85+
}
86+
87+
.version {
88+
font-size: 20px;
89+
font-weight: 600;
90+
letter-spacing: -0.01em;
91+
color: var(--text);
92+
}
93+
94+
.latestBadge {
95+
display: inline-flex;
96+
align-items: center;
97+
font-size: 11px;
98+
font-weight: 600;
99+
letter-spacing: 0.06em;
100+
text-transform: uppercase;
101+
padding: 3px 8px;
102+
border-radius: 999px;
103+
background: var(--accent-dim);
104+
color: var(--accent);
105+
}
106+
107+
.detailRow {
108+
display: flex;
109+
align-items: center;
110+
flex-wrap: wrap;
111+
gap: 14px;
112+
font-size: 13px;
113+
color: var(--text-secondary);
114+
}
115+
116+
.detail {
117+
display: inline-flex;
118+
align-items: center;
119+
gap: 6px;
120+
}
121+
122+
.commitLink {
123+
font-family:
124+
ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono",
125+
monospace;
126+
font-size: 12px;
127+
color: var(--text-tertiary);
128+
transition: color 150ms ease;
129+
}
130+
131+
.commitLink:hover {
132+
color: var(--text-secondary);
133+
}
134+
135+
.downloadBtn {
136+
display: inline-flex;
137+
align-items: center;
138+
gap: 8px;
139+
padding: 10px 16px;
140+
border-radius: 10px;
141+
background: var(--surface);
142+
color: var(--text);
143+
font-size: 14px;
144+
font-weight: 500;
145+
transition:
146+
background 150ms ease,
147+
transform 150ms ease;
148+
white-space: nowrap;
149+
}
150+
151+
.downloadBtn:hover {
152+
background: var(--surface-hover);
153+
}
154+
155+
.downloadBtnPrimary {
156+
background: var(--accent);
157+
color: white;
158+
}
159+
160+
.downloadBtnPrimary:hover {
161+
background: var(--accent-hover);
162+
}
163+
164+
.empty {
165+
padding: 48px 24px;
166+
text-align: center;
167+
color: var(--text-secondary);
168+
background: var(--bg-elevated);
169+
border: 1px dashed var(--border);
170+
border-radius: 12px;
171+
}
172+
173+
@media (max-width: 560px) {
174+
.item {
175+
grid-template-columns: minmax(0, 1fr);
176+
}
177+
.downloadBtn {
178+
justify-content: center;
179+
}
180+
}

website/app/history/page.tsx

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import type { Metadata } from 'next';
2+
import { TopNav } from '@/components/TopNav';
3+
import { Footer } from '@/components/Footer';
4+
import { LucideIcon } from '@/components/ui/LucideIcon';
5+
import { GITHUB_URL } from '@/lib/version';
6+
import {
7+
loadAppcastItems,
8+
formatBytes,
9+
formatPubDate,
10+
type AppcastItem,
11+
} from '@/lib/appcast';
12+
import styles from './history.module.css';
13+
14+
export const metadata: Metadata = {
15+
title: 'Version History · Dao Browser',
16+
description:
17+
'Every shipped release of Dao Browser, with direct download links for the macOS Apple Silicon build.',
18+
};
19+
20+
// Resolve at request time so a redeployed appcast.xml is picked up
21+
// without rebuilding the page.
22+
export const dynamic = 'force-dynamic';
23+
24+
export default async function HistoryPage() {
25+
const items = await loadAppcastItems();
26+
return (
27+
<>
28+
<TopNav />
29+
<main className={styles.root}>
30+
<header className={styles.header}>
31+
<div className={styles.eyebrow}>
32+
<LucideIcon name="package" size={14} aria-hidden />
33+
Version history
34+
</div>
35+
<h1 className={styles.heading}>All releases</h1>
36+
<p className={styles.subhead}>
37+
Every Dao Browser build we&apos;ve shipped, newest first. Each link
38+
points at the signed .dmg on our release CDN.
39+
</p>
40+
</header>
41+
42+
{items.length === 0 ? (
43+
<div className={styles.empty}>
44+
No releases found in appcast.xml.
45+
</div>
46+
) : (
47+
<ol className={styles.list}>
48+
{items.map((item, idx) => (
49+
<ReleaseRow key={item.shortVersion} item={item} isLatest={idx === 0} />
50+
))}
51+
</ol>
52+
)}
53+
</main>
54+
<Footer />
55+
</>
56+
);
57+
}
58+
59+
function ReleaseRow({ item, isLatest }: { item: AppcastItem; isLatest: boolean }) {
60+
const fileName = item.downloadUrl.split('/').pop() ?? 'download.dmg';
61+
const commitShort = item.gitCommit ? item.gitCommit.slice(0, 7) : null;
62+
return (
63+
<li className={`${styles.item} ${isLatest ? styles.itemLatest : ''}`}>
64+
<div className={styles.meta}>
65+
<div className={styles.versionRow}>
66+
<span className={styles.version}>v{item.shortVersion}</span>
67+
{isLatest && <span className={styles.latestBadge}>Latest</span>}
68+
</div>
69+
<div className={styles.detailRow}>
70+
{item.pubDate && (
71+
<span className={styles.detail}>
72+
<LucideIcon name="calendar" size={14} aria-hidden />
73+
{formatPubDate(item.pubDate)}
74+
</span>
75+
)}
76+
<span className={styles.detail}>
77+
<LucideIcon name="hard-drive" size={14} aria-hidden />
78+
{formatBytes(item.sizeBytes)}
79+
</span>
80+
{item.minimumSystemVersion && (
81+
<span className={styles.detail}>
82+
<LucideIcon name="apple" size={14} aria-hidden />
83+
macOS {item.minimumSystemVersion}+
84+
</span>
85+
)}
86+
{commitShort && (
87+
<a
88+
className={styles.commitLink}
89+
href={`${GITHUB_URL}/commit/${item.gitCommit}`}
90+
target="_blank"
91+
rel="noopener noreferrer"
92+
title={item.gitCommit ?? undefined}
93+
>
94+
{commitShort}
95+
</a>
96+
)}
97+
</div>
98+
</div>
99+
<a
100+
href={item.downloadUrl}
101+
className={`${styles.downloadBtn} ${isLatest ? styles.downloadBtnPrimary : ''}`}
102+
download={fileName}
103+
>
104+
<LucideIcon name="download" size={16} aria-hidden />
105+
Download
106+
</a>
107+
</li>
108+
);
109+
}

website/components/Footer.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { GITHUB_URL, DOWNLOAD_URL } from '@/lib/version';
22
import styles from './Footer.module.css';
33

44
export function Footer() {
5-
const releasesUrl = `${GITHUB_URL}/releases`;
65
return (
76
<footer className={styles.footer}>
87
<div className={styles.inner}>
@@ -37,13 +36,8 @@ export function Footer() {
3736
</a>
3837
</li>
3938
<li>
40-
<a
41-
className={styles.link}
42-
href={releasesUrl}
43-
target="_blank"
44-
rel="noopener noreferrer"
45-
>
46-
Releases
39+
<a className={styles.link} href="/history">
40+
Version history
4741
</a>
4842
</li>
4943
</ul>

website/components/TopNav.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ export function TopNav() {
4949
>
5050
<span className={styles.linkText}>AI Agent</span>
5151
</Link>
52+
<Link
53+
href="/history"
54+
className={styles.link}
55+
onClick={() => trackEvent('nav_link_click', { target: 'history' })}
56+
>
57+
<span className={styles.linkText}>Versions</span>
58+
</Link>
5259
<a
5360
href={GITHUB_URL}
5461
target="_blank"

website/components/ui/LucideIcon.tsx

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@ export type IconName =
4747
| 'shield-check'
4848
| 'loader-circle'
4949
| 'circle-check'
50-
| 'circle-alert';
50+
| 'circle-alert'
51+
| 'package'
52+
| 'calendar'
53+
| 'hard-drive'
54+
| 'apple';
5155

5256
const ICON_PATHS: Record<IconName, ReactNode> = {
5357
'panel-left': (
@@ -313,6 +317,36 @@ const ICON_PATHS: Record<IconName, ReactNode> = {
313317
<line x1="12" x2="12.01" y1="16" y2="16" />
314318
</>
315319
),
320+
package: (
321+
<>
322+
<path d="M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z" />
323+
<path d="M12 22V12" />
324+
<polyline points="3.29 7 12 12 20.71 7" />
325+
<path d="m7.5 4.27 9 5.15" />
326+
</>
327+
),
328+
calendar: (
329+
<>
330+
<path d="M8 2v4" />
331+
<path d="M16 2v4" />
332+
<rect width="18" height="18" x="3" y="4" rx="2" />
333+
<path d="M3 10h18" />
334+
</>
335+
),
336+
'hard-drive': (
337+
<>
338+
<path d="M10 16h.01" />
339+
<path d="M2.212 11.577a2 2 0 0 0-.212.896V18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-5.527a2 2 0 0 0-.212-.896L18.55 5.11A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" />
340+
<path d="M21.946 12.013H2.054" />
341+
<path d="M6 16h.01" />
342+
</>
343+
),
344+
apple: (
345+
<>
346+
<path d="M12 6.528V3a1 1 0 0 1 1-1h0" />
347+
<path d="M18.237 21A15 15 0 0 0 22 11a6 6 0 0 0-10-4.472A6 6 0 0 0 2 11a15.1 15.1 0 0 0 3.763 10 3 3 0 0 0 3.648.648 5.5 5.5 0 0 1 5.178 0A3 3 0 0 0 18.237 21" />
348+
</>
349+
),
316350
};
317351

318352
export interface LucideIconProps {

0 commit comments

Comments
 (0)