basic night mode support

Forces the Fusion theme when running night mode, so we don't need
to work around platform themes that don't respond to the defined
palette.

Feedback/suggestions on the chosen colours welcome - _vars.scss is the
file to change if you want to experiment with adjustments.
This commit is contained in:
Damien Elmes 2020-01-23 15:08:10 +10:00
parent 44f2f16546
commit 7dcbc7efec
26 changed files with 430 additions and 115 deletions

View file

@ -226,11 +226,12 @@ def entsToTxt(html: str) -> str:
return reEnts.sub(fixup, html)
# legacy function
def bodyClass(col, card) -> str:
bodyclass = "card card%d" % (card.ord + 1)
if col.conf.get("nightMode"):
bodyclass += " nightMode"
return bodyclass
from aqt.theme import theme_manager
print("bodyClass() deprecated")
return theme_manager.body_classes_for_card_ord(card.ord)
# IDs

View file

@ -5,7 +5,7 @@ MAKEFLAGS += --warn-undefined-variables
MAKEFLAGS += --no-builtin-rules
.SUFFIXES:
BLACKARGS := -t py36 aqt tests setup.py tools/*.py --exclude='aqt/forms|buildinfo'
BLACKARGS := -t py36 aqt tests setup.py tools/*.py --exclude='aqt/forms|buildinfo|colors'
ISORTARGS := aqt tests setup.py
$(shell mkdir -p .build ../dist)
@ -33,6 +33,7 @@ TSDEPS := $(wildcard ts/src/*.ts) $(wildcard ts/scss/*.scss)
.build/js: $(TSDEPS)
(cd ts && npm i && npm run build)
python ./tools/extract_scss_colors.py
@touch $@
.build/hooks: tools/genhooks_gui.py ../pylib/tools/hookslib.py

1
qt/aqt/.gitignore vendored
View file

@ -1 +1,2 @@
buildinfo.py
colors.py

View file

@ -20,19 +20,12 @@ from anki.consts import *
from anki.lang import _, ngettext
from anki.models import NoteType
from anki.notes import Note
from anki.utils import (
bodyClass,
fmtTimeSpan,
htmlToTextLine,
ids2str,
intTime,
isMac,
isWin,
)
from anki.utils import fmtTimeSpan, htmlToTextLine, ids2str, intTime, isMac, isWin
from aqt import AnkiQt, gui_hooks
from aqt.editor import Editor
from aqt.qt import *
from aqt.sound import av_player
from aqt.theme import theme_manager
from aqt.utils import (
MenuList,
SubMenu,
@ -366,16 +359,6 @@ class DataModel(QAbstractTableModel):
# Line painter
######################################################################
COLOUR_SUSPENDED = "#FFFFB2"
COLOUR_MARKED = "#ccc"
flagColours = {
1: "#ffaaaa",
2: "#ffb347",
3: "#82E0AA",
4: "#85C1E9",
}
class StatusDelegate(QItemDelegate):
def __init__(self, browser, model):
@ -399,13 +382,13 @@ class StatusDelegate(QItemDelegate):
col = None
if c.userFlag() > 0:
col = flagColours[c.userFlag()]
col = theme_manager.qcolor(f"flag{c.userFlag()}-bg")
elif c.note().hasTag("Marked"):
col = COLOUR_MARKED
col = theme_manager.qcolor("marked-bg")
elif c.queue == -1:
col = COLOUR_SUSPENDED
col = theme_manager.qcolor("suspended-bg")
if col:
brush = QBrush(QColor(col))
brush = QBrush(col)
painter.save()
painter.fillRect(option.rect, brush)
painter.restore()
@ -450,7 +433,6 @@ class SidebarModel(QAbstractItemModel):
def __init__(self, root: SidebarItem) -> None:
super().__init__()
self.root = root
self.iconCache: Dict[str, QIcon] = {}
# Qt API
######################################################################
@ -510,18 +492,11 @@ class SidebarModel(QAbstractItemModel):
elif role == Qt.ToolTipRole:
return QVariant(item.tooltip)
else:
return QVariant(self.iconFromRef(item.icon))
return QVariant(theme_manager.icon_from_resources(item.icon))
# Helpers
######################################################################
def iconFromRef(self, iconRef: str) -> QIcon:
icon = self.iconCache.get(iconRef)
if icon is None:
icon = QIcon(iconRef)
self.iconCache[iconRef] = icon
return icon
def expandWhereNeccessary(self, tree: QTreeView) -> None:
for row, child in enumerate(self.root.children):
if child.expanded:
@ -821,8 +796,10 @@ class Browser(QMainWindow):
self.form.tableView.selectionModel()
self.form.tableView.setItemDelegate(StatusDelegate(self, self.model))
self.form.tableView.selectionModel().selectionChanged.connect(self.onRowChanged)
if not theme_manager.night_mode:
self.form.tableView.setStyleSheet(
"QTableView{ selection-background-color: rgba(127, 127, 127, 50); }"
"QTableView{ selection-background-color: rgba(150, 150, 150, 50); "
"selection-color: black; }"
)
self.singleCard = False
@ -1709,7 +1686,7 @@ where id in %s"""
txt = c.a()
txt = re.sub(r"\[\[type:[^]]+\]\]", "", txt)
bodyclass = bodyClass(self.mw.col, c)
bodyclass = theme_manager.body_classes_for_card_ord(c.ord)
if self.mw.reviewer.autoplay(c):
# if we're showing both sides at once, play question audio first

View file

@ -9,10 +9,11 @@ import re
import aqt
from anki.consts import *
from anki.lang import _, ngettext
from anki.utils import bodyClass, isMac, isWin, joinFields
from anki.utils import isMac, isWin, joinFields
from aqt import gui_hooks
from aqt.qt import *
from aqt.sound import av_player
from aqt.theme import theme_manager
from aqt.utils import (
askUser,
downArrow,
@ -336,7 +337,7 @@ Please create a new card type first."""
c = self.card
ti = self.maybeTextInput
bodyclass = bodyClass(self.mw.col, c)
bodyclass = theme_manager.body_classes_for_card_ord(c.ord)
q = ti(mungeQA(self.mw.col, c.q(reload=True)))
q = gui_hooks.card_will_show(q, c, "clayoutQuestion")

View file

@ -209,16 +209,16 @@ where id > ?""",
name,
)
# due counts
def nonzeroColour(cnt, colour):
def nonzeroColour(cnt, klass):
if not cnt:
colour = "#e0e0e0"
klass = "zero-count"
if cnt >= 1000:
cnt = "1000+"
return "<font color='%s'>%s</font>" % (colour, cnt)
return f'<span class="{klass}">{cnt}</span>'
buf += "<td align=right>%s</td><td align=right>%s</td>" % (
nonzeroColour(due, "#007700"),
nonzeroColour(new, "#000099"),
nonzeroColour(due, "review-count"),
nonzeroColour(new, "new-count"),
)
# options
buf += (

View file

@ -442,10 +442,10 @@ class Editor:
self.web.evalWithCallback("saveNow(%d)" % keepFocus, lambda res: callback())
def checkValid(self):
cols = ["#fff"] * len(self.note.fields)
cols = [""] * len(self.note.fields)
err = self.note.dupeOrEmpty()
if err == 2:
cols[0] = "#fcc"
cols[0] = "dupe"
self.web.eval("showDupes();")
else:
self.web.eval("hideDupes();")

View file

@ -5,7 +5,6 @@
import faulthandler
import gc
import os
import platform
import re
import signal
import time
@ -37,6 +36,7 @@ from aqt.profiles import ProfileManager as ProfileManagerType
from aqt.qt import *
from aqt.qt import sip
from aqt.taskman import TaskManager
from aqt.theme import theme_manager
from aqt.utils import (
askUser,
checkInvalidFilename,
@ -58,6 +58,7 @@ class AnkiQt(QMainWindow):
col: _Collection
pm: ProfileManagerType
web: aqt.webview.AnkiWebView
bottomWeb: aqt.webview.AnkiWebView
def __init__(
self,
@ -111,9 +112,9 @@ class AnkiQt(QMainWindow):
self.setupMediaServer()
self.setupSound()
self.setupSpellCheck()
self.setupStyle()
self.setupMainWindow()
self.setupSystemSpecific()
self.setupStyle()
self.setupMenus()
self.setupProgress()
self.setupErrorHandler()
@ -850,33 +851,8 @@ title="%s" %s>%s</button>""" % (
return True
def setupStyle(self) -> None:
buf = ""
if isWin and platform.release() == "10":
# add missing bottom border to menubar
buf += """
QMenuBar {
border-bottom: 1px solid #aaa;
background: white;
}
"""
# qt bug? setting the above changes the browser sidebar
# to white as well, so set it back
buf += """
QTreeWidget {
background: #eee;
}
"""
# allow addons to modify the styling
buf = gui_hooks.style_did_init(buf)
# allow users to extend styling
p = os.path.join(aqt.mw.pm.base, "style.css")
if os.path.exists(p):
buf += open(p).read()
self.app.setStyleSheet(buf)
theme_manager.night_mode = self.pm.night_mode()
theme_manager.apply_style(self.app)
# Key handling
##########################################################################

View file

@ -189,9 +189,9 @@ to their original deck."""
<table width=400 cellpadding=5>
<tr><td align=center valign=top>
<table cellspacing=5>
<tr><td>%s:</td><td><b><font color=#00a>%s</font></b></td></tr>
<tr><td>%s:</td><td><b><font color=#C35617>%s</font></b></td></tr>
<tr><td>%s:</td><td><b><font color=#0a0>%s</font></b></td></tr>
<tr><td>%s:</td><td><b><span class=new-count>%s</span></b></td></tr>
<tr><td>%s:</td><td><b><font class=learn-count>%s</span></b></td></tr>
<tr><td>%s:</td><td><b><span class=review-count>%s</span></b></td></tr>
</table>
</td><td align=center>
%s</td></tr></table>""" % (

View file

@ -85,7 +85,6 @@ class Preferences(QDialog):
f.timeLimit.setValue(qc["timeLim"] / 60.0)
f.showEstimates.setChecked(qc["estTimes"])
f.showProgress.setChecked(qc["dueCounts"])
f.nightMode.setChecked(qc.get("nightMode", False))
f.newSpread.addItems(list(c.newCardSchedulingLabels().values()))
f.newSpread.setCurrentIndex(qc["newSpread"])
f.useCurrent.setCurrentIndex(int(not qc.get("addToCur", True)))
@ -113,7 +112,6 @@ class Preferences(QDialog):
qc["dueCounts"] = f.showProgress.isChecked()
qc["estTimes"] = f.showEstimates.isChecked()
qc["newSpread"] = f.newSpread.currentIndex()
qc["nightMode"] = f.nightMode.isChecked()
qc["timeLim"] = f.timeLimit.value() * 60
qc["collapseTime"] = f.lrnCutoff.value() * 60
qc["addToCur"] = not f.useCurrent.currentIndex()
@ -227,12 +225,22 @@ Not currently enabled; click the sync button in the main window to enable."""
self.form.uiScale.setValue(self.mw.pm.uiScale() * 100)
self.form.pasteInvert.setChecked(self.prof.get("pasteInvert", False))
self.form.showPlayButtons.setChecked(self.prof.get("showPlayButtons", True))
self.form.nightMode.setChecked(self.mw.pm.night_mode())
def updateOptions(self):
restart_required = False
self.prof["pastePNG"] = self.form.pastePNG.isChecked()
self.prof["pasteInvert"] = self.form.pasteInvert.isChecked()
newScale = self.form.uiScale.value() / 100
if newScale != self.mw.pm.uiScale():
self.mw.pm.setUiScale(newScale)
showInfo(_("Changes will take effect when you restart Anki."))
restart_required = True
self.prof["showPlayButtons"] = self.form.showPlayButtons.isChecked()
if self.mw.pm.night_mode() != self.form.nightMode.isChecked():
self.mw.pm.set_night_mode(not self.mw.pm.night_mode())
restart_required = True
if restart_required:
showInfo(_("Changes will take effect when you restart Anki."))

View file

@ -495,3 +495,9 @@ please see:
def set_last_addon_update_check(self, secs):
self.meta["last_addon_update_check"] = secs
def night_mode(self) -> bool:
return self.meta.get("night_mode", False)
def set_night_mode(self, on: bool) -> None:
self.meta["night_mode"] = on

View file

@ -14,10 +14,11 @@ from anki import hooks
from anki.cards import Card
from anki.lang import _, ngettext
from anki.sound import AVTag
from anki.utils import bodyClass, stripHTML
from anki.utils import stripHTML
from aqt import AnkiQt, gui_hooks
from aqt.qt import *
from aqt.sound import av_player, getAudio
from aqt.theme import theme_manager
from aqt.toolbar import BottomBar
from aqt.utils import (
askUserDialog,
@ -199,7 +200,7 @@ The front of this card is empty. Please run Tools>Empty Cards."""
q = self._mungeQA(q)
q = gui_hooks.card_will_show(q, c, "reviewQuestion")
bodyclass = bodyClass(self.mw.col, c)
bodyclass = theme_manager.body_classes_for_card_ord(c.ord)
self.web.eval("_showQuestion(%s,'%s');" % (json.dumps(q), bodyclass))
self._drawFlag()
@ -600,9 +601,9 @@ time = %(time)d;
idx = self.mw.col.sched.countIdx(self.card)
counts[idx] = "<u>%s</u>" % (counts[idx])
space = " + "
ctxt = '<font color="#000099">%s</font>' % counts[0]
ctxt += space + '<font color="#C35617">%s</font>' % counts[1]
ctxt += space + '<font color="#007700">%s</font>' % counts[2]
ctxt = "<span class=new-count>%s</span>" % counts[0]
ctxt += space + "<span class=learn-count>%s</span>" % counts[1]
ctxt += space + "<span class=review-count>%s</span>" % counts[2]
return ctxt
def _defaultEase(self):

126
qt/aqt/theme.py Normal file
View file

@ -0,0 +1,126 @@
# -*- coding: utf-8 -*-
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import platform
from typing import Dict
from aqt import QApplication, gui_hooks, isWin
from aqt.colors import colors
from aqt.qt import QColor, QIcon, QPalette, QPixmap, QStyleFactory, Qt
class ThemeManager:
night_mode = True
_icon_cache: Dict[str, QIcon] = {}
_icon_size = 128
def icon_from_resources(self, path: str) -> QIcon:
"Fetch icon from Qt resources, and invert if in night mode."
icon = self._icon_cache.get(path)
if icon:
return icon
icon = QIcon(path)
if self.night_mode:
img = icon.pixmap(self._icon_size, self._icon_size).toImage()
img.invertPixels()
icon = QIcon(QPixmap(img))
return self._icon_cache.setdefault(path, icon)
def body_class(self) -> str:
"Returns '' in normal mode, 'nightMode' in night mode."
return self.night_mode and "nightMode" or ""
def body_classes_for_card_ord(self, card_ord: int) -> str:
"Returns body classes used when showing a card."
return f"card card{card_ord+1} {self.body_class()}"
def str_color(self, key: str) -> str:
"""Get a color defined in _vars.scss
If the colour is called '$day-frame-bg', key should be
'frame-bg'.
Returns the color as a string hex code or color name."""
prefix = self.night_mode and "night-" or "day-"
c = colors.get(prefix + key)
if c is None:
raise Exception("no such color:", key)
return c
def qcolor(self, key: str) -> QColor:
"""Get a color defined in _vars.scss as a QColor."""
return QColor(self.str_color(key))
def apply_style(self, app: QApplication) -> None:
self._apply_palette(app)
self._apply_style(app)
def _apply_style(self, app: QApplication) -> None:
buf = ""
if isWin and platform.release() == "10" and not self.night_mode:
# add missing bottom border to menubar
buf += """
QMenuBar {
border-bottom: 1px solid #aaa;
background: white;
}
"""
# qt bug? setting the above changes the browser sidebar
# to white as well, so set it back
buf += """
QTreeWidget {
background: #eee;
}
"""
# allow addons to modify the styling
buf = gui_hooks.style_did_init(buf)
app.setStyleSheet(buf)
def _apply_palette(self, app: QApplication) -> None:
if not self.night_mode:
return
app.setStyle(QStyleFactory.create("fusion")) # type: ignore
palette = QPalette()
text_fg = self.qcolor("text-fg")
palette.setColor(QPalette.WindowText, text_fg)
palette.setColor(QPalette.ToolTipBase, text_fg)
palette.setColor(QPalette.ToolTipText, text_fg)
palette.setColor(QPalette.Text, text_fg)
palette.setColor(QPalette.ButtonText, text_fg)
hlbg = self.qcolor("highlight-bg")
hlbg.setAlpha(64)
palette.setColor(QPalette.HighlightedText, self.qcolor("highlight-fg"))
palette.setColor(QPalette.Highlight, hlbg)
window_bg = self.qcolor("window-bg")
palette.setColor(QPalette.Window, window_bg)
palette.setColor(QPalette.AlternateBase, window_bg)
palette.setColor(QPalette.Button, window_bg)
palette.setColor(QPalette.Base, self.qcolor("frame-bg"))
disabled_color = self.qcolor("disabled")
palette.setColor(QPalette.Disabled, QPalette.Text, disabled_color)
palette.setColor(QPalette.Disabled, QPalette.ButtonText, disabled_color)
palette.setColor(QPalette.Disabled, QPalette.HighlightedText, disabled_color)
palette.setColor(QPalette.Link, self.qcolor("link"))
palette.setColor(QPalette.BrightText, Qt.red)
app.setPalette(palette)
theme_manager = ThemeManager()

View file

@ -10,6 +10,7 @@ from anki.lang import _
from anki.utils import isLin, isMac, isWin
from aqt import gui_hooks
from aqt.qt import *
from aqt.theme import theme_manager
from aqt.utils import openLink
# Page for debug messages
@ -308,6 +309,8 @@ div[contenteditable="true"]:focus {
head = mw.baseHTML() + head + csstxt + jstxt
body_class = theme_manager.body_class()
html = """
<!doctype html>
<html><head>
@ -321,7 +324,7 @@ body {{ zoom: {}; background: {}; {} }}
{}
</head>
<body>{}</body>
<body class="{}">{}</body>
</html>""".format(
self.title,
self.zoomFactor(),
@ -329,6 +332,7 @@ body {{ zoom: {}; background: {}; {} }}
fontspec,
widgetspec,
head,
body_class,
body,
)
# print(html)

View file

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>422</width>
<height>579</height>
<height>586</height>
</rect>
</property>
<property name="windowTitle">
@ -111,7 +111,7 @@
<item>
<widget class="QCheckBox" name="nightMode">
<property name="text">
<string>Show cards as white on black (night mode)</string>
<string>Night mode</string>
</property>
</widget>
</item>

View file

@ -0,0 +1,23 @@
import re
import json
colors = {}
for line in open("ts/scss/_vars.scss"):
line = line.strip()
if not line:
continue
m = re.match(r"^\$(.+): (.+);$", line)
if not m:
print("failed to match", line)
continue
var = m.group(1)
val = m.group(2)
colors[var] = val
with open("aqt/colors.py", "w") as buf:
buf.write("# this file is auto-generated from _vars.scss\n")
buf.write("colors = " + json.dumps(colors))

27
qt/ts/scss/_buttons.scss Normal file
View file

@ -0,0 +1,27 @@
@use 'vars';
.nightMode {
button {
-webkit-appearance: none;
color: vars.$night-text-fg;
/* match the fusion button gradient */
background: linear-gradient(0deg,
vars.$fusion-button-gradient-start 0%,
vars.$fusion-button-gradient-end 100%);
box-shadow: 0 0 3px vars.$fusion-button-outline;
border: 1px solid vars.$night-faint-border;
border-radius: 3px;
height: 24px;
padding: 5px;
padding-left: 10px;
padding-right: 10px;
padding-bottom: 18px;
}
button:hover {
background: vars.$fusion-button-hover-bg;
}
}

