feat(atm-plataforma): tela de login Athletic Map
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# GERADO por scripts/tema_login_escolinha.py — nao edite na mao.
|
||||
# Fonte: keycloak-theme/escolinha/*.ftl (login.ftl, login-update-password.ftl, estilo.ftl, template.ftl, error.ftl, info.ftl, logout-confirm.ftl, login-page-expired.ftl, login-reset-password.ftl, login-config-totp.ftl, login-otp.ftl, webauthn-register.ftl, webauthn-authenticate.ftl, select-authenticator.ftl)
|
||||
# Fonte: keycloak-theme/escolinha/*.ftl (login.ftl, login-update-password.ftl, estilo.ftl, template.ftl, error.ftl, info.ftl, logout-confirm.ftl, login-page-expired.ftl, login-reset-password.ftl, login-config-totp.ftl, login-otp.ftl, webauthn-register.ftl, webauthn-authenticate.ftl, select-authenticator.ftl, login-username.ftl, login-password.ftl)
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
@@ -616,6 +616,26 @@ data:
|
||||
.credenciais input:checked+label.cartao{border-color:var(--orange);box-shadow:0 0 0 3px rgba(245,130,32,.16)}
|
||||
.conteudo .cartao.estatico{cursor:default}
|
||||
|
||||
/* "Primeiro o usuario, depois a senha" (login-username, login-password —
|
||||
2026-10-08): os mesmos campos do login, agora DENTRO de `.conteudo`, cujo
|
||||
`button` laranja de largura toda e `a` sublinhado engoliriam o olho da
|
||||
senha, o "Esqueceu sua senha?" e o botao de passkey da macro do base. */
|
||||
.conteudo button.olho{width:40px;height:40px;margin:0;padding:0;background:transparent;
|
||||
color:#8F8F8B;border-radius:9px}
|
||||
.conteudo button.olho:hover{background:#F2F0EC;color:var(--navy)}
|
||||
.conteudo .esqueci{text-decoration:none}
|
||||
.conteudo .esqueci:hover{text-decoration:underline}
|
||||
.sub .trocar-conta{color:var(--blue);text-decoration:none;white-space:nowrap}
|
||||
.sub .trocar-conta:hover{text-decoration:underline}
|
||||
.sociais{display:flex;flex-direction:column;gap:12px;margin-top:16px}
|
||||
.conteudo a#authenticateWebAuthnButton{
|
||||
display:flex;align-items:center;justify-content:center;gap:10px;
|
||||
width:100%;height:56px;margin-top:12px;border-radius:12px;box-sizing:border-box;
|
||||
font-size:16px;font-weight:700;text-decoration:none;
|
||||
background:#fff;color:var(--navy);border:1.5px solid var(--line);
|
||||
}
|
||||
.conteudo a#authenticateWebAuthnButton:hover{background:#F6F4F1;color:var(--navy)}
|
||||
|
||||
/* ---------- Telas estreitas ---------- */
|
||||
@media (max-width:980px){
|
||||
.stage{grid-template-columns:1fr}
|
||||
@@ -1438,3 +1458,172 @@ data:
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
||||
|
||||
login-username.ftl: |-
|
||||
<#--
|
||||
PRIMEIRO O USUARIO — a etapa "Username Form" de um fluxo que pede o e-mail
|
||||
numa tela e a senha (ou a passkey) na seguinte. A senha e a login-password.ftl.
|
||||
|
||||
Nenhum realm usa esse fluxo hoje (o login de todos e a login.ftl, usuario e
|
||||
senha juntos). Esta pagina existe para que, se um fluxo passar a usa-lo — o
|
||||
caminho natural da passkey sem senha —, a tela nao caia no tema de fabrica no
|
||||
meio do login (2026-10-08).
|
||||
|
||||
NAO MUDE OS NOMES: sao os do tema base do Keycloak 26.x. O authenticator le
|
||||
`username` e `rememberMe` do POST; o form e `kc-form-login` e o botao
|
||||
`kc-login` (name `login`, que o `onsubmit` desliga); o erro do campo e
|
||||
`input-error-username`. Com `usernameHidden` (o usuario ja foi identificado
|
||||
por outra etapa), o campo e o "Lembrar-me" saem, como no base.
|
||||
|
||||
A passkey e a macro do tema BASE (`passkeys.ftl`), como no login.ftl: o
|
||||
`webauthn` no autocomplete faz o navegador sugerir a passkey no proprio campo,
|
||||
e sem a politica "Passkeys" no realm a macro nao desenha nada.
|
||||
-->
|
||||
<#import "template.ftl" as layout>
|
||||
<#import "passkeys.ftl" as passkeys>
|
||||
<@layout.registrationLayout displayMessage=!messagesPerField.existsError('username') displayInfo=(realm.password && realm.registrationAllowed && !registrationDisabled??); section>
|
||||
<#if section = "header">
|
||||
<#if (realm.name!"") == "athleticmap">
|
||||
Painel do <span class="hl">dono</span>
|
||||
<#elseif (realm.name!"") == "clientes">
|
||||
Painel da sua <span class="hl">conta</span>
|
||||
<#else>
|
||||
Bem-vindo de <span class="hl">volta!</span>
|
||||
</#if>
|
||||
<#elseif section = "sub">
|
||||
<#if (realm.name!"") == "athleticmap">
|
||||
Área restrita à administração da Athletic Map
|
||||
<#else>
|
||||
Acesse sua conta para continuar
|
||||
</#if>
|
||||
<#elseif section = "form">
|
||||
<#if realm.password>
|
||||
<form id="kc-form-login" onsubmit="login.disabled = true; return true;" action="${url.loginAction}" method="post" novalidate>
|
||||
<#if !usernameHidden??>
|
||||
<div class="campo">
|
||||
<label class="rotulo" for="username"><#if !realm.loginWithEmailAllowed>${msg("username")}<#elseif !realm.registrationEmailAsUsername>${msg("usernameOrEmail")}<#else>${msg("email")}</#if></label>
|
||||
<div class="caixa">
|
||||
<span class="icone">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="14" rx="2.5"/><path d="m3.5 7 8.5 6 8.5-6"/></svg>
|
||||
</span>
|
||||
<input tabindex="1" id="username" name="username" type="text" autofocus dir="ltr"
|
||||
placeholder="seu@email.com" value="${(login.username!'')}"
|
||||
autocomplete="${(enableWebAuthnConditionalUI?has_content)?then('username webauthn', 'username')}"
|
||||
aria-invalid="<#if messagesPerField.existsError('username')>true</#if>"
|
||||
class="<#if messagesPerField.existsError('username')>erro</#if>"/>
|
||||
</div>
|
||||
<#if messagesPerField.existsError('username')>
|
||||
<span id="input-error-username" class="erro-campo" aria-live="polite">${kcSanitize(messagesPerField.get('username'))?no_esc}</span>
|
||||
</#if>
|
||||
</div>
|
||||
</#if>
|
||||
|
||||
<#if realm.rememberMe && !usernameHidden??>
|
||||
<div class="opcoes">
|
||||
<label class="lembrar">
|
||||
<input tabindex="3" id="rememberMe" name="rememberMe" type="checkbox"
|
||||
<#if login.rememberMe??>checked</#if>/> ${msg("rememberMe")}
|
||||
</label>
|
||||
</div>
|
||||
</#if>
|
||||
|
||||
<button tabindex="4" class="botao entrar" name="login" id="kc-login" type="submit">
|
||||
Continuar
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m13 6 6 6-6 6"/></svg>
|
||||
</button>
|
||||
</form>
|
||||
<#-- FORA do form: a macro traz os proprios forms (`webauth`, `authn_select`). -->
|
||||
<@passkeys.conditionalUIData />
|
||||
</#if>
|
||||
<#elseif section = "info">
|
||||
<#if realm.password && realm.registrationAllowed && !registrationDisabled??>
|
||||
<div id="kc-registration">
|
||||
<span>${msg("noAccount")} <a tabindex="6" href="${url.registrationUrl}">${msg("doRegister")}</a></span>
|
||||
</div>
|
||||
</#if>
|
||||
<#elseif section = "socialProviders">
|
||||
<#-- Mesmo desenho do login.ftl. Hoje nenhum realm tem provedor. -->
|
||||
<#if realm.password && social?? && social.providers?? && social.providers?has_content>
|
||||
<div id="kc-social-providers" class="sociais">
|
||||
<div class="ou">ou</div>
|
||||
<#list social.providers as p>
|
||||
<a id="social-${p.alias!''}" class="botao social" href="${p.loginUrl}">
|
||||
<#if p.providerId?? && p.providerId == "google">
|
||||
<svg width="20" height="20" viewBox="0 0 48 48" aria-hidden="true"><path fill="#4285F4" d="M45.1 24.5c0-1.6-.1-3.1-.4-4.5H24v8.5h11.8c-.5 2.8-2.1 5.1-4.4 6.7v5.6h7.1c4.2-3.8 6.6-9.5 6.6-16.3z"/><path fill="#34A853" d="M24 46c6 0 11-2 14.6-5.4l-7.1-5.6c-2 1.3-4.5 2.1-7.5 2.1-5.8 0-10.7-3.9-12.4-9.1H4.3v5.8C7.9 41.1 15.4 46 24 46z"/><path fill="#FBBC05" d="M11.6 28c-.4-1.3-.7-2.6-.7-4s.3-2.7.7-4v-5.8H4.3C2.8 17.1 2 20.4 2 24s.8 6.9 2.3 9.8L11.6 28z"/><path fill="#EA4335" d="M24 10.9c3.3 0 6.2 1.1 8.5 3.3l6.3-6.3C35 4.4 30 2 24 2 15.4 2 7.9 6.9 4.3 14.2l7.3 5.8c1.7-5.2 6.6-9.1 12.4-9.1z"/></svg>
|
||||
<#else>
|
||||
<svg width="19" height="19" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3 4 6v6c0 5 3.4 8 8 9 4.6-1 8-4 8-9V6l-8-3Z"/></svg>
|
||||
</#if>
|
||||
Entrar com ${p.displayName!'SSO'}
|
||||
</a>
|
||||
</#list>
|
||||
</div>
|
||||
</#if>
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
||||
|
||||
login-password.ftl: |-
|
||||
<#--
|
||||
DEPOIS A SENHA — a etapa "Password Form" de um fluxo que pediu o e-mail
|
||||
antes (login-username.ftl, ou o usuario ja identificado por outra etapa).
|
||||
|
||||
Nenhum realm usa esse fluxo hoje; ver o cabecalho da login-username.ftl.
|
||||
|
||||
NAO MUDE OS NOMES: sao os do tema base do Keycloak 26.x. O authenticator le
|
||||
`password` do POST; o form e `kc-form-login`, o botao `kc-login` (name
|
||||
`login`) e o erro do campo `input-error-password`.
|
||||
|
||||
O tema base mostra QUEM esta entrando (`kc-attempted-username`) com o link
|
||||
para recomecar (`reset-login` -> `url.loginRestartFlowUrl`) na moldura dele.
|
||||
A moldura deste tema nao faz isso, entao a pagina faz, no subtitulo: sem o
|
||||
link, quem digitou o e-mail errado so sai fechando a aba. O "Tente outra
|
||||
forma" (passkey, 2FA) e da moldura e aparece sozinho quando o fluxo oferece.
|
||||
-->
|
||||
<#import "template.ftl" as layout>
|
||||
<#import "passkeys.ftl" as passkeys>
|
||||
<@layout.registrationLayout displayMessage=!messagesPerField.existsError('password'); section>
|
||||
<#if section = "header">
|
||||
Digite sua <span class="hl">senha</span>
|
||||
<#elseif section = "sub">
|
||||
<#if (auth.attemptedUsername)?has_content>
|
||||
Entrando como <b id="kc-attempted-username">${auth.attemptedUsername}</b>.
|
||||
<a id="reset-login" class="trocar-conta" href="${url.loginRestartFlowUrl}" aria-label="${msg("restartLoginTooltip")}">Não é você?</a>
|
||||
<#else>
|
||||
Acesse sua conta para continuar
|
||||
</#if>
|
||||
<#elseif section = "form">
|
||||
<form id="kc-form-login" onsubmit="login.disabled = true; return true;" action="${url.loginAction}" method="post" novalidate>
|
||||
<div class="campo">
|
||||
<label class="rotulo" for="password">${msg("password")}</label>
|
||||
<div class="caixa">
|
||||
<span class="icone">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="10" width="16" height="11" rx="2.4"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/></svg>
|
||||
</span>
|
||||
<input tabindex="2" id="password" name="password" type="password" autofocus dir="ltr"
|
||||
placeholder="••••••••" autocomplete="current-password"
|
||||
aria-invalid="<#if messagesPerField.existsError('password')>true</#if>"
|
||||
class="<#if messagesPerField.existsError('password')>erro</#if>"/>
|
||||
<button type="button" class="olho" aria-label="Mostrar senha" aria-controls="password"
|
||||
onclick="var p=document.getElementById('password');p.type=p.type==='password'?'text':'password';this.setAttribute('aria-label',p.type==='password'?'Mostrar senha':'Ocultar senha');">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
<#if messagesPerField.existsError('password')>
|
||||
<span id="input-error-password" class="erro-campo" aria-live="polite">${kcSanitize(messagesPerField.get('password'))?no_esc}</span>
|
||||
</#if>
|
||||
</div>
|
||||
|
||||
<#if realm.resetPasswordAllowed>
|
||||
<div class="opcoes">
|
||||
<a tabindex="5" class="esqueci" href="${url.loginResetCredentialsUrl}">Esqueceu sua senha?</a>
|
||||
</div>
|
||||
</#if>
|
||||
|
||||
<button tabindex="4" class="botao entrar" name="login" id="kc-login" type="submit">
|
||||
Entrar
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m13 6 6 6-6 6"/></svg>
|
||||
</button>
|
||||
</form>
|
||||
<#-- Como no keycloak.v2: a macro so desenha com a politica "Passkeys" ligada. -->
|
||||
<@passkeys.conditionalUIData />
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user