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>
73 lines
3.7 KiB
HTML
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>
|