View file

@ -0,0 +1,28 @@
@use 'vars';
.review-count {
color: vars.$day-review-count;
}
.new-count {
color: vars.$day-new-count;
}
.learn-count {
color: vars.$day-learn-count;
}
.nightMode {
.review-count {
color: vars.$night-review-count;
}
.new-count {
color: vars.$night-new-count;
}
.learn-count {
color: vars.$night-learn-count;
}
}

46
qt/ts/scss/_vars.scss Normal file
View file

@ -0,0 +1,46 @@
$day-text-fg: black;
$day-window-bg: white;
$day-frame-bg: white;
$day-border: #aaa;
$day-faint-border: #e7e7e7;
$day-link: #00a;
$day-review-count: #0a0;
$day-new-count: #00a;
$day-learn-count: #C35617;
$day-zero-count: #aaa;
$day-slightly-grey-text: #333;
$day-highlight-bg: #77ccff;
$day-highlight-fg: black;
$day-disabled: #777;
$day-flag1-bg: #ffaaaa;
$day-flag2-bg: #ffb347;
$day-flag3-bg: #82E0AA;
$day-flag4-bg: #85C1E9;
$day-suspended-bg: #FFFFB2;
$day-marked-bg: #cce;
$night-text-fg: white;
$night-window-bg: #2f2f31;
$night-frame-bg: #3a3a3a;
$night-border: #777;
$night-faint-border: #444;
$night-link: #aaf;
$night-review-count: #7CFC00;
$night-new-count: #77ccff;
$night-learn-count: #FF935B;
$night-zero-count: #777;
$night-slightly-grey-text: #ccc;
$night-highlight-bg: #77ccff;
$night-highlight-fg: white;
$night-disabled: #777;
$night-flag1-bg: #aa5555;
$night-flag2-bg: #aa6337;
$night-flag3-bg: #33a055;
$night-flag4-bg: #3581a9;
$night-suspended-bg: #aaaa33;
$night-marked-bg: #77c;
$fusion-button-gradient-start: #363636;
$fusion-button-gradient-end: #404040;
$fusion-button-outline: #000;
$fusion-button-hover-bg: #454545;

