feat(skilltree): add central auth pages with shared components

- Add SkillTreeLogo to shared-branding (emerald green theme)
- Add login, register, forgot-password pages using shared-auth-ui
- Initialize authStore in layout alongside skillStore
- Add shared-auth-ui, shared-i18n, shared-branding dependencies
- German translations as default

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Till-JS 2026-01-29 13:55:22 +01:00
parent f3424c26aa
commit 51ec8f8419
11 changed files with 182 additions and 2 deletions

View file

@ -32,6 +32,9 @@
},
"dependencies": {
"@manacore/shared-auth": "workspace:*",
"@manacore/shared-auth-ui": "workspace:*",
"@manacore/shared-branding": "workspace:*",
"@manacore/shared-i18n": "workspace:*",
"@manacore/shared-icons": "workspace:*",
"@manacore/shared-tailwind": "workspace:*",
"@manacore/shared-theme": "workspace:*",

View file

@ -0,0 +1,30 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { ForgotPasswordPage } from '@manacore/shared-auth-ui';
import { getForgotPasswordTranslations } from '@manacore/shared-i18n';
import { SkillTreeLogo } from '@manacore/shared-branding';
import { authStore } from '$lib/stores/auth.svelte';
// Get translations (default to German for this app)
const translations = $derived(getForgotPasswordTranslations('de'));
async function handleForgotPassword(email: string) {
return authStore.resetPassword(email);
}
</script>
<svelte:head>
<title>{translations.titleForm} | SkillTree</title>
</svelte:head>
<ForgotPasswordPage
appName="SkillTree"
logo={SkillTreeLogo}
primaryColor="#10b981"
onForgotPassword={handleForgotPassword}
{goto}
loginPath="/login"
lightBackground="#d1fae5"
darkBackground="#064e3b"
{translations}
/>

View file

@ -0,0 +1,64 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { browser } from '$app/environment';
import { LoginPage } from '@manacore/shared-auth-ui';
import { getLoginTranslations } from '@manacore/shared-i18n';
import { SkillTreeLogo } from '@manacore/shared-branding';
import { authStore } from '$lib/stores/auth.svelte';
import { apiClient } from '$lib/api/client';
// Get redirect URL from query params or sessionStorage
const redirectTo = $derived.by(() => {
const queryRedirect = $page.url.searchParams.get('redirectTo');
if (queryRedirect) return queryRedirect;
if (browser) {
const sessionRedirect = sessionStorage.getItem('auth-return-url');
if (sessionRedirect) {
sessionStorage.removeItem('auth-return-url');
return sessionRedirect;
}
}
return '/';
});
// Get translations (default to German for this app)
const translations = $derived(getLoginTranslations('de'));
// Read verification status from query params
const verified = $derived($page.url.searchParams.get('verified') === 'true');
const initialEmail = $derived($page.url.searchParams.get('email') || '');
async function handleSignIn(email: string, password: string) {
const result = await authStore.signIn(email, password);
if (result.success) {
const token = await authStore.getValidToken();
apiClient.setAccessToken(token);
}
return result;
}
</script>
<svelte:head>
<title>{translations.title} | SkillTree</title>
</svelte:head>
<LoginPage
appName="SkillTree"
logo={SkillTreeLogo}
primaryColor="#10b981"
onSignIn={handleSignIn}
{goto}
enableGoogle={false}
enableApple={false}
successRedirect={redirectTo}
registerPath="/register"
forgotPasswordPath="/forgot-password"
lightBackground="#d1fae5"
darkBackground="#064e3b"
{translations}
{verified}
{initialEmail}
/>

View file

@ -0,0 +1,44 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { browser } from '$app/environment';
import { RegisterPage } from '@manacore/shared-auth-ui';
import { getRegisterTranslations } from '@manacore/shared-i18n';
import { SkillTreeLogo } from '@manacore/shared-branding';
import { authStore } from '$lib/stores/auth.svelte';
// Get redirect URL from sessionStorage
const redirectTo = $derived.by(() => {
if (browser) {
const sessionRedirect = sessionStorage.getItem('auth-return-url');
if (sessionRedirect) {
sessionStorage.removeItem('auth-return-url');
return sessionRedirect;
}
}
return '/';
});
// Get translations (default to German for this app)
const translations = $derived(getRegisterTranslations('de'));
async function handleSignUp(email: string, password: string) {
return authStore.signUp(email, password);
}
</script>
<svelte:head>
<title>{translations.title} | SkillTree</title>
</svelte:head>
<RegisterPage
appName="SkillTree"
logo={SkillTreeLogo}
primaryColor="#10b981"
onSignUp={handleSignUp}
{goto}
successRedirect={redirectTo}
loginPath="/login"
lightBackground="#d1fae5"
darkBackground="#064e3b"
{translations}
/>

View file

@ -2,13 +2,14 @@
import '../app.css';
import { onMount } from 'svelte';
import { skillStore } from '$lib/stores/skills.svelte';
import { authStore } from '$lib/stores/auth.svelte';
let { children } = $props();
let loading = $state(true);
onMount(async () => {
await skillStore.initialize();
await Promise.all([authStore.initialize(), skillStore.initialize()]);
loading = false;
});
</script>