From 244f7e40cebaf5f312eb49da3fc5fd0d65e5096c Mon Sep 17 00:00:00 2001 From: Yusur Princeps Date: Sun, 14 Sep 2025 16:05:35 +0200 Subject: [PATCH 01/13] fixes --- src/lib/MetaNav.svelte | 4 ++-- src/routes/+page.ts | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/lib/MetaNav.svelte b/src/lib/MetaNav.svelte index 94ec87f..31448ca 100644 --- a/src/lib/MetaNav.svelte +++ b/src/lib/MetaNav.svelte @@ -28,8 +28,8 @@ let { user } : {user: UserEntry} = $props(); {#if user}
  • - @{user.username} - {0} karma + @{user.username} + {user.karma || 0} karma
  • diff --git a/src/routes/+page.ts b/src/routes/+page.ts index 1d3080e..0d51905 100644 --- a/src/routes/+page.ts +++ b/src/routes/+page.ts @@ -6,8 +6,10 @@ import type { LoadEvent } from '@sveltejs/kit'; async function loadFeed (event: LoadEvent): Promise { const resp = await backend.withEvent(event).fetch('home/feed'); - if ([200].indexOf(resp.status) < 0) return null; - + if ([200].indexOf(resp.status) < 0) { + console.error(`fetch feed returned status ${resp.status}`); + return null; + } try { const respJ = await resp.json(); From a13c7cbc22225dbd5f184356bcd5d656ce8e329e Mon Sep 17 00:00:00 2001 From: Yusur Princeps Date: Wed, 17 Sep 2025 14:00:59 +0200 Subject: [PATCH 02/13] cleanup + fix feed --- package.json | 2 +- src/lib/MetaNav.svelte | 6 +++++- src/lib/backend.ts | 4 ++-- src/routes/+page.svelte | 19 ++++++++++--------- src/routes/user/[id]/+page.ts | 1 - 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 0735b89..c8e971d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@yusurko/vigil", "private": true, - "version": "0.1.0-dev36", + "version": "0.1.0-dev37", "type": "module", "scripts": { "dev": "vite dev", diff --git a/src/lib/MetaNav.svelte b/src/lib/MetaNav.svelte index 31448ca..217bf43 100644 --- a/src/lib/MetaNav.svelte +++ b/src/lib/MetaNav.svelte @@ -6,7 +6,7 @@ let { user } : {user: UserEntry} = $props(); - +let enable_search = $state(false); @@ -14,6 +14,7 @@ let { user } : {user: UserEntry} = $props();
    • + {#if enable_search}
    • {#if user}
    • diff --git a/src/lib/backend.ts b/src/lib/backend.ts index c870c2e..d0f46d4 100644 --- a/src/lib/backend.ts +++ b/src/lib/backend.ts @@ -48,8 +48,7 @@ export class Backend { } async fetch(url: string, options?: RequestInit) { - console.info(`fetch ${Backend.ENDPOINT_BASE}/${encodeURIComponent(url)}`) - return await fetch(`${Backend.ENDPOINT_BASE}/${encodeURIComponent(url)}`, options); + return await fetch(`${Backend.ENDPOINT_BASE}/${url.replace(/^\/+/, '')}`, options); } withEvent(event: any) { @@ -76,6 +75,7 @@ class EventBackend extends Backend { } async fetch(url: string, options?: RequestInit): Promise { + console.debug(`fetch ${Backend.ENDPOINT_BASE}/${url.replace(/^\/+/, '')}`); return await this.event.fetch(`${Backend.ENDPOINT_BASE}/${url.replace(/^\/+/, '')}`, options); } } diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index c7a0c4b..b4cfb46 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -7,22 +7,23 @@ let me = getMe(); let { data } : { data: { feed: PostEntry[] } } = $props(); - let feed: PostEntry[] = $state([]); + let feed: PostEntry[] = $state(Array.prototype.slice.call(data.feed, 0)); let feedIndex = $state(0); - $effect(() => { - if (me && feed) { - feed.push(...data.feed.slice(feedIndex)); - feedIndex += feed.length; - } else if (me) { - console.log('feed is', feed) - } - }); + // $effect(() => { + // if (me && data?.feed) { + // feed.push(...data.feed.slice(feedIndex)); + // feedIndex += feed.length; + // } else if (me) { + // console.log('data.feed is', data?.feed) + // } + // }); {#if me} + {#snippet left()} ... {/snippet} diff --git a/src/routes/user/[id]/+page.ts b/src/routes/user/[id]/+page.ts index 80b4089..9b53c98 100644 --- a/src/routes/user/[id]/+page.ts +++ b/src/routes/user/[id]/+page.ts @@ -16,7 +16,6 @@ export async function load(event) { const respJ = await resp.json(); let { users } = respJ; - console.log(users); if (users[id]) { if (users[id].username) { redirect(302, "/@" +users[id].username ); From 55455c1693218b1efeec0fd813a501f079878efa Mon Sep 17 00:00:00 2001 From: Yusur Princeps Date: Tue, 7 Oct 2025 09:36:42 +0200 Subject: [PATCH 03/13] add top guilds --- package.json | 2 +- src/lib/HomeMenu.svelte | 10 ++++++ src/lib/UserAbout.svelte | 7 +++-- src/lib/backend.ts | 4 ++- src/routes/+page.svelte | 66 ++++++++++++++++++++++++---------------- src/routes/+page.ts | 27 +++++++++++++--- 6 files changed, 82 insertions(+), 34 deletions(-) create mode 100644 src/lib/HomeMenu.svelte diff --git a/package.json b/package.json index c8e971d..11df13e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@yusurko/vigil", "private": true, - "version": "0.1.0-dev37", + "version": "0.1.0-dev40", "type": "module", "scripts": { "dev": "vite dev", diff --git a/src/lib/HomeMenu.svelte b/src/lib/HomeMenu.svelte new file mode 100644 index 0000000..6f2baa4 --- /dev/null +++ b/src/lib/HomeMenu.svelte @@ -0,0 +1,10 @@ + + + diff --git a/src/lib/UserAbout.svelte b/src/lib/UserAbout.svelte index e050fba..b6df1f0 100644 --- a/src/lib/UserAbout.svelte +++ b/src/lib/UserAbout.svelte @@ -1,7 +1,7 @@ {#if me} - + - {#snippet left()} - ... - {/snippet} + {#snippet left()} + + {/snippet} - {#snippet right()} - ... - {/snippet} + {#snippet right()} + {#if top_guilds} + +
        + {#each top_guilds as gu} +
      • + +{gu.name} - + {gu.post_count ?? 0} posts - + {gu.subscriber_count ?? 0} subscribers +
      • + {/each} +
      +
      + {/if} + {/snippet}
      {:else} -

      {appName()} is a social media platform made by people like you.
      - Log in or (sign up) to see {activePostCount()} posts and talk with {activeUserCount()} users right now!

      +

      {appName()} is a social media platform made by people like you.
      + Log in or (sign up) to see {activePostCount()} posts and talk with {activeUserCount()} users right now!

      {/if} diff --git a/src/routes/+page.ts b/src/routes/+page.ts index 0d51905..a1f2924 100644 --- a/src/routes/+page.ts +++ b/src/routes/+page.ts @@ -1,4 +1,4 @@ -import { backend, type PostEntry } from '$lib/backend.js'; +import { backend, type GuildEntry, type PostEntry } from '$lib/backend.js'; import { getMe } from '$lib/globals.svelte.js'; import type { LoadEvent } from '@sveltejs/kit'; @@ -19,16 +19,35 @@ async function loadFeed (event: LoadEvent): Promise { } catch (e) { return null; } - } -export async function load(event): Promise<{feed: PostEntry[] | null}> { +async function loadTopGuilds (event: LoadEvent): Promise { + const resp = await backend.withEvent(event).fetch('top/guilds'); + + if ([200].indexOf(resp.status) < 0) { + console.error(`fetch top_guilds returned status ${resp.status}`); + return null; + } + try { + const respJ = await resp.json(); + + const { has: top_guilds } : { has: GuildEntry[] } = respJ; + console.log('top_guilds is', top_guilds); + return top_guilds; + } catch (e) { + return null; + } +} + +export async function load(event): Promise<{feed: PostEntry[] | null, top_guilds?: GuildEntry[] | null}> { let feed = null; let me = getMe(); + let top_guilds = null; if (me) { feed = await loadFeed(event); + top_guilds = await loadTopGuilds(event); } - return { feed }; + return { feed, top_guilds }; } \ No newline at end of file From cd92a4b12ef17a4014c6cb170c2e1dc4ba02c646 Mon Sep 17 00:00:00 2001 From: Yusur Princeps Date: Tue, 7 Oct 2025 11:46:05 +0200 Subject: [PATCH 04/13] add upvote count, fix loading issues --- src/lib/FullPost.svelte | 18 +++++++++++++++++ src/lib/VoteButton.svelte | 41 +++++++++++++++++++++++++++++++++++++++ src/lib/globals.svelte.ts | 3 +++ src/routes/+page.ts | 9 ++++++++- 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/lib/VoteButton.svelte diff --git a/src/lib/FullPost.svelte b/src/lib/FullPost.svelte index 0eeb0be..142b0e4 100644 --- a/src/lib/FullPost.svelte +++ b/src/lib/FullPost.svelte @@ -10,6 +10,7 @@ import PostMeta from "./PostMeta.svelte"; import GuildMenu from "./GuildMenu.svelte"; import { SvelteShowdown } from "svelte-showdown"; + import VoteButton from "./VoteButton.svelte"; @@ -32,6 +33,7 @@ let { title, created_at, id, content = '', to } = post;
    +
    @@ -56,7 +58,23 @@ let { title, created_at, id, content = '', to } = post; \ No newline at end of file diff --git a/src/lib/VoteButton.svelte b/src/lib/VoteButton.svelte new file mode 100644 index 0000000..56e5ac5 --- /dev/null +++ b/src/lib/VoteButton.svelte @@ -0,0 +1,41 @@ + + +
    + {#if vote > 0} + + {:else} + + {/if} + + {score ?? '-'} + + {#if vote > 0} + + {:else} + + {/if} +
    + + + diff --git a/src/lib/globals.svelte.ts b/src/lib/globals.svelte.ts index b75c147..26db889 100644 --- a/src/lib/globals.svelte.ts +++ b/src/lib/globals.svelte.ts @@ -47,3 +47,6 @@ export function activeUserCount (): number{ return health.user_count || 0; } +export async function sleep (ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)); +} \ No newline at end of file diff --git a/src/routes/+page.ts b/src/routes/+page.ts index a1f2924..b800451 100644 --- a/src/routes/+page.ts +++ b/src/routes/+page.ts @@ -1,7 +1,8 @@ import { backend, type GuildEntry, type PostEntry } from '$lib/backend.js'; -import { getMe } from '$lib/globals.svelte.js'; +import { getMe, sleep } from '$lib/globals.svelte.js'; import type { LoadEvent } from '@sveltejs/kit'; +let isFirstLoad = false; async function loadFeed (event: LoadEvent): Promise { const resp = await backend.withEvent(event).fetch('home/feed'); @@ -40,6 +41,12 @@ async function loadTopGuilds (event: LoadEvent): Promise { } export async function load(event): Promise<{feed: PostEntry[] | null, top_guilds?: GuildEntry[] | null}> { + // delay loading after layout + if (!isFirstLoad) { + await sleep(2000); + isFirstLoad = true; + } + let feed = null; let me = getMe(); let top_guilds = null; From c33ab48225aa475d5ac26923f08657c28e685878 Mon Sep 17 00:00:00 2001 From: Yusur Princeps Date: Sat, 11 Oct 2025 20:14:07 +0200 Subject: [PATCH 05/13] add guild info in post, report and edit button --- src/lib/FullPost.svelte | 11 ++++++++++- src/lib/PostMeta.svelte | 4 ++-- src/routes/[x+3d][id]/+page.ts | 19 +++++++++++++++---- static/favicon.ico | Bin 0 -> 318 bytes 4 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 static/favicon.ico diff --git a/src/lib/FullPost.svelte b/src/lib/FullPost.svelte index 142b0e4..82a2dba 100644 --- a/src/lib/FullPost.svelte +++ b/src/lib/FullPost.svelte @@ -1,7 +1,7 @@ @@ -36,6 +39,12 @@ let { title, created_at, id, content = '', to } = post;
      + {#if me && me.id !== post.author?.id} +
    • Report
    • + {/if} + {#if me && me.id === post.author?.id } +
    • Edit
    • + {/if}
    diff --git a/src/lib/PostMeta.svelte b/src/lib/PostMeta.svelte index 48e2905..1462428 100644 --- a/src/lib/PostMeta.svelte +++ b/src/lib/PostMeta.svelte @@ -1,5 +1,5 @@ @@ -7,4 +7,7 @@
  • Home
  • +
  • + Settings +
  • diff --git a/src/lib/backend.ts b/src/lib/backend.ts index 5626c43..e36d983 100644 --- a/src/lib/backend.ts +++ b/src/lib/backend.ts @@ -39,7 +39,8 @@ export type ServerHealth = { post_count: number, user_count: number, me: string | null, - csrf_token?: string + csrf_token?: string, + color_theme?: number }; diff --git a/src/lib/globals.svelte.ts b/src/lib/globals.svelte.ts index 26db889..984b82f 100644 --- a/src/lib/globals.svelte.ts +++ b/src/lib/globals.svelte.ts @@ -3,21 +3,23 @@ import type { ServerHealth, UserEntry } from "$lib/backend"; let health : { app_name: string, version: string, post_count: number, - user_count: number, me: null | UserEntry + user_count: number, me: null | UserEntry, color_theme: number } = $state({ app_name: 'app_name', version: "?.?", post_count: NaN, user_count: NaN, - me: null + me: null, + color_theme: 0 }); -export function setHealth ({ name, version, post_count, user_count }: ServerHealth) { +export function setHealth ({ name, version, post_count, user_count, color_theme = 0 }: ServerHealth) { health.app_name = name; health.version = version; health.post_count = post_count; health.user_count = user_count; + health.color_theme = color_theme; } @@ -49,4 +51,8 @@ export function activeUserCount (): number{ export async function sleep (ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)); +} + +export function getColorThemeCode (): number { + return health.color_theme; } \ No newline at end of file diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 548a9ee..ff7f53f 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,4 +1,5 @@ @@ -30,23 +36,26 @@ const flash = getFlash(page); -
    -

    - {appName()} -

    - - -
    + +
    +

    + {appName()} +

    + + +
    -
    - {#if $flash} - - {/if} +
    + {#if $flash} + + {/if} - {@render children()} -
    + {@render children()} +
    + + +
    - \ No newline at end of file diff --git a/src/lib/MetaNav.svelte b/src/lib/MetaNav.svelte index 217bf43..9b9d224 100644 --- a/src/lib/MetaNav.svelte +++ b/src/lib/MetaNav.svelte @@ -6,7 +6,7 @@ let { user } : {user: UserEntry} = $props(); -let enable_search = $state(false); +let enable_search = $derived(user !== null); @@ -19,7 +19,7 @@ let enable_search = $state(false); method="POST" class="mini-search-bar nomobile"> - + @@ -98,7 +98,7 @@ let enable_search = $state(false); overflow: hidden; } -.mini-search-bar + a {display: none} + diff --git a/src/lib/SLayout.svelte b/src/lib/SLayout.svelte index 5bff0d2..4530590 100644 --- a/src/lib/SLayout.svelte +++ b/src/lib/SLayout.svelte @@ -2,18 +2,21 @@ import { RiInformationLine, RiMenu3Line, RiShieldLine } from "svelte-remixicon"; let { children, title, left, right } = $props(); + +let mobiLeftActive = $state(false); +let mobiRightActive = $state(false);
    {title}
    -
    {@render left()}
    +
    {@render left()}
    {@render children()}
    -
    {@render right()}
    +
    {@render right()}
    -
    {}}>
    -
    {}}>
    +
    {mobiLeftActive = !mobiLeftActive;}}>
    +
    {mobiRightActive = !mobiRightActive;}}>
    \ No newline at end of file diff --git a/src/lib/UserMenu.svelte b/src/lib/UserMenu.svelte index 17f7d3a..0733732 100644 --- a/src/lib/UserMenu.svelte +++ b/src/lib/UserMenu.svelte @@ -1,11 +1,12 @@
    \ No newline at end of file From f6cb4fed12925401411ed47ae7a34375abe87f0a Mon Sep 17 00:00:00 2001 From: Yusur Princeps Date: Tue, 21 Oct 2025 14:32:16 +0200 Subject: [PATCH 09/13] add mock settings page --- src/routes/settings/+layout.svelte | 21 +++++++++++++++++++++ src/routes/settings/+page.svelte | 2 ++ src/routes/settings/appearance/+page.svelte | 2 ++ 3 files changed, 25 insertions(+) create mode 100644 src/routes/settings/+layout.svelte create mode 100644 src/routes/settings/+page.svelte create mode 100644 src/routes/settings/appearance/+page.svelte diff --git a/src/routes/settings/+layout.svelte b/src/routes/settings/+layout.svelte new file mode 100644 index 0000000..e785cb1 --- /dev/null +++ b/src/routes/settings/+layout.svelte @@ -0,0 +1,21 @@ + + + + + + {@render children()} + {#snippet left()} +
      + +
    + {/snippet} + {#snippet right()} + + {/snippet} +
    \ No newline at end of file diff --git a/src/routes/settings/+page.svelte b/src/routes/settings/+page.svelte new file mode 100644 index 0000000..5254392 --- /dev/null +++ b/src/routes/settings/+page.svelte @@ -0,0 +1,2 @@ + +Select a setting from the left menu to change its settings \ No newline at end of file diff --git a/src/routes/settings/appearance/+page.svelte b/src/routes/settings/appearance/+page.svelte new file mode 100644 index 0000000..265b473 --- /dev/null +++ b/src/routes/settings/appearance/+page.svelte @@ -0,0 +1,2 @@ + +TODO \ No newline at end of file From 792cce7973aded30836f337304d7bcd119bff5bd Mon Sep 17 00:00:00 2001 From: Yusur Princeps Date: Wed, 22 Oct 2025 11:58:43 +0200 Subject: [PATCH 10/13] add register page stub --- src/app.html | 4 +++ src/routes/+page.svelte | 4 +-- src/routes/login/+page.svelte | 3 +- src/routes/register/+page.svelte | 50 ++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 src/routes/register/+page.svelte diff --git a/src/app.html b/src/app.html index 2ac9833..ae88168 100644 --- a/src/app.html +++ b/src/app.html @@ -234,6 +234,10 @@ button.card { border-radius: 1em; } +:disabled { + opacity: .5; +} + article h1, article h2 { font-weight: 500; } diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index e5842b3..4472a30 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -29,7 +29,7 @@ {#snippet left()} {/snippet} - + {#snippet right()} {#if top_guilds} @@ -49,7 +49,7 @@ {:else}

    {appName()} is a social media platform made by people like you.
    - Log in or (sign up) to see {activePostCount()} posts and talk with {activeUserCount()} users right now!

    + Log in or sign up to see {activePostCount()} posts and talk with {activeUserCount()} users right now!

    {/if} diff --git a/src/routes/login/+page.svelte b/src/routes/login/+page.svelte index 4ef3ad4..59736d8 100644 --- a/src/routes/login/+page.svelte +++ b/src/routes/login/+page.svelte @@ -14,7 +14,7 @@
    diff --git a/src/routes/register/+page.svelte b/src/routes/register/+page.svelte new file mode 100644 index 0000000..4195c82 --- /dev/null +++ b/src/routes/register/+page.svelte @@ -0,0 +1,50 @@ + + + + +
    + + + ... + + +
    +
    +
    + + + \ No newline at end of file From 4f816c9066d228d35654f77691ed553563abd425 Mon Sep 17 00:00:00 2001 From: Yusur Princeps Date: Wed, 22 Oct 2025 13:55:19 +0200 Subject: [PATCH 11/13] add create stub --- src/routes/create/+page.svelte | 69 ++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/routes/create/+page.svelte diff --git a/src/routes/create/+page.svelte b/src/routes/create/+page.svelte new file mode 100644 index 0000000..403f7da --- /dev/null +++ b/src/routes/create/+page.svelte @@ -0,0 +1,69 @@ + + + +{#if me} + +
    +

    Posting as @{me.username}

    + + + + + + +
    + + {#snippet left()} + ... + {/snippet} + + {#snippet right()} + ... + {/snippet} +
    +{:else} + + You must be logged in in order to create posts. + +{/if} + + \ No newline at end of file From 58d6a248c7a341e76a9caa94c6a3a482375648ca Mon Sep 17 00:00:00 2001 From: Yusur Princeps Date: Wed, 22 Oct 2025 15:09:10 +0200 Subject: [PATCH 12/13] add ul.grid, improve /create and SLayout --- src/app.html | 20 ++++++++++++ src/lib/GuildSelect.svelte | 54 +++++++++++++++++++++++++++++++ src/lib/PrivacySelect.svelte | 59 ++++++++++++++++++++++++++++++++++ src/lib/SLayout.svelte | 8 ++--- src/routes/create/+page.svelte | 58 ++++++++++++++++++++------------- 5 files changed, 172 insertions(+), 27 deletions(-) create mode 100644 src/lib/GuildSelect.svelte create mode 100644 src/lib/PrivacySelect.svelte diff --git a/src/app.html b/src/app.html index ae88168..5265380 100644 --- a/src/app.html +++ b/src/app.html @@ -187,6 +187,26 @@ ul.column { padding: 0; } +ul.grid { + list-style: none; + padding: 0; + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + grid-template-rows: auto; +} + +ul.grid > li { + border: 1px solid var(--border); + border-radius: .5em; + padding: .5em; + margin: 1em .5em; + text-align: center; +} + +ul.grid > li small { + display: block; +} + a svg { text-decoration: none; } diff --git a/src/lib/GuildSelect.svelte b/src/lib/GuildSelect.svelte new file mode 100644 index 0000000..12c07c4 --- /dev/null +++ b/src/lib/GuildSelect.svelte @@ -0,0 +1,54 @@ + + + +
    + +
      + {#each suggestions as sug} +
    • + {:else} +
    • + +{value} +
    • + {/each} + +
    +
    + + + diff --git a/src/lib/PrivacySelect.svelte b/src/lib/PrivacySelect.svelte new file mode 100644 index 0000000..22057d6 --- /dev/null +++ b/src/lib/PrivacySelect.svelte @@ -0,0 +1,59 @@ + + +
      +
    • + +
    • +
    • + +
    • +
    • + +
    • +
    • + +
    • +
    + + diff --git a/src/lib/SLayout.svelte b/src/lib/SLayout.svelte index 4530590..a7bec54 100644 --- a/src/lib/SLayout.svelte +++ b/src/lib/SLayout.svelte @@ -46,14 +46,14 @@ let mobiRightActive = $state(false); .layout-licon, .layout-ricon { display: none; } } -@media (min-width: 800px) and (max-width: 919px) { +@media (min-width: 800px) and (max-width: 959px) { .layout-left, .layout-right { font-size: smaller; } } -@media (min-width: 920px) { +@media (min-width: 960px) { .layout { grid-template-columns: 240px auto 240px; } @@ -61,13 +61,13 @@ let mobiRightActive = $state(false); .layout-licon, .layout-ricon { display: none; } } -@media (min-width: 1000px) { +@media (min-width: 1080px) { .layout { grid-template-columns: 270px auto 270px; } } -@media (min-width: 1080px) { +@media (min-width: 1200px) { .layout { grid-template-columns: 300px auto 300px; } diff --git a/src/routes/create/+page.svelte b/src/routes/create/+page.svelte index 403f7da..16cb54d 100644 --- a/src/routes/create/+page.svelte +++ b/src/routes/create/+page.svelte @@ -1,11 +1,15 @@
      - {#each suggestions as sug} -
    • {:else}
    • +{value}
    • {/each} - + {:catch ex} +
    • + +{value} ({ex}) +
    • + {/await}
    @@ -46,7 +63,7 @@ let suggestions: GuildEntry[] = $state([]); border-bottom: 1px solid var(--border); } - :not(:focus) + ul { + :not(:focus) + ul:not(:active) { display: none; } diff --git a/src/lib/backend.ts b/src/lib/backend.ts index e36d983..92cbfdb 100644 --- a/src/lib/backend.ts +++ b/src/lib/backend.ts @@ -44,6 +44,32 @@ export type ServerHealth = { }; +// caches an oath (CSRF token) +class OathKeeper { + lastOath : number; + csrfToken: string | null; + + constructor () { + this.lastOath = 0; + this.csrfToken = null; + } + + set (tok: string) { + this.lastOath = +new Date; + this.csrfToken = tok; + } + + get () { + if (this.lastOath === 0 || +new Date() - this.lastOath > 1800000) { + // 30 minutes decay + return null; + } + return this.csrfToken; + } +} + +const oathKeeper = new OathKeeper(); + export class Backend { static ENDPOINT_BASE = '/v1'; @@ -60,33 +86,42 @@ export class Backend { } class EventBackend extends Backend { - event: any; + event: any | null; - constructor (event: any) { + constructor (event: any | null) { super(); this.event = event; } async oath (): Promise { - const resp = await this.fetch("oath"); - if (resp.status !== 200) { - throw new Error(); + let csrfToken = oathKeeper.get(); + if (!csrfToken) { + const resp = await this.fetch("oath"); + if (resp.status !== 200) { + throw new Error(); + } + const respJ = await resp.json(); + csrfToken = respJ.csrf_token; + } + if (!csrfToken) { + console.warn("csrf_token is null"); + } + else { + oathKeeper.set(csrfToken); } - const respJ = await resp.json(); - const { csrfToken } = respJ; return new CsrfEventBackend(this.event, csrfToken); } async fetch(url: string, options?: RequestInit): Promise { console.debug(`fetch ${Backend.ENDPOINT_BASE}/${url.replace(/^\/+/, '')}`); - return await this.event.fetch(`${Backend.ENDPOINT_BASE}/${url.replace(/^\/+/, '')}`, options); + return await (this.event?.fetch||fetch)(`${Backend.ENDPOINT_BASE}/${url.replace(/^\/+/, '')}`, options); } } class CsrfEventBackend extends EventBackend { - csrfToken: string; + csrfToken: string | null; - constructor(event:EventBackend, csrfToken: string) { + constructor(event: EventBackend | null, csrfToken: string | null) { super(event); this.csrfToken = csrfToken; } @@ -97,7 +132,7 @@ class CsrfEventBackend extends EventBackend { body: JSON.stringify(data), headers: { 'content-type': 'application/json', - 'x-csrftoken': this.csrfToken + 'x-csrftoken': this.csrfToken || "" } }); }