From 57c0517508a711041fec17e5142554deb58d8856 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 5 Aug 2020 10:41:26 +0530 Subject: [PATCH] Server and Viewer: Add support for dark themes in the UI UI now uses dark colors when either the browser is in dark mode or the viewer color theme is dark --- src/pyj/book_list/theme.pyj | 59 ++++++++++++++++++++++++------------- src/pyj/read_book/view.pyj | 7 +++-- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/src/pyj/book_list/theme.pyj b/src/pyj/book_list/theme.pyj index 42b913eec4..895f94e693 100644 --- a/src/pyj/book_list/theme.pyj +++ b/src/pyj/book_list/theme.pyj @@ -6,38 +6,46 @@ LIGHT = '#F6F3E9' LIGHT_DARKER = '#b6b3a8' LIGHT_GRADIENT = 'linear-gradient(to bottom, {}, {})'.format(LIGHT, LIGHT_DARKER) +DT_DARK = '#2d2d2d' +DT_DARK_LIGHTER = '#777' +DT_LIGHT = '#ddd' +DARK_GRADIENT = 'linear-gradient(to bottom, {}, {})'.format(DT_DARK_LIGHTER, DT_DARK) + +def c(light, dark): + return {'light': light, 'dark': dark or light} + DEFAULT_COLORS = { # General colors - 'window-background': LIGHT, - 'window-background2': LIGHT_DARKER, - 'window-foreground': DARK, - 'window-error-foreground': 'red', - 'window-hover-foreground': 'red', - 'link-foreground': 'blue', + 'window-background': c(LIGHT, DT_DARK), + 'window-background2': c(LIGHT_DARKER, DT_DARK_LIGHTER), + 'window-foreground': c(DARK, DT_LIGHT), + 'window-error-foreground': c('red'), + 'window-hover-foreground': c('red'), + 'link-foreground': c('blue', '#6cb4ee'), # Top bar specific colors - 'bar-background': DARK, - 'bar-foreground': LIGHT, - 'bar-highlight': 'yellow', - 'heart': '#B92111', + 'bar-background': c(DARK, DT_DARK_LIGHTER), + 'bar-foreground': c(LIGHT, DT_DARK), + 'bar-highlight': c('yellow'), + 'heart': c('#B92111'), # Item list colors - 'list-hover-background': DARK, - 'list-hover-foreground': LIGHT, + 'list-hover-background': c(DARK, DT_DARK_LIGHTER), + 'list-hover-foreground': c(LIGHT, DT_DARK), # Tree colors - 'tree-highlight-item': LIGHT_DARKER, + 'tree-highlight-item': c(LIGHT_DARKER, DT_DARK_LIGHTER), # Button colors - 'button-start': DARK, - 'button-end': '#49423B', - 'button-text': LIGHT, + 'button-start': c(DARK, DT_LIGHT), + 'button-end': c('#49423B', '#666'), + 'button-text': c(LIGHT, DT_DARK), # Dialog colors - 'dialog-background': LIGHT, - 'dialog-background-image': LIGHT_GRADIENT, - 'dialog-foreground': DARK, + 'dialog-background': c(LIGHT, DT_DARK), + 'dialog-background-image': c(LIGHT_GRADIENT, DARK_GRADIENT), + 'dialog-foreground': c(DARK, DT_LIGHT), } DEFAULT_SIZES = { @@ -50,10 +58,21 @@ 'main': 'sans-serif' } + +def set_ui_colors(is_dark_theme): + attr = 'dark' if is_dark_theme else 'light' + s = document.documentElement.style + for k in DEFAULT_COLORS: + val = DEFAULT_COLORS[k][attr] + s.setProperty('--calibre-color-' + k, val) + + def css_for_variables(): + is_dark_theme = window.matchMedia('(prefers-color-scheme: dark)').matches + attr = 'dark' if is_dark_theme else 'light' ans = v'[]' for k in DEFAULT_COLORS: - val = DEFAULT_COLORS[k] + val = DEFAULT_COLORS[k][attr] ans.push(f'--calibre-color-{k}: {val};') return ':root { ' + ans.join('\n') + '}' diff --git a/src/pyj/read_book/view.pyj b/src/pyj/read_book/view.pyj index 94ccd78582..41d6017a8f 100644 --- a/src/pyj/read_book/view.pyj +++ b/src/pyj/read_book/view.pyj @@ -8,7 +8,7 @@ import read_book.iframe # noqa from ajax import ajax_send from book_list.globals import get_session_data -from book_list.theme import cached_color_to_rgba, get_color +from book_list.theme import cached_color_to_rgba, get_color, set_ui_colors from dom import add_extra_css, build_rule, clear, set_css, svgicon, unique_id from iframe_comm import IframeWrapper from modals import error_dialog, warning_dialog @@ -295,9 +295,10 @@ def __init__(self, container): , } entry_point = None if runtime.is_standalone_viewer else 'read_book.iframe' + self.current_color_scheme = resolve_color_scheme() if runtime.is_standalone_viewer: document.documentElement.addEventListener('keydown', self.handle_keypress, {'passive': False}) - self.current_color_scheme = resolve_color_scheme() + set_ui_colors(self.current_color_scheme.is_dark_theme) self.iframe_wrapper = IframeWrapper( handlers, document.getElementById(iframe_id), entry_point, _('Bootstrapping book reader...'), f'{runtime.FAKE_PROTOCOL}://{runtime.SANDBOX_HOST}/book/__index__') @@ -718,6 +719,8 @@ def on_iframe_error(self, data): def apply_color_scheme(self): self.current_color_scheme = ans = resolve_color_scheme() + if runtime.is_standalone_viewer: + set_ui_colors(self.current_color_scheme.is_dark_theme) for which in 'left top right bottom'.split(' '): m = document.getElementById('book-{}-margin'.format(which)) s = m.style