Introduce new color palette using Sass maps (#2016)

* Remove --medium-border variable

* Implement color palette using Sass maps

I hand-picked the gray tones, the other colors are from the Tailwind CSS v3 palette.

Significant changes:
- light theme is brighter
- dark theme is darker
- borders are softer

I also deleted some platform- and night-mode-specific code.

* Use custom colors for note view switch

* Use same placeholder color for all inputs

* Skew color palette for more dark values

by removing gray[3], which wasn't used anywhere. Slight adjustments were made to the darker tones.

* Adjust frame- window- and border colors

* Give deck browser entries --frame-bg as background color

* Define styling for QComboBox and QLineEdit globally

* Experiment with CSS filter for inline-colors

Inside darker inputs, some colors like dark blue will be hard to read, so we could try to improve text-color contrast with global adjustments depending on the theme.

* Use different map structure for _vars.scss

after @hgiesel's idea: https://github.com/ankitects/anki/pull/2016#discussion_r947087871

* Move custom QLineEdit styles out of searchbar.py

* Merge branch 'main' into color-palette

* Revert QComboBox stylesheet override

* Align gray color palette more with macOS

* Adjust light theme

* Use --slightly-grey-text for options tab color

* Replace gray tones with more neutral values

* Improve categorization of global colors

by renaming almost all of them and sorting them into separate maps.

* Saturate highlight-bg in light theme

* Tweak gray tones

* Adjust box-shadow of EditingArea to make fields look inset

* Add Sass functions to access color palette and semantic variables

in response to https://github.com/ankitects/anki/pull/2016#issuecomment-1220571076

* Showcase use of access functions in several locations

@hgiesel in buttons.scss I access the color palette directly. Is this what you meant by "... keep it local to the component, and possibly make it global at a later time ..."?

* Fix focus box shadow transition and remove default shadow for a cleaner look

I couldn't quite get the inset look the way I wanted, because inset box-shadows do not respect the border radius, therefore causing aliasing.

* Tweak light theme border and shadow colors

* Add functions and colors to base_lib

* Add vars_lib as dependency to base_lib and button_mixins_lib

* Improve uses of default-themed variables

* Use old --frame-bg color and use darker tone for canvas-default

* Return CSS var by default and add palette-of function for raw value

* Showcase use of palette-of function

The #{...} syntax is required only because the use cases are CSS var definitions. In other cases a simple palette-of(keyword, theme) would suffice.

* Light theme: decrease brightness of canvas-default and adjust fg-default

* Use canvas-inset variable for switch knob

* Adjust light theme

* Add back box-shadow to EditingArea

* Light theme: darken background and flatten transition

also set hue and saturation of gray-8 to 0 (like all the other grays).

* Reduce flag colors to single default value

* Tweak card/note accent colors

* Experiment with inset look for fields again

Is this too dark in night mode? It's the same color used for all other text inputs.

* Dark theme: make border-default one shade darker

* Tweak inset shadow color

* Dark theme: make border-faint darker than canvas-default

meaning two shades darker than it currently was.

* Fix PlainTextInput not expanding

* Dark theme: use less saturated flag colors

* Adjust gray tones

* Fix nested variables not getting extracted correctly

* Rename canvas-outset to canvas-elevated

* Light theme: darken canvas-default

* Make canvas-elevated a bit darker

* Rename variables and use them in various components

* Refactor button mixins

* Remove fusion vars from Anki

* Adjust button gradients

* Refactor button mixins

* Fix deck browser table td background color

* Use color function in buttons.scss

* Rework QTabWidget stylesheet

* Fix crash on browser open

* Perfect QTableView header

* Fix bottom toolbar button gradient

* Fix focus outline of bottom toolbar buttons

* Fix custom webview scrollbar

* Fix uses of vars in various webviews

The command @use vars as * lead to repeated inclusion of the CSS vars.

* Enable primary button color with mixin

* Run prettier

* Fix Python code style issues

* Tweak colors

* Lighten scrollbar shades in light theme

* Fix code style issues caused by merge

* Fix harsh border color in editor

caused by leftover --medium-border variables, probably introduced with a merge commit.

* Compile Sass before extracting Python colors/props

This means the Python side doesn't need to worry about the map structure and Sass functions, just copy the output CSS values.

* Desaturate primary button colors by 10%

* Convert accidentally capitalized variable names to lowercase

* Simplify color definitions with qcolor function

* Remove default border-focus variable

* Remove redundant colon

* Apply custom scrollbar CSS only on Windows and Linux

* Make border-subtle color brighter than background in dark theme

* Make border-subtle color a shade brighter in light theme

* Use border-subtle for NoteEditor and EditorToolbar border

* Small patches
This commit is contained in:
Matthias Metelka 2022-09-16 06:11:18 +02:00 committed by GitHub
parent 3ec7e23d7c
commit 8142176f84
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
67 changed files with 1101 additions and 727 deletions

View file

@ -16,9 +16,9 @@ py_binary(
) )
py_binary( py_binary(
name = "extract_sass_colors", name = "extract_sass_vars",
srcs = [ srcs = [
"tools/extract_sass_colors.py", "tools/extract_sass_vars.py",
], ],
imports = ["."], imports = ["."],
visibility = [":__subpackages__"], visibility = [":__subpackages__"],

View file

@ -3,6 +3,22 @@ load("@py_deps//:requirements.bzl", "requirement")
load("@rules_python//python:packaging.bzl", "py_package", "py_wheel") load("@rules_python//python:packaging.bzl", "py_package", "py_wheel")
load("//:defs.bzl", "anki_version") 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( genrule(
name = "hooks_gen", name = "hooks_gen",
outs = ["hooks_gen.py"], outs = ["hooks_gen.py"],
@ -11,14 +27,14 @@ genrule(
) )
genrule( genrule(
name = "extract_sass_colors", name = "extract_sass_vars",
srcs = [ srcs = [
"//sass:_vars.scss", "_vars.css",
], ],
outs = ["colors.py"], outs = ["colors.py", "props.py"],
cmd = "$(location //qt:extract_sass_colors) $< $@", cmd = "$(location //qt:extract_sass_vars) $(SRCS) $(OUTS)",
tools = [ tools = [
"//qt:extract_sass_colors", "//qt:extract_sass_vars",
], ],
) )
@ -35,6 +51,7 @@ _py_srcs_and_forms = _py_srcs + [
aqt_core_data = [ aqt_core_data = [
"colors.py", "colors.py",
"props.py",
"py.typed", "py.typed",
":hooks_gen", ":hooks_gen",
] ]

View file

@ -104,7 +104,7 @@ class SidebarTreeView(QTreeView):
def _setup_style(self) -> None: def _setup_style(self) -> None:
# match window background color and tweak style # match window background color and tweak style
bgcolor = QPalette().window().color().name() bgcolor = QPalette().window().color().name()
border = theme_manager.color(colors.MEDIUM_BORDER) border = theme_manager.var(colors.BORDER)
styles = [ styles = [
"padding: 3px", "padding: 3px",
"padding-right: 0px", "padding-right: 0px",
@ -303,7 +303,7 @@ class SidebarTreeView(QTreeView):
) -> None: ) -> None:
if self.current_search and (item := self.model().item_for_index(idx)): if self.current_search and (item := self.model().item_for_index(idx)):
if item.is_highlighted(): if item.is_highlighted():
brush = QBrush(theme_manager.qcolor(colors.SUSPENDED_BG)) brush = QBrush(theme_manager.qcolor(colors.STATE_SUSPENDED))
painter.save() painter.save()
painter.fillRect(options.rect, brush) painter.fillRect(options.rect, brush)
painter.restore() painter.restore()
@ -653,36 +653,36 @@ class SidebarTreeView(QTreeView):
type=SidebarItemType.CARD_STATE_ROOT, type=SidebarItemType.CARD_STATE_ROOT,
) )
type = SidebarItemType.CARD_STATE type = SidebarItemType.CARD_STATE
colored_icon = ColoredIcon(path=icon, color=colors.DISABLED) colored_icon = ColoredIcon(path=icon, color=colors.FG_DISABLED)
root.add_simple( root.add_simple(
tr.actions_new(), tr.actions_new(),
icon=colored_icon.with_color(colors.NEW_COUNT), icon=colored_icon.with_color(colors.STATE_NEW),
type=type, type=type,
search_node=SearchNode(card_state=SearchNode.CARD_STATE_NEW), search_node=SearchNode(card_state=SearchNode.CARD_STATE_NEW),
) )
root.add_simple( root.add_simple(
name=tr.scheduling_learning(), name=tr.scheduling_learning(),
icon=colored_icon.with_color(colors.LEARN_COUNT), icon=colored_icon.with_color(colors.STATE_LEARN),
type=type, type=type,
search_node=SearchNode(card_state=SearchNode.CARD_STATE_LEARN), search_node=SearchNode(card_state=SearchNode.CARD_STATE_LEARN),
) )
root.add_simple( root.add_simple(
name=tr.scheduling_review(), name=tr.scheduling_review(),
icon=colored_icon.with_color(colors.REVIEW_COUNT), icon=colored_icon.with_color(colors.STATE_REVIEW),
type=type, type=type,
search_node=SearchNode(card_state=SearchNode.CARD_STATE_REVIEW), search_node=SearchNode(card_state=SearchNode.CARD_STATE_REVIEW),
) )
root.add_simple( root.add_simple(
name=tr.browsing_suspended(), name=tr.browsing_suspended(),
icon=colored_icon.with_color(colors.SUSPENDED_FG), icon=colored_icon.with_color(colors.STATE_SUSPENDED),
type=type, type=type,
search_node=SearchNode(card_state=SearchNode.CARD_STATE_SUSPENDED), search_node=SearchNode(card_state=SearchNode.CARD_STATE_SUSPENDED),
) )
root.add_simple( root.add_simple(
name=tr.browsing_buried(), name=tr.browsing_buried(),
icon=colored_icon.with_color(colors.BURIED_FG), icon=colored_icon.with_color(colors.STATE_BURIED),
type=type, type=type,
search_node=SearchNode(card_state=SearchNode.CARD_STATE_BURIED), search_node=SearchNode(card_state=SearchNode.CARD_STATE_BURIED),
) )

View file

@ -13,6 +13,7 @@ from anki.collection import BrowserColumns as Columns
from anki.collection import BrowserRow from anki.collection import BrowserRow
from anki.notes import NoteId from anki.notes import NoteId
from aqt import colors from aqt import colors
from aqt.qt import QColor
from aqt.utils import tr from aqt.utils import tr
Column = Columns.Column Column = Columns.Column
@ -76,24 +77,37 @@ class CellRow:
def backend_color_to_aqt_color(color: BrowserRow.Color.V) -> tuple[str, str] | None: def backend_color_to_aqt_color(color: BrowserRow.Color.V) -> tuple[str, str] | None:
temp_color = None
if color == BrowserRow.COLOR_MARKED: if color == BrowserRow.COLOR_MARKED:
return colors.MARKED_BG temp_color = colors.STATE_MARKED
if color == BrowserRow.COLOR_SUSPENDED: if color == BrowserRow.COLOR_SUSPENDED:
return colors.SUSPENDED_BG temp_color = colors.STATE_SUSPENDED
if color == BrowserRow.COLOR_FLAG_RED: if color == BrowserRow.COLOR_FLAG_RED:
return colors.FLAG1_BG temp_color = colors.FLAG_1
if color == BrowserRow.COLOR_FLAG_ORANGE: if color == BrowserRow.COLOR_FLAG_ORANGE:
return colors.FLAG2_BG temp_color = colors.FLAG_2
if color == BrowserRow.COLOR_FLAG_GREEN: if color == BrowserRow.COLOR_FLAG_GREEN:
return colors.FLAG3_BG temp_color = colors.FLAG_3
if color == BrowserRow.COLOR_FLAG_BLUE: if color == BrowserRow.COLOR_FLAG_BLUE:
return colors.FLAG4_BG temp_color = colors.FLAG_4
if color == BrowserRow.COLOR_FLAG_PINK: if color == BrowserRow.COLOR_FLAG_PINK:
return colors.FLAG5_BG temp_color = colors.FLAG_5
if color == BrowserRow.COLOR_FLAG_TURQUOISE: if color == BrowserRow.COLOR_FLAG_TURQUOISE:
return colors.FLAG6_BG temp_color = colors.FLAG_6
if color == BrowserRow.COLOR_FLAG_PURPLE: if color == BrowserRow.COLOR_FLAG_PURPLE:
return colors.FLAG7_BG 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 return None

View file

@ -375,7 +375,7 @@ class Table:
) )
elif theme_manager.macos_dark_mode(): elif theme_manager.macos_dark_mode():
self._view.setStyleSheet( self._view.setStyleSheet(
f"QTableView {{ gridline-color: {colors.FRAME_BG} }}" f"QTableView {{ gridline-color: {colors.CANVAS_INSET} }}"
) )
else: else:
self._view.setStyleSheet("") self._view.setStyleSheet("")

