Fix dashboard black screen, add login gate, and expand README.

Pin React Three Fiber to React 18, remove PWA caching, add SessionGate and error boundaries, and document movie fusion, auth, outputs, and troubleshooting.
This commit is contained in:
drjones
2026-05-29 08:50:48 -07:00
parent b99c8aab15
commit e11fb30350
14 changed files with 601 additions and 4151 deletions

View File

@@ -0,0 +1,73 @@
import { useEffect, useState, type ReactNode } from 'react';
import { getStoredAuth, setStoredAuth } from '../api/auth';
export default function SessionGate({ children }: { children: ReactNode }) {
const [ready, setReady] = useState(false);
const [authed, setAuthed] = useState(!!getStoredAuth());
const [user, setUser] = useState('drjones');
const [pass, setPass] = useState('');
const [err, setErr] = useState('');
useEffect(() => {
const token = getStoredAuth();
if (!token) {
setReady(true);
return;
}
fetch('/api/v1/config', { headers: { Authorization: `Basic ${token}` } })
.then((r) => {
setAuthed(r.ok);
setReady(true);
})
.catch(() => setReady(true));
}, []);
const handleLogin = async (e: React.FormEvent) => {
e.preventDefault();
setErr('');
const token = btoa(`${user}:${pass}`);
const res = await fetch('/api/v1/config', { headers: { Authorization: `Basic ${token}` } });
if (!res.ok) {
setErr('Login failed — check username and password.');
return;
}
setStoredAuth(user, pass);
setAuthed(true);
};
if (!ready) {
return (
<div className="session-gate">
<p className="font-tech">Starting AetherForge</p>
</div>
);
}
if (!authed) {
return (
<div className="session-gate">
<form className="session-gate-card card" onSubmit={handleLogin}>
<h1 className="font-display">AetherForge</h1>
<p className="form-hint">Sign in to open the command deck.</p>
<label className="label">Username</label>
<input className="input" value={user} onChange={(e) => setUser(e.target.value)} autoComplete="username" />
<label className="label">Password</label>
<input
className="input"
type="password"
value={pass}
onChange={(e) => setPass(e.target.value)}
autoComplete="current-password"
/>
{err && <p className="form-hint" style={{ color: 'var(--accent-red)' }}>{err}</p>}
<button type="submit" className="btn btn-primary btn-lg">
Enter Command Deck
</button>
<p className="form-hint">Default: drjones / czapiewski (change under Calibrate Users)</p>
</form>
</div>
);
}
return <>{children}</>;
}