Files
exbyte-depot-viewer-perforce/waitlist-server/views/login.html
Bonchellon 3954082e8d v0.3.2 — commit/submit progress, cancel, thumbnails, waitlist landing+admin
Client:
- Commit: batch `p4 reopen` so huge changelists (63k+) no longer blow the
  Windows command-line limit; live "N / total" progress + spinner during commit.
- Submit dialog: white arrow, "N of total" + % bar, running file log,
  Cancel button (aborts pre-commit; changelist stays pending).
- Disk scan: streaming reconcile with a live "found N files" counter + Cancel.
- Thumbnails: only decode browser-renderable image formats; glyph fallback
  (+ onError) instead of a broken-image icon for bmp/tga/dds/etc.

Landing + waitlist:
- waitlist-server: Express + SQLite email collector (dedup) with a secure
  admin panel (scrypt auth, rate-limited login, signed cookies) and CSV export.
- landing form now POSTs signups to the waitlist API.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 20:40:53 +03:00

73 lines
3.7 KiB
HTML

<!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 · Exbyte Depot</title>
<style>
:root{
--bg:#0a0a0f; --panel:#12121b; --elevated:#1a1a24; --border:#26263340;
--txt:#ececf4; --muted:#a2a2b4; --faint:#6d6d80;
--acc:#7c6ef6; --acc-2:#9d93ff; --acc-deep:#5b4ee0; --del:#f2637e;
}
*{box-sizing:border-box}
body{margin:0;min-height:100vh;display:grid;place-items:center;padding:24px;
background:radial-gradient(1200px 600px at 50% -10%,#171626 0%,var(--bg) 55%);
font:15px/1.5 -apple-system,Segoe UI,Roboto,Inter,system-ui,sans-serif;color:var(--txt)}
.card{width:100%;max-width:380px;background:var(--panel);border:1px solid var(--border);
border-radius:18px;padding:34px 30px;box-shadow:0 30px 80px -30px #000}
.brand{display:flex;align-items:center;gap:11px;margin-bottom:24px}
.logo{width:38px;height:38px;border-radius:11px;flex:0 0 auto;
background:linear-gradient(145deg,var(--acc-2),var(--acc-deep));
box-shadow:0 0 22px rgba(124,110,246,.5);display:grid;place-items:center}
.logo svg{width:20px;height:20px}
.brand b{font-size:15px;font-weight:650;letter-spacing:.2px}
.brand span{display:block;font-size:11.5px;color:var(--faint);font-weight:500}
h1{font-size:19px;font-weight:650;margin:0 0 4px}
.sub{color:var(--muted);font-size:12.5px;margin:0 0 22px}
label{display:block;font-size:11.5px;color:var(--muted);font-weight:600;margin:0 0 6px;
text-transform:uppercase;letter-spacing:.4px}
.field{margin-bottom:16px}
input{width:100%;background:var(--elevated);border:1px solid var(--border);border-radius:11px;
padding:11px 13px;color:var(--txt);font-size:14px;outline:none;transition:.15s}
input:focus{border-color:var(--acc);box-shadow:0 0 0 3px rgba(124,110,246,.16)}
button{width:100%;margin-top:6px;padding:12px;border:0;border-radius:11px;cursor:pointer;
background:linear-gradient(145deg,var(--acc-2),var(--acc-deep));color:#fff;
font-size:14.5px;font-weight:650;letter-spacing:.2px;transition:.15s}
button:hover{filter:brightness(1.08)}
.err{display:none;background:rgba(242,99,126,.1);border:1px solid rgba(242,99,126,.35);
color:#ff9db0;font-size:12.5px;padding:9px 12px;border-radius:10px;margin-bottom:18px}
.err.show{display:block}
.foot{margin-top:20px;text-align:center;font-size:11px;color:var(--faint)}
</style>
</head>
<body>
<form class="card" method="POST" action="/admin/login" autocomplete="off">
<div class="brand">
<span class="logo"><svg viewBox="0 0 24 24" fill="none"><path d="M4 7l8-4 8 4v10l-8 4-8-4V7Z" stroke="#fff" stroke-width="1.6" stroke-linejoin="round"/><path d="M4 7l8 4 8-4M12 11v10" stroke="#fff" stroke-width="1.6" stroke-linejoin="round"/></svg></span>
<div><b>Exbyte Depot</b><span>Waitlist admin</span></div>
</div>
<h1>Sign in</h1>
<p class="sub">Restricted area — authorized access only.</p>
<div class="err" id="err">Invalid username or password.</div>
<div class="field">
<label for="u">Username</label>
<input id="u" name="username" type="text" autocomplete="username" required autofocus />
</div>
<div class="field">
<label for="p">Password</label>
<input id="p" name="password" type="password" autocomplete="current-password" required />
</div>
<button type="submit">Sign in</button>
<div class="foot">Protected endpoint · rate-limited</div>
</form>
<script>
if (new URLSearchParams(location.search).get("error")) {
document.getElementById("err").classList.add("show");
history.replaceState(null, "", "/admin/login");
}
</script>
</body>
</html>