From be3a4b34d3cf7d4903f34e748b2fe454814855d4 Mon Sep 17 00:00:00 2001 From: dtonon Date: Fri, 5 Jun 2026 17:32:11 +0100 Subject: [PATCH] Allow to specify accend and secondary colors --- .env.example | 3 +++ src/lib/components/ChatContent.svelte | 8 +++--- src/lib/components/ChatSidebar.svelte | 4 +-- src/lib/components/DeleteModal.svelte | 2 +- src/lib/components/DiscussionsFeed.svelte | 4 +-- src/lib/components/JoinModal.svelte | 4 +-- src/lib/components/LatestDiscussions.svelte | 4 +-- src/lib/components/LeftSidebar.svelte | 10 ++++---- src/lib/components/LoginModal.svelte | 10 ++++---- src/lib/components/MessageEditor.svelte | 2 +- src/lib/components/MobileMenu.svelte | 16 ++++++------ src/lib/components/NewDiscussionModal.svelte | 12 ++++----- src/lib/components/PostContent.svelte | 8 +++--- src/lib/components/Tag.svelte | 2 +- src/lib/components/ThreadItem.svelte | 2 +- src/lib/components/ThreadScrubber.svelte | 2 +- src/lib/config.ts | 5 ++++ src/routes/+layout.svelte | 27 +++++++++++++++++--- src/routes/+page.svelte | 4 +-- src/routes/contacts/+page.svelte | 8 +++--- src/routes/layout.css | 12 ++++----- src/routes/resource/[slug]/+page.svelte | 2 +- src/routes/thread/[id]/+page.svelte | 12 ++++----- 23 files changed, 96 insertions(+), 67 deletions(-) diff --git a/.env.example b/.env.example index c366e73..0ab941c 100644 --- a/.env.example +++ b/.env.example @@ -5,3 +5,6 @@ PUBLIC_MODE=simple # simple | full PUBLIC_JOINCODE=no # yes | no — show invite-code field on join failure PUBLIC_LABELS= # comma-separated labels (e.g., bug,feature,question) PUBLIC_BLOSSOM_URL= # Blossom server URL (e.g., https://blossom.primal.net) +# 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 diff --git a/src/lib/components/ChatContent.svelte b/src/lib/components/ChatContent.svelte index 5f7684d..ee828ad 100644 --- a/src/lib/components/ChatContent.svelte +++ b/src/lib/components/ChatContent.svelte @@ -42,22 +42,22 @@ href="https://njump.me/{t.entity}" target="_blank" rel="noopener noreferrer" - class="text-brand hover:underline">@{u?.shortName ?? t.fallback}@{u?.shortName ?? t.fallback}{:else if t.type === "entity"}{@const ref = t.id ? resolvedThreads[t.id] : undefined}{#if ref}{ref.title}{ref.title}{:else}{t.label}{t.label}{/if}{:else if t.type === "link"}{t.label}{t.label}{:else}{t.value}{/if}{/each} diff --git a/src/lib/components/ChatSidebar.svelte b/src/lib/components/ChatSidebar.svelte index 282aa76..698c33f 100644 --- a/src/lib/components/ChatSidebar.svelte +++ b/src/lib/components/ChatSidebar.svelte @@ -232,7 +232,7 @@ {expanded ? 'md:w-150 md:shadow-2xl' : 'md:w-80 md:shadow-lg'}" >
- Chat + Chat
diff --git a/src/lib/components/DeleteModal.svelte b/src/lib/components/DeleteModal.svelte index 38ca355..f7599f2 100644 --- a/src/lib/components/DeleteModal.svelte +++ b/src/lib/components/DeleteModal.svelte @@ -70,7 +70,7 @@ disabled={deleteState.busy} rows="2" placeholder="Recorded with the deletion" - class="focus:ring-brand mb-4 w-full resize-none rounded border border-neutral-200 dark:border-neutral-700 px-3 py-2 text-sm focus:ring-1 focus:outline-none disabled:opacity-50" + class="focus:ring-accent mb-4 w-full resize-none rounded border border-neutral-200 dark:border-neutral-700 px-3 py-2 text-sm focus:ring-1 focus:outline-none disabled:opacity-50" >
diff --git a/src/lib/components/DiscussionsFeed.svelte b/src/lib/components/DiscussionsFeed.svelte index 2ea378c..d28e8a3 100644 --- a/src/lib/components/DiscussionsFeed.svelte +++ b/src/lib/components/DiscussionsFeed.svelte @@ -97,11 +97,11 @@
-

