Files
pictureFrame-webApp/templates/security/login.html.twig
T
football2801 0489028486
CI / test (push) Has been cancelled
refactor(design): single source of truth — wevisto-design.css
v2 tokens were duplicated: in design-v2.scss for the SPA, inlined in
login.html.twig for Twig. Two places to keep in sync.

Now: one shared /public/css/wevisto-design.css loaded by every Twig
standalone template AND linked from the SPA index.html. It contains:
- Brand constants (yellow / navy / fonts)
- v2 tokens with per-theme dusk overrides
- v2 base body bg + editorial typography defaults
- v2 overrides for the .card / .btn / .field-error / .logo-badge
  patterns used across all Twig templates

The SPA's design-v2.scss now holds only SPA-specific composition:
side rail at desktop, frame card, theme swatch harbor preview,
settings polish. No token duplication.

Result: changing a v2 color in one file flows to every surface in both
worlds. Adding v2 to another Twig template only requires the existing
shared CSS link (already wired up to all 11 standalone templates).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 15:24:45 -04:00

124 lines
4.6 KiB
Twig

<!DOCTYPE html>
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v1') }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/svg+xml" href="/build/favicon.svg?v=20260515-vviewfinder">
<link rel="icon" type="image/png" sizes="32x32" href="/build/icons/favicon-32.png?v=20260515-vviewfinder">
<link rel="icon" type="image/png" sizes="16x16" href="/build/icons/favicon-16.png?v=20260515-vviewfinder">
<link rel="apple-touch-icon" sizes="180x180" href="/build/icons/apple-touch-icon.png?v=20260515-vviewfinder">
<link rel="stylesheet" href="/css/wevisto-design.css">
<title>Sign in — WeVisto</title>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: system-ui, sans-serif;
display: flex;
align-items: center;
justify-content: center;
min-height: 100dvh;
background: #fdf6ee;
color: #3a2e22;
}
.card {
width: 100%;
max-width: 380px;
margin: 1rem;
padding: 2rem;
background: #fff9f2;
border-radius: 16px;
border: 1px solid #e8d9c4;
}
h1 { font-size: 1.4rem; font-weight: 700; margin-bottom: 1.5rem; }
.field { margin-bottom: 1rem; }
label { display: block; font-size: 0.8125rem; font-weight: 600; color: #8a7060; margin-bottom: 0.375rem; }
input[type="email"],
input[type="password"] {
width: 100%;
min-height: 44px;
padding: 0 0.875rem;
border: 1px solid #e8d9c4;
border-radius: 10px;
background: #fff;
font-size: 1rem;
color: #3a2e22;
transition: border-color 0.15s;
}
input:focus { outline: none; border-color: #c97c3a; }
input[aria-invalid="true"] { border-color: #c0392b; }
.field-error {
margin-top: 0.25rem;
font-size: 0.8125rem;
color: #c0392b;
min-height: 1.2em;
}
.btn {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: 44px;
margin-top: 1.25rem;
background: #c97c3a;
color: #fff;
border: none;
border-radius: 9999px;
font-size: 1rem;
font-weight: 700;
cursor: pointer;
transition: opacity 0.15s;
}
.btn:hover { opacity: 0.9; }
.register-link { display: block; text-align: center; margin-top: 1rem; font-size: 0.875rem; color: #8a7060; }
.register-link a { color: #c97c3a; text-decoration: none; font-weight: 600; }
.logo-badge { display: block; width: 88px; height: 88px; margin: 0 auto 1.25rem; border-radius: 14px; overflow: hidden; border: 1px solid #e8d9c4; box-shadow: 0 2px 10px rgba(0,0,0,.06); }
.logo-badge img { display: block; width: 100%; height: 100%; }
</style>
</head>
<body>
<div class="card">
<a href="/" class="logo-badge" aria-label="WeVisto"><img src="/build/logo.svg" alt=""></a>
<h1>Sign in</h1>
<form method="post" novalidate>
<div class="field">
<label for="inputEmail">Email address</label>
<input
type="email"
id="inputEmail"
name="_username"
value="{{ last_username }}"
autocomplete="email"
aria-describedby="login-error"
{% if error %}aria-invalid="true"{% endif %}
autofocus
>
</div>
<div class="field">
<label for="inputPassword">Password</label>
<input
type="password"
id="inputPassword"
name="_password"
autocomplete="current-password"
aria-describedby="login-error"
{% if error %}aria-invalid="true"{% endif %}
>
{% if error %}
<p id="login-error" class="field-error" role="alert">Incorrect email or password</p>
{% else %}
<p id="login-error" class="field-error"></p>
{% endif %}
</div>
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
<button type="submit" class="btn">Sign in</button>
</form>
<p class="register-link">Don't have an account? <a href="/register">Create one</a></p>
</div>
</body>
</html>