Initial commit

This commit is contained in:
2026-07-28 08:58:44 +02:00
commit c3c1f5e216
46 changed files with 10231 additions and 0 deletions
+97
View File
@@ -0,0 +1,97 @@
<div class="card max-w-sm mx-auto mt-16">
<header>
<h2>Connexion</h2>
<p>Connectez-vous à votre compte PokeShare</p>
</header>
<section>
<form id="login-form" class="grid gap-4">
<div role="group" class="field">
<label for="username">Nom d'utilisateur</label>
<input
class="input"
type="text"
id="username"
name="username"
placeholder="votre@email.com"
required
/>
</div>
<div role="group" class="field">
<label for="password">Mot de passe</label>
<input
class="input"
type="password"
id="password"
name="password"
placeholder="••••••••"
required
/>
</div>
</form>
</section>
<footer class="flex-col gap-2">
<button
class="btn w-full"
type="submit"
form="login-form"
id="login-submit"
>
Se connecter
</button>
</footer>
</div>
<script>
const form = document.getElementById("login-form");
const submitBtn = document.getElementById(
"login-submit",
) as HTMLButtonElement;
const toaster = document.getElementById("toaster") as ToasterElement;
const showToast = (
category: "success" | "error",
title: string,
description: string,
) => {
if (toaster?.toast) {
toaster.toast({ category, title, description });
}
};
form?.addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(form as HTMLFormElement);
const username = formData.get("username");
const password = formData.get("password");
submitBtn.disabled = true;
const originalText = submitBtn.innerHTML;
submitBtn.innerHTML = `<svg aria-label="Loading" role="status" data-icon="inline-start" class="animate-spin lucide lucide-loader-circle" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-6.219-8.56" /></svg> Connexion...`;
try {
const res = await fetch("/api/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username, password }),
});
if (res.ok) {
window.location.href = "/";
} else {
const data = await res.json();
showToast(
"error",
"Erreur",
data.error ?? "Identifiants incorrects",
);
submitBtn.disabled = false;
submitBtn.innerHTML = originalText;
}
} catch {
showToast("error", "Erreur", "Erreur réseau");
submitBtn.disabled = false;
submitBtn.innerHTML = originalText;
}
});
</script>
+304
View File
@@ -0,0 +1,304 @@
---
const { pb } = Astro.locals;
const user = pb.authStore.record;
const initials = user
? (user.name || user.email || "")
.split(/[\s@.]+/)
.filter(Boolean)
.slice(0, 2)
.map((s: string) => s[0].toUpperCase())
.join("")
: "";
---
<header
class="sticky top-0 z-50 border-b border-border bg-background/95 backdrop-blur"
>
<nav
class="mx-auto flex h-16 max-w-7xl items-center justify-between px-4 sm:px-8"
>
<a
href="/"
class="flex items-center gap-2 text-lg font-bold no-underline"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 24 24"
>
<path d="M0 0h24v24H0z" fill="none"></path>
<path
fill="currentColor"
d="M12 2a10 10 0 0 1 10 10a10 10 0 0 1-10 10A10 10 0 0 1 2 12A10 10 0 0 1 12 2m0 2c-4.08 0-7.45 3.05-7.94 7h4.07c.44-1.73 2.01-3 3.87-3s3.43 1.27 3.87 3h4.07c-.49-3.95-3.86-7-7.94-7m0 16c4.08 0 7.45-3.05 7.94-7h-4.07c-.44 1.73-2.01 3-3.87 3s-3.43-1.27-3.87-3H4.06c.49 3.95 3.86 7 7.94 7m0-10a2 2 0 0 0-2 2a2 2 0 0 0 2 2a2 2 0 0 0 2-2a2 2 0 0 0-2-2"
></path>
</svg>
PokeShare
</a>
<ul class="flex items-center gap-1 list-none m-0 p-0">
<li>
<a
href="/friends"
class="btn relative"
data-variant="ghost"
data-size="icon-sm"
aria-label="Amis"
title="Amis"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"
></path>
<circle cx="9" cy="7" r="4"></circle>
<path d="M22 21v-2a4 4 0 0 0-3-3.87"></path>
<path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
</svg>
</a>
</li>
<li>
<a
href="/search"
class="btn"
data-variant="ghost"
data-size="sm"
>
<svg
data-icon="inline-start"
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
viewBox="0 0 24 24"
>
<path d="M0 0h24v24H0z" fill="none"></path>
<path
fill="currentColor"
d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5l-1.5 1.5l-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16A6.5 6.5 0 0 1 3 9.5A6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14S14 12 14 9.5S12 5 9.5 5"
></path>
</svg>
<span class="hidden sm:inline">Rechercher</span>
</a>
</li>
<li>
<a
href="/mycards"
class="btn"
data-variant="ghost"
data-size="sm"
>
<svg
data-icon="inline-start"
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
viewBox="0 0 24 24"
>
<path d="M0 0h24v24H0z" fill="none"></path>
<path
fill="currentColor"
d="m12.1 18.55l-.1.1l-.11-.1C7.14 14.24 4 11.39 4 8.5C4 6.5 5.5 5 7.5 5c1.54 0 3.04 1 3.57 2.36h1.86C13.46 6 14.96 5 16.5 5c2 0 3.5 1.5 3.5 3.5c0 2.89-3.14 5.74-7.9 10.05M16.5 3c-1.74 0-3.41.81-4.5 2.08C10.91 3.81 9.24 3 7.5 3C4.42 3 2 5.41 2 8.5c0 3.77 3.4 6.86 8.55 11.53L12 21.35l1.45-1.32C18.6 15.36 22 12.27 22 8.5C22 5.41 19.58 3 16.5 3"
></path>
</svg>
<span class="hidden sm:inline">Mes cartes</span>
</a>
</li>
{
user ? (
<li class="ml-2">
<div id="user-menu" class="dropdown-menu">
<button
type="button"
id="user-menu-trigger"
aria-haspopup="menu"
aria-controls="user-menu-dropdown"
aria-expanded="false"
class="btn rounded-full"
data-variant="ghost"
data-size="sm"
>
<span class="avatar" data-size="sm">
<span>{initials}</span>
</span>
<span class="hidden sm:inline ml-1 text-sm">
{user.name || user.email}
</span>
<svg
data-icon="inline-end"
xmlns="http://www.w3.org/2000/svg"
width="12"
height="12"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m6 9 6 6 6-6" />
</svg>
</button>
<div
id="user-menu-popover"
data-popover
aria-hidden="true"
data-align="end"
class="w-48"
>
<div
role="menu"
id="user-menu-dropdown"
aria-labelledby="user-menu-trigger"
>
<div role="group">
<div
role="heading"
class="px-2 py-1.5 text-xs opacity-60"
>
{user.email}
</div>
<div
role="menuitem"
onclick="window.location.href='/mycards'"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m12.1 18.55-.1.1-.11-.1C7.14 14.24 4 11.39 4 8.5C4 6.5 5.5 5 7.5 5c1.54 0 3.04 1 3.57 2.36h1.86C13.46 6 14.96 5 16.5 5c2 0 3.5 1.5 3.5 3.5 0 2.89-3.14 5.74-7.9 10.05" />
</svg>
Ma collection
</div>
<div
role="menuitem"
onclick="window.location.href='/profile'"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" />
<circle cx="12" cy="7" r="4" />
</svg>
Profil
</div>
</div>
<hr role="separator" />
<div role="group">
<div
role="menuitem"
onclick="fetch('/api/logout', { method: 'POST' }).finally(() => window.location.href='/login')"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m16 17 5-5-5-5" />
<path d="M21 12H9" />
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
</svg>
Déconnexion
</div>
</div>
</div>
</div>
</div>
</li>
) : (
<li>
<a
href="/login"
class="btn"
data-variant="outline"
data-size="sm"
>
Login
</a>
</li>
)
}
<li>
<button
type="button"
aria-label="Toggle dark mode"
onclick="window.basecoat.theme.toggle()"
class="btn"
data-variant="ghost"
data-size="icon-sm"
>
<span class="hidden dark:block">
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="12" r="4"></circle>
<path d="M12 2v2"></path>
<path d="M12 20v2"></path>
<path d="m4.93 4.93 1.41 1.41"></path>
<path d="m17.66 17.66 1.41 1.41"></path>
<path d="M2 12h2"></path>
<path d="M20 12h2"></path>
<path d="m6.34 17.66-1.41 1.41"></path>
<path d="m19.07 4.93-1.41 1.41"></path>
</svg>
</span>
<span class="block dark:hidden">
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"
></path>
</svg>
</span>
</button>
</li>
</ul>
</nav>
</header>