diff --git a/frontend/src/components.jsx b/frontend/src/components.jsx index a16f378..7dd53aa 100644 --- a/frontend/src/components.jsx +++ b/frontend/src/components.jsx @@ -238,18 +238,34 @@ export function AuthModal({ mode: initialMode, onClose, onAuthed }) { const [mode, setMode] = useState(initialMode || 'register') const [email, setEmail] = useState('') const [password, setPassword] = useState('') + const [reveal, setReveal] = useState(false) const [error, setError] = useState('') const [busy, setBusy] = useState(false) const registering = mode === 'register' + // Esc dismisses, like the overlay click already does. + useEffect(() => { + const onKey = (e) => { if (e.key === 'Escape') onClose() } + window.addEventListener('keydown', onKey) + return () => window.removeEventListener('keydown', onKey) + }, [onClose]) + + const switchTo = (next) => { + if (next === mode) return + setMode(next) + setError('') + setReveal(false) + } + const submit = async (e) => { e.preventDefault() setBusy(true) setError('') try { + const address = email.trim() const me = registering - ? await api.register(email, password) - : await api.login(email, password) + ? await api.register(address, password) + : await api.login(address, password) onAuthed(me, mode) } catch (err) { setError(err.message) @@ -259,34 +275,54 @@ export function AuthModal({ mode: initialMode, onClose, onAuthed }) { return (
-
e.stopPropagation()} onSubmit={submit}> -

{registering ? 'Create an account' : 'Log in'}

-

+ e.stopPropagation()} onSubmit={submit} + aria-labelledby="auth-title"> +

+

{registering ? 'Create an account' : 'Welcome back'}

+

{registering ? 'Everything you’ve played as a guest stays with your new account, and you can pick it up from any device.' - : 'Welcome back — log in to reach your adventures.'} + : 'Log in to reach your adventures.'}

+ +
+ + +
+ - {error &&
{error}
} -
- -
- -
+ {registering && At least 8 characters.} + + + {error &&
{error}
} + +
+ +
diff --git a/frontend/src/index.css b/frontend/src/index.css index edb642b..0b82463 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -184,7 +184,7 @@ label.field .label { color: var(--text-dim); margin-bottom: 5px; } -input[type="text"], input[type="password"], input[type="number"], textarea, select { +input[type="text"], input[type="email"], input[type="password"], input[type="number"], textarea, select { width: 100%; background: var(--bg-input); color: var(--text); @@ -1262,6 +1262,76 @@ button:disabled { opacity: 0.45; cursor: default; transform: none; box-shadow: n .modal .modal-hint { margin: 0 0 18px; color: var(--text-dim); font-size: 0.88rem; } .modal .modal-buttons { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; } +/* ---------- Auth (log in / sign up) ---------- */ + +.auth-modal { width: min(400px, calc(100vw - 40px)); text-align: center; padding-top: 22px; } +.auth-crest { + font-size: 1.1rem; + color: var(--accent-dim); + letter-spacing: 0.3em; + margin-bottom: 6px; +} +.auth-modal h2 { font-size: 1.35rem; } +.auth-modal .auth-hint { margin-bottom: 16px; line-height: 1.45; } +/* Fields go back to left-aligned — only the header is centred. */ +.auth-modal label.field { text-align: left; } + +.auth-tabs { + display: flex; + gap: 4px; + padding: 4px; + margin-bottom: 18px; + background: var(--bg-input); + border: 1px solid var(--border); + border-radius: 10px; +} +.auth-tab { + flex: 1; + padding: 7px 0; + border: 1px solid transparent; + border-radius: 7px; + background: transparent; + color: var(--text-dim); + font-family: var(--font-display); + font-size: 0.78rem; + letter-spacing: 0.1em; + text-transform: uppercase; +} +.auth-tab:hover { color: var(--text); background: rgba(212, 169, 78, 0.06); } +.auth-tab.active { + background: var(--bg-panel); + border-color: var(--accent-dim); + color: var(--accent-bright); +} + +.auth-password { display: flex; gap: 8px; } +.auth-password input { flex: 1; min-width: 0; } +.auth-reveal { + flex: none; + padding: 0 12px; + font-size: 0.78rem; + color: var(--text-dim); +} +.auth-reveal:hover { color: var(--accent-bright); } + +.auth-help { + display: block; + margin-top: 6px; + font-size: 0.76rem; + color: var(--text-dim); +} +.auth-error { + margin-top: 4px; + padding: 9px 12px; + border: 1px solid rgba(208, 101, 101, 0.45); + border-radius: 8px; + background: rgba(208, 101, 101, 0.09); + color: var(--danger); + font-size: 0.85rem; + text-align: left; + white-space: pre-wrap; +} + /* "Update from scenario" — a wider modal, since it lists a diff. */ .refresh-modal { width: min(620px, calc(100vw - 40px)); } .refresh-changes { @@ -1984,7 +2054,7 @@ button.primary.compact { padding: 3px 12px; font-size: 0.76rem; margin-left: aut /* ---------- Global page padding / typography ---------- */ .page { padding: 18px 14px; } /* 16px inputs stop iOS Safari auto-zooming when a field is focused. */ - input[type="text"], input[type="password"], input[type="number"], textarea, select { + input[type="text"], input[type="email"], input[type="password"], input[type="number"], textarea, select { font-size: 16px; }