diff --git a/Build/Sources/Sass/component/_root.scss b/Build/Sources/Sass/component/_root.scss index 0cb995c69b5d22dc99aba80f99fb74312fb74db1..a9b43e255a2c682a98037d9aa26c2405e7347d7d 100644 --- a/Build/Sources/Sass/component/_root.scss +++ b/Build/Sources/Sass/component/_root.scss @@ -313,10 +313,34 @@ [data-color-scheme="dark"] { color-scheme: only dark; + + & .nodes-container, + & .tree-toolbar, + & .dropdown-menu, + & .scaffold-content-navigation-drag, + & .scaffold-content-navigation-switcher, + & .alwan, + & .context-menu, + & .flatpickr-calendar, + & .dragging-tooltip { + color-scheme: only dark; + } } [data-color-scheme="light"] { color-scheme: only light; + + & .nodes-container, + & .tree-toolbar, + & .dropdown-menu, + & .scaffold-content-navigation-drag, + & .scaffold-content-navigation-switcher, + & .alwan, + & .context-menu, + & .flatpickr-calendar, + & .dragging-tooltip { + color-scheme: only light; + } } // diff --git a/Build/Sources/TypeScript/backend/color-scheme-manager.ts b/Build/Sources/TypeScript/backend/color-scheme-manager.ts new file mode 100644 index 0000000000000000000000000000000000000000..13c0000673e1673dbec0297fb969e0afe0368489 --- /dev/null +++ b/Build/Sources/TypeScript/backend/color-scheme-manager.ts @@ -0,0 +1,39 @@ +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read theà + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +enum Identifier { + switch = 'typo3-backend-color-scheme-switch', +} + +class ColorSchemeManager { + constructor() { + document.addEventListener('typo3:color-scheme:update', this.onBroadcastSchemeUpdate.bind(this)); + } + + private onBroadcastSchemeUpdate(event: CustomEvent<{ name: string; payload: { name: string }}>) { + // The tab-local broadcast message is missing the "payload" object #93270 + const colorScheme = event.detail.payload?.name || event.detail.name; + + document.documentElement.setAttribute('data-color-scheme', colorScheme); + document.list_frame.document.documentElement.setAttribute('data-color-scheme', colorScheme); + + this.updateActiveScheme(colorScheme); + } + + private updateActiveScheme(colorScheme: string) { + const colorSchemeSwitch = document.querySelector(Identifier.switch); + colorSchemeSwitch.activeColorScheme = colorScheme; + } +} + +export default new ColorSchemeManager(); diff --git a/Build/Sources/TypeScript/backend/color-scheme-switch.ts b/Build/Sources/TypeScript/backend/color-scheme-switch.ts new file mode 100644 index 0000000000000000000000000000000000000000..52fe9d1ab3a8981f53ad005cf45042c8bb4204ea --- /dev/null +++ b/Build/Sources/TypeScript/backend/color-scheme-switch.ts @@ -0,0 +1,92 @@ +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read theà + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +import { html, LitElement, TemplateResult } from 'lit'; +import { customElement, property } from 'lit/decorators'; +import AjaxRequest from '@typo3/core/ajax/ajax-request'; +import { BroadcastMessage } from '@typo3/backend/broadcast-message'; +import BroadcastService from '@typo3/backend/broadcast-service'; +import '@typo3/backend/element/icon-element'; + +interface ColorScheme { + label: string, + icon: string, + value: string, +} + +@customElement('typo3-backend-color-scheme-switch') +export class ColorSchemeSwitchElement extends LitElement { + @property({ type: String }) activeColorScheme: string = null; + @property({ type: Array }) data: ColorScheme[] = null; + + protected createRenderRoot(): HTMLElement | ShadowRoot { + return this; + } + + protected render(): TemplateResult | symbol { + return html` + <ul class="dropdown-list"> + ${this.data.map(item => this.renderItem(item))} + </ul> + `; + } + + protected renderItem(colorScheme: ColorScheme): TemplateResult | symbol { + return html` + <li> + <button class="dropdown-item" @click="${() => this.handleClick(colorScheme.value)}" aria-current="${this.activeColorScheme === colorScheme.value ? 'true' : 'false'}"> + <span class="dropdown-item-columns"> + ${this.activeColorScheme === colorScheme.value ? html` + <span class="text-primary"> + <typo3-backend-icon identifier="actions-dot" size="small"></typo3-backend-icon> + </span> + ` : html` + <typo3-backend-icon identifier="empty-empty" size="small"></typo3-backend-icon> + `} + <span class="dropdown-item-column dropdown-item-column-icon" aria-hidden="true"> + <typo3-backend-icon identifier="${colorScheme.icon}" size="small"></typo3-backend-icon> + </span> + <span class="dropdown-item-column dropdown-item-column-title"> + ${colorScheme.label} + </span> + <slot></slot> + </span> + </button> + </li> + `; + } + + private async handleClick(value: string): Promise<void> { + this.broadcastSchemeUpdate(value); + await this.persistSchemeUpdate(value); + } + + private async persistSchemeUpdate(colorScheme: string) { + const url = new URL(TYPO3.settings.ajaxUrls.color_scheme_update, window.location.origin); + + return await (new AjaxRequest(url)).post({ colorScheme: colorScheme }); + } + + private broadcastSchemeUpdate(colorScheme: string): void { + const broadcastMessage = new BroadcastMessage('color-scheme', 'update', { name: colorScheme }); + + BroadcastService.post(broadcastMessage); + document.dispatchEvent(broadcastMessage.createCustomEvent('typo3')); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'typo3-backend-color-scheme-switch': ColorSchemeSwitchElement; + } +} diff --git a/typo3/sysext/backend/Classes/Backend/ColorScheme.php b/typo3/sysext/backend/Classes/Backend/ColorScheme.php new file mode 100644 index 0000000000000000000000000000000000000000..c8615e14e0fc78a985dd9ac39fcba42fa22bd4b7 --- /dev/null +++ b/typo3/sysext/backend/Classes/Backend/ColorScheme.php @@ -0,0 +1,52 @@ +<?php + +declare(strict_types=1); + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +namespace TYPO3\CMS\Backend\Backend; + +enum ColorScheme: string +{ + case auto = 'auto'; + case light = 'light'; + case dark = 'dark'; + + public function getLabel(): string + { + return match ($this) { + self::auto => 'LLL:EXT:backend/Resources/Private/Language/locallang.xlf:colorScheme.auto', + self::light => 'LLL:EXT:backend/Resources/Private/Language/locallang.xlf:colorScheme.light', + self::dark => 'LLL:EXT:backend/Resources/Private/Language/locallang.xlf:colorScheme.dark', + }; + } + + public function getIcon(): string + { + return match ($this) { + self::auto => 'actions-circle-half', + self::light => 'actions-brightness-high', + self::dark => 'actions-moon', + }; + } + + public static function getAvailableItemsForSelection(): array + { + return [ + self::auto->value => self::auto->getLabel(), + self::light->value => self::light->getLabel(), + self::dark->value => self::dark->getLabel(), + ]; + } +} diff --git a/typo3/sysext/backend/Classes/Backend/ToolbarItems/UserToolbarItem.php b/typo3/sysext/backend/Classes/Backend/ToolbarItems/UserToolbarItem.php index 547ce50442bccbd4e826a5b816d13684e6615278..381b5af080d56cfddb1da89c3860d3636a0fff73 100644 --- a/typo3/sysext/backend/Classes/Backend/ToolbarItems/UserToolbarItem.php +++ b/typo3/sysext/backend/Classes/Backend/ToolbarItems/UserToolbarItem.php @@ -18,6 +18,7 @@ declare(strict_types=1); namespace TYPO3\CMS\Backend\Backend\ToolbarItems; use Psr\Http\Message\ServerRequestInterface; +use TYPO3\CMS\Backend\Backend\ColorScheme; use TYPO3\CMS\Backend\Module\ModuleProvider; use TYPO3\CMS\Backend\Toolbar\RequestAwareToolbarItemInterface; use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface; @@ -25,6 +26,7 @@ use TYPO3\CMS\Backend\View\BackendViewFactory; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Database\Connection; use TYPO3\CMS\Core\Database\ConnectionPool; +use TYPO3\CMS\Core\Localization\LanguageService; use TYPO3\CMS\Core\Utility\GeneralUtility; /** @@ -115,6 +117,9 @@ class UserToolbarItem implements ToolbarItemInterface, RequestAwareToolbarItemIn 'modules' => $modules, 'switchUserMode' => $this->getBackendUser()->getOriginalUserIdWhenInSwitchUserMode() !== null, 'recentUsers' => $mostRecentUsers, + 'colorSchemeSwitchEnabled' => $this->getColorSchemeSwitchEnabled(), + 'activeColorScheme' => $backendUser->uc['colorScheme'] ?? 'auto', + 'colorSchemes' => $this->getColorSchemes(), ]); return $view->render('ToolbarItems/UserToolbarItemDropDown'); } @@ -153,4 +158,34 @@ class UserToolbarItem implements ToolbarItemInterface, RequestAwareToolbarItemIn { return $GLOBALS['BE_USER']; } + + protected function getLanguageService(): LanguageService + { + return $GLOBALS['LANG']; + } + + protected function getColorSchemeSwitchEnabled(): bool + { + $backendUser = $this->getBackendUser(); + $userTS = $backendUser->getTSConfig(); + + return !isset($userTS['setup.']['fields.']['colorScheme.']['disabled']) || $userTS['setup.']['fields.']['colorScheme.']['disabled'] !== '1'; + } + + protected function getColorSchemes(): array + { + $schemes = []; + + foreach (ColorScheme::cases() as $scheme) { + $schemeItem = [ + 'label' => $this->getLanguageService()->sL($scheme->getLabel()), + 'value' => $scheme->value, + 'icon' => $scheme->getIcon(), + ]; + + $schemes[] = $schemeItem; + } + + return $schemes; + } } diff --git a/typo3/sysext/backend/Classes/Controller/BackendController.php b/typo3/sysext/backend/Classes/Controller/BackendController.php index 40cba5a7c6727a69afa2fae8b726a67c76d2e0db..0eed75282d5f0f73d9f950cf3d6f24a44919f219 100644 --- a/typo3/sysext/backend/Classes/Controller/BackendController.php +++ b/typo3/sysext/backend/Classes/Controller/BackendController.php @@ -114,6 +114,9 @@ class BackendController $javaScriptRenderer->addJavaScriptModuleInstruction( JavaScriptModuleInstruction::create('@typo3/backend/hotkeys.js') ); + $javaScriptRenderer->addJavaScriptModuleInstruction( + JavaScriptModuleInstruction::create('@typo3/backend/color-scheme-manager.js') + ); // load the storage API and fill the UC into the PersistentStorage, so no additional AJAX call is needed $javaScriptRenderer->addJavaScriptModuleInstruction( JavaScriptModuleInstruction::create('@typo3/backend/storage/persistent.js') diff --git a/typo3/sysext/backend/Classes/Controller/ColorSchemeController.php b/typo3/sysext/backend/Classes/Controller/ColorSchemeController.php new file mode 100644 index 0000000000000000000000000000000000000000..90423d457841efa3cd1ad18ac1bf474927a2c716 --- /dev/null +++ b/typo3/sysext/backend/Classes/Controller/ColorSchemeController.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +namespace TYPO3\CMS\Backend\Controller; + +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use TYPO3\CMS\Backend\Attribute\AsController; +use TYPO3\CMS\Backend\Backend\ColorScheme; +use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; +use TYPO3\CMS\Core\Http\JsonResponse; +use TYPO3\CMS\Core\Http\Response; + +#[AsController] +class ColorSchemeController +{ + public function updateAction(ServerRequestInterface $request): ResponseInterface + { + $colorScheme = $request->getParsedBody()['colorScheme']; + + if ($request->getMethod() !== 'POST' || !ColorScheme::tryFrom($colorScheme)) { + return new JsonResponse(null, 400); + } + + $backendUser = $this->getBackendUser(); + $backendUser->uc['colorScheme'] = $colorScheme; + $backendUser->writeUC(); + + return new Response(null); + } + + protected function getBackendUser(): BackendUserAuthentication + { + return $GLOBALS['BE_USER']; + } +} diff --git a/typo3/sysext/backend/Configuration/Backend/AjaxRoutes.php b/typo3/sysext/backend/Configuration/Backend/AjaxRoutes.php index 9f48f395ced486dea732e11ddd15cd46c85601e1..de98e6986772385ebd45887dd6680e4a2d9e2903 100644 --- a/typo3/sysext/backend/Configuration/Backend/AjaxRoutes.php +++ b/typo3/sysext/backend/Configuration/Backend/AjaxRoutes.php @@ -413,4 +413,9 @@ return [ 'path' => '/code-editor/codecompletion/load-templates', 'target' => \TYPO3\CMS\Backend\Controller\CodeEditor\CodeCompletionController::class . '::loadCompletions', ], + + 'color_scheme_update' => [ + 'path' => '/color-scheme/update', + 'target' => Controller\ColorSchemeController::class . '::updateAction', + ], ]; diff --git a/typo3/sysext/backend/Resources/Private/Language/locallang.xlf b/typo3/sysext/backend/Resources/Private/Language/locallang.xlf index 8a209e9b9e9a4a3d8a7eed63ad6da42f453658ab..3b81975aa71dfeecb30518b9ff23ab4763ce8eb2 100644 --- a/typo3/sysext/backend/Resources/Private/Language/locallang.xlf +++ b/typo3/sysext/backend/Resources/Private/Language/locallang.xlf @@ -189,6 +189,18 @@ <trans-unit id="editdocument.moduleMenu.dropdown.label" resname="editdocument.moduleMenu.dropdown.label"> <source>Record language</source> </trans-unit> + <trans-unit id="colorScheme" resname="colorScheme"> + <source>Color scheme</source> + </trans-unit> + <trans-unit id="colorScheme.auto" resname="colorScheme.auto"> + <source>OS default</source> + </trans-unit> + <trans-unit id="colorScheme.light" resname="colorScheme.light"> + <source>Light</source> + </trans-unit> + <trans-unit id="colorScheme.dark" resname="colorScheme.dark"> + <source>Dark</source> + </trans-unit> </body> </file> </xliff> diff --git a/typo3/sysext/backend/Resources/Private/Templates/ToolbarItems/UserToolbarItemDropDown.html b/typo3/sysext/backend/Resources/Private/Templates/ToolbarItems/UserToolbarItemDropDown.html index 7b68f971897dd9cf020a6265a42f77a98f4369d2..806de8f69e5dd3959c61372e4690c8ed94572b4a 100644 --- a/typo3/sysext/backend/Resources/Private/Templates/ToolbarItems/UserToolbarItemDropDown.html +++ b/typo3/sysext/backend/Resources/Private/Templates/ToolbarItems/UserToolbarItemDropDown.html @@ -5,7 +5,8 @@ > <f:be.pageRenderer includeJavaScriptModules="{ - 0: '@typo3/backend/switch-user.js' + 0: '@typo3/backend/switch-user.js', + 1: '@typo3/backend/color-scheme-switch.js', }" /> <p class="h3 dropdown-headline">{f:translate(key: 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.user')}</p> @@ -58,6 +59,11 @@ </f:for> </ul> </f:if> +<f:if condition="{colorSchemeSwitchEnabled}"> + <hr class="dropdown-divider" aria-hidden="true"> + <p class="h4 dropdown-headline"><f:translate key="LLL:EXT:backend/Resources/Private/Language/locallang.xlf:colorScheme" /></p> + <typo3-backend-color-scheme-switch data="{colorSchemes -> f:format.json()}" activeColorScheme="{activeColorScheme}"></typo3-backend-color-scheme-switch> +</f:if> <hr class="dropdown-divider" aria-hidden="true"> <f:if condition="{switchUserMode}"> <f:then> diff --git a/typo3/sysext/backend/Resources/Public/Css/backend.css b/typo3/sysext/backend/Resources/Public/Css/backend.css index 19bdde0151abc7c4bd8af5c626cf694731eb8f77..191321c2020abec3e52f670ceeb3523e966f14fb 100644 --- a/typo3/sysext/backend/Resources/Public/Css/backend.css +++ b/typo3/sysext/backend/Resources/Public/Css/backend.css @@ -2378,7 +2378,9 @@ button[aria-expanded=true]:not(:disabled) .modulemenu-indicator:after{transform: :root{color-scheme:only light;scroll-behavior:smooth;--typo3-font-size:12px;--typo3-font-size-small:11px;--typo3-font-family-sans-serif:Verdana,Arial,Helvetica,sans-serif;--typo3-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;--typo3-font-family:var(--typo3-font-family-sans-serif);--typo3-font-family-code:var(--typo3-font-family-monospace);--typo3-spacing:1rem;--typo3-header-font-family:"Source Sans 3",sans-serif;--typo3-zindex-modal-backdrop:1050;--typo3-zindex-modal:1055;--typo3-text-color-base:light-dark(var(--token-color-neutral-90), var(--token-color-neutral-10));--typo3-text-color-link:var(--typo3-text-color-base);--typo3-text-color-variant:light-dark(var(--token-color-neutral-60), var(--token-color-neutral-30));--typo3-text-color-primary:light-dark(var(--token-color-blue-60), var(--token-color-blue-30));--typo3-text-color-secondary:light-dark(var(--token-color-neutral-70), var(--token-color-neutral-35));--typo3-text-color-info:light-dark(var(--token-color-teal-70), var(--token-color-teal-40));--typo3-text-color-success:light-dark(var(--token-color-green-70), var(--token-color-green-50));--typo3-text-color-warning:light-dark(var(--token-color-yellow-80), var(--token-color-yellow-40));--typo3-text-color-danger:light-dark(var(--token-color-red-60), var(--token-color-red-40));--typo3-text-color-code:light-dark(var(--token-color-magenta-60), var(--token-color-magenta-35));--typo3-text-color-notice:light-dark(var(--token-color-neutral-75), var(--token-color-neutral-40));--typo3-text-color-default:var(--typo3-text-color-base);--typo3-surface-dim:light-dark(var(--token-color-neutral-15), var(--token-color-neutral-96));--typo3-surface-base:light-dark(var(--token-color-neutral-4), var(--token-color-neutral-96));--typo3-surface-bright:light-dark(var(--token-color-neutral-4), var(--token-color-neutral-85));--typo3-surface-container-lowest:light-dark(var(--token-color-neutral-0), var(--token-color-neutral-100));--typo3-surface-container-low:light-dark(var(--token-color-neutral-3), var(--token-color-neutral-97));--typo3-surface-container-base:light-dark(var(--token-color-neutral-5), var(--token-color-neutral-95));--typo3-surface-container-high:light-dark(var(--token-color-neutral-10), var(--token-color-neutral-90));--typo3-surface-container-highest:light-dark(var(--token-color-neutral-15), var(--token-color-neutral-85));--typo3-surface-primary:light-dark(var(--token-color-blue-60), var(--token-color-blue-70));--typo3-surface-primary-text:light-dark(var(--token-color-neutral-0), var(--token-color-neutral-0));--typo3-surface-container-primary:light-dark(var(--token-color-blue-10), var(--token-color-blue-90));--typo3-surface-container-primary-text:light-dark(var(--token-color-blue-90), var(--token-color-blue-10));--typo3-surface-secondary:light-dark(var(--token-color-neutral-70), var(--token-color-neutral-70));--typo3-surface-secondary-text:light-dark(var(--token-color-neutral-0), var(--token-color-neutral-0));--typo3-surface-container-secondary:light-dark(var(--token-color-neutral-10), var(--token-color-neutral-90));--typo3-surface-container-secondary-text:light-dark(var(--token-color-neutral-90), var(--token-color-neutral-10));--typo3-surface-info:light-dark(var(--token-color-teal-20), var(--token-color-teal-70));--typo3-surface-info-text:light-dark(var(--token-color-neutral-90), var(--token-color-neutral-0));--typo3-surface-container-info:light-dark(var(--token-color-teal-10), var(--token-color-teal-90));--typo3-surface-container-info-text:light-dark(var(--token-color-teal-90), var(--token-color-teal-10));--typo3-surface-success:light-dark(var(--token-color-green-70), var(--token-color-green-80));--typo3-surface-success-text:light-dark(var(--token-color-neutral-0), var(--token-color-neutral-0));--typo3-surface-container-success:light-dark(var(--token-color-green-10), var(--token-color-green-90));--typo3-surface-container-success-text:light-dark(var(--token-color-green-90), var(--token-color-green-10));--typo3-surface-warning:light-dark(var(--token-color-yellow-40), var(--token-color-yellow-80));--typo3-surface-warning-text:light-dark(var(--token-color-neutral-90), var(--token-color-neutral-0));--typo3-surface-container-warning:light-dark(var(--token-color-yellow-10), var(--token-color-yellow-90));--typo3-surface-container-warning-text:light-dark(var(--token-color-yellow-90), var(--token-color-yellow-10));--typo3-surface-danger:light-dark(var(--token-color-red-50), var(--token-color-red-70));--typo3-surface-danger-text:light-dark(var(--token-color-neutral-0), var(--token-color-neutral-0));--typo3-surface-container-danger:light-dark(var(--token-color-red-10), var(--token-color-red-90));--typo3-surface-container-danger-text:light-dark(var(--token-color-red-90), var(--token-color-red-10));--typo3-surface-notice:light-dark(var(--token-color-neutral-75), var(--token-color-neutral-85));--typo3-surface-notice-text:light-dark(var(--token-color-neutral-0), var(--token-color-neutral-0));--typo3-surface-container-notice:light-dark(var(--token-color-neutral-10), var(--token-color-neutral-90));--typo3-surface-container-notice-text:light-dark(var(--token-color-neutral-95), var(--token-color-neutral-0));--typo3-surface-default:light-dark(var(--token-color-neutral-5), var(--token-color-neutral-95));--typo3-surface-default-text:light-dark(var(--token-color-neutral-90), var(--token-color-neutral-0));--typo3-surface-container-default:light-dark(var(--token-color-neutral-5), var(--token-color-neutral-95));--typo3-surface-container-default-text:light-dark(var(--token-color-neutral-90), var(--token-color-neutral-0));--typo3-state-default-color:light-dark(var(--token-color-neutral-90), var(--token-color-neutral-0));--typo3-state-default-bg:light-dark(var(--token-color-neutral-5), var(--token-color-neutral-90));--typo3-state-default-border-color:light-dark(var(--token-color-neutral-25), var(--token-color-neutral-80));--typo3-state-default-hover-color:var(--typo3-state-default-color);--typo3-state-default-hover-bg:light-dark(var(--token-color-neutral-10), var(--token-color-neutral-85));--typo3-state-default-hover-border-color:light-dark(var(--token-color-neutral-35), var(--token-color-neutral-75));--typo3-state-default-focus-color:var(--typo3-state-default-color);--typo3-state-default-focus-bg:light-dark(var(--token-color-neutral-15), var(--token-color-neutral-80));--typo3-state-default-focus-border-color:light-dark(var(--token-color-neutral-40), var(--token-color-neutral-70));--typo3-state-default-disabled-color:var(--typo3-state-default-color);--typo3-state-default-disabled-bg:var(--typo3-state-default-bg);--typo3-state-default-disabled-border-color:var(--typo3-state-default-border-color);--typo3-state-primary-color:light-dark(var(--token-color-neutral-0), var(--token-color-neutral-0));--typo3-state-primary-bg:light-dark(var(--token-color-blue-60), var(--token-color-blue-70));--typo3-state-primary-border-color:light-dark(var(--token-color-blue-65), var(--token-color-blue-65));--typo3-state-primary-hover-color:var(--typo3-state-primary-color);--typo3-state-primary-hover-bg:light-dark(var(--token-color-blue-65), var(--token-color-blue-65));--typo3-state-primary-hover-border-color:light-dark(var(--token-color-blue-70), var(--token-color-blue-60));--typo3-state-primary-focus-color:var(--typo3-state-primary-color);--typo3-state-primary-focus-bg:light-dark(var(--token-color-blue-70), var(--token-color-blue-60));--typo3-state-primary-focus-border-color:light-dark(var(--token-color-blue-75), var(--token-color-blue-55));--typo3-state-primary-disabled-color:var(--typo3-state-primary-color);--typo3-state-primary-disabled-bg:var(--typo3-state-primary-bg);--typo3-state-primary-disabled-border-color:var(--typo3-state-default-primary-color);--typo3-state-secondary-color:light-dark(var(--token-color-neutral-0), var(--token-color-neutral-0));--typo3-state-secondary-bg:light-dark(var(--token-color-neutral-70), var(--token-color-neutral-70));--typo3-state-secondary-border-color:light-dark(var(--token-color-neutral-75), var(--token-color-neutral-65));--typo3-state-secondary-hover-color:var(--typo3-state-secondary-color);--typo3-state-secondary-hover-bg:light-dark(var(--token-color-neutral-75), var(--token-color-neutral-65));--typo3-state-secondary-hover-border-color:light-dark(var(--token-color-neutral-80), var(--token-color-neutral-60));--typo3-state-secondary-focus-color:var(--typo3-state-secondary-color);--typo3-state-secondary-focus-bg:light-dark(var(--token-color-neutral-80), var(--token-color-neutral-60));--typo3-state-secondary-focus-border-color:light-dark(var(--token-color-neutral-85), var(--token-color-neutral-55));--typo3-state-secondary-disabled-color:var(--typo3-state-secondary-color);--typo3-state-secondary-disabled-bg:var(--typo3-state-secondary-bg);--typo3-state-secondary-disabled-border-color:var(--typo3-state-default-secondary-color);--typo3-state-success-color:light-dark(var(--token-color-neutral-0), var(--token-color-neutral-0));--typo3-state-success-bg:light-dark(var(--token-color-green-70), var(--token-color-green-80));--typo3-state-success-border-color:light-dark(var(--token-color-green-75), var(--token-color-green-75));--typo3-state-success-hover-color:var(--typo3-state-success-color);--typo3-state-success-hover-bg:light-dark(var(--token-color-green-75), var(--token-color-green-75));--typo3-state-success-hover-border-color:light-dark(var(--token-color-green-80), var(--token-color-green-70));--typo3-state-success-focus-color:var(--typo3-state-success-color);--typo3-state-success-focus-bg:light-dark(var(--token-color-green-80), var(--token-color-green-70));--typo3-state-success-focus-border-color:light-dark(var(--token-color-green-85), var(--token-color-green-65));--typo3-state-success-disabled-color:var(--typo3-state-success-color);--typo3-state-success-disabled-bg:var(--typo3-state-success-bg);--typo3-state-success-disabled-border-color:var(--typo3-state-default-success-color);--typo3-state-warning-color:light-dark(var(--token-color-neutral-90), var(--token-color-neutral-0));--typo3-state-warning-bg:light-dark(var(--token-color-yellow-40), var(--token-color-yellow-80));--typo3-state-warning-border-color:light-dark(var(--token-color-yellow-45), var(--token-color-yellow-75));--typo3-state-warning-hover-color:var(--typo3-state-warning-color);--typo3-state-warning-hover-bg:light-dark(var(--token-color-yellow-45), var(--token-color-yellow-75));--typo3-state-warning-hover-border-color:light-dark(var(--token-color-yellow-50), var(--token-color-yellow-70));--typo3-state-warning-focus-color:var(--typo3-state-warning-color);--typo3-state-warning-focus-bg:light-dark(var(--token-color-yellow-50), var(--token-color-yellow-70));--typo3-state-warning-focus-border-color:light-dark(var(--token-color-yellow-55), var(--token-color-yellow-65));--typo3-state-warning-disabled-color:var(--typo3-state-warning-color);--typo3-state-warning-disabled-bg:var(--typo3-state-warning-bg);--typo3-state-warning-disabled-border-color:var(--typo3-state-warning-border-color);--typo3-state-danger-color:light-dark(var(--token-color-neutral-0), var(--token-color-neutral-0));--typo3-state-danger-bg:light-dark(var(--token-color-red-50), var(--token-color-red-70));--typo3-state-danger-border-color:light-dark(var(--token-color-red-55), var(--token-color-red-65));--typo3-state-danger-hover-color:var(--typo3-state-danger-color);--typo3-state-danger-hover-bg:light-dark(var(--token-color-red-55), var(--token-color-red-65));--typo3-state-danger-hover-border-color:light-dark(var(--token-color-red-60), var(--token-color-red-60));--typo3-state-danger-focus-color:var(--typo3-state-danger-color);--typo3-state-danger-focus-bg:light-dark(var(--token-color-red-60), var(--token-color-red-60));--typo3-state-danger-focus-border-color:light-dark(var(--token-color-red-65), var(--token-color-red-55));--typo3-state-danger-disabled-color:var(--typo3-state-danger-color);--typo3-state-danger-disabled-bg:var(--typo3-state-danger-bg);--typo3-state-danger-disabled-border-color:var(--typo3-state-danger-border-color);--typo3-state-info-color:light-dark(var(--token-color-neutral-90), var(--token-color-neutral-0));--typo3-state-info-bg:light-dark(var(--token-color-teal-20), var(--token-color-teal-70));--typo3-state-info-border-color:light-dark(var(--token-color-teal-25), var(--token-color-teal-65));--typo3-state-info-hover-color:var(--typo3-state-info-color);--typo3-state-info-hover-bg:light-dark(var(--token-color-teal-25), var(--token-color-teal-65));--typo3-state-info-hover-border-color:light-dark(var(--token-color-teal-30), var(--token-color-teal-60));--typo3-state-info-focus-color:var(--typo3-state-info-color);--typo3-state-info-focus-bg:light-dark(var(--token-color-teal-30), var(--token-color-teal-60));--typo3-state-info-focus-border-color:light-dark(var(--token-color-teal-35), var(--token-color-teal-55));--typo3-state-info-disabled-color:var(--typo3-state-info-color);--typo3-state-info-disabled-bg:var(--typo3-state-info-bg);--typo3-state-info-disabled-border-color:var(--typo3-state-info-border-color);--typo3-state-notice-color:light-dark(var(--token-color-neutral-0), var(--token-color-neutral-0));--typo3-state-notice-bg:light-dark(var(--token-color-neutral-75), var(--token-color-neutral-85));--typo3-state-notice-border-color:light-dark(var(--token-color-neutral-80), var(--token-color-neutral-80));--typo3-state-notice-hover-color:var(--typo3-state-notice-color);--typo3-state-notice-hover-bg:light-dark(var(--token-color-neutral-80), var(--token-color-neutral-80));--typo3-state-notice-hover-border-color:light-dark(var(--token-color-neutral-85), var(--token-color-neutral-75));--typo3-state-notice-focus-color:var(--typo3-state-notice-color);--typo3-state-notice-focus-bg:light-dark(var(--token-color-neutral-85), var(--token-color-neutral-75));--typo3-state-notice-focus-border-color:light-dark(var(--token-color-neutral-90), var(--token-color-neutral-70));--typo3-state-notice-disabled-color:var(--typo3-state-notice-color);--typo3-state-notice-disabled-bg:var(--typo3-state-notice-bg);--typo3-state-notice-disabled-border-color:var(--typo3-state-notice-border-color);--typo3-shadow-2:0 1px 2px light-dark(rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0.2)),0 1px 2px light-dark(rgba(0, 0, 0, 0.14), rgba(0, 0, 0, 0.28));--typo3-shadow-4:0 2px 4px light-dark(rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0.2)),0 2px 4px light-dark(rgba(0, 0, 0, 0.14), rgba(0, 0, 0, 0.28));--typo3-shadow-8:0 4px 8px light-dark(rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0.2)),0 4px 8px light-dark(rgba(0, 0, 0, 0.14), rgba(0, 0, 0, 0.28));--typo3-shadow-16:0 8px 16px light-dark(rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0.2)),0 8px 16px light-dark(rgba(0, 0, 0, 0.14), rgba(0, 0, 0, 0.28));--typo3-shadow-28:0 14px 28px light-dark(rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0.2)),0 14px 28px light-dark(rgba(0, 0, 0, 0.14), rgba(0, 0, 0, 0.28));--typo3-shadow-64:0 0 4px light-dark(rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0.2)),0 32px 64px light-dark(rgba(0, 0, 0, 0.14), rgba(0, 0, 0, 0.28));--typo3-component-color:var(--typo3-text-color-base);--typo3-component-variant-color:var(--typo3-text-color-variant);--typo3-component-primary-color:var(--typo3-text-color-primary);--typo3-component-secondary-color:var(--typo3-text-color-secondary);--typo3-component-match-highlight-color:inherit;--typo3-component-match-highlight-bg:rgba(234, 92, 0, .33);--typo3-component-bg:var(--typo3-surface-container-lowest);--typo3-component-link-color:light-dark(#05c, #6699e0);--typo3-component-link-hover-color:light-dark(#1a66d1, #80aae6);--typo3-component-font-size:0.75rem;--typo3-component-line-height:1.5;--typo3-component-border-radius:4px;--typo3-component-border-width:1px;--typo3-component-border-color:light-dark(rgb(215, 215, 215), rgb(51, 51, 51));--typo3-component-padding-y:.75rem;--typo3-component-padding-x:1rem;--typo3-component-box-shadow:var(--typo3-shadow-2);--typo3-component-box-shadow-strong:var(--typo3-shadow-4);--typo3-component-box-shadow-tooltip:var(--typo3-shadow-8);--typo3-component-box-shadow-flyout:var(--typo3-shadow-16);--typo3-component-box-shadow-dialog:var(--typo3-shadow-28);--typo3-component-box-shadow-window:var(--typo3-shadow-64);--typo3-component-hover-color:var(--typo3-component-color);--typo3-component-hover-bg:light-dark(#f2f7fc, rgb(51, 51, 51));--typo3-component-hover-border-color:light-dark(#d9e6f7, rgb(90, 90, 90));--typo3-component-focus-color:var(--typo3-component-color);--typo3-component-focus-bg:light-dark(#f2f7fc, #002b66);--typo3-component-focus-border-color:light-dark(#3377d6, #00337a);--typo3-component-active-color:#fff;--typo3-component-active-bg:light-dark(#3377d6, #0048ad);--typo3-component-active-border-color:light-dark(#3377d6, #0044a3);--typo3-component-disabled-color:rgb(115, 115, 115);--typo3-component-disabled-bg:transparent;--typo3-component-disabled-border-color:transparent;--typo3-component-spacing:2rem;--typo3-list-item-padding-y:.5rem;--typo3-list-item-padding-x:.75rem;--typo3-list-item-hover-color:var(--typo3-component-hover-color);--typo3-list-item-hover-bg:var(--typo3-component-hover-bg);--typo3-list-item-hover-border-color:var(--typo3-component-hover-border-color);--typo3-list-item-focus-color:var(--typo3-component-focus-color);--typo3-list-item-focus-bg:var(--typo3-component-focus-bg);--typo3-list-item-focus-border-color:var(--typo3-component-focus-border-color);--typo3-list-item-active-color:var(--typo3-list-item-focus-color);--typo3-list-item-active-bg:var(--typo3-list-item-focus-bg);--typo3-list-item-active-border-color:var(--typo3-list-item-focus-border-color);--typo3-list-item-disabled-color:var(--typo3-component-disabled-color);--typo3-list-item-disabled-bg:var(--typo3-component-disabled-bg);--typo3-list-item-disabled-border-color:var(--typo3-component-disabled-border-color);--typo3-legend-font-weight:600;--typo3-input-font-size:.75rem;--typo3-input-line-height:1.5;--typo3-input-padding-y:.5rem;--typo3-input-padding-x:.75rem;--typo3-input-sm-padding-y:.3125rem;--typo3-input-sm-padding-x:.5rem;--typo3-input-sm-font-size:.6875rem;--typo3-input-border-width:1px;--typo3-input-border-radius:var(--typo3-component-border-radius);--typo3-input-color:var(--typo3-text-color-base);--typo3-input-placeholder-color:color-mix(in srgb, var(--typo3-input-color), transparent 30%);--typo3-input-bg:var(--typo3-surface-container-lowest);--typo3-input-group-addon-bg:color-mix(in srgb, var(--typo3-input-bg), var(--typo3-input-color) 10%);--typo3-input-border-color:var(--typo3-state-default-border-color);--typo3-input-hover-color:var(--typo3-input-color);--typo3-input-hover-bg:var(--typo3-input-bg);--typo3-input-hover-border-color:var(--typo3-state-default-hover-border-color);--typo3-input-focus-color:var(--typo3-input-color);--typo3-input-focus-bg:var(--typo3-input-bg);--typo3-input-focus-border-color:var(--typo3-state-primary-focus-border-color);--typo3-input-active-color:var(--typo3-state-primary-color);--typo3-input-active-bg:var(--typo3-state-primary-bg);--typo3-input-active-border-color:var(--typo3-state-primary-focus-border-color);--typo3-input-disabled-color:var(--typo3-state-default-disabled-color);--typo3-input-disabled-bg:var(--typo3-state-default-disabled-bg);--typo3-input-disabled-border-color:var(--typo3-state-default-disabled-border-color);--typo3-input-disabled-opacity:.65} [data-color-scheme=auto]{color-scheme:light dark} [data-color-scheme=dark]{color-scheme:only dark} +[data-color-scheme=dark] .alwan,[data-color-scheme=dark] .context-menu,[data-color-scheme=dark] .dragging-tooltip,[data-color-scheme=dark] .dropdown-menu,[data-color-scheme=dark] .flatpickr-calendar,[data-color-scheme=dark] .nodes-container,[data-color-scheme=dark] .scaffold-content-navigation-drag,[data-color-scheme=dark] .scaffold-content-navigation-switcher,[data-color-scheme=dark] .tree-toolbar{color-scheme:only dark} [data-color-scheme=light]{color-scheme:only light} +[data-color-scheme=light] .alwan,[data-color-scheme=light] .context-menu,[data-color-scheme=light] .dragging-tooltip,[data-color-scheme=light] .dropdown-menu,[data-color-scheme=light] .flatpickr-calendar,[data-color-scheme=light] .nodes-container,[data-color-scheme=light] .scaffold-content-navigation-drag,[data-color-scheme=light] .scaffold-content-navigation-switcher,[data-color-scheme=light] .tree-toolbar{color-scheme:only light} :root{--typo3-position-modifier:1;--typo3-position-start:left;--typo3-position-end:right} [dir=rtl]{--typo3-position-modifier:-1;--typo3-position-start:right;--typo3-position-end:left} .dropdown-menu{--bs-secondary-color:var(--typo3-component-secondary-color)} diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/color-scheme-manager.js b/typo3/sysext/backend/Resources/Public/JavaScript/color-scheme-manager.js new file mode 100644 index 0000000000000000000000000000000000000000..2d4eb66a7db71054b6eba19761cb51398f705552 --- /dev/null +++ b/typo3/sysext/backend/Resources/Public/JavaScript/color-scheme-manager.js @@ -0,0 +1,13 @@ +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ +var Identifier;!function(e){e.switch="typo3-backend-color-scheme-switch"}(Identifier||(Identifier={}));class ColorSchemeManager{constructor(){document.addEventListener("typo3:color-scheme:update",this.onBroadcastSchemeUpdate.bind(this))}onBroadcastSchemeUpdate(e){const t=e.detail.payload?.name||e.detail.name;document.documentElement.setAttribute("data-color-scheme",t),document.list_frame.document.documentElement.setAttribute("data-color-scheme",t),this.updateActiveScheme(t)}updateActiveScheme(e){document.querySelector(Identifier.switch).activeColorScheme=e}}export default new ColorSchemeManager; \ No newline at end of file diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/color-scheme-switch.js b/typo3/sysext/backend/Resources/Public/JavaScript/color-scheme-switch.js new file mode 100644 index 0000000000000000000000000000000000000000..db06969cdcb08d2ab02832cd54ca63f7f318410f --- /dev/null +++ b/typo3/sysext/backend/Resources/Public/JavaScript/color-scheme-switch.js @@ -0,0 +1,38 @@ +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ +var __decorate=function(e,t,o,r){var c,a=arguments.length,n=a<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,o):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(e,t,o,r);else for(var i=e.length-1;i>=0;i--)(c=e[i])&&(n=(a<3?c(n):a>3?c(t,o,n):c(t,o))||n);return a>3&&n&&Object.defineProperty(t,o,n),n};import{html,LitElement}from"lit";import{customElement,property}from"lit/decorators.js";import AjaxRequest from"@typo3/core/ajax/ajax-request.js";import{BroadcastMessage}from"@typo3/backend/broadcast-message.js";import BroadcastService from"@typo3/backend/broadcast-service.js";import"@typo3/backend/element/icon-element.js";let ColorSchemeSwitchElement=class extends LitElement{constructor(){super(...arguments),this.activeColorScheme=null,this.data=null}createRenderRoot(){return this}render(){return html` + <ul class="dropdown-list"> + ${this.data.map((e=>this.renderItem(e)))} + </ul> + `}renderItem(e){return html` + <li> + <button class="dropdown-item" @click="${()=>this.handleClick(e.value)}" aria-current="${this.activeColorScheme===e.value?"true":"false"}"> + <span class="dropdown-item-columns"> + ${this.activeColorScheme===e.value?html` + <span class="text-primary"> + <typo3-backend-icon identifier="actions-dot" size="small"></typo3-backend-icon> + </span> + `:html` + <typo3-backend-icon identifier="empty-empty" size="small"></typo3-backend-icon> + `} + <span class="dropdown-item-column dropdown-item-column-icon" aria-hidden="true"> + <typo3-backend-icon identifier="${e.icon}" size="small"></typo3-backend-icon> + </span> + <span class="dropdown-item-column dropdown-item-column-title"> + ${e.label} + </span> + <slot></slot> + </span> + </button> + </li> + `}async handleClick(e){this.broadcastSchemeUpdate(e),await this.persistSchemeUpdate(e)}async persistSchemeUpdate(e){const t=new URL(TYPO3.settings.ajaxUrls.color_scheme_update,window.location.origin);return await new AjaxRequest(t).post({colorScheme:e})}broadcastSchemeUpdate(e){const t=new BroadcastMessage("color-scheme","update",{name:e});BroadcastService.post(t),document.dispatchEvent(t.createCustomEvent("typo3"))}};__decorate([property({type:String})],ColorSchemeSwitchElement.prototype,"activeColorScheme",void 0),__decorate([property({type:Array})],ColorSchemeSwitchElement.prototype,"data",void 0),ColorSchemeSwitchElement=__decorate([customElement("typo3-backend-color-scheme-switch")],ColorSchemeSwitchElement);export{ColorSchemeSwitchElement}; \ No newline at end of file diff --git a/typo3/sysext/core/Classes/Page/PageRenderer.php b/typo3/sysext/core/Classes/Page/PageRenderer.php index 1ec6c332429473e0ab0f11197ff5290fd31e71e5..55890b91badbf1c7315d2e4bf528f144a7e3dcca 100644 --- a/typo3/sysext/core/Classes/Page/PageRenderer.php +++ b/typo3/sysext/core/Classes/Page/PageRenderer.php @@ -283,6 +283,14 @@ class PageRenderer implements SingletonInterface if ($this->locale->isRightToLeftLanguageDirection()) { $attributes['dir'] = 'rtl'; } + // TODO: build an API to add HTML attributes cleanly + if ($this->getApplicationType() === 'BE' && !empty($GLOBALS['BE_USER'])) { + $userTS = $GLOBALS['BE_USER']->getTSConfig(); + + if (!isset($userTS['setup.']['fields.']['colorScheme.']['disabled']) || $userTS['setup.']['fields.']['colorScheme.']['disabled'] !== '1') { + $attributes['data-color-scheme'] = $GLOBALS['BE_USER']->uc['colorScheme'] ?? 'auto'; + } + } $this->setHtmlTag('<html ' . GeneralUtility::implodeAttributes($attributes, true) . '>'); } } diff --git a/typo3/sysext/core/Documentation/Changelog/13.3/Feature-104868-AddColorSchemeSwitching.rst b/typo3/sysext/core/Documentation/Changelog/13.3/Feature-104868-AddColorSchemeSwitching.rst new file mode 100644 index 0000000000000000000000000000000000000000..5587805ac15b3006975c65ad1e44c918ea8f41fa --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/13.3/Feature-104868-AddColorSchemeSwitching.rst @@ -0,0 +1,25 @@ +.. include:: /Includes.rst.txt + +.. _feature-104868-1725912804: + +============================================= +Feature: #104868 - Add color scheme switching +============================================= + +See :issue:`104868` + +Description +=========== + +Options have been added to switch between the available color schemes in TYPO3. A set of buttons +for each available color scheme in the user dropdown at the top right and a setting in User Settings. + +As the dark color scheme is currently regarded experimental until further notice, color scheme switching logic is +currently hidden behind the UserTS setting :typoscript:`setup.fields.colorScheme.disabled`. + +Impact +====== + +It is now possible to switch to an automatic, light or dark color scheme for use in the backend. + +.. index:: Backend, ext:backend diff --git a/typo3/sysext/install/Classes/Controller/AbstractController.php b/typo3/sysext/install/Classes/Controller/AbstractController.php index 03a06ea81561c74fe37538df4c470e6413dd19e3..8e1ef6580171e74b85c87b6090e9c26074bd6bb8 100644 --- a/typo3/sysext/install/Classes/Controller/AbstractController.php +++ b/typo3/sysext/install/Classes/Controller/AbstractController.php @@ -51,6 +51,7 @@ class AbstractController 'context' => $request->getQueryParams()['install']['context'] ?? '', 'composerMode' => Environment::isComposerMode(), 'currentTypo3Version' => (string)(new Typo3Version()), + 'colorScheme' => $request->getQueryParams()['install']['colorScheme'] ?? '', ]); return $view; } diff --git a/typo3/sysext/install/Classes/Controller/BackendModuleController.php b/typo3/sysext/install/Classes/Controller/BackendModuleController.php index 1dfaf382cfc00b27ab03ed34298448b91850a937..2719148bd85d7367b04a21dc360ee5b1270fd2d8 100644 --- a/typo3/sysext/install/Classes/Controller/BackendModuleController.php +++ b/typo3/sysext/install/Classes/Controller/BackendModuleController.php @@ -87,7 +87,7 @@ class BackendModuleController $this->sessionService->startSession(); $this->sessionService->setAuthorizedBackendSession($userSession); $entryPointResolver = GeneralUtility::makeInstance(BackendEntryPointResolver::class); - $redirectLocation = $entryPointResolver->getUriFromRequest($request, 'install.php')->withQuery('?install[controller]=' . $controller . '&install[context]=backend'); + $redirectLocation = $entryPointResolver->getUriFromRequest($request, 'install.php')->withQuery('?install[controller]=' . $controller . '&install[context]=backend' . '&install[colorScheme]=' . ($this->getBackendUser()->uc['colorScheme'] ?? '')); return new RedirectResponse($redirectLocation, 303); } diff --git a/typo3/sysext/install/Resources/Private/Templates/Layout/Init.html b/typo3/sysext/install/Resources/Private/Templates/Layout/Init.html index 59d9afac3ef24bfaf9f91465c8593330c603e6fd..adabff7868f3a94ae5d64126fa1bff7146564495 100644 --- a/typo3/sysext/install/Resources/Private/Templates/Layout/Init.html +++ b/typo3/sysext/install/Resources/Private/Templates/Layout/Init.html @@ -1,5 +1,5 @@ <!DOCTYPE html> -<html lang="en"> +<html lang="en" {f:if(condition: colorScheme, then: 'data-color-scheme="{colorScheme}"')}> <head> <title>Install Tool on site {siteName}</title> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> diff --git a/typo3/sysext/setup/Configuration/user.tsconfig b/typo3/sysext/setup/Configuration/user.tsconfig new file mode 100644 index 0000000000000000000000000000000000000000..9ea482816db459fe412aa07087926cf567496d6a --- /dev/null +++ b/typo3/sysext/setup/Configuration/user.tsconfig @@ -0,0 +1 @@ +setup.fields.colorScheme.disabled = 1 diff --git a/typo3/sysext/setup/ext_tables.php b/typo3/sysext/setup/ext_tables.php index 2a7b637428485133f2ae8362a17506b0131e778a..981384387f39032c113b217eb3c11110cc013342 100644 --- a/typo3/sysext/setup/ext_tables.php +++ b/typo3/sysext/setup/ext_tables.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use TYPO3\CMS\Backend\Backend\ColorScheme; use TYPO3\CMS\Setup\Controller\SetupModuleController; defined('TYPO3') or die(); @@ -94,10 +95,15 @@ $GLOBALS['TYPO3_USER_SETTINGS'] = [ 'sitenameFirst' => 'LLL:EXT:setup/Resources/Private/Language/locallang.xlf:backendTitleFormat.sitenameFirst', ], ], + 'colorScheme' => [ + 'type' => 'select', + 'label' => 'LLL:EXT:backend/Resources/Private/Language/locallang.xlf:colorScheme', + 'items' => ColorScheme::getAvailableItemsForSelection(), + ], ], 'showitem' => '--div--;LLL:EXT:setup/Resources/Private/Language/locallang.xlf:personal_data,realName,email,emailMeAtLogin,avatar,lang, --div--;LLL:EXT:setup/Resources/Private/Language/locallang.xlf:accountSecurity,passwordCurrent,password,password2,mfaProviders, - --div--;LLL:EXT:setup/Resources/Private/Language/locallang.xlf:opening,startModule,backendTitleFormat, + --div--;LLL:EXT:setup/Resources/Private/Language/locallang.xlf:opening,colorScheme,startModule,backendTitleFormat, --div--;LLL:EXT:setup/Resources/Private/Language/locallang.xlf:editFunctionsTab,titleLen,edit_docModuleUpload,showHiddenFilesAndFolders,copyLevels, --div--;LLL:EXT:setup/Resources/Private/Language/locallang.xlf:resetTab,resetConfiguration', ];