From 68fa661b532ef965e72357c2876636271f01fa67 Mon Sep 17 00:00:00 2001 From: Matthias Metelka <62722460+kleinerpirat@users.noreply.github.com> Date: Thu, 27 Oct 2022 01:11:36 +0200 Subject: [PATCH] Finish #2070: Single overlay instead of per field (#2144) * Move up MathjaxOverlay to be initialized only once * Move ImageOverlay to NoteEditor root * Move Symbols Overlay to NoteEditor root * Refactor image overlay to not require second mutation observer * Use elevation + overflow:hidden in Editorfield * Make it possible to show input next to each other again * Set handle background color to code bg * Make Collapsible unmount the component * Simplify how decorated elements are mounted * Set RichTextInput background to frame-bg again * Strip out FocusTrap code * Revert "Make Collapsible unmount the component" This reverts commit 52722065ea199fa57ae750fa34bf47ee1c5aab3c. * Allow clicking on label container to unfocus field * Fix mathjax overlay resetting too its api too soon * Allow scrolling on overlays * Set focus-border border-color in focused field * Fix background color of fields * Add back grid-gap removed it during merge to see if margin-top would behave any differently - which is not the case. * Fix double border issue within Collapsible.svelte * Format * Edit appearance of focused fields a bit * Remove unused properties * Include elevation in button_mixins_lib * Give label-container a background color Co-authored-by: Henrik Giesel --- sass/BUILD.bazel | 1 + sass/elevation.scss | 10 +- ts/components/Collapsible.svelte | 13 + ts/components/DropdownItem.svelte | 12 +- ts/editor/ClozeButtons.svelte | 2 +- ts/editor/CodeMirror.svelte | 2 + ts/editor/DecoratedElements.svelte | 13 - ts/editor/EditingArea.svelte | 113 +------ ts/editor/EditorField.svelte | 17 +- ts/editor/Fields.svelte | 4 + ts/editor/FocusTrap.svelte | 41 --- ts/editor/FrameElement.svelte | 20 -- ts/editor/LabelContainer.svelte | 5 +- ts/editor/MathjaxElement.svelte | 14 - ts/editor/NoteEditor.svelte | 298 +++++++++--------- ts/editor/decorated-elements.ts | 31 ++ ts/editor/editor-toolbar/BlockButtons.svelte | 2 +- .../editor-toolbar/CommandIconButton.svelte | 2 +- ts/editor/editor-toolbar/LatexButton.svelte | 2 +- .../editor-toolbar/TemplateButtons.svelte | 12 +- ts/editor/image-overlay/ImageOverlay.svelte | 105 +++--- .../mathjax-overlay/MathjaxOverlay.svelte | 133 +++++--- .../plain-text-input/PlainTextInput.svelte | 28 +- ts/editor/plain-text-input/transform.ts | 2 +- .../rich-text-input/RichTextInput.svelte | 46 +-- .../rich-text-input/normalizing-node-store.ts | 2 +- ts/editor/rich-text-input/transform.ts | 2 +- .../symbols-overlay/SymbolsOverlay.svelte | 79 +++-- 28 files changed, 463 insertions(+), 548 deletions(-) delete mode 100644 ts/editor/DecoratedElements.svelte delete mode 100644 ts/editor/FocusTrap.svelte delete mode 100644 ts/editor/FrameElement.svelte delete mode 100644 ts/editor/MathjaxElement.svelte create mode 100644 ts/editor/decorated-elements.ts diff --git a/sass/BUILD.bazel b/sass/BUILD.bazel index 9171d5f9d..1f03a0dbb 100644 --- a/sass/BUILD.bazel +++ b/sass/BUILD.bazel @@ -83,6 +83,7 @@ sass_library( visibility = ["//visibility:public"], deps = [ "vars_lib", + "elevation_lib", ], ) diff --git a/sass/elevation.scss b/sass/elevation.scss index b543844c6..ccf796bae 100644 --- a/sass/elevation.scss +++ b/sass/elevation.scss @@ -59,7 +59,7 @@ $umbra-opacity: 0.2; $penumbra-opacity: 0.14; $ambient-opacity: 0.12; -@function box-shadow($level, $opacity-boost: 0, $color: black) { +@function box-shadow($level, $opacity-boost, $color) { $umbra-z-value: map.get($umbra-map, $level); $penumbra-z-value: map.get($penumbra-map, $level); $ambient-z-value: map.get($ambient-map, $level); @@ -75,6 +75,10 @@ $ambient-opacity: 0.12; ); } -@mixin elevation($level, $other: ()) { - box-shadow: list.join(box-shadow($level), $other); +@mixin elevation($level, $opacity-boost: 0, $color: black) { + box-shadow: box-shadow($level, $opacity-boost, $color); +} + +@mixin elevation-transition() { + transition: box-shadow 80ms cubic-bezier(0.33, 1, 0.68, 1); } diff --git a/ts/components/Collapsible.svelte b/ts/components/Collapsible.svelte index b8eef8738..128e1e3d6 100644 --- a/ts/components/Collapsible.svelte +++ b/ts/components/Collapsible.svelte @@ -8,6 +8,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import { tweened } from "svelte/motion"; export let collapse = false; + export let toggleDisplay = false; export let animated = !document.body.classList.contains("reduced-motion"); let collapsed = false; @@ -62,6 +63,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html class="collapsible" class:animated class:expanded + class:full-hide={toggleDisplay} + class:collapsed={!expanded} class:measuring class:transitioning style:--height="{height}px" @@ -75,8 +78,18 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html {/if} diff --git a/ts/editor/EditorField.svelte b/ts/editor/EditorField.svelte index f66ae1b1c..f1e6d3d9d 100644 --- a/ts/editor/EditorField.svelte +++ b/ts/editor/EditorField.svelte @@ -109,9 +109,20 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html diff --git a/ts/editor/Fields.svelte b/ts/editor/Fields.svelte index e12f46eae..557d59353 100644 --- a/ts/editor/Fields.svelte +++ b/ts/editor/Fields.svelte @@ -20,6 +20,10 @@ Contains the fields. This contains the scrollable area. /* Add space after the last field and the start of the tag editor */ padding-bottom: 5px; + /* Move the scrollbar for the NoteEditor into this element */ + position: relative; + overflow-y: auto; + /* Push the tag editor to the bottom of the note editor */ flex-grow: 1; } diff --git a/ts/editor/FocusTrap.svelte b/ts/editor/FocusTrap.svelte deleted file mode 100644 index e9920ed7e..000000000 --- a/ts/editor/FocusTrap.svelte +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - diff --git a/ts/editor/FrameElement.svelte b/ts/editor/FrameElement.svelte deleted file mode 100644 index b3bd715b9..000000000 --- a/ts/editor/FrameElement.svelte +++ /dev/null @@ -1,20 +0,0 @@ - - diff --git a/ts/editor/LabelContainer.svelte b/ts/editor/LabelContainer.svelte index be844405b..6f4f3bbad 100644 --- a/ts/editor/LabelContainer.svelte +++ b/ts/editor/LabelContainer.svelte @@ -20,7 +20,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html } -
+
- diff --git a/ts/editor/NoteEditor.svelte b/ts/editor/NoteEditor.svelte index 40ee1fdee..1af2fdb1f 100644 --- a/ts/editor/NoteEditor.svelte +++ b/ts/editor/NoteEditor.svelte @@ -52,7 +52,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import { TagEditor } from "../tag-editor"; import TagAddButton from "../tag-editor/tag-options-button/TagAddButton.svelte"; import { ChangeTimer } from "./change-timer"; - import DecoratedElements from "./DecoratedElements.svelte"; import { clearableArray } from "./destroyable"; import DuplicateLink from "./DuplicateLink.svelte"; import EditorToolbar from "./editor-toolbar"; @@ -60,12 +59,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import EditorField from "./EditorField.svelte"; import FieldDescription from "./FieldDescription.svelte"; import Fields from "./Fields.svelte"; - import FrameElement from "./FrameElement.svelte"; import { alertIcon } from "./icons"; - import ImageHandle from "./image-overlay"; + import ImageOverlay from "./image-overlay"; import { shrinkImagesByDefault } from "./image-overlay/ImageOverlay.svelte"; - import MathjaxHandle from "./mathjax-overlay"; - import MathjaxElement from "./MathjaxElement.svelte"; + import MathjaxOverlay from "./mathjax-overlay"; import Notification from "./Notification.svelte"; import PlainTextInput from "./plain-text-input"; import { closeHTMLTags } from "./plain-text-input/PlainTextInput.svelte"; @@ -412,161 +409,154 @@ the AddCards dialog) should be implemented in the user of this component. > - - {#each fieldsData as field, index} - {@const content = fieldStores[index]} + {#each fieldsData as field, index} + {@const content = fieldStores[index]} - { - $focusedField = fields[index]; - bridgeCommand(`focus:${index}`); - }} - on:focusout={() => { - $focusedField = null; - bridgeCommand( - `blur:${index}:${getNoteId()}:${transformContentBeforeSave( - get(content), - )}`, - ); - }} - on:mouseenter={() => { - $hoveredField = fields[index]; - }} - on:mouseleave={() => { - $hoveredField = null; - }} - collapsed={fieldsCollapsed[index]} - --dupes-color={cols[index] === "dupe" - ? "var(--accent-danger)" - : "transparent"} - > - - { - fieldsCollapsed[index] = - !fieldsCollapsed[index]; + { + $focusedField = fields[index]; + bridgeCommand(`focus:${index}`); + }} + on:focusout={() => { + $focusedField = null; + bridgeCommand( + `blur:${index}:${getNoteId()}:${transformContentBeforeSave( + get(content), + )}`, + ); + }} + on:mouseenter={() => { + $hoveredField = fields[index]; + }} + on:mouseleave={() => { + $hoveredField = null; + }} + collapsed={fieldsCollapsed[index]} + --dupes-color={cols[index] === "dupe" + ? "var(--accent-danger)" + : "transparent"} + > + + { + fieldsCollapsed[index] = !fieldsCollapsed[index]; - const defaultInput = !plainTextDefaults[index] - ? richTextInputs[index] - : plainTextInputs[index]; + const defaultInput = !plainTextDefaults[index] + ? richTextInputs[index] + : plainTextInputs[index]; - if (!fieldsCollapsed[index]) { - refocusInput(defaultInput.api); - } else if (!plainTextDefaults[index]) { - plainTextsHidden[index] = true; - } else { - richTextsHidden[index] = true; - } - }} - > - - - {field.name} - - - - {#if cols[index] === "dupe"} - - {/if} - {#if plainTextDefaults[index]} - { - richTextsHidden[index] = - !richTextsHidden[index]; + if (!fieldsCollapsed[index]) { + refocusInput(defaultInput.api); + } else if (!plainTextDefaults[index]) { + plainTextsHidden[index] = true; + } else { + richTextsHidden[index] = true; + } + }} + > + + + {field.name} + + + + {#if cols[index] === "dupe"} + + {/if} + {#if plainTextDefaults[index]} + { + richTextsHidden[index] = + !richTextsHidden[index]; - if (!richTextsHidden[index]) { - refocusInput( - richTextInputs[index].api, - ); - } - }} - /> - {:else} - { - plainTextsHidden[index] = - !plainTextsHidden[index]; - - if (!plainTextsHidden[index]) { - refocusInput( - plainTextInputs[index].api, - ); - } - }} - /> - {/if} - - - - - - - { - saveFieldNow(); - $focusedInput = null; - }} - bind:this={richTextInputs[index]} - > - - - {#if insertSymbols} - - {/if} - - {field.description} - - - - - - - { - saveFieldNow(); - $focusedInput = null; - }} - bind:this={plainTextInputs[index]} - /> - - - - {/each} + {:else} + { + plainTextsHidden[index] = + !plainTextsHidden[index]; - - - + if (!plainTextsHidden[index]) { + refocusInput( + plainTextInputs[index].api, + ); + } + }} + /> + {/if} + + + + + + + { + saveFieldNow(); + $focusedInput = null; + }} + bind:this={richTextInputs[index]} + > + + {field.description} + + + + + + + { + saveFieldNow(); + $focusedInput = null; + }} + bind:this={plainTextInputs[index]} + /> + + + + {/each} + + + + {#if insertSymbols} + + {/if} diff --git a/ts/editor/decorated-elements.ts b/ts/editor/decorated-elements.ts new file mode 100644 index 000000000..5809822cc --- /dev/null +++ b/ts/editor/decorated-elements.ts @@ -0,0 +1,31 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +import { CustomElementArray } from "../editable/decorated"; +import { FrameElement } from "../editable/frame-element"; +import { FrameEnd, FrameStart } from "../editable/frame-handle"; +import { Mathjax } from "../editable/mathjax-element"; +import { BLOCK_ELEMENTS } from "../lib/dom"; +import { parsingInstructions } from "./plain-text-input"; + +const decoratedElements = new CustomElementArray(); + +function registerMathjax() { + decoratedElements.push(Mathjax); + parsingInstructions.push(""); +} + +function registerFrameElement() { + customElements.define(FrameElement.tagName, FrameElement); + customElements.define(FrameStart.tagName, FrameStart); + customElements.define(FrameEnd.tagName, FrameEnd); + + /* This will ensure that they are not targeted by surrounding algorithms */ + BLOCK_ELEMENTS.push(FrameStart.tagName.toUpperCase()); + BLOCK_ELEMENTS.push(FrameEnd.tagName.toUpperCase()); +} + +registerMathjax(); +registerFrameElement(); + +export { decoratedElements }; diff --git a/ts/editor/editor-toolbar/BlockButtons.svelte b/ts/editor/editor-toolbar/BlockButtons.svelte index 624ceefa4..64464afd3 100644 --- a/ts/editor/editor-toolbar/BlockButtons.svelte +++ b/ts/editor/editor-toolbar/BlockButtons.svelte @@ -69,7 +69,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html const { focusedInput } = context.get(); - $: disabled = !editingInputIsRichText($focusedInput); + $: disabled = !$focusedInput || !editingInputIsRichText($focusedInput); let showFloating = false; diff --git a/ts/editor/editor-toolbar/CommandIconButton.svelte b/ts/editor/editor-toolbar/CommandIconButton.svelte index 744219856..f26332f0b 100644 --- a/ts/editor/editor-toolbar/CommandIconButton.svelte +++ b/ts/editor/editor-toolbar/CommandIconButton.svelte @@ -25,7 +25,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html execCommand(key); } - $: disabled = !editingInputIsRichText($focusedInput); + $: disabled = !$focusedInput || !editingInputIsRichText($focusedInput); {#if withoutState} diff --git a/ts/editor/editor-toolbar/LatexButton.svelte b/ts/editor/editor-toolbar/LatexButton.svelte index adfbb5610..c7513fc08 100644 --- a/ts/editor/editor-toolbar/LatexButton.svelte +++ b/ts/editor/editor-toolbar/LatexButton.svelte @@ -72,7 +72,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html [onLatexMathEnv, "Control+T, M", tr.editingLatexMathEnv()], ]; - $: disabled = !editingInputIsRichText($focusedInput); + $: disabled = !$focusedInput || !editingInputIsRichText($focusedInput); let showFloating = false; diff --git a/ts/editor/editor-toolbar/TemplateButtons.svelte b/ts/editor/editor-toolbar/TemplateButtons.svelte index 528b9368c..24326d26f 100644 --- a/ts/editor/editor-toolbar/TemplateButtons.svelte +++ b/ts/editor/editor-toolbar/TemplateButtons.svelte @@ -19,7 +19,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import { getPlatformString } from "../../lib/shortcuts"; import { context } from "../NoteEditor.svelte"; import { setFormat } from "../old-editor-adapter"; - import { editingInputIsRichText } from "../rich-text-input"; + import { editingInputIsRichText, RichTextInputAPI } from "../rich-text-input"; import { micIcon, paperclipIcon } from "./icons"; import LatexButton from "./LatexButton.svelte"; @@ -35,12 +35,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html } function attachMediaOnFocus(): void { - if (!editingInputIsRichText($focusedInput)) { + if (disabled) { return; } [mediaPromise, resolve] = promiseWithResolver(); - $focusedInput.editable.focusHandler.focus.on( + ($focusedInput as RichTextInputAPI).editable.focusHandler.focus.on( async () => setFormat("inserthtml", await mediaPromise), { once: true }, ); @@ -55,12 +55,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html const recordCombination = "F5"; function attachRecordingOnFocus(): void { - if (!editingInputIsRichText($focusedInput)) { + if (disabled) { return; } [mediaPromise, resolve] = promiseWithResolver(); - $focusedInput.editable.focusHandler.focus.on( + ($focusedInput as RichTextInputAPI).editable.focusHandler.focus.on( async () => setFormat("inserthtml", await mediaPromise), { once: true }, ); @@ -68,7 +68,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html bridgeCommand("record"); } - $: disabled = !editingInputIsRichText($focusedInput); + $: disabled = !$focusedInput || !editingInputIsRichText($focusedInput); export let api = {}; diff --git a/ts/editor/image-overlay/ImageOverlay.svelte b/ts/editor/image-overlay/ImageOverlay.svelte index 918743534..71605ee8a 100644 --- a/ts/editor/image-overlay/ImageOverlay.svelte +++ b/ts/editor/image-overlay/ImageOverlay.svelte @@ -9,7 +9,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html @@ -126,7 +127,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html return hidden; } - const className = "rich-text-editable"; let richTextDiv: HTMLElement; async function getInputAPI(target: EventTarget): Promise { @@ -221,29 +221,35 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html let:attachToShadow={attachStyles} let:stylesDidLoad > -
+
+
- {#await Promise.all([richTextPromise, stylesDidLoad]) then _} -
- -
- {/await} + {#await Promise.all([richTextPromise, stylesDidLoad]) then _} +
+ +
+ {/await} +
-
diff --git a/ts/editor/rich-text-input/normalizing-node-store.ts b/ts/editor/rich-text-input/normalizing-node-store.ts index d75076006..7a8b10923 100644 --- a/ts/editor/rich-text-input/normalizing-node-store.ts +++ b/ts/editor/rich-text-input/normalizing-node-store.ts @@ -4,7 +4,7 @@ import type { DecoratedElement } from "../../editable/decorated"; import type { NodeStore } from "../../sveltelib/node-store"; import { nodeStore } from "../../sveltelib/node-store"; -import { decoratedElements } from "../DecoratedElements.svelte"; +import { decoratedElements } from "../decorated-elements"; function normalizeFragment(fragment: DocumentFragment): void { fragment.normalize(); diff --git a/ts/editor/rich-text-input/transform.ts b/ts/editor/rich-text-input/transform.ts index 33ce0afb8..b71a4b888 100644 --- a/ts/editor/rich-text-input/transform.ts +++ b/ts/editor/rich-text-input/transform.ts @@ -7,7 +7,7 @@ import { nodeIsElement, } from "../../lib/dom"; import { createDummyDoc } from "../../lib/parsing"; -import { decoratedElements } from "../DecoratedElements.svelte"; +import { decoratedElements } from "../decorated-elements"; function adjustInputHTML(html: string): string { for (const component of decoratedElements) { diff --git a/ts/editor/symbols-overlay/SymbolsOverlay.svelte b/ts/editor/symbols-overlay/SymbolsOverlay.svelte index 49d8e3d58..c689e33a6 100644 --- a/ts/editor/symbols-overlay/SymbolsOverlay.svelte +++ b/ts/editor/symbols-overlay/SymbolsOverlay.svelte @@ -3,7 +3,7 @@ Copyright: Ankitects Pty Ltd and contributors License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -->
@@ -392,8 +418,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html max-height: 15rem; font-size: 12px; - overflow-x: hidden; + overflow: hidden auto; text-overflow: ellipsis; - overflow-y: auto; }