From 6364e53e5a4bf60ef81d214baa99ec286c8ea198 Mon Sep 17 00:00:00 2001 From: =?utf8?q?John=20Molakvo=C3=A6?= Date: Wed, 7 Feb 2024 18:20:00 +0100 Subject: [PATCH] Merge pull request #32231 from nextcloud/feat/theming-scheme-meta --- apps/theming/lib/ITheme.php | 8 +++ .../lib/Service/ThemeInjectionService.php | 51 ++++++++++++++++--- .../lib/Themes/DarkHighContrastTheme.php | 8 +-- apps/theming/lib/Themes/DarkTheme.php | 16 ++++-- apps/theming/lib/Themes/DefaultTheme.php | 4 ++ apps/theming/lib/Themes/HighContrastTheme.php | 8 +-- apps/theming/lib/Themes/LightTheme.php | 12 +++-- 7 files changed, 84 insertions(+), 23 deletions(-) diff --git a/apps/theming/lib/ITheme.php b/apps/theming/lib/ITheme.php index 3c3b081aec5..4ff455005a2 100644 --- a/apps/theming/lib/ITheme.php +++ b/apps/theming/lib/ITheme.php @@ -71,6 +71,14 @@ interface ITheme { */ public function getDescription(): string; + /** + * Get the meta attribute matching the theme + * e.g. https://html.spec.whatwg.org/multipage/semantics.html#meta-color-scheme + * @return array{name?: string, content?: string}[] + * @since 29.0.0 + */ + public function getMeta(): array; + /** * Get the media query triggering this theme * Optional, ignored if falsy diff --git a/apps/theming/lib/Service/ThemeInjectionService.php b/apps/theming/lib/Service/ThemeInjectionService.php index c7560bdf8f8..169bc0c0223 100644 --- a/apps/theming/lib/Service/ThemeInjectionService.php +++ b/apps/theming/lib/Service/ThemeInjectionService.php @@ -22,6 +22,7 @@ */ namespace OCA\Theming\Service; +use OCA\Theming\ITheme; use OCA\Theming\Themes\DefaultTheme; use OCA\Theming\Util; use OCP\IConfig; @@ -48,6 +49,7 @@ class ThemeInjectionService { $this->defaultTheme = $defaultTheme; $this->util = $util; $this->config = $config; + if ($userSession->getUser() !== null) { $this->userId = $userSession->getUser()->getUID(); } else { @@ -55,7 +57,7 @@ class ThemeInjectionService { } } - public function injectHeaders() { + public function injectHeaders(): void { $themes = $this->themesService->getThemes(); $defaultTheme = $themes[$this->defaultTheme->getId()]; $mediaThemes = array_filter($themes, function ($theme) { @@ -64,11 +66,11 @@ class ThemeInjectionService { }); // Default theme fallback - $this->addThemeHeader($defaultTheme->getId()); + $this->addThemeHeaders($defaultTheme); // Themes applied by media queries foreach($mediaThemes as $theme) { - $this->addThemeHeader($theme->getId(), true, $theme->getMediaQuery()); + $this->addThemeHeaders($theme, true, $theme->getMediaQuery()); } // Themes @@ -77,20 +79,23 @@ class ThemeInjectionService { if ($theme->getId() === $this->defaultTheme->getId()) { continue; } - $this->addThemeHeader($theme->getId(), false); + $this->addThemeHeaders($theme, false); } + + // Meta headers + $this->addThemeMetaHeaders($themes); } /** * Inject theme header into rendered page * - * @param string $themeId the theme ID + * @param ITheme $theme the theme * @param bool $plain request the :root syntax * @param string $media media query to use in the element */ - private function addThemeHeader(string $themeId, bool $plain = true, string $media = null) { + private function addThemeHeaders(ITheme $theme, bool $plain = true, string $media = null): void { $linkToCSS = $this->urlGenerator->linkToRoute('theming.Theming.getThemeStylesheet', [ - 'themeId' => $themeId, + 'themeId' => $theme->getId(), 'plain' => $plain, 'v' => $this->util->getCacheBuster(), ]); @@ -101,4 +106,36 @@ class ThemeInjectionService { 'class' => 'theme' ]); } + + /** + * Inject meta headers into rendered page + * + * @param ITheme[] $themes the theme + */ + private function addThemeMetaHeaders(array $themes): void { + $metaHeaders = []; + + // Meta headers + foreach($this->themesService->getThemes() as $theme) { + if (!empty($theme->getMeta())) { + foreach($theme->getMeta() as $meta) { + if (!isset($meta['name']) || !isset($meta['content'])) { + continue; + } + + if (!isset($metaHeaders[$meta['name']])) { + $metaHeaders[$meta['name']] = []; + } + $metaHeaders[$meta['name']][] = $meta['content']; + } + } + } + + foreach($metaHeaders as $name => $content) { + \OCP\Util::addHeader('meta', [ + 'name' => $name, + 'content' => join(' ', array_unique($content)), + ]); + } + } } diff --git a/apps/theming/lib/Themes/DarkHighContrastTheme.php b/apps/theming/lib/Themes/DarkHighContrastTheme.php index 965dac2922c..e6f1da94b4e 100644 --- a/apps/theming/lib/Themes/DarkHighContrastTheme.php +++ b/apps/theming/lib/Themes/DarkHighContrastTheme.php @@ -33,10 +33,6 @@ class DarkHighContrastTheme extends DarkTheme implements ITheme { return 'dark-highcontrast'; } - public function getMediaQuery(): string { - return '(prefers-color-scheme: dark) and (prefers-contrast: more)'; - } - public function getTitle(): string { return $this->l->t('Dark theme with high contrast mode'); } @@ -49,6 +45,10 @@ class DarkHighContrastTheme extends DarkTheme implements ITheme { return $this->l->t('Similar to the high contrast mode, but with dark colours.'); } + public function getMediaQuery(): string { + return '(prefers-color-scheme: dark) and (prefers-contrast: more)'; + } + /** * Keep this consistent with other HighContrast Themes */ diff --git a/apps/theming/lib/Themes/DarkTheme.php b/apps/theming/lib/Themes/DarkTheme.php index f63854289ad..a40f8009e17 100644 --- a/apps/theming/lib/Themes/DarkTheme.php +++ b/apps/theming/lib/Themes/DarkTheme.php @@ -33,10 +33,6 @@ class DarkTheme extends DefaultTheme implements ITheme { return 'dark'; } - public function getMediaQuery(): string { - return '(prefers-color-scheme: dark)'; - } - public function getTitle(): string { return $this->l->t('Dark theme'); } @@ -49,6 +45,18 @@ class DarkTheme extends DefaultTheme implements ITheme { return $this->l->t('A dark theme to ease your eyes by reducing the overall luminosity and brightness.'); } + public function getMediaQuery(): string { + return '(prefers-color-scheme: dark)'; + } + + public function getMeta(): array { + // https://html.spec.whatwg.org/multipage/semantics.html#meta-color-scheme + return [[ + 'name' => 'color-scheme', + 'content' => 'dark', + ]]; + } + public function getCSSVariables(): array { $defaultVariables = parent::getCSSVariables(); diff --git a/apps/theming/lib/Themes/DefaultTheme.php b/apps/theming/lib/Themes/DefaultTheme.php index 3dfa89f8d3a..af1489c3577 100644 --- a/apps/theming/lib/Themes/DefaultTheme.php +++ b/apps/theming/lib/Themes/DefaultTheme.php @@ -101,6 +101,10 @@ class DefaultTheme implements ITheme { return ''; } + public function getMeta(): array { + return []; + } + public function getCSSVariables(): array { $colorMainText = '#222222'; $colorMainTextRgb = join(',', $this->util->hexToRGB($colorMainText)); diff --git a/apps/theming/lib/Themes/HighContrastTheme.php b/apps/theming/lib/Themes/HighContrastTheme.php index 92511b59c81..b1c2bf1564f 100644 --- a/apps/theming/lib/Themes/HighContrastTheme.php +++ b/apps/theming/lib/Themes/HighContrastTheme.php @@ -33,10 +33,6 @@ class HighContrastTheme extends DefaultTheme implements ITheme { return 'light-highcontrast'; } - public function getMediaQuery(): string { - return '(prefers-contrast: more)'; - } - public function getTitle(): string { return $this->l->t('High contrast mode'); } @@ -49,6 +45,10 @@ class HighContrastTheme extends DefaultTheme implements ITheme { return $this->l->t('A high contrast mode to ease your navigation. Visual quality will be reduced but clarity will be increased.'); } + public function getMediaQuery(): string { + return '(prefers-contrast: more)'; + } + /** * Keep this consistent with other HighContrast Themes */ diff --git a/apps/theming/lib/Themes/LightTheme.php b/apps/theming/lib/Themes/LightTheme.php index 320f8334147..7e6773992a1 100644 --- a/apps/theming/lib/Themes/LightTheme.php +++ b/apps/theming/lib/Themes/LightTheme.php @@ -33,10 +33,6 @@ class LightTheme extends DefaultTheme implements ITheme { return 'light'; } - public function getType(): int { - return ITheme::TYPE_THEME; - } - public function getTitle(): string { return $this->l->t('Light theme'); } @@ -52,4 +48,12 @@ class LightTheme extends DefaultTheme implements ITheme { public function getMediaQuery(): string { return '(prefers-color-scheme: light)'; } + + public function getMeta(): array { + // https://html.spec.whatwg.org/multipage/semantics.html#meta-color-scheme + return [[ + 'name' => 'color-scheme', + 'content' => 'light', + ]]; + } } -- 2.39.5