Files
ipodderx-rs/web/login.html
rays 49dafedbbc Inter, one file where WordPress listed two, and a pin heading on line
Inter (#11): the pages are set in Inter's variable font, served from the
binary at /inter.woff2 as the icon is, with its OFL licence beside it in
web/. Classic keeps Lucida Grande, the 2004 app's face.

Double audio (#12): WordPress numbers each audio player on a page by
adding ?_=N to its file's URL, so a post that embeds the file it encloses
listed it twice, and it was downloaded twice. The parser keeps the first
of an item's enclosures that differ only by that number. At startup the
repeats already stored fold into the first; where only the repeat had
been downloaded its file moves to the first rather than being deleted.

Pin heading (#13): the rows' icon buttons kept the browser's side
padding, which pushed their 16px icon 3px right of centre, and the
heading's icon sat at the left of its column. Both are centred now, and
the heading row takes the pixel of border the rows have, so every
heading sits over its column.

Closes #11, closes #12, closes #13.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 17:31:03 +00:00

96 lines
3.5 KiB
HTML

<title>Sign in — iPodderX</title>
<link rel="icon" href="/icon.png">
<style>
/* Inter, from ipx itself; see the same rule in index.html. */
@font-face{font-family:Inter;src:url(/inter.woff2) format("woff2");font-weight:100 900;font-display:swap}
:root {
--bg:#0e131b; /* the screen's navy (#314B74), taken right down */
--panel:#151c27;
--panel2:#1c2431;
--raise:#25303f;
--line:#2c3849;
--fg:#f5f5f5; /* #F5F5F5 device highlight */
--dim:#95a0b1; /* #95A0B1 straight from the icon's blue-grey */
--faint:#7a8799; /* lifted from the icon ramp until it clears AA at small sizes */
--accent:#92b2e6; /* #92B2E6 the screen blue */
--accent2:#f49e2c; /* #F49E2C the EQ bars */
--ink:#0e131b; /* text on an accent fill */
--good:#6fbf8b;
--warn:#f49e2c; /* the amber doubles as the pending colour */
--bad:#e2705f;
--shadow:0 8px 28px rgba(6,10,16,.55);
--r:10px;
}
:root[data-theme="light"] {
--bg:#f2f4f7;
--panel:#ffffff; /* #FFFFFF device body */
--panel2:#e9edf3;
--raise:#dde3ec;
--line:#d6d6d6; /* #D6D6D6 device edge */
--fg:#1a1a1a; /* #1A1A1A icon outline */
--dim:#606060; /* #606060 */
--faint:#767676; /* between the icon's #929292 and #606060, to clear AA */
--accent:#2d5391; /* #2D5391 the deep screen blue reads better on white */
--accent2:#b06f10;
--ink:#ffffff;
--good:#2f7d4f;
--warn:#b06f10;
--bad:#b3402f;
--shadow:0 8px 28px rgba(45,83,145,.14);
}
*{box-sizing:border-box}
html,body{height:100%}
body{
margin:0;display:grid;place-items:center;background:var(--bg);color:var(--fg);
font:14.5px/1.55 Inter,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;padding:20px;
}
form{
width:min(360px,100%);background:var(--panel);border:1px solid var(--line);
border-radius:14px;padding:22px;box-shadow:var(--shadow);
}
/* The one place the 2004 icon is shown at the size it was drawn for. */
.brand{display:flex;flex-direction:column;align-items:center;gap:6px;margin-bottom:20px}
.brand img{width:96px;height:auto}
h1{font-size:21px;margin:0;font-weight:650;letter-spacing:-.01em}
label{display:block;font-size:12px;color:var(--dim);margin:0 0 4px}
input{
width:100%;background:var(--bg);border:1px solid var(--line);color:var(--fg);
border-radius:8px;padding:9px 11px;font:inherit;margin-bottom:13px;
}
input:focus{outline:0;border-color:var(--accent)}
button{
width:100%;font:inherit;font-weight:600;cursor:pointer;color:var(--ink);
background:var(--accent);border:0;border-radius:8px;padding:10px;
}
.msg{color:var(--bad);font-size:13px;min-height:19px;margin:10px 0 0;text-align:center}
button:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
</style>
<form id="f">
<div class="brand"><img src="/icon.png" alt=""><h1>iPodderX</h1></div>
<label for="name">Name</label>
<input id="name" name="name" autocomplete="username" autofocus required>
<label for="pw">Password</label>
<input id="pw" name="password" type="password" autocomplete="current-password" required>
<button type="submit">Sign in</button>
<p class="msg" id="msg"></p>
</form>
<script>
document.getElementById('f').onsubmit = async e => {
e.preventDefault();
const msg = document.getElementById('msg');
msg.textContent = '';
const r = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: document.getElementById('name').value,
password: document.getElementById('pw').value,
}),
});
if (r.ok) location.href = '/';
else msg.textContent = await r.text() || 'Sign in failed';
};
</script>