diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte index 2baa443..f37ecbb 100644 --- a/frontend/src/App.svelte +++ b/frontend/src/App.svelte @@ -14,6 +14,7 @@ import Admin from './components/Admin.svelte'; import ActivityPermalink from './components/ActivityPermalink.svelte'; import Personvern from './components/Personvern.svelte'; + import TagPage from './components/TagPage.svelte'; /** * URL contract: @@ -22,6 +23,7 @@ * /a/:id — permalink to a single activity (any visibility) * //list — opt-in public list for that user * /personvern — privacy + how-it-works long-form page + * /tags/:tag — activities matching a tag, scoped to viewer visibility * * Anything else (signup, login, recovery, profile, feedback, admin) is an * in-app view state, not a URL. We update window.history on view changes @@ -35,17 +37,19 @@ | 'profile' | 'feedback' | 'admin' | 'public-list' // "//list" | 'permalink' // "/a/:id" - | 'personvern'; // "/personvern" + | 'personvern' // "/personvern" + | 'tag'; // "/tags/:tag" let view: View = $state('loading'); let publicListUsername = $state(''); let activityId = $state(''); + let tagName = $state(''); let defaultEmail = $state(''); let inviteToken = $state(''); let selfRegistryEnabled = $state(true); interface Route { - view: 'public-home' | 'home' | 'public-list' | 'permalink' | 'invite' | 'personvern'; + view: 'public-home' | 'home' | 'public-list' | 'permalink' | 'invite' | 'personvern' | 'tag'; payload?: string; } @@ -54,6 +58,18 @@ if (path === '/' || path === '') return { view: 'public-home' }; if (path === '/home' || path === '/home/') return { view: 'home' }; if (path === '/personvern' || path === '/personvern/') return { view: 'personvern' }; + // Tag pages: /tags/. We don't constrain charset here + // because tags allow spaces and any character (they're normalised + // server-side to lowercase + trim). decodeURIComponent below gets the + // visible value back. + const tagMatch = path.match(/^\/tags\/([^/]+)\/?$/); + if (tagMatch) { + try { + return { view: 'tag', payload: decodeURIComponent(tagMatch[1]!) }; + } catch { + return { view: 'public-home' }; + } + } const userList = path.match(/^\/([a-z0-9_-]{2,31})\/list\/?$/); if (userList) return { view: 'public-list', payload: userList[1] }; const perma = path.match(/^\/a\/([A-Za-z0-9-]+)\/?$/); @@ -128,9 +144,18 @@ view = session.user ? 'public-home' : 'signup'; } else if (route.view === 'personvern') { view = 'personvern'; + } else if (route.view === 'tag') { + tagName = route.payload ?? tagName; + view = 'tag'; } } + function leaveTag() { + // Same logic as leavePersonvern — back to wherever they were. + if (session.user) goHome(); + else goPublicHome(); + } + function goPersonvern() { pushUrl('/personvern'); view = 'personvern'; @@ -171,7 +196,7 @@ { e.preventDefault(); goPublicHome(); }} style="color: inherit; text-decoration: none;">Vinterliste - {#if view !== 'public-list' && view !== 'permalink'} + {#if view !== 'public-list' && view !== 'permalink' && view !== 'tag'}
{#if session.user} {#if view !== 'home'} @@ -230,6 +255,8 @@ {:else if view === 'personvern'} + {:else if view === 'tag'} + {:else} {/if} diff --git a/frontend/src/components/ActivityRow.svelte b/frontend/src/components/ActivityRow.svelte index c0f9276..00cf323 100644 --- a/frontend/src/components/ActivityRow.svelte +++ b/frontend/src/components/ActivityRow.svelte @@ -206,7 +206,10 @@ {/if} {#if decrypted.tags.length}
- {#each decrypted.tags as t}{t}{/each} + {#each decrypted.tags as t} + {t} + {/each}
{/if} {#if decrypted.loc_label} @@ -236,7 +239,10 @@ {/if} {#if activity.tags.length}
- {#each activity.tags as t}{t}{/each} + {#each activity.tags as t} + {t} + {/each}
{/if} {#if activity.loc_label} diff --git a/frontend/src/components/Profile.svelte b/frontend/src/components/Profile.svelte index b2f87da..99eac75 100644 --- a/frontend/src/components/Profile.svelte +++ b/frontend/src/components/Profile.svelte @@ -185,8 +185,8 @@

- Vises på offentlige aktiviteter du legger til. La være tomt for å bruke - delen av eposten din før @. + Vises på offentlige aktiviteter du legger til. Er feltet tomt og du har + satt et brukernavn, brukes det i stedet. Ellers vises ingen attribusjon.

diff --git a/frontend/src/components/TagPage.svelte b/frontend/src/components/TagPage.svelte new file mode 100644 index 0000000..17757ce --- /dev/null +++ b/frontend/src/components/TagPage.svelte @@ -0,0 +1,114 @@ + + +
+ {#if onBack} +
+ +
+ {/if} + +

+ Etikett: {needle} +

+

+ {#if session.user} + Aktiviteter med denne etiketten du har tilgang til — egne private, + offentlige, anonyme, og fra venner. + {:else} + Offentlige og anonyme aktiviteter med denne etiketten. + {/if} +

+ + {#if loading} +

Laster …

+ {:else if error} +

{error}

+ {:else if matched.length === 0} +

Ingen aktiviteter med denne etiketten ennå.

+ {:else} + {#each matched as a (a.id)} + + {/each} + {/if} +