feat(Captive Portal): update styling, add support for theme.css per connection profile#9071
Merged
Merged
Conversation
d17ae9c to
8ca6ccf
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
This PR modernizes PacketFence Captive Portal theming by introducing CSS-variable–based styling (light/dark support) and enabling per-connection-profile asset overrides via file presence (theme.css/background.png/logo.png), with packaging/install hooks to seed defaults.
Changes:
- Add
theme.cssandbackground.pngsupport per connection profile, and update asset resolution in the captive portal renderer. - Rework captive portal CSS/SCSS to use
--pf-*CSS custom properties and add light/dark theming (including removal of the oldstyles-dark.css). - Update build/packaging/docs and portal preview URL rewriting to account for the new assets and markup.
Reviewed changes
Copilot reviewed 58 out of 62 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| rpm/packetfence.spec | RPM install step now seeds default profile theme.css and background.png. |
| Makefile | Adds targets to copy theme.css/background.png into default profile templates. |
| html/common/theme.css | New theme customization template documenting --pf-* variables. |
| html/common/styles.css | Updated/minified compiled CSS with CSS variables + dark mode support. |
| html/common/styles-dark.css | Removes legacy dark stylesheet. |
| html/common/scss/styles.scss | Imports new theme settings and updates heading size. |
| html/common/scss/_utilities.text.scss | Updates caption styling to use CSS vars; adds .no-select. |
| html/common/scss/_settings.theme.scss | New layer exporting theme tokens as CSS custom properties (light/dark/light-dark()). |
| html/common/scss/_settings.packetfence.scss | Defines light/dark palette tokens and layout constants. |
| html/common/scss/_settings.global.scss | Removes global transition variable (no longer used). |
| html/common/scss/_settings.colors.scss | Replaces static SCSS colors with CSS-var wrappers + internal constants. |
| html/common/scss/_objects.tables.scss | Uses new $pf-primary-color. |
| html/common/scss/_objects.media.scss | Restyles notice/error blocks with theme tokens + dark overrides. |
| html/common/scss/_objects.box.scss | Updates backgrounds/border accents to use theme tokens. |
| html/common/scss/_objects.aup.scss | Adds themed scrollbar styling. |
| html/common/scss/_elements.page.scss | Sets base typography from CSS vars; adds responsive background image styling. |
| html/common/scss/_elements.headings.scss | Adjusts h1 weight and color via theme tokens. |
| html/common/scss/_elements.header.scss | Adds .pf-logo styling and removes header background override. |
| html/common/scss/_elements.footer.scss | Moves client info styling into .c-footer-info; suppresses stray <footer>. |
| html/common/scss/_components.timerbar.scss | Theme-aware timerbar styling with layered fallbacks. |
| html/common/scss/_components.input.scss | Theme-aware inputs + focus ring fallbacks; mobile tap improvements. |
| html/common/scss/_components.iconic.scss | Theme-aware SVG icon fill colors. |
| html/common/scss/_components.frame.scss | Theme-aware frame styling + modern border/shadow strategy. |
| html/common/scss/_components.dot.scss | Adds tap UX tweaks and theme-aware dot styling. |
| html/common/scss/_components.divider.scss | Divider now uses --pf-divider-color. |
| html/common/scss/_components.buttons.scss | Theme-aware button styles, disabled styling, and dark-mode variants. |
| html/common/pf.js | Improves key handling using classList + e.key. |
| html/common/package.json | Adds postcss-custom-properties dependency (used by Grunt postcss). |
| html/common/package-lock.json | Locks the new PostCSS plugin and its transitive deps. |
| html/common/Makefile | Excludes styles.css.map from distribution file list. |
| html/common/Gruntfile.js | Disables dist sourcemaps; runs postcss-custom-properties in dist/dev pipelines. |
| html/captive-portal/templates/sms/validate.html | Fixes invalid HTML inside <a> elements. |
| html/captive-portal/templates/layout.html | Adds theme link + responsive background picture + logo class + client info block changes. |
| html/captive-portal/templates/emails/emails-security_event-triggered.html | Removes body background inline style (wrapper still provides background). |
| html/captive-portal/templates/emails/emails-renewal_certificate.html | Same body style adjustment. |
| html/captive-portal/templates/emails/emails-pki_certificate.html | Same body style adjustment. |
| html/captive-portal/templates/emails/emails-guest_sponsor_preregistration.html | Same body style adjustment. |
| html/captive-portal/templates/emails/emails-guest_sponsor_confirmed.html | Same body style adjustment. |
| html/captive-portal/templates/emails/emails-guest_sponsor_activation.html | Same body style adjustment. |
| html/captive-portal/templates/emails/emails-guest_password_reset.html | Same body style adjustment. |
| html/captive-portal/templates/emails/emails-guest_password_of_the_day.html | Same body style adjustment. |
| html/captive-portal/templates/emails/emails-guest_local_account_creation.html | Same body style adjustment. |
| html/captive-portal/templates/emails/emails-guest_email_preregistration.html | Same body style adjustment. |
| html/captive-portal/templates/emails/emails-guest_email_preregistration_confirmed.html | Same body style adjustment. |
| html/captive-portal/templates/emails/emails-guest_email_activation.html | Same body style adjustment. |
| html/captive-portal/templates/emails/emails-guest_admin_pregistration.html | Same body style adjustment. |
| html/captive-portal/templates/emails/emails-fleetdm-policy-violation.html | Same body style adjustment. |
| html/captive-portal/templates/emails/emails-fleetdm-cve.html | Same body style adjustment. |
| html/captive-portal/templates/emails/emails-billing_stripe_customer.subscription.deleted.html | Same body style adjustment. |
| html/captive-portal/templates/emails/emails-billing_confirmation.html | Same body style adjustment. |
| html/captive-portal/lib/captiveportal/PacketFence/DynamicRouting/Application.pm | Adds _resolve_theme_assets() and passes theme/background/logo to layout. |
| html/captive-portal/content/guest-management.js | Removes unused legacy JS. |
| html/captive-portal/content/ChilliLibrary.js | Removes unused legacy JS library. |
| html/captive-portal/content/billing/authorizenet.js | Removes unused billing JS. |
| html/captive-portal/content/autosubmit.js | Removes unused autosubmit JS. |
| go/httpdportalpreview/httpdportalpreview.go | Adds rewriting support for <source> tags and srcset. |
| docs/styles/app.css | Fixes code styling in sidebar TOC by scoping code colors. |
| docs/developer/customizing_packetfence.asciidoc | Documents logo/background/theme.css customization and inheritance behavior. |
| debian/packetfence.postinst | Seeds default profile theme/background assets during Debian install/upgrade. |
Files not reviewed (1)
- html/common/package-lock.json: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
ed1bf53 to
115b299
Compare
88506d6 to
dde2d9c
Compare
…er-profile theme.css - Add CSS custom property system (--pf-*) for full runtime theming without a build step; light/dark token values defined as flat SCSS variables in _settings.packetfence.scss and emitted via _settings.theme.scss - Dark mode via @media (prefers-color-scheme: dark) fallback (Chrome 76+, FF 67+, Safari 12.1+) and light-dark() progressive enhancement (Chrome 123+, FF 120+, Safari 17.5+); operator can force a mode with color-scheme - Logo filter defaults to none (light) / brightness(0) invert(1) (dark); note: light-dark() does not apply to filter values, only @media is used - Add captive-portal/templates/theme.css: per-profile customisation template with all --pf-* vars commented out and FORCE DARK fallback block - layout.html: load theme via [% IF theme_path %] before page renders; remove data-color-scheme JS attribute approach - Delete unused html/common/theme.css and html/common/styles-dark.css - _settings.colors.scss: all vars use var(--pf-*, fallback) including $pf-footer-background-color; fix stale filename reference - styles.css, _elements.page.scss: wire --pf-font-size-base, --pf-font-weight-normal/heading; rename settings.css-vars → settings.theme
…tton state - Remove transition: all (buttons) and border-color/box-shadow (inputs) - Replace all rgba() and opacity transparency with pre-computed solid colors - Disabled buttons: absolute ::after backdrop + muted text via CSS variables (--pf-btn-disabled-text, --pf-btn-primary/secondary-disabled-overlay) with light/dark values in _settings.packetfence/theme/colors.scss - Expose disabled button vars in captive-portal/templates/theme.css
… remove .o-page wrapper - Move IP/MAC client info from <footer> into the card bottom with a full-width divider; remove the <footer> element from layout.html - Add --pf-background-image CSS variable (default: none); background-color, background-image, background-size/position/repeat and background-attachment: fixed all on html so the image is viewport-pinned on long pages - Remove .o-page wrapper div (no longer needed now that background lives on html) - Make header transparent so background image shows through it - Remove dead 'footer .c-divider' rule from _components.divider.scss - Add --pf-background-image: none default to _settings.theme.scss (:root) - Comment out --pf-background-image entry in theme.css operator reference - Docs: add 'CSS Background Image' section with dimension/format recommendations (1920×1080 min, 2560×1440 preferred, 16:9 JPEG ≤ 300 KB)
- touch-action: manipulation on .c-btn, .dot, checkbox labels — eliminates the 300ms tap delay on older iOS / Android browsers - -webkit-tap-highlight-color: transparent on all tappable elements — removes the default gray/blue tap flash on iOS and Android Chrome - pf.js: replace deprecated e.which with e.key in tabbable keyup handler; replace strict className equality check with classList.contains() so elements with multiple classes are matched correctly
- Add bg-akamai.png (Akamai Orange 1440×900) as background on tablet+ (≥740px) - Replace packetfence-cp.png with new PacketFence-only logo (372×110px) - Dark mode secondary ghost buttons render filled (#1878bd); darken on hover - Card border visible in light (#d4d4d4) and dark (#2c2f43) mode; no box-shadow - Remove title/logo divider from layout.html; add margin-top to .pf-logo - Trim theme.css; Gruntfile/Makefile: disable sourceMap in dist - Update docs: single bg image, logo size guidance - Remove unused JS: ChilliLibrary.js, authorizenet.js, guest-management.js, captive-portal/content/autosubmit.js (duplicate of common/autosubmit.js)
- o-media--notice/error: tinted solid backgrounds (mix() pre-computed), 4px colored left border, dark text; dark mode tints and lighter border colors - c-timerbar: track uses --pf-media-border-color; fill uses --pf-color-secondary - c-frame--raised: modern 0 2px 8px shadow; dark mode restores 1px border ring - c-btn--tertiary: transparent background in dark mode (link appearance) - c-btn--ghost.c-btn--secondary: filled in dark mode, darkens on hover - Status colors are fixed SCSS values — not overridable via theme.css
- Remove background-color from <body> inline style in all email templates
(background now controlled by layout/captive portal wrapper)
- Keep background-color:#F2F2F2 on wrapper <div> for email client rendering
- Fix email preview footer: email templates contain </body></html> which
causes browser HTML error recovery to push layout content into a
browser-generated <footer> element; suppress with body > footer { display:none }
- sms/validate.html: remove stray </p> tags inside <a> elements
Add _resolve_theme_path helper that checks profile-specific theme.css first, falls back to default connection profile, and returns undef if neither exists — matching the same fallback pattern used by the logo field.
An empty profile-templates/default/theme.css would shadow the base templates/theme.css, causing _resolve_theme_path to serve a blank theme. Add a -s guard so zero-byte files are skipped in the lookup.
Renames all public CSS custom properties to a consistent semantic scheme (--pf-primary-color, --pf-text-base-color, --pf-error-color, etc.) and removes implementation-detail variables from the operator-facing API: - Hover/disabled/overlay button states → compile-time SCSS constants - Border colors (frame, media) → derived via color-mix() from their parent background; three-tier fallback: IE static hex → var() → color-mix() - Footer background, input label/border/border-width → removed or aliased - Spacing collapsed to --pf-spacing-base: 6px (atomic unit) Internal CSS custom properties (frame/media border fallbacks, input background, focus ring, font-family) are blocked in _settings.theme.scss with a clear INTERNAL comment banner. Updates theme.css template, customizing_packetfence.asciidoc reference table, and rebuilds styles.css.
- Background rendered on body::before pseudo-element (fixed, full viewport, tablet+ only); default is packetfence-background.png - Renamed html/common/img/bg-akamai.png → packetfence-background.png - Removed --pf-background-image CSS custom property; background is set via a direct url() rule in the profile's theme.css using a relative path (constraint: absolute paths bypass the admin preview proxy) - theme.css template: concise how-to comment with constraint note - customizing_packetfence.asciidoc: background image section updated
- SCSS: remove decorative/obvious comments, keep only non-obvious ones (three-tier cascade rationale, internal markers, Sass color-function constraint, computed-value origins) - Dark mode: add @media block for disabled button colours — compile-time vars had no dark override after CSS custom property removal - Button hover (primary, secondary, tertiary): derive shade from --pf-*-color via color-mix() so operator color overrides apply to hover - Ghost secondary dark-mode hover: same fix - Input focus ring: color-mix() tints to match --pf-primary-color - c-frame--raised dark-mode border ring: fix @media query - customizing_packetfence.asciidoc: replace 7 variable tables with a single practical example; remove tiny 6th-level heading
- Auto-resolve logo, theme and background from filesystem in Profile.pm:
profile-specific file in profile-templates/{name}/ takes priority,
falls back to /common/theme.css and /common/background.png for theme
and background, or the configured value for logo
- Move html/common/theme.css from captive-portal/templates/ (pure CSS,
no TT directives; served as static asset alongside background.png)
- Remove profile-templates/default/{background,theme} install targets
from Makefile — /common/ fallback makes them unnecessary
- Document per-profile theme.css customization in developer guide
…tally remove Background.
Remove stale /common/theme.css fallback from the documented asset resolution order and the _resolve_theme_assets pod comment — the fallback was dropped in f8863d2. Clarify that /common/theme.css is the shipped source copied to the default connection profile on install, and that if neither the profile nor the default has a theme.css, no stylesheet is loaded.
… on decorative elements Apply to background image, logo, and logout icon link in layout.html.
…is, since new PF logo will be applied.
dde2d9c to
46a4228
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Provide the way to customize Captive Portal, by adding branded background image and applying own brand theme.
Update the resolving assets mechanism for background, logo png files and theme.css file to file-based instead of config ( only logo has it's as a fallback ).
By default new customers will have new files for a captive portal: background.png and theme.css ( empty CSS rules which might be edit ) for a default connection profile. The inheritance for these files works for new connection profiles until files will be overridden.
By removing background.png file from default connection profile the branded backgroung color will be applied.
Core changes
New
/common/background.pngbranded Akamai file.New
/common/theme.cssas a placeholder CSS file.Updated Captive Portal
*.scssstyling, added CSS variables in order to apply customer's branded theme.Added light | dark themes to Captive Portal.
Updated the way for resolving theme assets based on file existence in connection profile.
Updated documentation
customizing_packetfence.asciidocby adding description for modifying the theme and changing background image.Provide the CSS variables ( for configuration and for internal use ).
Updated styles in order to support modern and old browsers.
Updated
packetfence-cp.pnglogo and default background Akamai brandedbackground.pngfrom Akamai resourcesImpacts
html/captive-portal/templateshtml/common/*customization_packetfence.asciidochtml/captive-portal/lib/captiveportal/PacketFence/DynamicRouting/Application.pmto resolve required assets "background_url", "theme_path", "logo" as well.html/common/packetfence-cp.pngwith a new branded PF.docs/styles/app.cssfor navigation links ( sidebar ) which has<code/>Makefileadded 2 commands to copy background and theme from/common/*to default connection profile.httpdportalpreview.go( httpd.admin_dispatcher ) for updating src urls for the new elementsource.Delete branch after merge
YES
Checklist
(REQUIRED) - [yes, no or n/a]
styles.cssshould be minified and present in PR.styles-dark.css,styles-map.cssno need.styles.csstheme.cssin separate connection profile.theme.css, only major rules.customization_packetfence.asciidocAttachments