{title}

+

{title}

diff --git a/src/lib/components/JoinModal.svelte b/src/lib/components/JoinModal.svelte index 37296a7..c427bc3 100644 --- a/src/lib/components/JoinModal.svelte +++ b/src/lib/components/JoinModal.svelte @@ -87,7 +87,7 @@ autocapitalize="off" spellcheck="false" onkeydown={(e) => e.key === "Enter" && onRetry()} - class="focus:ring-brand mb-3 w-full rounded border border-neutral-200 dark:border-neutral-700 px-3 py-2 text-sm focus:ring-1 focus:outline-none disabled:opacity-50" + class="focus:ring-accent mb-3 w-full rounded border border-neutral-200 dark:border-neutral-700 px-3 py-2 text-sm focus:ring-1 focus:outline-none disabled:opacity-50" /> {/if} @@ -104,7 +104,7 @@ type="button" onclick={onRetry} disabled={joinState.busy || (joinState.codeRequired && !code.trim())} - class="bg-brand hover:bg-brand-hover rounded px-3 py-2 text-sm font-medium text-white disabled:cursor-not-allowed disabled:opacity-50" + class="bg-accent hover:bg-accent-hover rounded px-3 py-2 text-sm font-medium text-white disabled:cursor-not-allowed disabled:opacity-50" > {joinState.busy ? "Trying…" : "Retry"} diff --git a/src/lib/components/LatestDiscussions.svelte b/src/lib/components/LatestDiscussions.svelte index eacea58..3d40648 100644 --- a/src/lib/components/LatestDiscussions.svelte +++ b/src/lib/components/LatestDiscussions.svelte @@ -28,7 +28,7 @@
@@ -123,7 +123,7 @@ @@ -159,7 +159,7 @@
diff --git a/src/lib/components/LoginModal.svelte b/src/lib/components/LoginModal.svelte index 98166a6..01941a4 100644 --- a/src/lib/components/LoginModal.svelte +++ b/src/lib/components/LoginModal.svelte @@ -119,7 +119,7 @@ @@ -131,7 +131,7 @@ @@ -149,12 +149,12 @@ autocorrect="off" spellcheck="false" onkeydown={(e) => e.key === "Enter" && handleNsec()} - class="focus:ring-brand w-full rounded border border-neutral-200 dark:border-neutral-700 px-3 py-2 font-mono text-sm focus:ring-1 focus:outline-none disabled:opacity-50" + class="focus:ring-accent w-full rounded border border-neutral-200 dark:border-neutral-700 px-3 py-2 font-mono text-sm focus:ring-1 focus:outline-none disabled:opacity-50" /> @@ -164,7 +164,7 @@ diff --git a/src/lib/components/MessageEditor.svelte b/src/lib/components/MessageEditor.svelte index 6880b49..2e0ee42 100644 --- a/src/lib/components/MessageEditor.svelte +++ b/src/lib/components/MessageEditor.svelte @@ -103,7 +103,7 @@ {rows} {placeholder} {contextPubkeys} - textareaClass="block w-full rounded-t border border-neutral-200 dark:border-neutral-700 px-3 py-2 focus:outline-none focus:ring-1 focus:ring-brand disabled:opacity-50 resize-y {minHeightClass}" + textareaClass="block w-full rounded-t border border-neutral-200 dark:border-neutral-700 px-3 py-2 focus:outline-none focus:ring-1 focus:ring-accent disabled:opacity-50 resize-y {minHeightClass}" /> {/if}
{mode === "simple" ? "Discussions" : "Home"} @@ -139,7 +139,7 @@ href="/room/{room.id}" onclick={onClose} class="block py-1.5 text-xl - {activeRoom === room.id ? 'text-brand' : 'hover:text-brand text-neutral-700 dark:text-neutral-300'}" + {activeRoom === room.id ? 'text-accent' : 'hover:text-accent text-neutral-700 dark:text-neutral-300'}" > {room.name} @@ -158,8 +158,8 @@ href="/resource/{r.slug}" onclick={onClose} aria-current={activeResource === r.slug ? "page" : undefined} - class="hover:text-brand block py-1.5 text-xl - {activeResource === r.slug ? 'text-brand' : 'text-neutral-700 dark:text-neutral-300'}" + class="hover:text-accent block py-1.5 text-xl + {activeResource === r.slug ? 'text-accent' : 'text-neutral-700 dark:text-neutral-300'}" >{r.title} {/each} @@ -167,8 +167,8 @@ href="/contacts" onclick={onClose} aria-current={contactsActive ? "page" : undefined} - class="hover:text-brand block py-1.5 text-lg - {contactsActive ? 'text-brand' : 'text-neutral-700 dark:text-neutral-300'}">ContactsContacts @@ -177,7 +177,7 @@ @@ -219,7 +219,7 @@ diff --git a/src/lib/components/NewDiscussionModal.svelte b/src/lib/components/NewDiscussionModal.svelte index 5cba7e8..76e3355 100644 --- a/src/lib/components/NewDiscussionModal.svelte +++ b/src/lib/components/NewDiscussionModal.svelte @@ -151,7 +151,7 @@ {#if targetName}

