From a170bec3dbf9dea1458264510b8ad523b5f352e6 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 11:39:04 +0200 Subject: [PATCH 01/43] feat(touch_bar): basic integration --- src/public/app/components/app_context.ts | 5 ++++ src/public/app/widgets/touch_bar.ts | 37 ++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/public/app/widgets/touch_bar.ts diff --git a/src/public/app/components/app_context.ts b/src/public/app/components/app_context.ts index 8c62a5586..8cbe6b527 100644 --- a/src/public/app/components/app_context.ts +++ b/src/public/app/components/app_context.ts @@ -25,6 +25,7 @@ import type { default as NoteContext, GetTextEditorCallback } from "./note_conte import type { ContextMenuEvent } from "../menus/context_menu.js"; import type TypeWidget from "../widgets/type_widgets/type_widget.js"; import type EditableTextTypeWidget from "../widgets/type_widgets/editable_text.js"; +import TouchBarWidget from "../widgets/touch_bar.js"; interface Layout { getRootWidget: (appContext: AppContext) => RootWidget; @@ -444,6 +445,10 @@ class AppContext extends Component { this.components = [this.tabManager, new RootCommandExecutor(), new Entrypoints(), new MainTreeExecutors(), new ShortcutComponent()]; + if (utils.isElectron() && utils.isMac()) { + this.components.push(new TouchBarWidget()); + } + if (utils.isMobile()) { this.components.push(new MobileScreenSwitcherExecutor()); } diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/widgets/touch_bar.ts new file mode 100644 index 000000000..48ab23688 --- /dev/null +++ b/src/public/app/widgets/touch_bar.ts @@ -0,0 +1,37 @@ +import utils from "../services/utils.js"; +import Component from "../components/component.js"; + +export default class TouchBarWidget extends Component { + + remote: typeof import("@electron/remote"); + + constructor() { + super(); + this.remote = utils.dynamicRequire("@electron/remote") as typeof import("@electron/remote"); + this.#setTouchBar(); + } + + #setTouchBar() { + const touchBarData = this.#buildTouchBar(); + this.remote.getCurrentWindow().setTouchBar(touchBarData); + console.log("Setting touch bar", touchBarData); + } + + #buildTouchBar() { + const { TouchBarButton } = this.remote.TouchBar; + + const items = [ + new TouchBarButton({ + label: "New note", + click: () => { + console.log("New note pressed."); + } + }) + ]; + + return new this.remote.TouchBar({ + items + }); + } + +} From 3358b405e9a834f117aab0439b6c4899799824fb Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 11:51:55 +0200 Subject: [PATCH 02/43] feat(touch_bar): use icon for new note --- src/public/app/widgets/touch_bar.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/widgets/touch_bar.ts index 48ab23688..272f0cb1c 100644 --- a/src/public/app/widgets/touch_bar.ts +++ b/src/public/app/widgets/touch_bar.ts @@ -3,10 +3,12 @@ import Component from "../components/component.js"; export default class TouchBarWidget extends Component { + nativeImage: typeof import("electron").nativeImage; remote: typeof import("@electron/remote"); constructor() { super(); + this.nativeImage = utils.dynamicRequire("electron").nativeImage; this.remote = utils.dynamicRequire("@electron/remote") as typeof import("@electron/remote"); this.#setTouchBar(); } @@ -14,22 +16,24 @@ export default class TouchBarWidget extends Component { #setTouchBar() { const touchBarData = this.#buildTouchBar(); this.remote.getCurrentWindow().setTouchBar(touchBarData); - console.log("Setting touch bar", touchBarData); } #buildTouchBar() { + const { nativeImage } = this; + const { TouchBar } = this.remote; const { TouchBarButton } = this.remote.TouchBar; const items = [ new TouchBarButton({ - label: "New note", + icon: nativeImage.createFromNamedImage("NSTouchBarAddDetailTemplate", [-1, 0, 1]), click: () => { console.log("New note pressed."); } }) ]; - return new this.remote.TouchBar({ + console.log("Update ", items); + return new TouchBar({ items }); } From 0430a9c3f5800cd9c1b182c546e0dbb2f20942e3 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 11:55:09 +0200 Subject: [PATCH 03/43] feat(touch_bar): resize icon even if blurry --- src/public/app/widgets/touch_bar.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/widgets/touch_bar.ts index 272f0cb1c..076a52fdd 100644 --- a/src/public/app/widgets/touch_bar.ts +++ b/src/public/app/widgets/touch_bar.ts @@ -18,14 +18,19 @@ export default class TouchBarWidget extends Component { this.remote.getCurrentWindow().setTouchBar(touchBarData); } + #buildIcon(name: string) { + return this.nativeImage + .createFromNamedImage(name, [-1, 0, 1]) + .resize({ height: 20 }); + } + #buildTouchBar() { - const { nativeImage } = this; const { TouchBar } = this.remote; const { TouchBarButton } = this.remote.TouchBar; const items = [ new TouchBarButton({ - icon: nativeImage.createFromNamedImage("NSTouchBarAddDetailTemplate", [-1, 0, 1]), + icon: this.#buildIcon("NSTouchBarAddDetailTemplate"), click: () => { console.log("New note pressed."); } From f2f0f6178b0777103c692a03cd6bb334baf1e110 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 12:01:32 +0200 Subject: [PATCH 04/43] fix(touch_bar): blurry native images --- src/public/app/widgets/touch_bar.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/widgets/touch_bar.ts index 076a52fdd..5fcb3ee7d 100644 --- a/src/public/app/widgets/touch_bar.ts +++ b/src/public/app/widgets/touch_bar.ts @@ -19,9 +19,21 @@ export default class TouchBarWidget extends Component { } #buildIcon(name: string) { - return this.nativeImage - .createFromNamedImage(name, [-1, 0, 1]) - .resize({ height: 20 }); + const sourceImage = this.nativeImage.createFromNamedImage(name, [-1, 0, 1]); + const newImage = this.nativeImage.createEmpty() + newImage.addRepresentation({ + scaleFactor: 1, + width: 22, + height: 22, + buffer: sourceImage.resize({ height: 22 }).toBitmap() + }); + newImage.addRepresentation({ + scaleFactor: 2, + width: 44, + height: 44, + buffer: sourceImage.resize({ height: 44 }).toBitmap() + }); + return newImage; } #buildTouchBar() { From dd575787fe42cc89d4f138e8c867410453e4f5f7 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 12:06:35 +0200 Subject: [PATCH 05/43] feat(touch_bar): functional new note button --- src/public/app/components/app_context.ts | 2 ++ src/public/app/widgets/touch_bar.ts | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/public/app/components/app_context.ts b/src/public/app/components/app_context.ts index 8cbe6b527..3e1535393 100644 --- a/src/public/app/components/app_context.ts +++ b/src/public/app/components/app_context.ts @@ -162,6 +162,8 @@ export type CommandMappings = { moveNoteDownInHierarchy: ContextMenuCommandData; selectAllNotesInParent: ContextMenuCommandData; + createNoteIntoInbox: CommandData; + addNoteLauncher: ContextMenuCommandData; addScriptLauncher: ContextMenuCommandData; addWidgetLauncher: ContextMenuCommandData; diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/widgets/touch_bar.ts index 5fcb3ee7d..92b1ab060 100644 --- a/src/public/app/widgets/touch_bar.ts +++ b/src/public/app/widgets/touch_bar.ts @@ -42,10 +42,8 @@ export default class TouchBarWidget extends Component { const items = [ new TouchBarButton({ - icon: this.#buildIcon("NSTouchBarAddDetailTemplate"), - click: () => { - console.log("New note pressed."); - } + icon: this.#buildIcon("NSTouchBarComposeTemplate"), + click: () => this.triggerCommand("createNoteIntoInbox") }) ]; From d9a689bd9a76f8bfc88d6d4aad9a61287bb1f26a Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 12:34:06 +0200 Subject: [PATCH 06/43] feat(touch_bar): functional bold, italic, underline --- src/public/app/widgets/touch_bar.ts | 47 ++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/widgets/touch_bar.ts index 92b1ab060..7103c1988 100644 --- a/src/public/app/widgets/touch_bar.ts +++ b/src/public/app/widgets/touch_bar.ts @@ -1,5 +1,6 @@ import utils from "../services/utils.js"; import Component from "../components/component.js"; +import appContext from "../components/app_context.js"; export default class TouchBarWidget extends Component { @@ -20,30 +21,60 @@ export default class TouchBarWidget extends Component { #buildIcon(name: string) { const sourceImage = this.nativeImage.createFromNamedImage(name, [-1, 0, 1]); - const newImage = this.nativeImage.createEmpty() + const { width, height } = sourceImage.getSize(); + const newImage = this.nativeImage.createEmpty(); newImage.addRepresentation({ scaleFactor: 1, - width: 22, - height: 22, - buffer: sourceImage.resize({ height: 22 }).toBitmap() + width: width / 2, + height: height / 2, + buffer: sourceImage.resize({ height: height / 2 }).toBitmap() }); newImage.addRepresentation({ scaleFactor: 2, - width: 44, - height: 44, - buffer: sourceImage.resize({ height: 44 }).toBitmap() + width: width, + height: height, + buffer: sourceImage.toBitmap() }); return newImage; } + async #triggerTextEditorCommand(command: string) { + const editor = await appContext.tabManager.getActiveContext().getTextEditor(); + if (!editor) { + return; + } + + // TODO: Fix type of editor. + (editor as any).execute(command); + } + #buildTouchBar() { const { TouchBar } = this.remote; - const { TouchBarButton } = this.remote.TouchBar; + const { TouchBarButton, TouchBarSpacer, TouchBarGroup } = this.remote.TouchBar; const items = [ new TouchBarButton({ icon: this.#buildIcon("NSTouchBarComposeTemplate"), click: () => this.triggerCommand("createNoteIntoInbox") + }), + new TouchBarSpacer({ }), + new TouchBarGroup({ + items: new TouchBar({ + items: [ + new TouchBarButton({ + icon: this.#buildIcon("NSTouchBarTextBoldTemplate"), + click: () => this.#triggerTextEditorCommand("bold") + }), + new TouchBarButton({ + icon: this.#buildIcon("NSTouchBarTextItalicTemplate"), + click: () => this.#triggerTextEditorCommand("italic") + }), + new TouchBarButton({ + icon: this.#buildIcon("NSTouchBarTextUnderlineTemplate"), + click: () => this.#triggerTextEditorCommand("underline") + }) + ] + }) }) ]; From 9c24b891806cadafc4239d6cff4abb47fcf33b9d Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 13:13:21 +0200 Subject: [PATCH 07/43] feat(touch_bar): jump to note --- src/public/app/components/app_context.ts | 1 + src/public/app/widgets/touch_bar.ts | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/public/app/components/app_context.ts b/src/public/app/components/app_context.ts index 3e1535393..e93994fd5 100644 --- a/src/public/app/components/app_context.ts +++ b/src/public/app/components/app_context.ts @@ -241,6 +241,7 @@ export type CommandMappings = { scrollToEnd: CommandData; closeThisNoteSplit: CommandData; moveThisNoteSplit: CommandData & { isMovingLeft: boolean }; + jumpToNote: CommandData; // Geomap deleteFromMap: { noteId: string }; diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/widgets/touch_bar.ts index 7103c1988..e9a7c3d4e 100644 --- a/src/public/app/widgets/touch_bar.ts +++ b/src/public/app/widgets/touch_bar.ts @@ -57,7 +57,7 @@ export default class TouchBarWidget extends Component { icon: this.#buildIcon("NSTouchBarComposeTemplate"), click: () => this.triggerCommand("createNoteIntoInbox") }), - new TouchBarSpacer({ }), + new TouchBarSpacer({ size: "flexible" }), new TouchBarGroup({ items: new TouchBar({ items: [ @@ -75,6 +75,11 @@ export default class TouchBarWidget extends Component { }) ] }) + }), + new TouchBarSpacer({ size: "flexible" }), + new TouchBarButton({ + icon: this.#buildIcon("NSTouchBarAddDetailTemplate"), + click: () => this.triggerCommand("jumpToNote") }) ]; From 26765963841961e521d2aea2f2c5a060ee1f114c Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 13:16:38 +0200 Subject: [PATCH 08/43] feat(touch_bar): reduce items moving around --- src/public/app/widgets/touch_bar.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/widgets/touch_bar.ts index e9a7c3d4e..be73ab85b 100644 --- a/src/public/app/widgets/touch_bar.ts +++ b/src/public/app/widgets/touch_bar.ts @@ -50,14 +50,14 @@ export default class TouchBarWidget extends Component { #buildTouchBar() { const { TouchBar } = this.remote; - const { TouchBarButton, TouchBarSpacer, TouchBarGroup } = this.remote.TouchBar; + const { TouchBarButton, TouchBarSpacer, TouchBarGroup, TouchBarOtherItemsProxy } = this.remote.TouchBar; const items = [ new TouchBarButton({ icon: this.#buildIcon("NSTouchBarComposeTemplate"), click: () => this.triggerCommand("createNoteIntoInbox") }), - new TouchBarSpacer({ size: "flexible" }), + new TouchBarSpacer({ size: "large" }), new TouchBarGroup({ items: new TouchBar({ items: [ @@ -76,6 +76,7 @@ export default class TouchBarWidget extends Component { ] }) }), + new TouchBarOtherItemsProxy(), new TouchBarSpacer({ size: "flexible" }), new TouchBarButton({ icon: this.#buildIcon("NSTouchBarAddDetailTemplate"), From 60859954b96dfdcd4c1d0d1a5b2bbdeeed8c98ca Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 13:22:24 +0200 Subject: [PATCH 09/43] feat(touch_bar): paragraph and heading buttons --- src/public/app/widgets/touch_bar.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/widgets/touch_bar.ts index be73ab85b..2ef520426 100644 --- a/src/public/app/widgets/touch_bar.ts +++ b/src/public/app/widgets/touch_bar.ts @@ -38,14 +38,14 @@ export default class TouchBarWidget extends Component { return newImage; } - async #triggerTextEditorCommand(command: string) { + async #triggerTextEditorCommand(command: string, args?: object) { const editor = await appContext.tabManager.getActiveContext().getTextEditor(); if (!editor) { return; } // TODO: Fix type of editor. - (editor as any).execute(command); + (editor as any).execute(command, args); } #buildTouchBar() { @@ -61,6 +61,18 @@ export default class TouchBarWidget extends Component { new TouchBarGroup({ items: new TouchBar({ items: [ + new TouchBarButton({ + label: "P", + click: () => this.#triggerTextEditorCommand("paragraph") + }), + new TouchBarButton({ + label: "H2", + click: () => this.#triggerTextEditorCommand("heading", { value: "heading2" }) + }), + new TouchBarButton({ + label: "H3", + click: () => this.#triggerTextEditorCommand("heading", { value: "heading3" }) + }), new TouchBarButton({ icon: this.#buildIcon("NSTouchBarTextBoldTemplate"), click: () => this.#triggerTextEditorCommand("bold") From 214674cf73b78033590897e62f602c218d3af5ab Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 13:26:08 +0200 Subject: [PATCH 10/43] feat(touch_bar): use segmented control for heading --- src/public/app/widgets/touch_bar.ts | 60 ++++++++++++++++------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/widgets/touch_bar.ts index 2ef520426..61166a6fc 100644 --- a/src/public/app/widgets/touch_bar.ts +++ b/src/public/app/widgets/touch_bar.ts @@ -2,6 +2,16 @@ import utils from "../services/utils.js"; import Component from "../components/component.js"; import appContext from "../components/app_context.js"; +async function triggerTextEditorCommand(command: string, args?: object) { + const editor = await appContext.tabManager.getActiveContext().getTextEditor(); + if (!editor) { + return; + } + + // TODO: Fix type of editor. + (editor as any).execute(command, args); +} + export default class TouchBarWidget extends Component { nativeImage: typeof import("electron").nativeImage; @@ -38,19 +48,9 @@ export default class TouchBarWidget extends Component { return newImage; } - async #triggerTextEditorCommand(command: string, args?: object) { - const editor = await appContext.tabManager.getActiveContext().getTextEditor(); - if (!editor) { - return; - } - - // TODO: Fix type of editor. - (editor as any).execute(command, args); - } - #buildTouchBar() { const { TouchBar } = this.remote; - const { TouchBarButton, TouchBarSpacer, TouchBarGroup, TouchBarOtherItemsProxy } = this.remote.TouchBar; + const { TouchBarButton, TouchBarSpacer, TouchBarGroup, TouchBarSegmentedControl, TouchBarOtherItemsProxy } = this.remote.TouchBar; const items = [ new TouchBarButton({ @@ -58,32 +58,40 @@ export default class TouchBarWidget extends Component { click: () => this.triggerCommand("createNoteIntoInbox") }), new TouchBarSpacer({ size: "large" }), + new TouchBarSegmentedControl({ + segments: [ + { label: "P" }, + { label: "H2" }, + { label: "H3" } + ], + change(selectedIndex, isSelected) { + switch (selectedIndex) { + case 0: + triggerTextEditorCommand("paragraph") + break; + case 1: + triggerTextEditorCommand("heading", { value: "heading2" }); + break; + case 2: + triggerTextEditorCommand("heading", { value: "heading3" }); + break; + } + }, + }), new TouchBarGroup({ items: new TouchBar({ items: [ - new TouchBarButton({ - label: "P", - click: () => this.#triggerTextEditorCommand("paragraph") - }), - new TouchBarButton({ - label: "H2", - click: () => this.#triggerTextEditorCommand("heading", { value: "heading2" }) - }), - new TouchBarButton({ - label: "H3", - click: () => this.#triggerTextEditorCommand("heading", { value: "heading3" }) - }), new TouchBarButton({ icon: this.#buildIcon("NSTouchBarTextBoldTemplate"), - click: () => this.#triggerTextEditorCommand("bold") + click: () => triggerTextEditorCommand("bold") }), new TouchBarButton({ icon: this.#buildIcon("NSTouchBarTextItalicTemplate"), - click: () => this.#triggerTextEditorCommand("italic") + click: () => triggerTextEditorCommand("italic") }), new TouchBarButton({ icon: this.#buildIcon("NSTouchBarTextUnderlineTemplate"), - click: () => this.#triggerTextEditorCommand("underline") + click: () => triggerTextEditorCommand("underline") }) ] }) From db8d47183d64a9f385503ed478fdab2a499bb006 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 22:00:29 +0200 Subject: [PATCH 11/43] refactor(touch_bar): command-driven approach --- src/public/app/components/app_context.ts | 12 +-- src/public/app/layouts/desktop_layout.js | 2 + src/public/app/widgets/touch_bar.ts | 78 +++++++------------ .../app/widgets/type_widgets/editable_text.js | 45 +++++++++++ 4 files changed, 82 insertions(+), 55 deletions(-) diff --git a/src/public/app/components/app_context.ts b/src/public/app/components/app_context.ts index e93994fd5..8b5b7eb7c 100644 --- a/src/public/app/components/app_context.ts +++ b/src/public/app/components/app_context.ts @@ -22,10 +22,9 @@ import type LoadResults from "../services/load_results.js"; import type { Attribute } from "../services/attribute_parser.js"; import type NoteTreeWidget from "../widgets/note_tree.js"; import type { default as NoteContext, GetTextEditorCallback } from "./note_context.js"; -import type { ContextMenuEvent } from "../menus/context_menu.js"; import type TypeWidget from "../widgets/type_widgets/type_widget.js"; import type EditableTextTypeWidget from "../widgets/type_widgets/editable_text.js"; -import TouchBarWidget from "../widgets/touch_bar.js"; +import type { NativeImage } from "electron"; interface Layout { getRootWidget: (appContext: AppContext) => RootWidget; @@ -256,6 +255,11 @@ export type CommandMappings = { refreshResults: {}; refreshSearchDefinition: {}; + + buildTouchBar: CommandData & { + TouchBar: typeof import("electron").TouchBar; + buildIcon(name: string): NativeImage; + }; }; type EventMappings = { @@ -448,10 +452,6 @@ class AppContext extends Component { this.components = [this.tabManager, new RootCommandExecutor(), new Entrypoints(), new MainTreeExecutors(), new ShortcutComponent()]; - if (utils.isElectron() && utils.isMac()) { - this.components.push(new TouchBarWidget()); - } - if (utils.isMobile()) { this.components.push(new MobileScreenSwitcherExecutor()); } diff --git a/src/public/app/layouts/desktop_layout.js b/src/public/app/layouts/desktop_layout.js index ecb97fe5f..f5b3dc2eb 100644 --- a/src/public/app/layouts/desktop_layout.js +++ b/src/public/app/layouts/desktop_layout.js @@ -88,6 +88,7 @@ import utils from "../services/utils.js"; import GeoMapButtons from "../widgets/floating_buttons/geo_map_button.js"; import ContextualHelpButton from "../widgets/floating_buttons/help_button.js"; import CloseZenButton from "../widgets/close_zen_button.js"; +import TouchBarWidget from "../widgets/touch_bar.js"; export default class DesktopLayout { constructor(customWidgets) { @@ -153,6 +154,7 @@ export default class DesktopLayout { .filling() .collapsible() .id("center-pane") + .child(new TouchBarWidget()) .child( new SplitNoteContainer(() => new NoteWrapperWidget() diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/widgets/touch_bar.ts index 61166a6fc..534de0ded 100644 --- a/src/public/app/widgets/touch_bar.ts +++ b/src/public/app/widgets/touch_bar.ts @@ -1,6 +1,8 @@ import utils from "../services/utils.js"; import Component from "../components/component.js"; import appContext from "../components/app_context.js"; +import NoteContextAwareWidget from "./note_context_aware_widget.js"; +import type FNote from "../entities/fnote.js"; async function triggerTextEditorCommand(command: string, args?: object) { const editor = await appContext.tabManager.getActiveContext().getTextEditor(); @@ -12,7 +14,7 @@ async function triggerTextEditorCommand(command: string, args?: object) { (editor as any).execute(command, args); } -export default class TouchBarWidget extends Component { +export default class TouchBarWidget extends NoteContextAwareWidget { nativeImage: typeof import("electron").nativeImage; remote: typeof import("@electron/remote"); @@ -21,15 +23,30 @@ export default class TouchBarWidget extends Component { super(); this.nativeImage = utils.dynamicRequire("electron").nativeImage; this.remote = utils.dynamicRequire("@electron/remote") as typeof import("@electron/remote"); - this.#setTouchBar(); + this.$widget = $("
"); + + $(window).on("focusin", async (e) => { + const target = e.target; + const parentComponentEl = $(target).closest(".component"); + // TODO: Remove typecast once it's no longer necessary. + const parentComponent = appContext.getComponentByEl(parentComponentEl[0]) as Component; + const { TouchBar } = this.remote; + if (!parentComponent) { + return; + } + + const result = parentComponent.triggerCommand("buildTouchBar", { + TouchBar, + buildIcon: this.buildIcon.bind(this) + }); + + if (result) { + this.remote.getCurrentWindow().setTouchBar(result); + } + }); } - #setTouchBar() { - const touchBarData = this.#buildTouchBar(); - this.remote.getCurrentWindow().setTouchBar(touchBarData); - } - - #buildIcon(name: string) { + buildIcon(name: string) { const sourceImage = this.nativeImage.createFromNamedImage(name, [-1, 0, 1]); const { width, height } = sourceImage.getSize(); const newImage = this.nativeImage.createEmpty(); @@ -48,58 +65,21 @@ export default class TouchBarWidget extends Component { return newImage; } - #buildTouchBar() { + #buildTextTouchBar() { const { TouchBar } = this.remote; const { TouchBarButton, TouchBarSpacer, TouchBarGroup, TouchBarSegmentedControl, TouchBarOtherItemsProxy } = this.remote.TouchBar; const items = [ new TouchBarButton({ - icon: this.#buildIcon("NSTouchBarComposeTemplate"), + icon: this.buildIcon("NSTouchBarComposeTemplate"), click: () => this.triggerCommand("createNoteIntoInbox") }), new TouchBarSpacer({ size: "large" }), - new TouchBarSegmentedControl({ - segments: [ - { label: "P" }, - { label: "H2" }, - { label: "H3" } - ], - change(selectedIndex, isSelected) { - switch (selectedIndex) { - case 0: - triggerTextEditorCommand("paragraph") - break; - case 1: - triggerTextEditorCommand("heading", { value: "heading2" }); - break; - case 2: - triggerTextEditorCommand("heading", { value: "heading3" }); - break; - } - }, - }), - new TouchBarGroup({ - items: new TouchBar({ - items: [ - new TouchBarButton({ - icon: this.#buildIcon("NSTouchBarTextBoldTemplate"), - click: () => triggerTextEditorCommand("bold") - }), - new TouchBarButton({ - icon: this.#buildIcon("NSTouchBarTextItalicTemplate"), - click: () => triggerTextEditorCommand("italic") - }), - new TouchBarButton({ - icon: this.#buildIcon("NSTouchBarTextUnderlineTemplate"), - click: () => triggerTextEditorCommand("underline") - }) - ] - }) - }), + // data should go here new TouchBarOtherItemsProxy(), new TouchBarSpacer({ size: "flexible" }), new TouchBarButton({ - icon: this.#buildIcon("NSTouchBarAddDetailTemplate"), + icon: this.buildIcon("NSTouchBarAddDetailTemplate"), click: () => this.triggerCommand("jumpToNote") }) ]; diff --git a/src/public/app/widgets/type_widgets/editable_text.js b/src/public/app/widgets/type_widgets/editable_text.js index 9ac5f1b56..c950a562b 100644 --- a/src/public/app/widgets/type_widgets/editable_text.js +++ b/src/public/app/widgets/type_widgets/editable_text.js @@ -507,4 +507,49 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { await this.reinitialize(data); } + buildTouchBarCommand(data) { + const { TouchBar, buildIcon } = data; + const { TouchBarSegmentedControl, TouchBarGroup, TouchBarButton } = TouchBar; + return [ + new TouchBarSegmentedControl({ + segments: [ + { label: "P" }, + { label: "H2" }, + { label: "H3" } + ], + change(selectedIndex, isSelected) { + switch (selectedIndex) { + case 0: + triggerTextEditorCommand("paragraph") + break; + case 1: + triggerTextEditorCommand("heading", { value: "heading2" }); + break; + case 2: + triggerTextEditorCommand("heading", { value: "heading3" }); + break; + } + }, + }), + new TouchBarGroup({ + items: new TouchBar({ + items: [ + new TouchBarButton({ + icon: buildIcon("NSTouchBarTextBoldTemplate"), + click: () => triggerTextEditorCommand("bold") + }), + new TouchBarButton({ + icon: buildIcon("NSTouchBarTextItalicTemplate"), + click: () => triggerTextEditorCommand("italic") + }), + new TouchBarButton({ + icon: buildIcon("NSTouchBarTextUnderlineTemplate"), + click: () => triggerTextEditorCommand("underline") + }) + ] + }) + }) + ]; + } + } From c2e4af1cfa00b95353e98c78d427ad39bf98f556 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 22:14:20 +0200 Subject: [PATCH 12/43] chore(touch_bar): bring back local config --- src/public/app/widgets/touch_bar.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/widgets/touch_bar.ts index 534de0ded..38235a51d 100644 --- a/src/public/app/widgets/touch_bar.ts +++ b/src/public/app/widgets/touch_bar.ts @@ -3,6 +3,7 @@ import Component from "../components/component.js"; import appContext from "../components/app_context.js"; import NoteContextAwareWidget from "./note_context_aware_widget.js"; import type FNote from "../entities/fnote.js"; +import type { TouchBarButton, TouchBarGroup, TouchBarSegmentedControl, TouchBarSpacer } from "@electron/remote"; async function triggerTextEditorCommand(command: string, args?: object) { const editor = await appContext.tabManager.getActiveContext().getTextEditor(); @@ -35,14 +36,13 @@ export default class TouchBarWidget extends NoteContextAwareWidget { return; } - const result = parentComponent.triggerCommand("buildTouchBar", { + let result = parentComponent.triggerCommand("buildTouchBar", { TouchBar, buildIcon: this.buildIcon.bind(this) }); - if (result) { - this.remote.getCurrentWindow().setTouchBar(result); - } + const touchBar = this.#buildTouchBar(result); + this.remote.getCurrentWindow().setTouchBar(touchBar); }); } @@ -65,24 +65,29 @@ export default class TouchBarWidget extends NoteContextAwareWidget { return newImage; } - #buildTextTouchBar() { + #buildTouchBar(componentSpecificItems?: (TouchBarButton | TouchBarSpacer | TouchBarGroup | TouchBarSegmentedControl)[]) { const { TouchBar } = this.remote; const { TouchBarButton, TouchBarSpacer, TouchBarGroup, TouchBarSegmentedControl, TouchBarOtherItemsProxy } = this.remote.TouchBar; + // Disregard recursive calls or empty results. + if (!componentSpecificItems || "then" in componentSpecificItems) { + componentSpecificItems = []; + } + const items = [ new TouchBarButton({ icon: this.buildIcon("NSTouchBarComposeTemplate"), click: () => this.triggerCommand("createNoteIntoInbox") }), new TouchBarSpacer({ size: "large" }), - // data should go here + ...componentSpecificItems, new TouchBarOtherItemsProxy(), new TouchBarSpacer({ size: "flexible" }), new TouchBarButton({ icon: this.buildIcon("NSTouchBarAddDetailTemplate"), click: () => this.triggerCommand("jumpToNote") }) - ]; + ].flat(); console.log("Update ", items); return new TouchBar({ From 0fe5f79f09fc9bc9d3e67c6d44a62327a0eee9bd Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 22:18:03 +0200 Subject: [PATCH 13/43] fix(touch_bar): fix text editor commands --- src/public/app/widgets/touch_bar.ts | 11 ----------- .../app/widgets/type_widgets/editable_text.js | 14 ++++++++------ 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/widgets/touch_bar.ts index 38235a51d..7f7ef10d5 100644 --- a/src/public/app/widgets/touch_bar.ts +++ b/src/public/app/widgets/touch_bar.ts @@ -2,19 +2,8 @@ import utils from "../services/utils.js"; import Component from "../components/component.js"; import appContext from "../components/app_context.js"; import NoteContextAwareWidget from "./note_context_aware_widget.js"; -import type FNote from "../entities/fnote.js"; import type { TouchBarButton, TouchBarGroup, TouchBarSegmentedControl, TouchBarSpacer } from "@electron/remote"; -async function triggerTextEditorCommand(command: string, args?: object) { - const editor = await appContext.tabManager.getActiveContext().getTextEditor(); - if (!editor) { - return; - } - - // TODO: Fix type of editor. - (editor as any).execute(command, args); -} - export default class TouchBarWidget extends NoteContextAwareWidget { nativeImage: typeof import("electron").nativeImage; diff --git a/src/public/app/widgets/type_widgets/editable_text.js b/src/public/app/widgets/type_widgets/editable_text.js index c950a562b..a6efbbe11 100644 --- a/src/public/app/widgets/type_widgets/editable_text.js +++ b/src/public/app/widgets/type_widgets/editable_text.js @@ -510,6 +510,8 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { buildTouchBarCommand(data) { const { TouchBar, buildIcon } = data; const { TouchBarSegmentedControl, TouchBarGroup, TouchBarButton } = TouchBar; + const { editor } = this.watchdog; + return [ new TouchBarSegmentedControl({ segments: [ @@ -520,13 +522,13 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { change(selectedIndex, isSelected) { switch (selectedIndex) { case 0: - triggerTextEditorCommand("paragraph") + editor.execute("paragraph") break; case 1: - triggerTextEditorCommand("heading", { value: "heading2" }); + editor.execute("heading", { value: "heading2" }); break; case 2: - triggerTextEditorCommand("heading", { value: "heading3" }); + editor.execute("heading", { value: "heading3" }); break; } }, @@ -536,15 +538,15 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { items: [ new TouchBarButton({ icon: buildIcon("NSTouchBarTextBoldTemplate"), - click: () => triggerTextEditorCommand("bold") + click: () => editor.execute("bold") }), new TouchBarButton({ icon: buildIcon("NSTouchBarTextItalicTemplate"), - click: () => triggerTextEditorCommand("italic") + click: () => editor.execute("italic") }), new TouchBarButton({ icon: buildIcon("NSTouchBarTextUnderlineTemplate"), - click: () => triggerTextEditorCommand("underline") + click: () => editor.execute("underline") }) ] }) From 36eac98b4d5bf96de6d5d9cc9bce8b99dc906c5e Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 22:35:36 +0200 Subject: [PATCH 14/43] feat(touch_bar): zoom slider --- src/public/app/widgets/geo_map.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/public/app/widgets/geo_map.ts b/src/public/app/widgets/geo_map.ts index fabefcdc9..eef72a748 100644 --- a/src/public/app/widgets/geo_map.ts +++ b/src/public/app/widgets/geo_map.ts @@ -1,6 +1,7 @@ import type { Map } from "leaflet"; import library_loader from "../services/library_loader.js"; import NoteContextAwareWidget from "./note_context_aware_widget.js"; +import type { CommandListenerData } from "../components/app_context.js"; const TPL = `\
@@ -59,4 +60,22 @@ export default class GeoMapWidget extends NoteContextAwareWidget { }); } + buildTouchBarCommand({ TouchBar }: CommandListenerData<"buildTouchBar">) { + const map = this.map; + if (!map) { + return; + } + + return [ + new TouchBar.TouchBarSlider({ + label: "Zoom", + minValue: map.getMinZoom(), + maxValue: map.getMaxZoom(), + change(newValue) { + map.setZoom(newValue); + }, + }) + ]; + } + } From ece26960c338c44bf6ee2edd9edd56492c4fb5b1 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 22:46:14 +0200 Subject: [PATCH 15/43] feat(touch_bar): update zoom slider value --- src/public/app/components/app_context.ts | 1 + src/public/app/widgets/geo_map.ts | 3 ++ src/public/app/widgets/touch_bar.ts | 36 +++++++++++++++--------- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/public/app/components/app_context.ts b/src/public/app/components/app_context.ts index 8b5b7eb7c..5861894d1 100644 --- a/src/public/app/components/app_context.ts +++ b/src/public/app/components/app_context.ts @@ -260,6 +260,7 @@ export type CommandMappings = { TouchBar: typeof import("electron").TouchBar; buildIcon(name: string): NativeImage; }; + refreshTouchBar: CommandData; }; type EventMappings = { diff --git a/src/public/app/widgets/geo_map.ts b/src/public/app/widgets/geo_map.ts index eef72a748..b0a37d2b8 100644 --- a/src/public/app/widgets/geo_map.ts +++ b/src/public/app/widgets/geo_map.ts @@ -53,6 +53,8 @@ export default class GeoMapWidget extends NoteContextAwareWidget { this.initCallback(L); } + map.addEventListener("zoom", () => this.triggerCommand("refreshTouchBar")); + L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", { attribution: '© OpenStreetMap contributors', detectRetina: true @@ -69,6 +71,7 @@ export default class GeoMapWidget extends NoteContextAwareWidget { return [ new TouchBar.TouchBarSlider({ label: "Zoom", + value: map.getZoom(), minValue: map.getMinZoom(), maxValue: map.getMaxZoom(), change(newValue) { diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/widgets/touch_bar.ts index 7f7ef10d5..25db457c3 100644 --- a/src/public/app/widgets/touch_bar.ts +++ b/src/public/app/widgets/touch_bar.ts @@ -8,6 +8,7 @@ export default class TouchBarWidget extends NoteContextAwareWidget { nativeImage: typeof import("electron").nativeImage; remote: typeof import("@electron/remote"); + lastFocusedComponent?: Component; constructor() { super(); @@ -19,19 +20,8 @@ export default class TouchBarWidget extends NoteContextAwareWidget { const target = e.target; const parentComponentEl = $(target).closest(".component"); // TODO: Remove typecast once it's no longer necessary. - const parentComponent = appContext.getComponentByEl(parentComponentEl[0]) as Component; - const { TouchBar } = this.remote; - if (!parentComponent) { - return; - } - - let result = parentComponent.triggerCommand("buildTouchBar", { - TouchBar, - buildIcon: this.buildIcon.bind(this) - }); - - const touchBar = this.#buildTouchBar(result); - this.remote.getCurrentWindow().setTouchBar(touchBar); + this.lastFocusedComponent = appContext.getComponentByEl(parentComponentEl[0]) as Component; + this.#refreshTouchBar(); }); } @@ -54,6 +44,22 @@ export default class TouchBarWidget extends NoteContextAwareWidget { return newImage; } + #refreshTouchBar() { + const { TouchBar } = this.remote; + const parentComponent = this.lastFocusedComponent; + if (!parentComponent) { + return; + } + + let result = parentComponent.triggerCommand("buildTouchBar", { + TouchBar, + buildIcon: this.buildIcon.bind(this) + }); + + const touchBar = this.#buildTouchBar(result); + this.remote.getCurrentWindow().setTouchBar(touchBar); + } + #buildTouchBar(componentSpecificItems?: (TouchBarButton | TouchBarSpacer | TouchBarGroup | TouchBarSegmentedControl)[]) { const { TouchBar } = this.remote; const { TouchBarButton, TouchBarSpacer, TouchBarGroup, TouchBarSegmentedControl, TouchBarOtherItemsProxy } = this.remote.TouchBar; @@ -84,4 +90,8 @@ export default class TouchBarWidget extends NoteContextAwareWidget { }); } + refreshTouchBarEvent() { + this.#refreshTouchBar(); + } + } From 5961e983c73420be2e4a3b696a2dcf21e906c776 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 22:56:32 +0200 Subject: [PATCH 16/43] feat(touch_bar): new geonote button --- src/public/app/components/app_context.ts | 5 ++--- src/public/app/widgets/geo_map.ts | 4 ++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/public/app/components/app_context.ts b/src/public/app/components/app_context.ts index 5861894d1..f863274aa 100644 --- a/src/public/app/components/app_context.ts +++ b/src/public/app/components/app_context.ts @@ -256,6 +256,8 @@ export type CommandMappings = { refreshResults: {}; refreshSearchDefinition: {}; + geoMapCreateChildNote: CommandData; + buildTouchBar: CommandData & { TouchBar: typeof import("electron").TouchBar; buildIcon(name: string): NativeImage; @@ -356,9 +358,6 @@ type EventMappings = { exportSvg: { ntxId: string | null | undefined; }; - geoMapCreateChildNote: { - ntxId: string | null | undefined; // TODO: deduplicate ntxId - }; tabReorder: { ntxIdsInOrder: string[]; }; diff --git a/src/public/app/widgets/geo_map.ts b/src/public/app/widgets/geo_map.ts index b0a37d2b8..76ff7d0eb 100644 --- a/src/public/app/widgets/geo_map.ts +++ b/src/public/app/widgets/geo_map.ts @@ -77,6 +77,10 @@ export default class GeoMapWidget extends NoteContextAwareWidget { change(newValue) { map.setZoom(newValue); }, + }), + new TouchBar.TouchBarButton({ + label: "New geo note", + click: () => this.parent?.triggerEvent("geoMapCreateChildNote", { ntxId: this.ntxId }) }) ]; } From 323f42873f10748bf6bb5c3b046774c01b3d9722 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 23:00:05 +0200 Subject: [PATCH 17/43] refactor(touch_bar): move geomap to parent typewidget --- src/public/app/widgets/geo_map.ts | 24 ------------------ .../app/widgets/type_widgets/geo_map.ts | 25 ++++++++++++++++++- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/public/app/widgets/geo_map.ts b/src/public/app/widgets/geo_map.ts index 76ff7d0eb..b9f14c3ef 100644 --- a/src/public/app/widgets/geo_map.ts +++ b/src/public/app/widgets/geo_map.ts @@ -1,7 +1,6 @@ import type { Map } from "leaflet"; import library_loader from "../services/library_loader.js"; import NoteContextAwareWidget from "./note_context_aware_widget.js"; -import type { CommandListenerData } from "../components/app_context.js"; const TPL = `\
@@ -62,27 +61,4 @@ export default class GeoMapWidget extends NoteContextAwareWidget { }); } - buildTouchBarCommand({ TouchBar }: CommandListenerData<"buildTouchBar">) { - const map = this.map; - if (!map) { - return; - } - - return [ - new TouchBar.TouchBarSlider({ - label: "Zoom", - value: map.getZoom(), - minValue: map.getMinZoom(), - maxValue: map.getMaxZoom(), - change(newValue) { - map.setZoom(newValue); - }, - }), - new TouchBar.TouchBarButton({ - label: "New geo note", - click: () => this.parent?.triggerEvent("geoMapCreateChildNote", { ntxId: this.ntxId }) - }) - ]; - } - } diff --git a/src/public/app/widgets/type_widgets/geo_map.ts b/src/public/app/widgets/type_widgets/geo_map.ts index dddccbac8..9c86bbf48 100644 --- a/src/public/app/widgets/type_widgets/geo_map.ts +++ b/src/public/app/widgets/type_widgets/geo_map.ts @@ -5,7 +5,7 @@ import TypeWidget from "./type_widget.js"; import server from "../../services/server.js"; import toastService from "../../services/toast.js"; import dialogService from "../../services/dialog.js"; -import type { EventData } from "../../components/app_context.js"; +import type { CommandListenerData, EventData } from "../../components/app_context.js"; import { t } from "../../services/i18n.js"; import attributes from "../../services/attributes.js"; import asset_path from "../../../../services/asset_path.js"; @@ -381,4 +381,27 @@ export default class GeoMapTypeWidget extends TypeWidget { this.moveMarker(noteId, null); } + buildTouchBarCommand({ TouchBar }: CommandListenerData<"buildTouchBar">) { + const map = this.geoMapWidget.map; + if (!map) { + return; + } + + return [ + new TouchBar.TouchBarSlider({ + label: "Zoom", + value: map.getZoom(), + minValue: map.getMinZoom(), + maxValue: map.getMaxZoom(), + change(newValue) { + map.setZoom(newValue); + }, + }), + new TouchBar.TouchBarButton({ + label: "New geo note", + click: () => this.triggerCommand("geoMapCreateChildNote", { ntxId: this.ntxId }) + }) + ]; + } + } From cbbe10ba677dc48335d3274a7d7e8940a6dfa700 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 23:13:58 +0200 Subject: [PATCH 18/43] fix(touch_bar): jerkiness when zooming --- src/public/app/widgets/geo_map.ts | 2 -- src/public/app/widgets/type_widgets/geo_map.ts | 10 ++++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/public/app/widgets/geo_map.ts b/src/public/app/widgets/geo_map.ts index b9f14c3ef..fabefcdc9 100644 --- a/src/public/app/widgets/geo_map.ts +++ b/src/public/app/widgets/geo_map.ts @@ -52,8 +52,6 @@ export default class GeoMapWidget extends NoteContextAwareWidget { this.initCallback(L); } - map.addEventListener("zoom", () => this.triggerCommand("refreshTouchBar")); - L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", { attribution: '© OpenStreetMap contributors', detectRetina: true diff --git a/src/public/app/widgets/type_widgets/geo_map.ts b/src/public/app/widgets/type_widgets/geo_map.ts index 9c86bbf48..b68b2c09c 100644 --- a/src/public/app/widgets/type_widgets/geo_map.ts +++ b/src/public/app/widgets/type_widgets/geo_map.ts @@ -105,6 +105,7 @@ export default class GeoMapTypeWidget extends TypeWidget { private currentMarkerData: Record; private currentTrackData: Record; private gpxLoaded?: boolean; + private ignoreNextZoomEvent?: boolean; static getType() { return "geoMap"; @@ -144,6 +145,13 @@ export default class GeoMapTypeWidget extends TypeWidget { map.on("moveend", updateFn); map.on("zoomend", updateFn); map.on("click", (e) => this.#onMapClicked(e)); + map.on("zoom", () => { + if (!this.ignoreNextZoomEvent) { + this.triggerCommand("refreshTouchBar"); + } + + this.ignoreNextZoomEvent = false; + }); } async #restoreViewportAndZoom() { @@ -383,6 +391,7 @@ export default class GeoMapTypeWidget extends TypeWidget { buildTouchBarCommand({ TouchBar }: CommandListenerData<"buildTouchBar">) { const map = this.geoMapWidget.map; + const that = this; if (!map) { return; } @@ -394,6 +403,7 @@ export default class GeoMapTypeWidget extends TypeWidget { minValue: map.getMinZoom(), maxValue: map.getMaxZoom(), change(newValue) { + that.ignoreNextZoomEvent = true; map.setZoom(newValue); }, }), From a3c58834d1f7bf5715eda84fb9c3248aab29627f Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 23:21:13 +0200 Subject: [PATCH 19/43] feat(touch_bar): reflect new note state --- .../app/widgets/type_widgets/geo_map.ts | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/public/app/widgets/type_widgets/geo_map.ts b/src/public/app/widgets/type_widgets/geo_map.ts index b68b2c09c..5ada5c7f5 100644 --- a/src/public/app/widgets/type_widgets/geo_map.ts +++ b/src/public/app/widgets/type_widgets/geo_map.ts @@ -280,6 +280,7 @@ export default class GeoMapTypeWidget extends TypeWidget { #changeState(newState: State) { this._state = newState; this.geoMapWidget.$container.toggleClass("placing-note", newState === State.NewNote); + this.triggerCommand("refreshTouchBar"); } async #onMapClicked(e: LeafletMouseEvent) { @@ -396,22 +397,31 @@ export default class GeoMapTypeWidget extends TypeWidget { return; } - return [ - new TouchBar.TouchBarSlider({ - label: "Zoom", - value: map.getZoom(), - minValue: map.getMinZoom(), - maxValue: map.getMaxZoom(), - change(newValue) { - that.ignoreNextZoomEvent = true; - map.setZoom(newValue); - }, - }), - new TouchBar.TouchBarButton({ - label: "New geo note", - click: () => this.triggerCommand("geoMapCreateChildNote", { ntxId: this.ntxId }) - }) - ]; + switch (this._state) { + case State.Normal: + return [ + new TouchBar.TouchBarSlider({ + label: "Zoom", + value: map.getZoom(), + minValue: map.getMinZoom(), + maxValue: map.getMaxZoom(), + change(newValue) { + that.ignoreNextZoomEvent = true; + map.setZoom(newValue); + }, + }), + new TouchBar.TouchBarButton({ + label: "New geo note", + click: () => this.triggerCommand("geoMapCreateChildNote", { ntxId: this.ntxId }) + }) + ]; + + case State.NewNote: + return [ + new TouchBar.TouchBarSpacer({ size: "flexible" }), + new TouchBar.TouchBarLabel({ label: "New note" }) + ] + } } } From ff78ab650af813350e8f0d1e8d078acce5e95d7f Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 8 Mar 2025 23:25:06 +0200 Subject: [PATCH 20/43] feat(touch_bar): use disabled button for geomap --- .../app/widgets/type_widgets/geo_map.ts | 42 ++++++++----------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/src/public/app/widgets/type_widgets/geo_map.ts b/src/public/app/widgets/type_widgets/geo_map.ts index 5ada5c7f5..6b478f130 100644 --- a/src/public/app/widgets/type_widgets/geo_map.ts +++ b/src/public/app/widgets/type_widgets/geo_map.ts @@ -397,31 +397,23 @@ export default class GeoMapTypeWidget extends TypeWidget { return; } - switch (this._state) { - case State.Normal: - return [ - new TouchBar.TouchBarSlider({ - label: "Zoom", - value: map.getZoom(), - minValue: map.getMinZoom(), - maxValue: map.getMaxZoom(), - change(newValue) { - that.ignoreNextZoomEvent = true; - map.setZoom(newValue); - }, - }), - new TouchBar.TouchBarButton({ - label: "New geo note", - click: () => this.triggerCommand("geoMapCreateChildNote", { ntxId: this.ntxId }) - }) - ]; - - case State.NewNote: - return [ - new TouchBar.TouchBarSpacer({ size: "flexible" }), - new TouchBar.TouchBarLabel({ label: "New note" }) - ] - } + return [ + new TouchBar.TouchBarSlider({ + label: "Zoom", + value: map.getZoom(), + minValue: map.getMinZoom(), + maxValue: map.getMaxZoom(), + change(newValue) { + that.ignoreNextZoomEvent = true; + map.setZoom(newValue); + }, + }), + new TouchBar.TouchBarButton({ + label: "New geo note", + click: () => this.triggerCommand("geoMapCreateChildNote", { ntxId: this.ntxId }), + enabled: (this._state === State.Normal) + }) + ]; } } From fff140d141c41cdf44014c90d3e253de2a1a928a Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 9 Mar 2025 14:28:18 +0200 Subject: [PATCH 21/43] feat(touch_bar): reflect state for bold --- src/public/app/widgets/touch_bar.ts | 4 ++++ src/public/app/widgets/type_widgets/editable_text.js | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/widgets/touch_bar.ts index 25db457c3..d3da685e2 100644 --- a/src/public/app/widgets/touch_bar.ts +++ b/src/public/app/widgets/touch_bar.ts @@ -4,6 +4,10 @@ import appContext from "../components/app_context.js"; import NoteContextAwareWidget from "./note_context_aware_widget.js"; import type { TouchBarButton, TouchBarGroup, TouchBarSegmentedControl, TouchBarSpacer } from "@electron/remote"; +export function buildSelectedBackgroundColor(isSelected: boolean) { + return isSelected ? "#ff0000" : undefined; +} + export default class TouchBarWidget extends NoteContextAwareWidget { nativeImage: typeof import("electron").nativeImage; diff --git a/src/public/app/widgets/type_widgets/editable_text.js b/src/public/app/widgets/type_widgets/editable_text.js index a6efbbe11..79e32d603 100644 --- a/src/public/app/widgets/type_widgets/editable_text.js +++ b/src/public/app/widgets/type_widgets/editable_text.js @@ -16,6 +16,7 @@ import toast from "../../services/toast.js"; import { getMermaidConfig } from "../mermaid.js"; import { normalizeMimeTypeForCKEditor } from "../../services/mime_type_definitions.js"; import { buildConfig, buildToolbarConfig } from "./ckeditor/toolbars.js"; +import { buildSelectedBackgroundColor } from "../touch_bar.js"; const ENABLE_INSPECTOR = false; @@ -250,6 +251,9 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { CKEditorInspector.attach(editor); } + // Touch bar integration + editor.commands.get("bold").on("change", () => this.triggerCommand("refreshTouchBar")); + return editor; }); @@ -538,7 +542,8 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { items: [ new TouchBarButton({ icon: buildIcon("NSTouchBarTextBoldTemplate"), - click: () => editor.execute("bold") + click: () => editor.execute("bold"), + backgroundColor: buildSelectedBackgroundColor(editor.commands.get("bold").value) }), new TouchBarButton({ icon: buildIcon("NSTouchBarTextItalicTemplate"), From e71a18f4e4ec642d28424879ddd64de2c61bb40c Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 9 Mar 2025 14:37:00 +0200 Subject: [PATCH 22/43] feat(touch_bar): reflect state for underline, italic --- .../app/widgets/type_widgets/editable_text.js | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/public/app/widgets/type_widgets/editable_text.js b/src/public/app/widgets/type_widgets/editable_text.js index 79e32d603..f8754e29a 100644 --- a/src/public/app/widgets/type_widgets/editable_text.js +++ b/src/public/app/widgets/type_widgets/editable_text.js @@ -252,7 +252,9 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { } // Touch bar integration - editor.commands.get("bold").on("change", () => this.triggerCommand("refreshTouchBar")); + for (const event of [ "bold", "italic", "underline" ]) { + editor.commands.get(event).on("change", () => this.triggerCommand("refreshTouchBar")); + } return editor; }); @@ -516,6 +518,12 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { const { TouchBarSegmentedControl, TouchBarGroup, TouchBarButton } = TouchBar; const { editor } = this.watchdog; + const commandButton = (icon, command) => new TouchBarButton({ + icon: buildIcon(icon), + click: () => editor.execute(command), + backgroundColor: buildSelectedBackgroundColor(editor.commands.get(command).value) + }); + return [ new TouchBarSegmentedControl({ segments: [ @@ -540,19 +548,9 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { new TouchBarGroup({ items: new TouchBar({ items: [ - new TouchBarButton({ - icon: buildIcon("NSTouchBarTextBoldTemplate"), - click: () => editor.execute("bold"), - backgroundColor: buildSelectedBackgroundColor(editor.commands.get("bold").value) - }), - new TouchBarButton({ - icon: buildIcon("NSTouchBarTextItalicTemplate"), - click: () => editor.execute("italic") - }), - new TouchBarButton({ - icon: buildIcon("NSTouchBarTextUnderlineTemplate"), - click: () => editor.execute("underline") - }) + commandButton("NSTouchBarTextBoldTemplate", "bold"), + commandButton("NSTouchBarTextItalicTemplate", "italic"), + commandButton("NSTouchBarTextUnderlineTemplate", "underline") ] }) }) From 07c9565e0c5767fbffbc671d1b83aeea41013c0c Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 9 Mar 2025 14:42:23 +0200 Subject: [PATCH 23/43] feat(touch_bar): reflect state for paragraph and headings --- .../app/widgets/type_widgets/editable_text.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/public/app/widgets/type_widgets/editable_text.js b/src/public/app/widgets/type_widgets/editable_text.js index f8754e29a..dfcf63e5b 100644 --- a/src/public/app/widgets/type_widgets/editable_text.js +++ b/src/public/app/widgets/type_widgets/editable_text.js @@ -252,7 +252,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { } // Touch bar integration - for (const event of [ "bold", "italic", "underline" ]) { + for (const event of [ "bold", "italic", "underline", "paragraph", "heading" ]) { editor.commands.get(event).on("change", () => this.triggerCommand("refreshTouchBar")); } @@ -524,6 +524,17 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { backgroundColor: buildSelectedBackgroundColor(editor.commands.get(command).value) }); + let headingSelectedIndex = undefined; + const headingCommand = editor.commands.get("heading"); + const paragraphCommand = editor.commands.get("paragraph"); + if (paragraphCommand.value) { + headingSelectedIndex = 0; + } else if (headingCommand.value === "heading2") { + headingSelectedIndex = 1; + } else if (headingCommand.value === "heading3") { + headingSelectedIndex = 2; + } + return [ new TouchBarSegmentedControl({ segments: [ @@ -544,6 +555,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { break; } }, + selectedIndex: headingSelectedIndex }), new TouchBarGroup({ items: new TouchBar({ From 615a5f72226c974fa51b5125241584b7536cb122 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 9 Mar 2025 14:58:43 +0200 Subject: [PATCH 24/43] feat(touch_bar): change selected color --- src/public/app/widgets/touch_bar.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/widgets/touch_bar.ts index d3da685e2..9e3a80234 100644 --- a/src/public/app/widgets/touch_bar.ts +++ b/src/public/app/widgets/touch_bar.ts @@ -5,7 +5,7 @@ import NoteContextAwareWidget from "./note_context_aware_widget.js"; import type { TouchBarButton, TouchBarGroup, TouchBarSegmentedControl, TouchBarSpacer } from "@electron/remote"; export function buildSelectedBackgroundColor(isSelected: boolean) { - return isSelected ? "#ff0000" : undefined; + return isSelected ? "#757575" : undefined; } export default class TouchBarWidget extends NoteContextAwareWidget { From 975e641286c0c27b1c0920ecfb5a93fdb81030f6 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 9 Mar 2025 15:31:03 +0200 Subject: [PATCH 25/43] feat(touch_bar): run button for scripts --- src/public/app/widgets/touch_bar.ts | 7 +++--- .../app/widgets/type_widgets/editable_code.ts | 24 ++++++++++++++++++- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/widgets/touch_bar.ts index 9e3a80234..8ce1b0d34 100644 --- a/src/public/app/widgets/touch_bar.ts +++ b/src/public/app/widgets/touch_bar.ts @@ -4,6 +4,8 @@ import appContext from "../components/app_context.js"; import NoteContextAwareWidget from "./note_context_aware_widget.js"; import type { TouchBarButton, TouchBarGroup, TouchBarSegmentedControl, TouchBarSpacer } from "@electron/remote"; +export type TouchBarItem = (TouchBarButton | TouchBarSpacer | TouchBarGroup | TouchBarSegmentedControl); + export function buildSelectedBackgroundColor(isSelected: boolean) { return isSelected ? "#757575" : undefined; } @@ -58,13 +60,13 @@ export default class TouchBarWidget extends NoteContextAwareWidget { let result = parentComponent.triggerCommand("buildTouchBar", { TouchBar, buildIcon: this.buildIcon.bind(this) - }); + }) as unknown as TouchBarItem[]; const touchBar = this.#buildTouchBar(result); this.remote.getCurrentWindow().setTouchBar(touchBar); } - #buildTouchBar(componentSpecificItems?: (TouchBarButton | TouchBarSpacer | TouchBarGroup | TouchBarSegmentedControl)[]) { + #buildTouchBar(componentSpecificItems?: TouchBarItem[]) { const { TouchBar } = this.remote; const { TouchBarButton, TouchBarSpacer, TouchBarGroup, TouchBarSegmentedControl, TouchBarOtherItemsProxy } = this.remote.TouchBar; @@ -81,7 +83,6 @@ export default class TouchBarWidget extends NoteContextAwareWidget { new TouchBarSpacer({ size: "large" }), ...componentSpecificItems, new TouchBarOtherItemsProxy(), - new TouchBarSpacer({ size: "flexible" }), new TouchBarButton({ icon: this.buildIcon("NSTouchBarAddDetailTemplate"), click: () => this.triggerCommand("jumpToNote") diff --git a/src/public/app/widgets/type_widgets/editable_code.ts b/src/public/app/widgets/type_widgets/editable_code.ts index 389eb7ae3..ca922cfc2 100644 --- a/src/public/app/widgets/type_widgets/editable_code.ts +++ b/src/public/app/widgets/type_widgets/editable_code.ts @@ -1,9 +1,12 @@ -import type { EventData } from "../../components/app_context.js"; +import { app } from "electron"; +import type { CommandListenerData, EventData } from "../../components/app_context.js"; import type FNote from "../../entities/fnote.js"; import { t } from "../../services/i18n.js"; import keyboardActionService from "../../services/keyboard_actions.js"; import options from "../../services/options.js"; import AbstractCodeTypeWidget from "./abstract_code_type_widget.js"; +import appContext from "../../components/app_context.js"; +import type { TouchBarItem } from "../touch_bar.js"; const TPL = `
@@ -63,6 +66,8 @@ export default class EditableCodeTypeWidget extends AbstractCodeTypeWidget { }); this.show(); + + this.triggerCommand("refreshTouchBar"); } getData() { @@ -80,4 +85,21 @@ export default class EditableCodeTypeWidget extends AbstractCodeTypeWidget { resolve(this.codeEditor); } + + buildTouchBarCommand({ TouchBar, buildIcon }: CommandListenerData<"buildTouchBar">) { + const items: TouchBarItem[] = [ + new TouchBar.TouchBarSpacer({ size: "flexible" }), + ]; + + const note = this.note; + if (note?.mime.startsWith("application/javascript") || note?.mime === "text/x-sqlite;schema=trilium") { + items.push(new TouchBar.TouchBarButton({ + icon: buildIcon("NSImageNameTouchBarPlayTemplate"), + click: () => appContext.triggerCommand("runActiveNote") + })); + } + + return items; + } + } From 8a1b565aeea991da14c828d1a11fba81c6291c54 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 9 Mar 2025 20:41:31 +0200 Subject: [PATCH 26/43] feat(touch_bar): add unlock button for read-only text --- .../widgets/type_widgets/read_only_text.ts | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/public/app/widgets/type_widgets/read_only_text.ts b/src/public/app/widgets/type_widgets/read_only_text.ts index 8d788d6bd..2ac4d671b 100644 --- a/src/public/app/widgets/type_widgets/read_only_text.ts +++ b/src/public/app/widgets/type_widgets/read_only_text.ts @@ -3,11 +3,12 @@ import libraryLoader from "../../services/library_loader.js"; import { applySyntaxHighlight } from "../../services/syntax_highlight.js"; import { getMermaidConfig } from "../mermaid.js"; import type FNote from "../../entities/fnote.js"; -import type { EventData } from "../../components/app_context.js"; +import type { CommandListenerData, EventData } from "../../components/app_context.js"; import { getLocaleById } from "../../services/i18n.js"; +import appContext from "../../components/app_context.js"; const TPL = ` -
+
-
+
`; @@ -595,4 +597,65 @@ export default class CalendarView extends ViewMode { return newDate; } + buildTouchBarCommand({ TouchBar, buildIcon }: CommandListenerData<"buildTouchBar">) { + if (!this.calendar) { + return; + } + + const items: TouchBarItem[] = []; + const $toolbarItems = this.$calendarContainer.find(".fc-toolbar-chunk .fc-button-group, .fc-toolbar-chunk > button"); + + for (const item of $toolbarItems) { + // Button groups. + if (item.classList.contains("fc-button-group")) { + let mode: "single" | "buttons" = "single"; + const segments: SegmentedControlSegment[] = []; + const subItems = item.childNodes as NodeListOf; + for (const subItem of subItems) { + // Text button. + if (subItem.innerText) { + segments.push({ label: subItem.innerText }); + continue; + } + + // Icon button. + const iconEl = subItem.querySelector("span.fc-icon"); + let icon = null; + if (iconEl?.classList.contains("fc-icon-chevron-left")) { + icon = "NSImageNameTouchBarGoBackTemplate"; + mode = "buttons"; + } else if (iconEl?.classList.contains("fc-icon-chevron-right")) { + icon = "NSImageNameTouchBarGoForwardTemplate"; + mode = "buttons"; + } + + if (icon) { + segments.push({ + icon: buildIcon(icon) + }); + } + } + + items.push(new TouchBar.TouchBarSegmentedControl({ + mode, + segments, + change(selectedIndex, isSelected) { + subItems[selectedIndex].click(); + } + })); + continue; + } + + // Standalone item. + if (item.innerText) { + items.push(new TouchBar.TouchBarButton({ + label: item.innerText, + click: () => item.click() + })); + } + } + + return items; + } + } From 9d9ed2edcb83137ca0e9508e16fffdcc3f51e8ec Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 13 Apr 2025 21:31:20 +0300 Subject: [PATCH 32/43] feat(touchbar): refresh properly for calendar view --- .../app/widgets/view_widgets/calendar_view.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/public/app/widgets/view_widgets/calendar_view.ts b/src/public/app/widgets/view_widgets/calendar_view.ts index 83c12cc24..bda4d02d4 100644 --- a/src/public/app/widgets/view_widgets/calendar_view.ts +++ b/src/public/app/widgets/view_widgets/calendar_view.ts @@ -268,6 +268,8 @@ export default class CalendarView extends ViewMode { this.debouncedSaveView(); this.lastView = currentView; + + appContext.triggerCommand("refreshTouchBar"); } async #onCalendarSelection(e: DateSelectArg) { @@ -609,9 +611,16 @@ export default class CalendarView extends ViewMode { // Button groups. if (item.classList.contains("fc-button-group")) { let mode: "single" | "buttons" = "single"; + let selectedIndex = 0; const segments: SegmentedControlSegment[] = []; const subItems = item.childNodes as NodeListOf; + let index = 0; for (const subItem of subItems) { + if (subItem.ariaPressed === "true") { + selectedIndex = index; + } + index++; + // Text button. if (subItem.innerText) { segments.push({ label: subItem.innerText }); @@ -639,9 +648,8 @@ export default class CalendarView extends ViewMode { items.push(new TouchBar.TouchBarSegmentedControl({ mode, segments, - change(selectedIndex, isSelected) { - subItems[selectedIndex].click(); - } + selectedIndex, + change: (selectedIndex, isSelected) => subItems[selectedIndex].click() })); continue; } From f98ac84829f83f120d88bc0a81a689f642294831 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 13 Apr 2025 21:42:28 +0300 Subject: [PATCH 33/43] feat(touchbar): delete note in note tree --- src/public/app/widgets/note_tree.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/public/app/widgets/note_tree.ts b/src/public/app/widgets/note_tree.ts index 7fc801ecb..961432df9 100644 --- a/src/public/app/widgets/note_tree.ts +++ b/src/public/app/widgets/note_tree.ts @@ -25,6 +25,8 @@ import type FNote from "../entities/fnote.js"; import type { NoteType } from "../entities/fnote.js"; import type { AttributeRow, BranchRow } from "../services/load_results.js"; import type { SetNoteOpts } from "../components/note_context.js"; +import type { TouchBarItem } from "./touch_bar.js"; +import type { TreeCommandNames } from "../menus/tree_context_menu.js"; const TPL = /*html*/`
@@ -1760,4 +1762,28 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { appContext.tabManager.getActiveContext()?.setNote(resp.note.noteId); } + + buildTouchBarCommand({ TouchBar, buildIcon }: CommandListenerData<"buildTouchBar">) { + const triggerCommand = (command: TreeCommandNames) => { + const node = this.getActiveNode(); + const notePath = treeService.getNotePath(node); + + this.triggerCommand(command, { + node, + notePath, + noteId: node.data.noteId, + selectedOrActiveBranchIds: this.getSelectedOrActiveBranchIds(node), + selectedOrActiveNoteIds: this.getSelectedOrActiveNoteIds(node) + }); + } + + const items: TouchBarItem[] = [ + new TouchBar.TouchBarButton({ + icon: buildIcon("NSImageNameTouchBarDeleteTemplate"), + click: () => triggerCommand("deleteNotes") + }) + ]; + + return items; + } } From cbc6e74d640b0e2557c136b630e79290ff1e9c51 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 13 Apr 2025 21:47:16 +0300 Subject: [PATCH 34/43] feat(touchbar): create child note in note tree --- src/public/app/widgets/note_tree.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/public/app/widgets/note_tree.ts b/src/public/app/widgets/note_tree.ts index 961432df9..285b7eb79 100644 --- a/src/public/app/widgets/note_tree.ts +++ b/src/public/app/widgets/note_tree.ts @@ -1778,6 +1778,16 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { } const items: TouchBarItem[] = [ + new TouchBar.TouchBarButton({ + icon: buildIcon("NSImageNameTouchBarAddTemplate"), + click: () => { + const node = this.getActiveNode(); + const notePath = treeService.getNotePath(node); + noteCreateService.createNote(notePath, { + isProtected: node.data.isProtected + }); + } + }), new TouchBar.TouchBarButton({ icon: buildIcon("NSImageNameTouchBarDeleteTemplate"), click: () => triggerCommand("deleteNotes") From d734ac9e450d306b169c219a2be542e243450e31 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 13 Apr 2025 21:52:56 +0300 Subject: [PATCH 35/43] fix(touchbar): hide read-only button after editing --- src/public/app/widgets/floating_buttons/edit_button.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/public/app/widgets/floating_buttons/edit_button.ts b/src/public/app/widgets/floating_buttons/edit_button.ts index 0b4d381fd..2a11f0d01 100644 --- a/src/public/app/widgets/floating_buttons/edit_button.ts +++ b/src/public/app/widgets/floating_buttons/edit_button.ts @@ -23,7 +23,6 @@ export default class EditButton extends OnClickButtonWidget { this.noteContext.viewScope.readOnlyTemporarilyDisabled = true; appContext.triggerEvent("readOnlyTemporarilyDisabled", { noteContext: this.noteContext }); } - this.refresh(); }); } @@ -68,6 +67,10 @@ export default class EditButton extends OnClickButtonWidget { } } + readOnlyTemporarilyDisabledEvent() { + this.refresh(); + } + async noteTypeMimeChangedEvent({ noteId }: { noteId: string }): Promise { if (this.isNote(noteId)) { await this.refresh(); From d6478c2fed95b48a84ec12b922d744c32233dd5b Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 13 Apr 2025 22:08:26 +0300 Subject: [PATCH 36/43] fix(touchbar): errors refreshing touchbar if parent is missing --- src/public/app/widgets/type_widgets/editable_code.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/public/app/widgets/type_widgets/editable_code.ts b/src/public/app/widgets/type_widgets/editable_code.ts index 7b0891f3d..a17364502 100644 --- a/src/public/app/widgets/type_widgets/editable_code.ts +++ b/src/public/app/widgets/type_widgets/editable_code.ts @@ -65,7 +65,9 @@ export default class EditableCodeTypeWidget extends AbstractCodeTypeWidget { this.show(); - this.triggerCommand("refreshTouchBar"); + if (this.parent) { + this.triggerCommand("refreshTouchBar"); + } } getData() { From 3fb2378de9e0af6abe5594b5bcb0c5723b9a924a Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 13 Apr 2025 22:10:41 +0300 Subject: [PATCH 37/43] fix(touchbar): errors if there is no modal --- src/public/app/widgets/touch_bar.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/widgets/touch_bar.ts index 8cc2b9359..d361eed81 100644 --- a/src/public/app/widgets/touch_bar.ts +++ b/src/public/app/widgets/touch_bar.ts @@ -15,7 +15,7 @@ export default class TouchBarWidget extends NoteContextAwareWidget { nativeImage: typeof import("electron").nativeImage; remote: typeof import("@electron/remote"); lastFocusedComponent?: Component; - private $activeModal: JQuery; + private $activeModal?: JQuery; constructor() { super(); @@ -57,7 +57,7 @@ export default class TouchBarWidget extends NoteContextAwareWidget { const parentComponent = this.lastFocusedComponent; let touchBar = null; - if (this.$activeModal.length > 0) { + if (this.$activeModal?.length) { touchBar = this.#buildModalTouchBar(); } else if (parentComponent) { const items = parentComponent.triggerCommand("buildTouchBar", { @@ -78,16 +78,16 @@ export default class TouchBarWidget extends NoteContextAwareWidget { const items: TouchBarItem[] = []; // Look for the modal title. - const $title = this.$activeModal.find(".modal-title"); - if ($title.length > 0) { + const $title = this.$activeModal?.find(".modal-title"); + if ($title?.length) { items.push(new TouchBarLabel({ label: $title.text() })) } items.push(new TouchBarSpacer({ size: "flexible" })); // Look for buttons in the modal. - const $buttons = this.$activeModal.find(".modal-footer button"); - for (const button of $buttons) { + const $buttons = this.$activeModal?.find(".modal-footer button"); + for (const button of $buttons ?? []) { items.push(new TouchBarButton({ label: button.innerText, click: () => button.click(), From ef423f1a1fac9d7c4355b5c63f35892fe18bd18c Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 13 Apr 2025 22:12:38 +0300 Subject: [PATCH 38/43] chore(touchbar): reduce spacer width --- src/public/app/widgets/touch_bar.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/widgets/touch_bar.ts index d361eed81..9206d6f15 100644 --- a/src/public/app/widgets/touch_bar.ts +++ b/src/public/app/widgets/touch_bar.ts @@ -113,7 +113,7 @@ export default class TouchBarWidget extends NoteContextAwareWidget { icon: this.buildIcon("NSTouchBarComposeTemplate"), click: () => this.triggerCommand("createNoteIntoInbox") }), - new TouchBarSpacer({ size: "large" }), + new TouchBarSpacer({ size: "small" }), ...componentSpecificItems, new TouchBarSpacer({ size: "flexible" }), new TouchBarOtherItemsProxy(), From 342aff82096adc53cc7a619925f0c16043fc9757 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 13 Apr 2025 22:16:05 +0300 Subject: [PATCH 39/43] chore(touchbar): reduce centering --- src/public/app/widgets/type_widgets/editable_code.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/public/app/widgets/type_widgets/editable_code.ts b/src/public/app/widgets/type_widgets/editable_code.ts index a17364502..0f2c0d31e 100644 --- a/src/public/app/widgets/type_widgets/editable_code.ts +++ b/src/public/app/widgets/type_widgets/editable_code.ts @@ -87,11 +87,9 @@ export default class EditableCodeTypeWidget extends AbstractCodeTypeWidget { } buildTouchBarCommand({ TouchBar, buildIcon }: CommandListenerData<"buildTouchBar">) { - const items: TouchBarItem[] = [ - new TouchBar.TouchBarSpacer({ size: "flexible" }), - ]; - + const items: TouchBarItem[] = []; const note = this.note; + if (note?.mime.startsWith("application/javascript") || note?.mime === "text/x-sqlite;schema=trilium") { items.push(new TouchBar.TouchBarButton({ icon: buildIcon("NSImageNameTouchBarPlayTemplate"), From 83e7e82252a435cbb17222e5627944db3b6dbdb2 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 13 Apr 2025 23:04:06 +0300 Subject: [PATCH 40/43] chore(touchbar): address self-review --- src/public/app/components/app_context.ts | 4 ++-- src/public/app/widgets/type_widgets/editable_code.ts | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/public/app/components/app_context.ts b/src/public/app/components/app_context.ts index f32cf51c4..ad6b70a1c 100644 --- a/src/public/app/components/app_context.ts +++ b/src/public/app/components/app_context.ts @@ -24,7 +24,7 @@ import type NoteTreeWidget from "../widgets/note_tree.js"; import type { default as NoteContext, GetTextEditorCallback } from "./note_context.js"; import type TypeWidget from "../widgets/type_widgets/type_widget.js"; import type EditableTextTypeWidget from "../widgets/type_widgets/editable_text.js"; -import type { NativeImage } from "electron"; +import type { NativeImage, TouchBar } from "electron"; interface Layout { getRootWidget: (appContext: AppContext) => RootWidget; @@ -270,7 +270,7 @@ export type CommandMappings = { geoMapCreateChildNote: CommandData; buildTouchBar: CommandData & { - TouchBar: typeof import("electron").TouchBar; + TouchBar: typeof TouchBar; buildIcon(name: string): NativeImage; }; refreshTouchBar: CommandData; diff --git a/src/public/app/widgets/type_widgets/editable_code.ts b/src/public/app/widgets/type_widgets/editable_code.ts index 0f2c0d31e..49bcde3f1 100644 --- a/src/public/app/widgets/type_widgets/editable_code.ts +++ b/src/public/app/widgets/type_widgets/editable_code.ts @@ -1,4 +1,3 @@ -import { app } from "electron"; import type { CommandListenerData, EventData } from "../../components/app_context.js"; import type FNote from "../../entities/fnote.js"; import { t } from "../../services/i18n.js"; From 14516d53c3812d074ecdb6466a4857cba31d1056 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 13 Apr 2025 23:09:14 +0300 Subject: [PATCH 41/43] chore(touchbar): disable widget on non-mac --- src/public/app/layouts/desktop_layout.ts | 4 ++-- src/public/app/services/utils.ts | 2 ++ .../app/widgets/type_widgets/editable_code.ts | 3 ++- .../app/widgets/type_widgets/editable_text.ts | 8 +++++--- .../app/widgets/type_widgets/geo_map.ts | 20 ++++++++++++------- .../app/widgets/view_widgets/calendar_view.ts | 6 ++++-- 6 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/public/app/layouts/desktop_layout.ts b/src/public/app/layouts/desktop_layout.ts index 9ecbf7e8d..0750bba36 100644 --- a/src/public/app/layouts/desktop_layout.ts +++ b/src/public/app/layouts/desktop_layout.ts @@ -83,7 +83,7 @@ import CopyImageReferenceButton from "../widgets/floating_buttons/copy_image_ref import ScrollPaddingWidget from "../widgets/scroll_padding.js"; import ClassicEditorToolbar from "../widgets/ribbon_widgets/classic_editor_toolbar.js"; import options from "../services/options.js"; -import utils from "../services/utils.js"; +import utils, { hasTouchBar } from "../services/utils.js"; import GeoMapButtons from "../widgets/floating_buttons/geo_map_button.js"; import ContextualHelpButton from "../widgets/floating_buttons/help_button.js"; import CloseZenButton from "../widgets/close_zen_button.js"; @@ -162,7 +162,7 @@ export default class DesktopLayout { .filling() .collapsible() .id("center-pane") - .child(new TouchBarWidget()) + .optChild(hasTouchBar, new TouchBarWidget()) .child( new SplitNoteContainer(() => new NoteWrapperWidget() diff --git a/src/public/app/services/utils.ts b/src/public/app/services/utils.ts index efbb82cf8..6ba2793dd 100644 --- a/src/public/app/services/utils.ts +++ b/src/public/app/services/utils.ts @@ -147,6 +147,8 @@ function isMac() { return navigator.platform.indexOf("Mac") > -1; } +export const hasTouchBar = isMac(); + function isCtrlKey(evt: KeyboardEvent | MouseEvent | JQuery.ClickEvent | JQuery.ContextMenuEvent | JQuery.TriggeredEvent | React.PointerEvent) { return (!isMac() && evt.ctrlKey) || (isMac() && evt.metaKey); } diff --git a/src/public/app/widgets/type_widgets/editable_code.ts b/src/public/app/widgets/type_widgets/editable_code.ts index 49bcde3f1..371cb7f0a 100644 --- a/src/public/app/widgets/type_widgets/editable_code.ts +++ b/src/public/app/widgets/type_widgets/editable_code.ts @@ -6,6 +6,7 @@ import options from "../../services/options.js"; import AbstractCodeTypeWidget from "./abstract_code_type_widget.js"; import appContext from "../../components/app_context.js"; import type { TouchBarItem } from "../touch_bar.js"; +import { hasTouchBar } from "../../services/utils.js"; const TPL = /*html*/`
@@ -64,7 +65,7 @@ export default class EditableCodeTypeWidget extends AbstractCodeTypeWidget { this.show(); - if (this.parent) { + if (this.parent && hasTouchBar) { this.triggerCommand("refreshTouchBar"); } } diff --git a/src/public/app/widgets/type_widgets/editable_text.ts b/src/public/app/widgets/type_widgets/editable_text.ts index 2e2ba64c5..65166f2dc 100644 --- a/src/public/app/widgets/type_widgets/editable_text.ts +++ b/src/public/app/widgets/type_widgets/editable_text.ts @@ -2,7 +2,7 @@ import { t } from "../../services/i18n.js"; import libraryLoader from "../../services/library_loader.js"; import noteAutocompleteService from "../../services/note_autocomplete.js"; import mimeTypesService from "../../services/mime_types.js"; -import utils from "../../services/utils.js"; +import utils, { hasTouchBar } from "../../services/utils.js"; import keyboardActionService from "../../services/keyboard_actions.js"; import froca from "../../services/froca.js"; import noteCreateService from "../../services/note_create.js"; @@ -282,8 +282,10 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { } // Touch bar integration - for (const event of [ "bold", "italic", "underline", "paragraph", "heading" ]) { - editor.commands.get(event).on("change", () => this.triggerCommand("refreshTouchBar")); + if (hasTouchBar) { + for (const event of [ "bold", "italic", "underline", "paragraph", "heading" ]) { + editor.commands.get(event).on("change", () => this.triggerCommand("refreshTouchBar")); + } } return editor; diff --git a/src/public/app/widgets/type_widgets/geo_map.ts b/src/public/app/widgets/type_widgets/geo_map.ts index 82a01fc41..320fb7c9a 100644 --- a/src/public/app/widgets/type_widgets/geo_map.ts +++ b/src/public/app/widgets/type_widgets/geo_map.ts @@ -15,6 +15,7 @@ import appContext from "../../components/app_context.js"; import markerIcon from "leaflet/dist/images/marker-icon.png"; import markerIconShadow from "leaflet/dist/images/marker-shadow.png"; +import { hasTouchBar } from "../../services/utils.js"; const TPL = /*html*/`\
@@ -152,13 +153,16 @@ export default class GeoMapTypeWidget extends TypeWidget { map.on("moveend", updateFn); map.on("zoomend", updateFn); map.on("click", (e) => this.#onMapClicked(e)); - map.on("zoom", () => { - if (!this.ignoreNextZoomEvent) { - this.triggerCommand("refreshTouchBar"); - } - this.ignoreNextZoomEvent = false; - }); + if (hasTouchBar) { + map.on("zoom", () => { + if (!this.ignoreNextZoomEvent) { + this.triggerCommand("refreshTouchBar"); + } + + this.ignoreNextZoomEvent = false; + }); + } } async #restoreViewportAndZoom() { @@ -287,7 +291,9 @@ export default class GeoMapTypeWidget extends TypeWidget { #changeState(newState: State) { this._state = newState; this.geoMapWidget.$container.toggleClass("placing-note", newState === State.NewNote); - this.triggerCommand("refreshTouchBar"); + if (hasTouchBar) { + this.triggerCommand("refreshTouchBar"); + } } async #onMapClicked(e: LeafletMouseEvent) { diff --git a/src/public/app/widgets/view_widgets/calendar_view.ts b/src/public/app/widgets/view_widgets/calendar_view.ts index bda4d02d4..a5452de66 100644 --- a/src/public/app/widgets/view_widgets/calendar_view.ts +++ b/src/public/app/widgets/view_widgets/calendar_view.ts @@ -8,7 +8,7 @@ import options from "../../services/options.js"; import dialogService from "../../services/dialog.js"; import attributes from "../../services/attributes.js"; import type { CommandListenerData, EventData } from "../../components/app_context.js"; -import utils from "../../services/utils.js"; +import utils, { hasTouchBar } from "../../services/utils.js"; import date_notes from "../../services/date_notes.js"; import appContext from "../../components/app_context.js"; import type { EventImpl } from "@fullcalendar/core/internal"; @@ -269,7 +269,9 @@ export default class CalendarView extends ViewMode { this.debouncedSaveView(); this.lastView = currentView; - appContext.triggerCommand("refreshTouchBar"); + if (hasTouchBar) { + appContext.triggerCommand("refreshTouchBar"); + } } async #onCalendarSelection(e: DateSelectArg) { From c5ca3decb12df40d4ec039c69b288ed2d19e873a Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 13 Apr 2025 23:20:22 +0300 Subject: [PATCH 42/43] refactor(touchbar): turn into a component --- src/public/app/components/app_context.ts | 7 ++++++- src/public/app/{widgets => components}/touch_bar.ts | 7 +++---- src/public/app/layouts/desktop_layout.ts | 2 -- src/public/app/widgets/note_tree.ts | 2 +- src/public/app/widgets/type_widgets/editable_code.ts | 2 +- src/public/app/widgets/type_widgets/editable_text.ts | 2 +- src/public/app/widgets/view_widgets/calendar_view.ts | 2 +- 7 files changed, 13 insertions(+), 11 deletions(-) rename src/public/app/{widgets => components}/touch_bar.ts (95%) diff --git a/src/public/app/components/app_context.ts b/src/public/app/components/app_context.ts index ad6b70a1c..68f50218a 100644 --- a/src/public/app/components/app_context.ts +++ b/src/public/app/components/app_context.ts @@ -3,7 +3,7 @@ import bundleService from "../services/bundle.js"; import RootCommandExecutor from "./root_command_executor.js"; import Entrypoints, { type SqlExecuteResults } from "./entrypoints.js"; import options from "../services/options.js"; -import utils from "../services/utils.js"; +import utils, { hasTouchBar } from "../services/utils.js"; import zoomComponent from "./zoom.js"; import TabManager from "./tab_manager.js"; import Component from "./component.js"; @@ -25,6 +25,7 @@ import type { default as NoteContext, GetTextEditorCallback } from "./note_conte import type TypeWidget from "../widgets/type_widgets/type_widget.js"; import type EditableTextTypeWidget from "../widgets/type_widgets/editable_text.js"; import type { NativeImage, TouchBar } from "electron"; +import TouchBarComponent from "./touch_bar.js"; interface Layout { getRootWidget: (appContext: AppContext) => RootWidget; @@ -478,6 +479,10 @@ export class AppContext extends Component { if (utils.isElectron()) { this.child(zoomComponent); } + + if (hasTouchBar) { + this.child(new TouchBarComponent()); + } } renderWidgets() { diff --git a/src/public/app/widgets/touch_bar.ts b/src/public/app/components/touch_bar.ts similarity index 95% rename from src/public/app/widgets/touch_bar.ts rename to src/public/app/components/touch_bar.ts index 9206d6f15..4afe65151 100644 --- a/src/public/app/widgets/touch_bar.ts +++ b/src/public/app/components/touch_bar.ts @@ -1,7 +1,6 @@ import utils from "../services/utils.js"; -import Component from "../components/component.js"; -import appContext from "../components/app_context.js"; -import NoteContextAwareWidget from "./note_context_aware_widget.js"; +import Component from "./component.js"; +import appContext from "./app_context.js"; import type { TouchBarButton, TouchBarGroup, TouchBarSegmentedControl, TouchBarSpacer } from "@electron/remote"; export type TouchBarItem = (TouchBarButton | TouchBarSpacer | TouchBarGroup | TouchBarSegmentedControl); @@ -10,7 +9,7 @@ export function buildSelectedBackgroundColor(isSelected: boolean) { return isSelected ? "#757575" : undefined; } -export default class TouchBarWidget extends NoteContextAwareWidget { +export default class TouchBarComponent extends Component { nativeImage: typeof import("electron").nativeImage; remote: typeof import("@electron/remote"); diff --git a/src/public/app/layouts/desktop_layout.ts b/src/public/app/layouts/desktop_layout.ts index 0750bba36..ee6faed63 100644 --- a/src/public/app/layouts/desktop_layout.ts +++ b/src/public/app/layouts/desktop_layout.ts @@ -87,7 +87,6 @@ import utils, { hasTouchBar } from "../services/utils.js"; import GeoMapButtons from "../widgets/floating_buttons/geo_map_button.js"; import ContextualHelpButton from "../widgets/floating_buttons/help_button.js"; import CloseZenButton from "../widgets/close_zen_button.js"; -import TouchBarWidget from "../widgets/touch_bar.js"; import type { AppContext } from "./../components/app_context.js"; import type { WidgetsByParent } from "../services/bundle.js"; import SwitchSplitOrientationButton from "../widgets/floating_buttons/switch_layout_button.js"; @@ -162,7 +161,6 @@ export default class DesktopLayout { .filling() .collapsible() .id("center-pane") - .optChild(hasTouchBar, new TouchBarWidget()) .child( new SplitNoteContainer(() => new NoteWrapperWidget() diff --git a/src/public/app/widgets/note_tree.ts b/src/public/app/widgets/note_tree.ts index e29696a69..cbc3ec055 100644 --- a/src/public/app/widgets/note_tree.ts +++ b/src/public/app/widgets/note_tree.ts @@ -25,7 +25,7 @@ import type FNote from "../entities/fnote.js"; import type { NoteType } from "../entities/fnote.js"; import type { AttributeRow, BranchRow } from "../services/load_results.js"; import type { SetNoteOpts } from "../components/note_context.js"; -import type { TouchBarItem } from "./touch_bar.js"; +import type { TouchBarItem } from "../components/touch_bar.js"; import type { TreeCommandNames } from "../menus/tree_context_menu.js"; const TPL = /*html*/` diff --git a/src/public/app/widgets/type_widgets/editable_code.ts b/src/public/app/widgets/type_widgets/editable_code.ts index 371cb7f0a..fbdee8244 100644 --- a/src/public/app/widgets/type_widgets/editable_code.ts +++ b/src/public/app/widgets/type_widgets/editable_code.ts @@ -5,7 +5,7 @@ import keyboardActionService from "../../services/keyboard_actions.js"; import options from "../../services/options.js"; import AbstractCodeTypeWidget from "./abstract_code_type_widget.js"; import appContext from "../../components/app_context.js"; -import type { TouchBarItem } from "../touch_bar.js"; +import type { TouchBarItem } from "../../components/touch_bar.js"; import { hasTouchBar } from "../../services/utils.js"; const TPL = /*html*/` diff --git a/src/public/app/widgets/type_widgets/editable_text.ts b/src/public/app/widgets/type_widgets/editable_text.ts index 65166f2dc..edefbcdcd 100644 --- a/src/public/app/widgets/type_widgets/editable_text.ts +++ b/src/public/app/widgets/type_widgets/editable_text.ts @@ -14,7 +14,7 @@ import { initSyntaxHighlighting } from "./ckeditor/syntax_highlight.js"; import options from "../../services/options.js"; import toast from "../../services/toast.js"; import { normalizeMimeTypeForCKEditor } from "../../services/mime_type_definitions.js"; -import { buildSelectedBackgroundColor } from "../touch_bar.js"; +import { buildSelectedBackgroundColor } from "../../components/touch_bar.js"; import { buildConfig, buildToolbarConfig } from "./ckeditor/config.js"; import type FNote from "../../entities/fnote.js"; import { getMermaidConfig } from "../../services/mermaid.js"; diff --git a/src/public/app/widgets/view_widgets/calendar_view.ts b/src/public/app/widgets/view_widgets/calendar_view.ts index a5452de66..3ffc43d74 100644 --- a/src/public/app/widgets/view_widgets/calendar_view.ts +++ b/src/public/app/widgets/view_widgets/calendar_view.ts @@ -13,7 +13,7 @@ import date_notes from "../../services/date_notes.js"; import appContext from "../../components/app_context.js"; import type { EventImpl } from "@fullcalendar/core/internal"; import debounce, { type DebouncedFunction } from "debounce"; -import type { TouchBarItem } from "../touch_bar.js"; +import type { TouchBarItem } from "../../components/touch_bar.js"; import type { SegmentedControlSegment } from "electron"; const TPL = /*html*/` From 58a33efeab713b5ca88048ca799ea0dac6e9a83b Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 13 Apr 2025 23:26:35 +0300 Subject: [PATCH 43/43] fix(touchbar): crashing on server --- src/public/app/services/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/public/app/services/utils.ts b/src/public/app/services/utils.ts index 6ba2793dd..a52b7443a 100644 --- a/src/public/app/services/utils.ts +++ b/src/public/app/services/utils.ts @@ -147,7 +147,7 @@ function isMac() { return navigator.platform.indexOf("Mac") > -1; } -export const hasTouchBar = isMac(); +export const hasTouchBar = (isMac() && isElectron()); function isCtrlKey(evt: KeyboardEvent | MouseEvent | JQuery.ClickEvent | JQuery.ContextMenuEvent | JQuery.TriggeredEvent | React.PointerEvent) { return (!isMac() && evt.ctrlKey) || (isMac() && evt.metaKey);