diff options
Diffstat (limited to 'apps/theming/lib/Themes')
-rw-r--r-- | apps/theming/lib/Themes/DarkHighContrastTheme.php | 98 | ||||
-rw-r--r-- | apps/theming/lib/Themes/DarkTheme.php | 87 | ||||
-rw-r--r-- | apps/theming/lib/Themes/DefaultTheme.php | 203 | ||||
-rw-r--r-- | apps/theming/lib/Themes/DyslexiaFont.php | 84 | ||||
-rw-r--r-- | apps/theming/lib/Themes/HighContrastTheme.php | 91 |
5 files changed, 563 insertions, 0 deletions
diff --git a/apps/theming/lib/Themes/DarkHighContrastTheme.php b/apps/theming/lib/Themes/DarkHighContrastTheme.php new file mode 100644 index 00000000000..62b7d4f6358 --- /dev/null +++ b/apps/theming/lib/Themes/DarkHighContrastTheme.php @@ -0,0 +1,98 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2022 Joas Schilling <coding@schilljs.com> + * + * @author Joas Schilling <coding@schilljs.com> + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCA\Theming\Themes; + +use OCA\Theming\ITheme; + +class DarkHighContrastTheme extends DarkTheme implements ITheme { + + public function getId(): string { + 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'); + } + + public function getEnableLabel(): string { + return $this->l->t('Enable dark high contrast mode'); + } + + public function getDescription(): string { + return $this->l->t('Similar to the high contrast mode, but with dark colours.'); + } + + /** + * Try to keep this consistent with HighContrastTheme + */ + public function getCSSVariables(): array { + $variables = parent::getCSSVariables(); + $colorMainText = '#ffffff'; + $colorMainBackground = '#000000'; + $colorBoxShadowRGB = join(',', $this->util->hexToRGB($colorMainText)); + + $variables['--color-main-background'] = $colorMainBackground; + $variables['--color-main-text'] = $colorMainText; + + $variables['--color-background-dark'] = $this->util->lighten($colorMainBackground, 30); + $variables['--color-background-darker'] = $this->util->lighten($colorMainBackground, 30); + + $variables['--color-placeholder-light'] = $this->util->lighten($colorMainBackground, 30); + $variables['--color-placeholder-dark'] = $this->util->lighten($colorMainBackground, 45); + + $variables['--color-text-maxcontrast'] = $colorMainText; + $variables['--color-text-light'] = $colorMainText; + $variables['--color-text-lighter'] = $colorMainText; + + // used for the icon loading animation + $variables['--color-loading-light'] = '#000000'; + $variables['--color-loading-dark'] = '#dddddd'; + + + $variables['--color-box-shadow-rgb'] = $colorBoxShadowRGB; + $variables['--color-box-shadow'] = $colorBoxShadowRGB; + + + $variables['--color-border'] = $this->util->lighten($colorMainBackground, 50); + $variables['--color-border-dark'] = $this->util->lighten($colorMainBackground, 50); + + return $variables; + } + + public function getCustomCss(): string { + return " + [class^='icon-'], [class*=' icon-'], + .action, + #appmenu li a, + .menutoggle { + opacity: 1 !important; + } + "; + } +} diff --git a/apps/theming/lib/Themes/DarkTheme.php b/apps/theming/lib/Themes/DarkTheme.php new file mode 100644 index 00000000000..f0cacfc1696 --- /dev/null +++ b/apps/theming/lib/Themes/DarkTheme.php @@ -0,0 +1,87 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2022 Joas Schilling <coding@schilljs.com> + * + * @author Joas Schilling <coding@schilljs.com> + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCA\Theming\Themes; + +use OCA\Theming\ITheme; + +class DarkTheme extends DefaultTheme implements ITheme { + + public function getId(): string { + return 'dark'; + } + + public function getMediaQuery(): string { + return '(prefers-color-scheme: dark)'; + } + + public function getTitle(): string { + return $this->l->t('Dark theme'); + } + + public function getEnableLabel(): string { + return $this->l->t('Enable dark theme'); + } + + public function getDescription(): string { + return $this->l->t('A dark theme to ease your eyes by reducing the overall luminosity and brightness. It is still under development, so please report any issues you may find.'); + } + + public function getCSSVariables(): array { + $defaultVariables = parent::getCSSVariables(); + + $colorMainText = '#D8D8D8'; + $colorMainBackground = '#171717'; + $colorMainBackgroundRGB = join(',', $this->util->hexToRGB($colorMainBackground)); + $colorBoxShadow = $this->util->darken($colorMainBackground, 70); + $colorBoxShadowRGB = join(',', $this->util->hexToRGB($colorBoxShadow)); + + return array_merge($defaultVariables, [ + '--color-main-text' => $colorMainText, + '--color-main-background' => $colorMainBackground, + '--color-main-background-rgb' => $colorMainBackgroundRGB, + + '--color-background-hover' => $this->util->lighten($colorMainBackground, 4), + '--color-background-dark' => $this->util->lighten($colorMainBackground, 7), + '--color-background-darker' => $this->util->lighten($colorMainBackground, 14), + + '--color-placeholder-light' => $this->util->lighten($colorMainBackground, 10), + '--color-placeholder-dark' => $this->util->lighten($colorMainBackground, 20), + + '--color-text-maxcontrast' => $this->util->darken($colorMainText, 30), + '--color-text-light' => $this->util->darken($colorMainText, 10), + '--color-text-lighter' => $this->util->darken($colorMainText, 20), + + '--color-loading-light' => '#777', + '--color-loading-dark' => '#CCC', + + '--color-box-shadow-rgb' => $colorBoxShadowRGB, + + '--color-border' => $this->util->lighten($colorMainBackground, 7), + '--color-border-dark' => $this->util->lighten($colorMainBackground, 14), + + '--background-invert-if-dark' => 'invert(100%)', + ]); + } +} diff --git a/apps/theming/lib/Themes/DefaultTheme.php b/apps/theming/lib/Themes/DefaultTheme.php new file mode 100644 index 00000000000..7efd8f133d7 --- /dev/null +++ b/apps/theming/lib/Themes/DefaultTheme.php @@ -0,0 +1,203 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2022 Joas Schilling <coding@schilljs.com> + * + * @author Joas Schilling <coding@schilljs.com> + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCA\Theming\Themes; + +use OCA\Theming\ImageManager; +use OCA\Theming\ThemingDefaults; +use OCA\Theming\Util; +use OCA\Theming\ITheme; +use OCP\IConfig; +use OCP\IL10N; +use OCP\IURLGenerator; + +class DefaultTheme implements ITheme { + public Util $util; + public ThemingDefaults $themingDefaults; + public IURLGenerator $urlGenerator; + public ImageManager $imageManager; + public IConfig $config; + public IL10N $l; + + public string $primaryColor; + + public function __construct(Util $util, + ThemingDefaults $themingDefaults, + IURLGenerator $urlGenerator, + ImageManager $imageManager, + IConfig $config, + IL10N $l) { + $this->util = $util; + $this->themingDefaults = $themingDefaults; + $this->urlGenerator = $urlGenerator; + $this->imageManager = $imageManager; + $this->config = $config; + $this->l = $l; + + $this->primaryColor = $this->themingDefaults->getColorPrimary(); + } + + public function getId(): string { + return 'default'; + } + + public function getType(): int { + return ITheme::TYPE_THEME; + } + + public function getTitle(): string { + return $this->l->t('Light theme'); + } + + public function getEnableLabel(): string { + return $this->l->t('Enable the default light theme'); + } + + public function getDescription(): string { + return $this->l->t('The default light appearance.'); + } + + public function getMediaQuery(): string { + return ''; + } + + public function getCSSVariables(): array { + $colorMainText = '#222222'; + $colorMainBackground = '#ffffff'; + $colorMainBackgroundRGB = join(',', $this->util->hexToRGB($colorMainBackground)); + $colorBoxShadow = $this->util->darken($colorMainBackground, 70); + $colorBoxShadowRGB = join(',', $this->util->hexToRGB($colorBoxShadow)); + + $variables = [ + '--color-main-background' => $colorMainBackground, + '--color-main-background-rgb' => $colorMainBackgroundRGB, + '--color-main-background-translucent' => 'rgba(var(--color-main-background-rgb), .97)', + + // to use like this: background-image: linear-gradient(0, var('--gradient-main-background)); + '--gradient-main-background' => 'var(--color-main-background) 0%, var(--color-main-background-translucent) 85%, transparent 100%', + + // used for different active/hover/focus/disabled states + '--color-background-hover' => $this->util->darken($colorMainBackground, 4), + '--color-background-dark' => $this->util->darken($colorMainBackground, 7), + '--color-background-darker' => $this->util->darken($colorMainBackground, 14), + + '--color-placeholder-light' => $this->util->darken($colorMainBackground, 10), + '--color-placeholder-dark' => $this->util->darken($colorMainBackground, 20), + + // primary related colours + '--color-primary' => $this->primaryColor, + '--color-primary-text' => $this->util->invertTextColor($this->primaryColor) ? '#000000' : '#ffffff', + '--color-primary-hover' => $this->util->mix($this->primaryColor, $colorMainBackground, 80), + '--color-primary-light' => $this->util->mix($this->primaryColor, $colorMainBackground, 10), + '--color-primary-light-text' => $this->primaryColor, + '--color-primary-light-hover' => $this->util->mix($this->primaryColor, $colorMainText, 10), + '--color-primary-text-dark' => $this->util->darken($this->util->invertTextColor($this->primaryColor) ? '#000000' : '#ffffff', 7), + // used for buttons, inputs... + '--color-primary-element' => $this->util->elementColor($this->primaryColor), + '--color-primary-element-hover' => $this->util->mix($this->util->elementColor($this->primaryColor), $colorMainBackground, 80), + '--color-primary-element-light' => $this->util->lighten($this->util->elementColor($this->primaryColor), 15), + '--color-primary-element-lighter' => $this->util->mix($this->util->elementColor($this->primaryColor), $colorMainBackground, 15), + + // max contrast for WCAG compliance + '--color-main-text' => $colorMainText, + '--color-text-maxcontrast' => $this->util->lighten($colorMainText, 33), + '--color-text-light' => $colorMainText, + '--color-text-lighter' => $this->util->lighten($colorMainText, 33), + + // info/warning/success feedback colours + '--color-error' => '#e9322d', + '--color-error-hover' => $this->util->mix('#e9322d', $colorMainBackground, 80), + '--color-warning' => '#eca700', + '--color-warning-hover' => $this->util->mix('#eca700', $colorMainBackground, 80), + '--color-success' => '#46ba61', + '--color-success-hover' => $this->util->mix('#46ba61', $colorMainBackground, 80), + + // used for the icon loading animation + '--color-loading-light' => '#cccccc', + '--color-loading-dark' => '#444444', + + '--color-box-shadow-rgb' => $colorBoxShadowRGB, + '--color-box-shadow' => "rgba(var(--color-box-shadow-rgb), 0.5)", + + '--color-border' => $this->util->darken($colorMainBackground, 7), + '--color-border-dark' => $this->util->darken($colorMainBackground, 14), + + '--font-face' => "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Cantarell, Ubuntu, 'Helvetica Neue', Arial, sans-serif, 'Noto Color Emoji', 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'", + '--default-font-size' => '15px', + + // TODO: support "(prefers-reduced-motion)" + '--animation-quick' => '100ms', + '--animation-slow' => '300ms', + + // Default variables -------------------------------------------- + '--border-radius' => '3px', + '--border-radius-large' => '10px', + // pill-style button, value is large so big buttons also have correct roundness + '--border-radius-pill' => '100px', + + '--default-line-height' => '24px', + + // various structure data + '--header-height' => '50px', + '--navigation-width' => '300px', + '--sidebar-min-width' => '300px', + '--sidebar-max-width' => '500px', + '--list-min-width' => '200px', + '--list-max-width' => '300px', + '--header-menu-item-height' => '44px', + '--header-menu-profile-item-height' => '66px', + + // mobile. Keep in sync with core/js/js.js + '--breakpoint-mobile' => '1024px', + + // invert filter if primary is too bright + // to be used for legacy reasons only. Use inline + // svg with proper css variable instead or material + // design icons. + '--primary-invert-if-bright' => $this->util->invertTextColor($this->primaryColor) ? 'invert(100%)' : 'unset', + '--background-invert-if-dark' => 'unset', + ]; + + // Register image variables only if custom-defined + $backgroundDeleted = $this->config->getAppValue('theming', 'backgroundMime', '') === 'backgroundColor'; + foreach(['logo', 'logoheader', 'favicon', 'background'] as $image) { + if ($this->imageManager->hasImage($image)) { + // If primary as background has been request, let's not define the background image + if ($image === 'background' && $backgroundDeleted) { + $variables["--image-background-plain"] = true; + continue; + } else if ($image === 'background') { + $variables['--image-background-size'] = 'cover'; + } + $variables["--image-$image"] = "url('".$this->imageManager->getImageUrl($image)."')"; + } + } + + return $variables; + } + + public function getCustomCss(): string { + return ''; + } +} diff --git a/apps/theming/lib/Themes/DyslexiaFont.php b/apps/theming/lib/Themes/DyslexiaFont.php new file mode 100644 index 00000000000..50284d33b9d --- /dev/null +++ b/apps/theming/lib/Themes/DyslexiaFont.php @@ -0,0 +1,84 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2022 Joas Schilling <coding@schilljs.com> + * + * @author Joas Schilling <coding@schilljs.com> + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCA\Theming\Themes; + +use OCA\Theming\ITheme; + +class DyslexiaFont extends DefaultTheme implements ITheme { + + public function getId(): string { + return 'opendyslexic'; + } + + public function getType(): int { + return ITheme::TYPE_FONT; + } + + public function getTitle(): string { + return $this->l->t('Dyslexia font'); + } + + public function getEnableLabel(): string { + return $this->l->t('Enable dyslexia font'); + } + + public function getDescription(): string { + return $this->l->t('OpenDyslexic is a free typeface/font designed to mitigate some of the common reading errors caused by dyslexia.'); + } + + public function getCSSVariables(): array { + $variables = parent::getCSSVariables(); + $originalFontFace = $variables['--font-face']; + + $variables = [ + '--font-face' => 'OpenDyslexic, ' . $originalFontFace + ]; + + return $variables; + } + + public function getCustomCss(): string { + return " + @font-face { + font-family: 'OpenDyslexic'; + font-style: normal; + font-weight: 400; + src: url('../fonts/OpenDyslexic-Regular.woff') format('woff'), + url('../fonts/OpenDyslexic-Regular.otf') format('opentype'), + url('../fonts/OpenDyslexic-Regular.ttf') format('truetype'); + } + + @font-face { + font-family: 'OpenDyslexic'; + font-style: normal; + font-weight: 700; + src: url('../fonts/OpenDyslexic-Bold.woff') format('woff'), + url('../fonts/OpenDyslexic-Bold.otf') format('opentype'), + url('../fonts/OpenDyslexic-Bold.ttf') format('truetype'); + } + "; + } +} + diff --git a/apps/theming/lib/Themes/HighContrastTheme.php b/apps/theming/lib/Themes/HighContrastTheme.php new file mode 100644 index 00000000000..77239f2076c --- /dev/null +++ b/apps/theming/lib/Themes/HighContrastTheme.php @@ -0,0 +1,91 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2022 Joas Schilling <coding@schilljs.com> + * + * @author Joas Schilling <coding@schilljs.com> + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCA\Theming\Themes; + +use OCA\Theming\ITheme; + +class HighContrastTheme extends DefaultTheme implements ITheme { + + public function getId(): string { + return 'highcontrast'; + } + + public function getMediaQuery(): string { + return '(prefers-contrast: more)'; + } + + public function getTitle(): string { + return $this->l->t('High contrast mode'); + } + + public function getEnableLabel(): string { + return $this->l->t('Enable high contrast mode'); + } + + public function getDescription(): string { + return $this->l->t('A high contrast mode to ease your navigation. Visual quality will be reduced but clarity will be increased.'); + } + + public function getCSSVariables(): array { + $variables = parent::getCSSVariables(); + $colorMainText = '#000000'; + $colorMainBackground = '#ffffff'; + + $variables['--color-main-background'] = $colorMainBackground; + $variables['--color-main-text'] = $colorMainText; + + $variables['--color-background-dark'] = $this->util->darken($colorMainBackground, 30); + $variables['--color-background-darker'] = $this->util->darken($colorMainBackground, 30); + + $variables['--color-placeholder-light'] = $this->util->darken($colorMainBackground, 30); + $variables['--color-placeholder-dark'] = $this->util->darken($colorMainBackground, 45); + + $variables['--color-text-maxcontrast'] = 'var(--color-main-text)'; + $variables['--color-text-light'] = 'var(--color-main-text)'; + $variables['--color-text-lighter'] = 'var(--color-main-text)'; + + // used for the icon loading animation + $variables['--color-loading-light'] = '#dddddd'; + $variables['--color-loading-dark'] = '#000000'; + + $variables['--color-box-shadow'] = 'var(--color-main-text)'; + + $variables['--color-border'] = $this->util->darken($colorMainBackground, 50); + $variables['--color-border-dark'] = $this->util->darken($colorMainBackground, 50); + + return $variables; + } + + public function getCustomCss(): string { + return " + [class^='icon-'], [class*=' icon-'], + .action, + #appmenu li a, + .menutoggle { + opacity: 1 !important; + } + "; + } +} |