Allow to config the external client

This commit is contained in:
dtonon 2026-09-24 16:24:29 +02:00
parent 58e81d1dba
commit 5f8bf2fe7e
6 changed files with 28 additions and 8 deletions

View file

@ -14,6 +14,7 @@ PUBLIC_SEARCH=no # yes | no — enable the search box (req
PUBLIC_LABELS= # comma-separated discussion labels (e.g., bug,feature,question)
PUBLIC_NOSTRCONNECT_RELAYS= # comma-separated relays for nostrconnect:// (bunker) login; defaults to bucket.coracle.social,relay.primal.net
PUBLIC_BLOSSOM_URL= # Blossom server URL for uploads (e.g., https://blossom.primal.net)
PUBLIC_EXTERNAL_CLIENT= # external client for profiles/events, {e} is the bech32 entity; default https://njump.me/{e}
# Theme color overrides — quote the value, a leading # is read as a comment otherwise
PUBLIC_ACCENT_COLOR= # override the accent color (default #e32a6d), e.g. "#00ff00"; hover shade derived
PUBLIC_SECONDARY_COLOR= # override the secondary color (default #ffaf25), e.g. "#0000ff"; hover shade derived

View file

@ -34,6 +34,7 @@ Squalk is configured entirely through environment variables (all prefixed `PUBLI
| `PUBLIC_SEARCH` | no | `no` | `yes` to show a search box at the top of the homepage. Requires a relay with NIP-50 search support. |
| `PUBLIC_LABELS` | no | — | Comma-separated discussion labels offered when composing, e.g. `bug,feature,question`. |
| `PUBLIC_BLOSSOM_URL` | no | — | Blossom server URL used for media uploads, e.g. `https://blossom.primal.net`. Uploads are disabled when unset. |
| `PUBLIC_EXTERNAL_CLIENT` | no | `https://njump.me/{e}` | URL template of the external Nostr client used to open profiles and events outside the forum. `{e}` is replaced with the bech32 entity (npub, nevent, naddr), e.g. `https://nostr.at/{e}`. |
| `PUBLIC_ACCENT_COLOR` | no | `#e32a6d` | Override the accent (primary) color. Quote the value (`"#00ff00"`) — an unquoted leading `#` is read as a comment. The hover shade is derived automatically. |
| `PUBLIC_SECONDARY_COLOR` | no | `#ffaf25` | Override the secondary color. Same quoting rule and derived hover shade as above. |

View file

@ -2,6 +2,7 @@
import { loadNostrUser, type NostrUser } from "$lib/gadgets";
import * as nip19 from "@nostr/tools/nip19";
import { profilePath } from "$lib/forum/profiles";
import { externalLink } from "$lib/config";
import {
resolveThreadRef,
threadRefHref,
@ -311,7 +312,7 @@
const entity = dest.slice(6).toLowerCase();
try {
nip19.decode(entity);
return { type: "link", href: `https://njump.me/${entity}`, label };
return { type: "link", href: externalLink(entity), label };
} catch {
return { type: "text", value: label };
}
@ -642,7 +643,7 @@
>
{:else}
<a
href="https://njump.me/{inline.entity}"
href={externalLink(inline.entity)}
target="_blank"
rel="noopener noreferrer"
class="text-accent break-all hover:underline">{inline.label}</a

View file

@ -73,3 +73,20 @@ export const FAVICON =
encodeURIComponent(
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path fill-rule="evenodd" fill="${ACCENT_COLOR || DEFAULT_ACCENT}" d="M16 0a16 16 0 1 0 0 32a16 16 0 1 0 0-32zM16 8a8 8 0 1 1 0 16a8 8 0 1 1 0-16z"/></svg>`,
);
// External Nostr client used to open events and profiles that live outside
// the forum. {e} is replaced with the bech32 entity (npub, nevent, naddr...).
const DEFAULT_EXTERNAL_CLIENT = "https://njump.me/{e}";
export const EXTERNAL_CLIENT = env.PUBLIC_EXTERNAL_CLIENT?.includes("{e}")
? env.PUBLIC_EXTERNAL_CLIENT
: DEFAULT_EXTERNAL_CLIENT;
export const EXTERNAL_CLIENT_NAME = (() => {
try {
return new URL(EXTERNAL_CLIENT.replace("{e}", "x")).hostname;
} catch {
return "external client";
}
})();
export function externalLink(entity: string): string {
return EXTERNAL_CLIENT.replace("{e}", entity);
}

View file

@ -1,5 +1,5 @@
import * as nip19 from "@nostr/tools/nip19";
import { RELAY_URL } from "./config";
import { RELAY_URL, externalLink } from "./config";
// Curated TLD list: gTLDs, popular new gTLDs, common ccTLDs
const TLDS = [
@ -157,7 +157,7 @@ function decodeEntity(entity: string): ChatToken | null {
return {
type: "entity",
entity,
href: `https://njump.me/${entity}`,
href: externalLink(entity),
label: shortNostrEntity(entity),
id: decoded.type === "note" ? decoded.data : decoded.data.id,
};
@ -165,7 +165,7 @@ function decodeEntity(entity: string): ChatToken | null {
return {
type: "entity",
entity,
href: `https://njump.me/${entity}`,
href: externalLink(entity),
label: shortNostrEntity(entity),
};
} catch {

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { page } from "$app/state";
import { MODE } from "$lib/config";
import { MODE, EXTERNAL_CLIENT_NAME, externalLink } from "$lib/config";
import { getGroupName } from "$lib/group.svelte";
import { groupsStore } from "$lib/groups.svelte";
import {
@ -235,12 +235,12 @@
</span>
{/if}
<a
href="https://njump.me/{npub}"
href={externalLink(npub)}
target="_blank"
rel="noopener noreferrer"
class="text-accent text-sm hover:underline"
>
View on njump ↗
View on {EXTERNAL_CLIENT_NAME} ↗
</a>
</div>