- Created a new login page for admin access at frontend/admin/login/index.html. - Implemented form submission with error handling for login credentials. - Updated frontend/index.html to mute the video player and removed unnecessary Alpine.js data binding. - Enhanced manifest URL resolution in frontend/src/main.ts to include cache-busting parameters. - Modified vite.config.ts to include the new admin login page in the build process. - Updated nginx.conf to handle admin login routing, authentication, and API proxying for admin actions.
70 lines
3.1 KiB
HTML
70 lines
3.1 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>Linear Void Admin Login</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<link rel="stylesheet" href="../../src/style.css" />
|
|
</head>
|
|
|
|
<body class="min-h-screen bg-slate-950 text-slate-100 flex items-center justify-center px-6">
|
|
<main class="w-full max-w-md bg-slate-900 border border-slate-800 rounded-[2rem] shadow-2xl p-8">
|
|
<div class="mb-8">
|
|
<div class="text-xs uppercase tracking-[0.3em] text-slate-500 mb-3">Linear Void</div>
|
|
<h1 class="text-4xl font-semibold text-white mb-2">Admin Login</h1>
|
|
<p class="text-sm text-slate-400">Authenticate to access protected admin controls.</p>
|
|
</div>
|
|
|
|
<form id="login-form" class="space-y-4">
|
|
<label class="block text-sm">
|
|
<span class="block text-slate-400 mb-2">Username</span>
|
|
<input id="username" type="text" class="w-full bg-slate-950 border border-slate-700 rounded-xl px-4 py-3 focus:outline-none focus:border-blue-500" autocomplete="username" required />
|
|
</label>
|
|
<label class="block text-sm">
|
|
<span class="block text-slate-400 mb-2">Password</span>
|
|
<input id="password" type="password" class="w-full bg-slate-950 border border-slate-700 rounded-xl px-4 py-3 focus:outline-none focus:border-blue-500" autocomplete="current-password" required />
|
|
</label>
|
|
<button id="submit" type="submit" class="w-full bg-blue-600 hover:bg-blue-500 px-4 py-3 rounded-xl font-medium text-white">Sign in</button>
|
|
<div id="status" class="text-sm text-slate-400 min-h-6"></div>
|
|
</form>
|
|
</main>
|
|
|
|
<script>
|
|
const form = document.getElementById('login-form');
|
|
const username = document.getElementById('username');
|
|
const password = document.getElementById('password');
|
|
const submit = document.getElementById('submit');
|
|
const status = document.getElementById('status');
|
|
|
|
form.addEventListener('submit', async (event) => {
|
|
event.preventDefault();
|
|
submit.disabled = true;
|
|
status.textContent = 'Signing in...';
|
|
status.className = 'text-sm text-slate-400 min-h-6';
|
|
|
|
try {
|
|
const response = await fetch('/api/admin/login', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ username: username.value, password: password.value })
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP ${response.status}`);
|
|
}
|
|
|
|
window.location.href = '/admin/';
|
|
} catch (error) {
|
|
console.error('Failed to sign in', error);
|
|
status.textContent = 'Login failed. Check your credentials.';
|
|
status.className = 'text-sm text-rose-400 min-h-6';
|
|
} finally {
|
|
submit.disabled = false;
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
|
|
</html> |