View file

@ -9,6 +9,7 @@ compile_sass(
group = "css_local", group = "css_local",
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
deps = [ deps = [
"//sass:vars_lib",
"//sass:buttons_lib", "//sass:buttons_lib",
"//sass:card_counts_lib", "//sass:card_counts_lib",
"//sass:scrollbar_lib", "//sass:scrollbar_lib",

View file

@ -1,10 +1,11 @@
/* Copyright: Ankitects Pty Ltd and contributors /* 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/vars";
@use "sass/card-counts"; @use "sass/card-counts";
a.deck { a.deck {
color: var(--text-fg); color: var(--fg);
text-decoration: none; text-decoration: none;
min-width: 5em; min-width: 5em;
display: inline-block; display: inline-block;
@ -15,7 +16,7 @@ a.deck:hover {
} }
tr.deck td { tr.deck td {
border-bottom: 1px solid var(--faint-border); border-bottom: 1px solid var(--border-subtle);
} }
tr.top-level-drag-row td { tr.top-level-drag-row td {
@ -36,7 +37,7 @@ body {
} }
.current { .current {
background-color: var(--faint-border); background-color: var(--shadow-subtle);
} }
.decktd { .decktd {
@ -55,14 +56,14 @@ body {
} }
.collapse { .collapse {
color: var(--text-fg); color: var(--fg);
text-decoration: none; text-decoration: none;
display: inline-block; display: inline-block;
width: 1em; width: 1em;
} }
.filtered { .filtered {
color: var(--link) !important; color: var(--accent-link) !important;
} }
.gears { .gears {
@ -79,7 +80,7 @@ body {
} }
.callout { .callout {
background: var(--medium-border); background: var(--border);
padding: 1em; padding: 1em;
margin: 1em; margin: 1em;

View file

@ -13,7 +13,7 @@ h3 {
.descfont { .descfont {
padding: 1em; padding: 1em;
color: var(--slightly-grey-text); color: var(--fg-subtle);
} }
.description { .description {

View file

@ -1,10 +1,11 @@
/* Copyright: Ankitects Pty Ltd and contributors /* 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 "vars";
@use "sass/card-counts"; @use "sass/card-counts";
:root { :root {
--focus-color: #0078d7; --focus-color: #{vars.palette-of(button-focus)};
.isMac { .isMac {
--focus-color: rgba(0 103 244 / 0.247); --focus-color: rgba(0 103 244 / 0.247);
@ -80,6 +81,6 @@ button {
.nightMode { .nightMode {
#outer { #outer {
border-top-color: var(--faint-border); border-top-color: var(--border-subtle);
} }
} }

View file

@ -26,7 +26,7 @@ body {
padding-right: 12px; padding-right: 12px;
padding-left: 12px; padding-left: 12px;
text-decoration: none; text-decoration: none;
color: var(--text-fg); color: var(--fg);
} }
.hitem:hover { .hitem:hover {
@ -38,11 +38,11 @@ body {
} }
.nightMode #header { .nightMode #header {
border-bottom-color: var(--faint-border); border-bottom-color: var(--border-subtle);
} }
.isMac.nightMode #header { .isMac.nightMode #header {
border-bottom-color: var(--frame-bg); border-bottom-color: var(--canvas-elevated);
} }
@keyframes spin { @keyframes spin {
@ -71,9 +71,9 @@ body {
} }
.normal-sync { .normal-sync {
color: var(--new-count); color: var(--state-new);
} }
.full-sync { .full-sync {
color: var(--learn-count); color: var(--state-learn);
} }

View file

@ -12,16 +12,17 @@
} }
body { body {
color: var(--text-fg); color: var(--fg);
background: var(--window-bg); background: var(--canvas);
transition: opacity 0.5s ease-out; transition: opacity 0.5s ease-out;
margin: 2em; margin: 2em;
overscroll-behavior: none; overscroll-behavior: none;
@include scrollbar.custom;
} }
@include scrollbar.custom;
a { a {
color: var(--link); color: var(--accent-link);
text-decoration: none; text-decoration: none;
} }

View file

@ -164,7 +164,7 @@ class Editor:
context=self, context=self,
default_css=False, default_css=False,
) )
self.web._fix_editor_background_color_and_show() self.web.show()
lefttopbtns: list[str] = [] lefttopbtns: list[str] = []
gui_hooks.editor_did_init_left_buttons(lefttopbtns, self) 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) self.tags = aqt.tagedit.TagEdit(self.widget)
qconnect(self.tags.lostFocus, self.on_tag_focus_lost) qconnect(self.tags.lostFocus, self.on_tag_focus_lost)
self.tags.setToolTip(shortcut(tr.editing_jump_to_tags_with_ctrlandshiftandt())) 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}") self.tags.setStyleSheet(f"border: 1px solid {border}")
tb.addWidget(self.tags, 1, 1) tb.addWidget(self.tags, 1, 1)
g.setLayout(tb) g.setLayout(tb)

View file

@ -84,8 +84,8 @@ class FilteredDeckConfigDialog(QDialog):
qconnect(self.form.search_button.clicked, self.on_search_button) 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.search_button_2.clicked, self.on_search_button_2)
qconnect(self.form.hint_button.clicked, self.on_hint_button) qconnect(self.form.hint_button.clicked, self.on_hint_button)
blue = theme_manager.color(colors.LINK) blue = theme_manager.var(colors.ACCENT_LINK)
grey = theme_manager.color(colors.DISABLED) grey = theme_manager.var(colors.FG_DISABLED)
self.setStyleSheet( self.setStyleSheet(
f"""QPushButton[label] {{ padding: 0; border: 0 }} f"""QPushButton[label] {{ padding: 0; border: 0 }}
QPushButton[label]:hover {{ text-decoration: underline }} QPushButton[label]:hover {{ text-decoration: underline }}

View file

@ -61,55 +61,55 @@ class FlagManager:
def _load_flags(self) -> None: def _load_flags(self) -> None:
labels = cast(dict[str, str], self.mw.col.get_config("flagLabels", {})) 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 = [ self._flags = [
Flag( Flag(
1, 1,
labels["1"] if "1" in labels else tr.actions_flag_red(), 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), SearchNode(flag=SearchNode.FLAG_RED),
"actionRed_Flag", "actionRed_Flag",
), ),
Flag( Flag(
2, 2,
labels["2"] if "2" in labels else tr.actions_flag_orange(), 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), SearchNode(flag=SearchNode.FLAG_ORANGE),
"actionOrange_Flag", "actionOrange_Flag",
), ),
Flag( Flag(
3, 3,
labels["3"] if "3" in labels else tr.actions_flag_green(), 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), SearchNode(flag=SearchNode.FLAG_GREEN),
"actionGreen_Flag", "actionGreen_Flag",
), ),
Flag( Flag(
4, 4,
labels["4"] if "4" in labels else tr.actions_flag_blue(), 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), SearchNode(flag=SearchNode.FLAG_BLUE),
"actionBlue_Flag", "actionBlue_Flag",
), ),
Flag( Flag(
5, 5,
labels["5"] if "5" in labels else tr.actions_flag_pink(), 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), SearchNode(flag=SearchNode.FLAG_PINK),
"actionPink_Flag", "actionPink_Flag",
), ),
Flag( Flag(
6, 6,
labels["6"] if "6" in labels else tr.actions_flag_turquoise(), 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), SearchNode(flag=SearchNode.FLAG_TURQUOISE),
"actionTurquoise_Flag", "actionTurquoise_Flag",
), ),
Flag( Flag(
7, 7,
labels["7"] if "7" in labels else tr.actions_flag_purple(), 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), SearchNode(flag=SearchNode.FLAG_PURPLE),
"actionPurple_Flag", "actionPurple_Flag",
), ),

View file

@ -1,6 +1,6 @@
# Copyright: Ankitects Pty Ltd and contributors # 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
from aqt import colors from aqt import colors, props
from aqt.theme import ThemeManager from aqt.theme import ThemeManager
@ -16,14 +16,14 @@ QLineEdit,
QListWidget, QListWidget,
QTreeWidget, QTreeWidget,
QListView {{ QListView {{
border: 1px solid {tm.color(colors.BORDER)}; border: 1px solid {tm.var(colors.BORDER)};
border-radius: 5px; border-radius: {tm.var(props.BORDER_RADIUS)};
}} }}
QLineEdit {{ QLineEdit {{
padding: 2px; padding: 2px;
}} }}
QLineEdit:focus {{ QLineEdit:focus {{
border-color: {tm.color(colors.FOCUS_BORDER)}; border-color: {tm.var(colors.BORDER_FOCUS)};
}} }}
QPushButton {{ QPushButton {{
margin-top: 1px; margin-top: 1px;
@ -34,7 +34,7 @@ QSpinBox {{
padding: 2px 6px; padding: 2px 6px;
}} }}
QToolTip {{ QToolTip {{
background: {tm.color(colors.TOOLTIP_BG)}; background: {tm.var(colors.CANVAS_OVERLAY)};
}} }}
""" """
return buf return buf
@ -43,31 +43,33 @@ QToolTip {{
def button_styles(tm: ThemeManager, buf: str) -> str: def button_styles(tm: ThemeManager, buf: str) -> str:
buf += f""" buf += f"""
QPushButton, QPushButton,
QTabBar::tab:!selected,
QComboBox:!editable {{ QComboBox:!editable {{
background: qlineargradient( background: qlineargradient(
spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, spread:pad, x1:0.5, y1:0, x2:0.5, y2:1,
stop:0 {tm.color(colors.BUTTON_GRADIENT_START)}, stop:0 {tm.var(colors.BUTTON_GRADIENT_START)},
stop:1 {tm.color(colors.BUTTON_GRADIENT_END)} stop:1 {tm.var(colors.BUTTON_GRADIENT_END)}
); );
}} }}
QPushButton:hover, QPushButton:hover,
QTabBar::tab:hover,
QComboBox:!editable:hover {{ QComboBox:!editable:hover {{
background: qlineargradient( background: qlineargradient(
spread:pad, x1:0.5, y1:0, x2:0.5, y2:1.25, spread:pad, x1:0.5, y1:0, x2:0.5, y2:1.25,
stop:0 {tm.color(colors.BUTTON_HOVER_GRADIENT_START)}, stop:0 {tm.var(colors.BUTTON_HOVER_GRADIENT_START)},
stop:1 {tm.color(colors.BUTTON_HOVER_GRADIENT_END)} stop:1 {tm.var(colors.BUTTON_HOVER_GRADIENT_END)}
); );
}} }}
QPushButton:pressed, QPushButton:pressed,
QComboBox:!editable:pressed {{ QComboBox:!editable:pressed {{
border: 1px solid {tm.color(colors.BUTTON_PRESSED_BORDER)}; border: 1px solid {tm.var(colors.BUTTON_PRESSED_BORDER)};
background: qlineargradient( background: qlineargradient(
spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, spread:pad, x1:0.5, y1:0, x2:0.5, y2:1,
stop:0 {tm.color(colors.BUTTON_PRESSED_SHADOW)}, stop:0 {tm.var(colors.BUTTON_PRESSED_SHADOW)},
stop:0.1 {tm.color(colors.BUTTON_GRADIENT_START)}, stop:0.1 {tm.var(colors.BUTTON_GRADIENT_START)},
stop:0.9 {tm.color(colors.BUTTON_GRADIENT_END)}, stop:0.9 {tm.var(colors.BUTTON_GRADIENT_END)},
stop:1 {tm.color(colors.BUTTON_PRESSED_SHADOW)}, stop:1 {tm.var(colors.BUTTON_PRESSED_SHADOW)},
); );
}} }}
""" """
@ -83,7 +85,7 @@ QComboBox:editable:on,
QComboBox:editable:focus, QComboBox:editable:focus,
QComboBox::drop-down:focus:editable, QComboBox::drop-down:focus:editable,
QComboBox::drop-down:pressed {{ QComboBox::drop-down:pressed {{
border-color: {tm.color(colors.FOCUS_BORDER)}; border-color: {tm.var(colors.BORDER_FOCUS)};
}} }}
QComboBox:on {{ QComboBox:on {{
border-bottom: none; border-bottom: none;
@ -91,13 +93,13 @@ QComboBox:on {{
border-bottom-left-radius: 0; border-bottom-left-radius: 0;
}} }}
QComboBox::item {{ QComboBox::item {{
color: {tm.color(colors.TEXT_FG)}; color: {tm.var(colors.FG)};
background: {tm.color(colors.FRAME_BG)}; background: {tm.var(colors.CANVAS_ELEVATED)};
}} }}
QComboBox::item:selected {{ QComboBox::item:selected {{
background: {tm.color(colors.HIGHLIGHT_BG)}; background: {tm.var(colors.HIGHLIGHT_BG)};
color: {tm.color(colors.HIGHLIGHT_FG)}; color: {tm.var(colors.HIGHLIGHT_FG)};
}} }}
QComboBox::item::icon:selected {{ QComboBox::item::icon:selected {{
position: absolute; position: absolute;
@ -108,9 +110,9 @@ QComboBox::drop-down {{
padding: 2px; padding: 2px;
width: 16px; width: 16px;
subcontrol-position: top right; subcontrol-position: top right;
border: 1px solid {tm.color(colors.BUTTON_BORDER)}; border: 1px solid {tm.var(colors.BUTTON_BORDER)};
border-top-right-radius: 5px; border-top-right-radius: {tm.var(props.BORDER_RADIUS)};
border-bottom-right-radius: 5px; border-bottom-right-radius: {tm.var(props.BORDER_RADIUS)};
}} }}
QComboBox::down-arrow {{ QComboBox::down-arrow {{
image: url(icons:chevron-down.svg); image: url(icons:chevron-down.svg);
@ -118,15 +120,15 @@ QComboBox::down-arrow {{
QComboBox::drop-down {{ QComboBox::drop-down {{
background: qlineargradient( background: qlineargradient(
spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, spread:pad, x1:0.5, y1:0, x2:0.5, y2:1,
stop:0 {tm.color(colors.BUTTON_PRIMARY_GRADIENT_START)}, stop:0 {tm.var(colors.BUTTON_PRIMARY_GRADIENT_START)},
stop:1 {tm.color(colors.BUTTON_PRIMARY_GRADIENT_END)} stop:1 {tm.var(colors.BUTTON_PRIMARY_GRADIENT_END)}
); );
}} }}
QComboBox::drop-down:hover {{ QComboBox::drop-down:hover {{
background: qlineargradient( background: qlineargradient(
spread:pad, x1:0.5, y1:0, x2:0.5, y2:1.25, spread:pad, x1:0.5, y1:0, x2:0.5, y2:1.25,
stop:0 {tm.color(colors.BUTTON_PRIMARY_HOVER_GRADIENT_START)}, stop:0 {tm.var(colors.BUTTON_PRIMARY_HOVER_GRADIENT_START)},
stop:1 {tm.color(colors.BUTTON_PRIMARY_HOVER_GRADIENT_END)} 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: def tabwidget_styles(tm: ThemeManager, buf: str) -> str:
buf += f""" buf += f"""
QTabWidget {{ QTabWidget {{
border-radius: 5px; border-radius: {tm.var(props.BORDER_RADIUS)};
border: none;
background: none; background: none;
}} }}
QTabWidget::pane {{ QTabWidget::pane {{
border: 1px solid {tm.color(colors.FRAME_BG)}; top: -15px;
border-radius: 5px; padding-top: 1em;
background: {tm.color(colors.FRAME_BG)}; 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 {{ QTabBar::tab {{
background: none; background: none;
border-top-left-radius: 5px; padding: 4px 8px;
border-top-right-radius: 5px; min-width: 8ex;
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)};
}} }}
QTabBar::tab {{ QTabBar::tab {{
min-width: 8ex; border: 1px solid {tm.var(colors.BORDER_SUBTLE)};
padding: 5px 10px 5px 10px; }}
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 {{ QTabBar::tab:selected {{
border-bottom-color: none; color: white;
}} background: qlineargradient(
QTabBar::tab:bottom:selected {{ spread:pad, x1:0.5, y1:0, x2:0.5, y2:1,
border-top-color: none; stop:0 {tm.var(colors.BUTTON_PRIMARY_GRADIENT_START)},
}} stop:1 {tm.var(colors.BUTTON_PRIMARY_GRADIENT_END)}
QTabBar::tab:previous-selected {{ );
border-top-left-radius: 0;
}}
QTabBar::tab:next-selected {{
border-top-right-radius: 0;
}} }}
""" """
return buf return buf
@ -186,49 +185,53 @@ QTabBar::tab:next-selected {{
def table_styles(tm: ThemeManager, buf: str) -> str: def table_styles(tm: ThemeManager, buf: str) -> str:
buf += f""" buf += f"""
QTableView {{ QTableView {{
margin: -1px -1px 1px -1px;
background: none; background: none;
border: 2px solid {tm.color(colors.WINDOW_BG)}; top: 2px;
border-radius: 5px; 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 {{ QHeaderView::section {{
border: 2px solid {tm.color(colors.WINDOW_BG)}; border: 1px solid {tm.var(colors.BORDER_SUBTLE)};
margin: -1px;
background: qlineargradient( background: qlineargradient(
spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, spread:pad, x1:0.5, y1:0, x2:0.5, y2:1,
stop:0 {tm.color(colors.BUTTON_GRADIENT_START)}, stop:0 {tm.var(colors.BUTTON_GRADIENT_START)},
stop:1 {tm.color(colors.BUTTON_GRADIENT_END)} stop:1 {tm.var(colors.BUTTON_GRADIENT_END)}
); );
}} }}
QHeaderView::section:pressed {{ QHeaderView::section:pressed {{
border: 1px solid {tm.color(colors.BUTTON_PRESSED_BORDER)}; border: 1px solid {tm.var(colors.BUTTON_PRESSED_BORDER)};
background: qlineargradient( background: qlineargradient(
spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, spread:pad, x1:0.5, y1:0, x2:0.5, y2:1,
stop:0 {tm.color(colors.BUTTON_PRESSED_SHADOW)}, stop:0 {tm.var(colors.BUTTON_PRESSED_SHADOW)},
stop:0.1 {tm.color(colors.BUTTON_GRADIENT_START)}, stop:0.1 {tm.var(colors.BUTTON_GRADIENT_START)},
stop:0.9 {tm.color(colors.BUTTON_GRADIENT_END)}, stop:0.9 {tm.var(colors.BUTTON_GRADIENT_END)},
stop:1 {tm.color(colors.BUTTON_PRESSED_SHADOW)}, stop:1 {tm.var(colors.BUTTON_PRESSED_SHADOW)},
); );
}} }}
QHeaderView::section:hover {{ QHeaderView::section:hover {{
background: qlineargradient( background: qlineargradient(
spread:pad, x1:0.5, y1:0, x2:0.5, y2:1.25, spread:pad, x1:0.5, y1:0, x2:0.5, y2:1.25,
stop:0 {tm.color(colors.BUTTON_HOVER_GRADIENT_START)}, stop:0 {tm.var(colors.BUTTON_HOVER_GRADIENT_START)},
stop:1 {tm.color(colors.BUTTON_HOVER_GRADIENT_END)} stop:1 {tm.var(colors.BUTTON_HOVER_GRADIENT_END)}
); );
}} }}
QHeaderView::section:first {{ QHeaderView::section:first {{
border-top: 2px solid {tm.color(colors.WINDOW_BG)}; margin-left: -1px;
border-left: 2px solid {tm.color(colors.WINDOW_BG)}; border-top: 1px solid {tm.var(colors.BORDER_SUBTLE)};
border-top-left-radius: 5px; border-left: 1px solid {tm.var(colors.BORDER_SUBTLE)};
border-top-left-radius: {tm.var(props.BORDER_RADIUS)};
}} }}
QHeaderView::section:!first {{ QHeaderView::section:!first {{
border-left: none; border-left: none;
}} }}
QHeaderView::section:last {{ QHeaderView::section:last {{
border-top: 2px solid {tm.color(colors.WINDOW_BG)}; border-top: 1px solid {tm.var(colors.BORDER_SUBTLE)};
border-right: 2px solid {tm.color(colors.WINDOW_BG)}; border-right: 1px solid {tm.var(colors.BORDER_SUBTLE)};
border-top-right-radius: 5px; border-top-right-radius: {tm.var(props.BORDER_RADIUS)};
}} }}
QHeaderView::section:next-selected {{ QHeaderView::section:next-selected {{
border-right: none; border-right: none;
@ -237,11 +240,11 @@ QHeaderView::section:previous-selected {{
border-left: none; border-left: none;
}} }}
QHeaderView::section:only-one {{ QHeaderView::section:only-one {{
border-left: 2px solid {tm.color(colors.WINDOW_BG)}; border-left: 1px solid {tm.var(colors.BORDER_SUBTLE)};
border-top: 2px solid {tm.color(colors.WINDOW_BG)}; border-top: 1px solid {tm.var(colors.BORDER_SUBTLE)};
border-right: 2px solid {tm.color(colors.WINDOW_BG)}; border-right: 1px solid {tm.var(colors.CANVAS)};
border-top-left-radius: 5px; border-top-left-radius: {tm.var(props.BORDER_RADIUS)};
border-top-right-radius: 5px; border-top-right-radius: {tm.var(props.BORDER_RADIUS)};
}} }}
QHeaderView::up-arrow, QHeaderView::up-arrow,
QHeaderView::down-arrow {{ QHeaderView::down-arrow {{
@ -264,41 +267,41 @@ QSpinBox::up-button,
QSpinBox::down-button {{ QSpinBox::down-button {{
subcontrol-origin: border; subcontrol-origin: border;
width: 16px; width: 16px;
border: 1px solid {tm.color(colors.BUTTON_BORDER)}; border: 1px solid {tm.var(colors.BUTTON_BORDER)};
background: qlineargradient( background: qlineargradient(
spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, spread:pad, x1:0.5, y1:0, x2:0.5, y2:1,
stop:0 {tm.color(colors.BUTTON_PRIMARY_GRADIENT_START)}, stop:0 {tm.var(colors.BUTTON_PRIMARY_GRADIENT_START)},
stop:1 {tm.color(colors.BUTTON_PRIMARY_GRADIENT_END)} stop:1 {tm.var(colors.BUTTON_PRIMARY_GRADIENT_END)}
); );
}} }}
QSpinBox::up-button:pressed, QSpinBox::up-button:pressed,
QSpinBox::down-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( background: qlineargradient(
spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, spread:pad, x1:0.5, y1:0, x2:0.5, y2:1,
stop:0 {tm.color(colors.BUTTON_PRESSED_SHADOW)}, stop:0 {tm.var(colors.BUTTON_PRESSED_SHADOW)},
stop:0.1 {tm.color(colors.BUTTON_PRIMARY_GRADIENT_START)}, stop:0.1 {tm.var(colors.BUTTON_PRIMARY_GRADIENT_START)},
stop:0.9 {tm.color(colors.BUTTON_PRIMARY_GRADIENT_END)}, stop:0.9 {tm.var(colors.BUTTON_PRIMARY_GRADIENT_END)},
stop:1 {tm.color(colors.BUTTON_PRESSED_SHADOW)}, stop:1 {tm.var(colors.BUTTON_PRESSED_SHADOW)},
); );
}} }}
QSpinBox::up-button:hover, QSpinBox::up-button:hover,
QSpinBox::down-button:hover {{ QSpinBox::down-button:hover {{
background: qlineargradient( background: qlineargradient(
spread:pad, x1:0.5, y1:0, x2:0.5, y2:1.25, spread:pad, x1:0.5, y1:0, x2:0.5, y2:1.25,
stop:0 {tm.color(colors.BUTTON_PRIMARY_HOVER_GRADIENT_START)}, stop:0 {tm.var(colors.BUTTON_PRIMARY_HOVER_GRADIENT_START)},
stop:1 {tm.color(colors.BUTTON_PRIMARY_HOVER_GRADIENT_END)} stop:1 {tm.var(colors.BUTTON_PRIMARY_HOVER_GRADIENT_END)}
); );
}} }}
QSpinBox::up-button {{ QSpinBox::up-button {{
margin-bottom: -1px; margin-bottom: -1px;
subcontrol-position: top right; subcontrol-position: top right;
border-top-right-radius: 5px; border-top-right-radius: {tm.var(props.BORDER_RADIUS)};
}} }}
QSpinBox::down-button {{ QSpinBox::down-button {{
margin-top: -1px; margin-top: -1px;
subcontrol-position: bottom right; subcontrol-position: bottom right;
border-bottom-right-radius: 5px; border-bottom-right-radius: {tm.var(props.BORDER_RADIUS)};
}} }}
QSpinBox::up-arrow {{ QSpinBox::up-arrow {{
image: url(icons:chevron-up.svg); image: url(icons:chevron-up.svg);
@ -322,7 +325,7 @@ QSpinBox::down-arrow:hover {{
}} }}
QSpinBox::up-button:disabled, QSpinBox::up-button:off, QSpinBox::up-button:disabled, QSpinBox::up-button:off,
QSpinBox::down-button:disabled, QSpinBox::down-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 return buf
@ -335,17 +338,17 @@ QAbstractScrollArea::corner {{
border: none; border: none;
}} }}
QScrollBar {{ QScrollBar {{
background-color: {tm.color(colors.WINDOW_BG)}; background-color: {tm.var(colors.CANVAS)};
}} }}
QScrollBar::handle {{ QScrollBar::handle {{
border-radius: 5px; border-radius: {tm.var(props.BORDER_RADIUS)};
background-color: {tm.color(colors.SCROLLBAR_BG)}; background-color: {tm.var(colors.SCROLLBAR_BG)};
}} }}
QScrollBar::handle:hover {{ QScrollBar::handle:hover {{
background-color: {tm.color(colors.SCROLLBAR_HOVER_BG)}; background-color: {tm.var(colors.SCROLLBAR_BG_HOVER)};
}} }}
QScrollBar::handle:pressed {{ QScrollBar::handle:pressed {{
background-color: {tm.color(colors.SCROLLBAR_ACTIVE_BG)}; background-color: {tm.var(colors.SCROLLBAR_BG_ACTIVE)};
}} }}
QScrollBar:horizontal {{ QScrollBar:horizontal {{
height: 12px; height: 12px;
@ -377,8 +380,8 @@ def win10_styles(tm: ThemeManager, buf: str) -> str:
# also set for border to apply # also set for border to apply
buf += f""" buf += f"""
QMenuBar {{ QMenuBar {{
border-bottom: 1px solid {tm.color(colors.BORDER)}; border-bottom: 1px solid {tm.var(colors.BORDER)};
background: {tm.color(colors.WINDOW_BG) if tm.night_mode else "white"}; background: {tm.var(colors.CANVAS) if tm.night_mode else "white"};
}} }}
""" """
@ -386,7 +389,7 @@ QMenuBar {{
# to white as well, so set it back # to white as well, so set it back
buf += f""" buf += f"""
QTreeWidget {{ QTreeWidget {{
background: {tm.color(colors.WINDOW_BG)}; background: {tm.var(colors.CANVAS)};
}} }}
""" """

View file

@ -19,8 +19,8 @@ class Switch(QAbstractButton):
radius: int = 10, radius: int = 10,
left_label: str = "", left_label: str = "",
right_label: str = "", right_label: str = "",
left_color: tuple[str, str] = colors.FLAG4_BG, left_color: tuple[str, str] = colors.ACCENT_CARD,
right_color: tuple[str, str] = colors.FLAG3_BG, right_color: tuple[str, str] = colors.ACCENT_NOTE,
parent: QWidget = None, parent: QWidget = None,
) -> None: ) -> None:
super().__init__(parent=parent) super().__init__(parent=parent)
@ -100,15 +100,12 @@ class Switch(QAbstractButton):
) )
def _paint_knob(self, painter: QPainter) -> None: def _paint_knob(self, painter: QPainter) -> None:
if theme_manager.night_mode: color = theme_manager.qcolor(colors.BUTTON_GRADIENT_START)
color = QColor(theme_manager.DARK_MODE_BUTTON_BG_MIDPOINT)
else:
color = theme_manager.qcolor(colors.FRAME_BG)
painter.setBrush(QBrush(color)) painter.setBrush(QBrush(color))
painter.drawEllipse(self._current_knob_rectangle()) painter.drawEllipse(self._current_knob_rectangle())
def _paint_label(self, painter: QPainter) -> None: 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 = painter.font()
font.setPixelSize(int(1.2 * self._knob_radius)) font.setPixelSize(int(1.2 * self._knob_radius))
painter.setFont(font) painter.setFont(font)

View file

@ -145,13 +145,13 @@ class ThemeManager:
"Returns body classes used when showing a card." "Returns body classes used when showing a card."
return f"card card{card_ord+1} {self.body_class(night_mode)}" return f"card card{card_ord+1} {self.body_class(night_mode)}"
def color(self, colors: tuple[str, str]) -> str: def var(self, vars: tuple[str, str]) -> str:
"""Given day/night colors, return the correct one for the current theme.""" """Given day/night colors/props, return the correct one for the current theme."""
idx = 1 if self.night_mode else 0 idx = 1 if self.night_mode else 0
return colors[idx] return vars[idx]
def qcolor(self, colors: tuple[str, str]) -> QColor: def qcolor(self, colors: tuple[str, str]) -> QColor:
return QColor(self.color(colors)) return QColor(self.var(colors))
def _determine_night_mode(self) -> bool: def _determine_night_mode(self) -> bool:
theme = aqt.mw.pm.theme() theme = aqt.mw.pm.theme()
@ -187,6 +187,7 @@ class ThemeManager:
def _apply_style(self, app: QApplication) -> None: def _apply_style(self, app: QApplication) -> None:
buf = "" buf = ""
if not is_mac: if not is_mac:
from aqt.stylesheets import ( from aqt.stylesheets import (
button_styles, button_styles,
@ -224,6 +225,9 @@ class ThemeManager:
if not self.night_mode: if not self.night_mode:
app.setStyle(QStyleFactory.create(self._default_style)) # type: ignore 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) app.setPalette(self.default_palette)
return return
@ -232,11 +236,11 @@ class ThemeManager:
palette = QPalette() palette = QPalette()
text_fg = self.qcolor(colors.TEXT_FG) text = self.qcolor(colors.FG)
palette.setColor(QPalette.ColorRole.WindowText, text_fg) palette.setColor(QPalette.ColorRole.WindowText, text)
palette.setColor(QPalette.ColorRole.ToolTipText, text_fg) palette.setColor(QPalette.ColorRole.ToolTipText, text)
palette.setColor(QPalette.ColorRole.Text, text_fg) palette.setColor(QPalette.ColorRole.Text, text)
palette.setColor(QPalette.ColorRole.ButtonText, text_fg) palette.setColor(QPalette.ColorRole.ButtonText, text)
hlbg = self.qcolor(colors.HIGHLIGHT_BG) hlbg = self.qcolor(colors.HIGHLIGHT_BG)
hlbg.setAlpha(64) hlbg.setAlpha(64)
@ -245,18 +249,21 @@ class ThemeManager:
) )
palette.setColor(QPalette.ColorRole.Highlight, hlbg) palette.setColor(QPalette.ColorRole.Highlight, hlbg)
window_bg = self.qcolor(colors.WINDOW_BG) canvas = self.qcolor(colors.CANVAS)
palette.setColor(QPalette.ColorRole.Window, window_bg) palette.setColor(QPalette.ColorRole.Window, canvas)
palette.setColor(QPalette.ColorRole.AlternateBase, window_bg) palette.setColor(QPalette.ColorRole.AlternateBase, canvas)
palette.setColor(QPalette.ColorRole.Button, QColor("#454545")) palette.setColor(QPalette.ColorRole.Button, QColor("#454545"))
frame_bg = self.qcolor(colors.FRAME_BG) canvas_inset = self.qcolor(colors.CANVAS_INSET)
palette.setColor(QPalette.ColorRole.Base, frame_bg) palette.setColor(QPalette.ColorRole.Base, canvas_inset)
palette.setColor(QPalette.ColorRole.ToolTipBase, frame_bg) palette.setColor(QPalette.ColorRole.ToolTipBase, canvas_inset)
disabled_color = self.qcolor(colors.DISABLED) palette.setColor(
palette.setColor(QPalette.ColorRole.PlaceholderText, disabled_color) QPalette.ColorRole.PlaceholderText, self.qcolor(colors.FG_SUBTLE)
)
disabled_color = self.qcolor(colors.FG_DISABLED)
palette.setColor( palette.setColor(
QPalette.ColorGroup.Disabled, QPalette.ColorRole.Text, disabled_color QPalette.ColorGroup.Disabled, QPalette.ColorRole.Text, disabled_color
) )
@ -269,7 +276,7 @@ class ThemeManager:
disabled_color, 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) palette.setColor(QPalette.ColorRole.BrightText, Qt.GlobalColor.red)
@ -278,11 +285,11 @@ class ThemeManager:
def _update_stat_colors(self) -> None: def _update_stat_colors(self) -> None:
import anki.stats as s import anki.stats as s
s.colLearn = self.color(colors.NEW_COUNT) s.colLearn = self.var(colors.STATE_NEW)
s.colRelearn = self.color(colors.LEARN_COUNT) s.colRelearn = self.var(colors.STATE_LEARN)
s.colCram = self.color(colors.SUSPENDED_BG) s.colCram = self.var(colors.STATE_SUSPENDED)
s.colSusp = self.color(colors.SUSPENDED_BG) s.colSusp = self.var(colors.STATE_SUSPENDED)
s.colMature = self.color(colors.REVIEW_COUNT) s.colMature = self.var(colors.STATE_REVIEW)
s._legacy_nightmode = self._night_mode_preference s._legacy_nightmode = self._night_mode_preference

View file

@ -233,9 +233,7 @@ class AnkiWebView(QWebEngineView):
self.set_title(title) self.set_title(title)
self._page = AnkiWebPage(self._onBridgeCmd) self._page = AnkiWebPage(self._onBridgeCmd)
# reduce flicker # reduce flicker
self._page.setBackgroundColor( self._page.setBackgroundColor(theme_manager.qcolor(colors.CANVAS))
self.get_window_bg_color(theme_manager.night_mode)
)
# in new code, use .set_bridge_command() instead of setting this directly # in new code, use .set_bridge_command() instead of setting this directly
self.onBridgeCmd: Callable[[str], Any] = self.defaultOnBridgeCmd self.onBridgeCmd: Callable[[str], Any] = self.defaultOnBridgeCmd
@ -404,15 +402,6 @@ class AnkiWebView(QWebEngineView):
else: else:
return 3 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: def standard_css(self) -> str:
palette = theme_manager.default_palette palette = theme_manager.default_palette
color_hl = palette.color(QPalette.ColorRole.Highlight).name() color_hl = palette.color(QPalette.ColorRole.Highlight).name()
@ -459,15 +448,12 @@ div[contenteditable="true"]:focus {{
zoom = self.app_zoom_factor() 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""" return f"""
body {{ zoom: {zoom}; background-color: var(--window-bg); }} body {{ zoom: {zoom}; background-color: var(--canvas); }}
html {{ {font} }} html {{ {font} }}
{button_style} {button_style}
:root {{ --window-bg: {window_bg_day} }} :root {{ --canvas: {colors.CANVAS[0]} }}
:root[class*=night-mode] {{ --window-bg: {window_bg_night} }} :root[class*=night-mode] {{ --canvas: {colors.CANVAS[1]} }}
""" """
def stdHtml( def stdHtml(
@ -711,9 +697,7 @@ html {{ {font} }}
def on_theme_did_change(self) -> None: def on_theme_did_change(self) -> None:
# avoid flashes if page reloaded # avoid flashes if page reloaded
self._page.setBackgroundColor( self._page.setBackgroundColor(theme_manager.qcolor(colors.CANVAS))
self.get_window_bg_color(theme_manager.night_mode)
)
# update night-mode class, and legacy nightMode/night-mode body classes # update night-mode class, and legacy nightMode/night-mode body classes
self.eval( self.eval(
f""" 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(),
)

View file

@ -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')

View file

@ -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')

View file

@ -3,21 +3,29 @@ load("@io_bazel_rules_sass//:defs.bzl", "sass_library")
sass_library( sass_library(
name = "base_lib", name = "base_lib",
srcs = [ srcs = [
"_fusion-vars.scss",
"_vars.scss",
"base.scss", "base.scss",
"bootstrap-dark.scss", "bootstrap-dark.scss",
], ],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
"vars_lib",
"//sass/bootstrap", "//sass/bootstrap",
], ],
) )
sass_library(
name = "vars_lib",
srcs = [
"_colors.scss",
"_functions.scss",
"_vars.scss",
],
visibility = ["//visibility:public"],
)
sass_library( sass_library(
name = "buttons_lib", name = "buttons_lib",
srcs = [ srcs = [
"_fusion-vars.scss",
"buttons.scss", "buttons.scss",
], ],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
@ -62,7 +70,9 @@ sass_library(
name = "button_mixins_lib", name = "button_mixins_lib",
srcs = [ srcs = [
"_button-mixins.scss", "_button-mixins.scss",
"_fusion-vars.scss", ],
deps = [
"vars_lib",
], ],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )

View file

@ -1,6 +1,6 @@
/* Copyright: Ankitects Pty Ltd and contributors /* 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 "fusion-vars"; @use "vars";
@use "sass:color"; @use "sass:color";
@import "bootstrap/scss/functions"; @import "bootstrap/scss/functions";
@ -19,102 +19,74 @@
border-bottom-right-radius: var(--border-right-radius); border-bottom-right-radius: var(--border-right-radius);
} }
$btn-base-color-day: white; @mixin base(
$selector: button,
@mixin btn-day-base { $with-primary: false,
color: var(--text-fg); $with-hover: true,
background-color: $btn-base-color-day; $with-active: true,
border-color: var(--medium-border) !important; $with-disabled: true
} ) {
#{$selector} {
@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;
-webkit-appearance: none; -webkit-appearance: none;
border: 1px solid var(--button-border);
@if ($with-hover) { color: var(--fg);
&:hover,
&.hover {
background: linear-gradient( background: linear-gradient(
180deg, 180deg,
color.scale(fusion-vars.$button-gradient-start, $lightness: 20%) 0%, var(--button-gradient-start) 0%,
color.scale(fusion-vars.$button-gradient-end, $lightness: 20%) 100% var(--button-gradient-end) 100%
); );
border-color: color.scale(fusion-vars.$button-border, $lightness: 20%);
@if ($with-hover) {
&:hover {
background: linear-gradient(
180deg,
var(--button-hover-gradient-start) 0%,
var(--button-hover-gradient-end) 100%
);
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) { @if ($with-active) {
&:active, &:active {
&.active {
@include impressed-shadow(0.35); @include impressed-shadow(0.35);
border-color: color.scale($btn-base-color-night, $lightness: -20%);
}
&:active.active {
box-shadow: none; box-shadow: none;
border-color: $btn-base-color-night; border-color: var(--button-border);
} }
} }
@if ($with-disabled) { @if ($with-disabled) {
&[disabled] { &[disabled] {
background-color: $btn-base-color-night !important; color: var(--fg-disabled);
background-color: var(--button-gradient-end) !important;
box-shadow: none !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: vars.color(shadow-focus);
$focus-color: rgba(21 97 174);
@function down-arrow($color) { @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"); @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");

213
sass/_colors.scss Normal file
View file

@ -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,
),
);

55
sass/_functions.scss Normal file
View file

@ -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);
}

View file

@ -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;

View file

@ -1,113 +1,314 @@
/* Copyright: Ankitects Pty Ltd and contributors /* 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 */
:root { @use "sass:map";
--text-fg: black; @use "sass:color";
--window-bg: #ececec; @use "functions" as *;
--frame-bg: white; @use "colors" as *;
--border: #aaa;
--medium-border: #b6b6b6; @function palette($key, $shade) {
--faint-border: #e7e7e7; $color: map.get($colors, $key);
--link: #00a; @return map.get($color, $shade);
--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;
} }
:root[class*="night-mode"] { $vars: (
--text-fg: white; props: (
--window-bg: #2f2f31; border-radius: (
--frame-bg: #3a3a3a; default: 5px,
--border: #1f1f1f; ),
--medium-border: #444; ),
--faint-border: #29292b; colors: (
--link: #77ccff; fg: (
--review-count: #5ccc00; default: (
--new-count: #77ccff; light: palette(darkgray, 9),
--learn-count: #ff935b; dark: palette(lightgray, 0),
--zero-count: #444; ),
--slightly-grey-text: #ccc; subtle: (
--highlight-bg: #1e95df; light: palette(darkgray, 6),
--highlight-fg: white; dark: palette(lightgray, 3),
--disabled: #777; ),
--flag1-fg: #ff7b7b; disabled: (
--flag2-fg: #f5aa41; light: palette(darkgray, 3),
--flag3-fg: #86ce5d; dark: palette(lightgray, 6),
--flag4-fg: #6f9dff; ),
--flag5-fg: #f097e4; faint: (
--flag6-fg: #5ccfca; light: palette(lightgray, 7),
--flag7-fg: #9f63d3; dark: palette(darkgray, 2),
--flag1-bg: #aa5555; ),
--flag2-bg: #ac653a; ),
--flag3-bg: #559238; canvas: (
--flag4-bg: #506aa3; default: (
--flag5-bg: #975d8f; light: palette(lightgray, 3),
--flag6-bg: #399185; dark: palette(darkgray, 5),
--flag7-bg: #624b77; ),
--buried-fg: #777733; elevated: (
--suspended-fg: #ffffb2; light: white,
--suspended-bg: #aaaa33; dark: palette(darkgray, 4),
--marked-bg: #77c; ),
--tooltip-bg: #272727; inset: (
--focus-border: #316dca; light: palette(lightgray, 4),
--focus-shadow: #194380; dark: palette(darkgray, 6),
--code-bg: #272822; ),
--button-primary-gradient-start: #1769e2; overlay: (
--button-primary-gradient-end: #014996; light: white,
--button-primary-hover-gradient-start: #2877c2; dark: black,
--button-primary-hover-gradient-end: #0d5db3; ),
--button-primary-disabled: #4977a1; code: (
--button-gradient-start: #3f3f3f; light: white,
--button-gradient-end: #363636; dark: palette(darkgray, 6),
--button-hover-gradient-start: #434343; ),
--button-hover-gradient-end: #404040; ),
--button-pressed-shadow: #232323; border: (
--button-border: #2f2f31; default: (
--button-pressed-border: #0a0a0a; light: palette(lightgray, 7),
--scrollbar-bg: #434343; dark: palette(darkgray, 7),
--scrollbar-hover-bg: #4e4e4e; ),
--scrollbar-active-bg: #464646; 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 {
$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; 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};
}
}
}

View file

@ -1,10 +1,10 @@
@use "vars"; @use "vars";
@use "scrollbar"; @use "scrollbar";
$body-color: var(--text-fg); $body-color: var(--fg);
$body-bg: var(--window-bg); $body-bg: var(--canvas);
$link-hover-color: var(--link); $link-hover-color: var(--accent-link);
$link-hover-decoration: none; $link-hover-decoration: none;
$utilities: ( $utilities: (
@ -34,9 +34,10 @@ $utilities: (
body { body {
overscroll-behavior: none; overscroll-behavior: none;
@include scrollbar.custom;
} }
@include scrollbar.custom;
button { button {
/* override transition for instant hover response */ /* override transition for instant hover response */
transition: color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !important; 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 { .night-mode .form-select:disabled {
background-color: var(--disabled); background-color: var(--fg-disabled);
} }
.reduced-motion * { .reduced-motion * {

View file

@ -2,16 +2,15 @@
* 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 "vars"; @use "vars";
@use "fusion-vars";
@mixin night-mode { @mixin night-mode {
input, input,
select { select {
background-color: var(--frame-bg); background-color: var(--canvas-elevated);
border-color: var(--border); border-color: var(--border);
&:focus { &:focus {
background-color: var(--window-bg); background-color: var(--canvas);
} }
} }
} }

View file

@ -1,6 +1,8 @@
/* Copyright: Ankitects Pty Ltd and contributors /* 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 "vars";
$tooltip-padding-y: 0.45rem; $tooltip-padding-y: 0.45rem;
$tooltip-padding-x: 0.65rem; $tooltip-padding-x: 0.65rem;
$tooltip-max-width: 300px; $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 // the default code color in tooltips is difficult to read; we'll probably
// want to add more of our own styling in the future // want to add more of our own styling in the future
code { code {
color: #ffaaaa; color: palette(red, 0);
direction: inherit; direction: inherit;
} }
} }

View file

@ -1,7 +1,7 @@
@use "fusion-vars"; @use "vars";
:root { :root {
--focus-color: #0078d7; --focus-color: #{vars.palette-of(shadow-focus)};
.isMac { .isMac {
--focus-color: rgba(0 103 244 / 0.247); --focus-color: rgba(0 103 244 / 0.247);
@ -20,50 +20,30 @@
} }
} }
.isLin {
button {
font-size: 14px;
-webkit-appearance: none;
border-radius: 5px;
padding: 5px;
border: 1px solid var(--border);
}
}
.nightMode {
button { button {
-webkit-appearance: none; -webkit-appearance: none;
color: var(--text-fg); color: vars.color(fg);
/* match the fusion button gradient */
background: linear-gradient( background: linear-gradient(
0deg, 180deg,
fusion-vars.$button-gradient-start 0%, vars.color(button-gradient-start) 0%,
fusion-vars.$button-gradient-end 100% vars.color(button-gradient-end) 100%
); );
border: 1px solid fusion-vars.$button-border; border: 1px solid vars.color(button-border);
border-radius: 5px; border-radius: vars.prop(border-radius);
padding: 3px 10px 3px; padding: 3px 10px 3px;
&:focus { &:focus {
outline: none; outline: none;
box-shadow: 0 0 0 2px var(--focus-color); box-shadow: 0 0 0 1px var(--focus-color);
} }
} }
button:hover { button:hover {
background: fusion-vars.$button-hover-bg; background: linear-gradient(
} 180deg,
} vars.color(button-hover-gradient-start) 0%,
vars.color(button-hover-gradient-end) 100%
/* 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;
} }

View file

@ -1,21 +1,21 @@
.review-count { .review-count {
color: var(--review-count); color: var(--state-review);
} }
.new-count { .new-count {
color: var(--new-count); color: var(--state-new);
} }
.learn-count { .learn-count {
color: var(--learn-count); color: var(--state-learn);
} }
.zero-count { .zero-count {
color: var(--zero-count); color: var(--fg-faint);
} }
.bury-count { .bury-count {
color: var(--disabled); color: var(--fg-disabled);
font-weight: bold; font-weight: bold;
margin-inline-start: 2px; margin-inline-start: 2px;

View file

@ -8,14 +8,14 @@
} }
body { body {
color: var(--text-fg); color: var(--fg);
background: var(--window-bg); background: var(--canvas);
margin: 1em; margin: 1em;
transition: opacity 0.5s ease-out; transition: opacity 0.5s ease-out;
overscroll-behavior: none; overscroll-behavior: none;
} }
a { a {
color: var(--link); color: var(--accent-link);
text-decoration: none; text-decoration: none;
} }

View file

@ -2,10 +2,10 @@
* 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 */
@mixin input { @mixin input {
background-color: var(--frame-bg); background-color: var(--canvas-elevated);
border-color: var(--border); border-color: var(--border);
&:focus { &:focus {
background-color: var(--window-bg); background-color: var(--canvas);
} }
} }

View file

@ -2,11 +2,12 @@
* 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 "vars"; @use "vars";
@use "fusion-vars";
@mixin custom { @mixin custom {
.isWin,
.isLin {
::-webkit-scrollbar { ::-webkit-scrollbar {
background-color: var(--window-bg); background-color: vars.color(canvas);
&:horizontal { &:horizontal {
height: 12px; height: 12px;
@ -18,8 +19,8 @@
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
background: var(--scrollbar-bg); background: vars.color(scrollbar-bg);
border-radius: 5px; border-radius: vars.prop(border-radius);
&:horizontal { &:horizontal {
min-width: 50px; min-width: 50px;
@ -30,16 +31,16 @@
} }
&:hover { &:hover {
background: var(--scrollbar-hover-bg); background: vars.color(scrollbar-bg-hover);
} }
&:active { &:active {
background: var(--scrollbar-active-bg); background: vars.color(scrollbar-bg-active);
} }
} }
::-webkit-scrollbar-corner { ::-webkit-scrollbar-corner {
background-color: var(--window-bg); background-color: vars.color(canvas);
} }
::-webkit-scrollbar-track { ::-webkit-scrollbar-track {
@ -47,3 +48,4 @@
background-color: transparent; background-color: transparent;
} }
} }
}

View file

@ -177,16 +177,16 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
.revlog-learn { .revlog-learn {
color: var(--new-count); color: var(--state-new);
} }
.revlog-review { .revlog-review {
color: var(--review-count); color: var(--state-review);
} }
.revlog-relearn, .revlog-relearn,
.revlog-ease1 { .revlog-ease1 {
color: var(--learn-count); color: var(--state-learn);
} }
@media only screen and (max-device-width: 480px) and (orientation: portrait) { @media only screen and (max-device-width: 480px) and (orientation: portrait) {

View file

@ -72,10 +72,5 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
.btn-night { .btn-night {
color: white; color: white;
&:hover,
&:focus {
@include button.btn-night-base;
}
} }
</style> </style>

View file

@ -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-border-radius;
} }
@include button.btn-day; @include button.base(".icon-button");
@include button.btn-night;
</style> </style>

View file

@ -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-border-radius;
} }
@include button.btn-day; @include button.base($with-primary: true);
@include button.btn-night;
</style> </style>

View file

@ -13,7 +13,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<style lang="scss"> <style lang="scss">
.popover { .popover {
border-radius: 5px; border-radius: 5px;
background-color: var(--frame-bg); background-color: var(--canvas-elevated);
min-width: 1rem; min-width: 1rem;
max-width: 95vw; max-width: 95vw;
@ -21,7 +21,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
padding: var(--popover-padding-block, 6px) var(--popover-padding-inline, 6px); padding: var(--popover-padding-block, 6px) var(--popover-padding-inline, 6px);
font-size: 1rem; font-size: 1rem;
color: var(--text-fg); color: var(--fg);
/* outer border */ /* outer border */
border: 1px solid #b6b6b6; border: 1px solid #b6b6b6;

View file

@ -41,8 +41,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<style lang="scss"> <style lang="scss">
@use "sass/button-mixins" as button; @use "sass/button-mixins" as button;
@include button.btn-day($with-hover: false); @include button.base($selector: "select", $with-hover: false);
@include button.btn-night($with-hover: false);
select { select {
height: var(--buttons-size); height: var(--buttons-size);
@ -61,7 +60,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
&.btn-day { &.btn-day {
/* Hide default arrow for consistency */ /* Hide default arrow for consistency */
background: var(--frame-bg); background: var(--canvas-elevated);
} }
} }

View file

@ -13,6 +13,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<style lang="scss"> <style lang="scss">
.select-option { .select-option {
background-color: var(--frame-bg); background-color: var(--canvas-elevated);
} }
</style> </style>

View file

@ -29,9 +29,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
right: 0; right: 0;
z-index: 50; z-index: 50;
background: var(--sticky-bg, var(--window-bg)); background: var(--sticky-bg, var(--canvas));
border-style: solid; border-style: solid;
border-color: var(--sticky-border, var(--medium-border)); border-color: var(--sticky-border, var(--border));
border-width: var(--sticky-borders, 0); border-width: var(--sticky-borders, 0);
} }
</style> </style>

View file

@ -41,7 +41,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
.nightMode:not(:checked) { .nightMode:not(:checked) {
background-color: var(--frame-bg); background-color: var(--canvas-elevated);
border-color: var(--border); border-color: var(--border);
} }
</style> </style>

View file

@ -70,7 +70,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
font-size: var(--base-font-size); font-size: var(--base-font-size);
:global(a) { :global(a) {
color: var(--link); color: var(--accent-link);
text-decoration: none; text-decoration: none;
} }

View file

@ -36,8 +36,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
.card-state-customizer { .card-state-customizer {
color: var(--text-fg); color: var(--fg);
background-color: var(--frame-bg); background-color: var(--canvas-elevated);
width: 100%; width: 100%;
height: 10em; height: 10em;

View file

@ -41,7 +41,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
.nightMode:not(:checked) { .nightMode:not(:checked) {
background-color: var(--frame-bg); background-color: var(--canvas-elevated);
border-color: var(--border); border-color: var(--border);
} }
</style> </style>

View file

@ -69,15 +69,15 @@
padding: 0.25rem 1rem; padding: 0.25rem 1rem;
cursor: pointer; cursor: pointer;
margin: 0 8px -1px 0; margin: 0 8px -1px 0;
color: var(--disabled); color: var(--fg-subtle);
} }
li.active > span { li.active > span {
border-color: var(--border) var(--border) var(--window-bg); border-color: var(--border) var(--border) var(--canvas);
color: var(--text-fg); color: var(--fg);
} }
span:hover { span:hover {
color: var(--text-fg); color: var(--fg);
} }
</style> </style>

View file

@ -100,8 +100,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
.default-colors { .default-colors {
background-color: var(--window-bg); background-color: var(--canvas);
color: var(--text-fg); color: var(--fg);
} }
.invert { .invert {

View file

@ -16,6 +16,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<style lang="scss"> <style lang="scss">
h1 { h1 {
border-bottom: 1px solid var(--medium-border); border-bottom: 1px solid var(--border);
} }
</style> </style>

View file

@ -188,28 +188,27 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
/* grid-template-columns: repeat(2, 1fr); */ /* grid-template-columns: repeat(2, 1fr); */
position: relative; position: relative;
background: var(--frame-bg); background: var(--canvas-elevated);
border-radius: 5px; border-radius: 5px;
border: 1px solid var(--border);
box-shadow: 0px 0px 2px 0px var(--border); /* Pseudo-element required to display
transition: box-shadow 80ms cubic-bezier(0.33, 1, 0.68, 1); inset focus box-shadow above field contents */
&:focus-within {
outline: none;
/* This pseudo-element is required to display
the inset box-shadow above field contents */
&::after { &::after {
content: ""; content: "";
position: absolute; position: absolute;
top: -1px; inset: 0;
right: -1px;
bottom: -1px;
left: -1px;
pointer-events: none; pointer-events: none;
border-radius: 5px; border-radius: 5px;
box-shadow: inset 0 0 0 2px var(--focus-border); box-shadow: 0 0 2px 1px var(--shadow);
transition: box-shadow 80ms cubic-bezier(0.33, 1, 0.68, 1);
}
&:focus-within {
outline: none;
&::after {
border: none;
inset: 1px;
box-shadow: 0 0 0 2px var(--border-focus);
} }
} }
} }

View file

@ -326,7 +326,7 @@ the AddCards dialog) should be implemented in the user of this component.
{#if hint} {#if hint}
<Absolute bottom right --margin="10px"> <Absolute bottom right --margin="10px">
<Notification> <Notification>
<Badge --badge-color="tomato" --icon-align="top" <Badge --badge-color="var(--accent-danger)" --icon-align="top"
>{@html alertIcon}</Badge >{@html alertIcon}</Badge
> >
<span>{@html hint}</span> <span>{@html hint}</span>
@ -360,8 +360,8 @@ the AddCards dialog) should be implemented in the user of this component.
}} }}
collapsed={fieldsCollapsed[index]} collapsed={fieldsCollapsed[index]}
--label-color={cols[index] === "dupe" --label-color={cols[index] === "dupe"
? "var(--flag1-bg)" ? "palette-of(flag-1)"
: "var(--window-bg)"} : "palette-of(canvas)"}
> >
<svelte:fragment slot="field-label"> <svelte:fragment slot="field-label">
<LabelContainer <LabelContainer
@ -500,6 +500,6 @@ the AddCards dialog) should be implemented in the user of this component.
border-width: thin 0 0; border-width: thin 0 0;
border-style: solid; border-style: solid;
border-color: var(--medium-border); border-color: var(--border-subtle);
} }
</style> </style>

