feat: convert to argument.es — Spanish, vote buttons, Docker
- Translate all ~430 prompts to Spanish with cultural adaptations - Translate all UI strings (frontend, admin, history, broadcast) - Translate AI system prompts; models now respond in Spanish - Replace Twitch/Fossabot viewer voting with in-site vote buttons - Add POST /api/vote endpoint (IP-based, supports vote switching) - Vote buttons appear during voting phase with active state highlight - Rename project to argument.es throughout (package.json, cookie, DB) - Add docker-compose.yml with SQLite volume mount - Add .env.sample documenting all required and optional vars Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
64
admin.tsx
64
admin.tsx
@@ -192,7 +192,7 @@ function App() {
|
||||
if (mode === "checking") {
|
||||
return (
|
||||
<div className="admin admin--centered">
|
||||
<div className="loading">Checking admin session...</div>
|
||||
<div className="loading">Comprobando sesión de administrador...</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -202,12 +202,12 @@ function App() {
|
||||
<div className="admin admin--centered">
|
||||
<main className="panel panel--login">
|
||||
<a href="/" className="logo-link">
|
||||
<img src="/assets/logo.svg" alt="quipslop" />
|
||||
<img src="/assets/logo.svg" alt="argument.es" />
|
||||
</a>
|
||||
<h1>Admin Access</h1>
|
||||
<h1>Acceso de administrador</h1>
|
||||
<p className="muted">
|
||||
Enter your passcode once. A secure cookie will keep this browser
|
||||
logged in.
|
||||
Introduce tu contraseña una vez. Una cookie segura mantendrá
|
||||
esta sesión activa en el navegador.
|
||||
</p>
|
||||
|
||||
<form
|
||||
@@ -218,7 +218,7 @@ function App() {
|
||||
data-lpignore="true"
|
||||
>
|
||||
<label htmlFor="passcode" className="field-label">
|
||||
Passcode
|
||||
Contraseña
|
||||
</label>
|
||||
<input
|
||||
id="passcode"
|
||||
@@ -239,15 +239,15 @@ function App() {
|
||||
data-1p-ignore
|
||||
data-lpignore="true"
|
||||
>
|
||||
{pending === "login" ? "Checking..." : "Unlock Admin"}
|
||||
{pending === "login" ? "Comprobando..." : "Desbloquear Admin"}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{error && <div className="error-banner">{error}</div>}
|
||||
|
||||
<div className="quick-links">
|
||||
<a href="/">Live Game</a>
|
||||
<a href="/history">History</a>
|
||||
<a href="/">Juego en vivo</a>
|
||||
<a href="/history">Historial</a>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
@@ -258,23 +258,23 @@ function App() {
|
||||
<div className="admin">
|
||||
<header className="admin-header">
|
||||
<a href="/" className="logo-link">
|
||||
quipslop
|
||||
argument.es
|
||||
</a>
|
||||
<nav className="quick-links">
|
||||
<a href="/">Live Game</a>
|
||||
<a href="/history">History</a>
|
||||
<a href="/">Juego en vivo</a>
|
||||
<a href="/history">Historial</a>
|
||||
<button className="link-button" onClick={onLogout} disabled={busy}>
|
||||
Logout
|
||||
Cerrar sesión
|
||||
</button>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main className="panel panel--main">
|
||||
<div className="panel-head">
|
||||
<h1>Admin Console</h1>
|
||||
<h1>Consola de administrador</h1>
|
||||
<p>
|
||||
Pause/resume the game loop, export all data as JSON, or wipe all
|
||||
stored data.
|
||||
Pausa/reanuda el bucle del juego, exporta todos los datos en JSON
|
||||
o borra todos los datos almacenados.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -282,18 +282,18 @@ function App() {
|
||||
|
||||
<section className="status-grid" aria-live="polite">
|
||||
<StatusCard
|
||||
label="Engine"
|
||||
value={snapshot?.isPaused ? "Paused" : "Running"}
|
||||
label="Motor"
|
||||
value={snapshot?.isPaused ? "En pausa" : "Ejecutándose"}
|
||||
/>
|
||||
<StatusCard
|
||||
label="Active Round"
|
||||
value={snapshot?.isRunningRound ? "In Progress" : "Idle"}
|
||||
label="Ronda activa"
|
||||
value={snapshot?.isRunningRound ? "En curso" : "Inactivo"}
|
||||
/>
|
||||
<StatusCard
|
||||
label="Persisted Rounds"
|
||||
label="Rondas guardadas"
|
||||
value={String(snapshot?.persistedRounds ?? 0)}
|
||||
/>
|
||||
<StatusCard label="Viewers" value={String(snapshot?.viewerCount ?? 0)} />
|
||||
<StatusCard label="Espectadores" value={String(snapshot?.viewerCount ?? 0)} />
|
||||
</section>
|
||||
|
||||
<section className="actions" aria-label="Admin actions">
|
||||
@@ -303,7 +303,7 @@ function App() {
|
||||
disabled={busy || Boolean(snapshot?.isPaused)}
|
||||
onClick={() => runControl("/api/admin/pause", "pause")}
|
||||
>
|
||||
{pending === "pause" ? "Pausing..." : "Pause"}
|
||||
{pending === "pause" ? "Pausando..." : "Pausar"}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@@ -311,10 +311,10 @@ function App() {
|
||||
disabled={busy || !snapshot?.isPaused}
|
||||
onClick={() => runControl("/api/admin/resume", "resume")}
|
||||
>
|
||||
{pending === "resume" ? "Resuming..." : "Resume"}
|
||||
{pending === "resume" ? "Reanudando..." : "Reanudar"}
|
||||
</button>
|
||||
<button type="button" className="btn" disabled={busy} onClick={onExport}>
|
||||
{pending === "export" ? "Exporting..." : "Export JSON"}
|
||||
{pending === "export" ? "Exportando..." : "Exportar JSON"}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@@ -322,7 +322,7 @@ function App() {
|
||||
disabled={busy}
|
||||
onClick={() => setIsResetOpen(true)}
|
||||
>
|
||||
Reset Data
|
||||
Borrar datos
|
||||
</button>
|
||||
</section>
|
||||
</main>
|
||||
@@ -330,13 +330,13 @@ function App() {
|
||||
{isResetOpen && (
|
||||
<div className="modal-backdrop" role="dialog" aria-modal="true">
|
||||
<div className="modal">
|
||||
<h2>Reset all data?</h2>
|
||||
<h2>¿Borrar todos los datos?</h2>
|
||||
<p>
|
||||
This permanently deletes every saved round and resets scores.
|
||||
Current game flow is also paused.
|
||||
Esto elimina permanentemente todas las rondas guardadas y
|
||||
reinicia las puntuaciones. El juego también se pausará.
|
||||
</p>
|
||||
<p>
|
||||
Type <code>{RESET_TOKEN}</code> to continue.
|
||||
Escribe <code>{RESET_TOKEN}</code> para continuar.
|
||||
</p>
|
||||
<input
|
||||
type="text"
|
||||
@@ -356,7 +356,7 @@ function App() {
|
||||
}}
|
||||
disabled={busy}
|
||||
>
|
||||
Cancel
|
||||
Cancelar
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@@ -364,7 +364,7 @@ function App() {
|
||||
onClick={onReset}
|
||||
disabled={busy || resetText !== RESET_TOKEN}
|
||||
>
|
||||
{pending === "reset" ? "Resetting..." : "Confirm Reset"}
|
||||
{pending === "reset" ? "Borrando..." : "Confirmar borrado"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user