This commit is contained in:
pj committed 2026-06-22 13:03:11 -04:00
1 parent b4097cc47f
commit 61bd7cf6e5
6 files changed
+87 -114

No files matched your search

+4 -1
View File
@@ -1,10 +1,12 @@
---
import { site, platforms } from "../data/site";
import { getRelease } from "../data/release";
interface Props {
large?: boolean;
}
const { large = false } = Astro.props;
const release = await getRelease();
---
<div class="dl">
@@ -26,7 +28,7 @@ const { large = false } = Astro.props;
platforms.map((p) => (
<a
class="dl__chip"
href={site.releasesUrl}
href={release.urls[p.id]}
data-download-os={p.id}
rel="noopener"
download
@@ -57,6 +59,7 @@ const { large = false } = Astro.props;
display: inline-flex;
align-items: center;
justify-content: center;
flex: none;
width: 44px;
height: 44px;
background: #ffffff;
+21 -35
View File
@@ -1,14 +1,13 @@
---
import { site } from "../data/site";
import { site, platforms } from "../data/site";
import { getRelease } from "../data/release";
const { repo, releasesUrl } = site;
const { urls, version } = await getRelease();
const matches = Object.fromEntries(platforms.map((p) => [p.id, p.match]));
---
<script define:vars={{ repo, releasesUrl }}>
const SUFFIXES = {
mac: [".dmg"],
windows: [".msi", ".exe"],
linux: [".AppImage", ".deb", ".rpm"],
};
<script define:vars={{ repo, releasesUrl, urls, version, matches }}>
const LABELS = { mac: "macOS", windows: "Windows", linux: "Linux" };
function detectOS() {
@@ -21,32 +20,31 @@ const { repo, releasesUrl } = site;
}
function pickAsset(assets, os) {
for (const sfx of SUFFIXES[os] || []) {
for (const sfx of matches[os] || []) {
const hit = assets.find((a) => a.name.toLowerCase().endsWith(sfx.toLowerCase()));
if (hit) return hit.browser_download_url;
}
return null;
}
function apply(map, ver) {
const os = detectOS();
document.querySelectorAll("[data-download]").forEach((el) => {
el.dataset.detectedOs = os;
const label = el.querySelector("[data-dl-label]");
if (label) label.textContent = "Download for " + LABELS[os];
if (map[os]) el.href = map[os];
});
document.querySelectorAll(".dl__alt [data-download-os]").forEach((el) => {
document.querySelectorAll("[data-download-os]").forEach((el) => {
const url = map[el.dataset.downloadOs];
if (url) el.href = url;
});
document.querySelectorAll(".dl__os [data-download-os]").forEach((el) => {
if (el.dataset.downloadOs === os) el.remove();
});
document.querySelectorAll("[data-osrow]").forEach((row) => {
const primary = row.querySelector(`[data-download-os="${os}"]`);
if (primary) {
primary.classList.add("is-detected");
row.prepend(primary);
if (ver) document.querySelectorAll("[data-version]").forEach((el) => (el.textContent = ver));
}
});
apply(urls, version);
(async () => {
try {
@@ -56,23 +54,11 @@ const { repo, releasesUrl } = site;
if (!res.ok) return;
const data = await res.json();
const assets = data.assets || [];
const version = data.tag_name || "";
document.querySelectorAll("[data-download]").forEach((el) => {
const url = pickAsset(assets, el.dataset.detectedOs || os);
if (url) el.href = url;
});
document.querySelectorAll("[data-download-os]").forEach((el) => {
const url = pickAsset(assets, el.dataset.downloadOs);
if (url) el.href = url;
});
if (version) {
document.querySelectorAll("[data-version]").forEach((el) => {
el.textContent = version;
});
}
const fresh = {};
for (const os of Object.keys(matches)) fresh[os] = pickAsset(assets, os) || urls[os] || releasesUrl;
apply(fresh, data.tag_name || version);
} catch (e) {
/* keep the releases-page fallback links */
/* keep the build-time links */
}
})();
</script>
+6 -3
View File
@@ -1,14 +1,17 @@
---
import { site } from "../data/site";
import { getRelease } from "../data/release";
import Logo from "./Logo.astro";
const release = await getRelease();
const cols = [
{
title: "Get Margin",
links: [
{ label: "Download for macOS", href: site.releasesUrl, os: "mac" },
{ label: "Download for Windows", href: site.releasesUrl, os: "windows" },
{ label: "Download for Linux", href: site.releasesUrl, os: "linux" },
{ label: "Download for macOS", href: release.urls.mac, os: "mac" },
{ label: "Download for Windows", href: release.urls.windows, os: "windows" },
{ label: "Download for Linux", href: release.urls.linux, os: "linux" },
],
},
{
+2 -73
View File
@@ -1,7 +1,7 @@
---
import AppWindow from "./AppWindow.astro";
import DownloadButtons from "./DownloadButtons.astro";
import OfferBadge from "./OfferBadge.astro";
import { site, platforms } from "../data/site";
---
<section class="hero">
@@ -21,25 +21,7 @@ import { site, platforms } from "../data/site";
</div>
<div class="container hero__get" id="download">
<div class="hero__buttons" data-osrow>
{
platforms.map((p) => (
<a
class="osbtn"
href={site.releasesUrl}
data-download-os={p.id}
rel="noopener"
download
>
<img class="osbtn__icon" src={`/logos/${p.logo}`} alt="" />
<span>Download for {p.label}</span>
</a>
))
}
</div>
<p class="hero__meta">
<span data-version>v0.1.2</span> · Works offline · No account
</p>
<DownloadButtons large />
<div class="hero__offer">
<OfferBadge />
</div>
@@ -75,62 +57,9 @@ import { site, platforms } from "../data/site";
margin-top: clamp(24px, 3vw, 32px);
scroll-margin-top: 96px;
}
.hero__buttons {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 12px;
}
.osbtn {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 0.82em 1.35em;
background: #ffffff;
border: 1px solid var(--line-strong);
border-radius: 999px;
color: #23201b;
font-family: var(--font-ui);
font-size: 1rem;
font-weight: 600;
box-shadow: var(--shadow-page);
transition:
transform 0.18s var(--ease),
box-shadow 0.18s var(--ease),
border-color 0.18s var(--ease);
}
.osbtn:hover {
transform: translateY(-1px);
box-shadow: var(--shadow-pop);
}
.osbtn.is-detected {
border-color: var(--ink);
}
.osbtn__icon {
width: 18px;
height: 18px;
flex: none;
object-fit: contain;
}
.hero__meta {
margin: 16px 0 0;
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
font-size: 0.8rem;
color: var(--ink-faint);
text-align: center;
}
.hero__offer {
display: flex;
justify-content: center;
margin-top: 22px;
}
@media (max-width: 480px) {
.hero__buttons {
flex-direction: column;
align-items: stretch;
}
.osbtn {
justify-content: center;
}
}
</style>
+52
View File
@@ -0,0 +1,52 @@
// Resolves the latest GitHub release to a direct download URL per OS, at build
// time. The picked file follows each platform's `match` order in site.ts.
// Falls back to the releases page if the release can't be read.
import { site, platforms } from "./site";
type Asset = { name: string; browser_download_url: string };
export type Release = {
version: string;
urls: Record<string, string>;
};
function pickAsset(assets: Asset[], match: string[]): string | null {
for (const sfx of match) {
const hit = assets.find((a) => a.name.toLowerCase().endsWith(sfx.toLowerCase()));
if (hit) return hit.browser_download_url;
}
return null;
}
function fallback(): Release {
return {
version: "",
urls: Object.fromEntries(platforms.map((p) => [p.id, site.releasesUrl])),
};
}
async function fetchRelease(): Promise<Release> {
try {
const res = await fetch(`https://api.github.com/repos/${site.repo}/releases/latest`, {
headers: { Accept: "application/vnd.github+json" },
signal: AbortSignal.timeout(8000),
});
if (!res.ok) return fallback();
const data = await res.json();
const assets: Asset[] = data.assets || [];
const urls = Object.fromEntries(
platforms.map((p) => [p.id, pickAsset(assets, p.match) ?? site.releasesUrl]),
);
return { version: data.tag_name ?? "", urls };
} catch {
return fallback();
}
}
let cached: Promise<Release> | null = null;
export function getRelease(): Promise<Release> {
cached ??= fetchRelease();
return cached;
}
+2 -2
View File
@@ -39,8 +39,8 @@ export type Platform = {
export const platforms: Platform[] = [
{ id: "mac", label: "macOS", logo: "macos.svg", match: [".dmg"] },
{ id: "windows", label: "Windows", logo: "windows.svg", match: [".msi", ".exe"] },
{ id: "linux", label: "Linux", logo: "linux.svg", match: [".AppImage", ".deb", ".rpm"] },
{ id: "windows", label: "Windows", logo: "windows.svg", match: [".exe", ".msi"] },
{ id: "linux", label: "Linux", logo: "linux.svg", match: [".deb", ".AppImage", ".rpm"] },
];
// Full-color store logos, served from /public/logos. Shown on white tiles so