mirror of
https://github.com/ankitects/anki.git
synced 2025-09-23 08:22:24 -04:00
Merge branch 'main' into sassy-comments
This commit is contained in:
commit
876f1670cc
30 changed files with 327 additions and 134 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -118,6 +118,7 @@ dependencies = [
|
||||||
"unicase",
|
"unicase",
|
||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
"utime",
|
"utime",
|
||||||
|
"which",
|
||||||
"zip",
|
"zip",
|
||||||
"zstd",
|
"zstd",
|
||||||
]
|
]
|
||||||
|
|
|
@ -579,6 +579,15 @@ alias(
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
alias(
|
||||||
|
name = "which",
|
||||||
|
actual = "@raze__which__4_3_0//:which",
|
||||||
|
tags = [
|
||||||
|
"cargo-raze",
|
||||||
|
"manual",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
alias(
|
alias(
|
||||||
name = "zip",
|
name = "zip",
|
||||||
actual = "@raze__zip__0_6_2//:zip",
|
actual = "@raze__zip__0_6_2//:zip",
|
||||||
|
|
|
@ -60,7 +60,7 @@ editing-collapse-field = Collapse field
|
||||||
editing-underline-text = Underline text
|
editing-underline-text = Underline text
|
||||||
editing-unordered-list = Unordered list
|
editing-unordered-list = Unordered list
|
||||||
editing-warning-cloze-deletions-will-not-work = Warning, cloze deletions will not work until you switch the type at the top to Cloze.
|
editing-warning-cloze-deletions-will-not-work = Warning, cloze deletions will not work until you switch the type at the top to Cloze.
|
||||||
editing-toggle-mathjax-rendering = Toggle MathJax Rendering
|
editing-mathjax-preview = MathJax Preview
|
||||||
editing-shrink-images = Shrink Images
|
editing-shrink-images = Shrink Images
|
||||||
editing-close-html-tags = Auto-close HTML tags
|
editing-close-html-tags = Auto-close HTML tags
|
||||||
|
|
||||||
|
|
|
@ -579,6 +579,15 @@ alias(
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
alias(
|
||||||
|
name = "which",
|
||||||
|
actual = "@raze__which__4_3_0//:which",
|
||||||
|
tags = [
|
||||||
|
"cargo-raze",
|
||||||
|
"manual",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
alias(
|
alias(
|
||||||
name = "zip",
|
name = "zip",
|
||||||
actual = "@raze__zip__0_6_2//:zip",
|
actual = "@raze__zip__0_6_2//:zip",
|
||||||
|
|
|
@ -345,26 +345,19 @@ class AnkiApp(QApplication):
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
def eventFilter(self, src: Any, evt: QEvent) -> bool:
|
def eventFilter(self, src: Any, evt: QEvent) -> bool:
|
||||||
if evt.type() == QEvent.Type.HoverEnter:
|
pointer_classes = (
|
||||||
if (
|
QPushButton,
|
||||||
(
|
QCheckBox,
|
||||||
isinstance(
|
QRadioButton,
|
||||||
src,
|
QMenu,
|
||||||
(
|
# classes with PyQt5 compatibility proxy
|
||||||
QPushButton,
|
without_qt5_compat_wrapper(QToolButton),
|
||||||
QCheckBox,
|
without_qt5_compat_wrapper(QTabBar),
|
||||||
QRadioButton,
|
)
|
||||||
# classes with PyQt5 compatibility proxy
|
if evt.type() in [QEvent.Type.Enter, QEvent.Type.HoverEnter]:
|
||||||
without_qt5_compat_wrapper(QToolButton),
|
if (isinstance(src, pointer_classes) and src.isEnabled()) or (
|
||||||
without_qt5_compat_wrapper(QTabBar),
|
isinstance(src, without_qt5_compat_wrapper(QComboBox))
|
||||||
),
|
and not src.isEditable()
|
||||||
)
|
|
||||||
)
|
|
||||||
and src.isEnabled()
|
|
||||||
or (
|
|
||||||
isinstance(src, without_qt5_compat_wrapper(QComboBox))
|
|
||||||
and not src.isEditable()
|
|
||||||
)
|
|
||||||
):
|
):
|
||||||
self.setOverrideCursor(QCursor(Qt.CursorShape.PointingHandCursor))
|
self.setOverrideCursor(QCursor(Qt.CursorShape.PointingHandCursor))
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -226,6 +226,7 @@ def show(mw: aqt.AnkiQt) -> QDialog:
|
||||||
"Nicholas Flint",
|
"Nicholas Flint",
|
||||||
"Daniel Vieira Memoria10X",
|
"Daniel Vieira Memoria10X",
|
||||||
"Luka Warren",
|
"Luka Warren",
|
||||||
|
"Christos Longros",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -126,19 +126,22 @@ class Browser(QMainWindow):
|
||||||
self._closeEventHasCleanedUp = False
|
self._closeEventHasCleanedUp = False
|
||||||
self.form = aqt.forms.browser.Ui_Dialog()
|
self.form = aqt.forms.browser.Ui_Dialog()
|
||||||
self.form.setupUi(self)
|
self.form.setupUi(self)
|
||||||
restoreGeom(self, "editor", 0)
|
|
||||||
restoreSplitter(self.form.splitter, "editor3")
|
|
||||||
self.form.splitter.setChildrenCollapsible(False)
|
self.form.splitter.setChildrenCollapsible(False)
|
||||||
# set if exactly 1 row is selected; used by the previewer
|
# set if exactly 1 row is selected; used by the previewer
|
||||||
self.card: Card | None = None
|
self.card: Card | None = None
|
||||||
self.current_card: Card | None = None
|
self.current_card: Card | None = None
|
||||||
self.setupSidebar()
|
self.setupSidebar()
|
||||||
# make sure to call restoreState() after QDockWidget is attached to QMainWindow
|
|
||||||
restoreState(self, "editor")
|
|
||||||
self.setup_table()
|
self.setup_table()
|
||||||
self.setupMenus()
|
self.setupMenus()
|
||||||
self.setupHooks()
|
self.setupHooks()
|
||||||
self.setupEditor()
|
self.setupEditor()
|
||||||
|
|
||||||
|
# restoreXXX() should be called after all child widgets have been created
|
||||||
|
# and attached to QMainWindow
|
||||||
|
restoreGeom(self, "editor", 0)
|
||||||
|
restoreSplitter(self.form.splitter, "editor3")
|
||||||
|
restoreState(self, "editor")
|
||||||
|
|
||||||
# responsive layout
|
# responsive layout
|
||||||
self.aspect_ratio = self.width() / self.height()
|
self.aspect_ratio = self.width() / self.height()
|
||||||
self.set_layout(self.mw.pm.browser_layout(), True)
|
self.set_layout(self.mw.pm.browser_layout(), True)
|
||||||
|
|
|
@ -28,7 +28,8 @@ qlineargradient(
|
||||||
|
|
||||||
def general_styles(tm: ThemeManager) -> str:
|
def general_styles(tm: ThemeManager) -> str:
|
||||||
return f"""
|
return f"""
|
||||||
QFrame {{
|
QFrame,
|
||||||
|
QWidget {{
|
||||||
background: none;
|
background: none;
|
||||||
}}
|
}}
|
||||||
QPushButton,
|
QPushButton,
|
||||||
|
@ -38,7 +39,7 @@ QLineEdit,
|
||||||
QListWidget,
|
QListWidget,
|
||||||
QTreeWidget,
|
QTreeWidget,
|
||||||
QListView {{
|
QListView {{
|
||||||
border: 1px solid {tm.var(colors.BORDER)};
|
border: 1px solid {tm.var(colors.BORDER_SUBTLE)};
|
||||||
border-radius: {tm.var(props.BORDER_RADIUS)};
|
border-radius: {tm.var(props.BORDER_RADIUS)};
|
||||||
}}
|
}}
|
||||||
QLineEdit {{
|
QLineEdit {{
|
||||||
|
@ -58,6 +59,47 @@ QSpinBox {{
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def menu_styles(tm: ThemeManager) -> str:
|
||||||
|
return f"""
|
||||||
|
QMenuBar {{
|
||||||
|
border-bottom: 1px solid {tm.var(colors.BORDER_FAINT)};
|
||||||
|
}}
|
||||||
|
QMenuBar::item {{
|
||||||
|
background-color: transparent;
|
||||||
|
padding: 2px 4px;
|
||||||
|
border-radius: {tm.var(props.BORDER_RADIUS)};
|
||||||
|
}}
|
||||||
|
QMenuBar::item:selected {{
|
||||||
|
background-color: {tm.var(colors.CANVAS_ELEVATED)};
|
||||||
|
}}
|
||||||
|
QMenu {{
|
||||||
|
background-color: {tm.var(colors.CANVAS_OVERLAY)};
|
||||||
|
border: 1px solid {tm.var(colors.BORDER_SUBTLE)};
|
||||||
|
padding: 4px;
|
||||||
|
}}
|
||||||
|
QMenu::item {{
|
||||||
|
background-color: transparent;
|
||||||
|
padding: 3px 14px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}}
|
||||||
|
QMenu::item:selected {{
|
||||||
|
background-color: {tm.var(colors.CANVAS_INSET)};
|
||||||
|
color: {tm.var(colors.HIGHLIGHT_FG)};
|
||||||
|
border-radius: {tm.var(props.BORDER_RADIUS)};
|
||||||
|
}}
|
||||||
|
QMenu::separator {{
|
||||||
|
height: 1px;
|
||||||
|
background: {tm.var(colors.BORDER_SUBTLE)};
|
||||||
|
margin: 0 8px 4px 8px;
|
||||||
|
}}
|
||||||
|
QMenu::indicator {{
|
||||||
|
border: 1px solid {tm.var(colors.BORDER)};
|
||||||
|
margin-left: 6px;
|
||||||
|
margin-right: -6px;
|
||||||
|
}}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def button_styles(tm: ThemeManager) -> str:
|
def button_styles(tm: ThemeManager) -> str:
|
||||||
return f"""
|
return f"""
|
||||||
QPushButton {{
|
QPushButton {{
|
||||||
|
@ -184,7 +226,7 @@ QTabWidget::pane {{
|
||||||
top: -15px;
|
top: -15px;
|
||||||
padding-top: 1em;
|
padding-top: 1em;
|
||||||
background: {tm.var(colors.CANVAS_ELEVATED)};
|
background: {tm.var(colors.CANVAS_ELEVATED)};
|
||||||
border: 1px solid {tm.var(colors.BORDER)};
|
border: 1px solid {tm.var(colors.BORDER_SUBTLE)};
|
||||||
border-radius: {tm.var(props.BORDER_RADIUS)};
|
border-radius: {tm.var(props.BORDER_RADIUS)};
|
||||||
}}
|
}}
|
||||||
QTabWidget::tab-bar {{
|
QTabWidget::tab-bar {{
|
||||||
|
@ -196,7 +238,7 @@ QTabBar::tab {{
|
||||||
min-width: 8ex;
|
min-width: 8ex;
|
||||||
}}
|
}}
|
||||||
QTabBar::tab {{
|
QTabBar::tab {{
|
||||||
border: 1px solid {tm.var(colors.BORDER)};
|
border: 1px solid {tm.var(colors.BORDER_SUBTLE)};
|
||||||
}}
|
}}
|
||||||
QTabBar::tab:first {{
|
QTabBar::tab:first {{
|
||||||
border-top-{tm.left()}-radius: {tm.var(props.BORDER_RADIUS)};
|
border-top-{tm.left()}-radius: {tm.var(props.BORDER_RADIUS)};
|
||||||
|
@ -225,7 +267,7 @@ def table_styles(tm: ThemeManager) -> str:
|
||||||
return f"""
|
return f"""
|
||||||
QTableView {{
|
QTableView {{
|
||||||
border-radius: {tm.var(props.BORDER_RADIUS)};
|
border-radius: {tm.var(props.BORDER_RADIUS)};
|
||||||
gridline-color: {tm.var(colors.BORDER)};
|
gridline-color: {tm.var(colors.BORDER_SUBTLE)};
|
||||||
selection-background-color: {tm.var(colors.SELECTED_BG)};
|
selection-background-color: {tm.var(colors.SELECTED_BG)};
|
||||||
selection-color: {tm.var(colors.SELECTED_FG)};
|
selection-color: {tm.var(colors.SELECTED_FG)};
|
||||||
}}
|
}}
|
||||||
|
@ -233,7 +275,7 @@ QHeaderView {{
|
||||||
background: {tm.var(colors.CANVAS)};
|
background: {tm.var(colors.CANVAS)};
|
||||||
}}
|
}}
|
||||||
QHeaderView::section {{
|
QHeaderView::section {{
|
||||||
border: 1px solid {tm.var(colors.BORDER)};
|
border: 1px solid {tm.var(colors.BORDER_SUBTLE)};
|
||||||
background: {
|
background: {
|
||||||
button_gradient(
|
button_gradient(
|
||||||
tm.var(colors.BUTTON_GRADIENT_START),
|
tm.var(colors.BUTTON_GRADIENT_START),
|
||||||
|
@ -261,19 +303,19 @@ QHeaderView::section:hover {{
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
QHeaderView::section:first {{
|
QHeaderView::section:first {{
|
||||||
border-left: 1px solid {tm.var(colors.BORDER)};
|
border-left: 1px solid {tm.var(colors.BORDER_SUBTLE)};
|
||||||
border-top-left-radius: {tm.var(props.BORDER_RADIUS)};
|
border-top-left-radius: {tm.var(props.BORDER_RADIUS)};
|
||||||
}}
|
}}
|
||||||
QHeaderView::section:!first {{
|
QHeaderView::section:!first {{
|
||||||
border-left: none;
|
border-left: none;
|
||||||
}}
|
}}
|
||||||
QHeaderView::section:last {{
|
QHeaderView::section:last {{
|
||||||
border-right: 1px solid {tm.var(colors.BORDER)};
|
border-right: 1px solid {tm.var(colors.BORDER_SUBTLE)};
|
||||||
border-top-right-radius: {tm.var(props.BORDER_RADIUS)};
|
border-top-right-radius: {tm.var(props.BORDER_RADIUS)};
|
||||||
}}
|
}}
|
||||||
QHeaderView::section:only-one {{
|
QHeaderView::section:only-one {{
|
||||||
border-left: 1px solid {tm.var(colors.BORDER)};
|
border-left: 1px solid {tm.var(colors.BORDER_SUBTLE)};
|
||||||
border-right: 1px solid {tm.var(colors.BORDER)};
|
border-right: 1px solid {tm.var(colors.BORDER_SUBTLE)};
|
||||||
border-top-left-radius: {tm.var(props.BORDER_RADIUS)};
|
border-top-left-radius: {tm.var(props.BORDER_RADIUS)};
|
||||||
border-top-right-radius: {tm.var(props.BORDER_RADIUS)};
|
border-top-right-radius: {tm.var(props.BORDER_RADIUS)};
|
||||||
}}
|
}}
|
||||||
|
@ -374,16 +416,16 @@ QRadioButton {{
|
||||||
margin: 2px 0;
|
margin: 2px 0;
|
||||||
}}
|
}}
|
||||||
QCheckBox::indicator,
|
QCheckBox::indicator,
|
||||||
QRadioButton::indicator {{
|
QRadioButton::indicator,
|
||||||
|
QMenu::indicator {{
|
||||||
border: 1px solid {tm.var(colors.BORDER_SUBTLE)};
|
border: 1px solid {tm.var(colors.BORDER_SUBTLE)};
|
||||||
|
border-radius: {tm.var(props.BORDER_RADIUS)};
|
||||||
background: {tm.var(colors.CANVAS_INSET)};
|
background: {tm.var(colors.CANVAS_INSET)};
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}}
|
}}
|
||||||
QCheckBox::indicator {{
|
QRadioButton::indicator,
|
||||||
border-radius: {tm.var(props.BORDER_RADIUS)};
|
QMenu::indicator:exclusive {{
|
||||||
}}
|
|
||||||
QRadioButton::indicator {{
|
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}}
|
}}
|
||||||
QCheckBox::indicator:hover,
|
QCheckBox::indicator:hover,
|
||||||
|
@ -395,7 +437,8 @@ QRadioButton::indicator:checked:hover {{
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}}
|
}}
|
||||||
QCheckBox::indicator:checked,
|
QCheckBox::indicator:checked,
|
||||||
QRadioButton::indicator:checked {{
|
QRadioButton::indicator:checked,
|
||||||
|
QMenu::indicator:checked {{
|
||||||
image: url({tm.themed_icon("mdi:check")});
|
image: url({tm.themed_icon("mdi:check")});
|
||||||
}}
|
}}
|
||||||
QCheckBox::indicator:indeterminate {{
|
QCheckBox::indicator:indeterminate {{
|
||||||
|
@ -445,20 +488,3 @@ QScrollBar::sub-line {{
|
||||||
background: none;
|
background: none;
|
||||||
}}
|
}}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def win10_styles(tm: ThemeManager) -> str:
|
|
||||||
return f"""
|
|
||||||
/* day mode is missing a bottom border; background must be
|
|
||||||
also set for border to apply */
|
|
||||||
QMenuBar {{
|
|
||||||
border-bottom: 1px solid {tm.var(colors.BORDER)};
|
|
||||||
background: {tm.var(colors.CANVAS) if tm.night_mode else "white"};
|
|
||||||
}}
|
|
||||||
|
|
||||||
/* qt bug? setting the above changes the browser sidebar
|
|
||||||
to white as well, so set it back */
|
|
||||||
QTreeWidget {{
|
|
||||||
background: {tm.var(colors.CANVAS)};
|
|
||||||
}}
|
|
||||||
"""
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ from __future__ import annotations
|
||||||
|
|
||||||
import enum
|
import enum
|
||||||
import os
|
import os
|
||||||
import platform
|
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
@ -227,29 +226,27 @@ class ThemeManager:
|
||||||
checkbox_styles,
|
checkbox_styles,
|
||||||
combobox_styles,
|
combobox_styles,
|
||||||
general_styles,
|
general_styles,
|
||||||
|
menu_styles,
|
||||||
scrollbar_styles,
|
scrollbar_styles,
|
||||||
spinbox_styles,
|
spinbox_styles,
|
||||||
table_styles,
|
table_styles,
|
||||||
tabwidget_styles,
|
tabwidget_styles,
|
||||||
win10_styles,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
buf += "".join(
|
buf += "".join(
|
||||||
[
|
[
|
||||||
general_styles(self),
|
general_styles(self),
|
||||||
button_styles(self),
|
button_styles(self),
|
||||||
|
checkbox_styles(self),
|
||||||
|
menu_styles(self),
|
||||||
combobox_styles(self),
|
combobox_styles(self),
|
||||||
tabwidget_styles(self),
|
tabwidget_styles(self),
|
||||||
table_styles(self),
|
table_styles(self),
|
||||||
spinbox_styles(self),
|
spinbox_styles(self),
|
||||||
checkbox_styles(self),
|
|
||||||
scrollbar_styles(self),
|
scrollbar_styles(self),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
if is_win and platform.release() == "10":
|
|
||||||
buf += win10_styles(self)
|
|
||||||
|
|
||||||
# allow addons to modify the styling
|
# allow addons to modify the styling
|
||||||
buf = gui_hooks.style_did_init(buf)
|
buf = gui_hooks.style_did_init(buf)
|
||||||
|
|
||||||
|
|
|
@ -115,12 +115,12 @@ def register_repos():
|
||||||
################
|
################
|
||||||
|
|
||||||
core_i18n_repo = "anki-core-i18n"
|
core_i18n_repo = "anki-core-i18n"
|
||||||
core_i18n_commit = "71bfeda9ef7667f3454e7341969835168768bd54"
|
core_i18n_commit = "b9d5c896f22fe6e79810194f41222d8638c13e16"
|
||||||
core_i18n_zip_csum = "4b4203d862aa1d90c0c391fac00bdf8ba0a8bffe00e4ba5fd36b2c7b288613c9"
|
core_i18n_zip_csum = "8ef7888373cacf682c17f41056dc1f5348f60a15e1809c8db0f66f4072e7d5fb"
|
||||||
|
|
||||||
qtftl_i18n_repo = "anki-desktop-ftl"
|
qtftl_i18n_repo = "anki-desktop-ftl"
|
||||||
qtftl_i18n_commit = "aa0e656fa4b0b9c926fc7436cb62418d8995e666"
|
qtftl_i18n_commit = "a8bd0e284e2785421180af2ce10dd1d534b0033d"
|
||||||
qtftl_i18n_zip_csum = "5949b0e19b92f8699e9f1a3ca17abf9249103232aa408b4bb21bb6c5d1ff28bc"
|
qtftl_i18n_zip_csum = "f88398324a64be99521bd5cd7e79e7dda64c31a2cd4e568328a211c7765b23ac"
|
||||||
|
|
||||||
i18n_build_content = """
|
i18n_build_content = """
|
||||||
filegroup(
|
filegroup(
|
||||||
|
|
|
@ -31,6 +31,7 @@ cargo_build_script(
|
||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
"//rslib/cargo:prost_build",
|
"//rslib/cargo:prost_build",
|
||||||
|
"//rslib/cargo:which",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ required-features = ["bench"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
prost-build = "0.11.1"
|
prost-build = "0.11.1"
|
||||||
|
which = "4.3.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.9.1"
|
env_logger = "0.9.1"
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{env, fmt::Write, path::PathBuf};
|
use std::{
|
||||||
|
env,
|
||||||
|
fmt::Write,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
struct CustomGenerator {}
|
struct CustomGenerator {}
|
||||||
|
|
||||||
|
@ -71,6 +75,7 @@ fn service_generator() -> Box<dyn prost_build::ServiceGenerator> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_backend_proto_rs() {
|
pub fn write_backend_proto_rs() {
|
||||||
|
maybe_add_protobuf_to_path();
|
||||||
let proto_dir = if let Ok(proto) = env::var("PROTO_TOP") {
|
let proto_dir = if let Ok(proto) = env::var("PROTO_TOP") {
|
||||||
PathBuf::from(proto).parent().unwrap().to_owned()
|
PathBuf::from(proto).parent().unwrap().to_owned()
|
||||||
} else {
|
} else {
|
||||||
|
@ -122,3 +127,27 @@ pub fn write_backend_proto_rs() {
|
||||||
.compile_protos(paths.as_slice(), &[proto_dir])
|
.compile_protos(paths.as_slice(), &[proto_dir])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If PROTOC is not defined, and protoc is not on path, use the protoc
|
||||||
|
/// fetched by Bazel so that Rust Analyzer does not fail.
|
||||||
|
fn maybe_add_protobuf_to_path() {
|
||||||
|
if std::env::var("PROTOC").is_ok() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if which::which("protoc").is_ok() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let path = if cfg!(target_os = "windows") {
|
||||||
|
let base = std::fs::read_link("../.bazel/out").unwrap();
|
||||||
|
base.join("../external/protoc_bin_windows/bin/protoc.exe")
|
||||||
|
} else {
|
||||||
|
let base = Path::new("../.bazel/out/../external");
|
||||||
|
let subpath = if cfg!(target_os = "macos") {
|
||||||
|
"protoc_bin_macos/bin/protoc"
|
||||||
|
} else {
|
||||||
|
"protoc_bin_linux_x86_64/bin/protoc"
|
||||||
|
};
|
||||||
|
base.join(subpath)
|
||||||
|
};
|
||||||
|
std::env::set_var("PROTOC", path.to_str().unwrap());
|
||||||
|
}
|
||||||
|
|
|
@ -579,6 +579,15 @@ alias(
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
alias(
|
||||||
|
name = "which",
|
||||||
|
actual = "@raze__which__4_3_0//:which",
|
||||||
|
tags = [
|
||||||
|
"cargo-raze",
|
||||||
|
"manual",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
alias(
|
alias(
|
||||||
name = "zip",
|
name = "zip",
|
||||||
actual = "@raze__zip__0_6_2//:zip",
|
actual = "@raze__zip__0_6_2//:zip",
|
||||||
|
|
|
@ -579,6 +579,15 @@ alias(
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
alias(
|
||||||
|
name = "which",
|
||||||
|
actual = "@raze__which__4_3_0//:which",
|
||||||
|
tags = [
|
||||||
|
"cargo-raze",
|
||||||
|
"manual",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
alias(
|
alias(
|
||||||
name = "zip",
|
name = "zip",
|
||||||
actual = "@raze__zip__0_6_2//:zip",
|
actual = "@raze__zip__0_6_2//:zip",
|
||||||
|
|
|
@ -579,6 +579,15 @@ alias(
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
alias(
|
||||||
|
name = "which",
|
||||||
|
actual = "@raze__which__4_3_0//:which",
|
||||||
|
tags = [
|
||||||
|
"cargo-raze",
|
||||||
|
"manual",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
alias(
|
alias(
|
||||||
name = "zip",
|
name = "zip",
|
||||||
actual = "@raze__zip__0_6_2//:zip",
|
actual = "@raze__zip__0_6_2//:zip",
|
||||||
|
|
|
@ -579,6 +579,15 @@ alias(
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
alias(
|
||||||
|
name = "which",
|
||||||
|
actual = "@raze__which__4_3_0//:which",
|
||||||
|
tags = [
|
||||||
|
"cargo-raze",
|
||||||
|
"manual",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
alias(
|
alias(
|
||||||
name = "zip",
|
name = "zip",
|
||||||
actual = "@raze__zip__0_6_2//:zip",
|
actual = "@raze__zip__0_6_2//:zip",
|
||||||
|
|
|
@ -89,11 +89,14 @@ $vars: (
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
overlay: (
|
overlay: (
|
||||||
"Background of floating elements (menus, tooltips)",
|
<<<<<<< HEAD "Background of floating elements (menus, tooltips)",
|
||||||
(
|
(
|
||||||
light: white,
|
light: white,
|
||||||
dark: black,
|
dark: black,
|
||||||
),
|
),
|
||||||
|
======= light: palette(lightgray, 0),
|
||||||
|
dark: palette(darkgray, 5),
|
||||||
|
>>>>>>> main,
|
||||||
),
|
),
|
||||||
code: (
|
code: (
|
||||||
"Background of code editors",
|
"Background of code editors",
|
||||||
|
@ -105,7 +108,8 @@ $vars: (
|
||||||
),
|
),
|
||||||
border: (
|
border: (
|
||||||
default: (
|
default: (
|
||||||
"Border color with medium contrast against window background",
|
<<<<<<< HEAD
|
||||||
|
"Border color with medium contrast against window background",
|
||||||
(
|
(
|
||||||
light: palette(lightgray, 6),
|
light: palette(lightgray, 6),
|
||||||
dark: palette(darkgray, 7),
|
dark: palette(darkgray, 7),
|
||||||
|
@ -117,6 +121,9 @@ $vars: (
|
||||||
light: palette(lightgray, 5),
|
light: palette(lightgray, 5),
|
||||||
dark: palette(darkgray, 6),
|
dark: palette(darkgray, 6),
|
||||||
),
|
),
|
||||||
|
======= light: palette(lightgray, 6),
|
||||||
|
dark: palette(darkgray, 4),
|
||||||
|
>>>>>>> main,
|
||||||
),
|
),
|
||||||
strong: (
|
strong: (
|
||||||
"Border color with high contrast against window background",
|
"Border color with high contrast against window background",
|
||||||
|
@ -125,6 +132,14 @@ $vars: (
|
||||||
dark: palette(darkgray, 1),
|
dark: palette(darkgray, 1),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
subtle: (
|
||||||
|
light: palette(lightgray, 5),
|
||||||
|
dark: palette(darkgray, 7),
|
||||||
|
),
|
||||||
|
faint: (
|
||||||
|
light: palette(lightgray, 4),
|
||||||
|
dark: palette(darkgray, 6),
|
||||||
|
),
|
||||||
focus: (
|
focus: (
|
||||||
"Border color of focused input elements",
|
"Border color of focused input elements",
|
||||||
(
|
(
|
||||||
|
@ -402,8 +417,8 @@ $vars: (
|
||||||
bg: (
|
bg: (
|
||||||
"Background color of highlighted items",
|
"Background color of highlighted items",
|
||||||
(
|
(
|
||||||
light: palette(blue, 3),
|
light: color.scale(palette(blue, 3), $alpha: -33%),
|
||||||
dark: palette(blue, 4),
|
dark: color.scale(palette(blue, 4), $alpha: -33%),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
fg: (
|
fg: (
|
||||||
|
|
|
@ -3,6 +3,9 @@ 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
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from "svelte";
|
||||||
|
import { fly } from "svelte/transition";
|
||||||
|
|
||||||
import { on } from "../lib/events";
|
import { on } from "../lib/events";
|
||||||
import { Callback, singleCallback } from "../lib/typing";
|
import { Callback, singleCallback } from "../lib/typing";
|
||||||
import IconConstrain from "./IconConstrain.svelte";
|
import IconConstrain from "./IconConstrain.svelte";
|
||||||
|
@ -12,8 +15,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
export let panes: ResizablePane[];
|
export let panes: ResizablePane[];
|
||||||
export let index = 0;
|
export let index = 0;
|
||||||
export let tip = "";
|
export let tip = "";
|
||||||
|
export let showIndicator = false;
|
||||||
export let clientHeight: number;
|
export let clientHeight: number;
|
||||||
|
|
||||||
|
const rtl = window.getComputedStyle(document.body).direction == "rtl";
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
let destroy: Callback;
|
let destroy: Callback;
|
||||||
|
|
||||||
let before: ResizablePane;
|
let before: ResizablePane;
|
||||||
|
@ -77,18 +85,31 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
destroy = singleCallback(
|
destroy = singleCallback(
|
||||||
on(window, "pointermove", onMove),
|
on(window, "pointermove", onMove),
|
||||||
on(window, "pointerup", releasePointer),
|
on(window, "pointerup", () => {
|
||||||
|
releasePointer.call(window);
|
||||||
|
dispatch("release");
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="horizontal-resizer"
|
class="horizontal-resizer"
|
||||||
|
class:rtl
|
||||||
title={tip}
|
title={tip}
|
||||||
bind:clientHeight={resizerHeight}
|
bind:clientHeight={resizerHeight}
|
||||||
on:pointerdown|preventDefault={lockPointer}
|
on:pointerdown|preventDefault={lockPointer}
|
||||||
on:dblclick
|
on:dblclick|preventDefault
|
||||||
>
|
>
|
||||||
|
{#if showIndicator}
|
||||||
|
<div
|
||||||
|
class="resize-indicator"
|
||||||
|
transition:fly={{ x: rtl ? 25 : -25, duration: 200 }}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div class="drag-handle">
|
<div class="drag-handle">
|
||||||
<IconConstrain iconSize={80}>{@html horizontalHandle}</IconConstrain>
|
<IconConstrain iconSize={80}>{@html horizontalHandle}</IconConstrain>
|
||||||
</div>
|
</div>
|
||||||
|
@ -99,7 +120,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
width: 100%;
|
width: 100%;
|
||||||
cursor: row-resize;
|
cursor: row-resize;
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 10px;
|
height: 25px;
|
||||||
border-top: 1px solid var(--border);
|
border-top: 1px solid var(--border);
|
||||||
|
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
|
@ -113,5 +134,15 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
&:hover .drag-handle {
|
&:hover .drag-handle {
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.resize-indicator {
|
||||||
|
position: absolute;
|
||||||
|
font-size: small;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
&.rtl .resize-indicator {
|
||||||
|
padding: 0.5rem 0 0 0.5rem;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -59,5 +59,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
.pane {
|
.pane {
|
||||||
@include panes.resizable(column, true, true);
|
@include panes.resizable(column, true, true);
|
||||||
|
opacity: var(--opacity, 1);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -6,7 +6,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import IconConstrain from "./IconConstrain.svelte";
|
import IconConstrain from "./IconConstrain.svelte";
|
||||||
import { chevronLeft, chevronRight } from "./icons";
|
import { chevronLeft, chevronRight } from "./icons";
|
||||||
|
|
||||||
export let value = 1;
|
export let value: number;
|
||||||
export let step = 1;
|
export let step = 1;
|
||||||
export let min = 1;
|
export let min = 1;
|
||||||
export let max = 9999;
|
export let max = 9999;
|
||||||
|
@ -22,7 +22,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
}
|
}
|
||||||
|
|
||||||
let stringValue: string;
|
let stringValue: string;
|
||||||
$: stringValue = value.toFixed(decimalPlaces(step));
|
$: if (value) stringValue = value.toFixed(decimalPlaces(step));
|
||||||
|
|
||||||
function update(this: HTMLInputElement): void {
|
function update(this: HTMLInputElement): void {
|
||||||
value = Math.min(max, Math.max(min, parseFloat(this.value)));
|
value = Math.min(max, Math.max(min, parseFloat(this.value)));
|
||||||
|
|
|
@ -355,12 +355,28 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
$: tagAmount = $tags.length;
|
$: tagAmount = $tags.length;
|
||||||
|
|
||||||
|
let snapTags = $tagsCollapsed;
|
||||||
|
|
||||||
function collapseTags(): void {
|
function collapseTags(): void {
|
||||||
lowerResizer.move([tagsPane, fieldsPane], tagsPane.minHeight);
|
lowerResizer.move([tagsPane, fieldsPane], tagsPane.minHeight);
|
||||||
|
$tagsCollapsed = snapTags = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function expandTags(): void {
|
function expandTags(): void {
|
||||||
lowerResizer.move([tagsPane, fieldsPane], tagsPane.maxHeight);
|
lowerResizer.move([tagsPane, fieldsPane], tagsPane.maxHeight);
|
||||||
|
$tagsCollapsed = snapTags = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("resize", () => snapResizer(snapTags));
|
||||||
|
|
||||||
|
function snapResizer(collapse: boolean): void {
|
||||||
|
if (collapse) {
|
||||||
|
collapseTags();
|
||||||
|
bridgeCommand("collapseTags");
|
||||||
|
} else {
|
||||||
|
expandTags();
|
||||||
|
bridgeCommand("expandTags");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -390,7 +406,9 @@ the AddCards dialog) should be implemented in the user of this component.
|
||||||
|
|
||||||
<Pane
|
<Pane
|
||||||
bind:this={fieldsPane.resizable}
|
bind:this={fieldsPane.resizable}
|
||||||
on:resize={(e) => (fieldsPane.height = e.detail.height)}
|
on:resize={(e) => {
|
||||||
|
fieldsPane.height = e.detail.height;
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<PaneContent>
|
<PaneContent>
|
||||||
<Fields>
|
<Fields>
|
||||||
|
@ -553,7 +571,17 @@ the AddCards dialog) should be implemented in the user of this component.
|
||||||
</PaneContent>
|
</PaneContent>
|
||||||
</Pane>
|
</Pane>
|
||||||
|
|
||||||
{#if $tagsCollapsed}
|
<HorizontalResizer
|
||||||
|
panes={[fieldsPane, tagsPane]}
|
||||||
|
showIndicator={$tagsCollapsed || snapTags}
|
||||||
|
tip={`Double click to ${$tagsCollapsed ? "expand" : "collapse"} tag editor`}
|
||||||
|
{clientHeight}
|
||||||
|
bind:this={lowerResizer}
|
||||||
|
on:dblclick={() => snapResizer(!$tagsCollapsed)}
|
||||||
|
on:release={() => {
|
||||||
|
snapResizer(snapTags);
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div class="tags-expander">
|
<div class="tags-expander">
|
||||||
<TagAddButton
|
<TagAddButton
|
||||||
on:tagappend={() => {
|
on:tagappend={() => {
|
||||||
|
@ -564,36 +592,28 @@ the AddCards dialog) should be implemented in the user of this component.
|
||||||
{@html tagAmount > 0 ? `${tagAmount} Tags` : ""}
|
{@html tagAmount > 0 ? `${tagAmount} Tags` : ""}
|
||||||
</TagAddButton>
|
</TagAddButton>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
</HorizontalResizer>
|
||||||
|
|
||||||
<HorizontalResizer
|
|
||||||
panes={[fieldsPane, tagsPane]}
|
|
||||||
tip={`Double click to ${$tagsCollapsed ? "expand" : "collapse"} tag editor`}
|
|
||||||
{clientHeight}
|
|
||||||
bind:this={lowerResizer}
|
|
||||||
on:dblclick={() => {
|
|
||||||
if ($tagsCollapsed) {
|
|
||||||
expandTags();
|
|
||||||
bridgeCommand("expandTags");
|
|
||||||
$tagsCollapsed = false;
|
|
||||||
} else {
|
|
||||||
collapseTags();
|
|
||||||
bridgeCommand("collapseTags");
|
|
||||||
$tagsCollapsed = true;
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Pane
|
<Pane
|
||||||
bind:this={tagsPane.resizable}
|
bind:this={tagsPane.resizable}
|
||||||
on:resize={(e) => {
|
on:resize={(e) => {
|
||||||
tagsPane.height = e.detail.height;
|
tagsPane.height = e.detail.height;
|
||||||
$tagsCollapsed = tagsPane.height == 0;
|
if (tagsPane.maxHeight > 0) {
|
||||||
|
snapTags = tagsPane.height < tagsPane.maxHeight / 2;
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
|
--opacity={(() => {
|
||||||
|
if (!$tagsCollapsed) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return snapTags ? tagsPane.height / tagsPane.maxHeight : 1;
|
||||||
|
}
|
||||||
|
})()}
|
||||||
>
|
>
|
||||||
<PaneContent scroll={false}>
|
<PaneContent scroll={false}>
|
||||||
<TagEditor
|
<TagEditor
|
||||||
{tags}
|
{tags}
|
||||||
|
--button-opacity={snapTags ? 0 : 1}
|
||||||
bind:this={tagEditor}
|
bind:this={tagEditor}
|
||||||
on:tagsupdate={saveTags}
|
on:tagsupdate={saveTags}
|
||||||
on:tagsFocused={() => {
|
on:tagsFocused={() => {
|
||||||
|
@ -617,7 +637,4 @@ the AddCards dialog) should be implemented in the user of this component.
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
.tags-expander {
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -9,7 +9,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import Shortcut from "../../components/Shortcut.svelte";
|
import Shortcut from "../../components/Shortcut.svelte";
|
||||||
import WithFloating from "../../components/WithFloating.svelte";
|
import WithFloating from "../../components/WithFloating.svelte";
|
||||||
import { mathjaxConfig } from "../../editable/mathjax-element";
|
import { mathjaxConfig } from "../../editable/mathjax-element";
|
||||||
import { bridgeCommand } from "../../lib/bridgecommand";
|
|
||||||
import * as tr from "../../lib/ftl";
|
import * as tr from "../../lib/ftl";
|
||||||
import { getPlatformString } from "../../lib/shortcuts";
|
import { getPlatformString } from "../../lib/shortcuts";
|
||||||
import { wrapInternal } from "../../lib/wrap";
|
import { wrapInternal } from "../../lib/wrap";
|
||||||
|
@ -27,15 +26,27 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMathjaxInline(): void {
|
function onMathjaxInline(): void {
|
||||||
surround("<anki-mathjax focusonmount>", "</anki-mathjax>");
|
if (mathjaxConfig.enabled) {
|
||||||
|
surround("<anki-mathjax focusonmount>", "</anki-mathjax>");
|
||||||
|
} else {
|
||||||
|
surround("\\(", "\\)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMathjaxBlock(): void {
|
function onMathjaxBlock(): void {
|
||||||
surround('<anki-mathjax block="true" focusonmount>', "</anki-matjax>");
|
if (mathjaxConfig.enabled) {
|
||||||
|
surround('<anki-mathjax block="true" focusonmount>', "</anki-matjax>");
|
||||||
|
} else {
|
||||||
|
surround("\\[", "\\]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMathjaxChemistry(): void {
|
function onMathjaxChemistry(): void {
|
||||||
surround('<anki-mathjax focusonmount="0,4">\\ce{', "}</anki-mathjax>");
|
if (mathjaxConfig.enabled) {
|
||||||
|
surround('<anki-mathjax focusonmount="0,4">\\ce{', "}</anki-mathjax>");
|
||||||
|
} else {
|
||||||
|
surround("\\(\\ce{", "}\\)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onLatex(): void {
|
function onLatex(): void {
|
||||||
|
@ -50,11 +61,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
surround("[$$]", "[/$$]");
|
surround("[$$]", "[/$$]");
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleShowMathjax(): void {
|
|
||||||
mathjaxConfig.enabled = !mathjaxConfig.enabled;
|
|
||||||
bridgeCommand("toggleMathjax");
|
|
||||||
}
|
|
||||||
|
|
||||||
type LatexItem = [() => void, string, string];
|
type LatexItem = [() => void, string, string];
|
||||||
|
|
||||||
const dropdownItems: LatexItem[] = [
|
const dropdownItems: LatexItem[] = [
|
||||||
|
@ -94,10 +100,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
>
|
>
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<DropdownItem on:click={toggleShowMathjax}>
|
|
||||||
<span>{tr.editingToggleMathjaxRendering()}</span>
|
|
||||||
</DropdownItem>
|
|
||||||
</Popover>
|
</Popover>
|
||||||
</WithFloating>
|
</WithFloating>
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import IconButton from "../../components/IconButton.svelte";
|
import IconButton from "../../components/IconButton.svelte";
|
||||||
import Popover from "../../components/Popover.svelte";
|
import Popover from "../../components/Popover.svelte";
|
||||||
import WithFloating from "../../components/WithFloating.svelte";
|
import WithFloating from "../../components/WithFloating.svelte";
|
||||||
|
import { mathjaxConfig } from "../../editable/mathjax-element";
|
||||||
import { bridgeCommand } from "../../lib/bridgecommand";
|
import { bridgeCommand } from "../../lib/bridgecommand";
|
||||||
import * as tr from "../../lib/ftl";
|
import * as tr from "../../lib/ftl";
|
||||||
import { shrinkImagesByDefault } from "../image-overlay/ImageOverlay.svelte";
|
import { shrinkImagesByDefault } from "../image-overlay/ImageOverlay.svelte";
|
||||||
|
@ -22,6 +23,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
showFloating = false;
|
showFloating = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleShowMathjax(_evt: MouseEvent): void {
|
||||||
|
mathjaxConfig.enabled = !mathjaxConfig.enabled;
|
||||||
|
bridgeCommand("toggleMathjax");
|
||||||
|
}
|
||||||
|
|
||||||
function toggleCloseHTMLTags(_evt: MouseEvent): void {
|
function toggleCloseHTMLTags(_evt: MouseEvent): void {
|
||||||
$closeHTMLTags = !$closeHTMLTags;
|
$closeHTMLTags = !$closeHTMLTags;
|
||||||
bridgeCommand("toggleCloseHTMLTags");
|
bridgeCommand("toggleCloseHTMLTags");
|
||||||
|
@ -50,6 +56,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
<CheckBox value={$shrinkImagesByDefault} />
|
<CheckBox value={$shrinkImagesByDefault} />
|
||||||
<span class="d-flex-inline ps-3">{tr.editingShrinkImages()}</span>
|
<span class="d-flex-inline ps-3">{tr.editingShrinkImages()}</span>
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
|
<DropdownItem on:click={toggleShowMathjax}>
|
||||||
|
<CheckBox value={mathjaxConfig.enabled} />
|
||||||
|
<span class="d-flex-inline ps-3">{tr.editingMathjaxPreview()}</span>
|
||||||
|
</DropdownItem>
|
||||||
<DropdownItem on:click={toggleCloseHTMLTags}>
|
<DropdownItem on:click={toggleCloseHTMLTags}>
|
||||||
<CheckBox value={$closeHTMLTags} />
|
<CheckBox value={$closeHTMLTags} />
|
||||||
<span class="d-flex-inline ps-3">{tr.editingCloseHtmlTags()}</span>
|
<span class="d-flex-inline ps-3">{tr.editingCloseHtmlTags()}</span>
|
||||||
|
|
|
@ -99,7 +99,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
{configuration}
|
{configuration}
|
||||||
bind:api={codeMirror}
|
bind:api={codeMirror}
|
||||||
on:change={({ detail: mathjaxText }) => code.set(mathjaxText)}
|
on:change={({ detail: mathjaxText }) => code.set(mathjaxText)}
|
||||||
on:tab
|
on:blur
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -65,14 +65,18 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clear(): void {
|
||||||
|
unsubscribe();
|
||||||
|
activeImage = null;
|
||||||
|
mathjaxElement = null;
|
||||||
|
}
|
||||||
|
|
||||||
async function resetHandle(): Promise<void> {
|
async function resetHandle(): Promise<void> {
|
||||||
selectAll = false;
|
selectAll = false;
|
||||||
position = undefined;
|
position = undefined;
|
||||||
|
|
||||||
if (activeImage && mathjaxElement) {
|
if (activeImage && mathjaxElement) {
|
||||||
unsubscribe();
|
clear();
|
||||||
activeImage = null;
|
|
||||||
mathjaxElement = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
allow();
|
allow();
|
||||||
|
@ -188,10 +192,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
placeHandle(true);
|
placeHandle(true);
|
||||||
await resetHandle();
|
await resetHandle();
|
||||||
}}
|
}}
|
||||||
on:tab={async () => {
|
on:blur={async () => {
|
||||||
// Instead of resetting on blur, we reset on tab
|
|
||||||
// Otherwise, when clicking from Mathjax element to another,
|
|
||||||
// the user has to click twice (focus is called before blur?)
|
|
||||||
await resetHandle();
|
await resetHandle();
|
||||||
}}
|
}}
|
||||||
let:editor={mathjaxEditor}
|
let:editor={mathjaxEditor}
|
||||||
|
@ -220,8 +221,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
}}
|
}}
|
||||||
on:delete={async () => {
|
on:delete={async () => {
|
||||||
placeCaretAfter(activeImage);
|
placeCaretAfter(activeImage);
|
||||||
activeImage.remove();
|
mathjaxElement?.remove();
|
||||||
await resetHandle();
|
clear();
|
||||||
}}
|
}}
|
||||||
on:surround={async ({ detail }) => {
|
on:surround={async ({ detail }) => {
|
||||||
const editor = await mathjaxEditor.editor;
|
const editor = await mathjaxEditor.editor;
|
||||||
|
|
|
@ -6,7 +6,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
export let selected = false;
|
export let selected = false;
|
||||||
export let active = false;
|
export let active = false;
|
||||||
|
|
||||||
let buttonRef: HTMLButtonElement;
|
let buttonRef: HTMLElement;
|
||||||
|
|
||||||
$: if (selected && buttonRef) {
|
$: if (selected && buttonRef) {
|
||||||
/* buttonRef.scrollIntoView({ behavior: "smooth", block: "start" }); */
|
/* buttonRef.scrollIntoView({ behavior: "smooth", block: "start" }); */
|
||||||
|
@ -18,7 +18,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button
|
<div
|
||||||
bind:this={buttonRef}
|
bind:this={buttonRef}
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
class="autocomplete-item"
|
class="autocomplete-item"
|
||||||
|
@ -30,20 +30,26 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
on:mouseleave
|
on:mouseleave
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</button>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@use "sass/button-mixins" as button;
|
@use "sass/button-mixins" as button;
|
||||||
|
|
||||||
.autocomplete-item {
|
.autocomplete-item {
|
||||||
@include button.base($with-disabled: false, $active-class: active);
|
padding: 4px 8px;
|
||||||
padding: 1px 7px 2px;
|
|
||||||
|
|
||||||
text-align: start;
|
text-align: start;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
&:not(:first-child) {
|
||||||
|
border-top-color: var(--border-subtle);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
@include button.base($with-disabled: false, $active-class: active);
|
||||||
|
}
|
||||||
&.selected {
|
&.selected {
|
||||||
@include button.base(
|
@include button.base(
|
||||||
$primary: true,
|
$primary: true,
|
||||||
|
|
|
@ -490,6 +490,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: row wrap;
|
flex-flow: row wrap;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
|
background: var(--canvas-inset);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
padding: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tag-relative {
|
.tag-relative {
|
||||||
|
|
|
@ -186,9 +186,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
flex-flow: column nowrap;
|
flex-flow: column nowrap;
|
||||||
|
|
||||||
width: 80vw;
|
width: 80vw;
|
||||||
max-height: 7rem;
|
max-height: 30vh;
|
||||||
|
|
||||||
font-size: 11px;
|
font-size: 13px;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
|
@ -25,6 +25,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.tag-options-button {
|
.tag-options-button {
|
||||||
padding: 6px 3px 0;
|
transition: opacity 0.2s linear;
|
||||||
|
opacity: var(--button-opacity, 1);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in a new issue