mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +01:00 
			
		
		
		
	Merge remote-tracking branch 'origin/develop' into feature/trilium_next_theme
This commit is contained in:
		| @@ -88,8 +88,11 @@ export default class Component { | |||||||
|  |  | ||||||
|         if (fun) { |         if (fun) { | ||||||
|             return this.callMethod(fun, data); |             return this.callMethod(fun, data); | ||||||
|         } |         } else { | ||||||
|         else { |             if (!this.parent) { | ||||||
|  |                 throw new Error(`Component "${this.componentId}" does not have a parent attached to propagate a command.`); | ||||||
|  |             } | ||||||
|  |  | ||||||
|             return this.parent.triggerCommand(name, data); |             return this.parent.triggerCommand(name, data); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -83,6 +83,7 @@ import UploadAttachmentsDialog from "../widgets/dialogs/upload_attachments.js"; | |||||||
| import CopyImageReferenceButton from "../widgets/floating_buttons/copy_image_reference_button.js"; | import CopyImageReferenceButton from "../widgets/floating_buttons/copy_image_reference_button.js"; | ||||||
| import ScrollPaddingWidget from "../widgets/scroll_padding.js"; | import ScrollPaddingWidget from "../widgets/scroll_padding.js"; | ||||||
| import ClassicEditorToolbar from "../widgets/ribbon_widgets/classic_editor_toolbar.js"; | import ClassicEditorToolbar from "../widgets/ribbon_widgets/classic_editor_toolbar.js"; | ||||||
|  | import options from "../services/options.js"; | ||||||
|  |  | ||||||
| export default class DesktopLayout { | export default class DesktopLayout { | ||||||
|     constructor(customWidgets) { |     constructor(customWidgets) { | ||||||
| @@ -92,112 +93,120 @@ export default class DesktopLayout { | |||||||
|     getRootWidget(appContext) { |     getRootWidget(appContext) { | ||||||
|         appContext.noteTreeWidget = new NoteTreeWidget(); |         appContext.noteTreeWidget = new NoteTreeWidget(); | ||||||
|  |  | ||||||
|         return new RootContainer() |         const launcherPaneIsHorizontal = (options.get("layoutOrientation") === "horizontal"); | ||||||
|  |         const launcherPane = this.#buildLauncherPane(launcherPaneIsHorizontal); | ||||||
|  |  | ||||||
|  |         return new RootContainer(launcherPaneIsHorizontal) | ||||||
|             .setParent(appContext) |             .setParent(appContext) | ||||||
|             .child(new FlexContainer("column") |             .optChild(launcherPaneIsHorizontal, new FlexContainer('row')                | ||||||
|                 .id("launcher-pane") |                 .child(new TabRowWidget().class("full-width")) | ||||||
|                 .css("width", "53px") |                 .child(new TitleBarButtonsWidget()) | ||||||
|                 .child(new GlobalMenuWidget()) |                 .css('height', '40px') | ||||||
|                 .child(new LauncherContainer()) |                 .css('background-color', 'var(--launcher-pane-background-color)') | ||||||
|                 .child(new LeftPaneToggleWidget()) |                 .setParent(appContext) | ||||||
|             ) |             ) | ||||||
|             .child(new LeftPaneContainer() |             .optChild(launcherPaneIsHorizontal, launcherPane) | ||||||
|                 .child(new QuickSearchWidget()) |             .child(new FlexContainer('row') | ||||||
|                 .child(appContext.noteTreeWidget) |  | ||||||
|                 .child(...this.customWidgets.get('left-pane')) |  | ||||||
|             ) |  | ||||||
|             .child(new FlexContainer('column') |  | ||||||
|                 .id('rest-pane') |  | ||||||
|                 .css("flex-grow", "1") |                 .css("flex-grow", "1") | ||||||
|                 .child(new FlexContainer('row') |                 .optChild(!launcherPaneIsHorizontal, launcherPane) | ||||||
|                     .child(new TabRowWidget()) |                 .child(new LeftPaneContainer() | ||||||
|                     .child(new TitleBarButtonsWidget()) |                     .optChild(!launcherPaneIsHorizontal, new QuickSearchWidget()) | ||||||
|                     .css('height', '40px') |                     .child(appContext.noteTreeWidget) | ||||||
|  |                     .child(...this.customWidgets.get('left-pane')) | ||||||
|                 ) |                 ) | ||||||
|                 .child(new FlexContainer('row') |                 .child(new FlexContainer('column') | ||||||
|                     .filling() |                     .id('rest-pane') | ||||||
|                     .collapsible() |                     .css("flex-grow", "1") | ||||||
|                     .child(new FlexContainer('column') |                     .optChild(!launcherPaneIsHorizontal, new FlexContainer('row') | ||||||
|  |                         .child(new TabRowWidget()) | ||||||
|  |                         .child(new TitleBarButtonsWidget()) | ||||||
|  |                         .css('height', '40px') | ||||||
|  |                     ) | ||||||
|  |                     .child(new FlexContainer('row') | ||||||
|                         .filling() |                         .filling() | ||||||
|                         .collapsible() |                         .collapsible() | ||||||
|                         .id('center-pane') |                         .child(new FlexContainer('column') | ||||||
|                         .child(new SplitNoteContainer(() => |                             .filling() | ||||||
|                                 new NoteWrapperWidget() |                             .collapsible() | ||||||
|                                     .child(new FlexContainer('row').class('title-row') |                             .id('center-pane') | ||||||
|                                         .css("height", "50px") |                             .child(new SplitNoteContainer(() => | ||||||
|                                         .css("min-height", "50px") |                                     new NoteWrapperWidget() | ||||||
|                                         .css('align-items', "center") |                                         .child(new FlexContainer('row').class('title-row') | ||||||
|                                         .cssBlock('.title-row > * { margin: 5px; }') |                                             .css("height", "50px") | ||||||
|                                         .child(new NoteIconWidget()) |                                             .css("min-height", "50px") | ||||||
|                                         .child(new NoteTitleWidget()) |                                             .css('align-items', "center") | ||||||
|                                         .child(new SpacerWidget(0, 1)) |                                             .cssBlock('.title-row > * { margin: 5px; }') | ||||||
|                                         .child(new MovePaneButton(true)) |                                             .child(new NoteIconWidget()) | ||||||
|                                         .child(new MovePaneButton(false)) |                                             .child(new NoteTitleWidget()) | ||||||
|                                         .child(new ClosePaneButton()) |                                             .child(new SpacerWidget(0, 1)) | ||||||
|                                         .child(new CreatePaneButton()) |                                             .child(new MovePaneButton(true)) | ||||||
|                                     ) |                                             .child(new MovePaneButton(false)) | ||||||
|                                     .child( |                                             .child(new ClosePaneButton()) | ||||||
|                                         new RibbonContainer() |                                             .child(new CreatePaneButton()) | ||||||
|                                             // the order of the widgets matter. Some of these want to "activate" themselves |                                         ) | ||||||
|                                             // when visible. When this happens to multiple of them, the first one "wins". |                                         .child( | ||||||
|                                             // promoted attributes should always win. |                                             new RibbonContainer() | ||||||
|                                             .ribbon(new ClassicEditorToolbar()) |                                                 // the order of the widgets matter. Some of these want to "activate" themselves | ||||||
|                                             .ribbon(new PromotedAttributesWidget()) |                                                 // when visible. When this happens to multiple of them, the first one "wins". | ||||||
|                                             .ribbon(new ScriptExecutorWidget()) |                                                 // promoted attributes should always win. | ||||||
|                                             .ribbon(new SearchDefinitionWidget()) |                                                 .ribbon(new ClassicEditorToolbar()) | ||||||
|                                             .ribbon(new EditedNotesWidget()) |                                                 .ribbon(new PromotedAttributesWidget()) | ||||||
|                                             .ribbon(new BookPropertiesWidget()) |                                                 .ribbon(new ScriptExecutorWidget()) | ||||||
|                                             .ribbon(new NotePropertiesWidget()) |                                                 .ribbon(new SearchDefinitionWidget()) | ||||||
|                                             .ribbon(new FilePropertiesWidget()) |                                                 .ribbon(new EditedNotesWidget()) | ||||||
|                                             .ribbon(new ImagePropertiesWidget()) |                                                 .ribbon(new BookPropertiesWidget()) | ||||||
|                                             .ribbon(new BasicPropertiesWidget()) |                                                 .ribbon(new NotePropertiesWidget()) | ||||||
|                                             .ribbon(new OwnedAttributeListWidget()) |                                                 .ribbon(new FilePropertiesWidget()) | ||||||
|                                             .ribbon(new InheritedAttributesWidget()) |                                                 .ribbon(new ImagePropertiesWidget()) | ||||||
|                                             .ribbon(new NotePathsWidget()) |                                                 .ribbon(new BasicPropertiesWidget()) | ||||||
|                                             .ribbon(new NoteMapRibbonWidget()) |                                                 .ribbon(new OwnedAttributeListWidget()) | ||||||
|                                             .ribbon(new SimilarNotesWidget()) |                                                 .ribbon(new InheritedAttributesWidget()) | ||||||
|                                             .ribbon(new NoteInfoWidget()) |                                                 .ribbon(new NotePathsWidget()) | ||||||
|                                             .button(new RevisionsButton()) |                                                 .ribbon(new NoteMapRibbonWidget()) | ||||||
|                                             .button(new NoteActionsWidget()) |                                                 .ribbon(new SimilarNotesWidget()) | ||||||
|                                     ) |                                                 .ribbon(new NoteInfoWidget()) | ||||||
|                                     .child(new SharedInfoWidget()) |                                                 .button(new RevisionsButton()) | ||||||
|                                     .child(new WatchedFileUpdateStatusWidget()) |                                                 .button(new NoteActionsWidget()) | ||||||
|                                     .child(new FloatingButtons() |                                         ) | ||||||
|                                         .child(new EditButton()) |                                         .child(new SharedInfoWidget()) | ||||||
|                                         .child(new ShowTocWidgetButton()) |                                         .child(new WatchedFileUpdateStatusWidget()) | ||||||
|                                         .child(new ShowHighlightsListWidgetButton()) |                                         .child(new FloatingButtons() | ||||||
|                                         .child(new CodeButtonsWidget()) |                                             .child(new EditButton()) | ||||||
|                                         .child(new RelationMapButtons()) |                                             .child(new ShowTocWidgetButton()) | ||||||
|                                         .child(new CopyImageReferenceButton()) |                                             .child(new ShowHighlightsListWidgetButton()) | ||||||
|                                         .child(new SvgExportButton()) |                                             .child(new CodeButtonsWidget()) | ||||||
|                                         .child(new BacklinksWidget()) |                                             .child(new RelationMapButtons()) | ||||||
|                                         .child(new HideFloatingButtonsButton()) |                                             .child(new CopyImageReferenceButton()) | ||||||
|                                     ) |                                             .child(new SvgExportButton()) | ||||||
|                                     .child(new MermaidWidget()) |                                             .child(new BacklinksWidget()) | ||||||
|                                     .child( |                                             .child(new HideFloatingButtonsButton()) | ||||||
|                                         new ScrollingContainer() |                                         ) | ||||||
|                                             .filling() |                                         .child(new MermaidWidget()) | ||||||
|                                             .child(new SqlTableSchemasWidget()) |                                         .child( | ||||||
|                                             .child(new NoteDetailWidget()) |                                             new ScrollingContainer() | ||||||
|                                             .child(new NoteListWidget()) |                                                 .filling() | ||||||
|                                             .child(new SearchResultWidget()) |                                                 .child(new SqlTableSchemasWidget()) | ||||||
|                                             .child(new SqlResultWidget()) |                                                 .child(new NoteDetailWidget()) | ||||||
|                                             .child(new ScrollPaddingWidget()) |                                                 .child(new NoteListWidget()) | ||||||
|                                     ) |                                                 .child(new SearchResultWidget()) | ||||||
|                                     .child(new ApiLogWidget()) |                                                 .child(new SqlResultWidget()) | ||||||
|                                     .child(new FindWidget()) |                                                 .child(new ScrollPaddingWidget()) | ||||||
|                                     .child( |                                         ) | ||||||
|                                         ...this.customWidgets.get('node-detail-pane'), // typo, let's keep it for a while as BC |                                         .child(new ApiLogWidget()) | ||||||
|                                         ...this.customWidgets.get('note-detail-pane') |                                         .child(new FindWidget()) | ||||||
|                                     ) |                                         .child( | ||||||
|  |                                             ...this.customWidgets.get('node-detail-pane'), // typo, let's keep it for a while as BC | ||||||
|  |                                             ...this.customWidgets.get('note-detail-pane') | ||||||
|  |                                         ) | ||||||
|  |                                 ) | ||||||
|                             ) |                             ) | ||||||
|  |                             .child(...this.customWidgets.get('center-pane')) | ||||||
|  |                         ) | ||||||
|  |                         .child(new RightPaneContainer() | ||||||
|  |                             .child(new TocWidget()) | ||||||
|  |                             .child(new HighlightsListWidget()) | ||||||
|  |                             .child(...this.customWidgets.get('right-pane')) | ||||||
|                         ) |                         ) | ||||||
|                         .child(...this.customWidgets.get('center-pane')) |  | ||||||
|                     ) |  | ||||||
|                     .child(new RightPaneContainer() |  | ||||||
|                         .child(new TocWidget()) |  | ||||||
|                         .child(new HighlightsListWidget()) |  | ||||||
|                         .child(...this.customWidgets.get('right-pane')) |  | ||||||
|                     ) |                     ) | ||||||
|                 ) |                 ) | ||||||
|             ) |             ) | ||||||
| @@ -225,4 +234,27 @@ export default class DesktopLayout { | |||||||
|             .child(new ConfirmDialog()) |             .child(new ConfirmDialog()) | ||||||
|             .child(new PromptDialog()); |             .child(new PromptDialog()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     #buildLauncherPane(isHorizontal) { | ||||||
|  |         let launcherPane;         | ||||||
|  |  | ||||||
|  |         if (isHorizontal) { | ||||||
|  |             launcherPane = new FlexContainer("row") | ||||||
|  |                 .css("height", "53px") | ||||||
|  |                 .class("horizontal") | ||||||
|  |                 .child(new LeftPaneToggleWidget(true)) | ||||||
|  |                 .child(new LauncherContainer(true)) | ||||||
|  |                 .child(new GlobalMenuWidget(true)) | ||||||
|  |         } else { | ||||||
|  |             launcherPane = new FlexContainer("column") | ||||||
|  |                 .css("width", "53px") | ||||||
|  |                 .class("vertical") | ||||||
|  |                 .child(new GlobalMenuWidget(false)) | ||||||
|  |                 .child(new LauncherContainer(false)) | ||||||
|  |                 .child(new LeftPaneToggleWidget(false)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         launcherPane.id("launcher-pane"); | ||||||
|  |         return launcherPane; | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -24,6 +24,7 @@ import RootContainer from "../widgets/containers/root_container.js"; | |||||||
| import SharedInfoWidget from "../widgets/shared_info.js"; | import SharedInfoWidget from "../widgets/shared_info.js"; | ||||||
| import PromotedAttributesWidget from "../widgets/ribbon_widgets/promoted_attributes.js"; | import PromotedAttributesWidget from "../widgets/ribbon_widgets/promoted_attributes.js"; | ||||||
| import ClassicEditorToolbar from "../widgets/ribbon_widgets/classic_editor_toolbar.js"; | import ClassicEditorToolbar from "../widgets/ribbon_widgets/classic_editor_toolbar.js"; | ||||||
|  | import options from "../services/options.js"; | ||||||
|  |  | ||||||
| const MOBILE_CSS = ` | const MOBILE_CSS = ` | ||||||
| <style> | <style> | ||||||
| @@ -112,15 +113,12 @@ span.fancytree-expander { | |||||||
|  |  | ||||||
| export default class MobileLayout { | export default class MobileLayout { | ||||||
|     getRootWidget(appContext) { |     getRootWidget(appContext) { | ||||||
|         return new RootContainer() |         const launcherPaneIsHorizontal = (options.get("layoutOrientation") === "horizontal"); | ||||||
|  |  | ||||||
|  |         return new RootContainer(launcherPaneIsHorizontal) | ||||||
|             .setParent(appContext) |             .setParent(appContext) | ||||||
|             .cssBlock(MOBILE_CSS) |             .cssBlock(MOBILE_CSS) | ||||||
|             .child(new FlexContainer("column") |             .child(this.#buildLauncherPane(launcherPaneIsHorizontal)) | ||||||
|                 .id("launcher-pane") |  | ||||||
|                 .css("width", "53px") |  | ||||||
|                 .child(new GlobalMenuWidget()) |  | ||||||
|                 .child(new LauncherContainer()) |  | ||||||
|             ) |  | ||||||
|             .child(new FlexContainer("row") |             .child(new FlexContainer("row") | ||||||
|                 .filling() |                 .filling() | ||||||
|                 .child(new ScreenContainer("tree", 'column') |                 .child(new ScreenContainer("tree", 'column') | ||||||
| @@ -140,12 +138,14 @@ export default class MobileLayout { | |||||||
|                     .child(new FlexContainer('row').contentSized() |                     .child(new FlexContainer('row').contentSized() | ||||||
|                         .css('font-size', 'larger') |                         .css('font-size', 'larger') | ||||||
|                         .css('align-items', 'center') |                         .css('align-items', 'center') | ||||||
|                         .child(new MobileDetailMenuWidget().contentSized()) |                         .optChild(!launcherPaneIsHorizontal, new MobileDetailMenuWidget(false).contentSized()) | ||||||
|                         .child(new NoteTitleWidget() |                         .child(new NoteTitleWidget() | ||||||
|                             .contentSized() |                             .contentSized() | ||||||
|                             .css("position: relative;") |                             .css("position: relative;") | ||||||
|                             .css("top: 5px;") |                             .css("top: 5px;") | ||||||
|  |                             .optCss(launcherPaneIsHorizontal, "padding-left", "0.5em") | ||||||
|                         ) |                         ) | ||||||
|  |                         .optChild(launcherPaneIsHorizontal, new MobileDetailMenuWidget(true).contentSized()) | ||||||
|                         .child(new CloseDetailButtonWidget().contentSized())) |                         .child(new CloseDetailButtonWidget().contentSized())) | ||||||
|                     .child(new SharedInfoWidget()) |                     .child(new SharedInfoWidget()) | ||||||
|                     .child(new FloatingButtons() |                     .child(new FloatingButtons() | ||||||
| @@ -174,4 +174,25 @@ export default class MobileLayout { | |||||||
|                 .child(new ConfirmDialog()) |                 .child(new ConfirmDialog()) | ||||||
|             ); |             ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     #buildLauncherPane(isHorizontal) { | ||||||
|  |         let launcherPane; | ||||||
|  |  | ||||||
|  |         if (isHorizontal) { | ||||||
|  |             launcherPane = new FlexContainer("row") | ||||||
|  |                 .class("horizontal") | ||||||
|  |                 .css("height", "53px") | ||||||
|  |                 .child(new LauncherContainer(true)) | ||||||
|  |                 .child(new GlobalMenuWidget(true)); | ||||||
|  |         } else { | ||||||
|  |             launcherPane = new FlexContainer("column")                 | ||||||
|  |                 .class("vertical") | ||||||
|  |                 .css("width", "53px") | ||||||
|  |                 .child(new GlobalMenuWidget(false)) | ||||||
|  |                 .child(new LauncherContainer(false)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         launcherPane.id("launcher-pane"); | ||||||
|  |         return launcherPane; | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -40,6 +40,21 @@ class BasicWidget extends Component { | |||||||
|         return this; |         return this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Conditionally adds the given components as children to this component. | ||||||
|  |      *  | ||||||
|  |      * @param {boolean} condition whether to add the components. | ||||||
|  |      * @param  {...any} components the components to be added as children to this component provided the condition is truthy.  | ||||||
|  |      * @returns self for chaining. | ||||||
|  |      */ | ||||||
|  |     optChild(condition, ...components) { | ||||||
|  |         if (condition) { | ||||||
|  |             return this.child(...components); | ||||||
|  |         } else { | ||||||
|  |             return this; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     id(id) { |     id(id) { | ||||||
|         this.attrs.id = id; |         this.attrs.id = id; | ||||||
|         return this; |         return this; | ||||||
| @@ -50,11 +65,34 @@ class BasicWidget extends Component { | |||||||
|         return this; |         return this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Sets the CSS attribute of the given name to the given value. | ||||||
|  |      *  | ||||||
|  |      * @param {string} name the name of the CSS attribute to set (e.g. `padding-left`). | ||||||
|  |      * @param {string} value the value of the CSS attribute to set (e.g. `12px`). | ||||||
|  |      * @returns self for chaining. | ||||||
|  |      */ | ||||||
|     css(name, value) { |     css(name, value) { | ||||||
|         this.attrs.style += `${name}: ${value};`; |         this.attrs.style += `${name}: ${value};`; | ||||||
|         return this; |         return this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Sets the CSS attribute of the given name to the given value, but only if the condition provided is truthy. | ||||||
|  |      *  | ||||||
|  |      * @param {boolean} condition `true` in order to apply the CSS, `false` to ignore it. | ||||||
|  |      * @param {string} name the name of the CSS attribute to set (e.g. `padding-left`). | ||||||
|  |      * @param {string} value the value of the CSS attribute to set (e.g. `12px`). | ||||||
|  |      * @returns self for chaining. | ||||||
|  |      */ | ||||||
|  |     optCss(condition, name, value) { | ||||||
|  |         if (condition) { | ||||||
|  |             return this.css(name, value); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     contentSized() { |     contentSized() { | ||||||
|         this.css("contain", "none"); |         this.css("contain", "none"); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -23,7 +23,11 @@ export default class AbstractButtonWidget extends NoteContextAwareWidget { | |||||||
|     doRender() { |     doRender() { | ||||||
|         this.$widget = $(TPL); |         this.$widget = $(TPL); | ||||||
|         this.tooltip = new bootstrap.Tooltip(this.$widget, { |         this.tooltip = new bootstrap.Tooltip(this.$widget, { | ||||||
|             html: true, title: () => this.getTitle(), trigger: 'hover' |             html: true, | ||||||
|  |             title: () => this.getTitle(), | ||||||
|  |             trigger: 'hover', | ||||||
|  |             placement: this.settings.titlePlacement, | ||||||
|  |             fallbackPlacements: [ this.settings.titlePlacement ] | ||||||
|         }) |         }) | ||||||
|  |  | ||||||
|         if (this.settings.onContextMenu) { |         if (this.settings.onContextMenu) { | ||||||
| @@ -36,8 +40,6 @@ export default class AbstractButtonWidget extends NoteContextAwareWidget { | |||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         this.$widget.attr("data-placement", this.settings.titlePlacement); |  | ||||||
|  |  | ||||||
|         super.doRender(); |         super.doRender(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ import UpdateAvailableWidget from "./update_available.js"; | |||||||
| import options from "../../services/options.js"; | import options from "../../services/options.js"; | ||||||
|  |  | ||||||
| const TPL = ` | const TPL = ` | ||||||
| <div class="dropdown global-menu dropend"> | <div class="dropdown global-menu"> | ||||||
|     <style> |     <style> | ||||||
|     .global-menu { |     .global-menu { | ||||||
|         width: 53px; |         width: 53px; | ||||||
| @@ -107,22 +107,6 @@ const TPL = ` | |||||||
|  |  | ||||||
|     <button type="button" data-bs-toggle="dropdown" aria-haspopup="true" |     <button type="button" data-bs-toggle="dropdown" aria-haspopup="true" | ||||||
|             aria-expanded="false" class="icon-action global-menu-button"> |             aria-expanded="false" class="icon-action global-menu-button"> | ||||||
|         <svg viewBox="0 0 256 256" data-bs-toggle="tooltip" title="${t('global_menu.menu')}"> |  | ||||||
|             <g> |  | ||||||
|                 <path class="st0" d="m202.9 112.7c-22.5 16.1-54.5 12.8-74.9 6.3l14.8-11.8 14.1-11.3 49.1-39.3-51.2 35.9-14.3 10-14.9 10.5c0.7-21.2 7-49.9 28.6-65.4 1.8-1.3 3.9-2.6 6.1-3.8 2.7-1.5 5.7-2.9 8.8-4.1 27.1-11.1 68.5-15.3 85.2-9.5 0.1 16.2-15.9 45.4-33.9 65.9-2.4 2.8-4.9 5.4-7.4 7.8-3.4 3.5-6.8 6.4-10.1 8.8z"/> |  | ||||||
|                 <path class="st1" d="m213.1 104c-22.2 12.6-51.4 9.3-70.3 3.2l14.1-11.3 49.1-39.3-51.2 35.9-14.3 10c0.5-18.1 4.9-42.1 19.7-58.6 2.7-1.5 5.7-2.9 8.8-4.1 27.1-11.1 68.5-15.3 85.2-9.5 0.1 16.2-15.9 45.4-33.9 65.9-2.3 2.8-4.8 5.4-7.2 7.8z"/> |  | ||||||
|                 <path class="st2" d="m220.5 96.2c-21.1 8.6-46.6 5.3-63.7-0.2l49.2-39.4-51.2 35.9c0.3-15.8 3.5-36.6 14.3-52.8 27.1-11.1 68.5-15.3 85.2-9.5 0.1 16.2-15.9 45.4-33.8 66z"/> |  | ||||||
|              |  | ||||||
|                 <path class="st3" d="m106.7 179c-5.8-21 5.2-43.8 15.5-57.2l4.8 14.2 4.5 13.4 15.9 47-12.8-47.6-3.6-13.2-3.7-13.9c15.5 6.2 35.1 18.6 40.7 38.8 0.5 1.7 0.9 3.6 1.2 5.5 0.4 2.4 0.6 5 0.7 7.7 0.9 23.1-7.1 54.9-15.9 65.7-12-4.3-29.3-24-39.7-42.8-1.4-2.6-2.7-5.1-3.8-7.6-1.6-3.5-2.9-6.8-3.8-10z"/> |  | ||||||
|                 <path class="st4" d="m110.4 188.9c-3.4-19.8 6.9-40.5 16.6-52.9l4.5 13.4 15.9 47-12.8-47.6-3.6-13.2c13.3 5.2 29.9 15 38.1 30.4 0.4 2.4 0.6 5 0.7 7.7 0.9 23.1-7.1 54.9-15.9 65.7-12-4.3-29.3-24-39.7-42.8-1.4-2.6-2.7-5.2-3.8-7.7z"/> |  | ||||||
|                 <path class="st5" d="m114.2 196.5c-0.7-18 8.6-35.9 17.3-47.1l15.9 47-12.8-47.6c11.6 4.4 26.1 12.4 35.2 24.8 0.9 23.1-7.1 54.9-15.9 65.7-12-4.3-29.3-24-39.7-42.8z"/> |  | ||||||
|      |  | ||||||
|                 <path class="st6" d="m86.3 59.1c21.7 10.9 32.4 36.6 35.8 54.9l-15.2-6.6-14.5-6.3-50.6-22 48.8 24.9 13.6 6.9 14.3 7.3c-16.6 7.9-41.3 14.5-62.1 4.1-1.8-0.9-3.6-1.9-5.4-3.2-2.3-1.5-4.5-3.2-6.8-5.1-19.9-16.4-40.3-46.4-42.7-61.5 12.4-6.5 41.5-5.8 64.8-0.3 3.2 0.8 6.2 1.6 9.1 2.5 4 1.3 7.6 2.8 10.9 4.4z"/> |  | ||||||
|                 <path class="st7" d="m75.4 54.8c18.9 12 28.4 35.6 31.6 52.6l-14.5-6.3-50.6-22 48.7 24.9 13.6 6.9c-14.1 6.8-34.5 13-53.3 8.2-2.3-1.5-4.5-3.2-6.8-5.1-19.8-16.4-40.2-46.4-42.6-61.5 12.4-6.5 41.5-5.8 64.8-0.3 3.1 0.8 6.2 1.6 9.1 2.6z"/> |  | ||||||
|                 <path class="st8" d="m66.3 52.2c15.3 12.8 23.3 33.6 26.1 48.9l-50.6-22 48.8 24.9c-12.2 6-29.6 11.8-46.5 10-19.8-16.4-40.2-46.4-42.6-61.5 12.4-6.5 41.5-5.8 64.8-0.3z"/> |  | ||||||
|             </g> |  | ||||||
|         </svg> |  | ||||||
|  |  | ||||||
|         <div class="global-menu-button-update-available"></div> |         <div class="global-menu-button-update-available"></div> | ||||||
|     </button> |     </button> | ||||||
|  |  | ||||||
| @@ -235,7 +219,7 @@ const TPL = ` | |||||||
|             ${t('global_menu.options')} |             ${t('global_menu.options')} | ||||||
|         </li> |         </li> | ||||||
|  |  | ||||||
|         <div class="dropdown-divider"></div> |         <div class="dropdown-divider desktop-only"></div> | ||||||
|  |  | ||||||
|         <li class="dropdown-item show-help-button" data-trigger-command="showHelp"> |         <li class="dropdown-item show-help-button" data-trigger-command="showHelp"> | ||||||
|             <span class="bx bx-help-circle"></span> |             <span class="bx bx-help-circle"></span> | ||||||
| @@ -265,18 +249,46 @@ const TPL = ` | |||||||
| `; | `; | ||||||
|  |  | ||||||
| export default class GlobalMenuWidget extends BasicWidget { | export default class GlobalMenuWidget extends BasicWidget { | ||||||
|     constructor() { |     constructor(isHorizontalLayout) { | ||||||
|         super(); |         super(); | ||||||
|  |  | ||||||
|         this.updateAvailableWidget = new UpdateAvailableWidget(); |         this.updateAvailableWidget = new UpdateAvailableWidget(); | ||||||
|  |         this.isHorizontalLayout = isHorizontalLayout;         | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     doRender() { |     doRender() { | ||||||
|         this.$widget = $(TPL); |         this.$widget = $(TPL); | ||||||
|  |  | ||||||
|         this.dropdown = bootstrap.Dropdown.getOrCreateInstance(this.$widget.find("[data-bs-toggle='dropdown']")); |         if (!this.isHorizontalLayout) { | ||||||
|  |             this.$widget.addClass("dropend"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         this.tooltip = new bootstrap.Tooltip(this.$widget.find("[data-bs-toggle='tooltip']"), { trigger: "hover" }); |         const $globalMenuButton = this.$widget.find(".global-menu-button") | ||||||
|  |         if (!this.isHorizontalLayout) { | ||||||
|  |             $globalMenuButton.prepend($(`\ | ||||||
|  |                 <svg viewBox="0 0 256 256" data-bs-toggle="tooltip" title="${t('global_menu.menu')}"> | ||||||
|  |                     <g> | ||||||
|  |                         <path class="st0" d="m202.9 112.7c-22.5 16.1-54.5 12.8-74.9 6.3l14.8-11.8 14.1-11.3 49.1-39.3-51.2 35.9-14.3 10-14.9 10.5c0.7-21.2 7-49.9 28.6-65.4 1.8-1.3 3.9-2.6 6.1-3.8 2.7-1.5 5.7-2.9 8.8-4.1 27.1-11.1 68.5-15.3 85.2-9.5 0.1 16.2-15.9 45.4-33.9 65.9-2.4 2.8-4.9 5.4-7.4 7.8-3.4 3.5-6.8 6.4-10.1 8.8z"/> | ||||||
|  |                         <path class="st1" d="m213.1 104c-22.2 12.6-51.4 9.3-70.3 3.2l14.1-11.3 49.1-39.3-51.2 35.9-14.3 10c0.5-18.1 4.9-42.1 19.7-58.6 2.7-1.5 5.7-2.9 8.8-4.1 27.1-11.1 68.5-15.3 85.2-9.5 0.1 16.2-15.9 45.4-33.9 65.9-2.3 2.8-4.8 5.4-7.2 7.8z"/> | ||||||
|  |                         <path class="st2" d="m220.5 96.2c-21.1 8.6-46.6 5.3-63.7-0.2l49.2-39.4-51.2 35.9c0.3-15.8 3.5-36.6 14.3-52.8 27.1-11.1 68.5-15.3 85.2-9.5 0.1 16.2-15.9 45.4-33.8 66z"/> | ||||||
|  |                      | ||||||
|  |                         <path class="st3" d="m106.7 179c-5.8-21 5.2-43.8 15.5-57.2l4.8 14.2 4.5 13.4 15.9 47-12.8-47.6-3.6-13.2-3.7-13.9c15.5 6.2 35.1 18.6 40.7 38.8 0.5 1.7 0.9 3.6 1.2 5.5 0.4 2.4 0.6 5 0.7 7.7 0.9 23.1-7.1 54.9-15.9 65.7-12-4.3-29.3-24-39.7-42.8-1.4-2.6-2.7-5.1-3.8-7.6-1.6-3.5-2.9-6.8-3.8-10z"/> | ||||||
|  |                         <path class="st4" d="m110.4 188.9c-3.4-19.8 6.9-40.5 16.6-52.9l4.5 13.4 15.9 47-12.8-47.6-3.6-13.2c13.3 5.2 29.9 15 38.1 30.4 0.4 2.4 0.6 5 0.7 7.7 0.9 23.1-7.1 54.9-15.9 65.7-12-4.3-29.3-24-39.7-42.8-1.4-2.6-2.7-5.2-3.8-7.7z"/> | ||||||
|  |                         <path class="st5" d="m114.2 196.5c-0.7-18 8.6-35.9 17.3-47.1l15.9 47-12.8-47.6c11.6 4.4 26.1 12.4 35.2 24.8 0.9 23.1-7.1 54.9-15.9 65.7-12-4.3-29.3-24-39.7-42.8z"/> | ||||||
|  |              | ||||||
|  |                         <path class="st6" d="m86.3 59.1c21.7 10.9 32.4 36.6 35.8 54.9l-15.2-6.6-14.5-6.3-50.6-22 48.8 24.9 13.6 6.9 14.3 7.3c-16.6 7.9-41.3 14.5-62.1 4.1-1.8-0.9-3.6-1.9-5.4-3.2-2.3-1.5-4.5-3.2-6.8-5.1-19.9-16.4-40.3-46.4-42.7-61.5 12.4-6.5 41.5-5.8 64.8-0.3 3.2 0.8 6.2 1.6 9.1 2.5 4 1.3 7.6 2.8 10.9 4.4z"/> | ||||||
|  |                         <path class="st7" d="m75.4 54.8c18.9 12 28.4 35.6 31.6 52.6l-14.5-6.3-50.6-22 48.7 24.9 13.6 6.9c-14.1 6.8-34.5 13-53.3 8.2-2.3-1.5-4.5-3.2-6.8-5.1-19.8-16.4-40.2-46.4-42.6-61.5 12.4-6.5 41.5-5.8 64.8-0.3 3.1 0.8 6.2 1.6 9.1 2.6z"/> | ||||||
|  |                         <path class="st8" d="m66.3 52.2c15.3 12.8 23.3 33.6 26.1 48.9l-50.6-22 48.8 24.9c-12.2 6-29.6 11.8-46.5 10-19.8-16.4-40.2-46.4-42.6-61.5 12.4-6.5 41.5-5.8 64.8-0.3z"/> | ||||||
|  |                     </g> | ||||||
|  |                 </svg>`)); | ||||||
|  |             this.tooltip = new bootstrap.Tooltip(this.$widget.find("[data-bs-toggle='tooltip']"), { trigger: "hover" }); | ||||||
|  |         } else { | ||||||
|  |             $globalMenuButton.toggleClass("bx bx-menu"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this.dropdown = bootstrap.Dropdown.getOrCreateInstance(this.$widget.find("[data-bs-toggle='dropdown']"), { | ||||||
|  |             alignment: "bottom" | ||||||
|  |         }); | ||||||
|  |  | ||||||
|         this.$widget.find(".show-about-dialog-button").on('click', () => this.triggerCommand("openAboutDialog")); |         this.$widget.find(".show-about-dialog-button").on('click', () => this.triggerCommand("openAboutDialog")); | ||||||
|  |  | ||||||
| @@ -300,7 +312,7 @@ export default class GlobalMenuWidget extends BasicWidget { | |||||||
|             if ($(e.target).children(".dropdown-menu").length === 1 || $(e.target).hasClass('dropdown-toggle')) { |             if ($(e.target).children(".dropdown-menu").length === 1 || $(e.target).hasClass('dropdown-toggle')) { | ||||||
|                 e.stopPropagation(); |                 e.stopPropagation(); | ||||||
|             } |             } | ||||||
|         }) |         })         | ||||||
|  |  | ||||||
|         this.$widget.find(".global-menu-button-update-available").append( |         this.$widget.find(".global-menu-button-update-available").append( | ||||||
|             this.updateAvailableWidget.render() |             this.updateAvailableWidget.render() | ||||||
| @@ -316,10 +328,14 @@ export default class GlobalMenuWidget extends BasicWidget { | |||||||
|         this.$zoomState = this.$widget.find(".zoom-state"); |         this.$zoomState = this.$widget.find(".zoom-state"); | ||||||
|         this.$widget.on('show.bs.dropdown', () => { |         this.$widget.on('show.bs.dropdown', () => { | ||||||
|             this.updateZoomState(); |             this.updateZoomState(); | ||||||
|             this.tooltip.hide(); |             if (this.tooltip) { | ||||||
|             this.tooltip.disable(); |                 this.tooltip.hide(); | ||||||
|  |                 this.tooltip.disable(); | ||||||
|  |             } | ||||||
|         }); |         }); | ||||||
|         this.$widget.on('hide.bs.dropdown', () => this.tooltip.enable()); |         if (this.tooltip) { | ||||||
|  |             this.$widget.on('hide.bs.dropdown', () => this.tooltip.enable()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         this.$widget.find(".zoom-buttons").on("click", |         this.$widget.find(".zoom-buttons").on("click", | ||||||
|             // delay to wait for the actual zoom change |             // delay to wait for the actual zoom change | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ import CommandButtonWidget from "./command_button.js"; | |||||||
| import { t } from "../../services/i18n.js"; | import { t } from "../../services/i18n.js"; | ||||||
|  |  | ||||||
| export default class LeftPaneToggleWidget extends CommandButtonWidget { | export default class LeftPaneToggleWidget extends CommandButtonWidget { | ||||||
|     constructor() { |     constructor(isHorizontalLayout) { | ||||||
|         super(); |         super(); | ||||||
|  |  | ||||||
|         this.class("launcher-button"); |         this.class("launcher-button"); | ||||||
| @@ -20,6 +20,10 @@ export default class LeftPaneToggleWidget extends CommandButtonWidget { | |||||||
|         this.settings.command = () => options.is('leftPaneVisible') |         this.settings.command = () => options.is('leftPaneVisible') | ||||||
|             ? "hideLeftPane" |             ? "hideLeftPane" | ||||||
|             : "showLeftPane"; |             : "showLeftPane"; | ||||||
|  |  | ||||||
|  |         if (isHorizontalLayout) { | ||||||
|  |             this.settings.titlePlacement = "bottom"; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     refreshIcon() { |     refreshIcon() { | ||||||
|   | |||||||
| @@ -2,13 +2,7 @@ import BasicWidget from "../basic_widget.js"; | |||||||
|  |  | ||||||
| const TPL = ` | const TPL = ` | ||||||
| <div class="dropdown right-dropdown-widget dropend"> | <div class="dropdown right-dropdown-widget dropend"> | ||||||
|     <style> |     <button type="button" data-bs-toggle="dropdown" | ||||||
|     .right-dropdown-widget { |  | ||||||
|         height: 53px; |  | ||||||
|     } |  | ||||||
|     </style> |  | ||||||
|  |  | ||||||
|     <button type="button" data-bs-toggle="dropdown" data-placement="right" |  | ||||||
|             aria-haspopup="true" aria-expanded="false"  |             aria-haspopup="true" aria-expanded="false"  | ||||||
|             class="bx right-dropdown-button launcher-button"></button> |             class="bx right-dropdown-button launcher-button"></button> | ||||||
|      |      | ||||||
| @@ -25,6 +19,10 @@ export default class RightDropdownButtonWidget extends BasicWidget { | |||||||
|         this.iconClass = iconClass; |         this.iconClass = iconClass; | ||||||
|         this.title = title; |         this.title = title; | ||||||
|         this.dropdownTpl = dropdownTpl; |         this.dropdownTpl = dropdownTpl; | ||||||
|  |  | ||||||
|  |         this.settings = { | ||||||
|  |             titlePlacement: "right"     | ||||||
|  |         }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     doRender() { |     doRender() { | ||||||
| @@ -33,7 +31,10 @@ export default class RightDropdownButtonWidget extends BasicWidget { | |||||||
|         this.dropdown = bootstrap.Dropdown.getOrCreateInstance(this.$widget.find("[data-bs-toggle='dropdown']")); |         this.dropdown = bootstrap.Dropdown.getOrCreateInstance(this.$widget.find("[data-bs-toggle='dropdown']")); | ||||||
|  |  | ||||||
|         this.$tooltip = this.$widget.find(".tooltip-trigger").attr("title", this.title); |         this.$tooltip = this.$widget.find(".tooltip-trigger").attr("title", this.title); | ||||||
|         this.tooltip = new bootstrap.Tooltip(this.$tooltip); |         this.tooltip = new bootstrap.Tooltip(this.$tooltip, { | ||||||
|  |             placement: this.settings.titlePlacement, | ||||||
|  |             fallbackPlacements: [ this.settings.titlePlacement ] | ||||||
|  |         }); | ||||||
|  |  | ||||||
|         this.$widget.find(".right-dropdown-button") |         this.$widget.find(".right-dropdown-button") | ||||||
|             .addClass(this.iconClass) |             .addClass(this.iconClass) | ||||||
|   | |||||||
| @@ -10,12 +10,14 @@ import CommandButtonWidget from "../buttons/command_button.js"; | |||||||
| import utils from "../../services/utils.js"; | import utils from "../../services/utils.js"; | ||||||
| import TodayLauncher from "../buttons/launcher/today_launcher.js"; | import TodayLauncher from "../buttons/launcher/today_launcher.js"; | ||||||
| import HistoryNavigationButton from "../buttons/history_navigation.js"; | import HistoryNavigationButton from "../buttons/history_navigation.js"; | ||||||
|  | import QuickSearchLauncherWidget from "../quick_search_launcher.js"; | ||||||
|  |  | ||||||
| export default class LauncherWidget extends BasicWidget { | export default class LauncherWidget extends BasicWidget { | ||||||
|     constructor() { |     constructor(isHorizontalLayout) { | ||||||
|         super(); |         super(); | ||||||
|  |  | ||||||
|         this.innerWidget = null; |         this.innerWidget = null; | ||||||
|  |         this.isHorizontalLayout = isHorizontalLayout; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     isEnabled() { |     isEnabled() { | ||||||
| @@ -63,6 +65,9 @@ export default class LauncherWidget extends BasicWidget { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         this.child(this.innerWidget); |         this.child(this.innerWidget); | ||||||
|  |         if (this.isHorizontalLayout && this.innerWidget.settings) { | ||||||
|  |             this.innerWidget.settings.titlePlacement = "bottom"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| @@ -86,29 +91,31 @@ export default class LauncherWidget extends BasicWidget { | |||||||
|  |  | ||||||
|     initBuiltinWidget(note) { |     initBuiltinWidget(note) { | ||||||
|         const builtinWidget = note.getLabelValue("builtinWidget"); |         const builtinWidget = note.getLabelValue("builtinWidget"); | ||||||
|  |         switch (builtinWidget) { | ||||||
|         if (builtinWidget === 'calendar') { |             case "calendar": | ||||||
|             return new CalendarWidget(note.title, note.getIcon()); |                 return new CalendarWidget(note.title, note.getIcon()); | ||||||
|         } else if (builtinWidget === 'spacer') { |             case "spacer": | ||||||
|             // || has to be inside since 0 is a valid value |                 // || has to be inside since 0 is a valid value | ||||||
|             const baseSize = parseInt(note.getLabelValue("baseSize") || "40"); |                 const baseSize = parseInt(note.getLabelValue("baseSize") || "40"); | ||||||
|             const growthFactor = parseInt(note.getLabelValue("growthFactor") || "100"); |                 const growthFactor = parseInt(note.getLabelValue("growthFactor") || "100"); | ||||||
|  |          | ||||||
|             return new SpacerWidget(baseSize, growthFactor); |                 return new SpacerWidget(baseSize, growthFactor); | ||||||
|         } else if (builtinWidget === 'bookmarks') { |             case "bookmarks": | ||||||
|             return new BookmarkButtons(); |                 return new BookmarkButtons(); | ||||||
|         } else if (builtinWidget === 'protectedSession') { |             case "protectedSession": | ||||||
|             return new ProtectedSessionStatusWidget(); |                 return new ProtectedSessionStatusWidget(); | ||||||
|         } else if (builtinWidget === 'syncStatus') { |             case "syncStatus": | ||||||
|             return new SyncStatusWidget(); |                 return new SyncStatusWidget(); | ||||||
|         } else if (builtinWidget === 'backInHistoryButton') { |             case "backInHistoryButton": | ||||||
|             return new HistoryNavigationButton(note, "backInNoteHistory"); |                 return new HistoryNavigationButton(note, "backInNoteHistory"); | ||||||
|         } else if (builtinWidget === 'forwardInHistoryButton') { |             case "forwardInHistoryButton": | ||||||
|             return new HistoryNavigationButton(note, "forwardInNoteHistory"); |                 return new HistoryNavigationButton(note, "forwardInNoteHistory"); | ||||||
|         } else if (builtinWidget === 'todayInJournal') { |             case "todayInJournal": | ||||||
|             return new TodayLauncher(note); |                 return new TodayLauncher(note); | ||||||
|         } else { |             case "quickSearch": | ||||||
|             throw new Error(`Unrecognized builtin widget ${builtinWidget} for launcher ${note.noteId} "${note.title}"`); |                 return new QuickSearchLauncherWidget(this.isHorizontalLayout); | ||||||
|  |             default: | ||||||
|  |                 throw new Error(`Unrecognized builtin widget ${builtinWidget} for launcher ${note.noteId} "${note.title}"`); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,12 +4,13 @@ import appContext from "../../components/app_context.js"; | |||||||
| import LauncherWidget from "./launcher.js"; | import LauncherWidget from "./launcher.js"; | ||||||
|  |  | ||||||
| export default class LauncherContainer extends FlexContainer { | export default class LauncherContainer extends FlexContainer { | ||||||
|     constructor() { |     constructor(isHorizontalLayout) { | ||||||
|         super('column'); |         super(isHorizontalLayout ? "row" : "column"); | ||||||
|  |  | ||||||
|         this.id('launcher-container'); |         this.id('launcher-container'); | ||||||
|         this.css('height', '100%'); |         this.css(isHorizontalLayout ? "width" : 'height', '100%'); | ||||||
|         this.filling(); |         this.filling(); | ||||||
|  |         this.isHorizontalLayout = isHorizontalLayout; | ||||||
|  |  | ||||||
|         this.load(); |         this.load(); | ||||||
|     } |     } | ||||||
| @@ -29,7 +30,7 @@ export default class LauncherContainer extends FlexContainer { | |||||||
|  |  | ||||||
|         for (const launcherNote of await visibleLaunchersRoot.getChildNotes()) { |         for (const launcherNote of await visibleLaunchersRoot.getChildNotes()) { | ||||||
|             try { |             try { | ||||||
|                 const launcherWidget = new LauncherWidget(); |                 const launcherWidget = new LauncherWidget(this.isHorizontalLayout); | ||||||
|                 const success = await launcherWidget.initLauncher(launcherNote); |                 const success = await launcherWidget.initLauncher(launcherNote); | ||||||
|  |  | ||||||
|                 if (success) { |                 if (success) { | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| import FlexContainer from "./flex_container.js"; | import FlexContainer from "./flex_container.js"; | ||||||
|  |  | ||||||
| export default class RootContainer extends FlexContainer { | export default class RootContainer extends FlexContainer { | ||||||
|     constructor() { |     constructor(isHorizontalLayout) { | ||||||
|         super('row'); |         super(isHorizontalLayout ? "column" : "row"); | ||||||
|  |  | ||||||
|         this.id('root-widget'); |         this.id('root-widget'); | ||||||
|         this.css('height', '100%'); |         this.css('height', '100%'); | ||||||
|   | |||||||
| @@ -6,12 +6,20 @@ import branchService from "../../services/branches.js"; | |||||||
| import treeService from "../../services/tree.js"; | import treeService from "../../services/tree.js"; | ||||||
| import { t } from "../../services/i18n.js"; | import { t } from "../../services/i18n.js"; | ||||||
|  |  | ||||||
| const TPL = `<button type="button" class="action-button bx bx-menu" style="padding-top: 10px;"></button>`; | const TPL = `<button type="button" class="action-button bx" style="padding-top: 10px;"></button>`; | ||||||
|  |  | ||||||
| class MobileDetailMenuWidget extends BasicWidget { | class MobileDetailMenuWidget extends BasicWidget { | ||||||
|  |  | ||||||
|  |     constructor(isHorizontalLayout) { | ||||||
|  |         super(); | ||||||
|  |         this.isHorizontalLayout = isHorizontalLayout; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     doRender() { |     doRender() { | ||||||
|         this.$widget = $(TPL); |         this.$widget = $(TPL); | ||||||
|  |  | ||||||
|  |         this.$widget.addClass(this.isHorizontalLayout ? "bx-dots-vertical-rounded" : "bx-menu"); | ||||||
|  |  | ||||||
|         this.$widget.on("click", async e => { |         this.$widget.on("click", async e => { | ||||||
|             const note = appContext.tabManager.getActiveContextNote(); |             const note = appContext.tabManager.getActiveContextNote(); | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										33
									
								
								src/public/app/widgets/quick_search_launcher.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/public/app/widgets/quick_search_launcher.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | import utils from "../services/utils.js"; | ||||||
|  | import QuickSearchWidget from "./quick_search.js"; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Similar to the {@link QuickSearchWidget} but meant to be included inside the launcher bar. | ||||||
|  |  *  | ||||||
|  |  * <p> | ||||||
|  |  * Adds specific tweaks such as: | ||||||
|  |  *  | ||||||
|  |  * - Hiding the widget on mobile. | ||||||
|  |  */ | ||||||
|  | export default class QuickSearchLauncherWidget extends QuickSearchWidget { | ||||||
|  |  | ||||||
|  |     constructor(isHorizontalLayout) { | ||||||
|  |         super(); | ||||||
|  |         this.isHorizontalLayout = isHorizontalLayout; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     isEnabled() { | ||||||
|  |         if (!this.isHorizontalLayout) { | ||||||
|  |             // The quick search widget is added somewhere else on the vertical layout. | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (utils.isMobile()) { | ||||||
|  |             // The widget takes too much spaces to be included in the mobile layout. | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return super.isEnabled(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -55,6 +55,10 @@ const TAB_ROW_TPL = ` | |||||||
|         background: var(--main-background-color); |         background: var(--main-background-color); | ||||||
|         overflow: hidden; |         overflow: hidden; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     .tab-row-widget.full-width { | ||||||
|  |         background: var(--launcher-pane-background-color); | ||||||
|  |     } | ||||||
|      |      | ||||||
|     .tab-row-widget * { |     .tab-row-widget * { | ||||||
|         box-sizing: inherit; |         box-sizing: inherit; | ||||||
|   | |||||||
| @@ -5,6 +5,26 @@ import { t } from "../../../../services/i18n.js"; | |||||||
|  |  | ||||||
| const TPL = ` | const TPL = ` | ||||||
| <div class="options-section"> | <div class="options-section"> | ||||||
|  |     <h4>${t("theme.layout")}</h4> | ||||||
|  |  | ||||||
|  |     <div class="form-group row"> | ||||||
|  |         <div> | ||||||
|  |             <label> | ||||||
|  |                 <input type="radio" name="layout-orientation" value="vertical" /> | ||||||
|  |                 <strong>${t("theme.layout-vertical-title")}</strong> | ||||||
|  |                 - ${t("theme.layout-vertical-description")} | ||||||
|  |             </label> | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|  |         <div> | ||||||
|  |             <label> | ||||||
|  |                 <input type="radio" name="layout-orientation" value="horizontal" /> | ||||||
|  |                 <strong>${t("theme.layout-horizontal-title")}</strong> | ||||||
|  |                 - ${t("theme.layout-horizontal-description")} | ||||||
|  |             </label> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  |  | ||||||
|     <h4>${t("theme.title")}</h4> |     <h4>${t("theme.title")}</h4> | ||||||
|      |      | ||||||
|     <div class="form-group row"> |     <div class="form-group row"> | ||||||
| @@ -19,7 +39,7 @@ const TPL = ` | |||||||
|                 ${t("theme.override_theme_fonts_label")} |                 ${t("theme.override_theme_fonts_label")} | ||||||
|             </label> |             </label> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div>     | ||||||
| </div>`; | </div>`; | ||||||
|  |  | ||||||
| export default class ThemeOptions extends OptionsWidget { | export default class ThemeOptions extends OptionsWidget { | ||||||
| @@ -27,6 +47,11 @@ export default class ThemeOptions extends OptionsWidget { | |||||||
|         this.$widget = $(TPL); |         this.$widget = $(TPL); | ||||||
|         this.$themeSelect = this.$widget.find(".theme-select"); |         this.$themeSelect = this.$widget.find(".theme-select"); | ||||||
|         this.$overrideThemeFonts = this.$widget.find(".override-theme-fonts"); |         this.$overrideThemeFonts = this.$widget.find(".override-theme-fonts"); | ||||||
|  |         this.$layoutOrientation = this.$widget.find(`input[name="layout-orientation"]`).on("change", async () => { | ||||||
|  |             const newLayoutOrientation = this.$widget.find(`input[name="layout-orientation"]:checked`).val(); | ||||||
|  |             await this.updateOption("layoutOrientation", newLayoutOrientation); | ||||||
|  |             utils.reloadFrontendApp("layout orientation change"); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|         this.$themeSelect.on('change', async () => { |         this.$themeSelect.on('change', async () => { | ||||||
|             const newTheme = this.$themeSelect.val(); |             const newTheme = this.$themeSelect.val(); | ||||||
| @@ -58,5 +83,8 @@ export default class ThemeOptions extends OptionsWidget { | |||||||
|         this.$themeSelect.val(options.theme); |         this.$themeSelect.val(options.theme); | ||||||
|  |  | ||||||
|         this.setCheckboxState(this.$overrideThemeFonts, options.overrideThemeFonts); |         this.setCheckboxState(this.$overrideThemeFonts, options.overrideThemeFonts); | ||||||
|  |  | ||||||
|  |         this.$widget.find(`input[name="layout-orientation"][value="${options.layoutOrientation}"]`) | ||||||
|  |             .prop("checked", "true"); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -40,6 +40,10 @@ body { | |||||||
|     font-size: var(--main-font-size); |     font-size: var(--main-font-size); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | body.mobile .desktop-only { | ||||||
|  |     display: none !important; | ||||||
|  | } | ||||||
|  |  | ||||||
| a { | a { | ||||||
|     text-decoration: none; |     text-decoration: none; | ||||||
| } | } | ||||||
| @@ -1022,6 +1026,18 @@ li.dropdown-submenu:hover > ul.dropdown-menu { | |||||||
|     overflow: auto; |     overflow: auto; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu { | ||||||
|  |     left: calc(-100% + 10px); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #launcher-pane.horizontal .right-dropdown-widget { | ||||||
|  |     width: 53px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #launcher-pane.vertical .right-dropdown-widget { | ||||||
|  |     height: 53px; | ||||||
|  | } | ||||||
|  |  | ||||||
| /* rotate caret on hover */ | /* rotate caret on hover */ | ||||||
| .dropdown-menu > li > a:hover:after { | .dropdown-menu > li > a:hover:after { | ||||||
|     text-decoration: underline; |     text-decoration: underline; | ||||||
| @@ -1123,9 +1139,21 @@ li.dropdown-submenu:hover > ul.dropdown-menu { | |||||||
|     cursor: pointer; |     cursor: pointer; | ||||||
|     border: none; |     border: none; | ||||||
|     color: var(--launcher-pane-text-color); |     color: var(--launcher-pane-text-color); | ||||||
|     background-color: var(--launcher-pane-background-color); |     background-color: var(--launcher-pane-background-color);     | ||||||
|     height: 53px; | } | ||||||
|  |  | ||||||
|  | #launcher-pane.vertical .launcher-button { | ||||||
|     width: 100%; |     width: 100%; | ||||||
|  |     height: 53px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #launcher-pane.horizontal .launcher-button { | ||||||
|  |     width: 53px; | ||||||
|  |     height: 100%; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #launcher-pane.horizontal .quick-search { | ||||||
|  |     width: 350px; | ||||||
| } | } | ||||||
|  |  | ||||||
| #launcher-pane .icon-action:hover { | #launcher-pane .icon-action:hover { | ||||||
|   | |||||||
| @@ -1062,7 +1062,12 @@ | |||||||
|     "override_theme_fonts_label": "Override theme fonts", |     "override_theme_fonts_label": "Override theme fonts", | ||||||
|     "light_theme": "Light", |     "light_theme": "Light", | ||||||
|     "dark_theme": "Dark", |     "dark_theme": "Dark", | ||||||
|     "triliumnext": "TriliumNext" |     "triliumnext": "TriliumNext", | ||||||
|  |     "layout": "Layout", | ||||||
|  |     "layout-vertical-title": "Vertical", | ||||||
|  |     "layout-horizontal-title": "Horizontal", | ||||||
|  |     "layout-vertical-description": "launcher bar is on the left (default)", | ||||||
|  |     "layout-horizontal-description": "launcher bar is underneath the tab bar, the tab bar is now full width." | ||||||
|   }, |   }, | ||||||
|   "zoom_factor": { |   "zoom_factor": { | ||||||
|     "title": "Zoom Factor (desktop build only)", |     "title": "Zoom Factor (desktop build only)", | ||||||
|   | |||||||
| @@ -1529,11 +1529,11 @@ | |||||||
|       "label": "Bară de formatare", |       "label": "Bară de formatare", | ||||||
|       "floating": { |       "floating": { | ||||||
|         "title": "Editor cu bară flotantă", |         "title": "Editor cu bară flotantă", | ||||||
|         "description": "uneltele de editare vor apărea lângă cursor." |         "description": "uneltele de editare vor apărea lângă cursor;" | ||||||
|       }, |       }, | ||||||
|       "fixed": { |       "fixed": { | ||||||
|         "title": "Editor cu bară fixă", |         "title": "Editor cu bară fixă", | ||||||
|         "description": "uneltele de editare vor apărea în tab-ul „Formatare” din panglică;" |         "description": "uneltele de editare vor apărea în tab-ul „Formatare” din panglică." | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   | |||||||
| @@ -66,7 +66,8 @@ const ALLOWED_OPTIONS = new Set([ | |||||||
|     'editedNotesOpenInRibbon', |     'editedNotesOpenInRibbon', | ||||||
|     'locale', |     'locale', | ||||||
|     'firstDayOfWeek', |     'firstDayOfWeek', | ||||||
|     'textNoteEditorType' |     'textNoteEditorType', | ||||||
|  |     'layoutOrientation' | ||||||
| ]); | ]); | ||||||
|  |  | ||||||
| function getOptions() { | function getOptions() { | ||||||
|   | |||||||
| @@ -34,7 +34,7 @@ interface Item { | |||||||
|     baseSize?: string; |     baseSize?: string; | ||||||
|     growthFactor?: string; |     growthFactor?: string; | ||||||
|     targetNoteId?: "_backendLog" | "_globalNoteMap"; |     targetNoteId?: "_backendLog" | "_globalNoteMap"; | ||||||
|     builtinWidget?: "bookmarks" | "spacer" | "backInHistoryButton" | "forwardInHistoryButton" | "syncStatus" | "protectedSession" | "todayInJournal" | "calendar"; |     builtinWidget?: "bookmarks" | "spacer" | "backInHistoryButton" | "forwardInHistoryButton" | "syncStatus" | "protectedSession" | "todayInJournal" | "calendar" | "quickSearch"; | ||||||
|     command?: keyof typeof Command; |     command?: keyof typeof Command; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -240,6 +240,7 @@ const HIDDEN_SUBTREE_DEFINITION: Item = { | |||||||
|                         { id: '_lbBookmarks', title: 'Bookmarks', type: 'launcher', builtinWidget: 'bookmarks', icon: 'bx bx-bookmark' }, |                         { id: '_lbBookmarks', title: 'Bookmarks', type: 'launcher', builtinWidget: 'bookmarks', icon: 'bx bx-bookmark' }, | ||||||
|                         { id: '_lbToday', title: "Open Today's Journal Note", type: 'launcher', builtinWidget: 'todayInJournal', icon: 'bx bx-calendar-star' }, |                         { id: '_lbToday', title: "Open Today's Journal Note", type: 'launcher', builtinWidget: 'todayInJournal', icon: 'bx bx-calendar-star' }, | ||||||
|                         { id: '_lbSpacer2', title: 'Spacer', type: 'launcher', builtinWidget: 'spacer', baseSize: "0", growthFactor: "1" }, |                         { id: '_lbSpacer2', title: 'Spacer', type: 'launcher', builtinWidget: 'spacer', baseSize: "0", growthFactor: "1" }, | ||||||
|  |                         { id: '_lbQuickSearch', title: "Quick Search", type: "launcher", builtinWidget: "quickSearch", icon: "bx bx-rectangle" }, | ||||||
|                         { id: '_lbProtectedSession', title: 'Protected Session', type: 'launcher', builtinWidget: 'protectedSession', icon: 'bx bx bx-shield-quarter' }, |                         { id: '_lbProtectedSession', title: 'Protected Session', type: 'launcher', builtinWidget: 'protectedSession', icon: 'bx bx bx-shield-quarter' }, | ||||||
|                         { id: '_lbSyncStatus', title: 'Sync Status', type: 'launcher', builtinWidget: 'syncStatus', icon: 'bx bx-wifi' }, |                         { id: '_lbSyncStatus', title: 'Sync Status', type: 'launcher', builtinWidget: 'syncStatus', icon: 'bx bx-wifi' }, | ||||||
|                         { id: '_lbSettings', title: 'Settings', type: 'launcher', command: 'showOptions', icon: 'bx bx-cog' } |                         { id: '_lbSettings', title: 'Settings', type: 'launcher', command: 'showOptions', icon: 'bx bx-cog' } | ||||||
|   | |||||||
| @@ -133,7 +133,9 @@ const defaultOptions: DefaultOption[] = [ | |||||||
|     { name: "codeBlockWordWrap", value: "false", isSynced: true }, |     { name: "codeBlockWordWrap", value: "false", isSynced: true }, | ||||||
|  |  | ||||||
|     // Text note configuration |     // Text note configuration | ||||||
|     { name: "textNoteEditorType", value: "ckeditor-balloon", isSynced: true } |     { name: "textNoteEditorType", value: "ckeditor-balloon", isSynced: true }, | ||||||
|  |  | ||||||
|  |     { name: "layoutOrientation", value: "vertical", isSynced: false } | ||||||
| ]; | ]; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user