beeeeg update
Some checks failed
Test and deploy staging / staging (push) Has been cancelled

This commit is contained in:
2026-09-23 04:15:10 +00:00
parent 487eff5bb2
commit d0c7b6548b
135 changed files with 9531 additions and 1777 deletions

View File

@@ -0,0 +1,13 @@
import { auth, authProviders } from '$lib/server/auth';
import { redirect } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ locals, request, url }) => {
if (!locals.user) redirect(303, '/login?returnTo=/account');
const accounts = await auth.api.listUserAccounts({ headers: request.headers });
return {
email: locals.user.email.endsWith('@osu.invalid') ? null : locals.user.email,
providers: authProviders,
linkedProviders: accounts.map((account) => account.providerId),
oauthError: url.searchParams.has('error')
};
};

View File

@@ -0,0 +1,72 @@
<script lang="ts">
import { resolve } from '$app/paths';
import { authClient } from '$lib/auth-client';
import type { PageProps } from './$types';
let { data }: PageProps = $props();
let busy = $state(false);
let message = $state('');
async function link(provider: 'google' | 'osu') {
busy = true;
message = '';
try {
const result = await authClient.linkSocial({
provider,
callbackURL: '/account',
errorCallbackURL: '/account'
});
if (result.error) {
message = result.error.message || 'Could not link this account.';
busy = false;
}
} catch {
message = 'Could not connect. Please try again.';
busy = false;
}
}
</script>
<section class="mx-auto max-w-xl p-6 space-y-6">
<div>
<h1 class="text-2xl font-bold">Your account</h1>
<p class="mt-2">Signed in as {data.user?.name}{data.email ? ` (${data.email})` : ''}.</p>
</div>
<p class="text-sm text-gray-500">Account ID: <code>{data.user?.id}</code></p>
<div class="rounded border p-4 space-y-3">
<h2 class="font-bold">Sign-in methods</h2>
<p class="text-sm text-gray-600">
Link a provider here to use it with this account and keep your saved progress together.
</p>
{#if message || data.oauthError}<p role="alert" class="text-red-700">
{message ||
'Linking failed or was cancelled. The provider may already belong to another account.'}
</p>{/if}
{#if data.linkedProviders.includes('credential')}<p>Email and password connected</p>{/if}
{#each ['google', 'osu'] as provider (provider)}
{@const label = provider === 'google' ? 'Google' : 'osu!'}
{#if data.linkedProviders.includes(provider)}<p>{label} connected</p>
{:else if data.providers[provider as 'google' | 'osu']}<button
class="block rounded border px-4 py-2 disabled:opacity-50"
disabled={busy}
onclick={() => link(provider as 'google' | 'osu')}>Connect {label}</button
>{/if}
{/each}
</div>
{#if data.isAdmin}
<div class="rounded border p-4 space-y-3">
<h2 class="font-bold">Administration</h2>
<div class="flex flex-wrap gap-4">
<a class="underline" href={resolve('/blog')}>Blog articles</a><a
class="underline"
href={resolve('/lists')}>Lists</a
><a class="underline" href={resolve('/projects/animaldex/admin')}>Animaldex moderation</a><a
class="underline"
href={resolve('/projects/progress')}>Progress</a
>
</div>
</div>
{/if}
<form method="POST" action="/logout">
<button class="rounded border px-4 py-2">Log out</button>
</form>
</section>