'theme-fontFamily-base', 'colorBrand' => 'theme-color-brand', 'colorBrandContrast' => 'theme-color-brand-contrast', 'colorNewBrand' => 'theme-color-new-brand', 'colorFocusRing' => 'theme-color-focus-ring', 'colorFocusRingAlternative' => 'theme-color-focus-ring-alternative', 'colorTextHighContrast' => 'theme-color-text-highContrast', 'colorText' => 'theme-color-text', 'colorTextContrast' => 'theme-color-text-contrast', 'colorTextLight' => 'theme-color-text-light', 'colorTextLighter' => 'theme-color-text-lighter', 'colorTextOnDisabled' => 'theme-color-text-on-disabled', 'colorTextPlaceholder' => 'theme-color-text-placeholder', 'colorTextInvert' => 'theme-color-text-invert', 'colorTextInvertContrast' => 'theme-color-text-invert-contrast', 'colorTextInvertLight' => 'theme-color-text-invert-light', 'colorTextDisabled' => 'theme-color-text-disabled', 'colorLink' => 'theme-color-link', 'colorBaseSeries' => 'theme-color-base-series', 'colorHeadlineAlternative' => 'theme-color-headline-alternative', 'colorHeaderBackground' => 'theme-color-header-background', 'colorHeaderText' => 'theme-color-header-text', 'colorMenuContrastText' => 'theme-color-menu-contrast-text', 'colorMenuContrastTextSelected' => 'theme-color-menu-contrast-textSelected', 'colorMenuContrastTextActive' => 'theme-color-menu-contrast-textActive', 'colorMenuContrastBackground' => 'theme-color-menu-contrast-background', 'colorWidgetExportedBackgroundBase' => 'theme-color-widget-exported-background-base', 'colorWidgetTitleText' => 'theme-color-widget-title-text', 'colorWidgetTitleBackground' => 'theme-color-widget-title-background', 'colorBackgroundBase' => 'theme-color-background-base', 'colorBackgroundTinyContrast' => 'theme-color-background-tinyContrast', 'colorBackgroundLowContrast' => 'theme-color-background-lowContrast', 'colorBackgroundContrast' => 'theme-color-background-contrast', 'colorBackgroundHighContrast' => 'theme-color-background-highContrast', 'colorBackgroundDisabled' => 'theme-color-background-disabled', 'colorBorder' => 'theme-color-border', 'colorBorderAlternative' => 'theme-color-border-alternative', 'colorBorderLight' => 'theme-color-border-light', 'colorBoxShadow' => 'theme-color-boxShadow', 'shadowOverlay' => 'theme-shadow-overlay', 'colorCode' => 'theme-color-code', 'colorCodeBackground' => 'theme-color-code-background', 'colorWidgetBackground' => 'theme-color-widget-background', 'colorWidgetBorder' => 'theme-color-widget-border', 'filterOnIllustration' => 'theme-filter-on-illustration', 'colorMenuContrastBackgroundHover' => 'theme-color-menu-contrast-backgroundHover', ]; /** * @var string */ protected $themeMode = self::AUTO_MODE; /** * @var string|array */ public $fontFamilyBase = '-apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, Oxygen-Sans, Cantarell, \'Helvetica Neue\', sans-serif'; /** * @var string|array */ public $colorBrand = ['#43a047', '#778fd4']; /** * @var string|array */ public $colorBrandContrast = ['#fff', '#ffffff']; /** * @var string|array */ public $colorNewBrand = '#00b4be'; /** * @var string|array */ public $colorFocusRing = '#0969da'; /** * @var string|array */ public $colorFocusRingAlternative = '#00b4bE'; /** * @var string|array */ public $colorTextHighContrast = ['#000', '#d9d9d9']; /** * @var string|array */ public $colorText = ['#212121', '#ccc']; /** * @var string|array */ public $colorTextContrast = ['#37474f', '#bbb']; /** * @var string|array */ public $colorTextLight = ['#444', '#aaa']; /** * @var string|array */ public $colorTextLighter = ['#646464', '#999']; /** * @var string|array */ public $colorTextOnDisabled = ['#666666', '#999']; /** * @var string|array * @since Matomo 5.12.0 */ public $colorTextPlaceholder = ['#d1d1d1', '#565656']; /** * @var string|array */ public $colorTextInvert = ['#ccc', '#555']; /** * @var string|array */ public $colorTextInvertContrast = ['#fff', '#000']; /** * @var string|array */ public $colorTextInvertLight = ['#b9b9b9', '#666']; /** * @var string|array */ public $colorTextDisabled = ['#aaa', '#666']; /** * @var string|array */ public $colorLink = ['#1976D2', '#778fd4']; /** * @var string|array */ public $colorBaseSeries = '#ee3024'; /** * @var string|array */ public $colorHeadlineAlternative = ['#4E4E4E', '#aaa']; /** * @var string|array */ public $colorHeaderBackground; /** * @var string|array */ public $colorHeaderText; /** * @var string|array */ public $colorMenuContrastText; /** * @var string|array */ public $colorMenuContrastTextSelected; /** * @var string|array */ public $colorMenuContrastTextActive = ['#1976D2', '#fff']; /** * @var string|array */ public $colorMenuContrastBackgroundHover = ['#eff0f1', '#151819']; /** * @var string|array */ public $colorMenuContrastBackground; /** * @var string|array */ public $colorWidgetExportedBackgroundBase; /** * @var string|array */ public $colorWidgetTitleText; /** * @var string|array */ public $colorWidgetTitleBackground; /** * @var string|array */ public $colorBackgroundBase = ['#f5f5f5', '#151819']; /** * @var string|array */ public $colorBackgroundTinyContrast = ['#f2f2f2', '#182c32']; /** * @var string|array */ public $colorBackgroundLowContrast = ['#d9d9d9', '#192d33']; /** * @var string|array */ public $colorBackgroundContrast = ['#fff', '#202329']; /** * @var string|array */ public $colorBackgroundHighContrast = ['#202020', '#404349']; /** * @var string|array */ public $colorBackgroundDisabled = ['#d9d9d9', '#303339']; /** * @var string|array */ public $colorBorderLight = ['#a9a399', '#645e54']; /** * @var string|array * @deprecated Use $colorBorderAlternative instead. Retained only for legacy use and will be * phased out once everything has moved to the alternative. */ public $colorBorder = ['#cccccc', '#555555']; /** * Use this as the new border color. $colorBorder only remains so that we don't need to update * screenshots unless we really need to * * @var string|array */ public $colorBorderAlternative = ['#E0E0E0', '#555555']; /** * @var string|array */ public $colorBoxShadow = ['rgba(0, 0, 0, 0.1)', 'rgba(0, 0, 0, 0.1)']; /** * @var string|array */ public $shadowOverlay = ['0 0 3px #A5B1CA4D, 0 10px 40px #A5B1CA4D', '0 0 3px #00000080, 0 10px 40px #00000080']; /** * @var string|array */ public $colorCode = '#f3f3f3'; /** * @var string|array */ public $colorCodeBackground = '#4d4d4d'; /** * @var string|array */ public $colorWidgetBackground; /** * @var string|array */ public $colorWidgetBorder; /** * @var string|array */ public $filterOnIllustration = ['none', 'brightness(89%) invert(100%) hue-rotate(180deg)']; public function __construct(string $themeMode) { $this->themeMode = $themeMode; $this->colorMenuContrastText = $this->colorText; $this->colorMenuContrastTextSelected = $this->colorMenuContrastText; $this->colorMenuContrastBackground = $this->colorBackgroundContrast; $this->colorWidgetExportedBackgroundBase = $this->colorBackgroundContrast; $this->colorWidgetTitleText = $this->colorText; $this->colorWidgetTitleBackground = $this->colorBackgroundContrast; $this->colorWidgetBackground = $this->colorBackgroundContrast; $this->colorWidgetBorder = $this->colorBackgroundTinyContrast; $this->colorHeaderBackground = $this->colorBackgroundContrast; $this->colorHeaderText = $this->colorTextLighter; } /** * @return ThemeStyles */ public static function get(string $mode = self::AUTO_MODE) { $result = new self($mode); /** * @ignore */ Piwik::postEvent('Theme.configureThemeVariables', [$result]); return $result; } public function getIsLightMode(): bool { return $this->themeMode === self::LIGHT_MODE; } public function getIsDarkMode(): bool { return $this->themeMode === self::DARK_MODE; } public function getThemeMode(): string { return $this->themeMode; } public function getPropertyValue(string $name): string { if (!property_exists($this, $name)) { return ''; } return $this->resolvePropertyValue($this->$name, $this->getIsDarkMode() ? 1 : 0); } public function toLessCode() { $rootCssVars = []; $darkCssVars = []; foreach (get_object_vars($this) as $name => $value) { $varName = isset(self::$propertyNamesToLessVariableNames[$name]) ? self::$propertyNamesToLessVariableNames[$name] : $this->getGenericThemeVarName($name); if (is_array($value)) { $rootCssVars[] = " --$varName: " . $this->resolvePropertyValue($value, 0) . ";\n"; $darkCssVars[] = " --$varName: " . $this->resolvePropertyValue($value, 1) . ";\n"; } else { $rootCssVars[] = " --$varName: " . $this->resolvePropertyValue($value, 0) . ";\n"; } } $result = ":root {\n color-scheme: light;\n" . implode('', $rootCssVars) . "}\n\n"; if (!empty($darkCssVars)) { $result .= "[data-theme-mode=\"dark\"] {\n color-scheme: dark;\n" . implode('', $darkCssVars) . "}\n\n"; $result .= "@media (prefers-color-scheme: dark) {\n"; $result .= " [data-theme-mode=\"auto\"] {\n color-scheme: dark;\n" . implode('', $darkCssVars) . " }\n"; $result .= "}\n\n"; } foreach (get_object_vars($this) as $name => $_) { $varName = isset(self::$propertyNamesToLessVariableNames[$name]) ? self::$propertyNamesToLessVariableNames[$name] : $this->getGenericThemeVarName($name); $result .= "@$varName: ~\"var(--$varName)\";\n"; } return $result; } private function getGenericThemeVarName($propertyName) { return 'theme-' . $propertyName; } /** * @param mixed $value */ private function resolvePropertyValue($value, int $preferredIndex): string { if (!is_array($value)) { return is_string($value) ? $value : ''; } $fallbackIndex = $preferredIndex === 1 ? 0 : 1; if (isset($value[$preferredIndex]) && is_string($value[$preferredIndex])) { return $value[$preferredIndex]; } if (isset($value[$fallbackIndex]) && is_string($value[$fallbackIndex])) { return $value[$fallbackIndex]; } return ''; } }