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 }) => {
).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')
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%')
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)
`${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,
'--pngx-primary-lightness',
RendererStyleFlags2.DashCase
)
+ this._renderer.removeStyle(
+ document.body,
+ '--bs-primary',
+ RendererStyleFlags2.DashCase
+ )
}
}
<!doctype html>
-<html lang="en">
+<html lang="en" data-bs-theme="auto">
<head>
<meta charset="utf-8">
<title>Paperless-ngx</title>
<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>
// 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";
+$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);
}
.doc-img {
- mix-blend-mode: normal;
+ mix-blend-mode: normal !important;
border-radius: 0;
border-color: var(--bs-border-color);
filter: invert(10%);
}
}
-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 {
@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;
+ }
}
+
}