Files
cinny/src/lotus-boot.ts
T
jaredandClaude Opus 5 7aba71490a fix(a11y): reduced-motion for spinner/call-avatar; tap-to-skip boot; AA accent contrast
- SendingSpinClass and CallAvatarAnimation respect prefers-reduced-motion
  (static opacity fallback), matching MsgAppearClass.
- Terminal boot overlay dismisses on click/tap and is aria-hidden.
- Primary.Main: Midnight #6b7ca8 -> #6f80aa (4.29 -> 4.51:1), Lotus
  Terminal Light #c44e00 -> #ba4a00 (4.14 -> 4.52:1), hue preserved.

Fixes #84
Fixes #86
Fixes #52

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
2026-09-12 20:28:41 -04:00

116 lines
3.7 KiB
TypeScript

const BOOT_MESSAGES = [
'╔════════════════════════════════════════════════════╗',
'║ LOTUS CHAT — LOTUSGUILD PLATFORM ║',
'║ SECURE MATRIX CLIENT — TERMINAL MODE ACTIVE ║',
'╚════════════════════════════════════════════════════╝',
'',
'[ OK ] Kernel modules loaded',
'[ OK ] Network interfaces configured',
'[ OK ] DNS resolution active',
'[ OK ] TLS certificate verified — matrix.lotusguild.org',
'[ OK ] Matrix homeserver connected',
'[ OK ] E2EE Olm/Megolm keys loaded',
'[ OK ] Cross-signing keys verified',
'[ OK ] Room state synchronized',
'[ OK ] Media proxy available',
'[ OK ] Notification service active',
'[ OK ] Terminal interface rendered',
'',
'> ALL SYSTEMS NOMINAL — LOTUS CHAT',
'> TYPE /help FOR COMMANDS',
'',
];
const STORAGE_KEY = 'lt_booted_lotus-chat';
export function resetBootSequence(): void {
sessionStorage.removeItem(STORAGE_KEY);
}
export function runLotusBootSequence(force = false): void {
if (!force && sessionStorage.getItem(STORAGE_KEY)) return;
if (document.getElementById('lt-boot')) return;
sessionStorage.setItem(STORAGE_KEY, '1');
const overlay = document.createElement('div');
overlay.id = 'lt-boot';
// Decorative boot animation, not content — hide it from assistive tech.
overlay.setAttribute('aria-hidden', 'true');
overlay.style.cssText = [
'position:fixed',
'inset:0',
'background:#000',
'z-index:10100',
'display:flex',
'align-items:flex-start',
'justify-content:flex-start',
'padding:3rem',
"font-family:'JetBrains Mono','Fira Code','Courier New',monospace",
].join(';');
const pre = document.createElement('pre');
pre.style.cssText = [
'font-family:inherit',
'font-size:0.78rem',
'color:#00FF88',
'text-shadow:0 0 6px #00FF88,0 0 16px rgba(0,255,136,0.45)',
'line-height:1.7',
'white-space:pre-wrap',
'overflow:hidden',
'flex:1',
].join(';');
overlay.appendChild(pre);
const escHint = document.createElement('div');
escHint.style.cssText = [
'position:absolute',
'bottom:1.5rem',
'right:2rem',
'font-size:0.68rem',
'color:rgba(0,255,136,0.55)',
"font-family:'JetBrains Mono','Courier New',monospace",
'letter-spacing:0.08em',
'user-select:none',
'pointer-events:none',
].join(';');
escHint.textContent = '[ ESC ] skip';
overlay.appendChild(escHint);
document.body.appendChild(overlay);
const dismiss = (): void => {
clearInterval(interval);
document.removeEventListener('keydown', onKey);
overlay.removeEventListener('click', dismiss);
overlay.style.transition = 'opacity 0.4s ease';
overlay.style.opacity = '0';
setTimeout(() => overlay.remove(), 400);
};
const onKey = (e: KeyboardEvent): void => {
if (e.key === 'Escape') dismiss();
};
document.addEventListener('keydown', onKey);
// No touch/click dismiss previously existed — mouse/touch users had no way
// to skip besides the keyboard-only Escape hint.
overlay.addEventListener('click', dismiss);
let i = 0;
let text = '';
const interval = setInterval(() => {
if (i >= BOOT_MESSAGES.length) {
clearInterval(interval);
document.removeEventListener('keydown', onKey);
setTimeout(() => {
overlay.style.transition = 'opacity 0.5s ease';
overlay.style.opacity = '0';
setTimeout(() => overlay.remove(), 500);
}, 500);
return;
}
text += `${BOOT_MESSAGES[i]}\n`;
pre.textContent = text;
i++;
}, 45);
}