mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 23:01:09 +02:00
feat(mana-games): add auth, settings, themes, help, submit, and onboarding pages
Adds login/register/forgot-password auth routes using shared-auth-ui, settings page with theme/language/account controls, themes browser, help page, community submit form, profile, and app onboarding modal. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
732f2b8edd
commit
0806600bc0
14 changed files with 602 additions and 0 deletions
|
|
@ -0,0 +1,41 @@
|
|||
import { createAppOnboardingStore, type AppOnboardingStep } from '@manacore/shared-app-onboarding';
|
||||
import { userSettings } from './user-settings.svelte';
|
||||
|
||||
const onboardingSteps: AppOnboardingStep[] = [
|
||||
{
|
||||
id: 'features',
|
||||
type: 'info',
|
||||
question: 'Willkommen bei Mana Games!',
|
||||
description: 'Das erwartet dich:',
|
||||
emoji: '🎮',
|
||||
gradient: { from: 'green-500', to: 'green-700' },
|
||||
bullets: [
|
||||
'22+ Browser-Spiele direkt spielbar',
|
||||
'KI-Spielgenerator: Erstelle eigene Games',
|
||||
'Statistiken: Highscores & Spielzeit',
|
||||
'Community: Reiche eigene Spiele ein',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'welcome',
|
||||
type: 'info',
|
||||
question: "Los geht's!",
|
||||
description: 'Tipps:',
|
||||
emoji: '🕹️',
|
||||
gradient: { from: 'primary', to: 'primary/70' },
|
||||
bullets: [
|
||||
'Cmd/Ctrl+K für Schnellsuche',
|
||||
'Spiele laufen komplett im Browser',
|
||||
'Stats werden lokal gespeichert',
|
||||
'Anmelden synchronisiert deine Daten',
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const gamesOnboarding = createAppOnboardingStore({
|
||||
appId: 'mana-games',
|
||||
steps: onboardingSteps,
|
||||
userSettings,
|
||||
onComplete: async () => {},
|
||||
onSkip: async () => {},
|
||||
});
|
||||
|
|
@ -26,6 +26,8 @@
|
|||
import { setLocale, supportedLocales } from '$lib/i18n';
|
||||
import { SessionExpiredBanner, AuthGate, GuestWelcomeModal } from '@manacore/shared-auth-ui';
|
||||
import { shouldShowGuestWelcome } from '@manacore/shared-auth-ui';
|
||||
import { gamesOnboarding } from '$lib/stores/app-onboarding.svelte';
|
||||
import { MiniOnboardingModal } from '@manacore/shared-app-onboarding';
|
||||
import { gamesStore } from '$lib/data/local-store';
|
||||
import {
|
||||
tagLocalStore,
|
||||
|
|
@ -241,6 +243,10 @@
|
|||
/>
|
||||
</div>
|
||||
|
||||
{#if gamesOnboarding.shouldShow}
|
||||
<MiniOnboardingModal store={gamesOnboarding} appName="Mana Games" appEmoji="🎮" />
|
||||
{/if}
|
||||
|
||||
<GuestWelcomeModal
|
||||
appId="mana-games"
|
||||
visible={showGuestWelcome}
|
||||
|
|
|
|||
47
games/mana-games/apps/web/src/routes/(app)/help/+page.svelte
Normal file
47
games/mana-games/apps/web/src/routes/(app)/help/+page.svelte
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<svelte:head>
|
||||
<title>Hilfe - Mana Games</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="max-w-2xl mx-auto space-y-6">
|
||||
<h1 class="text-2xl font-bold text-foreground">Hilfe</h1>
|
||||
|
||||
<section class="space-y-4">
|
||||
<div class="rounded-xl border border-border bg-card p-4">
|
||||
<h2 class="font-semibold text-foreground mb-2">Wie spiele ich?</h2>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Wähle ein Spiel auf der Startseite aus und klicke darauf. Das Spiel läuft direkt im Browser.
|
||||
Die Steuerung wird auf der Spielseite angezeigt.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl border border-border bg-card p-4">
|
||||
<h2 class="font-semibold text-foreground mb-2">KI-Spielgenerator</h2>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Unter "Erstellen" kannst du eigene Spiele beschreiben und von verschiedenen KI-Modellen
|
||||
generieren lassen. Generierte Spiele werden lokal in deinem Browser gespeichert.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl border border-border bg-card p-4">
|
||||
<h2 class="font-semibold text-foreground mb-2">Statistiken</h2>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Deine Highscores, Spielzeiten und Fortschritte werden automatisch gespeichert. Melde dich
|
||||
an, um sie geräteübergreifend zu synchronisieren.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl border border-border bg-card p-4">
|
||||
<h2 class="font-semibold text-foreground mb-2">Tastaturkürzel</h2>
|
||||
<div class="grid grid-cols-2 gap-2 mt-2">
|
||||
{#each [['Cmd/Ctrl+K', 'Schnellsuche'], ['Esc', 'Suche schließen']] as [key, desc]}
|
||||
<div class="flex items-center gap-2">
|
||||
<kbd class="px-2 py-0.5 rounded bg-muted text-xs font-mono text-muted-foreground"
|
||||
>{key}</kbd
|
||||
>
|
||||
<span class="text-sm text-foreground">{desc}</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<svelte:head>
|
||||
<title>Mana - Mana Games</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="max-w-2xl mx-auto text-center py-12">
|
||||
<p class="text-4xl mb-4">💎</p>
|
||||
<h1 class="text-2xl font-bold text-foreground">Mana</h1>
|
||||
<p class="text-muted-foreground mt-2">Demnächst verfügbar.</p>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<script lang="ts">
|
||||
import { ProfilePage } from '@manacore/shared-profile-ui';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Profil - Mana Games</title>
|
||||
</svelte:head>
|
||||
|
||||
{#if authStore.isAuthenticated}
|
||||
<ProfilePage {authStore} {goto} />
|
||||
{:else}
|
||||
<div class="max-w-2xl mx-auto text-center py-12">
|
||||
<p class="text-muted-foreground">Bitte melde dich an.</p>
|
||||
<a href="/login" class="text-primary hover:underline mt-2 inline-block">Anmelden</a>
|
||||
</div>
|
||||
{/if}
|
||||
165
games/mana-games/apps/web/src/routes/(app)/settings/+page.svelte
Normal file
165
games/mana-games/apps/web/src/routes/(app)/settings/+page.svelte
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
<script lang="ts">
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { locale } from 'svelte-i18n';
|
||||
import { theme } from '$lib/stores/theme.svelte';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { setLocale, supportedLocales } from '$lib/i18n';
|
||||
import { goto } from '$app/navigation';
|
||||
import { gameStatsCollection } from '$lib/data/local-store';
|
||||
|
||||
async function clearStats() {
|
||||
const all = await gameStatsCollection.getAll();
|
||||
for (const stat of all) {
|
||||
await gameStatsCollection.remove(stat.id);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleLogout() {
|
||||
await authStore.signOut();
|
||||
goto('/login');
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{$_('nav.settings')} - Mana Games</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="settings-page">
|
||||
<header class="mb-8">
|
||||
<h1 class="text-2xl font-bold text-foreground">{$_('nav.settings')}</h1>
|
||||
<p class="text-muted-foreground text-sm mt-1">Passe Mana Games an deine Bedürfnisse an</p>
|
||||
</header>
|
||||
|
||||
<!-- Theme -->
|
||||
<section class="settings-section">
|
||||
<h2 class="text-lg font-bold text-foreground mb-4">Darstellung</h2>
|
||||
|
||||
<div class="setting-row">
|
||||
<div>
|
||||
<div class="setting-label">Farbmodus</div>
|
||||
<div class="setting-desc">Hell, Dunkel oder System</div>
|
||||
</div>
|
||||
<div class="flex gap-1">
|
||||
{#each ['light', 'dark', 'system'] as mode}
|
||||
<button
|
||||
class="px-3 py-1.5 text-sm rounded-lg transition-colors {theme.mode === mode
|
||||
? 'bg-primary text-primary-foreground'
|
||||
: 'bg-muted text-muted-foreground hover:bg-muted/80'}"
|
||||
onclick={() => theme.setMode(mode as 'light' | 'dark' | 'system')}
|
||||
>
|
||||
{mode === 'light' ? 'Hell' : mode === 'dark' ? 'Dunkel' : 'System'}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Language -->
|
||||
<section class="settings-section">
|
||||
<h2 class="text-lg font-bold text-foreground mb-4">Sprache</h2>
|
||||
|
||||
<div class="setting-row">
|
||||
<div>
|
||||
<div class="setting-label">App-Sprache</div>
|
||||
<div class="setting-desc">Sprache der Benutzeroberfläche</div>
|
||||
</div>
|
||||
<select
|
||||
value={$locale}
|
||||
onchange={(e) => setLocale((e.target as HTMLSelectElement).value as any)}
|
||||
class="h-9 px-3 rounded-lg bg-background border border-border text-foreground text-sm"
|
||||
>
|
||||
{#each supportedLocales as loc}
|
||||
<option value={loc}>{loc === 'de' ? 'Deutsch' : 'English'}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Account -->
|
||||
<section class="settings-section">
|
||||
<h2 class="text-lg font-bold text-foreground mb-4">Konto</h2>
|
||||
|
||||
{#if authStore.isAuthenticated}
|
||||
<div class="setting-row">
|
||||
<div>
|
||||
<div class="setting-label">Eingeloggt als</div>
|
||||
<div class="setting-desc">{authStore.user?.email}</div>
|
||||
</div>
|
||||
<button
|
||||
class="px-4 py-2 rounded-lg bg-red-500/10 text-red-400 hover:bg-red-500/20 transition-colors text-sm"
|
||||
onclick={handleLogout}
|
||||
>
|
||||
Abmelden
|
||||
</button>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="setting-row">
|
||||
<div>
|
||||
<div class="setting-label">Gast-Modus</div>
|
||||
<div class="setting-desc">Melde dich an, um Stats zu synchronisieren</div>
|
||||
</div>
|
||||
<a
|
||||
href="/login"
|
||||
class="px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90 transition-colors text-sm"
|
||||
>
|
||||
Anmelden
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<!-- Data -->
|
||||
<section class="settings-section">
|
||||
<h2 class="text-lg font-bold text-foreground mb-4">Daten</h2>
|
||||
|
||||
<div class="setting-row">
|
||||
<div>
|
||||
<div class="setting-label">Spielstatistiken löschen</div>
|
||||
<div class="setting-desc">Alle Highscores und Spielzeiten zurücksetzen</div>
|
||||
</div>
|
||||
<button
|
||||
class="px-4 py-2 rounded-lg bg-red-500/10 text-red-400 hover:bg-red-500/20 transition-colors text-sm"
|
||||
onclick={clearStats}
|
||||
>
|
||||
Löschen
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.settings-page {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.settings-section {
|
||||
margin-bottom: 2rem;
|
||||
padding-bottom: 2rem;
|
||||
border-bottom: 1px solid hsl(var(--border));
|
||||
}
|
||||
|
||||
.settings-section:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.setting-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
padding: 0.75rem 0;
|
||||
}
|
||||
|
||||
.setting-label {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
color: hsl(var(--foreground));
|
||||
}
|
||||
|
||||
.setting-desc {
|
||||
font-size: 0.75rem;
|
||||
color: hsl(var(--muted-foreground));
|
||||
margin-top: 2px;
|
||||
}
|
||||
</style>
|
||||
202
games/mana-games/apps/web/src/routes/(app)/submit/+page.svelte
Normal file
202
games/mana-games/apps/web/src/routes/(app)/submit/+page.svelte
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
<script lang="ts">
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
|
||||
const BACKEND_URL = import.meta.env.DEV
|
||||
? 'http://localhost:3011'
|
||||
: import.meta.env.PUBLIC_MANA_GAMES_BACKEND_URL || '';
|
||||
|
||||
let title = $state('');
|
||||
let description = $state('');
|
||||
let controls = $state('');
|
||||
let difficulty = $state<'Einfach' | 'Mittel' | 'Schwer'>('Mittel');
|
||||
let tags = $state('');
|
||||
let htmlCode = $state('');
|
||||
let authorName = $state('');
|
||||
let isSubmitting = $state(false);
|
||||
let submitResult = $state<{ success: boolean; message: string } | null>(null);
|
||||
|
||||
async function handleSubmit() {
|
||||
if (!title.trim() || !htmlCode.trim() || !authorName.trim()) return;
|
||||
|
||||
isSubmitting = true;
|
||||
submitResult = null;
|
||||
|
||||
try {
|
||||
const response = await fetch(`${BACKEND_URL}/api/games/submit`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
title,
|
||||
description,
|
||||
controls,
|
||||
difficulty,
|
||||
complexity: 'Mittel',
|
||||
tags: tags
|
||||
.split(',')
|
||||
.map((t) => t.trim())
|
||||
.filter(Boolean),
|
||||
author: { name: authorName },
|
||||
files: { html: htmlCode },
|
||||
submittedAt: new Date().toISOString(),
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
submitResult = {
|
||||
success: data.success,
|
||||
message: data.success
|
||||
? `Eingereicht! PR #${data.prNumber} erstellt.`
|
||||
: data.error || 'Fehler beim Einreichen.',
|
||||
};
|
||||
|
||||
if (data.success) {
|
||||
title = '';
|
||||
description = '';
|
||||
controls = '';
|
||||
tags = '';
|
||||
htmlCode = '';
|
||||
}
|
||||
} catch {
|
||||
submitResult = { success: false, message: 'Verbindungsfehler zum Backend.' };
|
||||
} finally {
|
||||
isSubmitting = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Spiel einreichen - Mana Games</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="max-w-2xl mx-auto space-y-6">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-foreground">Spiel einreichen</h1>
|
||||
<p class="text-muted-foreground mt-1">Reiche dein eigenes HTML5-Spiel bei der Community ein.</p>
|
||||
</div>
|
||||
|
||||
{#if !authStore.isAuthenticated}
|
||||
<div class="rounded-xl border border-border bg-card p-6 text-center">
|
||||
<p class="text-muted-foreground mb-4">Bitte melde dich an, um ein Spiel einzureichen.</p>
|
||||
<a
|
||||
href="/login"
|
||||
class="inline-block px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90 transition-colors"
|
||||
>
|
||||
Anmelden
|
||||
</a>
|
||||
</div>
|
||||
{:else}
|
||||
<form
|
||||
onsubmit={(e) => {
|
||||
e.preventDefault();
|
||||
handleSubmit();
|
||||
}}
|
||||
class="space-y-4"
|
||||
>
|
||||
<div>
|
||||
<label for="title" class="block text-sm font-medium text-foreground mb-1">Titel *</label>
|
||||
<input
|
||||
id="title"
|
||||
type="text"
|
||||
bind:value={title}
|
||||
required
|
||||
class="w-full rounded-lg border border-border bg-background px-4 py-2 text-foreground focus:outline-none focus:ring-2 focus:ring-primary/50"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="author" class="block text-sm font-medium text-foreground mb-1">Autor *</label>
|
||||
<input
|
||||
id="author"
|
||||
type="text"
|
||||
bind:value={authorName}
|
||||
required
|
||||
class="w-full rounded-lg border border-border bg-background px-4 py-2 text-foreground focus:outline-none focus:ring-2 focus:ring-primary/50"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="desc" class="block text-sm font-medium text-foreground mb-1">Beschreibung</label
|
||||
>
|
||||
<textarea
|
||||
id="desc"
|
||||
bind:value={description}
|
||||
rows="3"
|
||||
class="w-full rounded-lg border border-border bg-background px-4 py-2 text-foreground focus:outline-none focus:ring-2 focus:ring-primary/50 resize-none"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label for="controls" class="block text-sm font-medium text-foreground mb-1"
|
||||
>Steuerung</label
|
||||
>
|
||||
<input
|
||||
id="controls"
|
||||
type="text"
|
||||
bind:value={controls}
|
||||
placeholder="Pfeiltasten, Maus..."
|
||||
class="w-full rounded-lg border border-border bg-background px-4 py-2 text-foreground focus:outline-none focus:ring-2 focus:ring-primary/50"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="difficulty" class="block text-sm font-medium text-foreground mb-1"
|
||||
>Schwierigkeit</label
|
||||
>
|
||||
<select
|
||||
id="difficulty"
|
||||
bind:value={difficulty}
|
||||
class="w-full rounded-lg border border-border bg-background px-4 py-2 text-foreground focus:outline-none focus:ring-2 focus:ring-primary/50"
|
||||
>
|
||||
<option value="Einfach">Einfach</option>
|
||||
<option value="Mittel">Mittel</option>
|
||||
<option value="Schwer">Schwer</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="tags" class="block text-sm font-medium text-foreground mb-1"
|
||||
>Tags (kommagetrennt)</label
|
||||
>
|
||||
<input
|
||||
id="tags"
|
||||
type="text"
|
||||
bind:value={tags}
|
||||
placeholder="Arcade, Action, Puzzle"
|
||||
class="w-full rounded-lg border border-border bg-background px-4 py-2 text-foreground focus:outline-none focus:ring-2 focus:ring-primary/50"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="html" class="block text-sm font-medium text-foreground mb-1">HTML-Code *</label>
|
||||
<textarea
|
||||
id="html"
|
||||
bind:value={htmlCode}
|
||||
rows="12"
|
||||
required
|
||||
placeholder="<!DOCTYPE html>..."
|
||||
class="w-full rounded-lg border border-border bg-background px-4 py-2 text-foreground font-mono text-sm focus:outline-none focus:ring-2 focus:ring-primary/50 resize-none"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
{#if submitResult}
|
||||
<div
|
||||
class="rounded-lg border p-3 text-sm {submitResult.success
|
||||
? 'border-green-500/30 bg-green-500/10 text-green-400'
|
||||
: 'border-red-500/30 bg-red-500/10 text-red-400'}"
|
||||
>
|
||||
{submitResult.message}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={!title.trim() || !htmlCode.trim() || !authorName.trim() || isSubmitting}
|
||||
class="w-full px-4 py-2.5 rounded-lg bg-primary text-primary-foreground font-medium hover:bg-primary/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{isSubmitting ? 'Wird eingereicht...' : 'Spiel einreichen'}
|
||||
</button>
|
||||
</form>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<svelte:head>
|
||||
<title>Tags - Mana Games</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="max-w-2xl mx-auto text-center py-12">
|
||||
<p class="text-4xl mb-4">🏷️</p>
|
||||
<h1 class="text-2xl font-bold text-foreground">Tags</h1>
|
||||
<p class="text-muted-foreground mt-2">Demnächst verfügbar.</p>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<script lang="ts">
|
||||
import { theme } from '$lib/stores/theme.svelte';
|
||||
import { THEME_DEFINITIONS, EXTENDED_THEME_VARIANTS } from '@manacore/shared-theme';
|
||||
import type { ThemeVariant } from '@manacore/shared-theme';
|
||||
|
||||
const allThemes = EXTENDED_THEME_VARIANTS;
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Themes - Mana Games</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="max-w-4xl mx-auto space-y-6">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-foreground">Themes</h1>
|
||||
<p class="text-muted-foreground mt-1">Wähle ein Theme für Mana Games</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-3">
|
||||
{#each allThemes as variant}
|
||||
{@const def = THEME_DEFINITIONS[variant]}
|
||||
{#if def}
|
||||
<button
|
||||
onclick={() => theme.setVariant(variant)}
|
||||
class="rounded-xl border p-4 text-left transition-all hover:-translate-y-0.5 {theme.variant ===
|
||||
variant
|
||||
? 'border-primary bg-primary/5 ring-2 ring-primary/30'
|
||||
: 'border-border bg-card hover:border-primary/30'}"
|
||||
>
|
||||
<div class="text-2xl mb-2">{def.icon || '🎨'}</div>
|
||||
<div class="font-medium text-foreground text-sm">{def.label}</div>
|
||||
</button>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { ForgotPasswordPage } from '@manacore/shared-auth-ui';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Mana Games - Passwort vergessen</title>
|
||||
</svelte:head>
|
||||
|
||||
<ForgotPasswordPage {authStore} {goto} appName="Mana Games" loginHref="/login" />
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { LoginPage } from '@manacore/shared-auth-ui';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Mana Games - Login</title>
|
||||
</svelte:head>
|
||||
|
||||
<LoginPage
|
||||
{authStore}
|
||||
{goto}
|
||||
appName="Mana Games"
|
||||
registerHref="/register"
|
||||
forgotPasswordHref="/forgot-password"
|
||||
primaryColor="#00ff88"
|
||||
/>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { RegisterPage } from '@manacore/shared-auth-ui';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Mana Games - Registrieren</title>
|
||||
</svelte:head>
|
||||
|
||||
<RegisterPage {authStore} {goto} appName="Mana Games" loginHref="/login" primaryColor="#00ff88" />
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Mana Games - Passwort zurücksetzen</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="min-h-screen flex items-center justify-center">
|
||||
<div class="max-w-md w-full p-6 text-center">
|
||||
<h1 class="text-xl font-bold text-foreground mb-4">Passwort zurücksetzen</h1>
|
||||
<p class="text-muted-foreground mb-6">Funktion wird eingerichtet.</p>
|
||||
<a href="/login" class="text-primary hover:underline">Zurück zum Login</a>
|
||||
</div>
|
||||
</div>
|
||||
14
games/mana-games/apps/web/src/routes/health/+server.ts
Normal file
14
games/mana-games/apps/web/src/routes/health/+server.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import type { RequestHandler } from './$types';
|
||||
|
||||
export const GET: RequestHandler = async () => {
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
status: 'ok',
|
||||
service: 'mana-games-web',
|
||||
timestamp: new Date().toISOString(),
|
||||
}),
|
||||
{
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}
|
||||
);
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue