feat(14-01): create auth_components.templ and auth_layout.templ
- auth_components.templ: AnimatedBackground (35 elements, /static/logo_dark.png, no light/dark pairs), GoogleButton (a/button variant, English label 'Sign in with Google'), AuthDivider ('or' divider)
- auth_layout.templ: standalone HTML shell with .login-screen, @AnimatedBackground(), .card-wrap/.card-glow/.auth-card-shell, htmx.min.js only (no sortable/sse scripts)
- No auth.User param on AuthLayout (auth pages always unauthenticated)
- just generate exits 0, all Go tests pass
This commit is contained in:
parent
cf116ff696
commit
e4d5f96571
2 changed files with 211 additions and 0 deletions
174
backend/templates/auth_components.templ
Normal file
174
backend/templates/auth_components.templ
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
package templates
|
||||
|
||||
// AnimatedBackground renders 35 decorative logo elements that animate across
|
||||
// the auth page background. The .background-layer carries aria-hidden="true"
|
||||
// so screen readers ignore all decorative content (T-14-01-03).
|
||||
//
|
||||
// Each element uses a single logo_dark.png image (dark-mode swap deferred per
|
||||
// DEFERRED/DARK-01). Image paths use /static/logo_dark.png — backend serves
|
||||
// static files under /static/ unlike go-backend which serves from /.
|
||||
templ AnimatedBackground() {
|
||||
<div class="background-layer" aria-hidden="true">
|
||||
<div class="background-logo bg-01 animate-move-right-slow opacity-04">
|
||||
<img alt="Xtablo" class="logo-asset size-16 animate-spin-slow" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-02 animate-move-right-medium opacity-03">
|
||||
<img alt="Xtablo" class="logo-asset size-12 animate-bounce-gentle" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-03 animate-move-right-fast opacity-05">
|
||||
<img alt="Xtablo" class="logo-asset size-20 animate-pulse-gentle" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-04 animate-move-right-slow opacity-02">
|
||||
<img alt="Xtablo" class="logo-asset size-14 animate-wiggle" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-05 animate-move-right-medium opacity-03">
|
||||
<img alt="Xtablo" class="logo-asset size-18 animate-float-gentle" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-06 animate-move-diagonal-1 opacity-03">
|
||||
<img alt="Xtablo" class="logo-asset size-10 animate-spin-reverse" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-07 animate-move-diagonal-2 opacity-04">
|
||||
<img alt="Xtablo" class="logo-asset size-16 animate-scale-gentle" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-08 animate-move-diagonal-3 opacity-02">
|
||||
<img alt="Xtablo" class="logo-asset size-12 animate-rotate-gentle" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-09 animate-move-down-slow opacity-03">
|
||||
<img alt="Xtablo" class="logo-asset size-14 animate-bounce-soft" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-10 animate-move-down-medium opacity-04">
|
||||
<img alt="Xtablo" class="logo-asset size-16 animate-sway" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-11 animate-orbit-1 opacity-02">
|
||||
<img alt="Xtablo" class="logo-asset size-08" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-12 animate-orbit-2 opacity-03">
|
||||
<img alt="Xtablo" class="logo-asset size-10" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-13 animate-orbit-3 opacity-02">
|
||||
<img alt="Xtablo" class="logo-asset size-06" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-14 animate-orbit-4 opacity-03">
|
||||
<img alt="Xtablo" class="logo-asset size-12 animate-spin-fast" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-15 animate-orbit-5 opacity-02">
|
||||
<img alt="Xtablo" class="logo-asset size-07 animate-pulse-fast" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-16 animate-zigzag-1 opacity-04">
|
||||
<img alt="Xtablo" class="logo-asset size-14 animate-wobble" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-17 animate-zigzag-2 opacity-03">
|
||||
<img alt="Xtablo" class="logo-asset size-11 animate-shake" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-18 animate-zigzag-3 opacity-05">
|
||||
<img alt="Xtablo" class="logo-asset size-16 animate-bounce-crazy" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-19 animate-spiral-1 opacity-03">
|
||||
<img alt="Xtablo" class="logo-asset size-09 animate-spin-wobble" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-20 animate-spiral-2 opacity-04">
|
||||
<img alt="Xtablo" class="logo-asset size-13 animate-flip" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-21 animate-float-random-1 opacity-02">
|
||||
<img alt="Xtablo" class="logo-asset size-08 animate-twirl" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-22 animate-float-random-2 opacity-03">
|
||||
<img alt="Xtablo" class="logo-asset size-10 animate-dance" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-23 animate-float-random-3 opacity-04">
|
||||
<img alt="Xtablo" class="logo-asset size-12 animate-jiggle" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-24 animate-float-random-4 opacity-02">
|
||||
<img alt="Xtablo" class="logo-asset size-09 animate-vibrate" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-25 animate-wave-1 opacity-03">
|
||||
<img alt="Xtablo" class="logo-asset size-11 animate-swing" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-26 animate-wave-2 opacity-04">
|
||||
<img alt="Xtablo" class="logo-asset size-13 animate-pendulum" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-27 animate-wave-3 opacity-02">
|
||||
<img alt="Xtablo" class="logo-asset size-10 animate-elastic" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-28 animate-wave-4 opacity-05">
|
||||
<img alt="Xtablo" class="logo-asset size-15 animate-rubber" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-29 animate-corner-shoot-1 opacity-03">
|
||||
<img alt="Xtablo" class="logo-asset size-12 animate-rocket" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-30 animate-corner-shoot-2 opacity-04">
|
||||
<img alt="Xtablo" class="logo-asset size-14 animate-comet" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-31 animate-corner-shoot-3 opacity-02">
|
||||
<img alt="Xtablo" class="logo-asset size-10 animate-meteor" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-32 animate-corner-shoot-4 opacity-05">
|
||||
<img alt="Xtablo" class="logo-asset size-16 animate-blast" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-33 animate-bounce-ball-1 opacity-04">
|
||||
<img alt="Xtablo" class="logo-asset size-08 animate-spin-bounce" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-34 animate-bounce-ball-2 opacity-03">
|
||||
<img alt="Xtablo" class="logo-asset size-11 animate-flip-bounce" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
<div class="background-logo bg-35 animate-bounce-ball-3 opacity-05">
|
||||
<img alt="Xtablo" class="logo-asset size-13 animate-scale-bounce" src="/static/logo_dark.png"/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
// GoogleButton renders the Material Design Google Sign-In button.
|
||||
//
|
||||
// When configured=true the button is an <a> element linking to the OAuth start
|
||||
// URL. When configured=false the button is rendered as a disabled <button> to
|
||||
// signal the provider is unavailable.
|
||||
//
|
||||
// The label uses English per D-G03 convention ("Sign in with Google").
|
||||
// The Google SVG uses four colored paths verbatim from the Material Design spec.
|
||||
templ GoogleButton(href string, configured bool) {
|
||||
if configured {
|
||||
<a class="gsi-material-button" href={ templ.SafeURL(href) }>
|
||||
<div class="gsi-material-button-state"></div>
|
||||
<div class="gsi-material-button-content-wrapper">
|
||||
<div class="gsi-material-button-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" aria-hidden="true">
|
||||
<path fill="#EA4335" d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"></path>
|
||||
<path fill="#4285F4" d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z"></path>
|
||||
<path fill="#FBBC05" d="M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z"></path>
|
||||
<path fill="#34A853" d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z"></path>
|
||||
<path fill="none" d="M0 0h48v48H0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<span class="gsi-material-button-contents">Sign in with Google</span>
|
||||
<span class="visually-hidden">Sign in with Google</span>
|
||||
</div>
|
||||
</a>
|
||||
} else {
|
||||
<button type="button" class="gsi-material-button" disabled aria-disabled="true">
|
||||
<div class="gsi-material-button-state"></div>
|
||||
<div class="gsi-material-button-content-wrapper">
|
||||
<div class="gsi-material-button-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" aria-hidden="true">
|
||||
<path fill="#EA4335" d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"></path>
|
||||
<path fill="#4285F4" d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z"></path>
|
||||
<path fill="#FBBC05" d="M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z"></path>
|
||||
<path fill="#34A853" d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z"></path>
|
||||
<path fill="none" d="M0 0h48v48H0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<span class="gsi-material-button-contents">Sign in with Google</span>
|
||||
<span class="visually-hidden">Sign in with Google</span>
|
||||
</div>
|
||||
</button>
|
||||
}
|
||||
}
|
||||
|
||||
// AuthDivider renders a horizontal divider with an "or" pill separator.
|
||||
// English label per D-G03 convention (not "Ou continuer avec" from go-backend).
|
||||
templ AuthDivider() {
|
||||
<div class="divider-row">
|
||||
<div class="divider-line"></div>
|
||||
<span class="divider-pill">or</span>
|
||||
<div class="divider-line"></div>
|
||||
</div>
|
||||
}
|
||||
37
backend/templates/auth_layout.templ
Normal file
37
backend/templates/auth_layout.templ
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
package templates
|
||||
|
||||
// AuthLayout is the standalone HTML shell for auth pages (/login, /signup).
|
||||
//
|
||||
// It replaces @Layout(...) for these pages. Differences from Layout:
|
||||
// - No header, footer, or <main> wrapper — auth pages are full-viewport centered
|
||||
// - Body uses .login-screen (gradient bg, flex center) instead of min-h-screen bg-white
|
||||
// - @AnimatedBackground() renders 35 animated logo elements behind the card
|
||||
// - No auth.User param — auth pages are always unauthenticated (T-14-01-04)
|
||||
// - Scripts: only htmx.min.js — sortable.min.js and discussion-sse.js are not needed
|
||||
//
|
||||
// csrfToken is threaded so page children (LoginPage, SignupPage) can forward it
|
||||
// into their form fragments via ui.CSRFField(csrfToken). AuthLayout itself does
|
||||
// not embed a CSRF field — only the form fragments do.
|
||||
templ AuthLayout(title string, csrfToken string) {
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>{ title }</title>
|
||||
<link rel="stylesheet" href="/static/tailwind.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="login-screen">
|
||||
@AnimatedBackground()
|
||||
<div class="card-wrap">
|
||||
<div class="card-glow"></div>
|
||||
<div class="auth-card-shell">
|
||||
{ children... }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/static/htmx.min.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
}
|
||||
Loading…
Reference in a new issue