A colour an admin sets in the token editor shows for users on "System default", but not for a user who picked the dark theme in their personal settings. Two dark users then see different colours.
Where, at development fd992ea:
lib/Service/CustomOverridesService.php:232-237 writes every override into one :root {} block.
lib/Service/CustomOverridesService.php:249-278 adds !important to each declaration to win the cascade.
- Nextcloud server
apps/theming/lib/Service/ThemeInjectionService.php:52-59 loads each chosen theme as a non-plain stylesheet.
- Nextcloud server
apps/theming/lib/Controller/ThemingController.php:433 scopes that stylesheet to [data-theme-<id>] { ... }.
- Nextcloud server
core/templates/layout.user.php:54-56 puts data-theme-dark on <body>.
|
return $header . ':root {}' . PHP_EOL; |
|
} |
|
|
|
$lines = $this->buildDeclarationLines(tokens: $tokens); |
|
|
|
return $header . ':root {' . PHP_EOL . implode(PHP_EOL, $lines) . PHP_EOL . '}' . PHP_EOL; |
|
}//end buildCss() |
|
|
|
/** |
|
* Build individual CSS declaration lines from a token map. |
|
* |
|
* @param array<string, string> $tokens Token name => value pairs. |
|
* |
|
* @return array<string> List of CSS declaration lines. |
|
* |
|
* @spec openspec/changes/retrofit-2026-05-24-annotate-nldesign/tasks.md#task-33 |
|
*/ |
|
private function buildDeclarationLines(array $tokens): array { |
|
$lines = []; |
|
foreach ($tokens as $name => $value) { |
|
// Reject any value containing CSS injection characters. |
|
if (preg_match('/[{};]|\/\*|\*\//', $value) === 1) { |
|
continue; |
|
} |
|
|
|
$safeValue = str_replace(["\n", "\r", ';', '{', '}', '/*', '*/'], '', $value); |
|
$safeName = preg_replace('/[^a-zA-Z0-9\-]/', '', $name); |
|
|
|
// Strip any pre-existing !important the caller may have included; it is |
|
// re-applied uniformly below so the round-trip stays canonical. |
|
$safeValue = trim(preg_replace('/\s*!\s*important\s*$/i', '', $safeValue)); |
|
|
|
// Emit each user override with !important so it wins the cascade. |
|
// The nldesign design-system stylesheets (theme/overrides/element-overrides.css) |
|
// re-declare every editable token with !important, and Nextcloud core theming |
|
// also overrides tokens like --color-primary. custom-overrides.css loads last, |
|
// but without !important it loses the cascade and the saved theme has no visible |
|
// effect. !important here is scoped to user-set overrides only (this file only |
|
// ever contains tokens the admin explicitly set in the editor), so it does not |
|
// blanket-!important the full token registry. |
|
$lines[] = ' ' . $safeName . ': ' . $safeValue . ' !important;'; |
|
}//end foreach |
|
|
|
return $lines; |
|
}//end buildDeclarationLines() |
|
|
|
/** |
!important only wins between declarations on the same element. Core declares the dark colours on body, so body and everything inside it use core's value and never inherit the one on :root. For "System default", core serves the dark values on :root inside a media query, where the override does win. An explicitly chosen light theme is served the same non-plain way, so it can lose the override too.
Specified fix: openspec/changes/authoring-token-value-types (requirement "Editor overrides apply the same way for every dark user", task 2.2).
Found by the OpenSpec pass on 27 Sep 2026 and re-read at fd992ea on 28 Sep.
Live check: set "Primary color" in the editor, then compare Files for a user on "System default" with a dark OS and a user who chose "Dark theme".
A colour an admin sets in the token editor shows for users on "System default", but not for a user who picked the dark theme in their personal settings. Two dark users then see different colours.
Where, at development fd992ea:
lib/Service/CustomOverridesService.php:232-237writes every override into one:root {}block.lib/Service/CustomOverridesService.php:249-278adds!importantto each declaration to win the cascade.apps/theming/lib/Service/ThemeInjectionService.php:52-59loads each chosen theme as a non-plain stylesheet.apps/theming/lib/Controller/ThemingController.php:433scopes that stylesheet to[data-theme-<id>] { ... }.core/templates/layout.user.php:54-56putsdata-theme-darkon<body>.thematiq/lib/Service/CustomOverridesService.php
Lines 232 to 278 in fd992ea
!importantonly wins between declarations on the same element. Core declares the dark colours onbody, sobodyand everything inside it use core's value and never inherit the one on:root. For "System default", core serves the dark values on:rootinside a media query, where the override does win. An explicitly chosen light theme is served the same non-plain way, so it can lose the override too.Specified fix:
openspec/changes/authoring-token-value-types(requirement "Editor overrides apply the same way for every dark user", task 2.2).Found by the OpenSpec pass on 27 Sep 2026 and re-read at fd992ea on 28 Sep.
Live check: set "Primary color" in the editor, then compare Files for a user on "System default" with a dark OS and a user who chose "Dark theme".