diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts index 3e7bca695e..af73129447 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts @@ -33,8 +33,8 @@ import { UmbDocumentBlueprintTreeStore } from './documents/document-blueprints/d import { UmbDataTypeDetailStore } from './settings/data-types/data-type.detail.store'; import { UmbDataTypeTreeStore } from './settings/data-types/data-type.tree.store'; +import { UmbThemeContext } from './themes/theme.context'; import { UmbLanguageStore } from './settings/languages/language.store'; -import { UmbThemeService, UMB_THEME_SERVICE_CONTEXT_TOKEN } from './themes/theme.service'; import { UmbNotificationService, UMB_NOTIFICATION_SERVICE_CONTEXT_TOKEN } from '@umbraco-cms/notification'; // Domains diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/themes/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/themes/manifests.ts index c65556a0e4..dc5136d57a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/themes/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/themes/manifests.ts @@ -1,11 +1,25 @@ import type { ManifestTheme } from '@umbraco-cms/models'; export const themes: Array = [ + { + type: 'theme', + alias: 'umb-light-theme', + name: 'Light', + weight: 300, + }, { type: 'theme', alias: 'umb-dark-theme', name: 'Dark', - loader: () => import('./themes/dark.theme') + loader: () => new Promise((resolve) => resolve('src/backoffice/themes/themes/dark.theme.css')), + weight: 200, + }, + { + type: 'theme', + alias: 'umb-high-contrast-theme', + name: 'High contrast', + loader: () => new Promise((resolve) => resolve('src/backoffice/themes/themes/high-contrast.theme.css')), + weight: 100, }, ]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/themes/theme.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/themes/theme.context.ts index c32d019f60..7c84f4d3a8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/themes/theme.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/themes/theme.context.ts @@ -1,6 +1,4 @@ import { map } from 'rxjs'; -//import { dark, highContrast } from './themes'; -import type { CSSResult } from 'lit'; import { manifests } from './manifests'; import { UmbContextProviderController, UmbContextToken } from '@umbraco-cms/context-api'; import { StringState, UmbObserverController } from '@umbraco-cms/observable-api'; @@ -8,97 +6,63 @@ import { umbExtensionsRegistry } from '@umbraco-cms/extensions-api'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; import { ManifestTheme } from '@umbraco-cms/extensions-registry'; -export interface UmbTheme { - name: string; - css: CSSResult; -} - - const LOCAL_STORAGE_KEY = 'umb-theme-alias'; export class UmbThemeContext { - - // TODO: Turn this into a extension type, get rid of the #themes subject and #themes observable - /* - #themes = new ArrayState(>[ - { - name: 'Light', - css: '', - }, - ]); - public readonly themes = this.#themes.asObservable(); - */ - private _host: UmbControllerHostInterface; - #theme = new StringState(null); + #theme = new StringState('umb-light-theme'); public readonly theme = this.#theme.asObservable(); - #styleElement: HTMLStyleElement; - private themeSubscription?: UmbObserverController; + #styleElement: HTMLLinkElement | null = null; + constructor(host: UmbControllerHostInterface) { - this._host = host; - console.log("Theme COntext") - new UmbContextProviderController(host, UMB_THEME_CONTEXT_TOKEN, this); - //TODO: Figure out how to extend this with themes from packages - //this.addTheme(dark); - //this.addTheme(highContrast); - this.#styleElement = document.createElement('style'); + this.#styleElement = document.createElement('link'); + this.#styleElement.setAttribute('rel', 'stylesheet'); + document.head.appendChild(this.#styleElement); const storedTheme = localStorage.getItem(LOCAL_STORAGE_KEY); - if(storedTheme) { + if (storedTheme) { this.setThemeByAlias(storedTheme); } - - document.documentElement.insertAdjacentElement('beforeend', this.#styleElement); } - public setThemeByAlias(themeAlias: string | null) { - + public setThemeByAlias(themeAlias: string) { this.#theme.next(themeAlias); this.themeSubscription?.destroy(); - if(themeAlias != null) { + if (themeAlias) { localStorage.setItem(LOCAL_STORAGE_KEY, themeAlias); - this.themeSubscription = new UmbObserverController(this._host, - umbExtensionsRegistry.extensionsOfType('theme').pipe(map( - (extensions) => extensions.filter((extension) => extension.alias === themeAlias) - )) - , + this.themeSubscription = new UmbObserverController( + this._host, + umbExtensionsRegistry + .extensionsOfType('theme') + .pipe(map((extensions) => extensions.filter((extension) => extension.alias === themeAlias))), async (themes) => { if (themes.length > 0 && themes[0].loader) { - const result = await themes[0].loader(); - console.log("result from loader: ", result.default); - this.#styleElement.innerHTML = result.default; + const path = await themes[0].loader(); + this.#styleElement?.setAttribute('href', path); + } else { + localStorage.removeItem(LOCAL_STORAGE_KEY); + this.#styleElement?.setAttribute('href', ''); } - // how to get CSS. - //this.#styleElement.innerHTML = ""; } ); } else { localStorage.removeItem(LOCAL_STORAGE_KEY); - this.#styleElement.innerHTML = ""; + this.#styleElement?.setAttribute('href', ''); } - } - - /* - public addTheme(theme: UmbTheme) { - this.#themes.next([...this.#themes.value, theme]); - } - */ } export const UMB_THEME_CONTEXT_TOKEN = new UmbContextToken('umbThemeContext'); - - // TODO: Can we do this in a smarter way: const registerExtensions = (manifests: Array) => { manifests.forEach((manifest) => { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/themes/themes/dark.theme.css b/src/Umbraco.Web.UI.Client/src/backoffice/themes/themes/dark.theme.css new file mode 100644 index 0000000000..3b5c546d2c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/themes/themes/dark.theme.css @@ -0,0 +1,47 @@ +:root { + --uui-color-selected: #316dca; + --uui-color-selected-emphasis: #3e79d0; + --uui-color-selected-standalone: #5b8dd7; + --uui-color-selected-contrast: #eeeeef; + --uui-color-current: #316dca; + --uui-color-current-emphasis: #3e79d0; + --uui-color-current-standalone: #5b8dd7; + --uui-color-current-contrast: #f000; + --uui-color-disabled: #434c56; + --uui-color-disabled-standalone: #545d68; + --uui-color-disabled-contrast: #fcfcfc4d; + --uui-color-header-surface: #21262e; + --uui-color-header-contrast: #eeeeef; + --uui-color-header-contrast-emphasis: #eeeeef; + --uui-color-focus: #316dca; + --uui-color-surface: #2d333b; + --uui-color-surface-alt: #373e47; + --uui-color-surface-emphasis: #434c56; + --uui-color-background: #21262e; + --uui-color-text: #eeeeef; + --uui-color-text-alt: #eeeeef; + --uui-color-interactive: #eeeeef; + --uui-color-interactive-emphasis: #eeeeef; + --uui-color-border: #434c56; + --uui-color-border-standalone: #545d68; + --uui-color-border-emphasis: #626e7b; + --uui-color-divider: #373e47; + --uui-color-divider-standalone: #434c56; + --uui-color-divider-emphasis: #545d68; + --uui-color-default: #316dca; + --uui-color-default-emphasis: #316dca; + --uui-color-default-standalone: #316dca; + --uui-color-default-contrast: #eeeeef; + --uui-color-warning: #af7c12; + --uui-color-warning-emphasis: #af7c12; + --uui-color-warning-standalone: #af7c12; + --uui-color-warning-contrast: #eeeeef; + --uui-color-danger: #ca3b37; + --uui-color-danger-emphasis: #ca3b37; + --uui-color-danger-standalone: #ca3b37; + --uui-color-danger-contrast: #eeeeef; + --uui-color-positive: #347d39; + --uui-color-positive-emphasis: #347d39; + --uui-color-positive-standalone: #347d39; + --uui-color-positive-contrast: #eeeeef; +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/themes/themes/dark.theme.ts b/src/Umbraco.Web.UI.Client/src/backoffice/themes/themes/dark.theme.ts deleted file mode 100644 index 7a81f37f03..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/themes/themes/dark.theme.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { css } from 'lit'; -import { UmbTheme } from '../theme.context'; - -// TODO: We should get this from UUI, and it should be served through an extension. -const name = 'Dark'; -const cssResult = css` - :root { - --uui-color-selected: #316dca; - --uui-color-selected-emphasis: #3e79d0; - --uui-color-selected-standalone: #5b8dd7; - --uui-color-selected-contrast: #eeeeef; - --uui-color-current: #316dca; - --uui-color-current-emphasis: #3e79d0; - --uui-color-current-standalone: #5b8dd7; - --uui-color-current-contrast: #f000; - --uui-color-disabled: #434c56; - --uui-color-disabled-standalone: #545d68; - --uui-color-disabled-contrast: #fcfcfc4d; - --uui-color-header-surface: #21262e; - --uui-color-header-contrast: #eeeeef; - --uui-color-header-contrast-emphasis: #eeeeef; - --uui-color-focus: #316dca; - --uui-color-surface: #2d333b; - --uui-color-surface-alt: #373e47; - --uui-color-surface-emphasis: #434c56; - --uui-color-background: #21262e; - --uui-color-text: #eeeeef; - --uui-color-text-alt: #eeeeef; - --uui-color-interactive: #eeeeef; - --uui-color-interactive-emphasis: #eeeeef; - --uui-color-border: #434c56; - --uui-color-border-standalone: #545d68; - --uui-color-border-emphasis: #626e7b; - --uui-color-divider: #373e47; - --uui-color-divider-standalone: #434c56; - --uui-color-divider-emphasis: #545d68; - --uui-color-default: #316dca; - --uui-color-default-emphasis: #316dca; - --uui-color-default-standalone: #316dca; - --uui-color-default-contrast: #eeeeef; - --uui-color-warning: #af7c12; - --uui-color-warning-emphasis: #af7c12; - --uui-color-warning-standalone: #af7c12; - --uui-color-warning-contrast: #eeeeef; - --uui-color-danger: #ca3b37; - --uui-color-danger-emphasis: #ca3b37; - --uui-color-danger-standalone: #ca3b37; - --uui-color-danger-contrast: #eeeeef; - --uui-color-positive: #347d39; - --uui-color-positive-emphasis: #347d39; - --uui-color-positive-standalone: #347d39; - --uui-color-positive-contrast: #eeeeef; - } -`; - -export default cssResult.cssText; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/themes/themes/high-contrast.theme.css b/src/Umbraco.Web.UI.Client/src/backoffice/themes/themes/high-contrast.theme.css new file mode 100644 index 0000000000..6e84c57c7e --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/themes/themes/high-contrast.theme.css @@ -0,0 +1,53 @@ +:root { + --uui-color-selected: var(--uui-palette-violet-blue, #3544b1); + --uui-color-selected-emphasis: var(--uui-palette-violet-blue-light, rgb(70, 86, 200)); + --uui-color-selected-standalone: var(--uui-palette-violet-blue-dark, rgb(54, 65, 156)); + --uui-color-selected-contrast: #fff; + --uui-color-current: var(--uui-palette-spanish-pink, #f5c1bc); + --uui-color-current-emphasis: var(--uui-palette-spanish-pink-light, rgb(248, 214, 211)); + --uui-color-current-standalone: var(--uui-palette-spanish-pink-dark, rgb(232, 192, 189)); + --uui-color-current-contrast: var(--uui-palette-space-cadet, #1b264f); + --uui-color-disabled: var(--uui-palette-sand, #f3f3f5); + --uui-color-disabled-standalone: var(--uui-palette-sand-dark, rgb(226, 226, 226)); + --uui-color-disabled-contrast: var(--uui-palette-grey, #c4c4c4); + --uui-color-header-surface: var(--uui-palette-space-cadet, #1b264f); + --uui-color-header-contrast: #fff; + --uui-color-header-contrast-emphasis: #fff; + --uui-color-focus: var(--uui-palette-malibu, #3879ff); + --uui-color-surface: #fff; + --uui-color-surface-alt: #fff; + --uui-color-surface-emphasis: #dadada; + --uui-color-background: #fff; + --uui-color-text: var(--uui-palette-black, #060606); + --uui-color-text-alt: var(--uui-palette-dune-black, #2e2b29); + --uui-color-interactive: var(--uui-palette-space-cadet, #1b264f); + --uui-color-interactive-emphasis: var(--uui-palette-violet-blue, #3544b1); + --uui-color-border: #000000; + --uui-color-border-standalone: #000000; + --uui-color-border-emphasis: #000000; + --uui-color-divider: #000000; + --uui-color-divider-standalone: #000000; + --uui-color-divider-emphasis: #000000; + --uui-color-default: var(--uui-palette-space-cadet, #1b264f); + --uui-color-default-emphasis: var(--uui-palette-violet-blue, #3544b1); + --uui-color-default-standalone: var(--uui-palette-space-cadet-dark, rgb(28, 35, 59)); + --uui-color-default-contrast: #fff; + --uui-color-warning: #ffd621; + --uui-color-warning-emphasis: #ffdc41; + --uui-color-warning-standalone: #ffdd43; + --uui-color-warning-contrast: #000; + --uui-color-danger: #c60239; + --uui-color-danger-emphasis: #da114a; + --uui-color-danger-standalone: #d0003b; + --uui-color-danger-contrast: white; + --uui-color-positive: #0d8844; + --uui-color-positive-emphasis: #159c52; + --uui-color-positive-standalone: #1cae5e; + --uui-color-positive-contrast: #fff; + + --uui-shadow-depth-1: 0 0 0px 1px black; + --uui-shadow-depth-2: 0 0 0px 1px black; + --uui-shadow-depth-3: 0 0 0px 1px black; + --uui-shadow-depth-4: 0 0 0px 1px black; + --uui-shadow-depth-5: 0 0 0px 1px black; +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/themes/themes/high-contrast.theme.ts b/src/Umbraco.Web.UI.Client/src/backoffice/themes/themes/high-contrast.theme.ts deleted file mode 100644 index 0cbbdf5581..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/themes/themes/high-contrast.theme.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { css } from 'lit'; -import { UmbTheme } from '../theme.context'; - -// TODO: We should get this from UUI, and it should be served through an extension. -const name = 'High Contrast'; -const cssResult = css` - :root { - --uui-color-selected: var(--uui-palette-violet-blue, #3544b1); - --uui-color-selected-emphasis: var(--uui-palette-violet-blue-light, rgb(70, 86, 200)); - --uui-color-selected-standalone: var(--uui-palette-violet-blue-dark, rgb(54, 65, 156)); - --uui-color-selected-contrast: #fff; - --uui-color-current: var(--uui-palette-spanish-pink, #f5c1bc); - --uui-color-current-emphasis: var(--uui-palette-spanish-pink-light, rgb(248, 214, 211)); - --uui-color-current-standalone: var(--uui-palette-spanish-pink-dark, rgb(232, 192, 189)); - --uui-color-current-contrast: var(--uui-palette-space-cadet, #1b264f); - --uui-color-disabled: var(--uui-palette-sand, #f3f3f5); - --uui-color-disabled-standalone: var(--uui-palette-sand-dark, rgb(226, 226, 226)); - --uui-color-disabled-contrast: var(--uui-palette-grey, #c4c4c4); - --uui-color-header-surface: var(--uui-palette-space-cadet, #1b264f); - --uui-color-header-contrast: #fff; - --uui-color-header-contrast-emphasis: #fff; - --uui-color-focus: var(--uui-palette-malibu, #3879ff); - --uui-color-surface: #fff; - --uui-color-surface-alt: #fff; - --uui-color-surface-emphasis: #dadada; - --uui-color-background: #fff; - --uui-color-text: var(--uui-palette-black, #060606); - --uui-color-text-alt: var(--uui-palette-dune-black, #2e2b29); - --uui-color-interactive: var(--uui-palette-space-cadet, #1b264f); - --uui-color-interactive-emphasis: var(--uui-palette-violet-blue, #3544b1); - --uui-color-border: #000000; - --uui-color-border-standalone: #000000; - --uui-color-border-emphasis: #000000; - --uui-color-divider: #000000; - --uui-color-divider-standalone: #000000; - --uui-color-divider-emphasis: #000000; - --uui-color-default: var(--uui-palette-space-cadet, #1b264f); - --uui-color-default-emphasis: var(--uui-palette-violet-blue, #3544b1); - --uui-color-default-standalone: var(--uui-palette-space-cadet-dark, rgb(28, 35, 59)); - --uui-color-default-contrast: #fff; - --uui-color-warning: #ffd621; - --uui-color-warning-emphasis: #ffdc41; - --uui-color-warning-standalone: #ffdd43; - --uui-color-warning-contrast: #000; - --uui-color-danger: #c60239; - --uui-color-danger-emphasis: #da114a; - --uui-color-danger-standalone: #d0003b; - --uui-color-danger-contrast: white; - --uui-color-positive: #0d8844; - --uui-color-positive-emphasis: #159c52; - --uui-color-positive-standalone: #1cae5e; - --uui-color-positive-contrast: #fff; - - --uui-shadow-depth-1: 0 0 0px 1px black; - --uui-shadow-depth-2: 0 0 0px 1px black; - --uui-shadow-depth-3: 0 0 0px 1px black; - --uui-shadow-depth-4: 0 0 0px 1px black; - --uui-shadow-depth-5: 0 0 0px 1px black; - } -`; - -export const highContrast: UmbTheme = { - name: name, - css: cssResult.cssText, -}; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/users/current-user/user-dashboard-themes.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/users/current-user/user-dashboard-themes.element.ts index a316d0c87e..84ce43e311 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/users/current-user/user-dashboard-themes.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/users/current-user/user-dashboard-themes.element.ts @@ -4,6 +4,8 @@ import { customElement, state } from 'lit/decorators.js'; import { UUISelectEvent } from '@umbraco-ui/uui'; import { UmbThemeContext, UMB_THEME_CONTEXT_TOKEN } from '../../themes/theme.context'; import { UmbLitElement } from '@umbraco-cms/element'; +import { umbExtensionsRegistry } from '@umbraco-cms/extensions-api'; +import { ManifestTheme } from '@umbraco-cms/extensions-registry'; @customElement('umb-user-dashboard-test') export class UmbUserDashboardTestElement extends UmbLitElement { @@ -26,26 +28,22 @@ export class UmbUserDashboardTestElement extends UmbLitElement { #themeService?: UmbThemeContext; @state() - private _theme: string | null = null; + private _themeAlias: string | null = null; @state() - private _themes: Array = []; + private _themes: Array = []; constructor() { super(); this.consumeContext(UMB_THEME_CONTEXT_TOKEN, (instance) => { - - console.log("ThemeCOntext", instance) this.#themeService = instance; - instance.theme.subscribe((theme) => { - this._theme = theme; + instance.theme.subscribe((themeAlias) => { + this._themeAlias = themeAlias; }); - instance.setThemeByAlias('umb-dark-theme'); - // TODO: We should get rid of the #themes state and instead use an extension point: - /*instance.themes.subscribe((themes) => { - this._themes = themes.map((t) => t.name); - });*/ + umbExtensionsRegistry.extensionsOfType('theme').subscribe((themes) => { + this._themes = themes; + }); }); } @@ -54,11 +52,11 @@ export class UmbUserDashboardTestElement extends UmbLitElement { const theme = event.target.value.toString(); - this.#themeService.changeTheme(theme); + this.#themeService.setThemeByAlias(theme); } get options() { - return this._themes.map((t) => ({ name: t, value: t, selected: t === this._theme })); + return this._themes.map((t) => ({ name: t.name, value: t.alias, selected: t.alias === this._themeAlias })); } render() { @@ -67,7 +65,7 @@ export class UmbUserDashboardTestElement extends UmbLitElement { `; }