mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-04 13:39:01 +01:00 
			
		
		
		
	Merge remote-tracking branch 'origin/develop' into feature/trilium_next_theme
This commit is contained in:
		
						commit
						5b62ad101d
					
				@ -88,8 +88,11 @@ export default class Component {
 | 
			
		||||
 | 
			
		||||
        if (fun) {
 | 
			
		||||
            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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -83,6 +83,7 @@ import UploadAttachmentsDialog from "../widgets/dialogs/upload_attachments.js";
 | 
			
		||||
import CopyImageReferenceButton from "../widgets/floating_buttons/copy_image_reference_button.js";
 | 
			
		||||
import ScrollPaddingWidget from "../widgets/scroll_padding.js";
 | 
			
		||||
import ClassicEditorToolbar from "../widgets/ribbon_widgets/classic_editor_toolbar.js";
 | 
			
		||||
import options from "../services/options.js";
 | 
			
		||||
 | 
			
		||||
export default class DesktopLayout {
 | 
			
		||||
    constructor(customWidgets) {
 | 
			
		||||
@ -92,112 +93,120 @@ export default class DesktopLayout {
 | 
			
		||||
    getRootWidget(appContext) {
 | 
			
		||||
        appContext.noteTreeWidget = new NoteTreeWidget();
 | 
			
		||||
 | 
			
		||||
        return new RootContainer()
 | 
			
		||||
        const launcherPaneIsHorizontal = (options.get("layoutOrientation") === "horizontal");
 | 
			
		||||
        const launcherPane = this.#buildLauncherPane(launcherPaneIsHorizontal);
 | 
			
		||||
 | 
			
		||||
        return new RootContainer(launcherPaneIsHorizontal)
 | 
			
		||||
            .setParent(appContext)
 | 
			
		||||
            .child(new FlexContainer("column")
 | 
			
		||||
                .id("launcher-pane")
 | 
			
		||||
                .css("width", "53px")
 | 
			
		||||
                .child(new GlobalMenuWidget())
 | 
			
		||||
                .child(new LauncherContainer())
 | 
			
		||||
                .child(new LeftPaneToggleWidget())
 | 
			
		||||
            .optChild(launcherPaneIsHorizontal, new FlexContainer('row')               
 | 
			
		||||
                .child(new TabRowWidget().class("full-width"))
 | 
			
		||||
                .child(new TitleBarButtonsWidget())
 | 
			
		||||
                .css('height', '40px')
 | 
			
		||||
                .css('background-color', 'var(--launcher-pane-background-color)')
 | 
			
		||||
                .setParent(appContext)
 | 
			
		||||
            )
 | 
			
		||||
            .child(new LeftPaneContainer()
 | 
			
		||||
                .child(new QuickSearchWidget())
 | 
			
		||||
                .child(appContext.noteTreeWidget)
 | 
			
		||||
                .child(...this.customWidgets.get('left-pane'))
 | 
			
		||||
            )
 | 
			
		||||
            .child(new FlexContainer('column')
 | 
			
		||||
                .id('rest-pane')
 | 
			
		||||
            .optChild(launcherPaneIsHorizontal, launcherPane)
 | 
			
		||||
            .child(new FlexContainer('row')
 | 
			
		||||
                .css("flex-grow", "1")
 | 
			
		||||
                .child(new FlexContainer('row')
 | 
			
		||||
                    .child(new TabRowWidget())
 | 
			
		||||
                    .child(new TitleBarButtonsWidget())
 | 
			
		||||
                    .css('height', '40px')
 | 
			
		||||
                .optChild(!launcherPaneIsHorizontal, launcherPane)
 | 
			
		||||
                .child(new LeftPaneContainer()
 | 
			
		||||
                    .optChild(!launcherPaneIsHorizontal, new QuickSearchWidget())
 | 
			
		||||
                    .child(appContext.noteTreeWidget)
 | 
			
		||||
                    .child(...this.customWidgets.get('left-pane'))
 | 
			
		||||
                )
 | 
			
		||||
                .child(new FlexContainer('row')
 | 
			
		||||
                    .filling()
 | 
			
		||||
                    .collapsible()
 | 
			
		||||
                    .child(new FlexContainer('column')
 | 
			
		||||
                .child(new FlexContainer('column')
 | 
			
		||||
                    .id('rest-pane')
 | 
			
		||||
                    .css("flex-grow", "1")
 | 
			
		||||
                    .optChild(!launcherPaneIsHorizontal, new FlexContainer('row')
 | 
			
		||||
                        .child(new TabRowWidget())
 | 
			
		||||
                        .child(new TitleBarButtonsWidget())
 | 
			
		||||
                        .css('height', '40px')
 | 
			
		||||
                    )
 | 
			
		||||
                    .child(new FlexContainer('row')
 | 
			
		||||
                        .filling()
 | 
			
		||||
                        .collapsible()
 | 
			
		||||
                        .id('center-pane')
 | 
			
		||||
                        .child(new SplitNoteContainer(() =>
 | 
			
		||||
                                new NoteWrapperWidget()
 | 
			
		||||
                                    .child(new FlexContainer('row').class('title-row')
 | 
			
		||||
                                        .css("height", "50px")
 | 
			
		||||
                                        .css("min-height", "50px")
 | 
			
		||||
                                        .css('align-items', "center")
 | 
			
		||||
                                        .cssBlock('.title-row > * { margin: 5px; }')
 | 
			
		||||
                                        .child(new NoteIconWidget())
 | 
			
		||||
                                        .child(new NoteTitleWidget())
 | 
			
		||||
                                        .child(new SpacerWidget(0, 1))
 | 
			
		||||
                                        .child(new MovePaneButton(true))
 | 
			
		||||
                                        .child(new MovePaneButton(false))
 | 
			
		||||
                                        .child(new ClosePaneButton())
 | 
			
		||||
                                        .child(new CreatePaneButton())
 | 
			
		||||
                                    )
 | 
			
		||||
                                    .child(
 | 
			
		||||
                                        new RibbonContainer()
 | 
			
		||||
                                            // 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".
 | 
			
		||||
                                            // promoted attributes should always win.
 | 
			
		||||
                                            .ribbon(new ClassicEditorToolbar())
 | 
			
		||||
                                            .ribbon(new PromotedAttributesWidget())
 | 
			
		||||
                                            .ribbon(new ScriptExecutorWidget())
 | 
			
		||||
                                            .ribbon(new SearchDefinitionWidget())
 | 
			
		||||
                                            .ribbon(new EditedNotesWidget())
 | 
			
		||||
                                            .ribbon(new BookPropertiesWidget())
 | 
			
		||||
                                            .ribbon(new NotePropertiesWidget())
 | 
			
		||||
                                            .ribbon(new FilePropertiesWidget())
 | 
			
		||||
                                            .ribbon(new ImagePropertiesWidget())
 | 
			
		||||
                                            .ribbon(new BasicPropertiesWidget())
 | 
			
		||||
                                            .ribbon(new OwnedAttributeListWidget())
 | 
			
		||||
                                            .ribbon(new InheritedAttributesWidget())
 | 
			
		||||
                                            .ribbon(new NotePathsWidget())
 | 
			
		||||
                                            .ribbon(new NoteMapRibbonWidget())
 | 
			
		||||
                                            .ribbon(new SimilarNotesWidget())
 | 
			
		||||
                                            .ribbon(new NoteInfoWidget())
 | 
			
		||||
                                            .button(new RevisionsButton())
 | 
			
		||||
                                            .button(new NoteActionsWidget())
 | 
			
		||||
                                    )
 | 
			
		||||
                                    .child(new SharedInfoWidget())
 | 
			
		||||
                                    .child(new WatchedFileUpdateStatusWidget())
 | 
			
		||||
                                    .child(new FloatingButtons()
 | 
			
		||||
                                        .child(new EditButton())
 | 
			
		||||
                                        .child(new ShowTocWidgetButton())
 | 
			
		||||
                                        .child(new ShowHighlightsListWidgetButton())
 | 
			
		||||
                                        .child(new CodeButtonsWidget())
 | 
			
		||||
                                        .child(new RelationMapButtons())
 | 
			
		||||
                                        .child(new CopyImageReferenceButton())
 | 
			
		||||
                                        .child(new SvgExportButton())
 | 
			
		||||
                                        .child(new BacklinksWidget())
 | 
			
		||||
                                        .child(new HideFloatingButtonsButton())
 | 
			
		||||
                                    )
 | 
			
		||||
                                    .child(new MermaidWidget())
 | 
			
		||||
                                    .child(
 | 
			
		||||
                                        new ScrollingContainer()
 | 
			
		||||
                                            .filling()
 | 
			
		||||
                                            .child(new SqlTableSchemasWidget())
 | 
			
		||||
                                            .child(new NoteDetailWidget())
 | 
			
		||||
                                            .child(new NoteListWidget())
 | 
			
		||||
                                            .child(new SearchResultWidget())
 | 
			
		||||
                                            .child(new SqlResultWidget())
 | 
			
		||||
                                            .child(new ScrollPaddingWidget())
 | 
			
		||||
                                    )
 | 
			
		||||
                                    .child(new ApiLogWidget())
 | 
			
		||||
                                    .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(new FlexContainer('column')
 | 
			
		||||
                            .filling()
 | 
			
		||||
                            .collapsible()
 | 
			
		||||
                            .id('center-pane')
 | 
			
		||||
                            .child(new SplitNoteContainer(() =>
 | 
			
		||||
                                    new NoteWrapperWidget()
 | 
			
		||||
                                        .child(new FlexContainer('row').class('title-row')
 | 
			
		||||
                                            .css("height", "50px")
 | 
			
		||||
                                            .css("min-height", "50px")
 | 
			
		||||
                                            .css('align-items', "center")
 | 
			
		||||
                                            .cssBlock('.title-row > * { margin: 5px; }')
 | 
			
		||||
                                            .child(new NoteIconWidget())
 | 
			
		||||
                                            .child(new NoteTitleWidget())
 | 
			
		||||
                                            .child(new SpacerWidget(0, 1))
 | 
			
		||||
                                            .child(new MovePaneButton(true))
 | 
			
		||||
                                            .child(new MovePaneButton(false))
 | 
			
		||||
                                            .child(new ClosePaneButton())
 | 
			
		||||
                                            .child(new CreatePaneButton())
 | 
			
		||||
                                        )
 | 
			
		||||
                                        .child(
 | 
			
		||||
                                            new RibbonContainer()
 | 
			
		||||
                                                // 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".
 | 
			
		||||
                                                // promoted attributes should always win.
 | 
			
		||||
                                                .ribbon(new ClassicEditorToolbar())
 | 
			
		||||
                                                .ribbon(new PromotedAttributesWidget())
 | 
			
		||||
                                                .ribbon(new ScriptExecutorWidget())
 | 
			
		||||
                                                .ribbon(new SearchDefinitionWidget())
 | 
			
		||||
                                                .ribbon(new EditedNotesWidget())
 | 
			
		||||
                                                .ribbon(new BookPropertiesWidget())
 | 
			
		||||
                                                .ribbon(new NotePropertiesWidget())
 | 
			
		||||
                                                .ribbon(new FilePropertiesWidget())
 | 
			
		||||
                                                .ribbon(new ImagePropertiesWidget())
 | 
			
		||||
                                                .ribbon(new BasicPropertiesWidget())
 | 
			
		||||
                                                .ribbon(new OwnedAttributeListWidget())
 | 
			
		||||
                                                .ribbon(new InheritedAttributesWidget())
 | 
			
		||||
                                                .ribbon(new NotePathsWidget())
 | 
			
		||||
                                                .ribbon(new NoteMapRibbonWidget())
 | 
			
		||||
                                                .ribbon(new SimilarNotesWidget())
 | 
			
		||||
                                                .ribbon(new NoteInfoWidget())
 | 
			
		||||
                                                .button(new RevisionsButton())
 | 
			
		||||
                                                .button(new NoteActionsWidget())
 | 
			
		||||
                                        )
 | 
			
		||||
                                        .child(new SharedInfoWidget())
 | 
			
		||||
                                        .child(new WatchedFileUpdateStatusWidget())
 | 
			
		||||
                                        .child(new FloatingButtons()
 | 
			
		||||
                                            .child(new EditButton())
 | 
			
		||||
                                            .child(new ShowTocWidgetButton())
 | 
			
		||||
                                            .child(new ShowHighlightsListWidgetButton())
 | 
			
		||||
                                            .child(new CodeButtonsWidget())
 | 
			
		||||
                                            .child(new RelationMapButtons())
 | 
			
		||||
                                            .child(new CopyImageReferenceButton())
 | 
			
		||||
                                            .child(new SvgExportButton())
 | 
			
		||||
                                            .child(new BacklinksWidget())
 | 
			
		||||
                                            .child(new HideFloatingButtonsButton())
 | 
			
		||||
                                        )
 | 
			
		||||
                                        .child(new MermaidWidget())
 | 
			
		||||
                                        .child(
 | 
			
		||||
                                            new ScrollingContainer()
 | 
			
		||||
                                                .filling()
 | 
			
		||||
                                                .child(new SqlTableSchemasWidget())
 | 
			
		||||
                                                .child(new NoteDetailWidget())
 | 
			
		||||
                                                .child(new NoteListWidget())
 | 
			
		||||
                                                .child(new SearchResultWidget())
 | 
			
		||||
                                                .child(new SqlResultWidget())
 | 
			
		||||
                                                .child(new ScrollPaddingWidget())
 | 
			
		||||
                                        )
 | 
			
		||||
                                        .child(new ApiLogWidget())
 | 
			
		||||
                                        .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 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 PromotedAttributesWidget from "../widgets/ribbon_widgets/promoted_attributes.js";
 | 
			
		||||
import ClassicEditorToolbar from "../widgets/ribbon_widgets/classic_editor_toolbar.js";
 | 
			
		||||
import options from "../services/options.js";
 | 
			
		||||
 | 
			
		||||
const MOBILE_CSS = `
 | 
			
		||||
<style>
 | 
			
		||||
@ -112,15 +113,12 @@ span.fancytree-expander {
 | 
			
		||||
 | 
			
		||||
export default class MobileLayout {
 | 
			
		||||
    getRootWidget(appContext) {
 | 
			
		||||
        return new RootContainer()
 | 
			
		||||
        const launcherPaneIsHorizontal = (options.get("layoutOrientation") === "horizontal");
 | 
			
		||||
 | 
			
		||||
        return new RootContainer(launcherPaneIsHorizontal)
 | 
			
		||||
            .setParent(appContext)
 | 
			
		||||
            .cssBlock(MOBILE_CSS)
 | 
			
		||||
            .child(new FlexContainer("column")
 | 
			
		||||
                .id("launcher-pane")
 | 
			
		||||
                .css("width", "53px")
 | 
			
		||||
                .child(new GlobalMenuWidget())
 | 
			
		||||
                .child(new LauncherContainer())
 | 
			
		||||
            )
 | 
			
		||||
            .child(this.#buildLauncherPane(launcherPaneIsHorizontal))
 | 
			
		||||
            .child(new FlexContainer("row")
 | 
			
		||||
                .filling()
 | 
			
		||||
                .child(new ScreenContainer("tree", 'column')
 | 
			
		||||
@ -140,12 +138,14 @@ export default class MobileLayout {
 | 
			
		||||
                    .child(new FlexContainer('row').contentSized()
 | 
			
		||||
                        .css('font-size', 'larger')
 | 
			
		||||
                        .css('align-items', 'center')
 | 
			
		||||
                        .child(new MobileDetailMenuWidget().contentSized())
 | 
			
		||||
                        .optChild(!launcherPaneIsHorizontal, new MobileDetailMenuWidget(false).contentSized())
 | 
			
		||||
                        .child(new NoteTitleWidget()
 | 
			
		||||
                            .contentSized()
 | 
			
		||||
                            .css("position: relative;")
 | 
			
		||||
                            .css("top: 5px;")
 | 
			
		||||
                            .optCss(launcherPaneIsHorizontal, "padding-left", "0.5em")
 | 
			
		||||
                        )
 | 
			
		||||
                        .optChild(launcherPaneIsHorizontal, new MobileDetailMenuWidget(true).contentSized())
 | 
			
		||||
                        .child(new CloseDetailButtonWidget().contentSized()))
 | 
			
		||||
                    .child(new SharedInfoWidget())
 | 
			
		||||
                    .child(new FloatingButtons()
 | 
			
		||||
@ -174,4 +174,25 @@ export default class MobileLayout {
 | 
			
		||||
                .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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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) {
 | 
			
		||||
        this.attrs.id = id;
 | 
			
		||||
        return this;
 | 
			
		||||
@ -50,11 +65,34 @@ class BasicWidget extends Component {
 | 
			
		||||
        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) {
 | 
			
		||||
        this.attrs.style += `${name}: ${value};`;
 | 
			
		||||
        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() {
 | 
			
		||||
        this.css("contain", "none");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,11 @@ export default class AbstractButtonWidget extends NoteContextAwareWidget {
 | 
			
		||||
    doRender() {
 | 
			
		||||
        this.$widget = $(TPL);
 | 
			
		||||
        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) {
 | 
			
		||||
@ -36,8 +40,6 @@ export default class AbstractButtonWidget extends NoteContextAwareWidget {
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.$widget.attr("data-placement", this.settings.titlePlacement);
 | 
			
		||||
 | 
			
		||||
        super.doRender();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ import UpdateAvailableWidget from "./update_available.js";
 | 
			
		||||
import options from "../../services/options.js";
 | 
			
		||||
 | 
			
		||||
const TPL = `
 | 
			
		||||
<div class="dropdown global-menu dropend">
 | 
			
		||||
<div class="dropdown global-menu">
 | 
			
		||||
    <style>
 | 
			
		||||
    .global-menu {
 | 
			
		||||
        width: 53px;
 | 
			
		||||
@ -107,22 +107,6 @@ const TPL = `
 | 
			
		||||
 | 
			
		||||
    <button type="button" data-bs-toggle="dropdown" aria-haspopup="true"
 | 
			
		||||
            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>
 | 
			
		||||
    </button>
 | 
			
		||||
 | 
			
		||||
@ -235,7 +219,7 @@ const TPL = `
 | 
			
		||||
            ${t('global_menu.options')}
 | 
			
		||||
        </li>
 | 
			
		||||
 | 
			
		||||
        <div class="dropdown-divider"></div>
 | 
			
		||||
        <div class="dropdown-divider desktop-only"></div>
 | 
			
		||||
 | 
			
		||||
        <li class="dropdown-item show-help-button" data-trigger-command="showHelp">
 | 
			
		||||
            <span class="bx bx-help-circle"></span>
 | 
			
		||||
@ -265,18 +249,46 @@ const TPL = `
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
export default class GlobalMenuWidget extends BasicWidget {
 | 
			
		||||
    constructor() {
 | 
			
		||||
    constructor(isHorizontalLayout) {
 | 
			
		||||
        super();
 | 
			
		||||
 | 
			
		||||
        this.updateAvailableWidget = new UpdateAvailableWidget();
 | 
			
		||||
        this.isHorizontalLayout = isHorizontalLayout;        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    doRender() {
 | 
			
		||||
        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"));
 | 
			
		||||
 | 
			
		||||
@ -300,7 +312,7 @@ export default class GlobalMenuWidget extends BasicWidget {
 | 
			
		||||
            if ($(e.target).children(".dropdown-menu").length === 1 || $(e.target).hasClass('dropdown-toggle')) {
 | 
			
		||||
                e.stopPropagation();
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
        })        
 | 
			
		||||
 | 
			
		||||
        this.$widget.find(".global-menu-button-update-available").append(
 | 
			
		||||
            this.updateAvailableWidget.render()
 | 
			
		||||
@ -316,10 +328,14 @@ export default class GlobalMenuWidget extends BasicWidget {
 | 
			
		||||
        this.$zoomState = this.$widget.find(".zoom-state");
 | 
			
		||||
        this.$widget.on('show.bs.dropdown', () => {
 | 
			
		||||
            this.updateZoomState();
 | 
			
		||||
            this.tooltip.hide();
 | 
			
		||||
            this.tooltip.disable();
 | 
			
		||||
            if (this.tooltip) {
 | 
			
		||||
                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",
 | 
			
		||||
            // delay to wait for the actual zoom change
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,7 @@ import CommandButtonWidget from "./command_button.js";
 | 
			
		||||
import { t } from "../../services/i18n.js";
 | 
			
		||||
 | 
			
		||||
export default class LeftPaneToggleWidget extends CommandButtonWidget {
 | 
			
		||||
    constructor() {
 | 
			
		||||
    constructor(isHorizontalLayout) {
 | 
			
		||||
        super();
 | 
			
		||||
 | 
			
		||||
        this.class("launcher-button");
 | 
			
		||||
@ -20,6 +20,10 @@ export default class LeftPaneToggleWidget extends CommandButtonWidget {
 | 
			
		||||
        this.settings.command = () => options.is('leftPaneVisible')
 | 
			
		||||
            ? "hideLeftPane"
 | 
			
		||||
            : "showLeftPane";
 | 
			
		||||
 | 
			
		||||
        if (isHorizontalLayout) {
 | 
			
		||||
            this.settings.titlePlacement = "bottom";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    refreshIcon() {
 | 
			
		||||
 | 
			
		||||
@ -2,13 +2,7 @@ import BasicWidget from "../basic_widget.js";
 | 
			
		||||
 | 
			
		||||
const TPL = `
 | 
			
		||||
<div class="dropdown right-dropdown-widget dropend">
 | 
			
		||||
    <style>
 | 
			
		||||
    .right-dropdown-widget {
 | 
			
		||||
        height: 53px;
 | 
			
		||||
    }
 | 
			
		||||
    </style>
 | 
			
		||||
 | 
			
		||||
    <button type="button" data-bs-toggle="dropdown" data-placement="right"
 | 
			
		||||
    <button type="button" data-bs-toggle="dropdown"
 | 
			
		||||
            aria-haspopup="true" aria-expanded="false" 
 | 
			
		||||
            class="bx right-dropdown-button launcher-button"></button>
 | 
			
		||||
    
 | 
			
		||||
@ -25,6 +19,10 @@ export default class RightDropdownButtonWidget extends BasicWidget {
 | 
			
		||||
        this.iconClass = iconClass;
 | 
			
		||||
        this.title = title;
 | 
			
		||||
        this.dropdownTpl = dropdownTpl;
 | 
			
		||||
 | 
			
		||||
        this.settings = {
 | 
			
		||||
            titlePlacement: "right"    
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    doRender() {
 | 
			
		||||
@ -33,7 +31,10 @@ export default class RightDropdownButtonWidget extends BasicWidget {
 | 
			
		||||
        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 = 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")
 | 
			
		||||
            .addClass(this.iconClass)
 | 
			
		||||
 | 
			
		||||
@ -10,12 +10,14 @@ import CommandButtonWidget from "../buttons/command_button.js";
 | 
			
		||||
import utils from "../../services/utils.js";
 | 
			
		||||
import TodayLauncher from "../buttons/launcher/today_launcher.js";
 | 
			
		||||
import HistoryNavigationButton from "../buttons/history_navigation.js";
 | 
			
		||||
import QuickSearchLauncherWidget from "../quick_search_launcher.js";
 | 
			
		||||
 | 
			
		||||
export default class LauncherWidget extends BasicWidget {
 | 
			
		||||
    constructor() {
 | 
			
		||||
    constructor(isHorizontalLayout) {
 | 
			
		||||
        super();
 | 
			
		||||
 | 
			
		||||
        this.innerWidget = null;
 | 
			
		||||
        this.isHorizontalLayout = isHorizontalLayout;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    isEnabled() {
 | 
			
		||||
@ -63,6 +65,9 @@ export default class LauncherWidget extends BasicWidget {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.child(this.innerWidget);
 | 
			
		||||
        if (this.isHorizontalLayout && this.innerWidget.settings) {
 | 
			
		||||
            this.innerWidget.settings.titlePlacement = "bottom";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
@ -86,29 +91,31 @@ export default class LauncherWidget extends BasicWidget {
 | 
			
		||||
 | 
			
		||||
    initBuiltinWidget(note) {
 | 
			
		||||
        const builtinWidget = note.getLabelValue("builtinWidget");
 | 
			
		||||
 | 
			
		||||
        if (builtinWidget === 'calendar') {
 | 
			
		||||
            return new CalendarWidget(note.title, note.getIcon());
 | 
			
		||||
        } else if (builtinWidget === 'spacer') {
 | 
			
		||||
            // || has to be inside since 0 is a valid value
 | 
			
		||||
            const baseSize = parseInt(note.getLabelValue("baseSize") || "40");
 | 
			
		||||
            const growthFactor = parseInt(note.getLabelValue("growthFactor") || "100");
 | 
			
		||||
 | 
			
		||||
            return new SpacerWidget(baseSize, growthFactor);
 | 
			
		||||
        } else if (builtinWidget === 'bookmarks') {
 | 
			
		||||
            return new BookmarkButtons();
 | 
			
		||||
        } else if (builtinWidget === 'protectedSession') {
 | 
			
		||||
            return new ProtectedSessionStatusWidget();
 | 
			
		||||
        } else if (builtinWidget === 'syncStatus') {
 | 
			
		||||
            return new SyncStatusWidget();
 | 
			
		||||
        } else if (builtinWidget === 'backInHistoryButton') {
 | 
			
		||||
            return new HistoryNavigationButton(note, "backInNoteHistory");
 | 
			
		||||
        } else if (builtinWidget === 'forwardInHistoryButton') {
 | 
			
		||||
            return new HistoryNavigationButton(note, "forwardInNoteHistory");
 | 
			
		||||
        } else if (builtinWidget === 'todayInJournal') {
 | 
			
		||||
            return new TodayLauncher(note);
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new Error(`Unrecognized builtin widget ${builtinWidget} for launcher ${note.noteId} "${note.title}"`);
 | 
			
		||||
        switch (builtinWidget) {
 | 
			
		||||
            case "calendar":
 | 
			
		||||
                return new CalendarWidget(note.title, note.getIcon());
 | 
			
		||||
            case "spacer":
 | 
			
		||||
                // || has to be inside since 0 is a valid value
 | 
			
		||||
                const baseSize = parseInt(note.getLabelValue("baseSize") || "40");
 | 
			
		||||
                const growthFactor = parseInt(note.getLabelValue("growthFactor") || "100");
 | 
			
		||||
        
 | 
			
		||||
                return new SpacerWidget(baseSize, growthFactor);
 | 
			
		||||
            case "bookmarks":
 | 
			
		||||
                return new BookmarkButtons();
 | 
			
		||||
            case "protectedSession":
 | 
			
		||||
                return new ProtectedSessionStatusWidget();
 | 
			
		||||
            case "syncStatus":
 | 
			
		||||
                return new SyncStatusWidget();
 | 
			
		||||
            case "backInHistoryButton":
 | 
			
		||||
                return new HistoryNavigationButton(note, "backInNoteHistory");
 | 
			
		||||
            case "forwardInHistoryButton":
 | 
			
		||||
                return new HistoryNavigationButton(note, "forwardInNoteHistory");
 | 
			
		||||
            case "todayInJournal":
 | 
			
		||||
                return new TodayLauncher(note);
 | 
			
		||||
            case "quickSearch":
 | 
			
		||||
                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";
 | 
			
		||||
 | 
			
		||||
export default class LauncherContainer extends FlexContainer {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super('column');
 | 
			
		||||
    constructor(isHorizontalLayout) {
 | 
			
		||||
        super(isHorizontalLayout ? "row" : "column");
 | 
			
		||||
 | 
			
		||||
        this.id('launcher-container');
 | 
			
		||||
        this.css('height', '100%');
 | 
			
		||||
        this.css(isHorizontalLayout ? "width" : 'height', '100%');
 | 
			
		||||
        this.filling();
 | 
			
		||||
        this.isHorizontalLayout = isHorizontalLayout;
 | 
			
		||||
 | 
			
		||||
        this.load();
 | 
			
		||||
    }
 | 
			
		||||
@ -29,7 +30,7 @@ export default class LauncherContainer extends FlexContainer {
 | 
			
		||||
 | 
			
		||||
        for (const launcherNote of await visibleLaunchersRoot.getChildNotes()) {
 | 
			
		||||
            try {
 | 
			
		||||
                const launcherWidget = new LauncherWidget();
 | 
			
		||||
                const launcherWidget = new LauncherWidget(this.isHorizontalLayout);
 | 
			
		||||
                const success = await launcherWidget.initLauncher(launcherNote);
 | 
			
		||||
 | 
			
		||||
                if (success) {
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
import FlexContainer from "./flex_container.js";
 | 
			
		||||
 | 
			
		||||
export default class RootContainer extends FlexContainer {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super('row');
 | 
			
		||||
    constructor(isHorizontalLayout) {
 | 
			
		||||
        super(isHorizontalLayout ? "column" : "row");
 | 
			
		||||
 | 
			
		||||
        this.id('root-widget');
 | 
			
		||||
        this.css('height', '100%');
 | 
			
		||||
 | 
			
		||||
@ -6,12 +6,20 @@ import branchService from "../../services/branches.js";
 | 
			
		||||
import treeService from "../../services/tree.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 {
 | 
			
		||||
 | 
			
		||||
    constructor(isHorizontalLayout) {
 | 
			
		||||
        super();
 | 
			
		||||
        this.isHorizontalLayout = isHorizontalLayout;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    doRender() {
 | 
			
		||||
        this.$widget = $(TPL);
 | 
			
		||||
 | 
			
		||||
        this.$widget.addClass(this.isHorizontalLayout ? "bx-dots-vertical-rounded" : "bx-menu");
 | 
			
		||||
 | 
			
		||||
        this.$widget.on("click", async e => {
 | 
			
		||||
            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);
 | 
			
		||||
        overflow: hidden;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .tab-row-widget.full-width {
 | 
			
		||||
        background: var(--launcher-pane-background-color);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    .tab-row-widget * {
 | 
			
		||||
        box-sizing: inherit;
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,26 @@ import { t } from "../../../../services/i18n.js";
 | 
			
		||||
 | 
			
		||||
const TPL = `
 | 
			
		||||
<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>
 | 
			
		||||
    
 | 
			
		||||
    <div class="form-group row">
 | 
			
		||||
@ -19,7 +39,7 @@ const TPL = `
 | 
			
		||||
                ${t("theme.override_theme_fonts_label")}
 | 
			
		||||
            </label>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    </div>    
 | 
			
		||||
</div>`;
 | 
			
		||||
 | 
			
		||||
export default class ThemeOptions extends OptionsWidget {
 | 
			
		||||
@ -27,6 +47,11 @@ export default class ThemeOptions extends OptionsWidget {
 | 
			
		||||
        this.$widget = $(TPL);
 | 
			
		||||
        this.$themeSelect = this.$widget.find(".theme-select");
 | 
			
		||||
        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 () => {
 | 
			
		||||
            const newTheme = this.$themeSelect.val();
 | 
			
		||||
@ -58,5 +83,8 @@ export default class ThemeOptions extends OptionsWidget {
 | 
			
		||||
        this.$themeSelect.val(options.theme);
 | 
			
		||||
 | 
			
		||||
        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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
body.mobile .desktop-only {
 | 
			
		||||
    display: none !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a {
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
}
 | 
			
		||||
@ -1022,6 +1026,18 @@ li.dropdown-submenu:hover > ul.dropdown-menu {
 | 
			
		||||
    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 */
 | 
			
		||||
.dropdown-menu > li > a:hover:after {
 | 
			
		||||
    text-decoration: underline;
 | 
			
		||||
@ -1123,9 +1139,21 @@ li.dropdown-submenu:hover > ul.dropdown-menu {
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    border: none;
 | 
			
		||||
    color: var(--launcher-pane-text-color);
 | 
			
		||||
    background-color: var(--launcher-pane-background-color);
 | 
			
		||||
    height: 53px;
 | 
			
		||||
    background-color: var(--launcher-pane-background-color);    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#launcher-pane.vertical .launcher-button {
 | 
			
		||||
    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 {
 | 
			
		||||
 | 
			
		||||
@ -1062,7 +1062,12 @@
 | 
			
		||||
    "override_theme_fonts_label": "Override theme fonts",
 | 
			
		||||
    "light_theme": "Light",
 | 
			
		||||
    "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": {
 | 
			
		||||
    "title": "Zoom Factor (desktop build only)",
 | 
			
		||||
 | 
			
		||||
@ -1529,11 +1529,11 @@
 | 
			
		||||
      "label": "Bară de formatare",
 | 
			
		||||
      "floating": {
 | 
			
		||||
        "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": {
 | 
			
		||||
        "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',
 | 
			
		||||
    'locale',
 | 
			
		||||
    'firstDayOfWeek',
 | 
			
		||||
    'textNoteEditorType'
 | 
			
		||||
    'textNoteEditorType',
 | 
			
		||||
    'layoutOrientation'
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
function getOptions() {
 | 
			
		||||
 | 
			
		||||
@ -34,7 +34,7 @@ interface Item {
 | 
			
		||||
    baseSize?: string;
 | 
			
		||||
    growthFactor?: string;
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -240,6 +240,7 @@ const HIDDEN_SUBTREE_DEFINITION: Item = {
 | 
			
		||||
                        { 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: '_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: '_lbSyncStatus', title: 'Sync Status', type: 'launcher', builtinWidget: 'syncStatus', icon: 'bx bx-wifi' },
 | 
			
		||||
                        { 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 },
 | 
			
		||||
 | 
			
		||||
    // Text note configuration
 | 
			
		||||
    { name: "textNoteEditorType", value: "ckeditor-balloon", isSynced: true }
 | 
			
		||||
    { name: "textNoteEditorType", value: "ckeditor-balloon", isSynced: true },
 | 
			
		||||
 | 
			
		||||
    { name: "layoutOrientation", value: "vertical", isSynced: false }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user