Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chore: change dark mode to use Bootstrap's color modes #4174

Merged
4 changes: 2 additions & 2 deletions src-ui/e2e/settings/settings.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }) => {
Expand Down
25 changes: 14 additions & 11 deletions src-ui/src/app/services/settings.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,35 +147,38 @@ 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')
).toEqual('50%')

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%')
Expand Down
35 changes: 25 additions & 10 deletions src-ui/src/app/services/settings.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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,
Expand All @@ -153,6 +163,11 @@ export class SettingsService {
'--pngx-primary-lightness',
RendererStyleFlags2.DashCase
)
this._renderer.removeStyle(
document.body,
'--bs-primary',
RendererStyleFlags2.DashCase
)
}
}

Expand Down
4 changes: 2 additions & 2 deletions src-ui/src/index.html
Original file line number Diff line number Diff line change
@@ -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>
Expand All @@ -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>
2 changes: 1 addition & 1 deletion src-ui/src/styles.scss
Original file line number Diff line number Diff line change
@@ -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";

Expand Down
39 changes: 23 additions & 16 deletions src-ui/src/theme.scss
Original file line number Diff line number Diff line change
@@ -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);

Expand Down Expand Up @@ -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%);
Expand Down Expand Up @@ -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 {
Expand All @@ -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;
}
}

}