]> git.ipfire.org Git - thirdparty/paperless-ngx.git/commitdiff
Chore: change dark mode to use Bootstrap's color modes (#4174)
authorDominik Mielcarek <github@bmx.email>
Wed, 13 Sep 2023 18:11:44 +0000 (20:11 +0200)
committerGitHub <noreply@github.com>
Wed, 13 Sep 2023 18:11:44 +0000 (18:11 +0000)
* Change setting dark mode to use Bootstrap's data-bs-theme attribute

* Update dark mode styling to use Bootstrap's color mode attribute

* Update unit tests and lints

* Fix not reflecting custom theme color

* Remove commented-out code

* fix inverted thumbnails in dark mode & card borders

* prettier

* Fix application of dark mode, tests

---------

Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
src-ui/e2e/settings/settings.spec.ts
src-ui/src/app/services/settings.service.spec.ts
src-ui/src/app/services/settings.service.ts
src-ui/src/index.html
src-ui/src/styles.scss
src-ui/src/theme.scss

index 51210acdda9a5cd19c5ad34c6493c85e78931a4b..1ae9afa06303ca328a7f132a37a61b50b452ce85 100644 (file)
@@ -46,10 +46,10 @@ test('should warn on unsaved changes', async ({ page }) => {
 test('should apply appearance changes when set', async ({ page }) => {
   await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
   await page.goto('/settings')
-  await expect(page.locator('body')).toHaveClass(/color-scheme-system/)
+  await expect(page.locator('html')).toHaveAttribute('data-bs-theme', /auto/)
   await page.getByLabel('Use system setting').click()
   await page.getByLabel('Enable dark mode').click()
-  await expect(page.locator('body')).toHaveClass(/color-scheme-dark/)
+  await expect(page.locator('html')).toHaveAttribute('data-bs-theme', /dark/)
 })
 
 test('should toggle saved view options when set & saved', async ({ page }) => {
index 560b67ae8f6c1452436c1fe6ee9fbfc277f05c7e..fac41ee6c4df8ec02653d9c99cebdbd4d9ab4c73 100644 (file)
@@ -147,13 +147,14 @@ describe('SettingsService', () => {
     ).toEqual('')
 
     const addClassSpy = jest.spyOn(settingsService.renderer, 'addClass')
-    const removeClassSpy = jest.spyOn(settingsService.renderer, 'removeClass')
+    const setAttributeSpy = jest.spyOn(settingsService.renderer, 'setAttribute')
 
     settingsService.updateAppearanceSettings(true, true, '#fff000')
     expect(addClassSpy).toHaveBeenCalledWith(document.body, 'primary-light')
-    expect(addClassSpy).toHaveBeenCalledWith(
-      document.body,
-      'color-scheme-system'
+    expect(setAttributeSpy).toHaveBeenCalledWith(
+      document.documentElement,
+      'data-bs-theme',
+      'auto'
     )
     expect(
       document.body.style.getPropertyValue('--pngx-primary-lightness')
@@ -161,21 +162,23 @@ describe('SettingsService', () => {
 
     settingsService.updateAppearanceSettings(false, false, '#000000')
     expect(addClassSpy).toHaveBeenCalledWith(document.body, 'primary-light')
-    expect(removeClassSpy).toHaveBeenCalledWith(
-      document.body,
-      'color-scheme-system'
+    expect(setAttributeSpy).toHaveBeenCalledWith(
+      document.documentElement,
+      'data-bs-theme',
+      'light'
     )
+
     expect(
       document.body.style.getPropertyValue('--pngx-primary-lightness')
     ).toEqual('0%')
 
     settingsService.updateAppearanceSettings(false, true, '#ffffff')
     expect(addClassSpy).toHaveBeenCalledWith(document.body, 'primary-dark')
-    expect(removeClassSpy).toHaveBeenCalledWith(
-      document.body,
-      'color-scheme-system'
+    expect(setAttributeSpy).toHaveBeenCalledWith(
+      document.documentElement,
+      'data-bs-theme',
+      'dark'
     )
-    expect(addClassSpy).toHaveBeenCalledWith(document.body, 'color-scheme-dark')
     expect(
       document.body.style.getPropertyValue('--pngx-primary-lightness')
     ).toEqual('100%')
index 134bb3ebb2e1311030b8b32e313144ed37812ac1..1081bede16c8e5510ac906c8906c6f0bdd450855 100644 (file)
@@ -106,19 +106,19 @@ export class SettingsService {
     themeColor ??= this.get(SETTINGS_KEYS.THEME_COLOR)
 
     if (darkModeUseSystem) {
-      this._renderer.addClass(this.document.body, 'color-scheme-system')
-      this._renderer.removeClass(this.document.body, 'color-scheme-dark')
+      this._renderer.setAttribute(
+        this.document.documentElement,
+        'data-bs-theme',
+        'auto'
+      )
     } else {
-      this._renderer.removeClass(this.document.body, 'color-scheme-system')
-      darkModeEnabled
-        ? this._renderer.addClass(this.document.body, 'color-scheme-dark')
-        : this._renderer.removeClass(this.document.body, 'color-scheme-dark')
+      this._renderer.setAttribute(
+        this.document.documentElement,
+        'data-bs-theme',
+        darkModeEnabled ? 'dark' : 'light'
+      )
     }
 
-    // remove these in case they were there
-    this._renderer.removeClass(this.document.body, 'primary-dark')
-    this._renderer.removeClass(this.document.body, 'primary-light')
-
     if (themeColor) {
       const hsl = hexToHsl(themeColor)
       const bgBrightnessEstimate = estimateBrightnessForColor(themeColor)
@@ -142,6 +142,16 @@ export class SettingsService {
         `${hsl.l * 100}%`,
         RendererStyleFlags2.DashCase
       )
+
+      /**
+       * Fix for not reflecting changed variables. (--bs-primary is at :root while here we set them to body)
+       */
+      this._renderer.setStyle(
+        document.body,
+        '--bs-primary',
+        'hsl(var(--pngx-primary), var(--pngx-primary-lightness))',
+        RendererStyleFlags2.DashCase
+      )
     } else {
       this._renderer.removeStyle(
         document.body,
@@ -153,6 +163,11 @@ export class SettingsService {
         '--pngx-primary-lightness',
         RendererStyleFlags2.DashCase
       )
+      this._renderer.removeStyle(
+        document.body,
+        '--bs-primary',
+        RendererStyleFlags2.DashCase
+      )
     }
   }
 
index c01df6243af6d335d385e1d47951cda93ab86530..118b9deff1c1a151c058a46482cd32066f4138cd 100644 (file)
@@ -1,5 +1,5 @@
 <!doctype html>
-<html lang="en">
+<html lang="en" data-bs-theme="auto">
 <head>
   <meta charset="utf-8">
   <title>Paperless-ngx</title>
@@ -11,7 +11,7 @@
   <link rel="icon" type="image/x-icon" href="favicon.ico">
   <link rel="apple-touch-icon" href="apple-touch-icon.png">
 </head>
-<body class="color-scheme-system">
+<body>
   <app-root></app-root>
 </body>
 </html>
index 1bdd84190c47b3b81cfbe31533235cd4a79bbb27..ffecca62f8b614601cfe2c27f23ecdc3d442cc75 100644 (file)
@@ -1,8 +1,8 @@
 // bs options
 $enable-negative-margins: true;
 
-@import "theme";
 @import "node_modules/bootstrap/scss/bootstrap";
+@import "theme";
 @import "~@ng-select/ng-select/themes/default.theme.css";
 @import "print";
 
index bcfceb6ec78c68537dde15fbc8324e891e57a6da..eadc125ab17377646c629138d4eea014594dae4c 100644 (file)
@@ -1,10 +1,14 @@
+$color-mode-type: data;
+
+@import 'bootstrap/scss/mixins/color-mode';
+
 @mixin paperless-green {
   // base color e.g. #17541f = hsl(128, 57%, 21%)
   --pngx-primary: 128, 57%;
   --pngx-primary-lightness: 21%;
 }
 
-body {
+:root {
   @include paperless-green;
   --pngx-primary-text-contrast: var(--bs-light);
 
@@ -158,7 +162,7 @@ $form-check-radio-checked-bg-image-dark: url("data:image/svg+xml,<svg xmlns='htt
   }
 
   .doc-img {
-    mix-blend-mode: normal;
+    mix-blend-mode: normal !important;
     border-radius: 0;
     border-color: var(--bs-border-color);
     filter: invert(10%);
@@ -270,9 +274,8 @@ $form-check-radio-checked-bg-image-dark: url("data:image/svg+xml,<svg xmlns='htt
   }
 }
 
-body.color-scheme-dark {
-  // no custom theme color
-  &:not(.primary-light):not(.primary-dark) {
+@include color-mode(dark) {
+  body:not(.primary-light):not(.primary-dark) {
     @include paperless-green-dark-mode;
 
     .navbar.bg-primary {
@@ -284,18 +287,22 @@ body.color-scheme-dark {
   @include dark-mode;
 }
 
-@media (prefers-color-scheme: dark) {
-  body.color-scheme-system {
-    // no custom theme color
-    &:not(.primary-light):not(.primary-dark) {
-      @include paperless-green-dark-mode;
-
-      .navbar.bg-primary {
-        // navbar is og green in dark mode
-        @include paperless-green;
+// Temp to not blink with white before angular loads
+@include color-mode(auto) {
+  @media (prefers-color-scheme: dark) {
+    body {
+      // no custom theme color
+      &:not(.primary-light):not(.primary-dark) {
+        @include paperless-green-dark-mode;
+
+        .navbar.bg-primary {
+          // navbar is og green in dark mode
+          @include paperless-green;
+        }
       }
-    }
 
-    @include dark-mode;
+      @include dark-mode;
+    }
   }
+
 }