2022-03-29 16:18:40 -04:00
< ? php
2023-11-23 04:22:34 -05:00
2022-03-29 16:18:40 -04:00
declare ( strict_types = 1 );
/**
2024-05-30 14:13:41 -04:00
* SPDX - FileCopyrightText : 2022 Nextcloud GmbH and Nextcloud contributors
* SPDX - License - Identifier : AGPL - 3.0 - or - later
2022-03-29 16:18:40 -04:00
*/
namespace OCA\Theming\Themes ;
2024-05-17 08:39:04 -04:00
use OC\AppFramework\Http\Request ;
2022-04-01 09:19:15 -04:00
use OCA\Theming\ImageManager ;
2022-08-29 09:11:41 -04:00
use OCA\Theming\ITheme ;
2022-03-29 16:18:40 -04:00
use OCA\Theming\ThemingDefaults ;
use OCA\Theming\Util ;
2022-08-26 16:44:48 -04:00
use OCP\App\IAppManager ;
2022-04-01 09:19:15 -04:00
use OCP\IConfig ;
2022-04-15 07:55:19 -04:00
use OCP\IL10N ;
2024-05-17 08:39:04 -04:00
use OCP\IRequest ;
2022-03-29 16:18:40 -04:00
use OCP\IURLGenerator ;
2022-08-26 16:44:48 -04:00
use OCP\IUserSession ;
2022-03-29 16:18:40 -04:00
class DefaultTheme implements ITheme {
2022-09-23 09:29:47 -04:00
use CommonThemeTrait ;
2022-10-05 05:34:05 -04:00
public string $defaultPrimaryColor ;
2022-03-29 16:18:40 -04:00
public string $primaryColor ;
2024-05-17 08:39:04 -04:00
public function __construct (
public Util $util ,
public ThemingDefaults $themingDefaults ,
public IUserSession $userSession ,
public IURLGenerator $urlGenerator ,
public ImageManager $imageManager ,
public IConfig $config ,
public IL10N $l ,
public IAppManager $appManager ,
private ? IRequest $request ,
) {
2022-10-05 05:34:05 -04:00
$this -> defaultPrimaryColor = $this -> themingDefaults -> getDefaultColorPrimary ();
2022-10-06 06:36:59 -04:00
$this -> primaryColor = $this -> themingDefaults -> getColorPrimary ();
2022-03-29 16:18:40 -04:00
}
public function getId () : string {
return 'default' ;
}
2022-04-15 07:55:19 -04:00
public function getType () : int {
return ITheme :: TYPE_THEME ;
}
public function getTitle () : string {
2022-04-27 13:39:36 -04:00
return $this -> l -> t ( 'System default theme' );
2022-04-15 07:55:19 -04:00
}
public function getEnableLabel () : string {
2022-04-27 13:39:36 -04:00
return $this -> l -> t ( 'Enable the system default' );
2022-04-15 07:55:19 -04:00
}
public function getDescription () : string {
2022-04-27 13:39:36 -04:00
return $this -> l -> t ( 'Using the default system appearance.' );
2022-04-15 07:55:19 -04:00
}
2022-03-29 16:18:40 -04:00
public function getMediaQuery () : string {
return '' ;
}
2024-02-07 12:20:00 -05:00
public function getMeta () : array {
return [];
}
2022-03-29 16:18:40 -04:00
public function getCSSVariables () : array {
$colorMainText = '#222222' ;
2023-10-04 17:32:55 -04:00
// Color that still provides enough contrast for text, so we need a ratio of 4.5:1 on main background AND hover
2023-10-25 07:57:28 -04:00
$colorTextMaxcontrast = '#6b6b6b' ; // 4.5 : 1 for hover background and background dark
2022-03-29 16:18:40 -04:00
$colorMainBackground = '#ffffff' ;
$colorMainBackgroundRGB = join ( ',' , $this -> util -> hexToRGB ( $colorMainBackground ));
$colorBoxShadow = $this -> util -> darken ( $colorMainBackground , 70 );
$colorBoxShadowRGB = join ( ',' , $this -> util -> hexToRGB ( $colorBoxShadow ));
2022-08-22 11:37:55 -04:00
2025-08-26 06:57:13 -04:00
/*
colorX : The background color for e . g . buttons and note - card
colorXText : The text color on that background
colorXElement : When that color needs to have element contrast like borders
*/
2025-08-18 12:11:34 -04:00
$colorError = '#FFE7E7' ;
$colorErrorText = '#8A0000' ;
$colorErrorElement = '#c90000' ;
$colorWarning = '#FFEEC5' ;
$colorWarningText = '#664700' ;
2025-08-26 06:57:13 -04:00
$colorWarningElement = '#BF7900' ;
2025-08-18 12:11:34 -04:00
$colorSuccess = '#D8F3DA' ;
$colorSuccessText = '#005416' ;
$colorSuccessElement = '#099f05' ;
$colorInfo = '#D5F1FA' ;
$colorInfoText = '#0066AC' ;
2025-08-26 06:57:13 -04:00
$colorInfoElement = '#0077C7' ;
2023-06-05 20:28:19 -04:00
2024-05-17 08:39:04 -04:00
$user = $this -> userSession -> getUser ();
// Chromium based browsers currently (2024) have huge performance issues with blur filters
$isChromium = $this -> request !== null && $this -> request -> isUserAgent ([ Request :: USER_AGENT_CHROME , Request :: USER_AGENT_MS_EDGE ]);
// Ignore MacOS because they always have hardware accelartion
$isChromium = $isChromium && ! $this -> request -> isUserAgent ([ '/Macintosh/' ]);
// Allow to force the blur filter
$forceEnableBlur = $user === null ? false : $this -> config -> getUserValue (
$user -> getUID (),
'theming' ,
'force_enable_blur_filter' ,
);
$workingBlur = match ( $forceEnableBlur ) {
'yes' => true ,
'no' => false ,
default => ! $isChromium
};
2022-04-01 09:19:15 -04:00
$variables = [
2022-03-29 16:18:40 -04:00
'--color-main-background' => $colorMainBackground ,
'--color-main-background-rgb' => $colorMainBackgroundRGB ,
'--color-main-background-translucent' => 'rgba(var(--color-main-background-rgb), .97)' ,
2022-08-18 08:52:01 -04:00
'--color-main-background-blur' => 'rgba(var(--color-main-background-rgb), .8)' ,
2024-05-17 08:39:04 -04:00
'--filter-background-blur' => $workingBlur ? 'blur(25px)' : 'none' ,
2022-03-29 16:18:40 -04:00
// 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 ),
// max contrast for WCAG compliance
'--color-main-text' => $colorMainText ,
2022-09-28 00:21:30 -04:00
'--color-text-maxcontrast' => $colorTextMaxcontrast ,
'--color-text-maxcontrast-default' => $colorTextMaxcontrast ,
'--color-text-maxcontrast-background-blur' => $this -> util -> darken ( $colorTextMaxcontrast , 7 ),
2025-08-26 06:57:13 -04:00
'--color-text-error' => $this -> util -> darken ( $colorErrorElement , 2 ),
2025-08-25 08:48:06 -04:00
'--color-text-success' => $this -> util -> darken ( $colorSuccessElement , 10 ),
2025-08-26 06:57:13 -04:00
// border colors
'--color-border' => $this -> util -> darken ( $colorMainBackground , 7 ),
'--color-border-dark' => $this -> util -> darken ( $colorMainBackground , 14 ),
'--color-border-maxcontrast' => $this -> util -> darken ( $colorMainBackground , 51 ),
'--color-border-error' => 'var(--color-element-error)' ,
'--color-border-success' => 'var(--color-element-success)' ,
2022-03-29 16:18:40 -04:00
2025-08-27 06:39:09 -04:00
// special colors for elements (providing corresponding contrast) e.g. icons
'--color-element-error' => $colorErrorElement ,
'--color-element-info' => $colorInfoElement ,
'--color-element-success' => $colorSuccessElement ,
'--color-element-warning' => $colorWarningElement ,
2022-08-31 06:05:13 -04:00
2025-08-18 12:11:34 -04:00
// error/warning/success/info feedback colors
'--color-error' => $colorError ,
'--color-error-hover' => $this -> util -> darken ( $colorError , 7 ),
'--color-error-text' => $colorErrorText ,
'--color-warning' => $colorWarning ,
'--color-warning-hover' => $this -> util -> darken ( $colorWarning , 7 ),
'--color-warning-text' => $colorWarningText ,
'--color-success' => $colorSuccess ,
'--color-success-hover' => $this -> util -> darken ( $colorSuccess , 7 ),
'--color-success-text' => $colorSuccessText ,
'--color-info' => $colorInfo ,
'--color-info-hover' => $this -> util -> darken ( $colorInfo , 7 ),
'--color-info-text' => $colorInfoText ,
2024-03-06 08:37:59 -05:00
'--color-favorite' => '#A37200' ,
2025-08-18 12:11:34 -04:00
// deprecated
'--color-error-rgb' => join ( ',' , $this -> util -> hexToRGB ( $colorError )),
'--color-warning-rgb' => join ( ',' , $this -> util -> hexToRGB ( $colorWarning )),
'--color-success-rgb' => join ( ',' , $this -> util -> hexToRGB ( $colorSuccess )),
'--color-info-rgb' => join ( ',' , $this -> util -> hexToRGB ( $colorInfo )),
2022-03-29 16:18:40 -04:00
// used for the icon loading animation
'--color-loading-light' => '#cccccc' ,
'--color-loading-dark' => '#444444' ,
2025-08-27 06:39:09 -04:00
// Scrollbar
'--color-scrollbar' => 'var(--color-border-maxcontrast) transparent' ,
// Box shadow of elements
2022-03-29 16:18:40 -04:00
'--color-box-shadow-rgb' => $colorBoxShadowRGB ,
'--color-box-shadow' => 'rgba(var(--color-box-shadow-rgb), 0.5)' ,
2025-08-27 06:39:09 -04:00
// Assistant colors (marking AI generated content)
'--color-background-assistant' => '#F6F5FF' , // Background for AI generated content
'--color-border-assistant' => 'linear-gradient(125deg, #7398FE 50%, #6104A4 125%)' , // Border for AI generated content
2025-09-25 04:41:46 -04:00
'--color-element-assistant' => 'linear-gradient(214deg, #A569D3 12%, #00679E 39%, #422083 86%)' , // Background of primary buttons to interact with the Assistant (e.g. generate content)
'--color-element-assistant-icon' => 'linear-gradient(214deg, #9669D3 15%, #00679E 40%, #492083 80%)' , // The color used for the Assistant icon
2025-08-27 06:39:09 -04:00
2023-07-21 04:39:06 -04:00
'--font-face' => " system-ui, -apple-system, 'Segoe UI', Roboto, Oxygen-Sans, Cantarell, Ubuntu, 'Helvetica Neue', 'Noto Sans', 'Liberation Sans', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji' " ,
2022-03-29 16:18:40 -04:00
'--default-font-size' => '15px' ,
2024-07-31 11:28:12 -04:00
'--font-size-small' => '13px' ,
2024-07-02 16:29:43 -04:00
// 1.5 * font-size for accessibility
2024-07-31 08:36:23 -04:00
'--default-line-height' => '1.5' ,
2022-03-29 16:18:40 -04:00
// TODO: support "(prefers-reduced-motion)"
'--animation-quick' => '100ms' ,
'--animation-slow' => '300ms' ,
// Default variables --------------------------------------------
2024-05-16 04:18:12 -04:00
// Border width for input elements such as text fields and selects
'--border-width-input' => '1px' ,
'--border-width-input-focused' => '2px' ,
2024-07-31 11:22:09 -04:00
// Border radii (new values)
'--border-radius-small' => '4px' , // For smaller elements
'--border-radius-element' => '8px' , // For interactive elements such as buttons, input, navigation and list items
2024-08-01 09:43:36 -04:00
'--border-radius-container' => '12px' , // For smaller containers like action menus
'--border-radius-container-large' => '16px' , // For bigger containers like body or modals
2024-07-31 11:22:09 -04:00
// Border radii (deprecated)
'--border-radius' => 'var(--border-radius-small)' ,
'--border-radius-large' => 'var(--border-radius-element)' ,
2023-05-15 09:59:34 -04:00
'--border-radius-rounded' => '28px' ,
2024-08-01 09:43:36 -04:00
'--border-radius-pill' => '100px' ,
2022-03-29 16:18:40 -04:00
2024-06-12 15:59:37 -04:00
'--default-clickable-area' => '34px' ,
2024-06-12 07:09:31 -04:00
'--clickable-area-large' => '48px' ,
'--clickable-area-small' => '24px' ,
2024-07-02 16:29:43 -04:00
2022-08-24 11:18:55 -04:00
'--default-grid-baseline' => '4px' ,
2022-03-29 16:18:40 -04:00
2025-07-31 08:37:38 -04:00
// header / navigation bar
2022-03-29 16:18:40 -04:00
'--header-height' => '50px' ,
2024-07-02 16:29:43 -04:00
'--header-menu-item-height' => '44px' ,
2025-07-31 08:37:38 -04:00
/* An alpha mask to be applied to all icons on the navigation bar ( header menu ) .
* Icons are have a size of 20 px but usually we use MDI which have a content of 16 px so 2 px padding top bottom ,
2025-08-14 04:06:46 -04:00
* for better gradient we must at first begin at those 2 px ( 10 % of height ) as start and stop positions .
2025-07-31 08:37:38 -04:00
*/
2025-08-14 04:06:46 -04:00
'--header-menu-icon-mask' => 'linear-gradient(var(--color-background-plain-text) 25%, color-mix(in srgb, var(--color-background-plain-text), 55% transparent) 90%) alpha' ,
2025-07-31 08:37:38 -04:00
// various structure data
2022-03-29 16:18:40 -04:00
'--navigation-width' => '300px' ,
'--sidebar-min-width' => '300px' ,
'--sidebar-max-width' => '500px' ,
2024-07-02 16:29:43 -04:00
// Border radius of the body container
2024-08-01 09:43:36 -04:00
'--body-container-radius' => 'var(--border-radius-container-large)' ,
2024-07-02 16:29:43 -04:00
// Margin of the body container
'--body-container-margin' => 'calc(var(--default-grid-baseline) * 2)' ,
// Height of the body container to fully fill the view port
'--body-height' => 'calc(100% - env(safe-area-inset-bottom) - var(--header-height) - var(--body-container-margin))' ,
// mobile. Keep in sync with core/src/init.js
2022-03-29 16:18:40 -04:00
'--breakpoint-mobile' => '1024px' ,
2022-04-28 05:30:36 -04:00
'--background-invert-if-dark' => 'no' ,
2022-08-08 06:56:31 -04:00
'--background-invert-if-bright' => 'invert(100%)' ,
2022-10-18 22:07:12 -04:00
'--background-image-invert-if-bright' => 'no' ,
2022-03-29 16:18:40 -04:00
];
2022-04-01 09:19:15 -04:00
2022-09-23 09:29:47 -04:00
// Primary variables
$variables = array_merge ( $variables , $this -> generatePrimaryVariables ( $colorMainBackground , $colorMainText ));
2022-10-19 06:23:24 -04:00
$variables = array_merge ( $variables , $this -> generateGlobalBackgroundVariables ());
$variables = array_merge ( $variables , $this -> generateUserBackgroundVariables ());
2022-08-26 16:44:48 -04:00
2022-04-01 09:19:15 -04:00
return $variables ;
2022-03-29 16:18:40 -04:00
}
2022-04-20 03:55:41 -04:00
public function getCustomCss () : string {
return '' ;
}
2022-03-29 16:18:40 -04:00
}