{targetName}

{/if} -

New discussion

+

New discussion

@@ -204,11 +204,11 @@ Labels
{#each draftState.labels as l} {l} @@ -304,7 +304,7 @@ disabled={draftState.publishing || !draftState.title.trim() || !draftState.content.trim()} - class="bg-brand hover:bg-brand-hover rounded px-5 py-1.5 font-medium text-white disabled:cursor-not-allowed disabled:opacity-50" + class="bg-accent hover:bg-accent-hover rounded px-5 py-1.5 font-medium text-white disabled:cursor-not-allowed disabled:opacity-50" > {draftState.publishing ? "Publishing…" : "Publish discussion"} diff --git a/src/lib/components/PostContent.svelte b/src/lib/components/PostContent.svelte index 9ea3221..7918f13 100644 --- a/src/lib/components/PostContent.svelte +++ b/src/lib/components/PostContent.svelte @@ -607,7 +607,7 @@ href={inline.href} target={internal ? undefined : "_blank"} rel={internal ? undefined : "noopener noreferrer"} - class="text-brand break-all hover:underline">{inline.label}{inline.label} {:else if inline.type === "mention"} {@const u = profiles[inline.pubkey] ?? resolvedUsers[inline.pubkey]} @@ -615,7 +615,7 @@ href="https://njump.me/{inline.entity}" target="_blank" rel="noopener noreferrer" - class="text-brand hover:underline">@{u?.shortName ?? inline.fallback}@{u?.shortName ?? inline.fallback} {:else if inline.type === "thread-quote"} {@const u = profiles[inline.pubkey] ?? resolvedUsers[inline.pubkey]} @@ -640,7 +640,7 @@ {:else if inline.type === "entity"} {@const ref = inline.id ? resolvedThreads[inline.id] : undefined} {#if ref} - {ref.title} {:else} @@ -648,7 +648,7 @@ href="https://njump.me/{inline.entity}" target="_blank" rel="noopener noreferrer" - class="text-brand break-all hover:underline">{inline.label}{inline.label} {/if} {:else if inline.type === "strong"} diff --git a/src/lib/components/Tag.svelte b/src/lib/components/Tag.svelte index e8be2de..be25f02 100644 --- a/src/lib/components/Tag.svelte +++ b/src/lib/components/Tag.svelte @@ -3,6 +3,6 @@ let { label }: Props = $props(); - + {label} diff --git a/src/lib/components/ThreadItem.svelte b/src/lib/components/ThreadItem.svelte index e1e99af..7a9dfa7 100644 --- a/src/lib/components/ThreadItem.svelte +++ b/src/lib/components/ThreadItem.svelte @@ -41,7 +41,7 @@
{thread.title}
diff --git a/src/lib/components/ThreadScrubber.svelte b/src/lib/components/ThreadScrubber.svelte index 666cd90..c9505d5 100644 --- a/src/lib/components/ThreadScrubber.svelte +++ b/src/lib/components/ThreadScrubber.svelte @@ -169,7 +169,7 @@
l.trim()) .filter(Boolean); export const BLOSSOM_URL = (env.PUBLIC_BLOSSOM_URL ?? "").replace(/\/$/, ""); + +// Theme color overrides: when set, replace the accent (primary) and secondary +// CSS variables defined in layout.css. Hover shades are derived in the layout. +export const ACCENT_COLOR = env.PUBLIC_ACCENT_COLOR ?? ""; +export const SECONDARY_COLOR = env.PUBLIC_SECONDARY_COLOR ?? ""; diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 20c4821..d5b75ee 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -23,10 +23,31 @@ import { seedProfiles } from "$lib/profiles.svelte"; import { startChat } from "$lib/chat.svelte"; import { activeGroup, setActiveGroup } from "$lib/active.svelte"; - import { MODE } from "$lib/config"; + import { MODE, ACCENT_COLOR, SECONDARY_COLOR } from "$lib/config"; let { children } = $props(); + // Optional env overrides for the theme colors. Set as inline custom props on + // so they outrank the @theme `:root` defaults; hover shades are derived + // by darkening the base 15% so admins only set one value per color. + $effect(() => { + const root = document.documentElement; + if (ACCENT_COLOR) { + root.style.setProperty("--color-accent", ACCENT_COLOR); + root.style.setProperty( + "--color-accent-hover", + `color-mix(in srgb, ${ACCENT_COLOR} 85%, #000)`, + ); + } + if (SECONDARY_COLOR) { + root.style.setProperty("--color-secondary", SECONDARY_COLOR); + root.style.setProperty( + "--color-secondary-hover", + `color-mix(in srgb, ${SECONDARY_COLOR} 85%, #000)`, + ); + } + }); + const mode = MODE; const chatEnabled = true; @@ -168,7 +189,7 @@ onclick={() => (mobileView = "forum")} aria-pressed={mobileView === "forum"} class="flex flex-1 flex-col items-center gap-0.5 py-2 text-xs font-medium - {mobileView === 'forum' ? 'text-brand' : 'text-neutral-500 dark:text-neutral-400'}" + {mobileView === 'forum' ? 'text-accent' : 'text-neutral-500 dark:text-neutral-400'}" > (mobileView = "chat")} aria-pressed={mobileView === "chat"} class="flex flex-1 flex-col items-center gap-0.5 py-2 text-xs font-medium - {mobileView === 'chat' ? 'text-brand' : 'text-neutral-500 dark:text-neutral-400'}" + {mobileView === 'chat' ? 'text-accent' : 'text-neutral-500 dark:text-neutral-400'}" > {:else} -

