diff --git a/Cargo.lock b/Cargo.lock index 068f85711..da19d3704 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -118,6 +118,7 @@ dependencies = [ "unicase", "unicode-normalization", "utime", + "which", "zip", "zstd", ] diff --git a/cargo/BUILD.bazel b/cargo/BUILD.bazel index 2b529535e..42a561ba5 100644 --- a/cargo/BUILD.bazel +++ b/cargo/BUILD.bazel @@ -579,6 +579,15 @@ alias( ], ) +alias( + name = "which", + actual = "@raze__which__4_3_0//:which", + tags = [ + "cargo-raze", + "manual", + ], +) + alias( name = "zip", actual = "@raze__zip__0_6_2//:zip", diff --git a/ftl/core/editing.ftl b/ftl/core/editing.ftl index 75b915f11..b91dcb390 100644 --- a/ftl/core/editing.ftl +++ b/ftl/core/editing.ftl @@ -60,7 +60,7 @@ editing-collapse-field = Collapse field editing-underline-text = Underline text 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-toggle-mathjax-rendering = Toggle MathJax Rendering +editing-mathjax-preview = MathJax Preview editing-shrink-images = Shrink Images editing-close-html-tags = Auto-close HTML tags diff --git a/pylib/rsbridge/cargo/BUILD.bazel b/pylib/rsbridge/cargo/BUILD.bazel index 5104f9b3e..cf09ad565 100644 --- a/pylib/rsbridge/cargo/BUILD.bazel +++ b/pylib/rsbridge/cargo/BUILD.bazel @@ -579,6 +579,15 @@ alias( ], ) +alias( + name = "which", + actual = "@raze__which__4_3_0//:which", + tags = [ + "cargo-raze", + "manual", + ], +) + alias( name = "zip", actual = "@raze__zip__0_6_2//:zip", diff --git a/qt/aqt/__init__.py b/qt/aqt/__init__.py index 767975982..378f058e3 100644 --- a/qt/aqt/__init__.py +++ b/qt/aqt/__init__.py @@ -345,26 +345,19 @@ class AnkiApp(QApplication): ################################################## def eventFilter(self, src: Any, evt: QEvent) -> bool: - if evt.type() == QEvent.Type.HoverEnter: - if ( - ( - isinstance( - src, - ( - QPushButton, - QCheckBox, - QRadioButton, - # classes with PyQt5 compatibility proxy - without_qt5_compat_wrapper(QToolButton), - without_qt5_compat_wrapper(QTabBar), - ), - ) - ) - and src.isEnabled() - or ( - isinstance(src, without_qt5_compat_wrapper(QComboBox)) - and not src.isEditable() - ) + pointer_classes = ( + QPushButton, + QCheckBox, + QRadioButton, + QMenu, + # classes with PyQt5 compatibility proxy + without_qt5_compat_wrapper(QToolButton), + without_qt5_compat_wrapper(QTabBar), + ) + if evt.type() in [QEvent.Type.Enter, QEvent.Type.HoverEnter]: + if (isinstance(src, pointer_classes) and src.isEnabled()) or ( + isinstance(src, without_qt5_compat_wrapper(QComboBox)) + and not src.isEditable() ): self.setOverrideCursor(QCursor(Qt.CursorShape.PointingHandCursor)) else: diff --git a/qt/aqt/about.py b/qt/aqt/about.py index 9197d7caa..643317304 100644 --- a/qt/aqt/about.py +++ b/qt/aqt/about.py @@ -226,6 +226,7 @@ def show(mw: aqt.AnkiQt) -> QDialog: "Nicholas Flint", "Daniel Vieira Memoria10X", "Luka Warren", + "Christos Longros", ) ) diff --git a/qt/aqt/browser/browser.py b/qt/aqt/browser/browser.py index 22a354747..1afe0ae67 100644 --- a/qt/aqt/browser/browser.py +++ b/qt/aqt/browser/browser.py @@ -126,19 +126,22 @@ class Browser(QMainWindow): self._closeEventHasCleanedUp = False self.form = aqt.forms.browser.Ui_Dialog() self.form.setupUi(self) - restoreGeom(self, "editor", 0) - restoreSplitter(self.form.splitter, "editor3") self.form.splitter.setChildrenCollapsible(False) # set if exactly 1 row is selected; used by the previewer self.card: Card | None = None self.current_card: Card | None = None self.setupSidebar() - # make sure to call restoreState() after QDockWidget is attached to QMainWindow - restoreState(self, "editor") self.setup_table() self.setupMenus() self.setupHooks() 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 self.aspect_ratio = self.width() / self.height() self.set_layout(self.mw.pm.browser_layout(), True) diff --git a/qt/aqt/stylesheets.py b/qt/aqt/stylesheets.py index 54afdb83d..a50468e48 100644 --- a/qt/aqt/stylesheets.py +++ b/qt/aqt/stylesheets.py @@ -28,7 +28,8 @@ qlineargradient( def general_styles(tm: ThemeManager) -> str: return f""" -QFrame {{ +QFrame, +QWidget {{ background: none; }} QPushButton, @@ -38,7 +39,7 @@ QLineEdit, QListWidget, QTreeWidget, QListView {{ - border: 1px solid {tm.var(colors.BORDER)}; + border: 1px solid {tm.var(colors.BORDER_SUBTLE)}; border-radius: {tm.var(props.BORDER_RADIUS)}; }} 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: return f""" QPushButton {{ @@ -184,7 +226,7 @@ QTabWidget::pane {{ top: -15px; padding-top: 1em; 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)}; }} QTabWidget::tab-bar {{ @@ -196,7 +238,7 @@ QTabBar::tab {{ min-width: 8ex; }} QTabBar::tab {{ - border: 1px solid {tm.var(colors.BORDER)}; + border: 1px solid {tm.var(colors.BORDER_SUBTLE)}; }} QTabBar::tab:first {{ border-top-{tm.left()}-radius: {tm.var(props.BORDER_RADIUS)}; @@ -225,7 +267,7 @@ def table_styles(tm: ThemeManager) -> str: return f""" QTableView {{ 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-color: {tm.var(colors.SELECTED_FG)}; }} @@ -233,7 +275,7 @@ QHeaderView {{ background: {tm.var(colors.CANVAS)}; }} QHeaderView::section {{ - border: 1px solid {tm.var(colors.BORDER)}; + border: 1px solid {tm.var(colors.BORDER_SUBTLE)}; background: { button_gradient( tm.var(colors.BUTTON_GRADIENT_START), @@ -261,19 +303,19 @@ QHeaderView::section:hover {{ }; }} 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)}; }} QHeaderView::section:!first {{ border-left: none; }} 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)}; }} QHeaderView::section:only-one {{ - border-left: 1px solid {tm.var(colors.BORDER)}; - border-right: 1px solid {tm.var(colors.BORDER)}; + border-left: 1px solid {tm.var(colors.BORDER_SUBTLE)}; + border-right: 1px solid {tm.var(colors.BORDER_SUBTLE)}; border-top-left-radius: {tm.var(props.BORDER_RADIUS)}; border-top-right-radius: {tm.var(props.BORDER_RADIUS)}; }} @@ -374,16 +416,16 @@ QRadioButton {{ margin: 2px 0; }} QCheckBox::indicator, -QRadioButton::indicator {{ +QRadioButton::indicator, +QMenu::indicator {{ border: 1px solid {tm.var(colors.BORDER_SUBTLE)}; + border-radius: {tm.var(props.BORDER_RADIUS)}; background: {tm.var(colors.CANVAS_INSET)}; width: 16px; height: 16px; }} -QCheckBox::indicator {{ - border-radius: {tm.var(props.BORDER_RADIUS)}; -}} -QRadioButton::indicator {{ +QRadioButton::indicator, +QMenu::indicator:exclusive {{ border-radius: 8px; }} QCheckBox::indicator:hover, @@ -395,7 +437,8 @@ QRadioButton::indicator:checked:hover {{ height: 14px; }} QCheckBox::indicator:checked, -QRadioButton::indicator:checked {{ +QRadioButton::indicator:checked, +QMenu::indicator:checked {{ image: url({tm.themed_icon("mdi:check")}); }} QCheckBox::indicator:indeterminate {{ @@ -445,20 +488,3 @@ QScrollBar::sub-line {{ 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)}; -}} - """ diff --git a/qt/aqt/theme.py b/qt/aqt/theme.py index 2e869f5d5..52f6b9459 100644 --- a/qt/aqt/theme.py +++ b/qt/aqt/theme.py @@ -5,7 +5,6 @@ from __future__ import annotations import enum import os -import platform import re import subprocess from dataclasses import dataclass @@ -227,29 +226,27 @@ class ThemeManager: checkbox_styles, combobox_styles, general_styles, + menu_styles, scrollbar_styles, spinbox_styles, table_styles, tabwidget_styles, - win10_styles, ) buf += "".join( [ general_styles(self), button_styles(self), + checkbox_styles(self), + menu_styles(self), combobox_styles(self), tabwidget_styles(self), table_styles(self), spinbox_styles(self), - checkbox_styles(self), scrollbar_styles(self), ] ) - if is_win and platform.release() == "10": - buf += win10_styles(self) - # allow addons to modify the styling buf = gui_hooks.style_did_init(buf) diff --git a/repos.bzl b/repos.bzl index b9250d337..3a51186c8 100644 --- a/repos.bzl +++ b/repos.bzl @@ -115,12 +115,12 @@ def register_repos(): ################ core_i18n_repo = "anki-core-i18n" - core_i18n_commit = "71bfeda9ef7667f3454e7341969835168768bd54" - core_i18n_zip_csum = "4b4203d862aa1d90c0c391fac00bdf8ba0a8bffe00e4ba5fd36b2c7b288613c9" + core_i18n_commit = "b9d5c896f22fe6e79810194f41222d8638c13e16" + core_i18n_zip_csum = "8ef7888373cacf682c17f41056dc1f5348f60a15e1809c8db0f66f4072e7d5fb" qtftl_i18n_repo = "anki-desktop-ftl" - qtftl_i18n_commit = "aa0e656fa4b0b9c926fc7436cb62418d8995e666" - qtftl_i18n_zip_csum = "5949b0e19b92f8699e9f1a3ca17abf9249103232aa408b4bb21bb6c5d1ff28bc" + qtftl_i18n_commit = "a8bd0e284e2785421180af2ce10dd1d534b0033d" + qtftl_i18n_zip_csum = "f88398324a64be99521bd5cd7e79e7dda64c31a2cd4e568328a211c7765b23ac" i18n_build_content = """ filegroup( diff --git a/rslib/BUILD.bazel b/rslib/BUILD.bazel index 2c027a0b8..7dfb7abfb 100644 --- a/rslib/BUILD.bazel +++ b/rslib/BUILD.bazel @@ -31,6 +31,7 @@ cargo_build_script( ], deps = [ "//rslib/cargo:prost_build", + "//rslib/cargo:which", ], ) diff --git a/rslib/Cargo.toml b/rslib/Cargo.toml index 3bc06a78c..efc87b693 100644 --- a/rslib/Cargo.toml +++ b/rslib/Cargo.toml @@ -23,6 +23,7 @@ required-features = ["bench"] [build-dependencies] prost-build = "0.11.1" +which = "4.3.0" [dev-dependencies] env_logger = "0.9.1" diff --git a/rslib/build/protobuf.rs b/rslib/build/protobuf.rs index 4535be3e1..c8f85b131 100644 --- a/rslib/build/protobuf.rs +++ b/rslib/build/protobuf.rs @@ -1,7 +1,11 @@ // Copyright: Ankitects Pty Ltd and contributors // 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 {} @@ -71,6 +75,7 @@ fn service_generator() -> Box { } pub fn write_backend_proto_rs() { + maybe_add_protobuf_to_path(); let proto_dir = if let Ok(proto) = env::var("PROTO_TOP") { PathBuf::from(proto).parent().unwrap().to_owned() } else { @@ -122,3 +127,27 @@ pub fn write_backend_proto_rs() { .compile_protos(paths.as_slice(), &[proto_dir]) .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()); +} diff --git a/rslib/cargo/BUILD.bazel b/rslib/cargo/BUILD.bazel index 5104f9b3e..cf09ad565 100644 --- a/rslib/cargo/BUILD.bazel +++ b/rslib/cargo/BUILD.bazel @@ -579,6 +579,15 @@ alias( ], ) +alias( + name = "which", + actual = "@raze__which__4_3_0//:which", + tags = [ + "cargo-raze", + "manual", + ], +) + alias( name = "zip", actual = "@raze__zip__0_6_2//:zip", diff --git a/rslib/i18n/cargo/BUILD.bazel b/rslib/i18n/cargo/BUILD.bazel index 5104f9b3e..cf09ad565 100644 --- a/rslib/i18n/cargo/BUILD.bazel +++ b/rslib/i18n/cargo/BUILD.bazel @@ -579,6 +579,15 @@ alias( ], ) +alias( + name = "which", + actual = "@raze__which__4_3_0//:which", + tags = [ + "cargo-raze", + "manual", + ], +) + alias( name = "zip", actual = "@raze__zip__0_6_2//:zip", diff --git a/rslib/i18n_helpers/cargo/BUILD.bazel b/rslib/i18n_helpers/cargo/BUILD.bazel index 5104f9b3e..cf09ad565 100644 --- a/rslib/i18n_helpers/cargo/BUILD.bazel +++ b/rslib/i18n_helpers/cargo/BUILD.bazel @@ -579,6 +579,15 @@ alias( ], ) +alias( + name = "which", + actual = "@raze__which__4_3_0//:which", + tags = [ + "cargo-raze", + "manual", + ], +) + alias( name = "zip", actual = "@raze__zip__0_6_2//:zip", diff --git a/rslib/linkchecker/cargo/BUILD.bazel b/rslib/linkchecker/cargo/BUILD.bazel index 5104f9b3e..cf09ad565 100644 --- a/rslib/linkchecker/cargo/BUILD.bazel +++ b/rslib/linkchecker/cargo/BUILD.bazel @@ -579,6 +579,15 @@ alias( ], ) +alias( + name = "which", + actual = "@raze__which__4_3_0//:which", + tags = [ + "cargo-raze", + "manual", + ], +) + alias( name = "zip", actual = "@raze__zip__0_6_2//:zip", diff --git a/sass/_vars.scss b/sass/_vars.scss index 3b99eff4e..796d05e81 100644 --- a/sass/_vars.scss +++ b/sass/_vars.scss @@ -89,11 +89,14 @@ $vars: ( ), ), overlay: ( - "Background of floating elements (menus, tooltips)", + <<<<<<< HEAD "Background of floating elements (menus, tooltips)", ( light: white, dark: black, ), + ======= light: palette(lightgray, 0), + dark: palette(darkgray, 5), + >>>>>>> main, ), code: ( "Background of code editors", @@ -105,7 +108,8 @@ $vars: ( ), border: ( default: ( - "Border color with medium contrast against window background", + <<<<<<< HEAD + "Border color with medium contrast against window background", ( light: palette(lightgray, 6), dark: palette(darkgray, 7), @@ -117,6 +121,9 @@ $vars: ( light: palette(lightgray, 5), dark: palette(darkgray, 6), ), + ======= light: palette(lightgray, 6), + dark: palette(darkgray, 4), + >>>>>>> main, ), strong: ( "Border color with high contrast against window background", @@ -125,6 +132,14 @@ $vars: ( dark: palette(darkgray, 1), ), ), + subtle: ( + light: palette(lightgray, 5), + dark: palette(darkgray, 7), + ), + faint: ( + light: palette(lightgray, 4), + dark: palette(darkgray, 6), + ), focus: ( "Border color of focused input elements", ( @@ -402,8 +417,8 @@ $vars: ( bg: ( "Background color of highlighted items", ( - light: palette(blue, 3), - dark: palette(blue, 4), + light: color.scale(palette(blue, 3), $alpha: -33%), + dark: color.scale(palette(blue, 4), $alpha: -33%), ), ), fg: ( diff --git a/ts/components/HorizontalResizer.svelte b/ts/components/HorizontalResizer.svelte index c43af360e..218e9dc3b 100644 --- a/ts/components/HorizontalResizer.svelte +++ b/ts/components/HorizontalResizer.svelte @@ -3,6 +3,9 @@ Copyright: Ankitects Pty Ltd and contributors License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -->
+ {#if showIndicator} +
+ +
+ {/if} +
{@html horizontalHandle}
@@ -99,7 +120,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html width: 100%; cursor: row-resize; position: relative; - height: 10px; + height: 25px; border-top: 1px solid var(--border); z-index: 20; @@ -113,5 +134,15 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html &:hover .drag-handle { opacity: 0.8; } + + .resize-indicator { + position: absolute; + font-size: small; + bottom: 0; + } + &.rtl .resize-indicator { + padding: 0.5rem 0 0 0.5rem; + right: 0; + } } diff --git a/ts/components/Pane.svelte b/ts/components/Pane.svelte index c291947ee..54d111cb0 100644 --- a/ts/components/Pane.svelte +++ b/ts/components/Pane.svelte @@ -59,5 +59,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html .pane { @include panes.resizable(column, true, true); + opacity: var(--opacity, 1); } diff --git a/ts/components/SpinBox.svelte b/ts/components/SpinBox.svelte index 52c483096..076d874a2 100644 --- a/ts/components/SpinBox.svelte +++ b/ts/components/SpinBox.svelte @@ -6,7 +6,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import IconConstrain from "./IconConstrain.svelte"; import { chevronLeft, chevronRight } from "./icons"; - export let value = 1; + export let value: number; export let step = 1; export let min = 1; 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; - $: stringValue = value.toFixed(decimalPlaces(step)); + $: if (value) stringValue = value.toFixed(decimalPlaces(step)); function update(this: HTMLInputElement): void { value = Math.min(max, Math.max(min, parseFloat(this.value))); diff --git a/ts/editor/NoteEditor.svelte b/ts/editor/NoteEditor.svelte index fe5f6f2e3..40ee1fdee 100644 --- a/ts/editor/NoteEditor.svelte +++ b/ts/editor/NoteEditor.svelte @@ -355,12 +355,28 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html $: tagAmount = $tags.length; + let snapTags = $tagsCollapsed; + function collapseTags(): void { lowerResizer.move([tagsPane, fieldsPane], tagsPane.minHeight); + $tagsCollapsed = snapTags = true; } function expandTags(): void { 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"); + } } @@ -390,7 +406,9 @@ the AddCards dialog) should be implemented in the user of this component. (fieldsPane.height = e.detail.height)} + on:resize={(e) => { + fieldsPane.height = e.detail.height; + }} > @@ -553,7 +571,17 @@ the AddCards dialog) should be implemented in the user of this component. - {#if $tagsCollapsed} + snapResizer(!$tagsCollapsed)} + on:release={() => { + snapResizer(snapTags); + }} + >
{ @@ -564,36 +592,28 @@ the AddCards dialog) should be implemented in the user of this component. {@html tagAmount > 0 ? `${tagAmount} Tags` : ""}
- {/if} - - { - if ($tagsCollapsed) { - expandTags(); - bridgeCommand("expandTags"); - $tagsCollapsed = false; - } else { - collapseTags(); - bridgeCommand("collapseTags"); - $tagsCollapsed = true; - } - }} - /> + { 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; + } + })()} > { @@ -617,7 +637,4 @@ the AddCards dialog) should be implemented in the user of this component. flex-direction: column; height: 100%; } - .tags-expander { - margin-top: 0.5rem; - } diff --git a/ts/editor/editor-toolbar/LatexButton.svelte b/ts/editor/editor-toolbar/LatexButton.svelte index ba5a6b81d..adfbb5610 100644 --- a/ts/editor/editor-toolbar/LatexButton.svelte +++ b/ts/editor/editor-toolbar/LatexButton.svelte @@ -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 WithFloating from "../../components/WithFloating.svelte"; import { mathjaxConfig } from "../../editable/mathjax-element"; - import { bridgeCommand } from "../../lib/bridgecommand"; import * as tr from "../../lib/ftl"; import { getPlatformString } from "../../lib/shortcuts"; 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 { - surround("", ""); + if (mathjaxConfig.enabled) { + surround("", ""); + } else { + surround("\\(", "\\)"); + } } function onMathjaxBlock(): void { - surround('', ""); + if (mathjaxConfig.enabled) { + surround('', ""); + } else { + surround("\\[", "\\]"); + } } function onMathjaxChemistry(): void { - surround('\\ce{', "}"); + if (mathjaxConfig.enabled) { + surround('\\ce{', "}"); + } else { + surround("\\(\\ce{", "}\\)"); + } } function onLatex(): void { @@ -50,11 +61,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html surround("[$$]", "[/$$]"); } - function toggleShowMathjax(): void { - mathjaxConfig.enabled = !mathjaxConfig.enabled; - bridgeCommand("toggleMathjax"); - } - type LatexItem = [() => void, string, string]; const dropdownItems: LatexItem[] = [ @@ -94,10 +100,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html > {/each} - - - {tr.editingToggleMathjaxRendering()} - diff --git a/ts/editor/editor-toolbar/OptionsButton.svelte b/ts/editor/editor-toolbar/OptionsButton.svelte index a871b3a95..4386aae92 100644 --- a/ts/editor/editor-toolbar/OptionsButton.svelte +++ b/ts/editor/editor-toolbar/OptionsButton.svelte @@ -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 Popover from "../../components/Popover.svelte"; import WithFloating from "../../components/WithFloating.svelte"; + import { mathjaxConfig } from "../../editable/mathjax-element"; import { bridgeCommand } from "../../lib/bridgecommand"; import * as tr from "../../lib/ftl"; 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; } + function toggleShowMathjax(_evt: MouseEvent): void { + mathjaxConfig.enabled = !mathjaxConfig.enabled; + bridgeCommand("toggleMathjax"); + } + function toggleCloseHTMLTags(_evt: MouseEvent): void { $closeHTMLTags = !$closeHTMLTags; bridgeCommand("toggleCloseHTMLTags"); @@ -50,6 +56,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html {tr.editingShrinkImages()} + + + {tr.editingMathjaxPreview()} + {tr.editingCloseHtmlTags()} diff --git a/ts/editor/mathjax-overlay/MathjaxEditor.svelte b/ts/editor/mathjax-overlay/MathjaxEditor.svelte index 142985405..ec90c0c65 100644 --- a/ts/editor/mathjax-overlay/MathjaxEditor.svelte +++ b/ts/editor/mathjax-overlay/MathjaxEditor.svelte @@ -99,7 +99,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html {configuration} bind:api={codeMirror} on:change={({ detail: mathjaxText }) => code.set(mathjaxText)} - on:tab + on:blur />
diff --git a/ts/editor/mathjax-overlay/MathjaxOverlay.svelte b/ts/editor/mathjax-overlay/MathjaxOverlay.svelte index 967fc8883..281b6752d 100644 --- a/ts/editor/mathjax-overlay/MathjaxOverlay.svelte +++ b/ts/editor/mathjax-overlay/MathjaxOverlay.svelte @@ -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 { selectAll = false; position = undefined; if (activeImage && mathjaxElement) { - unsubscribe(); - activeImage = null; - mathjaxElement = null; + clear(); } allow(); @@ -188,10 +192,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html placeHandle(true); await resetHandle(); }} - on:tab={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?) + on:blur={async () => { await resetHandle(); }} let:editor={mathjaxEditor} @@ -220,8 +221,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html }} on:delete={async () => { placeCaretAfter(activeImage); - activeImage.remove(); - await resetHandle(); + mathjaxElement?.remove(); + clear(); }} on:surround={async ({ detail }) => { const editor = await mathjaxEditor.editor; diff --git a/ts/tag-editor/AutocompleteItem.svelte b/ts/tag-editor/AutocompleteItem.svelte index 75926ade0..0d7bdb87f 100644 --- a/ts/tag-editor/AutocompleteItem.svelte +++ b/ts/tag-editor/AutocompleteItem.svelte @@ -6,7 +6,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html export let selected = false; export let active = false; - let buttonRef: HTMLButtonElement; + let buttonRef: HTMLElement; $: if (selected && buttonRef) { /* buttonRef.scrollIntoView({ behavior: "smooth", block: "start" }); */ @@ -18,7 +18,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html } - +