mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 02:16:05 +01:00 
			
		
		
		
	Merge branch 'develop' into feature/MFA
This commit is contained in:
		
							
								
								
									
										16
									
								
								libraries/ckeditor/ckeditor-content.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								libraries/ckeditor/ckeditor-content.css
									
									
									
									
										vendored
									
									
								
							| @@ -17,7 +17,7 @@ | ||||
|     margin: 0 !important; | ||||
| } | ||||
|  | ||||
| .ck-content .admonition { | ||||
| .admonition { | ||||
|     --accent-color: var(--card-border-color); | ||||
|     border: 1px solid var(--accent-color); | ||||
|     box-shadow: var(--card-box-shadow); | ||||
| @@ -29,19 +29,19 @@ | ||||
|     overflow: hidden; | ||||
| } | ||||
|  | ||||
| .ck-content .admonition p:last-child { | ||||
| .admonition p:last-child { | ||||
|     margin-bottom: 0; | ||||
| } | ||||
|  | ||||
| .ck-content .admonition p, h2 { | ||||
| .admonition p, h2 { | ||||
|     margin-top: 0; | ||||
| } | ||||
|  | ||||
| .ck-content .admonition.note { --accent-color: #69c7ff; } | ||||
| .ck-content .admonition.tip { --accent-color: #40c025; } | ||||
| .ck-content .admonition.important { --accent-color: #9839f7; } | ||||
| .ck-content .admonition.caution { --accent-color: #ff2e2e; } | ||||
| .ck-content .admonition.warning { --accent-color: #e2aa03; } | ||||
| .admonition.note { --accent-color: #69c7ff; } | ||||
| .admonition.tip { --accent-color: #40c025; } | ||||
| .admonition.important { --accent-color: #9839f7; } | ||||
| .admonition.caution { --accent-color: #ff2e2e; } | ||||
| .admonition.warning { --accent-color: #e2aa03; } | ||||
|  | ||||
| /* | ||||
|  * CKEditor 5 (v41.0.0) content styles. | ||||
|   | ||||
							
								
								
									
										2
									
								
								libraries/ckeditor/ckeditor.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								libraries/ckeditor/ckeditor.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								libraries/ckeditor/ckeditor.js.map
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								libraries/ckeditor/ckeditor.js.map
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										16
									
								
								src/public/app/doc_notes/en/User Guide/style.css
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										16
									
								
								src/public/app/doc_notes/en/User Guide/style.css
									
									
									
										generated
									
									
									
								
							| @@ -17,7 +17,7 @@ | ||||
|     margin: 0 !important; | ||||
| } | ||||
|  | ||||
| .ck-content .admonition { | ||||
| .admonition { | ||||
|     --accent-color: var(--card-border-color); | ||||
|     border: 1px solid var(--accent-color); | ||||
|     box-shadow: var(--card-box-shadow); | ||||
| @@ -29,19 +29,19 @@ | ||||
|     overflow: hidden; | ||||
| } | ||||
|  | ||||
| .ck-content .admonition p:last-child { | ||||
| .admonition p:last-child { | ||||
|     margin-bottom: 0; | ||||
| } | ||||
|  | ||||
| .ck-content .admonition p, h2 { | ||||
| .admonition p, h2 { | ||||
|     margin-top: 0; | ||||
| } | ||||
|  | ||||
| .ck-content .admonition.note { --accent-color: #69c7ff; } | ||||
| .ck-content .admonition.tip { --accent-color: #40c025; } | ||||
| .ck-content .admonition.important { --accent-color: #9839f7; } | ||||
| .ck-content .admonition.caution { --accent-color: #ff2e2e; } | ||||
| .ck-content .admonition.warning { --accent-color: #e2aa03; } | ||||
| .admonition.note { --accent-color: #69c7ff; } | ||||
| .admonition.tip { --accent-color: #40c025; } | ||||
| .admonition.important { --accent-color: #9839f7; } | ||||
| .admonition.caution { --accent-color: #ff2e2e; } | ||||
| .admonition.warning { --accent-color: #e2aa03; } | ||||
|  | ||||
| /* | ||||
|  * CKEditor 5 (v41.0.0) content styles. | ||||
|   | ||||
| @@ -36,7 +36,7 @@ import NoteMapRibbonWidget from "../widgets/ribbon_widgets/note_map.js"; | ||||
| import NotePathsWidget from "../widgets/ribbon_widgets/note_paths.js"; | ||||
| import SimilarNotesWidget from "../widgets/ribbon_widgets/similar_notes.js"; | ||||
| import RightPaneContainer from "../widgets/containers/right_pane_container.js"; | ||||
| import EditButton from "../widgets/buttons/edit_button.js"; | ||||
| import EditButton from "../widgets/floating_buttons/edit_button.js"; | ||||
| import EditedNotesWidget from "../widgets/ribbon_widgets/edited_notes.js"; | ||||
| import ShowTocWidgetButton from "../widgets/buttons/show_toc_widget_button.js"; | ||||
| import ShowHighlightsListWidgetButton from "../widgets/buttons/show_highlights_list_widget_button.js"; | ||||
| @@ -89,6 +89,8 @@ import ContextualHelpButton from "../widgets/floating_buttons/help_button.js"; | ||||
| import CloseZenButton from "../widgets/close_zen_button.js"; | ||||
| import type { AppContext } from "./../components/app_context.js"; | ||||
| import type { WidgetsByParent } from "../services/bundle.js"; | ||||
| import SwitchSplitOrientationButton from "../widgets/floating_buttons/switch_layout_button.js"; | ||||
| import ToggleReadOnlyButton from "../widgets/floating_buttons/toggle_read_only_button.js"; | ||||
|  | ||||
| export default class DesktopLayout { | ||||
|  | ||||
| @@ -202,6 +204,8 @@ export default class DesktopLayout { | ||||
|                                                         .child(new WatchedFileUpdateStatusWidget()) | ||||
|                                                         .child( | ||||
|                                                             new FloatingButtons() | ||||
|                                                                 .child(new SwitchSplitOrientationButton()) | ||||
|                                                                 .child(new ToggleReadOnlyButton()) | ||||
|                                                                 .child(new EditButton()) | ||||
|                                                                 .child(new ShowTocWidgetButton()) | ||||
|                                                                 .child(new ShowHighlightsListWidgetButton()) | ||||
|   | ||||
| @@ -11,7 +11,7 @@ import ProtectedSessionPasswordDialog from "../widgets/dialogs/protected_session | ||||
| import ConfirmDialog from "../widgets/dialogs/confirm.js"; | ||||
| import FilePropertiesWidget from "../widgets/ribbon_widgets/file_properties.js"; | ||||
| import FloatingButtons from "../widgets/floating_buttons/floating_buttons.js"; | ||||
| import EditButton from "../widgets/buttons/edit_button.js"; | ||||
| import EditButton from "../widgets/floating_buttons/edit_button.js"; | ||||
| import RelationMapButtons from "../widgets/floating_buttons/relation_map_buttons.js"; | ||||
| import SvgExportButton from "../widgets/floating_buttons/svg_export_button.js"; | ||||
| import BacklinksWidget from "../widgets/floating_buttons/zpetne_odkazy.js"; | ||||
|   | ||||
| @@ -23,6 +23,23 @@ async function removeAttributeById(noteId: string, attributeId: string) { | ||||
|     await server.remove(`notes/${noteId}/attributes/${attributeId}`); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Removes a label identified by its name from the given note, if it exists. Note that the label must be owned, i.e. | ||||
|  * it will not remove inherited attributes. | ||||
|  * | ||||
|  * @param note the note from which to remove the label. | ||||
|  * @param labelName the name of the label to remove. | ||||
|  * @returns `true` if an attribute was identified and removed, `false` otherwise. | ||||
|  */ | ||||
| function removeOwnedLabelByName(note: FNote, labelName: string) { | ||||
|     const label = note.getOwnedLabel(labelName); | ||||
|     if (label) { | ||||
|         removeAttributeById(note.noteId, label.attributeId); | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Sets the attribute of the given note to the provided value if its truthy, or removes the attribute if the value is falsy. | ||||
|  * For an attribute with an empty value, pass an empty string instead. | ||||
| @@ -90,5 +107,6 @@ export default { | ||||
|     setLabel, | ||||
|     setAttribute, | ||||
|     removeAttributeById, | ||||
|     removeOwnedLabelByName, | ||||
|     isAffecting | ||||
| }; | ||||
|   | ||||
| @@ -1,7 +1,26 @@ | ||||
| import type { MermaidConfig } from "mermaid"; | ||||
| import type { Mermaid } from "mermaid"; | ||||
|  | ||||
| let elkLoaded = false; | ||||
|  | ||||
| export function getMermaidConfig(): MermaidConfig { | ||||
|     const documentStyle = window.getComputedStyle(document.documentElement); | ||||
|     const mermaidTheme = documentStyle.getPropertyValue("--mermaid-theme") as "default"; | ||||
|  | ||||
|     return { | ||||
|         theme: mermaidTheme.trim() as "default", | ||||
|         securityLevel: "antiscript", | ||||
|         flowchart: { useMaxWidth: false }, | ||||
|         sequence: { useMaxWidth: false }, | ||||
|         gantt: { useMaxWidth: false }, | ||||
|         class: { useMaxWidth: false }, | ||||
|         state: { useMaxWidth: false }, | ||||
|         pie: { useMaxWidth: true }, | ||||
|         journey: { useMaxWidth: false }, | ||||
|         gitGraph: { useMaxWidth: false } | ||||
|     }; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Determines whether the ELK extension of Mermaid.js needs to be loaded (which is a relatively large library), based on the | ||||
|  * front-matter of the diagram and loads the library if needed. | ||||
|   | ||||
							
								
								
									
										14
									
								
								src/public/app/types.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								src/public/app/types.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -198,13 +198,13 @@ declare global { | ||||
|         }; | ||||
|         lineNumbers: boolean; | ||||
|         lineWrapping: boolean; | ||||
|         keyMap: "vim" | "default"; | ||||
|         lint: boolean; | ||||
|         gutters: string[]; | ||||
|         tabindex: number; | ||||
|         dragDrop: boolean; | ||||
|         placeholder: string; | ||||
|         readOnly: boolean; | ||||
|         keyMap?: "vim" | "default"; | ||||
|         lint?: boolean; | ||||
|         gutters?: string[]; | ||||
|         tabindex?: number; | ||||
|         dragDrop?: boolean; | ||||
|         placeholder?: string; | ||||
|         readOnly?: boolean; | ||||
|     } | ||||
|  | ||||
|     var CodeMirror: { | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import OnClickButtonWidget from "./onclick_button.js"; | ||||
| import OnClickButtonWidget from "../buttons/onclick_button.js"; | ||||
| import appContext from "../../components/app_context.js"; | ||||
| import attributeService from "../../services/attributes.js"; | ||||
| import protectedSessionHolder from "../../services/protected_session_holder.js"; | ||||
| @@ -0,0 +1,62 @@ | ||||
| import type { EventData } from "../../components/app_context.js"; | ||||
| import { t } from "../../services/i18n.js"; | ||||
| import options from "../../services/options.js"; | ||||
| import NoteContextAwareWidget from "../note_context_aware_widget.js"; | ||||
|  | ||||
| const TPL = ` | ||||
| <button type="button" | ||||
|     class="switch-layout-button"> | ||||
|     <span class="bx"></span> | ||||
| </button> | ||||
| `; | ||||
|  | ||||
| export default class SwitchSplitOrientationButton extends NoteContextAwareWidget { | ||||
|     isEnabled() { | ||||
|         return super.isEnabled() | ||||
|             && ["mermaid"].includes(this.note?.type ?? "") | ||||
|             && this.note?.isContentAvailable() | ||||
|             && !this.note?.hasLabel("readOnly") | ||||
|             && this.noteContext?.viewScope?.viewMode === "default"; | ||||
|     } | ||||
|  | ||||
|     doRender(): void { | ||||
|         super.doRender(); | ||||
|         this.$widget = $(TPL); | ||||
|         this.$widget.on("click", () => { | ||||
|             const currentOrientation = options.get("splitEditorOrientation"); | ||||
|             options.save("splitEditorOrientation", toggleOrientation(currentOrientation)); | ||||
|         }); | ||||
|         this.#adjustIcon(); | ||||
|         this.contentSized(); | ||||
|     } | ||||
|  | ||||
|     #adjustIcon() { | ||||
|         const currentOrientation = options.get("splitEditorOrientation"); | ||||
|         const upcomingOrientation = toggleOrientation(currentOrientation); | ||||
|         const $icon = this.$widget.find("span.bx"); | ||||
|         $icon | ||||
|             .toggleClass("bxs-dock-bottom", upcomingOrientation === "vertical") | ||||
|             .toggleClass("bxs-dock-left", upcomingOrientation === "horizontal"); | ||||
|  | ||||
|         if (upcomingOrientation === "vertical") { | ||||
|             this.$widget.attr("title", t("switch_layout_button.title_vertical")); | ||||
|         } else { | ||||
|             this.$widget.attr("title", t("switch_layout_button.title_horizontal")); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) { | ||||
|         if (loadResults.isOptionReloaded("splitEditorOrientation")) { | ||||
|             this.#adjustIcon(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| function toggleOrientation(orientation: string) { | ||||
|     if (orientation === "horizontal") { | ||||
|         return "vertical"; | ||||
|     } else { | ||||
|         return "horizontal"; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,48 @@ | ||||
| import type FNote from "../../entities/fnote.js"; | ||||
| import attributes from "../../services/attributes.js"; | ||||
| import { t } from "../../services/i18n.js"; | ||||
| import OnClickButtonWidget from "../buttons/onclick_button.js"; | ||||
|  | ||||
| export default class ToggleReadOnlyButton extends OnClickButtonWidget { | ||||
|  | ||||
|     private isReadOnly?: boolean; | ||||
|  | ||||
|     constructor() { | ||||
|         super(); | ||||
|  | ||||
|         this | ||||
|             .title(() => this.isReadOnly ? t("toggle_read_only_button.unlock-editing") : t("toggle_read_only_button.lock-editing")) | ||||
|             .titlePlacement("bottom") | ||||
|             .icon(() => this.isReadOnly ? "bx-lock-open-alt" : "bx-lock-alt") | ||||
|             .onClick(() => this.#toggleReadOnly()); | ||||
|     } | ||||
|  | ||||
|     #toggleReadOnly() { | ||||
|         if (!this.noteId || !this.note) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (this.isReadOnly) { | ||||
|             attributes.removeOwnedLabelByName(this.note, "readOnly"); | ||||
|         } else { | ||||
|             attributes.setLabel(this.noteId, "readOnly"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     async refreshWithNote(note: FNote | null | undefined) { | ||||
|         const isReadOnly = !!note?.hasLabel("readOnly"); | ||||
|  | ||||
|         if (isReadOnly !== this.isReadOnly) { | ||||
|             this.isReadOnly = isReadOnly; | ||||
|             this.refreshIcon(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     isEnabled() { | ||||
|         return super.isEnabled() | ||||
|             && this.note?.type === "mermaid" | ||||
|             && this.note?.isContentAvailable() | ||||
|             && this.noteContext?.viewScope?.viewMode === "default"; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -19,25 +19,10 @@ const TPL = `<div class="note-map-widget"> | ||||
|             overflow: hidden; | ||||
|         } | ||||
|  | ||||
|         .map-type-switcher { | ||||
|             position: absolute; | ||||
|             top: 10px; | ||||
|             left: 10px; | ||||
|             z-index: 10; /* should be below dropdown (note actions) */ | ||||
|         } | ||||
|  | ||||
|         .map-type-switcher button.bx { | ||||
|             font-size: 130%; | ||||
|             padding: 1px 10px 1px 10px; | ||||
|         } | ||||
|  | ||||
|         /* Style Ui Element to Drag Nodes */ | ||||
|         .fixnodes-type-switcher { | ||||
|             position: absolute; | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|             bottom: 10px; | ||||
|             left: 10px; | ||||
|             z-index: 10; /* should be below dropdown (note actions) */ | ||||
|             border-radius: .2rem; | ||||
|         } | ||||
| @@ -94,14 +79,14 @@ const TPL = `<div class="note-map-widget"> | ||||
|  | ||||
|     </style> | ||||
|  | ||||
|     <div class="btn-group btn-group-sm map-type-switcher" role="group"> | ||||
|     <div class="btn-group btn-group-sm map-type-switcher content-floating-buttons top-left" role="group"> | ||||
|       <button type="button" class="btn bx bx-network-chart tn-tool-button" title="${t("note-map.button-link-map")}" data-type="link"></button> | ||||
|       <button type="button" class="btn bx bx-sitemap tn-tool-button" title="${t("note-map.button-tree-map")}" data-type="tree"></button> | ||||
|     </div> | ||||
|  | ||||
|     <! UI for dragging Notes and link force > | ||||
|  | ||||
|     <div class=" btn-group-sm fixnodes-type-switcher" role="group"> | ||||
|     <div class="btn-group-sm fixnodes-type-switcher content-floating-buttons bottom-left" role="group"> | ||||
|       <button type="button" data-toggle="button" class="btn bx bx-lock-alt tn-tool-button" title="${t("note_map.fix-nodes")}" data-type="moveable"></button> | ||||
|       <input type="range" class="slider" min="1" title="${t("note_map.link-distance")}" max="100" value="40" > | ||||
|     </div> | ||||
|   | ||||
| @@ -123,7 +123,7 @@ export default class BasicPropertiesWidget extends NoteContextAwareWidget { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         this.$widget.find(".editability-select-container").toggle(this.note && ["text", "code"].includes(this.note.type)); | ||||
|         this.$widget.find(".editability-select-container").toggle(this.note && ["text", "code", "mermaid"].includes(this.note.type)); | ||||
|         this.$widget.find(".note-language-container").toggle(this.note && ["text"].includes(this.note.type)); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -4,15 +4,20 @@ import EditableCodeTypeWidget from "./editable_code.js"; | ||||
| import TypeWidget from "./type_widget.js"; | ||||
| import Split from "split.js"; | ||||
| import { DEFAULT_GUTTER_SIZE } from "../../services/resizer.js"; | ||||
| import options from "../../services/options.js"; | ||||
| import type SwitchSplitOrientationButton from "../floating_buttons/switch_layout_button.js"; | ||||
| import type { EventData } from "../../components/app_context.js"; | ||||
| import type OnClickButtonWidget from "../buttons/onclick_button.js"; | ||||
|  | ||||
| const TPL = `\ | ||||
| <div class="note-detail-split note-detail-printable split-horizontal"> | ||||
|     <div class="note-detail-split-first-col"> | ||||
| <div class="note-detail-split note-detail-printable"> | ||||
|     <div class="note-detail-split-editor-col"> | ||||
|         <div class="note-detail-split-editor"></div> | ||||
|         <div class="note-detail-error-container alert alert-warning hidden-ext"></div> | ||||
|         <div class="admonition caution note-detail-error-container hidden-ext"></div> | ||||
|     </div> | ||||
|     <div class="note-detail-split-second-col"> | ||||
|     <div class="note-detail-split-preview-col"> | ||||
|         <div class="note-detail-split-preview"></div> | ||||
|         <div class="btn-group btn-group-sm map-type-switcher content-floating-buttons preview-buttons bottom-right" role="group"></div> | ||||
|     </div> | ||||
|  | ||||
|     <style> | ||||
| @@ -21,8 +26,13 @@ const TPL = `\ | ||||
|             height: 100%; | ||||
|         } | ||||
|  | ||||
|         .note-detail-split-first-col { | ||||
|         .note-detail-split-editor-col { | ||||
|             display: flex; | ||||
|             flex-direction: column; | ||||
|         } | ||||
|  | ||||
|         .note-detail-split-preview-col { | ||||
|             position: relative; | ||||
|         } | ||||
|  | ||||
|         .note-detail-split .note-detail-split-editor { | ||||
| @@ -32,11 +42,14 @@ const TPL = `\ | ||||
|  | ||||
|         .note-detail-split .note-detail-error-container { | ||||
|             font-family: var(--monospace-font-family); | ||||
|             margin: 0.1em; | ||||
|             margin: 5px; | ||||
|             white-space: pre-wrap; | ||||
|             font-size: 0.85em; | ||||
|         } | ||||
|  | ||||
|         .note-detail-split .note-detail-split-preview { | ||||
|             transition: opacity 250ms ease-in-out; | ||||
|             height: 100%; | ||||
|         } | ||||
|  | ||||
|         .note-detail-split .note-detail-split-preview.on-error { | ||||
| @@ -45,11 +58,12 @@ const TPL = `\ | ||||
|  | ||||
|         /* Horizontal layout */ | ||||
|  | ||||
|         .note-detail-split.split-horizontal > .note-detail-split-second-col { | ||||
|         .note-detail-split.split-horizontal > .note-detail-split-preview-col { | ||||
|             border-left: 1px solid var(--main-border-color); | ||||
|         } | ||||
|  | ||||
|         .note-detail-split.split-horizontal > div { | ||||
|         .note-detail-split.split-horizontal > .note-detail-split-editor-col, | ||||
|         .note-detail-split.split-horizontal > .note-detail-split-preview-col { | ||||
|             height: 100%; | ||||
|             width: 50%; | ||||
|         } | ||||
| @@ -58,13 +72,31 @@ const TPL = `\ | ||||
|             height: 100%; | ||||
|         } | ||||
|  | ||||
|         .note-detail-split-first-col { | ||||
|         /* Vertical layout */ | ||||
|  | ||||
|         .note-detail-split.split-vertical { | ||||
|             flex-direction: column; | ||||
|         } | ||||
|  | ||||
|         /* Vertical layout */ | ||||
|         .note-detail-split.split-vertical > .note-detail-split-editor-col, | ||||
|         .note-detail-split.split-vertical > .note-detail-split-preview-col { | ||||
|             width: 100%; | ||||
|             height: 50%; | ||||
|         } | ||||
|  | ||||
|         .note-detail-split.split-vertical > .note-detail-split-editor-col { | ||||
|             border-top: 1px solid var(--main-border-color); | ||||
|         } | ||||
|  | ||||
|         .note-detail-split.split-vertical .note-detail-split-preview-col { | ||||
|             order: -1; | ||||
|         } | ||||
|  | ||||
|         /* Read-only view */ | ||||
|  | ||||
|         .note-detail-split.split-read-only .note-detail-split-preview-col { | ||||
|             width: 100%; | ||||
|         } | ||||
|     </style> | ||||
| </div> | ||||
| `; | ||||
| @@ -76,17 +108,20 @@ const TPL = `\ | ||||
|  * | ||||
|  * - The two panes are resizeable via a split, on desktop. The split can be optionally customized via {@link buildSplitExtraOptions}. | ||||
|  * - Can display errors to the user via {@link setError}. | ||||
|  * - Horizontal or vertical orientation for the editor/preview split, adjustable via {@link SwitchSplitOrientationButton}. | ||||
|  */ | ||||
| export default abstract class AbstractSplitTypeWidget extends TypeWidget { | ||||
|  | ||||
|     private splitInstance?: Split.Instance; | ||||
|  | ||||
|     protected $preview!: JQuery<HTMLElement>; | ||||
|     private $firstCol!: JQuery<HTMLElement>; | ||||
|     private $secondCol!: JQuery<HTMLElement>; | ||||
|     private $editorCol!: JQuery<HTMLElement>; | ||||
|     private $previewCol!: JQuery<HTMLElement>; | ||||
|     private $editor!: JQuery<HTMLElement>; | ||||
|     private $errorContainer!: JQuery<HTMLElement>; | ||||
|     private editorTypeWidget: EditableCodeTypeWidget; | ||||
|     private layoutOrientation?: "horizontal" | "vertical"; | ||||
|     private isReadOnly?: boolean; | ||||
|  | ||||
|     constructor() { | ||||
|         super(); | ||||
| @@ -98,13 +133,29 @@ export default abstract class AbstractSplitTypeWidget extends TypeWidget { | ||||
|     doRender(): void { | ||||
|         this.$widget = $(TPL); | ||||
|  | ||||
|         this.$firstCol = this.$widget.find(".note-detail-split-first-col"); | ||||
|         this.$secondCol = this.$widget.find(".note-detail-split-second-col"); | ||||
|         // Preview pane | ||||
|         this.$previewCol = this.$widget.find(".note-detail-split-preview-col"); | ||||
|         this.$preview = this.$widget.find(".note-detail-split-preview"); | ||||
|  | ||||
|         // Editor pane | ||||
|         this.$editorCol = this.$widget.find(".note-detail-split-editor-col"); | ||||
|         this.$editor = this.$widget.find(".note-detail-split-editor"); | ||||
|         this.$editor.append(this.editorTypeWidget.render()); | ||||
|         this.$errorContainer = this.$widget.find(".note-detail-error-container"); | ||||
|         this.#setupResizer(); | ||||
|         this.#adjustLayoutOrientation(); | ||||
|  | ||||
|         // Preview pane buttons | ||||
|         const $previewButtons = this.$previewCol.find(".preview-buttons"); | ||||
|         const previewButtons = this.buildPreviewButtons(); | ||||
|         $previewButtons.toggle(previewButtons.length > 0); | ||||
|         for (const previewButton of previewButtons) { | ||||
|             const $button = previewButton.render(); | ||||
|             $button.removeClass("button-widget") | ||||
|                 .addClass("btn") | ||||
|                 .addClass("tn-tool-button"); | ||||
|             $previewButtons.append($button); | ||||
|             previewButton.refreshIcon(); | ||||
|         } | ||||
|  | ||||
|         super.doRender(); | ||||
|     } | ||||
| @@ -115,27 +166,60 @@ export default abstract class AbstractSplitTypeWidget extends TypeWidget { | ||||
|     } | ||||
|  | ||||
|     async doRefresh(note: FNote | null | undefined) { | ||||
|         await this.editorTypeWidget.initialized; | ||||
|         this.#adjustLayoutOrientation(); | ||||
|  | ||||
|         if (note) { | ||||
|         if (note && !this.isReadOnly) { | ||||
|             await this.editorTypeWidget.initialized; | ||||
|             this.editorTypeWidget.noteContext = this.noteContext; | ||||
|             this.editorTypeWidget.spacedUpdate = this.spacedUpdate; | ||||
|             this.editorTypeWidget.doRefresh(note); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #adjustLayoutOrientation() { | ||||
|         // Read-only | ||||
|         const isReadOnly = this.note?.hasLabel("readOnly"); | ||||
|         if (this.isReadOnly !== isReadOnly) { | ||||
|             this.$editorCol.toggle(!isReadOnly); | ||||
|         } | ||||
|  | ||||
|         // Vertical vs horizontal layout | ||||
|         const layoutOrientation = options.get("splitEditorOrientation") ?? "horizontal"; | ||||
|         if (this.layoutOrientation === layoutOrientation && this.isReadOnly === isReadOnly) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         this.$widget | ||||
|             .toggleClass("split-horizontal", !isReadOnly && layoutOrientation === "horizontal") | ||||
|             .toggleClass("split-vertical", !isReadOnly && layoutOrientation === "vertical") | ||||
|             .toggleClass("split-read-only", isReadOnly); | ||||
|         this.layoutOrientation = layoutOrientation as ("horizontal" | "vertical"); | ||||
|         this.isReadOnly = isReadOnly; | ||||
|         this.#setupResizer(); | ||||
|     } | ||||
|  | ||||
|     #setupResizer() { | ||||
|         if (!utils.isDesktop()) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         let elements = [ this.$editorCol[0], this.$previewCol[0] ]; | ||||
|         if (this.layoutOrientation === "vertical") { | ||||
|             elements.reverse(); | ||||
|         } | ||||
|  | ||||
|         this.splitInstance?.destroy(); | ||||
|         this.splitInstance = Split([ this.$firstCol[0], this.$secondCol[0] ], { | ||||
|             sizes: [ 50, 50 ], | ||||
|             direction: "horizontal", | ||||
|             gutterSize: DEFAULT_GUTTER_SIZE, | ||||
|             ...this.buildSplitExtraOptions() | ||||
|         }); | ||||
|  | ||||
|         if (!this.isReadOnly) { | ||||
|             this.splitInstance = Split(elements, { | ||||
|                 sizes: [ 50, 50 ], | ||||
|                 direction: this.layoutOrientation, | ||||
|                 gutterSize: DEFAULT_GUTTER_SIZE, | ||||
|                 ...this.buildSplitExtraOptions() | ||||
|             }); | ||||
|         } else { | ||||
|             this.splitInstance = undefined; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -154,6 +238,10 @@ export default abstract class AbstractSplitTypeWidget extends TypeWidget { | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     buildPreviewButtons(): OnClickButtonWidget[] { | ||||
|         return []; | ||||
|     } | ||||
|  | ||||
|     setError(message: string | null | undefined) { | ||||
|         this.$errorContainer.toggleClass("hidden-ext", !message); | ||||
|         this.$preview.toggleClass("on-error", !!message); | ||||
| @@ -163,4 +251,11 @@ export default abstract class AbstractSplitTypeWidget extends TypeWidget { | ||||
|     getData() { | ||||
|         return this.editorTypeWidget.getData(); | ||||
|     } | ||||
|  | ||||
|     entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) { | ||||
|         if (loadResults.isOptionReloaded("splitEditorOrientation")) { | ||||
|             this.refresh(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,9 @@ | ||||
| import type { EventData } from "../../components/app_context.js"; | ||||
| import type FNote from "../../entities/fnote.js"; | ||||
| import { t } from "../../services/i18n.js"; | ||||
| import server from "../../services/server.js"; | ||||
| import utils from "../../services/utils.js"; | ||||
| import OnClickButtonWidget from "../buttons/onclick_button.js"; | ||||
| import AbstractSplitTypeWidget from "./abstract_split_type_widget.js"; | ||||
|  | ||||
| /** | ||||
| @@ -48,11 +50,20 @@ export default abstract class AbstractSvgSplitTypeWidget extends AbstractSplitTy | ||||
|         const blob = await note?.getBlob(); | ||||
|         const content = blob?.content || ""; | ||||
|         this.onContentChanged(content, true); | ||||
|  | ||||
|         // Save the SVG when entering a note only when it does not have an attachment. | ||||
|         this.note?.getAttachments().then((attachments) => { | ||||
|             const attachmentName = `${this.attachmentName}.svg`; | ||||
|             if (!attachments.find((a) => a.title === attachmentName)) { | ||||
|                 this.#saveSvg(); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     getData(): { content: string; } { | ||||
|         const data = super.getData(); | ||||
|         this.onContentChanged(data.content, false); | ||||
|         this.#saveSvg(); | ||||
|         return data; | ||||
|     } | ||||
|  | ||||
| @@ -70,24 +81,22 @@ export default abstract class AbstractSvgSplitTypeWidget extends AbstractSplitTy | ||||
|         let svg: string = ""; | ||||
|         try { | ||||
|             svg = await this.renderSvg(content); | ||||
|  | ||||
|             // Rendering was succesful. | ||||
|             this.setError(null); | ||||
|  | ||||
|             if (svg === this.svg) { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             this.svg = svg; | ||||
|             this.$renderContainer.html(svg); | ||||
|         } catch (e: unknown) { | ||||
|             // Rendering failed. | ||||
|             this.setError((e as Error)?.message); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // Rendering was succesful. | ||||
|         this.setError(null); | ||||
|  | ||||
|         if (svg === this.svg) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         this.svg = svg; | ||||
|  | ||||
|         this.$renderContainer.html(svg); | ||||
|         await this.#setupPanZoom(!recenter); | ||||
|         this.#saveSvg(); | ||||
|     } | ||||
|  | ||||
|     #saveSvg() { | ||||
| @@ -150,7 +159,7 @@ export default abstract class AbstractSvgSplitTypeWidget extends AbstractSplitTy | ||||
|         const svgPanZoom = (await import("svg-pan-zoom")).default; | ||||
|         const zoomInstance = svgPanZoom($svgEl[0], { | ||||
|             zoomEnabled: true, | ||||
|             controlIconsEnabled: true | ||||
|             controlIconsEnabled: false | ||||
|         }); | ||||
|  | ||||
|         if (preservePanZoom && pan && zoom) { | ||||
| @@ -159,6 +168,7 @@ export default abstract class AbstractSvgSplitTypeWidget extends AbstractSplitTy | ||||
|             zoomInstance.pan(pan); | ||||
|         } else { | ||||
|             // New instance, reposition properly. | ||||
|             zoomInstance.resize(); | ||||
|             zoomInstance.center(); | ||||
|             zoomInstance.fit(); | ||||
|         } | ||||
| @@ -172,6 +182,26 @@ export default abstract class AbstractSvgSplitTypeWidget extends AbstractSplitTy | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     buildPreviewButtons(): OnClickButtonWidget[] { | ||||
|         return [ | ||||
|             new OnClickButtonWidget() | ||||
|                 .icon("bx-zoom-in") | ||||
|                 .title(t("relation_map_buttons.zoom_in_title")) | ||||
|                 .titlePlacement("top") | ||||
|                 .onClick(() => this.zoomInstance?.zoomIn()) | ||||
|             , new OnClickButtonWidget() | ||||
|                 .icon("bx-zoom-out") | ||||
|                 .title(t("relation_map_buttons.zoom_out_title")) | ||||
|                 .titlePlacement("top") | ||||
|                 .onClick(() => this.zoomInstance?.zoomOut()) | ||||
|             , new OnClickButtonWidget() | ||||
|                 .icon("bx-crop") | ||||
|                 .title(t("relation_map_buttons.reset_pan_zoom_title")) | ||||
|                 .titlePlacement("top") | ||||
|                 .onClick(() => this.zoomHandler()) | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     #cleanUpZoom() { | ||||
|         if (this.zoomInstance) { | ||||
|             this.zoomInstance.destroy(); | ||||
|   | ||||
| @@ -16,7 +16,7 @@ import toast from "../../services/toast.js"; | ||||
| import { normalizeMimeTypeForCKEditor } from "../../services/mime_type_definitions.js"; | ||||
| import { buildConfig, buildToolbarConfig } from "./ckeditor/config.js"; | ||||
| import type FNote from "../../entities/fnote.js"; | ||||
| import { getMermaidConfig } from "./mermaid.js"; | ||||
| import { getMermaidConfig } from "../../services/mermaid.js"; | ||||
|  | ||||
| const ENABLE_INSPECTOR = false; | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| import type { MermaidConfig } from "mermaid"; | ||||
| import { loadElkIfNeeded, postprocessMermaidSvg } from "../../services/mermaid.js"; | ||||
| import { getMermaidConfig, loadElkIfNeeded, postprocessMermaidSvg } from "../../services/mermaid.js"; | ||||
| import AbstractSvgSplitTypeWidget from "./abstract_svg_split_type_widget.js"; | ||||
|  | ||||
| let idCounter = 1; | ||||
| @@ -34,22 +33,3 @@ export class MermaidTypeWidget extends AbstractSvgSplitTypeWidget { | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| export function getMermaidConfig(): MermaidConfig { | ||||
|     const documentStyle = window.getComputedStyle(document.documentElement); | ||||
|     const mermaidTheme = documentStyle.getPropertyValue("--mermaid-theme") as "default"; | ||||
|  | ||||
|     return { | ||||
|         theme: mermaidTheme.trim() as "default", | ||||
|         securityLevel: "antiscript", | ||||
|         flowchart: { useMaxWidth: false }, | ||||
|         sequence: { useMaxWidth: false }, | ||||
|         gantt: { useMaxWidth: false }, | ||||
|         class: { useMaxWidth: false }, | ||||
|         state: { useMaxWidth: false }, | ||||
|         pie: { useMaxWidth: true }, | ||||
|         journey: { useMaxWidth: false }, | ||||
|         gitGraph: { useMaxWidth: false } | ||||
|     }; | ||||
| } | ||||
|   | ||||
| @@ -4,7 +4,7 @@ import { applySyntaxHighlight } from "../../services/syntax_highlight.js"; | ||||
| import type FNote from "../../entities/fnote.js"; | ||||
| import type { EventData } from "../../components/app_context.js"; | ||||
| import { getLocaleById } from "../../services/i18n.js"; | ||||
| import { getMermaidConfig } from "./mermaid.js"; | ||||
| import { getMermaidConfig } from "../../services/mermaid.js"; | ||||
|  | ||||
| const TPL = ` | ||||
| <div class="note-detail-readonly-text note-detail-printable"> | ||||
| @@ -142,7 +142,10 @@ export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget { | ||||
|  | ||||
|         // Initialize mermaid | ||||
|         const mermaid = (await import("mermaid")).default; | ||||
|         mermaid.init(getMermaidConfig(), this.$content.find(".mermaid-diagram")[0]); | ||||
|         mermaid.initialize(getMermaidConfig()); | ||||
|         mermaid.run({ | ||||
|             nodes: this.$content.find(".mermaid-diagram") | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     async refreshIncludedNoteEvent({ noteId }: EventData<"refreshIncludedNote">) { | ||||
|   | ||||
| @@ -1722,7 +1722,7 @@ footer.file-footer button { | ||||
|     margin: 5px; | ||||
| } | ||||
|  | ||||
| .ck-content .admonition { | ||||
| .admonition { | ||||
|     --accent-color: var(--card-border-color); | ||||
|     border: 1px solid var(--accent-color); | ||||
|     box-shadow: var(--card-box-shadow); | ||||
| @@ -1735,11 +1735,11 @@ footer.file-footer button { | ||||
|     overflow: hidden; | ||||
| } | ||||
|  | ||||
| .ck-content .admonition p:last-child { | ||||
| .admonition p:last-child { | ||||
|     margin-bottom: 0; | ||||
| } | ||||
|  | ||||
| .ck-content .admonition::before {   | ||||
| .admonition::before {   | ||||
|     color: var(--accent-color); | ||||
|     font-family: boxicons !important; | ||||
|     position: absolute; | ||||
| @@ -1747,14 +1747,43 @@ footer.file-footer button { | ||||
|     left: 1em; | ||||
| } | ||||
|  | ||||
| .ck-content .admonition.note { --accent-color: #69c7ff; } | ||||
| .ck-content .admonition.tip { --accent-color: #40c025; } | ||||
| .ck-content .admonition.important { --accent-color: #9839f7; } | ||||
| .ck-content .admonition.caution { --accent-color: #ff2e2e; } | ||||
| .ck-content .admonition.warning { --accent-color: #e2aa03; } | ||||
| .admonition.note { --accent-color: #69c7ff; } | ||||
| .admonition.tip { --accent-color: #40c025; } | ||||
| .admonition.important { --accent-color: #9839f7; } | ||||
| .admonition.caution { --accent-color: #ff2e2e; } | ||||
| .admonition.warning { --accent-color: #e2aa03; } | ||||
|  | ||||
| .ck-content .admonition.note::before { content: "\eb21"; } | ||||
| .ck-content .admonition.tip::before { content: "\ea0d"; } | ||||
| .ck-content .admonition.important::before { content: "\ea7c"; } | ||||
| .ck-content .admonition.caution::before { content: "\eac7"; } | ||||
| .ck-content .admonition.warning::before { content: "\eac5"; } | ||||
| .admonition.note::before { content: "\eb21"; } | ||||
| .admonition.tip::before { content: "\ea0d"; } | ||||
| .admonition.important::before { content: "\ea7c"; } | ||||
| .admonition.caution::before { content: "\eac7"; } | ||||
| .admonition.warning::before { content: "\eac5"; } | ||||
|  | ||||
| /* | ||||
|  * In-content floating buttons | ||||
|  */ | ||||
|  | ||||
| .content-floating-buttons { | ||||
|     position: absolute; | ||||
|     z-index: 10; /* should be below dropdown (note actions) */ | ||||
| } | ||||
|  | ||||
| .content-floating-buttons.top-left { | ||||
|     top: 10px; | ||||
|     left: 10px; | ||||
| } | ||||
|  | ||||
| .content-floating-buttons.bottom-left { | ||||
|     bottom: 10px; | ||||
|     left: 10px; | ||||
| } | ||||
|  | ||||
| .content-floating-buttons.bottom-right { | ||||
|     bottom: 10px; | ||||
|     right: 10px; | ||||
| } | ||||
|  | ||||
| .content-floating-buttons button.bx { | ||||
|     font-size: 130%; | ||||
|     padding: 1px 10px 1px 10px; | ||||
| } | ||||
| @@ -1455,9 +1455,6 @@ | ||||
|     "title": "高亮列表", | ||||
|     "options": "选项" | ||||
|   }, | ||||
|   "mermaid": { | ||||
|     "diagram_error": "图表无法显示。 请参考 <a href=\"https://mermaid-js.github.io/mermaid/#/flowchart?id=graph\">帮助文档和示例</a>。" | ||||
|   }, | ||||
|   "quick-search": { | ||||
|     "placeholder": "快速搜索", | ||||
|     "searching": "正在搜索...", | ||||
|   | ||||
| @@ -1449,9 +1449,6 @@ | ||||
|     "title": "Hervorhebungs-Liste", | ||||
|     "options": "Optionen" | ||||
|   }, | ||||
|   "mermaid": { | ||||
|     "diagram_error": "Das Diagramm konnte nicht angezeigt werden. Siehe <a href=\"https://mermaid-js.github.io/mermaid/#/flowchart?id=graph\">Hilfe und Beispiele</a>." | ||||
|   }, | ||||
|   "quick-search": { | ||||
|     "placeholder": "Schnellsuche", | ||||
|     "searching": "Suche läuft…", | ||||
|   | ||||
| @@ -1465,9 +1465,6 @@ | ||||
|     "title": "Highlights List", | ||||
|     "options": "Options" | ||||
|   }, | ||||
|   "mermaid": { | ||||
|     "diagram_error": "The diagram could not be displayed. See <a href=\"https://mermaid-js.github.io/mermaid/#/flowchart?id=graph\">help and examples</a>." | ||||
|   }, | ||||
|   "quick-search": { | ||||
|     "placeholder": "Quick search", | ||||
|     "searching": "Searching...", | ||||
| @@ -1703,5 +1700,13 @@ | ||||
|   "content_language": { | ||||
|     "title": "Content languages", | ||||
|     "description": "Select one or more languages that should appear in the language selection in the Basic Properties section of a read-only or editable text note. This will allow features such as spell-checking or right-to-left support." | ||||
|   }, | ||||
|   "switch_layout_button": { | ||||
|     "title_vertical": "Move editing pane to the bottom", | ||||
|     "title_horizontal": "Move editing pane to the left" | ||||
|   }, | ||||
|   "toggle_read_only_button": { | ||||
|     "unlock-editing": "Unlock editing", | ||||
|     "lock-editing": "Lock editing" | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1455,9 +1455,6 @@ | ||||
|     "title": "Lista de destacados", | ||||
|     "options": "Opciones" | ||||
|   }, | ||||
|   "mermaid": { | ||||
|     "diagram_error": "El diagrama no pudo ser mostrado. Vea <a href=\"https://mermaid-js.github.io/mermaid/#/flowchart?id=graph\">ayuda y ejemplos</a>." | ||||
|   }, | ||||
|   "quick-search": { | ||||
|     "placeholder": "Búsqueda rápida", | ||||
|     "searching": "Buscando...", | ||||
|   | ||||
| @@ -1455,9 +1455,6 @@ | ||||
|     "title": "Accentuations", | ||||
|     "options": "Options" | ||||
|   }, | ||||
|   "mermaid": { | ||||
|     "diagram_error": "Le diagramme n'a pas pu être affiché. Consultez l'<a href=\"https://mermaid-js.github.io/mermaid/#/flowchart?id=graph\">aide et exemples</a>." | ||||
|   }, | ||||
|   "quick-search": { | ||||
|     "placeholder": "Recherche rapide", | ||||
|     "searching": "Recherche...", | ||||
|   | ||||
| @@ -1428,9 +1428,6 @@ | ||||
|     "options": "Setări", | ||||
|     "title": "Listă de evidențieri" | ||||
|   }, | ||||
|   "mermaid": { | ||||
|     "diagram_error": "Diagrama nu a putut fi afișată. Vedeți <a href=\"https://mermaid-js.github.io/mermaid/#/flowchart?id=graph\">informații și exemple pe site-ul oficial</a>." | ||||
|   }, | ||||
|   "note_icon": { | ||||
|     "change_note_icon": "Schimbă iconița notiței", | ||||
|     "category": "Categorie:", | ||||
|   | ||||
| @@ -1399,9 +1399,6 @@ | ||||
|     "title": "高亮列表", | ||||
|     "options": "選項" | ||||
|   }, | ||||
|   "mermaid": { | ||||
|     "diagram_error": "圖表無法顯示。 請參考 <a href=\"https://mermaid-js.github.io/mermaid/#/flowchart?id=graph\">幫助文檔和示例</a>。" | ||||
|   }, | ||||
|   "quick-search": { | ||||
|     "placeholder": "快速搜尋", | ||||
|     "searching": "正在搜尋...", | ||||
|   | ||||
| @@ -10,7 +10,7 @@ import { listSyntaxHighlightingThemes } from "../../services/code_block_theme.js | ||||
| import type { OptionNames } from "../../services/options_interface.js"; | ||||
|  | ||||
| // options allowed to be updated directly in the Options dialog | ||||
| const ALLOWED_OPTIONS = new Set([ | ||||
| const ALLOWED_OPTIONS = new Set<OptionNames>([ | ||||
|     "eraseEntitiesAfterTimeInSeconds", | ||||
|     "eraseEntitiesAfterTimeScale", | ||||
|     "protectedSessionTimeout", | ||||
| @@ -78,7 +78,8 @@ const ALLOWED_OPTIONS = new Set([ | ||||
|     "backgroundEffects", | ||||
|     "allowedHtmlTags", | ||||
|     "redirectBareDomain", | ||||
|     "showLoginInShareTheme" | ||||
|     "showLoginInShareTheme", | ||||
|     "splitEditorOrientation" | ||||
| ]); | ||||
|  | ||||
| function getOptions() { | ||||
| @@ -163,7 +164,10 @@ function getSupportedLocales() { | ||||
| } | ||||
|  | ||||
| function isAllowed(name: string) { | ||||
|     return ALLOWED_OPTIONS.has(name) || name.startsWith("keyboardShortcuts") || name.endsWith("Collapsed") || name.startsWith("hideArchivedNotes"); | ||||
|     return (ALLOWED_OPTIONS as Set<string>).has(name) | ||||
|         || name.startsWith("keyboardShortcuts") | ||||
|         || name.endsWith("Collapsed") | ||||
|         || name.startsWith("hideArchivedNotes"); | ||||
| } | ||||
|  | ||||
| export default { | ||||
|   | ||||
| @@ -136,6 +136,9 @@ const defaultOptions: DefaultOption[] = [ | ||||
|     { name: 'userSubjectIdentifierSaved', value: 'false', isSynced: true }, | ||||
|     { name: 'oAuthEnabled', value: 'false', isSynced: true }, | ||||
|  | ||||
|     // Appearance | ||||
|     { name: "splitEditorOrientation", value: "horizontal", isSynced: true }, | ||||
|  | ||||
|     // Internationalization | ||||
|     { name: "locale", value: "en", isSynced: true }, | ||||
|     { name: "firstDayOfWeek", value: "1", isSynced: true }, | ||||
|   | ||||
| @@ -49,6 +49,7 @@ export interface OptionDefinitions extends KeyboardShortcutsOptions<KeyboardActi | ||||
|     encryptedRecoveryCodes: boolean; | ||||
|     userSubjectIdentifierSaved: boolean; | ||||
|     oAuthEnabled: boolean; | ||||
|     hoistedNoteId: string; | ||||
|  | ||||
|     lastSyncedPull: number; | ||||
|     lastSyncedPush: number; | ||||
| @@ -77,6 +78,9 @@ export interface OptionDefinitions extends KeyboardShortcutsOptions<KeyboardActi | ||||
|     firstDayOfWeek: number; | ||||
|     languages: string; | ||||
|  | ||||
|     // Appearance | ||||
|     splitEditorOrientation: "horziontal" | "vertical"; | ||||
|  | ||||
|     initialized: boolean; | ||||
|     isPasswordSet: boolean; | ||||
|     overrideThemeFonts: boolean; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user