Add release to the footer

This commit is contained in:
dtonon 2026-09-23 23:11:52 +02:00
parent dde46dc5d1
commit 455898f3c9
5 changed files with 108 additions and 4 deletions

4
src/app.d.ts vendored
View file

@ -9,8 +9,10 @@ import type {
import type { ThreadDetail } from "$lib/forum/thread";
declare global {
// Injected by vite.config.ts from PUBLIC_SSR
// Injected by vite.config.ts from PUBLIC_SSR, package.json and git
const __SQUALK_SSR__: boolean;
const __SQUALK_VERSION__: string;
const __SQUALK_COMMIT__: string;
namespace App {
// interface Error {}

View file

@ -122,6 +122,10 @@ function closeBunker() {
bunker = null;
}
export function loginMethod(): string | null {
return user ? localStorage.getItem(METHOD_KEY) : null;
}
function clearStoredSession() {
localStorage.removeItem(PUBKEY_KEY);
localStorage.removeItem(METHOD_KEY);

23
src/lib/version.ts Normal file
View file

@ -0,0 +1,23 @@
import { MODE, RELAY_URL, SSR_ENABLED } from "$lib/config";
export const VERSION = __SQUALK_VERSION__;
export const COMMIT = __SQUALK_COMMIT__;
const REPO = "https://github.com/dtonon/squalk";
// A release build links to its GitHub release, anything else to its commit
export const VERSION_URL = VERSION.includes("+")
? `${REPO}/commit/${COMMIT}`
: `${REPO}/releases/tag/v${VERSION}`;
// Plain-text block to paste in a bug report
export function diagnostics(loginMethod: string | null): string {
return [
`Squalk ${VERSION}`,
`Commit: ${COMMIT || "unknown"}`,
`Mode: ${MODE}`,
`SSR: ${SSR_ENABLED ? "yes" : "no"}`,
`Relay: ${RELAY_URL}`,
`Login: ${loginMethod ?? "none"}`,
`Browser: ${navigator.userAgent}`,
].join("\n");
}

View file

@ -15,7 +15,9 @@
import { page } from "$app/state";
import { afterNavigate } from "$app/navigation";
import { onMount, untrack } from "svelte";
import { auth, restoreSession } from "$lib/auth.svelte";
import { auth, restoreSession, loginMethod } from "$lib/auth.svelte";
import { showToast } from "$lib/toast.svelte";
import { VERSION, VERSION_URL, diagnostics } from "$lib/version";
import { loadGroup } from "$lib/group.svelte";
import { ensureMembershipChecked } from "$lib/join.svelte";
import { loadGroups, groupsStore } from "$lib/groups.svelte";
@ -42,6 +44,15 @@
let { children } = $props();
async function copyDiagnostics() {
try {
await navigator.clipboard.writeText(diagnostics(loginMethod()));
showToast("Version info copied, paste it in your bug report");
} catch {
showToast("Could not copy to clipboard");
}
}
// Optional env overrides for the theme colors. Set as inline custom props on
// <html> so they outrank the @theme `:root` defaults; hover shades are derived
// by darkening the base 15% so admins only set one value per color.
@ -233,6 +244,8 @@
<footer
class="mt-auto pt-16 pb-4 text-center text-[90%] text-neutral-500/70 dark:text-neutral-400/70"
>
Hosting relay is {RELAY_URL.replace(/^wss?:\/\//, "")}
<br />
This forum is built on
<a
href="https://njump.me"
@ -249,7 +262,37 @@
class="underline hover:text-neutral-700 dark:hover:text-neutral-200"
>Squalk</a
>
- Hosting relay is {RELAY_URL.replace(/^wss?:\/\//, "")}
<a
href={VERSION_URL}
target="_blank"
rel="noopener noreferrer"
class="underline hover:text-neutral-700 dark:hover:text-neutral-200"
>v{VERSION}</a
>
<button
type="button"
onclick={copyDiagnostics}
aria-label="Copy version info for bug reports"
title="Copy version info for bug reports"
class="focus-visible:ring-accent inline-flex cursor-pointer items-center rounded align-text-bottom hover:text-neutral-700 focus-visible:ring-2 focus-visible:outline-none dark:hover:text-neutral-200"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="size-3.5"
aria-hidden="true"
>
<rect x="9" y="9" width="13" height="13" rx="2" />
<path
d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"
/>
</svg>
</button>
</footer>
</div>
</main>

View file

@ -1,6 +1,33 @@
import tailwindcss from "@tailwindcss/vite";
import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig, loadEnv } from "vite";
import { execSync } from "node:child_process";
import { readFileSync } from "node:fs";
function git(cmd: string): string {
try {
return execSync(`git ${cmd}`, { stdio: ["ignore", "pipe", "ignore"] })
.toString()
.trim();
} catch {
return "";
}
}
// Version comes from package.json; a build that is not exactly the tagged
// release commit (or has local changes) carries the commit as build metadata,
// e.g. 0.3.0+a1b2c3d or 0.3.0+a1b2c3d.dirty, so bug reports tell them apart.
function version(): { version: string; commit: string } {
const pkg = JSON.parse(readFileSync("package.json", "utf8"));
const commit = git("rev-parse --short HEAD");
const tagged = git("tag --points-at HEAD")
.split("\n")
.includes(`v${pkg.version}`);
const dirty = git("status --porcelain --untracked-files=no") !== "";
let v = pkg.version;
if (commit && (!tagged || dirty)) v += `+${commit}${dirty ? ".dirty" : ""}`;
return { version: v, commit };
}
// PUBLIC_SSR is a build-time decision (it also picks the adapter in
// svelte.config.js), so it is compiled in as a constant rather than read from
@ -8,8 +35,13 @@ import { defineConfig, loadEnv } from "vite";
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), "PUBLIC_");
const ssr = (process.env.PUBLIC_SSR ?? env.PUBLIC_SSR) === "yes";
const build = version();
return {
plugins: [tailwindcss(), sveltekit()],
define: { __SQUALK_SSR__: JSON.stringify(ssr) },
define: {
__SQUALK_SSR__: JSON.stringify(ssr),
__SQUALK_VERSION__: JSON.stringify(build.version),
__SQUALK_COMMIT__: JSON.stringify(build.commit),
},
};
});