Forum rooms

+

Forum rooms

{/if} {#if groupsStore.list.length === 0} @@ -83,7 +83,7 @@ >

{room.name}

diff --git a/src/routes/contacts/+page.svelte b/src/routes/contacts/+page.svelte index b13a2df..0fe768a 100644 --- a/src/routes/contacts/+page.svelte +++ b/src/routes/contacts/+page.svelte @@ -72,7 +72,7 @@
-

Contacts

+

Contacts

{#if partial}
@@ -120,7 +120,7 @@ href="https://njump.me/{c.npub}" target="_blank" rel="noopener noreferrer" - class="text-brand shrink-0 text-sm hover:underline" + class="text-accent shrink-0 text-sm hover:underline" > View profile ↗ @@ -141,7 +141,7 @@ href={websiteHref(c.entry.website)} target="_blank" rel="noopener noreferrer" - class="text-brand truncate hover:underline" + class="text-accent truncate hover:underline" > {websiteLabel(c.entry.website)} @@ -161,7 +161,7 @@ Manages: {#each rooms as r, i}{r.name}{r.name}{i < rooms.length - 1 ? ", " : ""}{/each}

{/if} diff --git a/src/routes/layout.css b/src/routes/layout.css index 29c6902..464dae2 100644 --- a/src/routes/layout.css +++ b/src/routes/layout.css @@ -47,7 +47,7 @@ body { } .prose :is(h1) { font-size: 1.65rem; - color: var(--color-brand); + color: var(--color-accent); } .prose :is(p) { margin-top: 0; @@ -61,7 +61,7 @@ body { color: var(--color-neutral-100); } :where(.dark) .prose :is(h1) { - color: var(--color-brand); + color: var(--color-accent); } :where(.dark) .prose :is(blockquote) { color: var(--color-neutral-400); @@ -72,8 +72,8 @@ body { } @theme { - --color-brand: #e32a6d; - --color-brand-hover: #c4205a; - --color-accent: #ffaf25; - --color-accent-hover: #e69e1a; + --color-accent: #e32a6d; + --color-accent-hover: #c4205a; + --color-secondary: #ffaf25; + --color-secondary-hover: #e69e1a; } diff --git a/src/routes/resource/[slug]/+page.svelte b/src/routes/resource/[slug]/+page.svelte index 7f7961f..310d833 100644 --- a/src/routes/resource/[slug]/+page.svelte +++ b/src/routes/resource/[slug]/+page.svelte @@ -31,7 +31,7 @@