View file

@ -1,8 +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 'card_counts';
a.deck {
color: #000;
color: vars.$day-text-fg;
text-decoration: none;
min-width: 5em;
display: inline-block;
@ -13,7 +16,7 @@ a.deck:hover {
}
tr.deck td {
border-bottom: 1px solid #e7e7e7;
border-bottom: 1px solid vars.$day-faint-border;
}
tr.top-level-drag-row td {
@ -25,7 +28,7 @@ td {
}
tr.drag-hover td {
border-bottom: 1px solid #aaa;
border-bottom: 1px solid vars.$day-border;
}
body {
@ -34,7 +37,7 @@ body {
}
.current {
background-color: #e7e7e7;
background-color: vars.$day-faint-border;
}
.decktd {
@ -51,14 +54,14 @@ body {
}
.collapse {
color: #000;
color: vars.$day-text-fg;
text-decoration: none;
display: inline-block;
width: 1em;
}
.filtered {
color: #00a !important;
color: vars.$day-link !important;
}
.gears {
@ -67,3 +70,29 @@ body {
opacity: .5;
padding-top: 0.2em;
}
.nightMode {
a.deck {
color: vars.$night-text-fg;
}
tr.deck td {
border-bottom-color: vars.$night-faint-border;
}
tr.drag-hover td {
border-bottom-color: vars.$night-border;
}
.current {
background-color: vars.$night-faint-border;
}
.collapse {
color: vars.$night-text-fg;
}
.gears {
filter: invert(180);
}
}

View file

@ -1,10 +1,12 @@
/* Copyright: Ankitects Pty Ltd and contributors
* License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */
@use 'vars';
.field {
border: 1px solid #aaa;
background: #fff;
color: #000;
border: 1px solid vars.$day-border;
background: vars.$day-frame-bg;
color: vars.$day-text-fg;
padding: 5px;
overflow-wrap: break-word;
}
@ -49,9 +51,10 @@ body {
color-stop(100%, #77f));
}
.linkb {
button.linkb {
-webkit-appearance: none;
border: 0;
box-shadow: none;
padding: 0px 2px;
background: transparent;
}
@ -68,3 +71,27 @@ body {
#fields {
margin-top: 35px;
}
.dupe {
background: #fcc;
}
.nightMode {
.field {
border-color: vars.$night-border;
background: vars.$night-frame-bg;
color: vars.$night-text-fg;
}
button.linkb > img {
filter: invert(180);
}
.dupe {
background: #a00;
}
#dupes a {
color: vars.$night-link;
}
}

View file

@ -1,6 +1,9 @@
/* Copyright: Ankitects Pty Ltd and contributors
* License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */
@use 'vars';
@use 'card_counts';
.smallLink {
font-size: 10px;
}
@ -11,7 +14,7 @@ h3 {
.descfont {
padding: 1em;
color: #333;
color: vars.$day-slightly-grey-text;
}
.description {
@ -31,3 +34,9 @@ h3 {
.dyn {
text-align: center;
}
.nightMode {
.descfont {
color: vars.$night-slightly-grey-text;
}
}

View file

@ -1,8 +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 'card_counts';
body {
margin: 0px;
margin: 0;
padding: 0;
}
@ -48,9 +51,15 @@ button {
}
#outer {
border-top: 1px solid #aaa;
border-top: 1px solid vars.$day-border;
}
#innertable {
padding: 3px;
}
.nightMode {
#outer {
border-top-color: vars.$night-border;
}
}

View file

@ -1,10 +1,12 @@
/* Copyright: Ankitects Pty Ltd and contributors
* License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */
@use 'vars';
#header {
padding: 3px;
font-weight: bold;
border-bottom: 1px solid #aaa;
border-bottom: 1px solid vars.$day-border;
}
.tdcenter {
@ -26,11 +28,7 @@ body {
padding-right: 12px;
padding-left: 12px;
text-decoration: none;
color: #000;
}
.nightMode .hitem {
color: white;
color: vars.$day-text-fg;
}
.hitem:hover {
@ -38,3 +36,13 @@ body {
}
.hitem:focus { outline: 0; }
.nightMode {
.hitem {
color: vars.$night-text-fg;
}
#header {
border-bottom-color: vars.$night-border;
}
}

View file

@ -1,6 +1,9 @@
/* Copyright: Ankitects Pty Ltd and contributors
* License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */
@use 'vars';
@use 'buttons';
body {
margin: 2em;
}
@ -10,6 +13,6 @@ h1 {
}
body.nightMode {
color: white;
background: #2f2f31;
color: vars.$night-text-fg;
background: vars.$night-window-bg;
}

View file

@ -352,7 +352,11 @@ function setFields(fields) {
function setBackgrounds(cols) {
for (let i = 0; i < cols.length; i++) {
$("#f" + i).css("background", cols[i]);
if (cols[i] == "dupe") {
$("#f" + i).addClass("dupe");
} else {
$("#f" + i).removeClass("dupe");
}
}
}