Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/theme.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ jobs:
# #99: parent styles must load before Xore/APIARY overrides, not
# replace them -- css/styles.css is keycloak.v2's own stylesheet.
grep -Fxq 'styles=css/styles.css css/xore-theme.css css/login.css' themes/apiary/login/theme.properties
# #91: the account theme vendors its own copy of the identical
# upstream file (Keycloak resolves theme resources per theme
# type, login/ and account/ can't share one file on disk) --
# nothing enforced these stay identical until now. Byte-diffing
# against login/'s already-checked copy, rather than a second
# independent hash, is deliberate: it catches the copy silently
# drifting out of sync with login/'s (and therefore with
# theme.lock's own pin) without hardcoding a second hash that
# would just be the same value duplicated.
cmp themes/apiary/login/resources/css/xore-theme.css themes/apiary/account/resources/css/xore-theme.css
grep -Fxq 'parent=keycloak.v3' themes/apiary/account/theme.properties
grep -Fxq 'styles=css/xore-theme.css css/account.css' themes/apiary/account/theme.properties
- name: Verify Keycloak compatibility record (#101)
shell: bash
run: .github/scripts/verify-keycloak-compat.sh
Expand Down
146 changes: 146 additions & 0 deletions themes/apiary/account/resources/css/account.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/* APIARY Keycloak account console theme (#91).
keycloak.v3's account console is a compiled React SPA (PatternFly v5) --
unlike the login theme, there is no FreeMarker markup to override, only
this CSS layered on top of the upstream bundle via theme.properties'
`styles=`. Component-level rules (form/button/alert) below are
deliberately the same selectors and values as ../../login/resources/css/
login.css: both themes render the identical PatternFly v5 component
library, confirmed live against this exact pinned Keycloak version, so
there is no reason for the two to diverge. */
/* light dark, not a forced dark-only scheme -- matches ../../login/resources/css/login.css's own convention, deferring to the browser/OS preference rather than assuming one. */
:root { color-scheme: light dark; }

html, body, #root {
min-height: 100%;
margin: 0;
background: var(--app-bg);
color: var(--text-primary);
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

/* ── Masthead ──────────────────────────────────────────────────────────
Keycloak's own logo/wordmark stays in place for now -- theme.properties'
`logo=` only swaps the image asset, not the surrounding chrome, and this
repo has no APIARY logo asset yet (the login theme uses Keycloak's own
realm displayName as text branding instead; account console has no
equivalent per-page title slot in its masthead). Restyling colors only
here is a real, scoped v1; a full brand-mark swap is separate follow-up
work, not blocked on this. */
.pf-v5-c-masthead {
background: var(--toolbar-bg);
border-bottom: 1px solid var(--border-subtle);
}
.pf-v5-c-masthead__toggle .pf-v5-c-button { color: var(--text-secondary); }

/* ── Sidebar navigation ──────────────────────────────────────────────── */
.pf-v5-c-page__sidebar { background: var(--sidebar-bg); }
.pf-v5-c-page__sidebar-body { background: transparent; }
.pf-v5-c-nav__section-title { color: var(--text-muted); font-size: 11px; letter-spacing: 0.02em; text-transform: uppercase; }
.pf-v5-c-nav__link {
color: var(--text-secondary);
font-size: 13px;
font-weight: 500;
}
.pf-v5-c-nav__link:hover { color: var(--text-primary); background: var(--surface-hover); }
.pf-v5-c-nav__link.pf-m-current {
color: var(--text-primary);
background: var(--accent-soft);
border-left: 3px solid var(--accent);
}
.pf-v5-c-nav__link.pf-m-current::after { border: none; }

/* ── Main content ────────────────────────────────────────────────────── */
.pf-v5-c-page__main { background: var(--app-bg); }
.pf-v5-c-page__main-section { background: transparent; }
.pf-v5-c-content h1, .pf-v5-c-content h2, .pf-v5-c-content h3 {
color: var(--text-primary);
font-family: var(--font-display);
font-weight: 400;
}
.pf-v5-c-content p { color: var(--text-secondary); }

.pf-v5-c-card {
background: var(--surface-0);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-panel);
box-shadow: none;
}
.pf-v5-c-card__title { color: var(--text-primary); }

