diff --git a/apps/theming/js/settings-admin.js b/apps/theming/js/settings-admin.js index 7efdab6dda47c..f5307f3da4b3c 100644 --- a/apps/theming/js/settings-admin.js +++ b/apps/theming/js/settings-admin.js @@ -72,6 +72,7 @@ function hideUndoButton(setting, value) { slogan: t('lib', 'a safe home for all your data'), url: 'https://nextcloud.com', color: '#0082c9', + color_dark_theme: document.getElementById('theming-color').value, logoMime: '', backgroundMime: '', imprintUrl: '', @@ -99,6 +100,8 @@ window.addEventListener('DOMContentLoaded', function () { // manually instantiate jscolor to work around new Function call which violates strict CSP var colorElement = $('#theming-color')[0]; var jscolor = new window.jscolor(colorElement, {hash: true}); + var colorDarkThemeElement = $('#theming-color_dark_theme')[0]; + var jscolorDarkTheme = new window.jscolor(colorDarkThemeElement, {hash: true}); $('#theming .theme-undo').each(function() { var setting = $(this).data('setting'); @@ -180,6 +183,13 @@ window.addEventListener('DOMContentLoaded', function () { if (value.indexOf('#') !== 0) { value = '#' + value; } + + // Hack: detect if color_dark_theme should follow color by checking if the undo button is visible. + if ($(".theme-undo[data-setting='color_dark_theme']").css('display') === 'none') { + var colorDarkThemePicker = document.getElementById('theming-color_dark_theme'); + colorDarkThemePicker.style.backgroundColor = value; + colorDarkThemePicker.value = value.toUpperCase(); + } } if(setting === 'name') { if(checkName()){ @@ -215,8 +225,21 @@ window.addEventListener('DOMContentLoaded', function () { ).done(function(response) { if (setting === 'color') { var colorPicker = document.getElementById('theming-color'); + var colorDarkThemePicker = document.getElementById('theming-color_dark_theme'); + + // If color_dark_theme is the same as color + // then we need to update it too as it is probably unset and defaulting to color. + if (colorPicker.value === colorDarkThemePicker.value) { + colorDarkThemePicker.style.backgroundColor = response.data.value; + colorDarkThemePicker.value = response.data.value.toUpperCase(); + } + colorPicker.style.backgroundColor = response.data.value; - colorPicker.value = response.data.value.slice(1).toUpperCase(); + colorPicker.value = response.data.value.toUpperCase(); + } else if (setting === 'color_dark_theme') { + var colorDarkThemePicker = document.getElementById('theming-color_dark_theme'); + colorDarkThemePicker.style.backgroundColor = response.data.value; + colorDarkThemePicker.value = response.data.value.toUpperCase(); } else if (!image) { var input = document.getElementById('theming-'+setting); input.value = response.data.value; diff --git a/apps/theming/lib/Controller/ThemingController.php b/apps/theming/lib/Controller/ThemingController.php index 94deb2e73768b..8a794dc0effe4 100644 --- a/apps/theming/lib/Controller/ThemingController.php +++ b/apps/theming/lib/Controller/ThemingController.php @@ -147,6 +147,7 @@ public function updateStylesheet($setting, $value) { } break; case 'color': + case 'color_dark_theme': if (!preg_match('/^\#([0-9a-f]{3}|[0-9a-f]{6})$/i', $value)) { $error = $this->l10n->t('The given color is invalid'); } @@ -328,7 +329,7 @@ public function getThemeStylesheet(string $themeId, bool $plain = false, bool $w // If plain is set, the browser decides of the css priority if ($plain) { $css = ":root { $variables } " . $customCss; - } else { + } else { // If not set, we'll rely on the body class $compiler = new Compiler(); $compiledCss = $compiler->compileString("body[data-theme-$themeId] { $variables $customCss }"); diff --git a/apps/theming/lib/ITheme.php b/apps/theming/lib/ITheme.php index a5c9cdf26a623..28822f447e974 100644 --- a/apps/theming/lib/ITheme.php +++ b/apps/theming/lib/ITheme.php @@ -96,4 +96,12 @@ public function getCSSVariables(): array; * @since 25.0.0 */ public function getCustomCss(): string; + + /** + * Whether the theme is dark + * Will be used to when selecting the primary color. + * + * @since 25.0.0 + */ + public function isDark(): bool; } diff --git a/apps/theming/lib/Settings/Admin.php b/apps/theming/lib/Settings/Admin.php index 6caa174d99bf8..3232c5db94248 100644 --- a/apps/theming/lib/Settings/Admin.php +++ b/apps/theming/lib/Settings/Admin.php @@ -76,6 +76,7 @@ public function getForm(): TemplateResponse { 'url' => $this->themingDefaults->getBaseUrl(), 'slogan' => $this->themingDefaults->getSlogan(), 'color' => $this->themingDefaults->getColorPrimary(), + 'color_dark_theme' => $this->themingDefaults->getColorPrimary(true), 'uploadLogoRoute' => $this->urlGenerator->linkToRoute('theming.Theming.uploadImage'), 'canThemeIcons' => $this->imageManager->shouldReplaceIcons(), 'iconDocs' => $this->urlGenerator->linkToDocs('admin-theming-icons'), diff --git a/apps/theming/lib/Themes/DarkTheme.php b/apps/theming/lib/Themes/DarkTheme.php index f5463d94fc4a9..550981d390165 100644 --- a/apps/theming/lib/Themes/DarkTheme.php +++ b/apps/theming/lib/Themes/DarkTheme.php @@ -28,6 +28,10 @@ class DarkTheme extends DefaultTheme implements ITheme { + public function isDark(): bool { + return true; + } + public function getId(): string { return 'dark'; } @@ -57,7 +61,7 @@ public function getCSSVariables(): array { $colorBoxShadow = $this->util->darken($colorMainBackground, 70); $colorBoxShadowRGB = join(',', $this->util->hexToRGB($colorBoxShadow)); - return array_merge($defaultVariables, [ + return array_merge($defaultVariables, [ '--color-main-text' => $colorMainText, '--color-main-background' => $colorMainBackground, '--color-main-background-rgb' => $colorMainBackgroundRGB, diff --git a/apps/theming/lib/Themes/DefaultTheme.php b/apps/theming/lib/Themes/DefaultTheme.php index 58983d29df132..037fe490e2b5c 100644 --- a/apps/theming/lib/Themes/DefaultTheme.php +++ b/apps/theming/lib/Themes/DefaultTheme.php @@ -55,7 +55,11 @@ public function __construct(Util $util, $this->config = $config; $this->l = $l; - $this->primaryColor = $this->themingDefaults->getColorPrimary(); + $this->primaryColor = $this->themingDefaults->getColorPrimary($this->isDark()); + } + + public function isDark(): bool { + return false; } public function getId(): string { diff --git a/apps/theming/lib/ThemingDefaults.php b/apps/theming/lib/ThemingDefaults.php index 3d7aaee2064a3..473783c096088 100644 --- a/apps/theming/lib/ThemingDefaults.php +++ b/apps/theming/lib/ThemingDefaults.php @@ -228,8 +228,22 @@ public function getShortFooter() { * * @return string */ - public function getColorPrimary() { - $color = $this->config->getAppValue('theming', 'color', $this->color); + public function getColorPrimary(bool $dark = false) { + $color = $this->config->getAppValue( + 'theming', + $dark ? 'color_dark_theme' : 'color', + 'none' + ); + + // Use the light theme color if the dark theme color is not set + if ($dark && $color === 'none') { + $color = $this->config->getAppValue( + 'theming', + 'color', + $this->color + ); + } + if (!preg_match('/^\#([0-9a-f]{3}|[0-9a-f]{6})$/i', $color)) { $color = '#0082c9'; } @@ -450,6 +464,9 @@ public function undo($setting) { case 'color': $returnValue = $this->getColorPrimary(); break; + case 'color_dark_theme': + $returnValue = $this->getColorPrimary(true); + break; case 'logo': case 'logoheader': case 'background': diff --git a/apps/theming/templates/settings-admin.php b/apps/theming/templates/settings-admin.php index 6014f0e85798e..e39a84e66f81d 100644 --- a/apps/theming/templates/settings-admin.php +++ b/apps/theming/templates/settings-admin.php @@ -67,6 +67,13 @@
+
+ +