diff --git a/pdfjs/viewer.css b/pdfjs/viewer.css index 1cf5eb0b..f19a3ce8 100644 --- a/pdfjs/viewer.css +++ b/pdfjs/viewer.css @@ -395,9 +395,7 @@ body, #viewerContainer { body:not(.disableDarkMode) .pdfViewer .page { background-color: #000000; } -} -@media (prefers-color-scheme: dark) { .textLayer { opacity: 0.5; } @@ -410,3 +408,30 @@ body, #viewerContainer { background-color: #FF00F1; } } + +:root[data-color-scheme=dark] body:not(.disableDarkMode), +:root[data-color-scheme=dark] body:not(.disableDarkMode) #viewerContainer { + background-color: #272727; + /* --color-toolbar */ +} + +:root[data-color-scheme=dark] body:not(.disableDarkMode) canvas, +:root[data-color-scheme=dark] body:not(.disableDarkMode) .textAnnotation { + filter: invert(90%) saturate(100%) hue-rotate(180deg) brightness(100%) contrast(125%) +} + +:root[data-color-scheme=dark] body:not(.disableDarkMode) .pdfViewer .page { + background-color: #000000; +} + +:root[data-color-scheme=dark] .textLayer { + opacity: 0.5; +} + +:root[data-color-scheme=dark] .textLayer .highlight.selected { + background-color: #00FF00; +} + +:root[data-color-scheme=dark] .textLayer .highlight { + background-color: #FF00F1; +} diff --git a/src/common/reader.js b/src/common/reader.js index 0f21fbc5..bd5335e0 100644 --- a/src/common/reader.js +++ b/src/common/reader.js @@ -338,12 +338,11 @@ class Reader { } if (init || this._state.useDarkModeForContent !== previousState.useDarkModeForContent) { - if (this._state.useDarkModeForContent) { - document.body.classList.add('use-dark-mode-for-content'); - } - else { - document.body.classList.remove('use-dark-mode-for-content'); - } + document.body.classList.toggle( + 'use-dark-mode-for-content', + this._state.useDarkModeForContent + ); + if (!init) { this._primaryView?.setUseDarkMode(this._state.useDarkModeForContent); this._secondaryView?.setUseDarkMode(this._state.useDarkModeForContent); @@ -357,6 +356,13 @@ class Reader { else { delete document.documentElement.dataset.colorScheme; } + if (!init) { + this._primaryView?.setColorScheme(this._state.colorScheme); + this._secondaryView?.setColorScheme(this._state.colorScheme); + // also update useDarkModeForContent as it depends on colorScheme + this._primaryView?.setUseDarkMode(this._state.useDarkModeForContent); + this._secondaryView?.setUseDarkMode(this._state.useDarkModeForContent); + } } if (this._state.readOnly !== previousState.readOnly) { @@ -782,6 +788,7 @@ class Reader { annotations: this._state.annotations.filter(x => !x._hidden), showAnnotations: this._state.showAnnotations, useDarkMode: this._state.useDarkModeForContent, + colorScheme: this._state.colorScheme, findState: this._state[primary ? 'primaryViewFindState' : 'secondaryViewFindState'], viewState: this._state[primary ? 'primaryViewState' : 'secondaryViewState'], location, diff --git a/src/dom/common/dom-view.tsx b/src/dom/common/dom-view.tsx index 3602c37b..7bc06287 100644 --- a/src/dom/common/dom-view.tsx +++ b/src/dom/common/dom-view.tsx @@ -70,6 +70,8 @@ abstract class DOMView { protected _useDarkMode: boolean; + protected _colorScheme: string | null; + protected _annotationPopup: AnnotationPopupParams | null; protected _selectionPopup: SelectionPopupParams | null; @@ -112,6 +114,7 @@ abstract class DOMView { // Don't show annotations if this is false this._showAnnotations = options.showAnnotations; this._useDarkMode = options.useDarkMode; + this._colorScheme = options.colorScheme; this._annotationPopup = options.annotationPopup; this._selectionPopup = options.selectionPopup; this._overlayPopup = options.overlayPopup; @@ -495,6 +498,7 @@ abstract class DOMView { this.setAnnotations(this._options.annotations); this.setTool(this._options.tool); this.setUseDarkMode(this._options.useDarkMode); + this.setColorScheme(this._options.colorScheme); await this._onInitialDisplay(this._options.viewState || {}); setTimeout(() => { @@ -1106,6 +1110,16 @@ abstract class DOMView { this._iframeDocument.documentElement.classList.toggle('disable-dark-mode', !use); } + setColorScheme(colorScheme: string | null) { + this._colorScheme = colorScheme; + if (colorScheme) { + this._iframeDocument.documentElement.dataset.colorScheme = colorScheme; + } + else { + delete this._iframeDocument.documentElement.dataset.colorScheme; + } + } + setSelectedAnnotationIDs(ids: string[]) { this._selectedAnnotationIDs = ids; // Close annotation popup each time when any annotation is selected, because the click is what opens the popup @@ -1187,6 +1201,7 @@ export type DOMViewOptions = { annotations: WADMAnnotation[]; showAnnotations: boolean; useDarkMode: boolean; + colorScheme: string | null; annotationPopup: AnnotationPopupParams | null; selectionPopup: SelectionPopupParams | null; overlayPopup: OverlayPopupParams | null; diff --git a/src/dom/common/stylesheets/annotation-overlay.scss b/src/dom/common/stylesheets/annotation-overlay.scss index 6f8fd181..b379f1ad 100644 --- a/src/dom/common/stylesheets/annotation-overlay.scss +++ b/src/dom/common/stylesheets/annotation-overlay.scss @@ -24,10 +24,18 @@ } } +@mixin -dark-rules() { + #annotation-overlay .annotation-container.blended { + mix-blend-mode: screen; + } +} + @media (prefers-color-scheme: dark) { :root:not(.disable-dark-mode) { - #annotation-overlay .annotation-container.blended { - mix-blend-mode: screen; - } + @include -dark-rules(); } } + +:root[data-color-scheme=dark]:not(.disable-dark-mode) { + @include -dark-rules(); +} diff --git a/src/dom/epub/stylesheets/_content.scss b/src/dom/epub/stylesheets/_content.scss index 09b32c22..8630789e 100644 --- a/src/dom/epub/stylesheets/_content.scss +++ b/src/dom/epub/stylesheets/_content.scss @@ -49,6 +49,13 @@ --visited-link-color: #0099e5; } } + + &[data-color-scheme=dark]:not(.disable-dark-mode) { + --background-color: #121212; + --text-color: #fefefe; + --link-color: #63caff; + --visited-link-color: #0099e5; + } } :root { diff --git a/src/dom/snapshot/snapshot-view.ts b/src/dom/snapshot/snapshot-view.ts index 42507c5c..0a7ee498 100644 --- a/src/dom/snapshot/snapshot-view.ts +++ b/src/dom/snapshot/snapshot-view.ts @@ -117,7 +117,8 @@ class SnapshotView extends DOMView { // Horrifying, but it works this._iframeWindow.eval(`{ let location = new URL(${JSON.stringify(url)}); ${darkReaderJS} }`); if (this._useDarkMode) { - this._iframeWindow.DarkReader.auto({}); + const mode = this._colorScheme === 'dark' ? 'enable' : 'auto'; + this._iframeWindow.DarkReader[mode]({}); } this._initOutline(); @@ -416,7 +417,8 @@ class SnapshotView extends DOMView { // Run Dark Reader now if it's been loaded if (this._iframeWindow.DarkReader) { if (use) { - this._iframeWindow.DarkReader.auto({}); + const mode = this._colorScheme === 'dark' ? 'enable' : 'auto'; + this._iframeWindow.DarkReader[mode]({}); } else { this._iframeWindow.DarkReader.auto(false); diff --git a/src/pdf/pdf-view.js b/src/pdf/pdf-view.js index b5544a1a..1eea6e0d 100644 --- a/src/pdf/pdf-view.js +++ b/src/pdf/pdf-view.js @@ -63,6 +63,7 @@ class PDFView { this._container = options.container; this._password = options.password; this._useDarkMode = options.useDarkMode; + this._colorScheme = options.colorScheme; this._onRequestPassword = options.onRequestPassword; this._onSetThumbnails = options.onSetThumbnails; this._onSetOutline = options.onSetOutline; @@ -157,6 +158,9 @@ class PDFView { if (!this._useDarkMode) { this._iframeWindow.document.body.classList.add('disableDarkMode'); } + if (this._colorScheme) { + this._iframeWindow.document.documentElement.dataset.colorScheme = this._colorScheme; + } this._iframeWindow.onAttachPage = this._attachPage.bind(this); this._iframeWindow.onDetachPage = this._detachPage.bind(this); this._init(); @@ -554,6 +558,15 @@ class PDFView { } } + setColorScheme(colorScheme) { + if (colorScheme) { + this._iframeWindow.document.documentElement.dataset.colorScheme = colorScheme; + } + else { + delete this._iframeWindow.document.documentElement.dataset.colorScheme; + } + } + setAnnotationPopup(popup) { this._annotationPopup = popup; }