feat(theme): add social login button styling and legal footer
Style social identity provider buttons (GitHub, Microsoft, Google) as full-width stacked buttons matching the dark theme. Add footer.js to inject Privacy Policy and Impressum links below the login card. Fix PF3 background image bleeding through on html element. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -75,6 +75,7 @@
|
|||||||
/* ===== Base Page ===== */
|
/* ===== Base Page ===== */
|
||||||
html.login-pf {
|
html.login-pf {
|
||||||
background-color: var(--cai-bg-body) !important;
|
background-color: var(--cai-bg-body) !important;
|
||||||
|
background-image: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
html.login-pf body {
|
html.login-pf body {
|
||||||
@@ -469,38 +470,146 @@ input.pf-c-button.pf-m-primary:hover,
|
|||||||
|
|
||||||
/* ===== Social Login / Identity Providers ===== */
|
/* ===== Social Login / Identity Providers ===== */
|
||||||
#kc-social-providers {
|
#kc-social-providers {
|
||||||
margin-top: 20px;
|
margin-top: 24px !important;
|
||||||
padding-top: 20px;
|
padding-top: 20px !important;
|
||||||
border-top: 1px solid var(--cai-border-primary);
|
border-top: 1px solid var(--cai-border-primary) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#kc-social-providers ul {
|
/* Social <hr> separator */
|
||||||
list-style: none;
|
#kc-social-providers > hr {
|
||||||
padding: 0;
|
border: none !important;
|
||||||
margin: 0;
|
border-top: 1px solid var(--cai-border-primary) !important;
|
||||||
|
margin: 0 0 16px 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* "Or sign in with" heading - subtle divider text */
|
||||||
|
#kc-social-providers h2,
|
||||||
|
#kc-social-providers > h2,
|
||||||
|
#kc-social-providers h4 {
|
||||||
|
font-family: 'Inter', sans-serif !important;
|
||||||
|
font-size: 12px !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
color: var(--cai-text-faint) !important;
|
||||||
|
text-transform: uppercase !important;
|
||||||
|
letter-spacing: 0.08em !important;
|
||||||
|
text-align: center !important;
|
||||||
|
margin: 0 0 16px 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Social button list - stacked full-width
|
||||||
|
* Production uses: ul.pf-c-login__main-footer-links.kc-social-links
|
||||||
|
* PF4 sets flex-direction:row on this - we must override with high specificity */
|
||||||
|
#kc-social-providers ul.pf-c-login__main-footer-links,
|
||||||
|
#kc-social-providers ul.kc-social-links,
|
||||||
|
#kc-social-providers ul,
|
||||||
|
#kc-social-providers ol {
|
||||||
|
list-style: none !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column !important;
|
||||||
|
gap: 10px !important;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#kc-social-providers ul.pf-c-login__main-footer-links > li,
|
||||||
|
#kc-social-providers ul.kc-social-links > li,
|
||||||
#kc-social-providers li {
|
#kc-social-providers li {
|
||||||
margin-bottom: 8px;
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
width: 100% !important;
|
||||||
|
flex: none !important;
|
||||||
|
display: block !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Social login buttons - full-width stacked with icon + label
|
||||||
|
* Production uses: a.pf-c-button.pf-m-control.pf-m-block.kc-social-item
|
||||||
|
* Must override .pf-c-button.pf-m-control (password toggle uses same classes) */
|
||||||
|
#kc-social-providers a.pf-c-button.pf-m-control,
|
||||||
|
#kc-social-providers a.kc-social-item,
|
||||||
|
#kc-social-providers a.pf-m-block,
|
||||||
#kc-social-providers a,
|
#kc-social-providers a,
|
||||||
#kc-social-providers .pf-c-button {
|
#kc-social-providers .zocial {
|
||||||
background-color: var(--cai-bg-surface) !important;
|
background-color: var(--cai-bg-input) !important;
|
||||||
border: 1px solid var(--cai-border-secondary) !important;
|
border: 1px solid var(--cai-border-secondary) !important;
|
||||||
|
border-top: 1px solid var(--cai-border-secondary) !important;
|
||||||
|
border-left: 1px solid var(--cai-border-secondary) !important;
|
||||||
border-radius: 8px !important;
|
border-radius: 8px !important;
|
||||||
color: var(--cai-text-primary) !important;
|
color: var(--cai-text-primary) !important;
|
||||||
padding: 10px 16px !important;
|
padding: 12px 16px !important;
|
||||||
display: block;
|
display: flex !important;
|
||||||
text-align: center;
|
align-items: center !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
gap: 10px !important;
|
||||||
|
width: 100% !important;
|
||||||
|
box-sizing: border-box !important;
|
||||||
|
text-align: center !important;
|
||||||
|
font-family: 'Inter', sans-serif !important;
|
||||||
font-size: 14px !important;
|
font-size: 14px !important;
|
||||||
font-weight: 500 !important;
|
font-weight: 500 !important;
|
||||||
transition: border-color 0.15s ease !important;
|
text-decoration: none !important;
|
||||||
|
transition: border-color 0.2s ease, background-color 0.2s ease,
|
||||||
|
box-shadow 0.2s ease, transform 0.15s ease !important;
|
||||||
|
white-space: nowrap !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#kc-social-providers a.pf-c-button.pf-m-control:hover,
|
||||||
|
#kc-social-providers a.kc-social-item:hover,
|
||||||
#kc-social-providers a:hover,
|
#kc-social-providers a:hover,
|
||||||
#kc-social-providers .pf-c-button:hover {
|
#kc-social-providers .zocial:hover {
|
||||||
border-color: var(--cai-accent) !important;
|
border-color: var(--cai-accent) !important;
|
||||||
|
background-color: rgba(145, 164, 210, 0.06) !important;
|
||||||
|
box-shadow: 0 0 16px rgba(145, 164, 210, 0.12) !important;
|
||||||
|
color: var(--cai-text-heading) !important;
|
||||||
|
transform: translateY(-1px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Provider icons inside social buttons */
|
||||||
|
#kc-social-providers .kc-social-provider-logo,
|
||||||
|
#kc-social-providers i.fa,
|
||||||
|
#kc-social-providers .kc-social-icon-text {
|
||||||
|
color: var(--cai-accent) !important;
|
||||||
|
font-size: 16px !important;
|
||||||
|
flex-shrink: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Provider text label */
|
||||||
|
#kc-social-providers .kc-social-provider-name {
|
||||||
|
font-family: 'Inter', sans-serif !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grid layout for social providers (some themes use .kc-social-grid) */
|
||||||
|
.kc-social-grid {
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column !important;
|
||||||
|
gap: 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kc-social-grid > div {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: none !important;
|
||||||
|
flex: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PF v5 grid layout override */
|
||||||
|
.pf-v5-l-grid.pf-m-gutter {
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column !important;
|
||||||
|
gap: 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-l-grid__item {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: none !important;
|
||||||
|
flex: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Social section separator */
|
||||||
|
#kc-social-providers::before {
|
||||||
|
content: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== Form Buttons Row ===== */
|
/* ===== Form Buttons Row ===== */
|
||||||
@@ -581,3 +690,244 @@ input.pf-c-button.pf-m-primary:hover,
|
|||||||
max-width: 440px;
|
max-width: 440px;
|
||||||
margin: 0 auto !important;
|
margin: 0 auto !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===== Legal Footer (injected by footer.js) ===== */
|
||||||
|
.cai-legal-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 24px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cai-legal-link {
|
||||||
|
font-family: 'Inter', sans-serif;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--cai-text-faint) !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
transition: color 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cai-legal-link:hover {
|
||||||
|
color: var(--cai-text-muted) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cai-legal-sep {
|
||||||
|
font-size: 10px;
|
||||||
|
color: var(--cai-text-faint);
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== PF v5 Social Provider Overrides ===== */
|
||||||
|
/* Production may use keycloak.v2 (PF v5) classes */
|
||||||
|
.pf-v5-c-login__main-footer {
|
||||||
|
padding: 0 32px 28px !important;
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-c-login__main-footer-band {
|
||||||
|
background-color: var(--cai-bg-surface) !important;
|
||||||
|
border-top: 1px solid var(--cai-border-primary) !important;
|
||||||
|
padding: 16px 32px !important;
|
||||||
|
text-align: center !important;
|
||||||
|
border-radius: 0 0 12px 12px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-c-login__main-footer-band-item {
|
||||||
|
font-size: 14px !important;
|
||||||
|
color: var(--cai-text-muted) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PF v5 social buttons */
|
||||||
|
.pf-v5-c-login__main-footer-links-item a,
|
||||||
|
.pf-v5-c-button.pf-m-secondary.pf-m-block {
|
||||||
|
background-color: var(--cai-bg-input) !important;
|
||||||
|
border: 1px solid var(--cai-border-secondary) !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
color: var(--cai-text-primary) !important;
|
||||||
|
font-family: 'Inter', sans-serif !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
padding: 12px 16px !important;
|
||||||
|
width: 100% !important;
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
gap: 10px !important;
|
||||||
|
transition: border-color 0.2s ease, background-color 0.2s ease,
|
||||||
|
box-shadow 0.2s ease, transform 0.15s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-c-login__main-footer-links-item a:hover,
|
||||||
|
.pf-v5-c-button.pf-m-secondary.pf-m-block:hover {
|
||||||
|
border-color: var(--cai-accent) !important;
|
||||||
|
background-color: rgba(145, 164, 210, 0.06) !important;
|
||||||
|
box-shadow: 0 0 16px rgba(145, 164, 210, 0.12) !important;
|
||||||
|
color: var(--cai-text-heading) !important;
|
||||||
|
transform: translateY(-1px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PF v5 social footer links list - stacked */
|
||||||
|
.pf-v5-c-login__main-footer-links {
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column !important;
|
||||||
|
gap: 10px !important;
|
||||||
|
list-style: none !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-c-login__main-footer-links-item {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PF v5 main container and card */
|
||||||
|
.pf-v5-c-login {
|
||||||
|
background:
|
||||||
|
radial-gradient(ellipse at 20% 20%, rgba(75, 63, 224, 0.07) 0%, transparent 50%),
|
||||||
|
radial-gradient(ellipse at 80% 80%, rgba(56, 178, 172, 0.05) 0%, transparent 50%),
|
||||||
|
radial-gradient(ellipse at 50% 50%, rgba(109, 133, 198, 0.03) 0%, transparent 70%),
|
||||||
|
var(--cai-bg-body) !important;
|
||||||
|
background-size: 200% 200%, 200% 200%, 100% 100%, 100% 100% !important;
|
||||||
|
animation: ambientShift 20s ease-in-out infinite !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-c-login::before {
|
||||||
|
background-image: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-c-login__container {
|
||||||
|
max-width: 440px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-c-login__header {
|
||||||
|
text-align: center !important;
|
||||||
|
margin-bottom: 32px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-c-brand {
|
||||||
|
font-family: 'Space Grotesk', sans-serif !important;
|
||||||
|
font-size: 28px !important;
|
||||||
|
font-weight: 700 !important;
|
||||||
|
color: var(--cai-text-heading) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-c-login__main {
|
||||||
|
background-color: var(--cai-bg-card) !important;
|
||||||
|
border: 1px solid var(--cai-border-secondary) !important;
|
||||||
|
border-radius: 12px !important;
|
||||||
|
animation: cardGlow 6s ease-in-out infinite !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-c-login__main::before {
|
||||||
|
content: '' !important;
|
||||||
|
position: absolute !important;
|
||||||
|
top: 0 !important;
|
||||||
|
left: 0 !important;
|
||||||
|
right: 0 !important;
|
||||||
|
height: 2px !important;
|
||||||
|
background: linear-gradient(90deg, transparent, var(--cai-brand-indigo),
|
||||||
|
var(--cai-brand-teal), var(--cai-accent-secondary), transparent) !important;
|
||||||
|
opacity: 0.5 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-c-login__main-header {
|
||||||
|
padding: 28px 32px 0 !important;
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-c-login__main-header .pf-v5-c-title {
|
||||||
|
font-family: 'Space Grotesk', sans-serif !important;
|
||||||
|
font-size: 22px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
color: var(--cai-text-heading) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-c-login__main-body {
|
||||||
|
padding: 24px 32px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PF v5 form controls */
|
||||||
|
.pf-v5-c-form-control {
|
||||||
|
background-color: var(--cai-bg-input) !important;
|
||||||
|
border: 1px solid var(--cai-border-secondary) !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
color: var(--cai-text-primary) !important;
|
||||||
|
font-family: 'Inter', sans-serif !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-c-form-control:focus-within {
|
||||||
|
border-color: var(--cai-accent) !important;
|
||||||
|
box-shadow: 0 0 0 1px var(--cai-accent), 0 0 12px rgba(145, 164, 210, 0.1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-c-form__label-text {
|
||||||
|
font-family: 'Inter', sans-serif !important;
|
||||||
|
font-size: 13px !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
color: var(--cai-text-muted) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PF v5 primary button */
|
||||||
|
.pf-v5-c-button.pf-m-primary {
|
||||||
|
background: linear-gradient(135deg, var(--cai-accent), var(--cai-accent-secondary),
|
||||||
|
var(--cai-brand-indigo), var(--cai-accent-secondary), var(--cai-accent)) !important;
|
||||||
|
background-size: 300% 100% !important;
|
||||||
|
animation: buttonShimmer 6s ease-in-out infinite !important;
|
||||||
|
border: none !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
color: #0a0c10 !important;
|
||||||
|
font-family: 'Inter', sans-serif !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
box-shadow: 0 2px 12px rgba(109, 133, 198, 0.2) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-c-button.pf-m-primary:hover {
|
||||||
|
opacity: 0.95;
|
||||||
|
box-shadow: 0 4px 20px rgba(109, 133, 198, 0.35) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PF v5 links */
|
||||||
|
.pf-v5-c-login a,
|
||||||
|
.pf-v5-c-login__main a,
|
||||||
|
.pf-v5-c-button.pf-m-link {
|
||||||
|
color: var(--cai-accent) !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-c-login a:hover,
|
||||||
|
.pf-v5-c-button.pf-m-link:hover {
|
||||||
|
color: var(--cai-accent-secondary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PF v5 alerts */
|
||||||
|
.pf-v5-c-alert.pf-m-inline {
|
||||||
|
background-color: var(--cai-bg-surface) !important;
|
||||||
|
border: 1px solid var(--cai-border-secondary) !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
color: var(--cai-text-primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PF v5 input group (password) */
|
||||||
|
.pf-v5-c-input-group {
|
||||||
|
background: transparent !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-c-button.pf-m-control {
|
||||||
|
background-color: var(--cai-bg-surface) !important;
|
||||||
|
color: var(--cai-text-muted) !important;
|
||||||
|
border: 1px solid var(--cai-border-secondary) !important;
|
||||||
|
border-left: 1px solid var(--cai-border-primary) !important;
|
||||||
|
border-radius: 0 8px 8px 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-v5-c-button.pf-m-control:hover {
|
||||||
|
color: var(--cai-accent) !important;
|
||||||
|
background-color: rgba(145, 164, 210, 0.08) !important;
|
||||||
|
}
|
||||||
|
|||||||
44
keycloak/themes/certifai/login/resources/js/footer.js
Normal file
44
keycloak/themes/certifai/login/resources/js/footer.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* CERTifAI Keycloak Theme - Footer Injection
|
||||||
|
*
|
||||||
|
* Injects legal footer links (Privacy Policy, Impressum) below the login card.
|
||||||
|
* Uses the APP_BASE_URL from the page's redirect_uri to construct absolute links,
|
||||||
|
* falling back to relative paths if unavailable.
|
||||||
|
*/
|
||||||
|
(function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
// Derive the app base URL from the OAuth redirect_uri parameter
|
||||||
|
var appBase = "";
|
||||||
|
try {
|
||||||
|
var params = new URLSearchParams(window.location.search);
|
||||||
|
var redirectUri = params.get("redirect_uri");
|
||||||
|
if (redirectUri) {
|
||||||
|
var url = new URL(redirectUri);
|
||||||
|
appBase = url.origin;
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
// Ignore parse errors; links will be relative
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the footer element
|
||||||
|
var footer = document.createElement("div");
|
||||||
|
footer.className = "cai-legal-footer";
|
||||||
|
footer.innerHTML =
|
||||||
|
'<a href="' + appBase + '/privacy" class="cai-legal-link" target="_blank" rel="noopener">' +
|
||||||
|
"Privacy Policy" +
|
||||||
|
"</a>" +
|
||||||
|
'<span class="cai-legal-sep">|</span>' +
|
||||||
|
'<a href="' + appBase + '/impressum" class="cai-legal-link" target="_blank" rel="noopener">' +
|
||||||
|
"Impressum" +
|
||||||
|
"</a>";
|
||||||
|
|
||||||
|
// Insert after the card or at the end of .login-pf-page / .pf-v5-c-login__container
|
||||||
|
var card = document.querySelector(".card-pf") ||
|
||||||
|
document.querySelector(".pf-v5-c-login__main");
|
||||||
|
if (card && card.parentNode) {
|
||||||
|
card.parentNode.insertBefore(footer, card.nextSibling);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
parent=keycloak
|
parent=keycloak
|
||||||
import=common/keycloak
|
import=common/keycloak
|
||||||
styles=css/login.css
|
styles=css/login.css
|
||||||
|
scripts=js/footer.js
|
||||||
|
|||||||
Reference in New Issue
Block a user