Add support for color scheme detection
authorAlexander Ebert <ebert@woltlab.com>
Thu, 10 Aug 2023 13:07:20 +0000 (15:07 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Thu, 10 Aug 2023 13:07:20 +0000 (15:07 +0200)
com.woltlab.wcf/templates/headIncludeJavaScript.tpl
ts/WoltLabSuite/Core/Bootstrap.ts
ts/WoltLabSuite/Core/Controller/Style/ColorScheme.ts
wcfsetup/install/files/acp/templates/header.tpl
wcfsetup/install/files/js/WoltLabSuite/Core/Bootstrap.js
wcfsetup/install/files/js/WoltLabSuite/Core/Controller/Style/ColorScheme.js
wcfsetup/install/files/lib/system/style/StyleHandler.class.php

index 1c3a5b74f28e7aa683d4b66edb5983d70e2e12f7..fd8a12e10800a263aa6d085eb1ff1705001c4f61 100644 (file)
                var COMPILER_TARGET_DEFAULT = {if !VISITOR_USE_TINY_BUILD || $__wcf->user->userID}true{else}false{/if};
        {/if}
 
-       {if $__wcf->getStyleHandler()->getStyle()->hasDarkMode}
+       {if $__wcf->getStyleHandler()->getColorScheme() === 'system'}
        {
-               let colorScheme = matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
-               try {
-                       const value = localStorage.getItem("wsc_colorScheme");
-                       if (value === "light" || value === "dark") {
-                               colorScheme = value;
-                       }
-               } catch {}
-
+               const colorScheme = matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
                document.documentElement.dataset.colorScheme = colorScheme;
        }
        {/if}
index fde7b576e673de3df7e007a3e2f6738b42009133..13a57e954ad844a04b82f496e0209e8d1498a997 100644 (file)
@@ -32,6 +32,7 @@ import { init as initSearch } from "./Ui/Search";
 import { PageMenuMainProvider } from "./Ui/Page/Menu/Main/Provider";
 import { whenFirstSeen } from "./LazyLoader";
 import { adoptPageOverlayContainer } from "./Helper/PageOverlay";
+import User from "./User"
 
 import type { ColorScheme } from "./Controller/Style/ColorScheme";
 
@@ -150,8 +151,8 @@ export function setup(options: BoostrapOptions): void {
 
   DomChangeListener.add("WoltLabSuite/Core/Bootstrap", () => initA11y);
 
-  if (options.colorScheme === "system") {
-    void import("./Controller/Style/ColorScheme").then(({ setup }) => setup());
+  if (options.colorScheme === "system" && User.userId) {
+    void import("./Controller/Style/ColorScheme").then(({ setup }) => setup(options.colorScheme));
   }
 
   whenFirstSeen("[data-report-content]", () => {
index 327a72ef8b63813993ec3deda1eb0f3a69e991f9..256fc5635c4d329284536a182605d815dd402c9b 100644 (file)
@@ -5,6 +5,7 @@
  * @copyright 2001-2023 WoltLab GmbH
  * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @since 6.0
+ * @woltlabExcludeBundle tiny
  */
 
 import { getPhrase } from "WoltLabSuite/Core/Language";
@@ -26,12 +27,6 @@ function setScheme(scheme: ColorScheme): void {
   } else {
     applySystemScheme();
   }
-
-  try {
-    localStorage.setItem("wsc_colorScheme", currentScheme);
-  } catch {
-    /* Ignore any errors when accessing the `localStorage`. */
-  }
 }
 
 function applySystemScheme(): void {
@@ -81,21 +76,13 @@ function initializeButton(button: HTMLElement): void {
   });
 }
 
-export function setup(): void {
+export function setup(colorScheme: ColorScheme): void {
   const button = document.querySelector<HTMLElement>(".jsButtonStyleColorScheme");
   if (button) {
-    initializeButton(button);
-  }
-
-  try {
-    const value = localStorage.getItem("wsc_colorScheme");
-    if (value === "light" || value === "dark") {
-      currentScheme = value;
-    }
-  } catch {
-    /* Ignore any errors when accessing the `localStorage`. */
+    //initializeButton(button);
   }
 
+  currentScheme = colorScheme;
   themeColor = document.querySelector('meta[name="theme-color"]')!;
 
   mediaQuery = matchMedia("(prefers-color-scheme: dark)");
index 5f2b21a1618dac38b9ec0cf9f1344f63a31731d0..4240ffe6c0245c9caaf8cc0ef901d6644ac553e8 100644 (file)
@@ -2,7 +2,7 @@
 <html
        dir="{@$__wcf->getLanguage()->getPageDirection()}"
        lang="{$__wcf->getLanguage()->getBcp47()}"
-       data-color-scheme="system"
+       data-color-scheme="{$__wcf->getStyleHandler()->getColorScheme()}"
 >
 <head>
        <meta charset="utf-8">
                {* Unlike the frontend, this option must be defined in the ACP at all times. *}
                var COMPILER_TARGET_DEFAULT = true;
 
+               {if $__wcf->getStyleHandler()->getColorScheme() === 'system'}
                {
-                       let colorScheme = matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
-                       try {
-                               const value = localStorage.getItem("wsc_colorScheme");
-                               if (value === "light" || value === "dark") {
-                                       colorScheme = value;
-                               }
-                       } catch {}
-
+                       const colorScheme = matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
                        document.documentElement.dataset.colorScheme = colorScheme;
                }
+               {/if}
        </script>
 
        <script data-eager="true" src="{$__wcf->getPath()}js/WoltLabSuite/WebComponent.js?v={@LAST_UPDATE_TIME}"></script>
@@ -99,7 +94,8 @@
                        
                        AcpBootstrap.setup({
                                bootstrap: {
-                                       enableMobileMenu: {if PACKAGE_ID && $__isLogin|empty}true{else}false{/if}
+                                       colorScheme: '{@$__wcf->getStyleHandler()->getColorScheme()|encodeJS}',
+                                       enableMobileMenu: {if PACKAGE_ID && $__isLogin|empty}true{else}false{/if},
                                }
                        });
                });
index 80f608319c7b3a6b05a5f8c9d7afa01ad473bb9b..80333d98ef43761b60eb36c8391c00d56329cc28 100644 (file)
@@ -7,7 +7,7 @@
  * @copyright  2001-2022 WoltLab GmbH
  * @license  GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  */
-define(["require", "exports", "tslib", "./Core", "./Date/Picker", "./Devtools", "./Dom/Change/Listener", "./Environment", "./Event/Handler", "./Form/XsrfToken", "./Language", "./Ui/Dialog", "./Ui/Dropdown/Simple", "./Ui/Mobile", "./Ui/Page/Action", "./Ui/TabMenu", "./Ui/Tooltip", "./Ui/Page/JumpTo", "./Ui/Password", "./Ui/Empty", "./Ui/Object/Action", "./Ui/Object/Action/Delete", "./Ui/Object/Action/Toggle", "./Ui/Search", "./LazyLoader", "./Helper/PageOverlay", "perfect-scrollbar"], function (require, exports, tslib_1, Core, Picker_1, Devtools_1, Listener_1, Environment, EventHandler, XsrfToken, Language, Dialog_1, Simple_1, UiMobile, UiPageAction, UiTabMenu, UiTooltip, UiPageJumpTo, UiPassword, UiEmpty, UiObjectAction, UiObjectActionDelete, UiObjectActionToggle, Search_1, LazyLoader_1, PageOverlay_1) {
+define(["require", "exports", "tslib", "./Core", "./Date/Picker", "./Devtools", "./Dom/Change/Listener", "./Environment", "./Event/Handler", "./Form/XsrfToken", "./Language", "./Ui/Dialog", "./Ui/Dropdown/Simple", "./Ui/Mobile", "./Ui/Page/Action", "./Ui/TabMenu", "./Ui/Tooltip", "./Ui/Page/JumpTo", "./Ui/Password", "./Ui/Empty", "./Ui/Object/Action", "./Ui/Object/Action/Delete", "./Ui/Object/Action/Toggle", "./Ui/Search", "./LazyLoader", "./Helper/PageOverlay", "./User", "perfect-scrollbar"], function (require, exports, tslib_1, Core, Picker_1, Devtools_1, Listener_1, Environment, EventHandler, XsrfToken, Language, Dialog_1, Simple_1, UiMobile, UiPageAction, UiTabMenu, UiTooltip, UiPageJumpTo, UiPassword, UiEmpty, UiObjectAction, UiObjectActionDelete, UiObjectActionToggle, Search_1, LazyLoader_1, PageOverlay_1, User_1) {
     "use strict";
     Object.defineProperty(exports, "__esModule", { value: true });
     exports.setup = void 0;
@@ -31,6 +31,7 @@ define(["require", "exports", "tslib", "./Core", "./Date/Picker", "./Devtools",
     UiObjectAction = tslib_1.__importStar(UiObjectAction);
     UiObjectActionDelete = tslib_1.__importStar(UiObjectActionDelete);
     UiObjectActionToggle = tslib_1.__importStar(UiObjectActionToggle);
+    User_1 = tslib_1.__importDefault(User_1);
     // non strict equals by intent
     if (window.WCF == null) {
         window.WCF = {};
@@ -116,8 +117,8 @@ define(["require", "exports", "tslib", "./Core", "./Date/Picker", "./Devtools",
         });
         initA11y();
         Listener_1.default.add("WoltLabSuite/Core/Bootstrap", () => initA11y);
-        if (options.colorScheme === "system") {
-            void new Promise((resolve_1, reject_1) => { require(["./Controller/Style/ColorScheme"], resolve_1, reject_1); }).then(tslib_1.__importStar).then(({ setup }) => setup());
+        if (options.colorScheme === "system" && User_1.default.userId) {
+            void new Promise((resolve_1, reject_1) => { require(["./Controller/Style/ColorScheme"], resolve_1, reject_1); }).then(tslib_1.__importStar).then(({ setup }) => setup(options.colorScheme));
         }
         (0, LazyLoader_1.whenFirstSeen)("[data-report-content]", () => {
             void new Promise((resolve_2, reject_2) => { require(["./Ui/Moderation/Report"], resolve_2, reject_2); }).then(tslib_1.__importStar).then(({ setup }) => setup());
index 69fc4906ee7e1b9e80de9abd9a47c6a6401b7ad1..ab100190cd04b87d6efbe06ccf182106e8d22ba7 100644 (file)
@@ -5,6 +5,7 @@
  * @copyright 2001-2023 WoltLab GmbH
  * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @since 6.0
+ * @woltlabExcludeBundle tiny
  */
 define(["require", "exports", "WoltLabSuite/Core/Language", "../../Ui/Dropdown/Builder", "../../Ui/Dropdown/Simple"], function (require, exports, Language_1, Builder_1, Simple_1) {
     "use strict";
@@ -22,12 +23,6 @@ define(["require", "exports", "WoltLabSuite/Core/Language", "../../Ui/Dropdown/B
         else {
             applySystemScheme();
         }
-        try {
-            localStorage.setItem("wsc_colorScheme", currentScheme);
-        }
-        catch {
-            /* Ignore any errors when accessing the `localStorage`. */
-        }
     }
     function applySystemScheme() {
         if (currentScheme === "system") {
@@ -71,20 +66,12 @@ define(["require", "exports", "WoltLabSuite/Core/Language", "../../Ui/Dropdown/B
             }
         });
     }
-    function setup() {
+    function setup(colorScheme) {
         const button = document.querySelector(".jsButtonStyleColorScheme");
         if (button) {
-            initializeButton(button);
-        }
-        try {
-            const value = localStorage.getItem("wsc_colorScheme");
-            if (value === "light" || value === "dark") {
-                currentScheme = value;
-            }
-        }
-        catch {
-            /* Ignore any errors when accessing the `localStorage`. */
+            //initializeButton(button);
         }
+        currentScheme = colorScheme;
         themeColor = document.querySelector('meta[name="theme-color"]');
         mediaQuery = matchMedia("(prefers-color-scheme: dark)");
         mediaQuery.addEventListener("change", () => {
index b4bb8e65f12478c3214e7aaf977fef6895d21fa0..c91c17ebdbe63ade03b0a3fc8b13aba77cdd0e1a 100644 (file)
@@ -292,18 +292,18 @@ class StyleHandler extends SingletonFactory
     }
 
     /**
-     * The color scheme is 'light' for styles without a dark mode. For styles
-     * with a dark mode, the special value 'system' is used to indicate that
-     * the client is able to negotiate a color scheme.
+     * Returns the preferred color scheme of the user. For guests this value
+     * will always be 'system' to indicate that the device preferences should
+     * be used to negotiate the color scheme.
      *
      * @since 6.0
      */
     public function getColorScheme(): string
     {
-        if ($this->getStyle()->hasDarkMode) {
+        if (!WCF::getUser()->userID) {
             return 'system';
         }
 
-        return 'light';
+        return WCF::getUser()->getUserOption('colorScheme');
     }
 }