/* ── Forms and buttons ───────────────────────────────────────────────
Identical rules to ../../login/resources/css/login.css -- see that
file's own comments for why the pf-m-secondary custom-property
indirection is required, not optional. */
.pf-v5-c-form { gap: 16px; }
.pf-v5-c-form__group { margin: 0 0 16px; }
.pf-v5-c-form__label, .pf-v5-c-check__label {
color: var(--text-primary);
font-size: 12px;
font-weight: 600;
}

.pf-v5-c-form-control {
min-height: 42px;
overflow: hidden;
border: 1px solid var(--border-strong);
border-radius: var(--radius-control);
background: var(--surface-1);
color: var(--text-primary);
}
.pf-v5-c-form-control input, .pf-v5-c-form-control textarea, .pf-v5-c-form-control select {
min-height: 40px;
padding: 9px 11px;
background: transparent;
color: var(--text-primary);
}
.pf-v5-c-form-control:focus-within {
border-color: var(--border-focus);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--border-focus) 22%, transparent);
}
.pf-v5-c-form-control[aria-invalid="true"], .pf-v5-c-form-control:has(input[aria-invalid="true"]) { border-color: var(--danger); }

.pf-v5-c-input-group { gap: 8px; }
.pf-v5-c-button {
min-height: 40px;
border-radius: var(--radius-control);
font-weight: 650;
transition: background-color var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast), transform var(--transition-fast);
}
.pf-v5-c-button.pf-m-primary { border-color: var(--accent); background: var(--accent); color: var(--text-on-accent); }
.pf-v5-c-button.pf-m-primary:hover, .pf-v5-c-button.pf-m-primary:focus-visible { border-color: var(--accent-hover); background: var(--accent-hover); }
.pf-v5-c-button.pf-m-control { border: 1px solid var(--border-strong); background: var(--surface-1); color: var(--text-secondary); }
.pf-v5-c-button.pf-m-secondary {
--pf-v5-c-button--m-secondary--BackgroundColor: var(--surface-1);
--pf-v5-c-button--m-secondary--Color: var(--text-secondary);
--pf-v5-c-button--m-secondary--after--BorderColor: var(--border-strong);
--pf-v5-c-button--m-secondary--hover--BackgroundColor: var(--surface-2);
--pf-v5-c-button--m-secondary--hover--Color: var(--text-primary);
--pf-v5-c-button--m-secondary--hover--after--BorderColor: var(--border-strong);
--pf-v5-c-button--m-secondary--focus--BackgroundColor: var(--surface-2);
--pf-v5-c-button--m-secondary--focus--Color: var(--text-primary);
--pf-v5-c-button--m-secondary--focus--after--BorderColor: var(--border-focus);
}
.pf-v5-c-button:active { transform: translateY(1px); }

a { color: var(--text-link); text-underline-offset: 3px; }
a:hover { color: var(--text-link-hover); }

.pf-v5-c-alert {
margin-bottom: 16px;
border: 1px solid var(--border-subtle);
border-radius: var(--radius-control);
box-shadow: none;
}
.pf-v5-c-alert.pf-m-danger { border-color: color-mix(in srgb, var(--danger) 40%, transparent); background: var(--danger-soft); color: var(--danger-text-on-soft); }
.pf-v5-c-alert.pf-m-success { border-color: color-mix(in srgb, var(--success) 40%, transparent); background: var(--success-soft); }
.pf-v5-c-helper-text, .pf-v5-c-form__helper-text, .pf-v5-c-form__helper-text a { font-size: 11px; }
.pf-v5-c-helper-text__item.pf-m-error, .pf-v5-c-form__helper-text.pf-m-error { color: var(--danger); }

/* ── Tables (device activity, applications) ─────────────────────────── */
.pf-v5-c-table { color: var(--text-primary); background: transparent; }
.pf-v5-c-table thead th { color: var(--text-muted); border-bottom: 1px solid var(--border-subtle); }
.pf-v5-c-table tbody tr { border-bottom: 1px solid var(--border-subtle); }

/* ── Data list (jump-to-section, applications list) ─────────────────── */
.pf-v5-c-data-list { background: transparent; }
.pf-v5-c-data-list__item { background: transparent; border-bottom: 1px solid var(--border-subtle); }
1 change: 1 addition & 0 deletions themes/apiary/account/resources/css/xore-theme.css

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions themes/apiary/account/theme.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
parent=keycloak.v3
styles=css/xore-theme.css css/account.css
meta=viewport==width=device-width,initial-scale=1
Loading