View file

@ -12,10 +12,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<style lang="scss"> <style lang="scss">
.notification { .notification {
background-color: var(--notification-bg, var(--window-bg)); background-color: var(--notification-bg, var(--canvas));
user-select: none; user-select: none;
border: 1px solid var(--medium-border); border: 1px solid var(--border);
border-radius: 5px; border-radius: 5px;
padding: 0.9rem 1.2rem; padding: 0.9rem 1.2rem;
} }

View file

@ -118,6 +118,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
border-width: 0 0 thin; border-width: 0 0 thin;
border-style: solid; border-style: solid;
border-color: var(--medium-border); border-color: var(--border-subtle);
} }
</style> </style>

View file

@ -1,11 +1,9 @@
/* Copyright: Ankitects Pty Ltd and contributors /* 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 "fusion-vars"; @use "sass/vars";
@use "sass:color"; @use "sass:color";
@use "sass/button-mixins" as button; @use "sass/button-mixins" as button;
$btn-base-color-day: white;
$btn-base-color-night: fusion-vars.$button-border;
$size: var(--buttons-size); $size: var(--buttons-size);
$padding: 2px; $padding: 2px;
@ -13,46 +11,10 @@ $padding: 2px;
width: $size; width: $size;
height: $size; height: $size;
padding: $padding; padding: $padding;
color: var(--text-fg);
font-size: calc($size * 0.6); 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, @include button.base($selector: ".linkb");
&: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%);
}
}
}
img.topbut { img.topbut {
max-width: calc($size - 2 * $padding); max-width: calc($size - 2 * $padding);

View file

@ -126,7 +126,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
font-family: sans-serif; font-family: sans-serif;
font-size: 55%; font-size: 55%;
text-align: center; text-align: center;
color: var(--slightly-grey-text); color: var(--fg-subtle);
} }
} }
</style> </style>

View file

@ -165,7 +165,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
border-radius: 0 0 5px 5px; border-radius: 0 0 5px 5px;
:global(.CodeMirror) { :global(.CodeMirror) {
background: var(--code-bg); background: var(--canvas-code);
border-radius: 0 0 5px 5px; border-radius: 0 0 5px 5px;
} }

View file

@ -143,7 +143,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
.search-link:hover { .search-link:hover {
cursor: pointer; cursor: pointer;
color: var(--link); color: var(--accent-link);
text-decoration: underline; text-decoration: underline;
} }
</style> </style>

View file

@ -19,7 +19,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<style lang="scss"> <style lang="scss">
.no-data { .no-data {
rect { rect {
fill: var(--window-bg); fill: var(--canvas);
} }
text { text {

View file

@ -117,8 +117,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
z-index: 1; z-index: 1;
top: 0; top: 0;
width: 100%; width: 100%;
color: var(--text-fg); color: var(--fg);
background: var(--window-bg); background: var(--canvas);
padding: 0.5em; padding: 0.5em;
@media print { @media print {

View file

@ -51,8 +51,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
opacity: 0; opacity: 0;
pointer-events: none; pointer-events: none;
transition: opacity 0.3s; transition: opacity 0.3s;
color: var(--text-fg); color: var(--fg);
background: var(--tooltip-bg); background: var(--canvas-overlay);
:global(table) { :global(table) {
border-spacing: 1em 0; border-spacing: 1em 0;

View file

@ -42,19 +42,19 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
td { td {
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
border: 1px solid var(--faint-border); border: 1px solid var(--border-subtle);
padding: 0.25rem 0.5rem; padding: 0.25rem 0.5rem;
max-width: 15em; max-width: 15em;
} }
th { th {
background: var(--medium-border); background: var(--border);
text-align: center; text-align: center;
} }
tr { tr {
&:nth-child(even) { &:nth-child(even) {
background: var(--frame-bg); background: var(--canvas-elevated);
} }
} }

View file

@ -50,7 +50,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
margin: 0; margin: 0;
padding: 0.25rem; padding: 0.25rem;
background: var(--window-bg); background: var(--canvas);
border-style: solid none none; border-style: solid none none;
border-color: var(--border); border-color: var(--border);
border-width: thin; border-width: thin;

View file

@ -210,7 +210,7 @@ export function _showAnswer(a: string, bodyclass: string): void {
export function _drawFlag(flag: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7): void { export function _drawFlag(flag: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7): void {
const elem = document.getElementById("_flag")!; const elem = document.getElementById("_flag")!;
elem.toggleAttribute("hidden", flag === 0); elem.toggleAttribute("hidden", flag === 0);
elem.style.color = `var(--flag${flag}-fg)`; elem.style.color = `var(--flag-${flag})`;
} }
export function _drawMark(mark: boolean): void { export function _drawMark(mark: boolean): void {

View file

@ -1,21 +1,22 @@
/* Copyright: Ankitects Pty Ltd and contributors /* 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 "vars";
hr { hr {
background-color: #ccc; background-color: vars.palette(darkgray, 0);
} }
body { body {
margin: 20px; margin: 20px;
overflow-wrap: break-word; overflow-wrap: break-word;
background-color: var(--window-bg); background-color: var(--canvas);
} }
// explicit nightMode definition required // explicit nightMode definition required
// to override default .card styling // to override default .card styling
body.nightMode { body.nightMode {
background-color: var(--window-bg); background-color: var(--canvas);
color: var(--text-fg); color: var(--fg);
} }
img { img {

View file

@ -37,6 +37,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
</button> </button>
<style lang="scss"> <style lang="scss">
@use "sass/vars";
@use "sass/button-mixins" as button; @use "sass/button-mixins" as button;
.autocomplete-item { .autocomplete-item {
@ -48,42 +49,5 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
border-radius: 0; border-radius: 0;
} }
button { @include button.base($with-disabled: false);
display: flex;
justify-content: space-between;
font-size: calc(var(--buttons-size) / 2.3);
background: none;
box-shadow: none !important;
border: none;
&.active {
background-color: button.$focus-color !important;
color: white !important;
}
}
/* reset global CSS from buttons.scss */
:global(.nightMode) button:hover {
background-color: inherit;
}
/* extra specificity bc of global CSS reset above */
button.btn-day {
color: black;
&.selected {
background-color: #e9ecef;
border-color: #e9ecef;
}
}
button.btn-night {
color: white;
&.selected {
@include button.btn-night-base;
}
}
</style> </style>

View file

@ -61,7 +61,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
font-size: var(--base-font-size); font-size: var(--base-font-size);
padding: 0; padding: 0;
--border-color: var(--medium-border); --border-color: var(--border);
border: 1px solid var(--border-color) !important; border: 1px solid var(--border-color) !important;
border-radius: 5px; border-radius: 5px;
@ -77,12 +77,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
&.selected { &.selected {
box-shadow: 0 0 0 2px var(--focus-shadow); box-shadow: 0 0 0 2px var(--border-focus);
--border-color: var(--focus-border); --border-color: var(--border-focus);
} }
} }
@include button.btn-day($with-active: false, $with-disabled: false); @include button.base($with-active: false, $with-disabled: false);
@include button.btn-night($with-active: false, $with-disabled: false);
</style> </style>

View file

@ -262,7 +262,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<style lang="scss"> <style lang="scss">
.tag-input { .tag-input {
width: 100%; width: 100%;
color: var(--text-fg); color: var(--fg);
background: none; background: none;
resize: none; resize: none;
appearance: none; appearance: none;