diff --git a/qt/BUILD.bazel b/qt/BUILD.bazel index be49bc6a6..3c1db25f5 100644 --- a/qt/BUILD.bazel +++ b/qt/BUILD.bazel @@ -16,9 +16,9 @@ py_binary( ) py_binary( - name = "extract_sass_colors", + name = "extract_sass_vars", srcs = [ - "tools/extract_sass_colors.py", + "tools/extract_sass_vars.py", ], imports = ["."], visibility = [":__subpackages__"], diff --git a/qt/aqt/BUILD.bazel b/qt/aqt/BUILD.bazel index 9248b51af..5a60e3393 100644 --- a/qt/aqt/BUILD.bazel +++ b/qt/aqt/BUILD.bazel @@ -3,6 +3,22 @@ load("@py_deps//:requirements.bzl", "requirement") load("@rules_python//python:packaging.bzl", "py_package", "py_wheel") load("//:defs.bzl", "anki_version") +load("//ts:copy.bzl", "copy_files_into_group") +load("//ts:compile_sass.bzl", "compile_sass") + +genrule( + name = "copy_vars", + srcs = ["//sass:_vars.scss"], + outs = ["_vars.scss"], + cmd = "cp $(SRCS) $(RULEDIR)", +) + +compile_sass( + srcs = ["_vars.scss"], + group = "vars", + visibility = ["//visibility:private"], +) + genrule( name = "hooks_gen", outs = ["hooks_gen.py"], @@ -11,14 +27,14 @@ genrule( ) genrule( - name = "extract_sass_colors", + name = "extract_sass_vars", srcs = [ - "//sass:_vars.scss", + "_vars.css", ], - outs = ["colors.py"], - cmd = "$(location //qt:extract_sass_colors) $< $@", + outs = ["colors.py", "props.py"], + cmd = "$(location //qt:extract_sass_vars) $(SRCS) $(OUTS)", tools = [ - "//qt:extract_sass_colors", + "//qt:extract_sass_vars", ], ) @@ -35,6 +51,7 @@ _py_srcs_and_forms = _py_srcs + [ aqt_core_data = [ "colors.py", + "props.py", "py.typed", ":hooks_gen", ] diff --git a/qt/aqt/browser/sidebar/tree.py b/qt/aqt/browser/sidebar/tree.py index cbdaca784..e778ed73b 100644 --- a/qt/aqt/browser/sidebar/tree.py +++ b/qt/aqt/browser/sidebar/tree.py @@ -104,7 +104,7 @@ class SidebarTreeView(QTreeView): def _setup_style(self) -> None: # match window background color and tweak style bgcolor = QPalette().window().color().name() - border = theme_manager.color(colors.MEDIUM_BORDER) + border = theme_manager.var(colors.BORDER) styles = [ "padding: 3px", "padding-right: 0px", @@ -303,7 +303,7 @@ class SidebarTreeView(QTreeView): ) -> None: if self.current_search and (item := self.model().item_for_index(idx)): if item.is_highlighted(): - brush = QBrush(theme_manager.qcolor(colors.SUSPENDED_BG)) + brush = QBrush(theme_manager.qcolor(colors.STATE_SUSPENDED)) painter.save() painter.fillRect(options.rect, brush) painter.restore() @@ -653,36 +653,36 @@ class SidebarTreeView(QTreeView): type=SidebarItemType.CARD_STATE_ROOT, ) type = SidebarItemType.CARD_STATE - colored_icon = ColoredIcon(path=icon, color=colors.DISABLED) + colored_icon = ColoredIcon(path=icon, color=colors.FG_DISABLED) root.add_simple( tr.actions_new(), - icon=colored_icon.with_color(colors.NEW_COUNT), + icon=colored_icon.with_color(colors.STATE_NEW), type=type, search_node=SearchNode(card_state=SearchNode.CARD_STATE_NEW), ) root.add_simple( name=tr.scheduling_learning(), - icon=colored_icon.with_color(colors.LEARN_COUNT), + icon=colored_icon.with_color(colors.STATE_LEARN), type=type, search_node=SearchNode(card_state=SearchNode.CARD_STATE_LEARN), ) root.add_simple( name=tr.scheduling_review(), - icon=colored_icon.with_color(colors.REVIEW_COUNT), + icon=colored_icon.with_color(colors.STATE_REVIEW), type=type, search_node=SearchNode(card_state=SearchNode.CARD_STATE_REVIEW), ) root.add_simple( name=tr.browsing_suspended(), - icon=colored_icon.with_color(colors.SUSPENDED_FG), + icon=colored_icon.with_color(colors.STATE_SUSPENDED), type=type, search_node=SearchNode(card_state=SearchNode.CARD_STATE_SUSPENDED), ) root.add_simple( name=tr.browsing_buried(), - icon=colored_icon.with_color(colors.BURIED_FG), + icon=colored_icon.with_color(colors.STATE_BURIED), type=type, search_node=SearchNode(card_state=SearchNode.CARD_STATE_BURIED), ) diff --git a/qt/aqt/browser/table/__init__.py b/qt/aqt/browser/table/__init__.py index 2cfd96b46..314ac742c 100644 --- a/qt/aqt/browser/table/__init__.py +++ b/qt/aqt/browser/table/__init__.py @@ -13,6 +13,7 @@ from anki.collection import BrowserColumns as Columns from anki.collection import BrowserRow from anki.notes import NoteId from aqt import colors +from aqt.qt import QColor from aqt.utils import tr Column = Columns.Column @@ -76,25 +77,38 @@ class CellRow: def backend_color_to_aqt_color(color: BrowserRow.Color.V) -> tuple[str, str] | None: + temp_color = None + if color == BrowserRow.COLOR_MARKED: - return colors.MARKED_BG + temp_color = colors.STATE_MARKED if color == BrowserRow.COLOR_SUSPENDED: - return colors.SUSPENDED_BG + temp_color = colors.STATE_SUSPENDED if color == BrowserRow.COLOR_FLAG_RED: - return colors.FLAG1_BG + temp_color = colors.FLAG_1 if color == BrowserRow.COLOR_FLAG_ORANGE: - return colors.FLAG2_BG + temp_color = colors.FLAG_2 if color == BrowserRow.COLOR_FLAG_GREEN: - return colors.FLAG3_BG + temp_color = colors.FLAG_3 if color == BrowserRow.COLOR_FLAG_BLUE: - return colors.FLAG4_BG + temp_color = colors.FLAG_4 if color == BrowserRow.COLOR_FLAG_PINK: - return colors.FLAG5_BG + temp_color = colors.FLAG_5 if color == BrowserRow.COLOR_FLAG_TURQUOISE: - return colors.FLAG6_BG + temp_color = colors.FLAG_6 if color == BrowserRow.COLOR_FLAG_PURPLE: - return colors.FLAG7_BG - return None + temp_color = colors.FLAG_7 + + return adjusted_bg_color(temp_color) + + +def adjusted_bg_color(color: tuple[str, str]) -> tuple[str, str]: + if color: + return ( + QColor(color[0]).lighter(150).name(), + QColor(color[1]).darker(150).name(), + ) + else: + return None from .model import DataModel diff --git a/qt/aqt/browser/table/table.py b/qt/aqt/browser/table/table.py index 29cdb67db..56de065a2 100644 --- a/qt/aqt/browser/table/table.py +++ b/qt/aqt/browser/table/table.py @@ -375,7 +375,7 @@ class Table: ) elif theme_manager.macos_dark_mode(): self._view.setStyleSheet( - f"QTableView {{ gridline-color: {colors.FRAME_BG} }}" + f"QTableView {{ gridline-color: {colors.CANVAS_INSET} }}" ) else: self._view.setStyleSheet("") diff --git a/qt/aqt/data/web/css/BUILD.bazel b/qt/aqt/data/web/css/BUILD.bazel index 8d677a20e..4067c5502 100644 --- a/qt/aqt/data/web/css/BUILD.bazel +++ b/qt/aqt/data/web/css/BUILD.bazel @@ -9,6 +9,7 @@ compile_sass( group = "css_local", visibility = ["//visibility:private"], deps = [ + "//sass:vars_lib", "//sass:buttons_lib", "//sass:card_counts_lib", "//sass:scrollbar_lib", diff --git a/qt/aqt/data/web/css/deckbrowser.scss b/qt/aqt/data/web/css/deckbrowser.scss index 4e32bcc46..e8561e26c 100644 --- a/qt/aqt/data/web/css/deckbrowser.scss +++ b/qt/aqt/data/web/css/deckbrowser.scss @@ -1,10 +1,11 @@ /* Copyright: Ankitects Pty Ltd and contributors * License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */ +@use "sass/vars"; @use "sass/card-counts"; a.deck { - color: var(--text-fg); + color: var(--fg); text-decoration: none; min-width: 5em; display: inline-block; @@ -15,7 +16,7 @@ a.deck:hover { } tr.deck td { - border-bottom: 1px solid var(--faint-border); + border-bottom: 1px solid var(--border-subtle); } tr.top-level-drag-row td { @@ -36,7 +37,7 @@ body { } .current { - background-color: var(--faint-border); + background-color: var(--shadow-subtle); } .decktd { @@ -55,14 +56,14 @@ body { } .collapse { - color: var(--text-fg); + color: var(--fg); text-decoration: none; display: inline-block; width: 1em; } .filtered { - color: var(--link) !important; + color: var(--accent-link) !important; } .gears { @@ -79,7 +80,7 @@ body { } .callout { - background: var(--medium-border); + background: var(--border); padding: 1em; margin: 1em; diff --git a/qt/aqt/data/web/css/overview.scss b/qt/aqt/data/web/css/overview.scss index 23565f573..719581eef 100644 --- a/qt/aqt/data/web/css/overview.scss +++ b/qt/aqt/data/web/css/overview.scss @@ -13,7 +13,7 @@ h3 { .descfont { padding: 1em; - color: var(--slightly-grey-text); + color: var(--fg-subtle); } .description { diff --git a/qt/aqt/data/web/css/reviewer-bottom.scss b/qt/aqt/data/web/css/reviewer-bottom.scss index 61e421a14..a62907826 100644 --- a/qt/aqt/data/web/css/reviewer-bottom.scss +++ b/qt/aqt/data/web/css/reviewer-bottom.scss @@ -1,10 +1,11 @@ /* Copyright: Ankitects Pty Ltd and contributors * License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */ +@use "vars"; @use "sass/card-counts"; :root { - --focus-color: #0078d7; + --focus-color: #{vars.palette-of(button-focus)}; .isMac { --focus-color: rgba(0 103 244 / 0.247); @@ -80,6 +81,6 @@ button { .nightMode { #outer { - border-top-color: var(--faint-border); + border-top-color: var(--border-subtle); } } diff --git a/qt/aqt/data/web/css/toolbar.scss b/qt/aqt/data/web/css/toolbar.scss index 235387461..351b7b4e5 100644 --- a/qt/aqt/data/web/css/toolbar.scss +++ b/qt/aqt/data/web/css/toolbar.scss @@ -26,7 +26,7 @@ body { padding-right: 12px; padding-left: 12px; text-decoration: none; - color: var(--text-fg); + color: var(--fg); } .hitem:hover { @@ -38,11 +38,11 @@ body { } .nightMode #header { - border-bottom-color: var(--faint-border); + border-bottom-color: var(--border-subtle); } .isMac.nightMode #header { - border-bottom-color: var(--frame-bg); + border-bottom-color: var(--canvas-elevated); } @keyframes spin { @@ -71,9 +71,9 @@ body { } .normal-sync { - color: var(--new-count); + color: var(--state-new); } .full-sync { - color: var(--learn-count); + color: var(--state-learn); } diff --git a/qt/aqt/data/web/css/webview.scss b/qt/aqt/data/web/css/webview.scss index f96d5f65b..3ce0b5eb3 100644 --- a/qt/aqt/data/web/css/webview.scss +++ b/qt/aqt/data/web/css/webview.scss @@ -12,16 +12,17 @@ } body { - color: var(--text-fg); - background: var(--window-bg); + color: var(--fg); + background: var(--canvas); transition: opacity 0.5s ease-out; margin: 2em; overscroll-behavior: none; - @include scrollbar.custom; } +@include scrollbar.custom; + a { - color: var(--link); + color: var(--accent-link); text-decoration: none; } diff --git a/qt/aqt/editor.py b/qt/aqt/editor.py index 89262ae21..8cefd11d8 100644 --- a/qt/aqt/editor.py +++ b/qt/aqt/editor.py @@ -164,7 +164,7 @@ class Editor: context=self, default_css=False, ) - self.web._fix_editor_background_color_and_show() + self.web.show() lefttopbtns: list[str] = [] gui_hooks.editor_did_init_left_buttons(lefttopbtns, self) @@ -673,7 +673,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too self.tags = aqt.tagedit.TagEdit(self.widget) qconnect(self.tags.lostFocus, self.on_tag_focus_lost) self.tags.setToolTip(shortcut(tr.editing_jump_to_tags_with_ctrlandshiftandt())) - border = theme_manager.color(colors.BORDER) + border = theme_manager.var(colors.BORDER) self.tags.setStyleSheet(f"border: 1px solid {border}") tb.addWidget(self.tags, 1, 1) g.setLayout(tb) diff --git a/qt/aqt/filtered_deck.py b/qt/aqt/filtered_deck.py index 2fa6c3924..1e8a7e262 100644 --- a/qt/aqt/filtered_deck.py +++ b/qt/aqt/filtered_deck.py @@ -84,8 +84,8 @@ class FilteredDeckConfigDialog(QDialog): qconnect(self.form.search_button.clicked, self.on_search_button) qconnect(self.form.search_button_2.clicked, self.on_search_button_2) qconnect(self.form.hint_button.clicked, self.on_hint_button) - blue = theme_manager.color(colors.LINK) - grey = theme_manager.color(colors.DISABLED) + blue = theme_manager.var(colors.ACCENT_LINK) + grey = theme_manager.var(colors.FG_DISABLED) self.setStyleSheet( f"""QPushButton[label] {{ padding: 0; border: 0 }} QPushButton[label]:hover {{ text-decoration: underline }} diff --git a/qt/aqt/flags.py b/qt/aqt/flags.py index 7a3ea6862..5373206ab 100644 --- a/qt/aqt/flags.py +++ b/qt/aqt/flags.py @@ -61,55 +61,55 @@ class FlagManager: def _load_flags(self) -> None: labels = cast(dict[str, str], self.mw.col.get_config("flagLabels", {})) - icon = ColoredIcon(path="icons:flag-variant.svg", color=colors.DISABLED) + icon = ColoredIcon(path="icons:flag-variant.svg", color=colors.FG_DISABLED) self._flags = [ Flag( 1, labels["1"] if "1" in labels else tr.actions_flag_red(), - icon.with_color(colors.FLAG1_FG), + icon.with_color(colors.FLAG_1), SearchNode(flag=SearchNode.FLAG_RED), "actionRed_Flag", ), Flag( 2, labels["2"] if "2" in labels else tr.actions_flag_orange(), - icon.with_color(colors.FLAG2_FG), + icon.with_color(colors.FLAG_2), SearchNode(flag=SearchNode.FLAG_ORANGE), "actionOrange_Flag", ), Flag( 3, labels["3"] if "3" in labels else tr.actions_flag_green(), - icon.with_color(colors.FLAG3_FG), + icon.with_color(colors.FLAG_3), SearchNode(flag=SearchNode.FLAG_GREEN), "actionGreen_Flag", ), Flag( 4, labels["4"] if "4" in labels else tr.actions_flag_blue(), - icon.with_color(colors.FLAG4_FG), + icon.with_color(colors.FLAG_4), SearchNode(flag=SearchNode.FLAG_BLUE), "actionBlue_Flag", ), Flag( 5, labels["5"] if "5" in labels else tr.actions_flag_pink(), - icon.with_color(colors.FLAG5_FG), + icon.with_color(colors.FLAG_5), SearchNode(flag=SearchNode.FLAG_PINK), "actionPink_Flag", ), Flag( 6, labels["6"] if "6" in labels else tr.actions_flag_turquoise(), - icon.with_color(colors.FLAG6_FG), + icon.with_color(colors.FLAG_6), SearchNode(flag=SearchNode.FLAG_TURQUOISE), "actionTurquoise_Flag", ), Flag( 7, labels["7"] if "7" in labels else tr.actions_flag_purple(), - icon.with_color(colors.FLAG7_FG), + icon.with_color(colors.FLAG_7), SearchNode(flag=SearchNode.FLAG_PURPLE), "actionPurple_Flag", ), diff --git a/qt/aqt/stylesheets.py b/qt/aqt/stylesheets.py index 5a27df1e8..960b9015d 100644 --- a/qt/aqt/stylesheets.py +++ b/qt/aqt/stylesheets.py @@ -1,6 +1,6 @@ # Copyright: Ankitects Pty Ltd and contributors # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -from aqt import colors +from aqt import colors, props from aqt.theme import ThemeManager @@ -16,14 +16,14 @@ QLineEdit, QListWidget, QTreeWidget, QListView {{ - border: 1px solid {tm.color(colors.BORDER)}; - border-radius: 5px; + border: 1px solid {tm.var(colors.BORDER)}; + border-radius: {tm.var(props.BORDER_RADIUS)}; }} QLineEdit {{ padding: 2px; }} QLineEdit:focus {{ - border-color: {tm.color(colors.FOCUS_BORDER)}; + border-color: {tm.var(colors.BORDER_FOCUS)}; }} QPushButton {{ margin-top: 1px; @@ -34,7 +34,7 @@ QSpinBox {{ padding: 2px 6px; }} QToolTip {{ - background: {tm.color(colors.TOOLTIP_BG)}; + background: {tm.var(colors.CANVAS_OVERLAY)}; }} """ return buf @@ -43,31 +43,33 @@ QToolTip {{ def button_styles(tm: ThemeManager, buf: str) -> str: buf += f""" QPushButton, +QTabBar::tab:!selected, QComboBox:!editable {{ background: qlineargradient( spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, - stop:0 {tm.color(colors.BUTTON_GRADIENT_START)}, - stop:1 {tm.color(colors.BUTTON_GRADIENT_END)} + stop:0 {tm.var(colors.BUTTON_GRADIENT_START)}, + stop:1 {tm.var(colors.BUTTON_GRADIENT_END)} ); }} QPushButton:hover, +QTabBar::tab:hover, QComboBox:!editable:hover {{ background: qlineargradient( spread:pad, x1:0.5, y1:0, x2:0.5, y2:1.25, - stop:0 {tm.color(colors.BUTTON_HOVER_GRADIENT_START)}, - stop:1 {tm.color(colors.BUTTON_HOVER_GRADIENT_END)} + stop:0 {tm.var(colors.BUTTON_HOVER_GRADIENT_START)}, + stop:1 {tm.var(colors.BUTTON_HOVER_GRADIENT_END)} ); }} QPushButton:pressed, QComboBox:!editable:pressed {{ - border: 1px solid {tm.color(colors.BUTTON_PRESSED_BORDER)}; + border: 1px solid {tm.var(colors.BUTTON_PRESSED_BORDER)}; background: qlineargradient( spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, - stop:0 {tm.color(colors.BUTTON_PRESSED_SHADOW)}, - stop:0.1 {tm.color(colors.BUTTON_GRADIENT_START)}, - stop:0.9 {tm.color(colors.BUTTON_GRADIENT_END)}, - stop:1 {tm.color(colors.BUTTON_PRESSED_SHADOW)}, + stop:0 {tm.var(colors.BUTTON_PRESSED_SHADOW)}, + stop:0.1 {tm.var(colors.BUTTON_GRADIENT_START)}, + stop:0.9 {tm.var(colors.BUTTON_GRADIENT_END)}, + stop:1 {tm.var(colors.BUTTON_PRESSED_SHADOW)}, ); }} """ @@ -83,7 +85,7 @@ QComboBox:editable:on, QComboBox:editable:focus, QComboBox::drop-down:focus:editable, QComboBox::drop-down:pressed {{ - border-color: {tm.color(colors.FOCUS_BORDER)}; + border-color: {tm.var(colors.BORDER_FOCUS)}; }} QComboBox:on {{ border-bottom: none; @@ -91,13 +93,13 @@ QComboBox:on {{ border-bottom-left-radius: 0; }} QComboBox::item {{ - color: {tm.color(colors.TEXT_FG)}; - background: {tm.color(colors.FRAME_BG)}; + color: {tm.var(colors.FG)}; + background: {tm.var(colors.CANVAS_ELEVATED)}; }} QComboBox::item:selected {{ - background: {tm.color(colors.HIGHLIGHT_BG)}; - color: {tm.color(colors.HIGHLIGHT_FG)}; + background: {tm.var(colors.HIGHLIGHT_BG)}; + color: {tm.var(colors.HIGHLIGHT_FG)}; }} QComboBox::item::icon:selected {{ position: absolute; @@ -108,9 +110,9 @@ QComboBox::drop-down {{ padding: 2px; width: 16px; subcontrol-position: top right; - border: 1px solid {tm.color(colors.BUTTON_BORDER)}; - border-top-right-radius: 5px; - border-bottom-right-radius: 5px; + border: 1px solid {tm.var(colors.BUTTON_BORDER)}; + border-top-right-radius: {tm.var(props.BORDER_RADIUS)}; + border-bottom-right-radius: {tm.var(props.BORDER_RADIUS)}; }} QComboBox::down-arrow {{ image: url(icons:chevron-down.svg); @@ -118,15 +120,15 @@ QComboBox::down-arrow {{ QComboBox::drop-down {{ background: qlineargradient( spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, - stop:0 {tm.color(colors.BUTTON_PRIMARY_GRADIENT_START)}, - stop:1 {tm.color(colors.BUTTON_PRIMARY_GRADIENT_END)} + stop:0 {tm.var(colors.BUTTON_PRIMARY_GRADIENT_START)}, + stop:1 {tm.var(colors.BUTTON_PRIMARY_GRADIENT_END)} ); }} QComboBox::drop-down:hover {{ background: qlineargradient( spread:pad, x1:0.5, y1:0, x2:0.5, y2:1.25, - stop:0 {tm.color(colors.BUTTON_PRIMARY_HOVER_GRADIENT_START)}, - stop:1 {tm.color(colors.BUTTON_PRIMARY_HOVER_GRADIENT_END)} + stop:0 {tm.var(colors.BUTTON_PRIMARY_HOVER_GRADIENT_START)}, + stop:1 {tm.var(colors.BUTTON_PRIMARY_HOVER_GRADIENT_END)} ); }} """ @@ -136,48 +138,45 @@ QComboBox::drop-down:hover {{ def tabwidget_styles(tm: ThemeManager, buf: str) -> str: buf += f""" QTabWidget {{ - border-radius: 5px; - border: none; + border-radius: {tm.var(props.BORDER_RADIUS)}; background: none; }} QTabWidget::pane {{ - border: 1px solid {tm.color(colors.FRAME_BG)}; - border-radius: 5px; - background: {tm.color(colors.FRAME_BG)}; + top: -15px; + padding-top: 1em; + background: {tm.var(colors.CANVAS_ELEVATED)}; + border: 1px solid {tm.var(colors.BORDER_SUBTLE)}; + border-radius: {tm.var(props.BORDER_RADIUS)}; +}} +QTabWidget::tab-bar {{ + alignment: center; }} QTabBar::tab {{ background: none; - border-top-left-radius: 5px; - border-top-right-radius: 5px; - padding: 5px 10px; - margin-bottom: 0px; -}} -QTabBar::tab:!selected:hover, -QTabBar::tab:selected {{ - background: {tm.color(colors.FRAME_BG)}; -}} -QTabBar::tab:selected {{ - margin-bottom: -1px; -}} -QTabBar::tab:!selected {{ - margin-top: 5px; - background: {tm.color(colors.WINDOW_BG)}; + padding: 4px 8px; + min-width: 8ex; }} QTabBar::tab {{ - min-width: 8ex; - padding: 5px 10px 5px 10px; + border: 1px solid {tm.var(colors.BORDER_SUBTLE)}; +}} +QTabBar::tab:first {{ + border-top-left-radius: {tm.var(props.BORDER_RADIUS)}; + border-bottom-left-radius: {tm.var(props.BORDER_RADIUS)}; +}} +QTabBar::tab:!first {{ + margin-left: -1px; +}} +QTabBar::tab:last {{ + border-top-right-radius: {tm.var(props.BORDER_RADIUS)}; + border-bottom-right-radius: {tm.var(props.BORDER_RADIUS)}; }} QTabBar::tab:selected {{ - border-bottom-color: none; -}} -QTabBar::tab:bottom:selected {{ - border-top-color: none; -}} -QTabBar::tab:previous-selected {{ - border-top-left-radius: 0; -}} -QTabBar::tab:next-selected {{ - border-top-right-radius: 0; + color: white; + background: qlineargradient( + spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, + stop:0 {tm.var(colors.BUTTON_PRIMARY_GRADIENT_START)}, + stop:1 {tm.var(colors.BUTTON_PRIMARY_GRADIENT_END)} + ); }} """ return buf @@ -186,49 +185,53 @@ QTabBar::tab:next-selected {{ def table_styles(tm: ThemeManager, buf: str) -> str: buf += f""" QTableView {{ - margin: -1px -1px 1px -1px; background: none; - border: 2px solid {tm.color(colors.WINDOW_BG)}; - border-radius: 5px; + top: 2px; + border-left: 1px solid {tm.var(colors.BORDER_SUBTLE)}; + border-radius: {tm.var(props.BORDER_RADIUS)}; + gridline-color: {tm.var(colors.BORDER_SUBTLE)}; +}} +QHeaderView {{ + background: {tm.var(colors.CANVAS)}; }} QHeaderView::section {{ - border: 2px solid {tm.color(colors.WINDOW_BG)}; - margin: -1px; + border: 1px solid {tm.var(colors.BORDER_SUBTLE)}; background: qlineargradient( spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, - stop:0 {tm.color(colors.BUTTON_GRADIENT_START)}, - stop:1 {tm.color(colors.BUTTON_GRADIENT_END)} + stop:0 {tm.var(colors.BUTTON_GRADIENT_START)}, + stop:1 {tm.var(colors.BUTTON_GRADIENT_END)} ); }} QHeaderView::section:pressed {{ - border: 1px solid {tm.color(colors.BUTTON_PRESSED_BORDER)}; + border: 1px solid {tm.var(colors.BUTTON_PRESSED_BORDER)}; background: qlineargradient( spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, - stop:0 {tm.color(colors.BUTTON_PRESSED_SHADOW)}, - stop:0.1 {tm.color(colors.BUTTON_GRADIENT_START)}, - stop:0.9 {tm.color(colors.BUTTON_GRADIENT_END)}, - stop:1 {tm.color(colors.BUTTON_PRESSED_SHADOW)}, + stop:0 {tm.var(colors.BUTTON_PRESSED_SHADOW)}, + stop:0.1 {tm.var(colors.BUTTON_GRADIENT_START)}, + stop:0.9 {tm.var(colors.BUTTON_GRADIENT_END)}, + stop:1 {tm.var(colors.BUTTON_PRESSED_SHADOW)}, ); }} QHeaderView::section:hover {{ background: qlineargradient( spread:pad, x1:0.5, y1:0, x2:0.5, y2:1.25, - stop:0 {tm.color(colors.BUTTON_HOVER_GRADIENT_START)}, - stop:1 {tm.color(colors.BUTTON_HOVER_GRADIENT_END)} + stop:0 {tm.var(colors.BUTTON_HOVER_GRADIENT_START)}, + stop:1 {tm.var(colors.BUTTON_HOVER_GRADIENT_END)} ); }} QHeaderView::section:first {{ - border-top: 2px solid {tm.color(colors.WINDOW_BG)}; - border-left: 2px solid {tm.color(colors.WINDOW_BG)}; - border-top-left-radius: 5px; + margin-left: -1px; + border-top: 1px solid {tm.var(colors.BORDER_SUBTLE)}; + border-left: 1px solid {tm.var(colors.BORDER_SUBTLE)}; + border-top-left-radius: {tm.var(props.BORDER_RADIUS)}; }} QHeaderView::section:!first {{ border-left: none; }} QHeaderView::section:last {{ - border-top: 2px solid {tm.color(colors.WINDOW_BG)}; - border-right: 2px solid {tm.color(colors.WINDOW_BG)}; - border-top-right-radius: 5px; + border-top: 1px solid {tm.var(colors.BORDER_SUBTLE)}; + border-right: 1px solid {tm.var(colors.BORDER_SUBTLE)}; + border-top-right-radius: {tm.var(props.BORDER_RADIUS)}; }} QHeaderView::section:next-selected {{ border-right: none; @@ -237,11 +240,11 @@ QHeaderView::section:previous-selected {{ border-left: none; }} QHeaderView::section:only-one {{ - border-left: 2px solid {tm.color(colors.WINDOW_BG)}; - border-top: 2px solid {tm.color(colors.WINDOW_BG)}; - border-right: 2px solid {tm.color(colors.WINDOW_BG)}; - border-top-left-radius: 5px; - border-top-right-radius: 5px; + border-left: 1px solid {tm.var(colors.BORDER_SUBTLE)}; + border-top: 1px solid {tm.var(colors.BORDER_SUBTLE)}; + border-right: 1px solid {tm.var(colors.CANVAS)}; + border-top-left-radius: {tm.var(props.BORDER_RADIUS)}; + border-top-right-radius: {tm.var(props.BORDER_RADIUS)}; }} QHeaderView::up-arrow, QHeaderView::down-arrow {{ @@ -264,41 +267,41 @@ QSpinBox::up-button, QSpinBox::down-button {{ subcontrol-origin: border; width: 16px; - border: 1px solid {tm.color(colors.BUTTON_BORDER)}; + border: 1px solid {tm.var(colors.BUTTON_BORDER)}; background: qlineargradient( spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, - stop:0 {tm.color(colors.BUTTON_PRIMARY_GRADIENT_START)}, - stop:1 {tm.color(colors.BUTTON_PRIMARY_GRADIENT_END)} + stop:0 {tm.var(colors.BUTTON_PRIMARY_GRADIENT_START)}, + stop:1 {tm.var(colors.BUTTON_PRIMARY_GRADIENT_END)} ); }} QSpinBox::up-button:pressed, QSpinBox::down-button:pressed {{ - border: 1px solid {tm.color(colors.BUTTON_PRESSED_BORDER)}; + border: 1px solid {tm.var(colors.BUTTON_PRESSED_BORDER)}; background: qlineargradient( spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, - stop:0 {tm.color(colors.BUTTON_PRESSED_SHADOW)}, - stop:0.1 {tm.color(colors.BUTTON_PRIMARY_GRADIENT_START)}, - stop:0.9 {tm.color(colors.BUTTON_PRIMARY_GRADIENT_END)}, - stop:1 {tm.color(colors.BUTTON_PRESSED_SHADOW)}, + stop:0 {tm.var(colors.BUTTON_PRESSED_SHADOW)}, + stop:0.1 {tm.var(colors.BUTTON_PRIMARY_GRADIENT_START)}, + stop:0.9 {tm.var(colors.BUTTON_PRIMARY_GRADIENT_END)}, + stop:1 {tm.var(colors.BUTTON_PRESSED_SHADOW)}, ); }} QSpinBox::up-button:hover, QSpinBox::down-button:hover {{ background: qlineargradient( spread:pad, x1:0.5, y1:0, x2:0.5, y2:1.25, - stop:0 {tm.color(colors.BUTTON_PRIMARY_HOVER_GRADIENT_START)}, - stop:1 {tm.color(colors.BUTTON_PRIMARY_HOVER_GRADIENT_END)} + stop:0 {tm.var(colors.BUTTON_PRIMARY_HOVER_GRADIENT_START)}, + stop:1 {tm.var(colors.BUTTON_PRIMARY_HOVER_GRADIENT_END)} ); }} QSpinBox::up-button {{ margin-bottom: -1px; subcontrol-position: top right; - border-top-right-radius: 5px; + border-top-right-radius: {tm.var(props.BORDER_RADIUS)}; }} QSpinBox::down-button {{ margin-top: -1px; subcontrol-position: bottom right; - border-bottom-right-radius: 5px; + border-bottom-right-radius: {tm.var(props.BORDER_RADIUS)}; }} QSpinBox::up-arrow {{ image: url(icons:chevron-up.svg); @@ -322,7 +325,7 @@ QSpinBox::down-arrow:hover {{ }} QSpinBox::up-button:disabled, QSpinBox::up-button:off, QSpinBox::down-button:disabled, QSpinBox::down-button:off {{ - background: {tm.color(colors.BUTTON_PRIMARY_DISABLED)}; + background: {tm.var(colors.BUTTON_PRIMARY_DISABLED)}; }} """ return buf @@ -335,17 +338,17 @@ QAbstractScrollArea::corner {{ border: none; }} QScrollBar {{ - background-color: {tm.color(colors.WINDOW_BG)}; + background-color: {tm.var(colors.CANVAS)}; }} QScrollBar::handle {{ - border-radius: 5px; - background-color: {tm.color(colors.SCROLLBAR_BG)}; + border-radius: {tm.var(props.BORDER_RADIUS)}; + background-color: {tm.var(colors.SCROLLBAR_BG)}; }} QScrollBar::handle:hover {{ - background-color: {tm.color(colors.SCROLLBAR_HOVER_BG)}; + background-color: {tm.var(colors.SCROLLBAR_BG_HOVER)}; }} QScrollBar::handle:pressed {{ - background-color: {tm.color(colors.SCROLLBAR_ACTIVE_BG)}; + background-color: {tm.var(colors.SCROLLBAR_BG_ACTIVE)}; }} QScrollBar:horizontal {{ height: 12px; @@ -377,8 +380,8 @@ def win10_styles(tm: ThemeManager, buf: str) -> str: # also set for border to apply buf += f""" QMenuBar {{ - border-bottom: 1px solid {tm.color(colors.BORDER)}; - background: {tm.color(colors.WINDOW_BG) if tm.night_mode else "white"}; + border-bottom: 1px solid {tm.var(colors.BORDER)}; + background: {tm.var(colors.CANVAS) if tm.night_mode else "white"}; }} """ @@ -386,7 +389,7 @@ QMenuBar {{ # to white as well, so set it back buf += f""" QTreeWidget {{ - background: {tm.color(colors.WINDOW_BG)}; + background: {tm.var(colors.CANVAS)}; }} """ diff --git a/qt/aqt/switch.py b/qt/aqt/switch.py index ca92fafbc..289688685 100644 --- a/qt/aqt/switch.py +++ b/qt/aqt/switch.py @@ -19,8 +19,8 @@ class Switch(QAbstractButton): radius: int = 10, left_label: str = "", right_label: str = "", - left_color: tuple[str, str] = colors.FLAG4_BG, - right_color: tuple[str, str] = colors.FLAG3_BG, + left_color: tuple[str, str] = colors.ACCENT_CARD, + right_color: tuple[str, str] = colors.ACCENT_NOTE, parent: QWidget = None, ) -> None: super().__init__(parent=parent) @@ -100,15 +100,12 @@ class Switch(QAbstractButton): ) def _paint_knob(self, painter: QPainter) -> None: - if theme_manager.night_mode: - color = QColor(theme_manager.DARK_MODE_BUTTON_BG_MIDPOINT) - else: - color = theme_manager.qcolor(colors.FRAME_BG) + color = theme_manager.qcolor(colors.BUTTON_GRADIENT_START) painter.setBrush(QBrush(color)) painter.drawEllipse(self._current_knob_rectangle()) def _paint_label(self, painter: QPainter) -> None: - painter.setPen(theme_manager.qcolor(colors.SLIGHTLY_GREY_TEXT)) + painter.setPen(theme_manager.qcolor(colors.FG)) font = painter.font() font.setPixelSize(int(1.2 * self._knob_radius)) painter.setFont(font) diff --git a/qt/aqt/theme.py b/qt/aqt/theme.py index 63b3318b3..713ffee72 100644 --- a/qt/aqt/theme.py +++ b/qt/aqt/theme.py @@ -145,13 +145,13 @@ class ThemeManager: "Returns body classes used when showing a card." return f"card card{card_ord+1} {self.body_class(night_mode)}" - def color(self, colors: tuple[str, str]) -> str: - """Given day/night colors, return the correct one for the current theme.""" + def var(self, vars: tuple[str, str]) -> str: + """Given day/night colors/props, return the correct one for the current theme.""" idx = 1 if self.night_mode else 0 - return colors[idx] + return vars[idx] def qcolor(self, colors: tuple[str, str]) -> QColor: - return QColor(self.color(colors)) + return QColor(self.var(colors)) def _determine_night_mode(self) -> bool: theme = aqt.mw.pm.theme() @@ -187,6 +187,7 @@ class ThemeManager: def _apply_style(self, app: QApplication) -> None: buf = "" + if not is_mac: from aqt.stylesheets import ( button_styles, @@ -224,6 +225,9 @@ class ThemeManager: if not self.night_mode: app.setStyle(QStyleFactory.create(self._default_style)) # type: ignore + self.default_palette.setColor( + QPalette.ColorRole.Window, self.qcolor(colors.CANVAS) + ) app.setPalette(self.default_palette) return @@ -232,11 +236,11 @@ class ThemeManager: palette = QPalette() - text_fg = self.qcolor(colors.TEXT_FG) - palette.setColor(QPalette.ColorRole.WindowText, text_fg) - palette.setColor(QPalette.ColorRole.ToolTipText, text_fg) - palette.setColor(QPalette.ColorRole.Text, text_fg) - palette.setColor(QPalette.ColorRole.ButtonText, text_fg) + text = self.qcolor(colors.FG) + palette.setColor(QPalette.ColorRole.WindowText, text) + palette.setColor(QPalette.ColorRole.ToolTipText, text) + palette.setColor(QPalette.ColorRole.Text, text) + palette.setColor(QPalette.ColorRole.ButtonText, text) hlbg = self.qcolor(colors.HIGHLIGHT_BG) hlbg.setAlpha(64) @@ -245,18 +249,21 @@ class ThemeManager: ) palette.setColor(QPalette.ColorRole.Highlight, hlbg) - window_bg = self.qcolor(colors.WINDOW_BG) - palette.setColor(QPalette.ColorRole.Window, window_bg) - palette.setColor(QPalette.ColorRole.AlternateBase, window_bg) + canvas = self.qcolor(colors.CANVAS) + palette.setColor(QPalette.ColorRole.Window, canvas) + palette.setColor(QPalette.ColorRole.AlternateBase, canvas) palette.setColor(QPalette.ColorRole.Button, QColor("#454545")) - frame_bg = self.qcolor(colors.FRAME_BG) - palette.setColor(QPalette.ColorRole.Base, frame_bg) - palette.setColor(QPalette.ColorRole.ToolTipBase, frame_bg) + canvas_inset = self.qcolor(colors.CANVAS_INSET) + palette.setColor(QPalette.ColorRole.Base, canvas_inset) + palette.setColor(QPalette.ColorRole.ToolTipBase, canvas_inset) - disabled_color = self.qcolor(colors.DISABLED) - palette.setColor(QPalette.ColorRole.PlaceholderText, disabled_color) + palette.setColor( + QPalette.ColorRole.PlaceholderText, self.qcolor(colors.FG_SUBTLE) + ) + + disabled_color = self.qcolor(colors.FG_DISABLED) palette.setColor( QPalette.ColorGroup.Disabled, QPalette.ColorRole.Text, disabled_color ) @@ -269,7 +276,7 @@ class ThemeManager: disabled_color, ) - palette.setColor(QPalette.ColorRole.Link, self.qcolor(colors.LINK)) + palette.setColor(QPalette.ColorRole.Link, self.qcolor(colors.ACCENT_LINK)) palette.setColor(QPalette.ColorRole.BrightText, Qt.GlobalColor.red) @@ -278,11 +285,11 @@ class ThemeManager: def _update_stat_colors(self) -> None: import anki.stats as s - s.colLearn = self.color(colors.NEW_COUNT) - s.colRelearn = self.color(colors.LEARN_COUNT) - s.colCram = self.color(colors.SUSPENDED_BG) - s.colSusp = self.color(colors.SUSPENDED_BG) - s.colMature = self.color(colors.REVIEW_COUNT) + s.colLearn = self.var(colors.STATE_NEW) + s.colRelearn = self.var(colors.STATE_LEARN) + s.colCram = self.var(colors.STATE_SUSPENDED) + s.colSusp = self.var(colors.STATE_SUSPENDED) + s.colMature = self.var(colors.STATE_REVIEW) s._legacy_nightmode = self._night_mode_preference diff --git a/qt/aqt/webview.py b/qt/aqt/webview.py index f68b58926..57d9b33e1 100644 --- a/qt/aqt/webview.py +++ b/qt/aqt/webview.py @@ -233,9 +233,7 @@ class AnkiWebView(QWebEngineView): self.set_title(title) self._page = AnkiWebPage(self._onBridgeCmd) # reduce flicker - self._page.setBackgroundColor( - self.get_window_bg_color(theme_manager.night_mode) - ) + self._page.setBackgroundColor(theme_manager.qcolor(colors.CANVAS)) # in new code, use .set_bridge_command() instead of setting this directly self.onBridgeCmd: Callable[[str], Any] = self.defaultOnBridgeCmd @@ -404,15 +402,6 @@ class AnkiWebView(QWebEngineView): else: return 3 - def get_window_bg_color(self, night_mode: bool) -> QColor: - if night_mode: - return QColor(colors.WINDOW_BG[1]) - elif is_mac: - # standard palette does not return correct window color on macOS - return QColor("#ececec") - else: - return theme_manager.default_palette.color(QPalette.ColorRole.Window) - def standard_css(self) -> str: palette = theme_manager.default_palette color_hl = palette.color(QPalette.ColorRole.Highlight).name() @@ -459,15 +448,12 @@ div[contenteditable="true"]:focus {{ zoom = self.app_zoom_factor() - window_bg_day = self.get_window_bg_color(False).name() - window_bg_night = self.get_window_bg_color(True).name() - return f""" -body {{ zoom: {zoom}; background-color: var(--window-bg); }} +body {{ zoom: {zoom}; background-color: var(--canvas); }} html {{ {font} }} {button_style} -:root {{ --window-bg: {window_bg_day} }} -:root[class*=night-mode] {{ --window-bg: {window_bg_night} }} +:root {{ --canvas: {colors.CANVAS[0]} }} +:root[class*=night-mode] {{ --canvas: {colors.CANVAS[1]} }} """ def stdHtml( @@ -711,9 +697,7 @@ html {{ {font} }} def on_theme_did_change(self) -> None: # avoid flashes if page reloaded - self._page.setBackgroundColor( - self.get_window_bg_color(theme_manager.night_mode) - ) + self._page.setBackgroundColor(theme_manager.qcolor(colors.CANVAS)) # update night-mode class, and legacy nightMode/night-mode body classes self.eval( f""" @@ -732,30 +716,3 @@ html {{ {font} }} }})(); """ ) - - def _fix_editor_background_color_and_show(self) -> None: - # The editor does not use our standard CSS, which takes care of matching the background - # colour of the webview to the window we're showing it in. This causes a difference in - # shades on Windows/Linux in day mode, that we need to work around. This is a temporary - # fix before the 2.1.50 release; with more time there may be a better way to do this. - - if theme_manager.night_mode: - # The styling changes are not required for night mode, and hiding+showing the - # webview causes a flash of black. - return - - self.hide() - - window_bg_day = self.get_window_bg_color(False).name() - css = f":root {{ --window-bg: {window_bg_day} }}" - self.evalWithCallback( - f""" -(function(){{ - const style = document.createElement('style'); - style.innerHTML = `{css}`; - document.head.appendChild(style); -}})(); -""", - # avoids FOUC - lambda _: self.show(), - ) diff --git a/qt/tools/extract_sass_colors.py b/qt/tools/extract_sass_colors.py deleted file mode 100644 index 219fd6a26..000000000 --- a/qt/tools/extract_sass_colors.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python3 -# Copyright: Ankitects Pty Ltd and contributors -# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html - -import json -import re -import sys - -input_scss = sys.argv[1] -output_py = sys.argv[2] - -colors = {} - -for line in open(input_scss): - line = line.strip() - if not line: - continue - m = re.match(r"--(.+): (.+);$", line) - if not m: - if ( - line != "}" - and not ":root" in line - and "Copyright" not in line - and "License" not in line - and "color-scheme" not in line - ): - print("failed to match", line) - continue - - var = m.group(1) - val = m.group(2) - - colors.setdefault(var, []).append(val) - -with open(output_py, "w") as buf: - buf.write( - """\ -# Copyright: Ankitects Pty Ltd and contributors -# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -""" - ) - buf.write("# this file is auto-generated from _vars.scss\n") - for color, (day, night) in colors.items(): - color = color.replace("-", "_").upper() - buf.write(f'{color} = ("{day}", "{night}")\n') diff --git a/qt/tools/extract_sass_vars.py b/qt/tools/extract_sass_vars.py new file mode 100644 index 000000000..7d59fe878 --- /dev/null +++ b/qt/tools/extract_sass_vars.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +# Copyright: Ankitects Pty Ltd and contributors +# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +import json +import re +import sys + +# bazel genrule "srcs" +vars_css = sys.argv[1] + +# bazel genrule "outs" +colors_py = sys.argv[2] +props_py = sys.argv[3] + +colors = {} +props = {} +reached_props = False + +for line in re.split(r"[;\{\}]", open(vars_css).read()): + line = line.strip() + + if not line: + continue + if "props" in line: + reached_props = True + + m = re.match(r"--(.+):(.+)$", line) + + if not m: + if ( + line != "}" + and not ":root" in line + and "Copyright" not in line + and "License" not in line + and "color-scheme" not in line + ): + print("failed to match", line) + continue + + var = m.group(1) + val = m.group(2) + + if reached_props: + props.setdefault(var, []).append(val) + else: + colors.setdefault(var, []).append(val) + + +copyright_notice = """\ +# Copyright: Ankitects Pty Ltd and contributors +# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +""" + +with open(colors_py, "w") as buf: + buf.write(copyright_notice) + buf.write("# this file is auto-generated from _vars.scss and _colors.scss\n") + + for color, val in colors.items(): + day = val[0] + night = val[1] if len(val) > 1 else day + + color = color.replace("-", "_").upper() + buf.write(f'{color} = ("{day}", "{night}")\n') + + +with open(props_py, "w") as buf: + buf.write(copyright_notice) + buf.write("# this file is auto-generated from _vars.scss\n") + + for prop, val in props.items(): + day = val[0] + night = val[1] if len(val) > 1 else day + + prop = prop.replace("-", "_").upper() + buf.write(f'{prop} = ("{day}", "{night}")\n') diff --git a/sass/BUILD.bazel b/sass/BUILD.bazel index 2e5ac043c..7dc74accf 100644 --- a/sass/BUILD.bazel +++ b/sass/BUILD.bazel @@ -3,21 +3,29 @@ load("@io_bazel_rules_sass//:defs.bzl", "sass_library") sass_library( name = "base_lib", srcs = [ - "_fusion-vars.scss", - "_vars.scss", "base.scss", "bootstrap-dark.scss", ], visibility = ["//visibility:public"], deps = [ + "vars_lib", "//sass/bootstrap", ], ) +sass_library( + name = "vars_lib", + srcs = [ + "_colors.scss", + "_functions.scss", + "_vars.scss", + ], + visibility = ["//visibility:public"], +) + sass_library( name = "buttons_lib", srcs = [ - "_fusion-vars.scss", "buttons.scss", ], visibility = ["//visibility:public"], @@ -62,7 +70,9 @@ sass_library( name = "button_mixins_lib", srcs = [ "_button-mixins.scss", - "_fusion-vars.scss", + ], + deps = [ + "vars_lib", ], visibility = ["//visibility:public"], ) diff --git a/sass/_button-mixins.scss b/sass/_button-mixins.scss index 6dc2e186f..57126c0fe 100644 --- a/sass/_button-mixins.scss +++ b/sass/_button-mixins.scss @@ -1,6 +1,6 @@ /* Copyright: Ankitects Pty Ltd and contributors * License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */ -@use "fusion-vars"; +@use "vars"; @use "sass:color"; @import "bootstrap/scss/functions"; @@ -19,102 +19,74 @@ border-bottom-right-radius: var(--border-right-radius); } -$btn-base-color-day: white; - -@mixin btn-day-base { - color: var(--text-fg); - background-color: $btn-base-color-day; - border-color: var(--medium-border) !important; -} - -@mixin btn-day($with-hover: true, $with-active: true, $with-disabled: true) { - .btn-day { - @include btn-day-base; - @content ($btn-base-color-day); - - @if ($with-hover) { - &:hover, - &.hover { - background-color: color.scale($btn-base-color-day, $lightness: -20%); - } - } - - @if ($with-active) { - &:active, - &.active { - @include impressed-shadow(0.25); - } - - &:active.active { - box-shadow: none; - } - } - - @if ($with-disabled) { - &[disabled] { - background-color: $btn-base-color-day !important; - box-shadow: none !important; - } - } - } -} - -$btn-base-color-night: fusion-vars.$button-border; - -@mixin btn-night-base { - color: var(--text-fg); - background: linear-gradient( - 180deg, - fusion-vars.$button-gradient-start 0%, - fusion-vars.$button-gradient-end 100% - ); -} - -@mixin btn-night($with-hover: true, $with-active: true, $with-disabled: true) { - .btn-night { - @include btn-night-base; - @content ($btn-base-color-night); - - border: 1px solid fusion-vars.$button-border; +@mixin base( + $selector: button, + $with-primary: false, + $with-hover: true, + $with-active: true, + $with-disabled: true +) { + #{$selector} { -webkit-appearance: none; + border: 1px solid var(--button-border); + + color: var(--fg); + background: linear-gradient( + 180deg, + var(--button-gradient-start) 0%, + var(--button-gradient-end) 100% + ); @if ($with-hover) { - &:hover, - &.hover { + &:hover { background: linear-gradient( 180deg, - color.scale(fusion-vars.$button-gradient-start, $lightness: 20%) 0%, - color.scale(fusion-vars.$button-gradient-end, $lightness: 20%) 100% + var(--button-hover-gradient-start) 0%, + var(--button-hover-gradient-end) 100% ); - border-color: color.scale(fusion-vars.$button-border, $lightness: 20%); + + border-color: var(--button-hover-border); + } + } + + @if ($with-primary) { + &.btn-primary { + color: white; + background: linear-gradient( + 180deg, + var(--button-primary-gradient-start) 0%, + var(--button-primary-gradient-end) 100% + ); + &:hover { + background: linear-gradient( + 180deg, + var(--button-primary-hover-gradient-start) 0%, + var(--button-primary-hover-gradient-end) 100% + ); + } } } @if ($with-active) { - &:active, - &.active { + &:active { @include impressed-shadow(0.35); - border-color: color.scale($btn-base-color-night, $lightness: -20%); - } - - &:active.active { box-shadow: none; - border-color: $btn-base-color-night; + border-color: var(--button-border); } } @if ($with-disabled) { &[disabled] { - background-color: $btn-base-color-night !important; + color: var(--fg-disabled); + background-color: var(--button-gradient-end) !important; box-shadow: none !important; - border-color: $btn-base-color-night !important; + border-color: var(--button-gradient-end) !important; } } } } -// should be similar to -webkit-focus-ring-color -$focus-color: rgba(21 97 174); +$focus-color: vars.color(shadow-focus); @function down-arrow($color) { @return url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='transparent' stroke='#{$color}' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"); diff --git a/sass/_colors.scss b/sass/_colors.scss new file mode 100644 index 000000000..17226fbdf --- /dev/null +++ b/sass/_colors.scss @@ -0,0 +1,213 @@ +/* Copyright: Ankitects Pty Ltd and contributors + * License: GNU AGPL, version 3 or later, http://www.gnu.org/licenses/agpl.html + * + * Anki Color Palette + * custom gray, rest from Tailwind CSS v3 palette + * ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */ + +$colors: ( + lightgray: ( + 0: #fcfcfc, + 1: #fafafa, + 2: #f5f5f5, + 3: #eeeeee, + 4: #e4e4e4, + 5: #d6d6d6, + 6: #c4c4c4, + 7: #afafaf, + 8: #999999, + 9: #858585, + ), + darkgray: ( + 0: #737373, + 1: #636363, + 2: #545454, + 3: #454545, + 4: #363636, + 5: #2c2c2c, + 6: #252525, + 7: #1f1f1f, + 8: #141414, + 9: #020202, + ), + red: ( + 0: #fef2f2, + 1: #fee2e2, + 2: #fecaca, + 3: #fca5a5, + 4: #f87171, + 5: #ef4444, + 6: #dc2626, + 7: #b91c1c, + 8: #991b1b, + 9: #7f1d1d, + ), + orange: ( + 0: #fff7ed, + 1: #ffedd5, + 2: #fed7aa, + 3: #fdba74, + 4: #fb923c, + 5: #f97316, + 6: #ea580c, + 7: #c2410c, + 8: #9a3412, + 9: #7c2d12, + ), + amber: ( + 0: #fffbeb, + 1: #fef3c7, + 2: #fde68a, + 3: #fcd34d, + 4: #fbbf24, + 5: #f59e0b, + 6: #d97706, + 7: #b45309, + 8: #92400e, + 9: #78350f, + ), + yellow: ( + 0: #fefce8, + 1: #fef9c3, + 2: #fef08a, + 3: #fde047, + 4: #facc15, + 5: #eab308, + 6: #ca8a04, + 7: #a16207, + 8: #854d0e, + 9: #713f12, + ), + lime: ( + 0: #f7fee7, + 1: #ecfccb, + 2: #d9f99d, + 3: #bef264, + 4: #a3e635, + 5: #84cc16, + 6: #65a30d, + 7: #4d7c0f, + 8: #3f6212, + 9: #365314, + ), + green: ( + 0: #f0fdf4, + 1: #dcfce7, + 2: #bbf7d0, + 3: #86efac, + 4: #4ade80, + 5: #22c55e, + 6: #16a34a, + 7: #15803d, + 8: #166534, + 9: #14532d, + ), + teal: ( + 0: #f0fdfa, + 1: #ccfbf1, + 2: #99f6e4, + 3: #5eead4, + 4: #2dd4bf, + 5: #14b8a6, + 6: #0d9488, + 7: #0f766e, + 8: #115e59, + 9: #134e4a, + ), + cyan: ( + 0: #ecfeff, + 1: #cffafe, + 2: #a5f3fc, + 3: #67e8f9, + 4: #22d3ee, + 5: #06b6d4, + 6: #0891b2, + 7: #0e7490, + 8: #155e75, + 9: #164e63, + ), + sky: ( + 0: #f0f9ff, + 1: #e0f2fe, + 2: #bae6fd, + 3: #7dd3fc, + 4: #38bdf8, + 5: #0ea5e9, + 6: #0284c7, + 7: #0369a1, + 8: #075985, + 9: #0c4a6e, + ), + blue: ( + 0: #eff6ff, + 1: #dbeafe, + 2: #bfdbfe, + 3: #93c5fd, + 4: #60a5fa, + 5: #3b82f6, + 6: #2563eb, + 7: #1d4ed8, + 8: #1e40af, + 9: #1e3a8a, + ), + indigo: ( + 0: #eef2ff, + 1: #e0e7ff, + 2: #c7d2fe, + 3: #a5b4fc, + 4: #818cf8, + 5: #6366f1, + 6: #4f46e5, + 7: #4338ca, + 8: #3730a3, + 9: #312e81, + ), + violet: ( + 0: #f5f3ff, + 1: #ede9fe, + 2: #ddd6fe, + 3: #c4b5fd, + 4: #a78bfa, + 5: #8b5cf6, + 6: #7c3aed, + 7: #6d28d9, + 8: #5b21b6, + 9: #4c1d95, + ), + purple: ( + 0: #faf5ff, + 1: #f3e8ff, + 2: #e9d5ff, + 3: #d8b4fe, + 4: #c084fc, + 5: #a855f7, + 6: #9333ea, + 7: #7e22ce, + 8: #6b21a8, + 9: #581c87, + ), + fuchsia: ( + 0: #fdf4ff, + 1: #fae8ff, + 2: #f5d0fe, + 3: #f0abfc, + 4: #e879f9, + 5: #d946ef, + 6: #c026d3, + 7: #a21caf, + 8: #86198f, + 9: #701a75, + ), + pink: ( + 0: #fdf2f8, + 1: #fce7f3, + 2: #fbcfe8, + 3: #f9a8d4, + 4: #f472b6, + 5: #ec4899, + 6: #db2777, + 7: #be185d, + 8: #9d174d, + 9: #831843, + ), +); diff --git a/sass/_functions.scss b/sass/_functions.scss new file mode 100644 index 000000000..3b1363f15 --- /dev/null +++ b/sass/_functions.scss @@ -0,0 +1,55 @@ +/* Copyright: Ankitects Pty Ltd and contributors + * License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */ + +@use "sass:map"; +@use "sass:list"; + +@function create-vars-from-map($map, $theme, $name: "-", $output: ()) { + @each $key, $value in $map { + @if $key == $theme { + @return map.set($output, $name, map.get($map, $key)); + } + @if type-of($value) == "map" { + @if $key == "default" { + $output: map-merge( + $output, + create-vars-from-map($value, $theme, #{$name}, $output) + ); + } @else { + $output: map-merge( + $output, + create-vars-from-map($value, $theme, #{$name}-#{$key}, $output) + ); + } + } + } + @return $output; +} + +@function map-deep-get($map, $keys) { + @each $key in $keys { + $map: map-get($map, $key); + } + @return $map; +} + +@function get-value-from-map($map, $keyword, $theme, $keys: ()) { + $i: str-index($keyword, "-"); + + @if $i { + @while $i { + $sub: str-slice($keyword, 0, $i - 1); + + @if list.length($keys) == 0 { + $keys: ($sub); + } @else { + $keys: list.append($keys, $sub); + } + $keyword: str-slice($keyword, $i + 1, -1); + $i: str-index($keyword, "-"); + } + } + $keys: list.join($keys, ($keyword, $theme)); + + @return map-deep-get($map, $keys); +} diff --git a/sass/_fusion-vars.scss b/sass/_fusion-vars.scss deleted file mode 100644 index 717d3450d..000000000 --- a/sass/_fusion-vars.scss +++ /dev/null @@ -1,7 +0,0 @@ -/* night-mode-specific colours */ -$button-gradient-start: #3f3f3f; -$button-gradient-end: #363636; -$button-outline: #202020; -$button-hover-bg: #404040; -$button-border: #202020; -$button-base-bg: #343434; diff --git a/sass/_vars.scss b/sass/_vars.scss index d0b1ab343..982a70cd5 100644 --- a/sass/_vars.scss +++ b/sass/_vars.scss @@ -1,113 +1,314 @@ /* Copyright: Ankitects Pty Ltd and contributors - * License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */ + * License: GNU AGPL, version 3 or later, http://www.gnu.org/licenses/agpl.html */ +@use "sass:map"; +@use "sass:color"; +@use "functions" as *; +@use "colors" as *; + +@function palette($key, $shade) { + $color: map.get($colors, $key); + @return map.get($color, $shade); +} + +$vars: ( + props: ( + border-radius: ( + default: 5px, + ), + ), + colors: ( + fg: ( + default: ( + light: palette(darkgray, 9), + dark: palette(lightgray, 0), + ), + subtle: ( + light: palette(darkgray, 6), + dark: palette(lightgray, 3), + ), + disabled: ( + light: palette(darkgray, 3), + dark: palette(lightgray, 6), + ), + faint: ( + light: palette(lightgray, 7), + dark: palette(darkgray, 2), + ), + ), + canvas: ( + default: ( + light: palette(lightgray, 3), + dark: palette(darkgray, 5), + ), + elevated: ( + light: white, + dark: palette(darkgray, 4), + ), + inset: ( + light: palette(lightgray, 4), + dark: palette(darkgray, 6), + ), + overlay: ( + light: white, + dark: black, + ), + code: ( + light: white, + dark: palette(darkgray, 6), + ), + ), + border: ( + default: ( + light: palette(lightgray, 7), + dark: palette(darkgray, 7), + ), + subtle: ( + light: palette(lightgray, 5), + dark: palette(darkgray, 4), + ), + focus: ( + light: palette(blue, 5), + dark: palette(blue, 5), + ), + ), + button: ( + border: ( + light: palette(lightgray, 6), + dark: palette(darkgray, 6), + ), + focus: ( + light: palette(cyan, 3), + dark: palette(cyan, 4), + ), + pressed: ( + shadow: ( + light: palette(lightgray, 7), + dark: palette(darkgray, 7), + ), + border: ( + light: palette(lightgray, 9), + dark: palette(darkgray, 9), + ), + ), + gradient: ( + start: ( + light: white, + dark: palette(darkgray, 3), + ), + end: ( + light: palette(lightgray, 1), + dark: palette(darkgray, 4), + ), + ), + hover: ( + gradient: ( + start: ( + light: palette(lightgray, 1), + dark: palette(darkgray, 2), + ), + end: ( + light: palette(lightgray, 3), + dark: palette(darkgray, 3), + ), + ), + border: ( + light: palette(lightgray, 8), + dark: palette(darkgray, 8), + ), + ), + primary: ( + gradient: ( + start: ( + light: palette(blue, 4), + dark: color.scale(palette(blue, 6), $saturation: -10%), + ), + end: ( + light: palette(blue, 6), + dark: color.scale(palette(blue, 8), $saturation: -10%), + ), + ), + hover: ( + gradient: ( + start: ( + light: palette(blue, 3), + dark: color.scale(palette(blue, 5), $saturation: -10%), + ), + end: ( + light: palette(blue, 5), + dark: color.scale(palette(blue, 7), $saturation: -10%), + ), + ), + ), + disabled: ( + light: palette(blue, 3), + dark: color.scale(palette(blue, 5), $saturation: -10%), + ), + ), + ), + scrollbar: ( + bg: ( + default: ( + light: palette(lightgray, 6), + dark: palette(darkgray, 4), + ), + hover: ( + light: palette(lightgray, 7), + dark: palette(darkgray, 3), + ), + active: ( + light: palette(lightgray, 8), + dark: palette(darkgray, 1), + ), + ), + ), + shadow: ( + default: ( + light: palette(lightgray, 8), + dark: palette(darkgray, 7), + ), + inset: ( + light: palette(lightgray, 9), + dark: palette(darkgray, 7), + ), + subtle: ( + light: palette(lightgray, 5), + dark: palette(darkgray, 6), + ), + focus: ( + default: palette(indigo, 5), + ), + ), + accent: ( + card: ( + light: palette(blue, 3), + dark: palette(blue, 4), + ), + note: ( + light: palette(green, 5), + dark: palette(green, 4), + ), + link: ( + light: palette(blue, 7), + dark: palette(blue, 2), + ), + danger: ( + light: palette(red, 5), + dark: palette(red, 4), + ), + ), + flag: ( + 1: ( + light: palette(red, 5), + dark: palette(red, 4), + ), + 2: ( + light: palette(orange, 4), + dark: palette(orange, 3), + ), + 3: ( + light: palette(green, 4), + dark: palette(green, 3), + ), + 4: ( + light: palette(blue, 5), + dark: palette(blue, 4), + ), + 5: ( + light: palette(fuchsia, 4), + dark: palette(fuchsia, 3), + ), + 6: ( + light: palette(teal, 4), + dark: palette(teal, 3), + ), + 7: ( + light: palette(purple, 5), + dark: palette(purple, 4), + ), + ), + state: ( + new: ( + light: palette(blue, 5), + dark: palette(blue, 3), + ), + learn: ( + light: palette(red, 6), + dark: palette(red, 4), + ), + review: ( + light: palette(green, 6), + dark: palette(green, 5), + ), + buried: ( + light: palette(amber, 5), + dark: palette(amber, 8), + ), + suspended: ( + light: palette(yellow, 4), + dark: palette(yellow, 1), + ), + marked: ( + light: palette(indigo, 2), + dark: palette(purple, 5), + ), + ), + highlight: ( + bg: ( + light: palette(blue, 3), + dark: palette(blue, 4), + ), + fg: ( + light: black, + dark: white, + ), + ), + ), +); + +@function color($keyword) { + @return var(--#{$keyword}); +} + +@function palette-of($keyword, $theme: default) { + $colors: map.get($vars, colors); + @return get-value-from-map($colors, $keyword, $theme); +} + +@function prop($keyword) { + @return var(--#{$keyword}); +} + +/*! colors */ :root { - --text-fg: black; - --window-bg: #ececec; - --frame-bg: white; - --border: #aaa; - --medium-border: #b6b6b6; - --faint-border: #e7e7e7; - --link: #00a; - --review-count: #0a0; - --new-count: #00a; - --learn-count: #c35617; - --zero-count: #ddd; - --slightly-grey-text: #333; - --highlight-bg: #77ccff; - --highlight-fg: black; - --disabled: #777; - --flag1-fg: #e25252; - --flag2-fg: #ffb347; - --flag3-fg: #54c414; - --flag4-fg: #578cff; - --flag5-fg: #ff82ee; - --flag6-fg: #00d1b5; - --flag7-fg: #9649dd; - --flag1-bg: #ff9b9b; - --flag2-bg: #ffb347; - --flag3-bg: #93e066; - --flag4-bg: #9dbcff; - --flag5-bg: #f5a8eb; - --flag6-bg: #7edbd7; - --flag7-bg: #cca3f1; - --buried-fg: #aaaa33; - --suspended-fg: #dd0; - --suspended-bg: #ffffb2; - --marked-bg: #cce; - --tooltip-bg: #fcfcfc; - --focus-border: #0969da; - --focus-shadow: rgba(9 105 218 / 0.3); - --code-bg: white; - --button-primary-gradient-start: #69b3fa; - --button-primary-gradient-end: #087fff; - --button-primary-hover-gradient-start: #69b3fa; - --button-primary-hover-gradient-end: #087fff; - --button-primary-disabled: #8fc5fc; - --button-gradient-start: white; - --button-gradient-end: #f6f6f6; - --button-hover-gradient-start: #fefefe; - --button-hover-gradient-end: #f1f1f1; - --button-pressed-shadow: #555; - --button-border: #666; - --button-pressed-border: #8f8f8f; - --scrollbar-bg: #d8d8d8; - --scrollbar-hover-bg: #d0d0d0; - --scrollbar-active-bg: #c8c8c8; + $colors: map.get($vars, colors); + @each $name, $val in create-vars-from-map($colors, light) { + #{$name}: #{$val}; + } + color-scheme: light; + &.night-mode { + @each $name, $val in create-vars-from-map($colors, dark) { + #{$name}: #{$val}; + } + color-scheme: dark; + } } -:root[class*="night-mode"] { - --text-fg: white; - --window-bg: #2f2f31; - --frame-bg: #3a3a3a; - --border: #1f1f1f; - --medium-border: #444; - --faint-border: #29292b; - --link: #77ccff; - --review-count: #5ccc00; - --new-count: #77ccff; - --learn-count: #ff935b; - --zero-count: #444; - --slightly-grey-text: #ccc; - --highlight-bg: #1e95df; - --highlight-fg: white; - --disabled: #777; - --flag1-fg: #ff7b7b; - --flag2-fg: #f5aa41; - --flag3-fg: #86ce5d; - --flag4-fg: #6f9dff; - --flag5-fg: #f097e4; - --flag6-fg: #5ccfca; - --flag7-fg: #9f63d3; - --flag1-bg: #aa5555; - --flag2-bg: #ac653a; - --flag3-bg: #559238; - --flag4-bg: #506aa3; - --flag5-bg: #975d8f; - --flag6-bg: #399185; - --flag7-bg: #624b77; - --buried-fg: #777733; - --suspended-fg: #ffffb2; - --suspended-bg: #aaaa33; - --marked-bg: #77c; - --tooltip-bg: #272727; - --focus-border: #316dca; - --focus-shadow: #194380; - --code-bg: #272822; - --button-primary-gradient-start: #1769e2; - --button-primary-gradient-end: #014996; - --button-primary-hover-gradient-start: #2877c2; - --button-primary-hover-gradient-end: #0d5db3; - --button-primary-disabled: #4977a1; - --button-gradient-start: #3f3f3f; - --button-gradient-end: #363636; - --button-hover-gradient-start: #434343; - --button-hover-gradient-end: #404040; - --button-pressed-shadow: #232323; - --button-border: #2f2f31; - --button-pressed-border: #0a0a0a; - --scrollbar-bg: #434343; - --scrollbar-hover-bg: #4e4e4e; - --scrollbar-active-bg: #464646; - color-scheme: dark; +/*! props */ +:root { + $props: map.get($vars, props); + @each $name, $val in create-vars-from-map($props, default) { + #{$name}: #{$val}; + } + @each $name, $val in create-vars-from-map($props, light) { + #{$name}: #{$val}; + } + &.night-mode { + @each $name, $val in create-vars-from-map($props, default) { + #{$name}: #{$val}; + } + @each $name, $val in create-vars-from-map($props, dark) { + #{$name}: #{$val}; + } + } } diff --git a/sass/base.scss b/sass/base.scss index 9dcd6552e..d5ce13df0 100644 --- a/sass/base.scss +++ b/sass/base.scss @@ -1,10 +1,10 @@ @use "vars"; @use "scrollbar"; -$body-color: var(--text-fg); -$body-bg: var(--window-bg); +$body-color: var(--fg); +$body-bg: var(--canvas); -$link-hover-color: var(--link); +$link-hover-color: var(--accent-link); $link-hover-decoration: none; $utilities: ( @@ -34,9 +34,10 @@ $utilities: ( body { overscroll-behavior: none; - @include scrollbar.custom; } +@include scrollbar.custom; + button { /* override transition for instant hover response */ transition: color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !important; @@ -69,7 +70,7 @@ samp { } .night-mode .form-select:disabled { - background-color: var(--disabled); + background-color: var(--fg-disabled); } .reduced-motion * { diff --git a/sass/bootstrap-dark.scss b/sass/bootstrap-dark.scss index 17de09341..e32e3ba92 100644 --- a/sass/bootstrap-dark.scss +++ b/sass/bootstrap-dark.scss @@ -2,16 +2,15 @@ * License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */ @use "vars"; -@use "fusion-vars"; @mixin night-mode { input, select { - background-color: var(--frame-bg); + background-color: var(--canvas-elevated); border-color: var(--border); &:focus { - background-color: var(--window-bg); + background-color: var(--canvas); } } } diff --git a/sass/bootstrap-tooltip.scss b/sass/bootstrap-tooltip.scss index a4d57e81d..4919e59db 100644 --- a/sass/bootstrap-tooltip.scss +++ b/sass/bootstrap-tooltip.scss @@ -1,6 +1,8 @@ /* Copyright: Ankitects Pty Ltd and contributors * License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */ +@use "vars"; + $tooltip-padding-y: 0.45rem; $tooltip-padding-x: 0.65rem; $tooltip-max-width: 300px; @@ -19,7 +21,7 @@ $tooltip-max-width: 300px; // the default code color in tooltips is difficult to read; we'll probably // want to add more of our own styling in the future code { - color: #ffaaaa; + color: palette(red, 0); direction: inherit; } } diff --git a/sass/buttons.scss b/sass/buttons.scss index e79b02310..f769e62b7 100644 --- a/sass/buttons.scss +++ b/sass/buttons.scss @@ -1,7 +1,7 @@ -@use "fusion-vars"; +@use "vars"; :root { - --focus-color: #0078d7; + --focus-color: #{vars.palette-of(shadow-focus)}; .isMac { --focus-color: rgba(0 103 244 / 0.247); @@ -20,50 +20,30 @@ } } -.isLin { - button { - font-size: 14px; +button { + -webkit-appearance: none; + color: vars.color(fg); - -webkit-appearance: none; - border-radius: 5px; - padding: 5px; - border: 1px solid var(--border); + background: linear-gradient( + 180deg, + vars.color(button-gradient-start) 0%, + vars.color(button-gradient-end) 100% + ); + border: 1px solid vars.color(button-border); + + border-radius: vars.prop(border-radius); + padding: 3px 10px 3px; + + &:focus { + outline: none; + box-shadow: 0 0 0 1px var(--focus-color); } } -.nightMode { - button { - -webkit-appearance: none; - color: var(--text-fg); - - /* match the fusion button gradient */ - background: linear-gradient( - 0deg, - fusion-vars.$button-gradient-start 0%, - fusion-vars.$button-gradient-end 100% - ); - border: 1px solid fusion-vars.$button-border; - - border-radius: 5px; - padding: 3px 10px 3px; - - &:focus { - outline: none; - box-shadow: 0 0 0 2px var(--focus-color); - } - } - - button:hover { - background: fusion-vars.$button-hover-bg; - } -} - -/* imitate standard macOS dark mode buttons */ -.isMac.nightMode.macos-dark-mode button:not(.linkb) { - background: #656565; - box-shadow: 0 1px 2px #222222; - border-top-color: #848484; - border-width: 0.5px 0 0; - padding: 2px 15px; - color: #e5e5e5; +button:hover { + background: linear-gradient( + 180deg, + vars.color(button-hover-gradient-start) 0%, + vars.color(button-hover-gradient-end) 100% + ); } diff --git a/sass/card-counts.scss b/sass/card-counts.scss index 2ddc5c947..8539313f9 100644 --- a/sass/card-counts.scss +++ b/sass/card-counts.scss @@ -1,21 +1,21 @@ .review-count { - color: var(--review-count); + color: var(--state-review); } .new-count { - color: var(--new-count); + color: var(--state-new); } .learn-count { - color: var(--learn-count); + color: var(--state-learn); } .zero-count { - color: var(--zero-count); + color: var(--fg-faint); } .bury-count { - color: var(--disabled); + color: var(--fg-disabled); font-weight: bold; margin-inline-start: 2px; diff --git a/sass/core.scss b/sass/core.scss index 0fa86894c..9cd31d459 100644 --- a/sass/core.scss +++ b/sass/core.scss @@ -8,14 +8,14 @@ } body { - color: var(--text-fg); - background: var(--window-bg); + color: var(--fg); + background: var(--canvas); margin: 1em; transition: opacity 0.5s ease-out; overscroll-behavior: none; } a { - color: var(--link); + color: var(--accent-link); text-decoration: none; } diff --git a/sass/night-mode.scss b/sass/night-mode.scss index 3a7eff2dd..fb5a5c3db 100644 --- a/sass/night-mode.scss +++ b/sass/night-mode.scss @@ -2,10 +2,10 @@ * License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */ @mixin input { - background-color: var(--frame-bg); + background-color: var(--canvas-elevated); border-color: var(--border); &:focus { - background-color: var(--window-bg); + background-color: var(--canvas); } } diff --git a/sass/scrollbar.scss b/sass/scrollbar.scss index 4b47b91d8..ebe35594e 100644 --- a/sass/scrollbar.scss +++ b/sass/scrollbar.scss @@ -2,48 +2,50 @@ * License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */ @use "vars"; -@use "fusion-vars"; @mixin custom { - ::-webkit-scrollbar { - background-color: var(--window-bg); + .isWin, + .isLin { + ::-webkit-scrollbar { + background-color: vars.color(canvas); - &:horizontal { - height: 12px; + &:horizontal { + height: 12px; + } + + &:vertical { + width: 12px; + } } - &:vertical { - width: 12px; - } - } + ::-webkit-scrollbar-thumb { + background: vars.color(scrollbar-bg); + border-radius: vars.prop(border-radius); - ::-webkit-scrollbar-thumb { - background: var(--scrollbar-bg); - border-radius: 5px; + &:horizontal { + min-width: 50px; + } - &:horizontal { - min-width: 50px; + &:vertical { + min-height: 50px; + } + + &:hover { + background: vars.color(scrollbar-bg-hover); + } + + &:active { + background: vars.color(scrollbar-bg-active); + } } - &:vertical { - min-height: 50px; + ::-webkit-scrollbar-corner { + background-color: vars.color(canvas); } - &:hover { - background: var(--scrollbar-hover-bg); + ::-webkit-scrollbar-track { + border-radius: 5px; + background-color: transparent; } - - &:active { - background: var(--scrollbar-active-bg); - } - } - - ::-webkit-scrollbar-corner { - background-color: var(--window-bg); - } - - ::-webkit-scrollbar-track { - border-radius: 5px; - background-color: transparent; } } diff --git a/ts/card-info/Revlog.svelte b/ts/card-info/Revlog.svelte index 88f2842cf..c71298de2 100644 --- a/ts/card-info/Revlog.svelte +++ b/ts/card-info/Revlog.svelte @@ -177,16 +177,16 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html } .revlog-learn { - color: var(--new-count); + color: var(--state-new); } .revlog-review { - color: var(--review-count); + color: var(--state-review); } .revlog-relearn, .revlog-ease1 { - color: var(--learn-count); + color: var(--state-learn); } @media only screen and (max-device-width: 480px) and (orientation: portrait) { diff --git a/ts/components/DropdownItem.svelte b/ts/components/DropdownItem.svelte index 5c1bea4ab..66575de39 100644 --- a/ts/components/DropdownItem.svelte +++ b/ts/components/DropdownItem.svelte @@ -72,10 +72,5 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html .btn-night { color: white; - - &:hover, - &:focus { - @include button.btn-night-base; - } } diff --git a/ts/components/IconButton.svelte b/ts/components/IconButton.svelte index b141252c6..6e1d640d5 100644 --- a/ts/components/IconButton.svelte +++ b/ts/components/IconButton.svelte @@ -48,6 +48,5 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html @include button.btn-border-radius; } - @include button.btn-day; - @include button.btn-night; + @include button.base(".icon-button"); diff --git a/ts/components/LabelButton.svelte b/ts/components/LabelButton.svelte index 4f4d08ca3..c37dd9dea 100644 --- a/ts/components/LabelButton.svelte +++ b/ts/components/LabelButton.svelte @@ -58,6 +58,5 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html @include button.btn-border-radius; } - @include button.btn-day; - @include button.btn-night; + @include button.base($with-primary: true); diff --git a/ts/components/Popover.svelte b/ts/components/Popover.svelte index 5c5d62b2a..f765c06b5 100644 --- a/ts/components/Popover.svelte +++ b/ts/components/Popover.svelte @@ -13,7 +13,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html diff --git a/ts/components/StickyContainer.svelte b/ts/components/StickyContainer.svelte index df11fdbc0..2f03bc170 100644 --- a/ts/components/StickyContainer.svelte +++ b/ts/components/StickyContainer.svelte @@ -29,9 +29,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html right: 0; z-index: 50; - background: var(--sticky-bg, var(--window-bg)); + background: var(--sticky-bg, var(--canvas)); border-style: solid; - border-color: var(--sticky-border, var(--medium-border)); + border-color: var(--sticky-border, var(--border)); border-width: var(--sticky-borders, 0); } diff --git a/ts/components/Switch.svelte b/ts/components/Switch.svelte index 7db1e6a63..ba1c48615 100644 --- a/ts/components/Switch.svelte +++ b/ts/components/Switch.svelte @@ -41,7 +41,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html } .nightMode:not(:checked) { - background-color: var(--frame-bg); + background-color: var(--canvas-elevated); border-color: var(--border); } diff --git a/ts/congrats/CongratsPage.svelte b/ts/congrats/CongratsPage.svelte index 55db748c3..1cb23b387 100644 --- a/ts/congrats/CongratsPage.svelte +++ b/ts/congrats/CongratsPage.svelte @@ -70,7 +70,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html font-size: var(--base-font-size); :global(a) { - color: var(--link); + color: var(--accent-link); text-decoration: none; } diff --git a/ts/deck-options/CardStateCustomizer.svelte b/ts/deck-options/CardStateCustomizer.svelte index 08505b481..cd9f3acf4 100644 --- a/ts/deck-options/CardStateCustomizer.svelte +++ b/ts/deck-options/CardStateCustomizer.svelte @@ -36,8 +36,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html } .card-state-customizer { - color: var(--text-fg); - background-color: var(--frame-bg); + color: var(--fg); + background-color: var(--canvas-elevated); width: 100%; height: 10em; diff --git a/ts/deck-options/Switch.svelte b/ts/deck-options/Switch.svelte index 7db1e6a63..ba1c48615 100644 --- a/ts/deck-options/Switch.svelte +++ b/ts/deck-options/Switch.svelte @@ -41,7 +41,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html } .nightMode:not(:checked) { - background-color: var(--frame-bg); + background-color: var(--canvas-elevated); border-color: var(--border); } diff --git a/ts/deck-options/TabbedValue.svelte b/ts/deck-options/TabbedValue.svelte index 3490d3dde..d59872eba 100644 --- a/ts/deck-options/TabbedValue.svelte +++ b/ts/deck-options/TabbedValue.svelte @@ -69,15 +69,15 @@ padding: 0.25rem 1rem; cursor: pointer; margin: 0 8px -1px 0; - color: var(--disabled); + color: var(--fg-subtle); } li.active > span { - border-color: var(--border) var(--border) var(--window-bg); - color: var(--text-fg); + border-color: var(--border) var(--border) var(--canvas); + color: var(--fg); } span:hover { - color: var(--text-fg); + color: var(--fg); } diff --git a/ts/deck-options/TextInputModal.svelte b/ts/deck-options/TextInputModal.svelte index 0937f4f86..0271737be 100644 --- a/ts/deck-options/TextInputModal.svelte +++ b/ts/deck-options/TextInputModal.svelte @@ -100,8 +100,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html } .default-colors { - background-color: var(--window-bg); - color: var(--text-fg); + background-color: var(--canvas); + color: var(--fg); } .invert { diff --git a/ts/deck-options/TitledContainer.svelte b/ts/deck-options/TitledContainer.svelte index 7fb1e4ed0..d4e75ee56 100644 --- a/ts/deck-options/TitledContainer.svelte +++ b/ts/deck-options/TitledContainer.svelte @@ -16,6 +16,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html diff --git a/ts/editor/EditingArea.svelte b/ts/editor/EditingArea.svelte index da5dfd0f9..203d13f32 100644 --- a/ts/editor/EditingArea.svelte +++ b/ts/editor/EditingArea.svelte @@ -188,28 +188,27 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html /* grid-template-columns: repeat(2, 1fr); */ position: relative; - background: var(--frame-bg); + background: var(--canvas-elevated); border-radius: 5px; - border: 1px solid var(--border); - box-shadow: 0px 0px 2px 0px var(--border); - transition: box-shadow 80ms cubic-bezier(0.33, 1, 0.68, 1); + /* Pseudo-element required to display + inset focus box-shadow above field contents */ + &::after { + content: ""; + position: absolute; + inset: 0; + pointer-events: none; + border-radius: 5px; + box-shadow: 0 0 2px 1px var(--shadow); + transition: box-shadow 80ms cubic-bezier(0.33, 1, 0.68, 1); + } &:focus-within { outline: none; - - /* This pseudo-element is required to display - the inset box-shadow above field contents */ &::after { - content: ""; - position: absolute; - top: -1px; - right: -1px; - bottom: -1px; - left: -1px; - pointer-events: none; - border-radius: 5px; - box-shadow: inset 0 0 0 2px var(--focus-border); + border: none; + inset: 1px; + box-shadow: 0 0 0 2px var(--border-focus); } } } diff --git a/ts/editor/NoteEditor.svelte b/ts/editor/NoteEditor.svelte index 0996bfda0..8d77f780f 100644 --- a/ts/editor/NoteEditor.svelte +++ b/ts/editor/NoteEditor.svelte @@ -326,7 +326,7 @@ the AddCards dialog) should be implemented in the user of this component. {#if hint} - {@html alertIcon} {@html hint} @@ -360,8 +360,8 @@ the AddCards dialog) should be implemented in the user of this component. }} collapsed={fieldsCollapsed[index]} --label-color={cols[index] === "dupe" - ? "var(--flag1-bg)" - : "var(--window-bg)"} + ? "palette-of(flag-1)" + : "palette-of(canvas)"} > diff --git a/ts/editor/Notification.svelte b/ts/editor/Notification.svelte index 297232856..46989c1fb 100644 --- a/ts/editor/Notification.svelte +++ b/ts/editor/Notification.svelte @@ -12,10 +12,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html diff --git a/ts/editor/legacy.scss b/ts/editor/legacy.scss index 817256259..8a8800b23 100644 --- a/ts/editor/legacy.scss +++ b/ts/editor/legacy.scss @@ -1,11 +1,9 @@ /* Copyright: Ankitects Pty Ltd and contributors * License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */ -@use "fusion-vars"; +@use "sass/vars"; @use "sass:color"; @use "sass/button-mixins" as button; -$btn-base-color-day: white; -$btn-base-color-night: fusion-vars.$button-border; $size: var(--buttons-size); $padding: 2px; @@ -13,47 +11,11 @@ $padding: 2px; width: $size; height: $size; padding: $padding; - color: var(--text-fg); font-size: calc($size * 0.6); - background-color: $btn-base-color-day; - border: 1px solid var(--medium-border); - @include button.btn-border-radius; - &:hover { - background-color: color.scale($btn-base-color-day, $lightness: -20%); - } - - &:active, - &:active:hover { - @include button.impressed-shadow(0.25); - } - - .nightMode & { - border: 1px solid fusion-vars.$button-border; - -webkit-appearance: none; - background: linear-gradient( - 0deg, - fusion-vars.$button-gradient-start 0%, - fusion-vars.$button-gradient-end 100% - ); - border: 1px solid fusion-vars.$button-border; - margin-left: 1px; - - &:hover { - background: linear-gradient( - 0deg, - color.scale(fusion-vars.$button-gradient-start, $lightness: 20%) 0%, - color.scale(fusion-vars.$button-gradient-end, $lightness: 20%) 100% - ); - border-color: color.scale(fusion-vars.$button-border, $lightness: 20%); - } - - &:active { - @include button.impressed-shadow(0.35); - border-color: color.scale($btn-base-color-night, $lightness: -20%); - } - } } +@include button.base($selector: ".linkb"); + img.topbut { max-width: calc($size - 2 * $padding); max-height: calc($size - 2 * $padding); diff --git a/ts/editor/mathjax-overlay/MathjaxEditor.svelte b/ts/editor/mathjax-overlay/MathjaxEditor.svelte index b136d682d..142985405 100644 --- a/ts/editor/mathjax-overlay/MathjaxEditor.svelte +++ b/ts/editor/mathjax-overlay/MathjaxEditor.svelte @@ -126,7 +126,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html font-family: sans-serif; font-size: 55%; text-align: center; - color: var(--slightly-grey-text); + color: var(--fg-subtle); } } diff --git a/ts/editor/plain-text-input/PlainTextInput.svelte b/ts/editor/plain-text-input/PlainTextInput.svelte index 4a495583c..7ebabb920 100644 --- a/ts/editor/plain-text-input/PlainTextInput.svelte +++ b/ts/editor/plain-text-input/PlainTextInput.svelte @@ -165,7 +165,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html border-radius: 0 0 5px 5px; :global(.CodeMirror) { - background: var(--code-bg); + background: var(--canvas-code); border-radius: 0 0 5px 5px; } diff --git a/ts/graphs/CardCounts.svelte b/ts/graphs/CardCounts.svelte index bc261ca39..c8db491e3 100644 --- a/ts/graphs/CardCounts.svelte +++ b/ts/graphs/CardCounts.svelte @@ -143,7 +143,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html .search-link:hover { cursor: pointer; - color: var(--link); + color: var(--accent-link); text-decoration: underline; } diff --git a/ts/graphs/NoDataOverlay.svelte b/ts/graphs/NoDataOverlay.svelte index a4dbf029f..80fae0a18 100644 --- a/ts/graphs/NoDataOverlay.svelte +++ b/ts/graphs/NoDataOverlay.svelte @@ -19,7 +19,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html diff --git a/ts/tag-editor/Tag.svelte b/ts/tag-editor/Tag.svelte index acf66d446..6f0070784 100644 --- a/ts/tag-editor/Tag.svelte +++ b/ts/tag-editor/Tag.svelte @@ -61,7 +61,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html font-size: var(--base-font-size); padding: 0; - --border-color: var(--medium-border); + --border-color: var(--border); border: 1px solid var(--border-color) !important; border-radius: 5px; @@ -77,12 +77,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html } &.selected { - box-shadow: 0 0 0 2px var(--focus-shadow); - --border-color: var(--focus-border); + box-shadow: 0 0 0 2px var(--border-focus); + --border-color: var(--border-focus); } } - @include button.btn-day($with-active: false, $with-disabled: false); - - @include button.btn-night($with-active: false, $with-disabled: false); + @include button.base($with-active: false, $with-disabled: false); diff --git a/ts/tag-editor/TagInput.svelte b/ts/tag-editor/TagInput.svelte index 4cb9c2a44..faec96aa3 100644 --- a/ts/tag-editor/TagInput.svelte +++ b/ts/tag-editor/TagInput.svelte @@ -262,7 +262,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html