WO-TF-012. Neo-brutalist creative-studio theme brought up to the Wave A OVERRIDE-CONTRACT (frozen against cms a0f07e2ae). - Override all 49 mandatory builtin keys in templates/overrides/brutalist/ (chrome, marketing, primitives, commerce, blog family, auth surface, 404), each carrying the brutalist chrome (chunky borders, hard offset shadows, hover snap, mono uppercase meta, candy accents) via a raw-CSS "bru-*" kit shipped in manifest.yaml. Load-bearing wiring (HTMX auth endpoints, signup form, contact-form submit + honeypot, facade scripts, lightbox) preserved verbatim. - 7 page templates: default, full-width, landing, article, blog-index, contact, auth (fixed a bug where templates omitted the `dark` class so dark presets never activated). - Blocks rework: removed 6 blocks that duplicated builtins (masthead, concrete_hero, meta_strip, caption_image, pull_quote, colophon) — now overrides; kept project_ledger; added persona blocks sticker_wall, changelog, spec_sheet (4 total). - 4 dual-mode presets (all mode "both", 19 tokens light + dark): Concrete & Cadmium, Hazard, Riso, Acid. - Bundled 8 latin-subset OFL woff2 (Space Grotesk, Archivo Black, Inter, IBM Plex Mono) in assets/fonts/ + LICENSES.md; fonts.json populated; all font-family via var(--font-*). RECOMMENDED_FONTS/ICONS updated; required_icon_packs declared. - Email-safe themed wrapper (tables, inline styles) cleaned up. - master_pages.json reworked to builtin navbar/hero/cta/footer. - Demo seed (seed/seed.json + workflows.json, demo:true): home, about, blog (3 posts), contact (form + contact_submissions data table + row_inserted → email-admins workflow), login — studio voice. Known codeless limitation: page-suggestions renders themed 404 chrome but the similar-pages list (server-side DB query, no template provider) can't be reproduced; auth-form captcha widget is server-generated and can't be emitted (seed leaves captchaEnabled=false). Verified: make exit 0; check-safety exit 0. Visual quality UNVERIFIED until Wave B. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
62 lines
5.3 KiB
Plaintext
62 lines
5.3 KiB
Plaintext
{# brutalist auth-form override — bordered login/register card. HTMX endpoints + input names + tab panels are load-bearing (public_auth.go); kept exact. Fields: default_tab, show_social, captchaEnabled; context.isPublicLoggedIn, context.publicUsername, context.site.google_oauth_client_id/facebook_app_id. NOTE: the proof-of-work captcha widget is server-generated and cannot be emitted from a codeless template — do NOT enable captchaEnabled on an override-rendered auth-form (see WO limitation). #}
|
|
{% if context.isPublicLoggedIn %}
|
|
<div class="bru-slab bru-shadow p-6 text-center" style="max-width:28rem;margin:0 auto">
|
|
<p class="bru-meta">Logged in as <strong class="text-foreground">{{ context.publicUsername }}</strong></p>
|
|
<a href="/account" class="bru-btn bru-btn-ghost mt-4">My Account</a>
|
|
</div>
|
|
{% else %}
|
|
{% set defaultTab = default_tab|default:"login" %}
|
|
<style>
|
|
.bru-auth-tab{color:hsl(var(--muted-foreground));border-bottom:3px solid transparent;margin-bottom:-3px;background:transparent}
|
|
.bru-auth-tab[data-active="1"]{color:hsl(var(--foreground));border-bottom-color:hsl(var(--accent))}
|
|
</style>
|
|
<div class="auth-form" style="max-width:28rem;margin:0 auto">
|
|
<div id="auth-message"></div>
|
|
<div class="flex mb-6" style="border-bottom:3px solid hsl(var(--border))">
|
|
<button type="button" data-auth-tab="login" class="bru-auth-tab flex-1 py-2.5 bru-meta" data-active="{% if defaultTab == "register" %}0{% else %}1{% endif %}">Login</button>
|
|
<button type="button" data-auth-tab="register" class="bru-auth-tab flex-1 py-2.5 bru-meta" data-active="{% if defaultTab == "register" %}1{% else %}0{% endif %}">Register</button>
|
|
</div>
|
|
<div id="login-panel"{% if defaultTab == "register" %} class="hidden"{% endif %}>
|
|
<form hx-post="/api/auth/login" hx-target="#auth-message" hx-swap="innerHTML" class="space-y-4">
|
|
<div><label class="bru-label">Email</label><input type="email" name="email" required class="bru-field"></div>
|
|
<div><label class="bru-label">Password</label><input type="password" name="password" required class="bru-field"></div>
|
|
{% if captchaEnabled %}<p class="bru-meta text-destructive">Captcha is enabled but cannot render in this theme. Disable it on the auth-form block.</p>{% endif %}
|
|
<button type="submit" class="bru-btn bru-btn-solid w-full" hx-disabled-elt="this">Login</button>
|
|
<p class="text-center bru-meta"><a href="/forgot-password" class="text-accent underline underline-offset-4">Forgot password?</a></p>
|
|
</form>
|
|
{% if show_social != false and (context.site.google_oauth_client_id or context.site.facebook_app_id) %}
|
|
<div class="mt-5"><div class="relative my-4"><hr class="bru-rule-thin"><span class="bru-meta" style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:hsl(var(--background));padding:0 .6rem">or</span></div>
|
|
{% if context.site.google_oauth_client_id %}<a href="/api/auth/google/start" class="bru-btn bru-btn-ghost w-full mb-2">Continue with Google</a>{% endif %}
|
|
{% if context.site.facebook_app_id %}<a href="/api/auth/facebook/start" class="bru-btn bru-btn-ghost w-full">Continue with Facebook</a>{% endif %}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div id="register-panel"{% if defaultTab != "register" %} class="hidden"{% endif %}>
|
|
<form hx-post="/api/auth/register" hx-target="#auth-message" hx-swap="innerHTML" class="space-y-4">
|
|
<div><label class="bru-label">Username</label><input type="text" name="username" required pattern="[a-zA-Z0-9_-]{3,30}" class="bru-field"></div>
|
|
<div><label class="bru-label">Email</label><input type="email" name="email" required class="bru-field"></div>
|
|
<div><label class="bru-label">Password</label><input type="password" name="password" required minlength="8" class="bru-field"></div>
|
|
{% if captchaEnabled %}<p class="bru-meta text-destructive">Captcha is enabled but cannot render in this theme. Disable it on the auth-form block.</p>{% endif %}
|
|
<button type="submit" class="bru-btn bru-btn-solid w-full" hx-disabled-elt="this">Create Account</button>
|
|
</form>
|
|
{% if show_social != false and (context.site.google_oauth_client_id or context.site.facebook_app_id) %}
|
|
<div class="mt-5"><div class="relative my-4"><hr class="bru-rule-thin"><span class="bru-meta" style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:hsl(var(--background));padding:0 .6rem">or</span></div>
|
|
{% if context.site.google_oauth_client_id %}<a href="/api/auth/google/start" class="bru-btn bru-btn-ghost w-full mb-2">Continue with Google</a>{% endif %}
|
|
{% if context.site.facebook_app_id %}<a href="/api/auth/facebook/start" class="bru-btn bru-btn-ghost w-full">Continue with Facebook</a>{% endif %}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<script>
|
|
(function(){
|
|
var tabs=document.querySelectorAll('[data-auth-tab]');
|
|
if(!tabs.length)return;
|
|
function activate(name){
|
|
var lp=document.getElementById('login-panel'),rp=document.getElementById('register-panel');
|
|
if(lp)lp.classList.toggle('hidden',name!=='login');
|
|
if(rp)rp.classList.toggle('hidden',name!=='register');
|
|
tabs.forEach(function(t){t.setAttribute('data-active',t.getAttribute('data-auth-tab')===name?'1':'0');});
|
|
}
|
|
tabs.forEach(function(t){t.addEventListener('click',function(){activate(t.getAttribute('data-auth-tab'));});});
|
|
})();
|
|
</script>
|
|
{% endif %}
|