/* ============================================================ hipa — the family archive The sign-in form is a placeholder. It has no backend: nothing is validated, stored, logged, or sent anywhere. Every submit ends in the same message. Wire it to a real endpoint before treating it as a login. ============================================================ */ (function () { 'use strict'; var root = document.documentElement; root.className += ' js'; /* -- develop sequence ------------------------------------------------- Prints come up first, staggered along the sheet. Each date stamp flicks on after its own print has settled. */ var STAGGER = 90; // ms between prints var LEAD = 260; // ms before the sheet starts var SETTLE = 620; // ms a print takes to settle before its stamp lights document.querySelectorAll('.frame').forEach(function (frame, i) { var at = LEAD + i * STAGGER; frame.querySelector('.frame-print').style.animationDelay = at + 'ms'; frame.querySelectorAll('.frame-stamp, .frame-run').forEach(function (el) { el.style.animationDelay = (at + SETTLE) + 'ms'; }); }); [['.eyebrow', 0], ['.lede-title', 60], ['.lede-sub', 160], ['.gate', 220], ['.ticker', 320]].forEach(function (pair) { var el = document.querySelector(pair[0]); if (el) el.style.animationDelay = pair[1] + 'ms'; }); /* -- show / hide the passphrase --------------------------------------- */ var pass = document.getElementById('pass'); var reveal = document.querySelector('[data-reveal]'); reveal.addEventListener('click', function () { var shown = pass.type === 'text'; pass.type = shown ? 'password' : 'text'; reveal.textContent = shown ? 'Show' : 'Hide'; reveal.setAttribute('aria-pressed', String(!shown)); pass.focus(); }); /* -- the gate --------------------------------------------------------- */ var form = document.getElementById('signin'); var gate = document.getElementById('gate'); var notice = document.getElementById('notice'); var unlock = form.querySelector('.unlock'); var email = document.getElementById('email'); function refuse(message) { notice.textContent = message; gate.classList.remove('is-refused'); void gate.offsetWidth; // restart the shake gate.classList.add('is-refused'); } form.addEventListener('submit', function (e) { e.preventDefault(); if (!email.value.trim()) { refuse('Enter the email address the invite was sent to.'); email.focus(); return; } if (!pass.value) { refuse('Enter your passphrase to open the archive.'); pass.focus(); return; } unlock.classList.remove('is-firing'); void unlock.offsetWidth; unlock.classList.add('is-firing'); notice.textContent = ''; window.setTimeout(function () { refuse('That passphrase does not match this archive. Check the email address too.'); pass.value = ''; }, 520); }); unlock.addEventListener('animationend', function () { unlock.classList.remove('is-firing'); }); document.querySelector('[data-passkey]').addEventListener('click', function () { refuse('No passkey is registered on this device. Sign in with your passphrase, then add one from Settings.'); }); })();