← back to Patterndesignlab
public/admin-login.html
40 lines
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="robots" content="noindex,nofollow">
<title>Admin sign in · Pattern Design Lab</title>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<header class="top"><div class="wrap">
<a class="brand" href="/">Pattern Design<span class="dot">.</span>Lab</a>
</div></header>
<div class="wrap" style="max-width:380px;padding:60px 20px">
<h1 style="font-size:22px;margin-bottom:4px">Admin sign in</h1>
<p style="color:#6b6b6b;font-size:14px;margin-bottom:18px">Curation & catalog controls.</p>
<form id="f">
<input id="u" placeholder="username" autocomplete="username" style="width:100%;height:42px;border:1px solid var(--line);border-radius:10px;padding:0 12px;margin-bottom:10px;font-size:14px">
<input id="p" type="password" placeholder="password" autocomplete="current-password" style="width:100%;height:42px;border:1px solid var(--line);border-radius:10px;padding:0 12px;margin-bottom:10px;font-size:14px">
<button class="buy" type="submit" style="width:100%">Sign in</button>
<p id="msg" class="note" style="margin-top:10px"></p>
</form>
</div>
<script>
document.getElementById('f').onsubmit = async (e) => {
e.preventDefault();
const msg = document.getElementById('msg');
const r = await fetch('/api/admin/login', { method:'POST', headers:{'Content-Type':'application/json'},
body: JSON.stringify({ user: document.getElementById('u').value, pass: document.getElementById('p').value }) });
if (r.ok) {
const next = new URLSearchParams(location.search).get('next');
location.href = (next && /^\/(?!\/)/.test(next)) ? next : '/admin'; // "/x" only — "//host" is an open redirect
} else { msg.textContent = 'Invalid credentials.'; msg.style.color = '#b3261e'; }
};
</script>
</body>
</html>