Add release to the footer
This commit is contained in:
parent
dde46dc5d1
commit
455898f3c9
5 changed files with 108 additions and 4 deletions
4
src/app.d.ts
vendored
4
src/app.d.ts
vendored
|
|
@ -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 {}
|
||||
|
|
|
|||
|
|
@ -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
23
src/lib/version.ts
Normal 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");
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue