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(
name = "extract_sass_colors",
name = "extract_sass_vars",
srcs = [
"tools/extract_sass_colors.py",
"tools/extract_sass_vars.py",
],
imports = ["."],
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("//: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",
]

View file

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

View file

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

View file

@ -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("")

View file

@ -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",

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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(
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"],
)

View file

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

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
* 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};
}
}
}

View file

@ -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 * {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -13,7 +13,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<style lang="scss">
.popover {
border-radius: 5px;
background-color: var(--frame-bg);
background-color: var(--canvas-elevated);
min-width: 1rem;
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);
font-size: 1rem;
color: var(--text-fg);
color: var(--fg);
/* outer border */
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">
@use "sass/button-mixins" as button;
@include button.btn-day($with-hover: false);
@include button.btn-night($with-hover: false);
@include button.base($selector: "select", $with-hover: false);
select {
height: var(--buttons-size);
@ -61,7 +60,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
}
&.btn-day {
/* 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">
.select-option {
background-color: var(--frame-bg);
background-color: var(--canvas-elevated);
}
</style>

View file

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

View file

@ -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);
}
</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);
:global(a) {
color: var(--link);
color: var(--accent-link);
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 {
color: var(--text-fg);
background-color: var(--frame-bg);
color: var(--fg);
background-color: var(--canvas-elevated);
width: 100%;
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) {
background-color: var(--frame-bg);
background-color: var(--canvas-elevated);
border-color: var(--border);
}
</style>

View file

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

View file

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

View file

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

View file

@ -326,7 +326,7 @@ the AddCards dialog) should be implemented in the user of this component.
{#if hint}
<Absolute bottom right --margin="10px">
<Notification>
<Badge --badge-color="tomato" --icon-align="top"
<Badge --badge-color="var(--accent-danger)" --icon-align="top"
>{@html alertIcon}</Badge
>
<span>{@html hint}</span>
@ -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)"}
>
<svelte:fragment slot="field-label">
<LabelContainer
@ -500,6 +500,6 @@ the AddCards dialog) should be implemented in the user of this component.
border-width: thin 0 0;
border-style: solid;
border-color: var(--medium-border);
border-color: var(--border-subtle);
}
</style>

View file

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

View file

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

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-size: 55%;
text-align: center;
color: var(--slightly-grey-text);
color: var(--fg-subtle);
}
}
</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;
:global(.CodeMirror) {
background: var(--code-bg);
background: var(--canvas-code);
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 {
cursor: pointer;
color: var(--link);
color: var(--accent-link);
text-decoration: underline;
}
</style>

View file

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

View file

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

View file

@ -51,8 +51,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
opacity: 0;
pointer-events: none;
transition: opacity 0.3s;
color: var(--text-fg);
background: var(--tooltip-bg);
color: var(--fg);
background: var(--canvas-overlay);
:global(table) {
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 {
text-overflow: ellipsis;
overflow: hidden;
border: 1px solid var(--faint-border);
border: 1px solid var(--border-subtle);
padding: 0.25rem 0.5rem;
max-width: 15em;
}
th {
background: var(--medium-border);
background: var(--border);
text-align: center;
}
tr {
&: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;
padding: 0.25rem;
background: var(--window-bg);
background: var(--canvas);
border-style: solid none none;
border-color: var(--border);
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 {
const elem = document.getElementById("_flag")!;
elem.toggleAttribute("hidden", flag === 0);
elem.style.color = `var(--flag${flag}-fg)`;
elem.style.color = `var(--flag-${flag})`;
}
export function _drawMark(mark: boolean): void {

View file

@ -1,21 +1,22 @@
/* Copyright: Ankitects Pty Ltd and contributors
* License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */
@use "vars";
hr {
background-color: #ccc;
background-color: vars.palette(darkgray, 0);
}
body {
margin: 20px;
overflow-wrap: break-word;
background-color: var(--window-bg);
background-color: var(--canvas);
}
// explicit nightMode definition required
// to override default .card styling
body.nightMode {
background-color: var(--window-bg);
color: var(--text-fg);
background-color: var(--canvas);
color: var(--fg);
}
img {

View file

@ -37,6 +37,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
</button>
<style lang="scss">
@use "sass/vars";
@use "sass/button-mixins" as button;
.autocomplete-item {
@ -48,42 +49,5 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
border-radius: 0;
}
button {
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;
}
}
@include button.base($with-disabled: false);
</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);
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);
</style>

View file

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