1+ ---
2+ import { DownloadIcon } from " ../base/icons/DownloadIcon" ;
3+ import { CheckIcon } from " ../base/icons/CheckIcon" ;
4+ import { PlatformType } from " ../base/types/platform" ;
5+
6+ interface Props {
7+ repoUrl: string ;
8+ }
9+
10+ const { repoUrl } = Astro .props ;
11+
12+ // Extract owner and repo from the URL
13+ const urlParts = repoUrl .split (' /' );
14+ const owner = urlParts [urlParts .length - 2 ];
15+ const repo = urlParts [urlParts .length - 1 ];
16+
17+ // Fetch releases from GitHub API
18+ const response = await fetch (
19+ ` https://api.github.com/repos/${owner }/${repo }/releases?per_page=10 `
20+ );
21+ const releases = await response .json ();
22+
23+ // Filter only stable releases (not pre-releases) and get the latest one
24+ const stableReleases = releases .filter ((release : any ) => ! release .prerelease );
25+ const latestRelease = stableReleases [0 ]; // Get only the latest release
26+
27+ interface Asset {
28+ name: string ;
29+ browser_download_url: string ;
30+ size: number ;
31+ }
32+
33+ function getAssetDescription(assetName : string ): string {
34+ // Mapping based on provided examples
35+ if (/ \. deb$ / .test (assetName ) && / x86_64-unknown-linux-gnu/ .test (assetName )) {
36+ return " Debian / Ubuntu (x64)" ;
37+ }
38+ if (/ \. rpm$ / .test (assetName ) && / x86_64-unknown-linux-gnu/ .test (assetName )) {
39+ return " Red Hat / Fedora (x64)" ;
40+ }
41+ if (/ \. pkg$ / .test (assetName ) && / x86_64-unknown-freebsd/ .test (assetName )) {
42+ return " FreeBSD (x64, pkg)" ;
43+ }
44+ if (/ \. tar\. gz$ / .test (assetName ) && / aarch64-unknown-linux-gnu/ .test (assetName )) {
45+ return " Linux (ARM64, tar.gz)" ;
46+ }
47+ if (/ \. tar\. gz$ / .test (assetName ) && / x86_64-unknown-freebsd/ .test (assetName )) {
48+ return " FreeBSD (x64, tar.gz)" ;
49+ }
50+ if (/ \. tar\. gz$ / .test (assetName ) && / x86_64-unknown-linux-gnu/ .test (assetName )) {
51+ return " Linux (x64, tar.gz)" ;
52+ }
53+ return " " ;
54+ }
55+
56+ function getPlatformType(assetName : string ): PlatformType {
57+ if (assetName .includes (' windows' )) return PlatformType .WINDOWS ;
58+ if (assetName .includes (' linux' ) && assetName .includes (' .deb' )) return PlatformType .DEBIAN ;
59+ if (assetName .includes (' macos' ) && (assetName .includes (' aarch64' ) || assetName .includes (' arm64' ))) return PlatformType .MACOSARM ;
60+ if (assetName .includes (' macos' ) && (assetName .includes (' x86_64' ) || assetName .includes (' amd64' ))) return PlatformType .MACOSINTEL ;
61+ return PlatformType .DEBIAN ; // Default to Debian if unknown
62+ }
63+ ---
64+
65+ <div class =" github-releases" >
66+ { latestRelease && (
67+ <div class = " release-container" >
68+ <div class = " release-header" >
69+ <div class = " release-version-info" >
70+ Latest stable release: { latestRelease .tag_name .replace (/ ^ v/ , " " )} | View changelog →
71+ <a href = { latestRelease .html_url } target = " _blank" rel = " noopener noreferrer" >
72+ { new Date (latestRelease .published_at ).toLocaleDateString ()}
73+ </a >
74+ </div >
75+ </div >
76+ { latestRelease .assets && latestRelease .assets .length > 0 && (
77+ <div class = " assets-container" >
78+ <ul class = " assets-list" >
79+ { (() => {
80+ const assets = latestRelease .assets ;
81+ const tarGzIndex = assets .findIndex ((a : any ) => a .name .includes (' .tar.gz' ));
82+ return assets .map ((asset : any , idx : number ) => [
83+ (idx === tarGzIndex && tarGzIndex !== 0 ) ? (
84+ <li class = " asset-separator" >
85+ <div class = " download-separator" >
86+ <hr />
87+ <p >compressed archives</p >
88+ <hr />
89+ </div >
90+ </li >
91+ ) : null ,
92+ <li class = " asset-item" >
93+ <a
94+ href = { asset .browser_download_url }
95+ target = " _blank"
96+ rel = " noopener noreferrer"
97+ class = " download-button-wrapper"
98+ title = { ` Size: ${(asset .size / 1024 / 1024 ).toFixed (2 )} MB ` }
99+ >
100+ <div class = " download-text-wrapper" >
101+ <span class = " download-filename" >Download now</span >
102+ { getAssetDescription (asset .name ) && <p >{ getAssetDescription (asset .name )} </p >}
103+ </div >
104+ <DownloadIcon />
105+ </a >
106+ </li >
107+ ]).flat ();
108+ })()}
109+ </ul >
110+ <div class = " release-note" >
111+ For pre-release archives, visit the
112+ <a href = { ` https://github.com/${owner }/${repo }/releases ` } target = " _blank" rel = " noopener noreferrer" >GitHub Releases page</a >
113+ to access all assets, including source code.
114+ </div >
115+ </div >
116+ )}
117+ </div >
118+ )}
119+ </div >
120+
121+ <style lang =" scss" >
122+ .github-releases {
123+ padding-top: 1rem;
124+ background: var(--theme-card-bg);
125+ border-radius: 8px;
126+ }
127+
128+ h3 {
129+ margin: 0 0 1rem 0;
130+ color: var(--theme-text);
131+ font-size: 1.2rem;
132+ text-align: center;
133+ }
134+
135+
136+ .release-header {
137+ margin-bottom: 0.5rem;
138+ }
139+
140+ .release-version-info {
141+ @include typography(pricebox-list);
142+ margin-bottom: 20px;
143+ line-height: 1.2;
144+ font-size: 16px;
145+
146+ a {
147+ text-decoration: underline;
148+ color: inherit;
149+ white-space: nowrap;
150+ transition: color 0.2s;
151+ }
152+ a:hover {
153+ color: #0c8ce0;
154+ }
155+ }
156+
157+ .assets-container {
158+ margin-top: 0.5rem;
159+ padding-left: 0;
160+ }
161+
162+ .assets-list {
163+ list-style: none;
164+ padding: 0;
165+ margin: 0;
166+ display: flex;
167+ flex-direction: column;
168+ gap: 0.5rem;
169+ }
170+
171+ .asset-item {
172+ margin: 0;
173+ padding: 0;
174+ }
175+
176+ .download-button-wrapper {
177+ display: flex;
178+ height: 64px;
179+ padding: 0px 20px;
180+ justify-content: space-between;
181+ align-items: center;
182+ align-self: stretch;
183+ border: 1px solid var(--text-body-primary);
184+ text-decoration: none;
185+ color: inherit;
186+ cursor: pointer;
187+ transition: all 0.2s ease;
188+
189+ // Default state for SVG
190+ svg {
191+ path {
192+ stroke: currentColor;
193+ transition: stroke 0.2s ease;
194+ }
195+ }
196+
197+ &:hover {
198+ background-color: var(--surface-frame-bg);
199+ border-color: #0c8ce0;
200+ color: #0c8ce0; // Set color on the wrapper itself
201+
202+ .download-text-wrapper {
203+ .download-filename {
204+ color: #0c8ce0;
205+ }
206+ p {
207+ color: var(--theme-text);
208+ }
209+ }
210+
211+ svg {
212+ path {
213+ stroke: currentColor; // Use currentColor to inherit from parent
214+ }
215+ }
216+ }
217+ }
218+
219+ .download-text-wrapper {
220+ display: flex;
221+ flex-direction: column;
222+ justify-content: flex-start;
223+ align-items: flex-start;
224+ @include typography(paragraph);
225+
226+ .download-filename {
227+ @include typography(paragraph);
228+ font-size: calc(18px * var(--font-scale-factor));
229+ color: var(--theme-text);
230+ }
231+
232+ p {
233+ @include typography(footer);
234+ margin: 0;
235+ color: var(--theme-text);
236+ }
237+ }
238+
239+ .btn {
240+ all: unset;
241+ padding: 20px;
242+ svg {
243+ path,
244+ rect {
245+ fill: none;
246+ stroke: var(--text-body-primary);
247+ transition: stroke 0.2s ease;
248+ }
249+ }
250+ }
251+
252+ .download-separator {
253+ display: flex;
254+ align-items: center;
255+ gap: 40px;
256+ align-self: stretch;
257+ text-align: center;
258+ @include typography(footer);
259+ padding-top: 1.5rem;
260+ padding-bottom: 1.5rem;
261+
262+ hr {
263+ flex: 1;
264+ height: 1px;
265+ background-color: var(--border-separator);
266+ border: none;
267+ margin: 0;
268+ }
269+
270+ p {
271+ width: 30%;
272+ }
273+ }
274+
275+ @include break-down(sm) {
276+ P {
277+ font-size: 12px;
278+ font-weight: 300;
279+ }
280+ .download-separator p {
281+ width: 30%;
282+ }
283+ }
284+
285+ .release-note {
286+ margin-top: 2rem;
287+ text-align: center;
288+ @include typography(footer);
289+ color: var(--theme-text-light);
290+ a {
291+ color: #0c8ce0;
292+ text-decoration: underline;
293+ transition: color 0.2s;
294+ }
295+ a:hover {
296+ color: #005fa3;
297+ }
298+ }
299+ </style >
0 commit comments