diff --git a/apps/client/src/widgets/react/TouchBar.tsx b/apps/client/src/widgets/react/TouchBar.tsx index e0f40fd879..02918d0a36 100644 --- a/apps/client/src/widgets/react/TouchBar.tsx +++ b/apps/client/src/widgets/react/TouchBar.tsx @@ -25,6 +25,7 @@ interface ButtonProps { icon?: string; click: () => void; enabled?: boolean; + backgroundColor?: string; } interface SpacerProps { @@ -129,13 +130,14 @@ export function TouchBarSlider({ label, value, minValue, maxValue, onChange }: S return <>; } -export function TouchBarButton({ label, icon, click, enabled }: ButtonProps) { +export function TouchBarButton({ label, icon, click, enabled, backgroundColor }: ButtonProps) { const api = useContext(TouchBarContext); const item = useMemo(() => { if (!api) return null; return new api.TouchBar.TouchBarButton({ label, click, enabled, - icon: icon ? buildIcon(api.nativeImage, icon) : undefined + icon: icon ? buildIcon(api.nativeImage, icon) : undefined, + backgroundColor }); }, [ label, icon ]); @@ -171,6 +173,32 @@ export function TouchBarSegmentedControl({ mode, segments, selectedIndex, onChan return <>; } +export function TouchBarGroup({ children }: { children: ComponentChildren }) { + const remote = dynamicRequire("@electron/remote") as typeof import("@electron/remote"); + const items: TouchBarItem[] = []; + + const api: TouchBarContextApi = { + TouchBar: remote.TouchBar, + nativeImage: remote.nativeImage, + addItem: (item) => { + items.push(item); + } + }; + + if (api) { + const item = new api.TouchBar.TouchBarGroup({ + items: new api.TouchBar({ items }) + }); + api.addItem(item); + } + + return <> + + {children} + + ; +} + export function TouchBarSpacer({ size }: SpacerProps) { const api = useContext(TouchBarContext); diff --git a/apps/client/src/widgets/type_widgets/text/EditableText.tsx b/apps/client/src/widgets/type_widgets/text/EditableText.tsx index bda1955113..2f9d122b67 100644 --- a/apps/client/src/widgets/type_widgets/text/EditableText.tsx +++ b/apps/client/src/widgets/type_widgets/text/EditableText.tsx @@ -1,7 +1,7 @@ import { useEffect, useRef, useState } from "preact/hooks"; import dialog from "../../../services/dialog"; import toast from "../../../services/toast"; -import utils, { deferred, isMobile } from "../../../services/utils"; +import utils, { deferred, hasTouchBar, isMobile } from "../../../services/utils"; import { useEditorSpacedUpdate, useKeyboardShortcuts, useLegacyImperativeHandlers, useNoteLabel, useTriliumEvent, useTriliumOption, useTriliumOptionBool } from "../../react/hooks"; import { TypeWidgetProps } from "../type_widget"; import CKEditorWithWatchdog, { CKEditorApi } from "./CKEditorWithWatchdog"; @@ -14,6 +14,9 @@ import getTemplates, { updateTemplateCache } from "./snippets.js"; import appContext from "../../../components/app_context"; import link, { parseNavigationStateFromUrl } from "../../../services/link"; import note_create from "../../../services/note_create"; +import TouchBar, { TouchBarButton, TouchBarGroup, TouchBarSegmentedControl } from "../../react/TouchBar"; +import { RefObject } from "preact"; +import { buildSelectedBackgroundColor } from "../../../components/touch_bar"; /** * The editor can operate into two distinct modes: @@ -26,6 +29,7 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext const [ content, setContent ] = useState(); const watchdogRef = useRef(null); const editorApiRef = useRef(null); + const refreshTouchBarRef = useRef<() => void>(null); const [ language ] = useNoteLabel(note, "language"); const [ textNoteEditorType ] = useTriliumOption("textNoteEditorType"); const [ codeBlockWordWrap ] = useTriliumOptionBool("codeBlockWordWrap"); @@ -201,9 +205,18 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext setupClassicEditor(editor, parentComponent); } + if (hasTouchBar) { + const handler = () => refreshTouchBarRef.current?.(); + for (const event of [ "bold", "italic", "underline", "paragraph", "heading" ]) { + editor.commands.get(event)?.on("change", handler); + } + } + initialized.current.resolve(); }} />} + + ) } @@ -304,3 +317,68 @@ function findClassicToolbar(parentComponent: Component): JQuery { return $("body").find(".classic-toolbar-widget"); } } + +function EditableTextTouchBar({ watchdogRef, refreshTouchBarRef }: { watchdogRef: RefObject, refreshTouchBarRef: RefObject<() => void> }) { + const [ headingSelectedIndex, setHeadingSelectedIndex ] = useState(); + + function refresh() { + let headingSelectedIndex: number | undefined = undefined; + const editor = watchdogRef.current?.editor; + 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; + } + setHeadingSelectedIndex(headingSelectedIndex); + } + + useEffect(refresh, []); + refreshTouchBarRef.current = refresh; + + return ( + + { + const editor = watchdogRef.current?.editor; + switch (selectedIndex) { + case 0: + editor?.execute("paragraph") + break; + case 1: + editor?.execute("heading", { value: "heading2" }); + break; + case 2: + editor?.execute("heading", { value: "heading3" }); + break; + } + }} + selectedIndex={headingSelectedIndex} + mode="buttons" + /> + + + + + + + + ) +} + +function TouchBarCommandButton({ watchdogRef, icon, command }: { watchdogRef: RefObject, icon: string, command: string }) { + const editor = watchdogRef.current?.editor; + return ( editor?.execute(command)} + backgroundColor={buildSelectedBackgroundColor(editor?.commands.get(command)?.value as boolean)} + />); +} diff --git a/apps/client/src/widgets/type_widgets_old/editable_text.ts b/apps/client/src/widgets/type_widgets_old/editable_text.ts index 11c17ffb94..c37787b031 100644 --- a/apps/client/src/widgets/type_widgets_old/editable_text.ts +++ b/apps/client/src/widgets/type_widgets_old/editable_text.ts @@ -32,23 +32,6 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { super.doRender(); } - async initEditor() { - this.watchdog.setCreator(async (_, editorConfig) => { - // Touch bar integration - if (hasTouchBar) { - for (const event of [ "bold", "italic", "underline", "paragraph", "heading" ]) { - editor.commands.get(event)?.on("change", () => this.triggerCommand("refreshTouchBar")); - } - } - - return editor; - }); - - await this.createEditor(); - } - - show() { } - getEditor() { return this.watchdog?.editor; } @@ -80,64 +63,5 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { await this.reinitialize(); } - buildTouchBarCommand(data: CommandListenerData<"buildTouchBar">) { - const { TouchBar, buildIcon } = data; - const { TouchBarSegmentedControl, TouchBarGroup, TouchBarButton } = TouchBar; - const { editor } = this.watchdog; - - if (!editor) { - return; - } - - const commandButton = (icon: string, command: string) => new TouchBarButton({ - icon: buildIcon(icon), - click: () => editor.execute(command), - backgroundColor: buildSelectedBackgroundColor(editor.commands.get(command)?.value as boolean) - }); - - let headingSelectedIndex: number | undefined = 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: [ - { label: "P" }, - { label: "H2" }, - { label: "H3" } - ], - change(selectedIndex: number, isSelected: boolean) { - switch (selectedIndex) { - case 0: - editor.execute("paragraph") - break; - case 1: - editor.execute("heading", { value: "heading2" }); - break; - case 2: - editor.execute("heading", { value: "heading3" }); - break; - } - }, - selectedIndex: headingSelectedIndex - }), - new TouchBarGroup({ - items: new TouchBar({ - items: [ - commandButton("NSTouchBarTextBoldTemplate", "bold"), - commandButton("NSTouchBarTextItalicTemplate", "italic"), - commandButton("NSTouchBarTextUnderlineTemplate", "underline") - ] - }) - }) - ]; - } }