Beta testers had to find prerelease assets on GitHub by hand. The download page now carries a Stable/Beta switch, with stable staying the default and the canonical URL. The channel lives in the URL (?channel=beta) rather than client state so maintainers can link someone straight to it. That link outlives the beta it was shared for, so the switch only renders while the newest prerelease leads stable on its core version, and a stale ?channel=beta falls back to stable instead of serving a promoted version twice. "What's new" deep-links the minor group anchor (/changelog#release-0.3), not the exact entry: promotion rewrites the -beta.N entry in place, so that anchor dies while the group survives — and the group is the stable-to-beta diff a beta downloader came to read. A version missing from the bundled changelog links plain /changelog rather than a dead anchor, which covers the window between a tag going public and the site redeploying. Homebrew, the app stores, and the web app have no beta, so the Beta view drops those rows instead of showing inert placeholders.
94 lines
2.8 KiB
TypeScript
94 lines
2.8 KiB
TypeScript
import type { ReactNode } from "react";
|
|
import { createContext, useContext } from "react";
|
|
import { Outlet, createRootRoute, HeadContent, Scripts } from "@tanstack/react-router";
|
|
import type { ReleaseChannels, ReleaseInfo } from "~/latest-release";
|
|
import { getLatestRelease } from "~/release";
|
|
import { getStarCount } from "~/stars";
|
|
|
|
interface StarsContext {
|
|
stars: string;
|
|
}
|
|
|
|
const ReleaseCtx = createContext<ReleaseChannels>({
|
|
stable: {
|
|
version: "",
|
|
linuxAppImageAsset: "",
|
|
windowsX64Asset: null,
|
|
windowsArm64Asset: null,
|
|
},
|
|
beta: null,
|
|
});
|
|
const StarsCtx = createContext<StarsContext>({ stars: "" });
|
|
|
|
const PLAUSIBLE_INIT_SCRIPT = {
|
|
__html: `window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};plausible.init()`,
|
|
};
|
|
|
|
/** The latest stable release. Everything on the site points here by default. */
|
|
export function useRelease(): ReleaseInfo {
|
|
return useContext(ReleaseCtx).stable;
|
|
}
|
|
|
|
/** The current beta, or null when there is no beta ahead of stable. */
|
|
export function useBetaRelease(): ReleaseInfo | null {
|
|
return useContext(ReleaseCtx).beta;
|
|
}
|
|
|
|
export function useStars(): StarsContext {
|
|
return useContext(StarsCtx);
|
|
}
|
|
|
|
export const Route = createRootRoute({
|
|
loader: async () => {
|
|
const [release, stars] = await Promise.all([getLatestRelease(), getStarCount()]);
|
|
return { release, ...stars };
|
|
},
|
|
head: () => ({
|
|
meta: [
|
|
{ charSet: "utf-8" },
|
|
{ name: "viewport", content: "width=device-width, initial-scale=1" },
|
|
{ name: "theme-color", content: "#101615" },
|
|
{ property: "og:site_name", content: "Paseo" },
|
|
{ property: "og:type", content: "website" },
|
|
{ property: "og:image", content: "https://paseo.sh/og-image.png" },
|
|
{ name: "twitter:card", content: "summary_large_image" },
|
|
{ name: "twitter:image", content: "https://paseo.sh/og-image.png" },
|
|
],
|
|
links: [
|
|
{ rel: "icon", href: "/favicon.ico", sizes: "48x48" },
|
|
{ rel: "icon", href: "/favicon.svg", type: "image/svg+xml" },
|
|
{ rel: "apple-touch-icon", href: "/favicon.svg" },
|
|
],
|
|
}),
|
|
component: RootComponent,
|
|
});
|
|
|
|
function RootComponent() {
|
|
const data = Route.useLoaderData();
|
|
return (
|
|
<ReleaseCtx value={data.release}>
|
|
<StarsCtx value={data}>
|
|
<RootDocument>
|
|
<Outlet />
|
|
</RootDocument>
|
|
</StarsCtx>
|
|
</ReleaseCtx>
|
|
);
|
|
}
|
|
|
|
function RootDocument({ children }: Readonly<{ children: ReactNode }>) {
|
|
return (
|
|
<html lang="en">
|
|
<head>
|
|
<HeadContent />
|
|
<script async src="https://plausible.io/js/pa-cKNUoWbeH_Iksb2fh82s3.js" />
|
|
<script dangerouslySetInnerHTML={PLAUSIBLE_INIT_SCRIPT} />
|
|
</head>
|
|
<body className="antialiased bg-background text-foreground">
|
|
{children}
|
|
<Scripts />
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|