Skip to content

Let controllers add the active theme's stylesheets and scripts - #243

Merged
ralflang merged 2 commits into
horde:FRAMEWORK_6_0from
pierrefardel:feat/theme-assets-controllers
Oct 14, 2026
Merged

ralflang merged 2 commits into
horde:FRAMEWORK_6_0from
pierrefardel:feat/theme-assets-controllers

Conversation

@pierrefardel

@pierrefardel pierrefardel commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Part of #233 (cause 1). Companion PR in horde/base switches the controllers
over to these methods.

Controllers that assemble their own <head> through PageComposer and
AssetCollector — the settings and admin pages — had no theme-aware call
available: AssetCollector::addStylesheet() only takes a URL. So they
hardcoded $themesUri . '/default/screen.css', and they never loaded the
scripts a theme declares in $theme_scripts.

Change

Two methods on ViewModeConfigurator, the service that already fills the
AssetCollector with core scripts:

  • addThemeStylesheets(AssetCollector, array $files, string $app = 'horde')
    resolves the user's theme through ThemeResolver and walks the existing
    CssDiscoverer cascade: default first, the theme layered on top, only
    files that exist. A theme that does not ship settings.css keeps
    inheriting the default one.
  • addThemeScripts(AssetCollector, string $app = 'horde') does what
    DesktopChromeRenderer already does with JsDiscoverer::discoverTheme().
    Meant to be called after configure(), since theme scripts may rely on
    prototype.js and horde.js.

The two new constructor arguments are optional and default to null; the
methods are no-ops if the services are unavailable.

Note on hook-based themes

As discussed on #233, this only helps self-contained themes. A theme that
gets its CSS custom properties from the cssfiles() hook still renders
unstyled on these pages, since nothing on the modern stack calls the hook
(CssHookProvider has no implementation yet). We moved our own community
theme to load its foundations itself for that reason.

Testing

On a FRAMEWORK_6_0 install, with this PR, the horde/base companion and
#242 applied, and a self-contained theme selected: the OAuth account,
OAuth provider and API registry pages render with the user's theme, load
its $theme_scripts, and the theme's display preferences apply.

#242 is needed for the end result: without it the theme is resolved for a
user id carrying a leading \0, and falls back to the server default.

…and scripts

Controllers that build their own <head> (settings and admin pages) had no
theme-aware call available on AssetCollector, so they hardcoded
"/default/screen.css" and never loaded the scripts a theme declares in
$theme_scripts.

Add ViewModeConfigurator::addThemeStylesheets(), which resolves the
user's theme and walks the existing CSS cascade (default first, the theme
layered on top, only files that exist), and addThemeScripts(), which does
what DesktopChromeRenderer already does with discoverTheme(). The new
constructor arguments are optional, so the methods are no-ops when the
services are unavailable.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Non-Horde asset requests can ignore the user's Horde-scoped theme preference.

1 open finding
What changed in this PR

Enables modern controllers to load theme assets through existing discovery services, addressing part of #233 alongside the companion controller changes and #242.

Changes:

  • Adds helpers for themed stylesheets and scripts.
  • Wires optional CSS discovery and theme resolution dependencies into the configurator.
File Description
src/​PageOutput/​ViewModeConfiguratorFactory.php Injects CSS discovery and theme resolution services.
src/​PageOutput/​ViewModeConfigurator.php Adds theme-aware stylesheet and script registration.

🧠 Review effort: Balanced


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

Comment thread src/PageOutput/ViewModeConfigurator.php Outdated

return $uid === ''
? 'default'
: $this->themeResolver->resolve($uid, null, $app);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, the theme is a Horde-wide preference and the chrome renderer factories resolve it in the horde scope. resolveTheme() now does the same; $app is only used to discover that app's files. Fixed in a737985. No runtime test here (PHPUnit isn't available on my setup), php -l only.

The theme preference is Horde-wide. Resolving it in the app's scope
ignored a user's horde:theme for non-horde apps, as the chrome
renderer factories already avoid.
@ralflang
ralflang merged commit 00e0ef6 into horde:FRAMEWORK_6_0 Oct 14, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants