201 lines
12 KiB
Plaintext
201 lines
12 KiB
Plaintext
{% extends "layouts/base.njk" %}
|
|
|
|
{% block body %}
|
|
<div class="mx-auto w-full max-w-[42rem] space-y-5">
|
|
<section id="auth-tabs" data-initial-tab="{% if resetToken %}reset{% else %}signin{% endif %}" class="rounded-[2rem] border border-zinc-200 bg-zinc-50 p-6 shadow-sm sm:p-8">
|
|
<p class="text-center text-xs font-medium tracking-[0.5em] text-slate-500">SIGN IN TO CONTINUE</p>
|
|
|
|
<div class="mt-6 grid grid-cols-3 gap-1 rounded-full bg-zinc-200 p-1.5">
|
|
<button type="button" data-tab-button data-tab="signin" class="rounded-full px-3 py-3 text-center text-sm font-semibold text-slate-500 transition">Sign In</button>
|
|
<button type="button" data-tab-button data-tab="signup" class="rounded-full px-3 py-3 text-center text-sm font-semibold text-slate-500 transition">Sign Up</button>
|
|
<button type="button" data-tab-button data-tab="reset" class="rounded-full px-3 py-3 text-center text-sm font-semibold text-slate-500 transition">Reset Password</button>
|
|
</div>
|
|
|
|
<section data-tab-panel="signin" class="mt-7 space-y-4">
|
|
<form hx-post="/auth/login" hx-target="#flash" hx-swap="innerHTML" class="space-y-4">
|
|
<div>
|
|
<label for="login-email" class="mb-2 block text-sm font-semibold text-slate-700">Email address</label>
|
|
<input id="login-email" name="email" type="email" placeholder="name@email.com" required class="w-full rounded-2xl border border-zinc-300 bg-zinc-100 px-4 py-3 text-base text-zinc-800 placeholder:text-zinc-400 focus:border-blue-500 focus:bg-white focus:outline-none" />
|
|
</div>
|
|
|
|
<div>
|
|
<label for="login-password" class="mb-2 block text-sm font-semibold text-slate-700">Password</label>
|
|
<div class="flex gap-2">
|
|
<input id="login-password" name="password" type="password" placeholder="Enter your password" required class="w-full rounded-2xl border border-zinc-300 bg-zinc-100 px-4 py-3 text-base text-zinc-800 placeholder:text-zinc-400 focus:border-blue-500 focus:bg-white focus:outline-none" />
|
|
<button type="button" data-toggle-password data-target="login-password" class="rounded-2xl border border-zinc-300 bg-zinc-100 px-4 py-3 text-sm font-semibold text-slate-600 transition hover:bg-white">Show</button>
|
|
</div>
|
|
</div>
|
|
|
|
<button type="submit" class="w-full rounded-2xl bg-blue-600 px-4 py-3 text-lg font-semibold text-white transition hover:bg-blue-700">Sign In</button>
|
|
</form>
|
|
|
|
<form id="magic-link-form" hx-post="/auth/magic-link" hx-target="#flash" hx-swap="innerHTML">
|
|
<input id="magic-link-email" type="hidden" name="email" value="" />
|
|
<button type="submit" class="w-full rounded-2xl border border-zinc-300 bg-zinc-100 px-4 py-3 text-lg font-semibold text-zinc-500 transition hover:bg-white hover:text-zinc-700">Send magic link</button>
|
|
</form>
|
|
|
|
<a href="/auth/google" class="block w-full rounded-2xl border border-zinc-300 bg-zinc-100 px-4 py-3 text-center text-lg font-semibold text-slate-700 no-underline transition hover:bg-white">Continue with Google</a>
|
|
</section>
|
|
|
|
<section data-tab-panel="signup" class="mt-7 hidden space-y-4">
|
|
<form hx-post="/auth/register" hx-target="#flash" hx-swap="innerHTML" class="space-y-4">
|
|
<div>
|
|
<label for="signup-name" class="mb-2 block text-sm font-semibold text-slate-700">Name</label>
|
|
<input id="signup-name" name="name" placeholder="Your full name" required class="w-full rounded-2xl border border-zinc-300 bg-zinc-100 px-4 py-3 text-base text-zinc-800 placeholder:text-zinc-400 focus:border-blue-500 focus:bg-white focus:outline-none" />
|
|
</div>
|
|
|
|
<div>
|
|
<label for="signup-email" class="mb-2 block text-sm font-semibold text-slate-700">Email address</label>
|
|
<input id="signup-email" name="email" type="email" placeholder="name@email.com" required class="w-full rounded-2xl border border-zinc-300 bg-zinc-100 px-4 py-3 text-base text-zinc-800 placeholder:text-zinc-400 focus:border-blue-500 focus:bg-white focus:outline-none" />
|
|
</div>
|
|
|
|
<div>
|
|
<label for="signup-password" class="mb-2 block text-sm font-semibold text-slate-700">Password</label>
|
|
<div class="flex gap-2">
|
|
<input id="signup-password" name="password" type="password" placeholder="Create a password" required class="w-full rounded-2xl border border-zinc-300 bg-zinc-100 px-4 py-3 text-base text-zinc-800 placeholder:text-zinc-400 focus:border-blue-500 focus:bg-white focus:outline-none" />
|
|
<button type="button" data-toggle-password data-target="signup-password" class="rounded-2xl border border-zinc-300 bg-zinc-100 px-4 py-3 text-sm font-semibold text-slate-600 transition hover:bg-white">Show</button>
|
|
</div>
|
|
</div>
|
|
|
|
<button type="submit" class="w-full rounded-2xl bg-blue-600 px-4 py-3 text-lg font-semibold text-white transition hover:bg-blue-700">Create Account</button>
|
|
</form>
|
|
|
|
<p class="rounded-2xl border border-blue-100 bg-blue-50 px-4 py-3 text-sm text-blue-700">New sign-ups are assigned the default <strong>MEMBER</strong> role.</p>
|
|
</section>
|
|
|
|
<section data-tab-panel="reset" class="mt-7 hidden space-y-4">
|
|
<form hx-post="/auth/password-reset/request" hx-target="#flash" hx-swap="innerHTML" class="space-y-4">
|
|
<div>
|
|
<label for="reset-email" class="mb-2 block text-sm font-semibold text-slate-700">Email address</label>
|
|
<input id="reset-email" name="email" type="email" placeholder="name@email.com" required class="w-full rounded-2xl border border-zinc-300 bg-zinc-100 px-4 py-3 text-base text-zinc-800 placeholder:text-zinc-400 focus:border-blue-500 focus:bg-white focus:outline-none" />
|
|
</div>
|
|
<button type="submit" class="w-full rounded-2xl border border-zinc-300 bg-zinc-100 px-4 py-3 text-lg font-semibold text-zinc-700 transition hover:bg-white">Request reset token</button>
|
|
</form>
|
|
|
|
<form hx-post="/auth/password-reset/confirm" hx-target="#flash" hx-swap="innerHTML" class="space-y-4 rounded-2xl border border-zinc-200 bg-white p-4">
|
|
<p class="text-sm font-semibold text-slate-700">Confirm reset</p>
|
|
<input name="token" placeholder="Reset token" value="{{ resetToken }}" required class="w-full rounded-2xl border border-zinc-300 bg-zinc-100 px-4 py-3 text-base text-zinc-800 placeholder:text-zinc-400 focus:border-blue-500 focus:bg-white focus:outline-none" />
|
|
<div class="flex gap-2">
|
|
<input id="reset-password" name="password" type="password" placeholder="New password" required class="w-full rounded-2xl border border-zinc-300 bg-zinc-100 px-4 py-3 text-base text-zinc-800 placeholder:text-zinc-400 focus:border-blue-500 focus:bg-white focus:outline-none" />
|
|
<button type="button" data-toggle-password data-target="reset-password" class="rounded-2xl border border-zinc-300 bg-zinc-100 px-4 py-3 text-sm font-semibold text-slate-600 transition hover:bg-white">Show</button>
|
|
</div>
|
|
<button type="submit" class="w-full rounded-2xl bg-blue-600 px-4 py-3 text-lg font-semibold text-white transition hover:bg-blue-700">Update password</button>
|
|
</form>
|
|
</section>
|
|
</section>
|
|
|
|
<section class="rounded-3xl border border-zinc-200 bg-zinc-50 p-6 shadow-sm">
|
|
<div class="rounded-2xl border border-zinc-200 bg-zinc-100 p-4">
|
|
<h2 class="text-2xl font-semibold text-slate-800">Default Admin Account</h2>
|
|
<p class="mt-2 text-lg text-slate-700">Email: <strong>admin@gmail.com</strong></p>
|
|
<p class="text-lg text-slate-700">Password: <strong>Whatever123$</strong></p>
|
|
<button type="button" data-try-login data-demo-email="admin@gmail.com" data-demo-password="Whatever123$" class="mt-3 rounded-xl border border-blue-200 bg-blue-50 px-4 py-2 text-sm font-semibold text-blue-700 transition hover:bg-blue-100">Use these credentials</button>
|
|
</div>
|
|
|
|
<ul class="mt-4 list-disc space-y-1 pl-5 text-zinc-700">
|
|
<li><strong>Sign in with the credentials above to access an <span class="font-bold text-red-600">ADMIN</span> account.</strong></li>
|
|
<li><strong>New sign-ups are assigned the default <span class="font-bold text-blue-600">MEMBER</span> role.</strong></li>
|
|
</ul>
|
|
|
|
<h3 class="mt-5 text-2xl font-bold text-zinc-800">Role Permissions Overview</h3>
|
|
|
|
<div class="mt-4 space-y-4 text-zinc-700">
|
|
<section>
|
|
<h4 class="text-xl font-bold text-blue-600">MEMBER</h4>
|
|
<ul class="list-disc space-y-1 pl-5">
|
|
<li>Can view the list of blog posts only.</li>
|
|
<li>No permission to create, edit, or delete posts.</li>
|
|
</ul>
|
|
</section>
|
|
|
|
<section>
|
|
<h4 class="text-xl font-bold text-amber-600">MANAGER</h4>
|
|
<ul class="list-disc space-y-1 pl-5">
|
|
<li>Can view all blog posts.</li>
|
|
<li>Can create new blog posts.</li>
|
|
<li>Newly created posts are always saved as Draft by default.</li>
|
|
<li>Cannot update or delete any post.</li>
|
|
</ul>
|
|
</section>
|
|
|
|
<section>
|
|
<h4 class="text-xl font-bold text-red-600">ADMIN</h4>
|
|
<ul class="list-disc space-y-1 pl-5">
|
|
<li>Full access to the system.</li>
|
|
<li>Can create, read, update, and delete any blog post.</li>
|
|
<li>Can manage all content without restrictions.</li>
|
|
</ul>
|
|
</section>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<script>
|
|
(function() {
|
|
const container = document.getElementById("auth-tabs");
|
|
if (!container) return;
|
|
|
|
const buttons = Array.from(container.querySelectorAll("[data-tab-button]"));
|
|
const panels = Array.from(container.querySelectorAll("[data-tab-panel]"));
|
|
const magicLinkForm = document.getElementById("magic-link-form");
|
|
const magicLinkEmail = document.getElementById("magic-link-email");
|
|
|
|
function setActiveTab(tabName) {
|
|
buttons.forEach((button) => {
|
|
const isActive = button.getAttribute("data-tab") === tabName;
|
|
button.classList.toggle("bg-white", isActive);
|
|
button.classList.toggle("text-zinc-800", isActive);
|
|
button.classList.toggle("shadow-sm", isActive);
|
|
button.classList.toggle("text-slate-500", !isActive);
|
|
});
|
|
|
|
panels.forEach((panel) => {
|
|
panel.classList.toggle("hidden", panel.getAttribute("data-tab-panel") !== tabName);
|
|
});
|
|
}
|
|
|
|
const initialTab = container.getAttribute("data-initial-tab") || "signin";
|
|
setActiveTab(initialTab);
|
|
|
|
container.addEventListener("click", function(event) {
|
|
const tabButton = event.target.closest("[data-tab-button]");
|
|
if (!tabButton) return;
|
|
setActiveTab(tabButton.getAttribute("data-tab") || "signin");
|
|
});
|
|
|
|
if (magicLinkForm && magicLinkEmail) {
|
|
magicLinkForm.addEventListener("submit", function() {
|
|
const emailInput = document.getElementById("login-email");
|
|
magicLinkEmail.value = emailInput ? emailInput.value.trim() : "";
|
|
});
|
|
}
|
|
|
|
document.addEventListener("click", function(event) {
|
|
const toggleButton = event.target.closest("[data-toggle-password]");
|
|
if (toggleButton) {
|
|
const targetId = toggleButton.getAttribute("data-target");
|
|
const input = targetId ? document.getElementById(targetId) : null;
|
|
if (input) {
|
|
const isPassword = input.getAttribute("type") === "password";
|
|
input.setAttribute("type", isPassword ? "text" : "password");
|
|
toggleButton.textContent = isPassword ? "Hide" : "Show";
|
|
}
|
|
return;
|
|
}
|
|
|
|
const demoButton = event.target.closest("[data-try-login]");
|
|
if (!demoButton) return;
|
|
|
|
const emailInput = document.getElementById("login-email");
|
|
const passwordInput = document.getElementById("login-password");
|
|
if (!emailInput || !passwordInput) return;
|
|
|
|
setActiveTab("signin");
|
|
emailInput.value = demoButton.getAttribute("data-demo-email") || "";
|
|
passwordInput.value = demoButton.getAttribute("data-demo-password") || "";
|
|
passwordInput.focus();
|
|
});
|
|
})();
|
|
</script>
|
|
{% endblock %}
|