mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-08-10 10:22:29 +08:00
Merge pull request #1549 from TriliumNext/feature/touchbar
Basic touchbar integration
This commit is contained in:
commit
e79730a707
@ -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";
|
||||
@ -24,7 +24,8 @@ 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 FAttribute from "../entities/fattribute.js";
|
||||
import type { NativeImage, TouchBar } from "electron";
|
||||
import TouchBarComponent from "./touch_bar.js";
|
||||
|
||||
interface Layout {
|
||||
getRootWidget: (appContext: AppContext) => RootWidget;
|
||||
@ -170,6 +171,8 @@ export type CommandMappings = {
|
||||
moveNoteDownInHierarchy: ContextMenuCommandData;
|
||||
selectAllNotesInParent: ContextMenuCommandData;
|
||||
|
||||
createNoteIntoInbox: CommandData;
|
||||
|
||||
addNoteLauncher: ContextMenuCommandData;
|
||||
addScriptLauncher: ContextMenuCommandData;
|
||||
addWidgetLauncher: ContextMenuCommandData;
|
||||
@ -249,6 +252,7 @@ export type CommandMappings = {
|
||||
scrollToEnd: CommandData;
|
||||
closeThisNoteSplit: CommandData;
|
||||
moveThisNoteSplit: CommandData & { isMovingLeft: boolean };
|
||||
jumpToNote: CommandData;
|
||||
|
||||
// Geomap
|
||||
deleteFromMap: { noteId: string };
|
||||
@ -263,6 +267,14 @@ export type CommandMappings = {
|
||||
|
||||
refreshResults: {};
|
||||
refreshSearchDefinition: {};
|
||||
|
||||
geoMapCreateChildNote: CommandData;
|
||||
|
||||
buildTouchBar: CommandData & {
|
||||
TouchBar: typeof TouchBar;
|
||||
buildIcon(name: string): NativeImage;
|
||||
};
|
||||
refreshTouchBar: CommandData;
|
||||
};
|
||||
|
||||
type EventMappings = {
|
||||
@ -467,6 +479,10 @@ export class AppContext extends Component {
|
||||
if (utils.isElectron()) {
|
||||
this.child(zoomComponent);
|
||||
}
|
||||
|
||||
if (hasTouchBar) {
|
||||
this.child(new TouchBarComponent());
|
||||
}
|
||||
}
|
||||
|
||||
renderWidgets() {
|
||||
|
135
src/public/app/components/touch_bar.ts
Normal file
135
src/public/app/components/touch_bar.ts
Normal file
@ -0,0 +1,135 @@
|
||||
import utils from "../services/utils.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);
|
||||
|
||||
export function buildSelectedBackgroundColor(isSelected: boolean) {
|
||||
return isSelected ? "#757575" : undefined;
|
||||
}
|
||||
|
||||
export default class TouchBarComponent extends Component {
|
||||
|
||||
nativeImage: typeof import("electron").nativeImage;
|
||||
remote: typeof import("@electron/remote");
|
||||
lastFocusedComponent?: Component;
|
||||
private $activeModal?: JQuery<HTMLElement>;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.nativeImage = utils.dynamicRequire("electron").nativeImage;
|
||||
this.remote = utils.dynamicRequire("@electron/remote") as typeof import("@electron/remote");
|
||||
this.$widget = $("<div>");
|
||||
|
||||
$(window).on("focusin", async (e) => {
|
||||
const $target = $(e.target);
|
||||
|
||||
this.$activeModal = $target.closest(".modal-dialog");
|
||||
const parentComponentEl = $target.closest(".component");
|
||||
this.lastFocusedComponent = appContext.getComponentByEl(parentComponentEl[0]);
|
||||
this.#refreshTouchBar();
|
||||
});
|
||||
}
|
||||
|
||||
buildIcon(name: string) {
|
||||
const sourceImage = this.nativeImage.createFromNamedImage(name, [-1, 0, 1]);
|
||||
const { width, height } = sourceImage.getSize();
|
||||
const newImage = this.nativeImage.createEmpty();
|
||||
newImage.addRepresentation({
|
||||
scaleFactor: 1,
|
||||
width: width / 2,
|
||||
height: height / 2,
|
||||
buffer: sourceImage.resize({ height: height / 2 }).toBitmap()
|
||||
});
|
||||
newImage.addRepresentation({
|
||||
scaleFactor: 2,
|
||||
width: width,
|
||||
height: height,
|
||||
buffer: sourceImage.toBitmap()
|
||||
});
|
||||
return newImage;
|
||||
}
|
||||
|
||||
#refreshTouchBar() {
|
||||
const { TouchBar } = this.remote;
|
||||
const parentComponent = this.lastFocusedComponent;
|
||||
let touchBar = null;
|
||||
|
||||
if (this.$activeModal?.length) {
|
||||
touchBar = this.#buildModalTouchBar();
|
||||
} else if (parentComponent) {
|
||||
const items = parentComponent.triggerCommand("buildTouchBar", {
|
||||
TouchBar,
|
||||
buildIcon: this.buildIcon.bind(this)
|
||||
}) as unknown as TouchBarItem[];
|
||||
touchBar = this.#buildTouchBar(items);
|
||||
}
|
||||
|
||||
if (touchBar) {
|
||||
this.remote.getCurrentWindow().setTouchBar(touchBar);
|
||||
}
|
||||
}
|
||||
|
||||
#buildModalTouchBar() {
|
||||
const { TouchBar } = this.remote;
|
||||
const { TouchBarButton, TouchBarLabel, TouchBarSpacer } = this.remote.TouchBar;
|
||||
const items: TouchBarItem[] = [];
|
||||
|
||||
// Look for the modal title.
|
||||
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 ?? []) {
|
||||
items.push(new TouchBarButton({
|
||||
label: button.innerText,
|
||||
click: () => button.click(),
|
||||
enabled: !button.hasAttribute("disabled")
|
||||
}));
|
||||
}
|
||||
|
||||
items.push(new TouchBarSpacer({ size: "flexible" }));
|
||||
return new TouchBar({ items });
|
||||
}
|
||||
|
||||
#buildTouchBar(componentSpecificItems?: TouchBarItem[]) {
|
||||
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: "small" }),
|
||||
...componentSpecificItems,
|
||||
new TouchBarSpacer({ size: "flexible" }),
|
||||
new TouchBarOtherItemsProxy(),
|
||||
new TouchBarButton({
|
||||
icon: this.buildIcon("NSTouchBarAddDetailTemplate"),
|
||||
click: () => this.triggerCommand("jumpToNote")
|
||||
})
|
||||
].flat();
|
||||
|
||||
console.log("Update ", items);
|
||||
return new TouchBar({
|
||||
items
|
||||
});
|
||||
}
|
||||
|
||||
refreshTouchBarEvent() {
|
||||
this.#refreshTouchBar();
|
||||
}
|
||||
|
||||
}
|
@ -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";
|
||||
|
@ -147,6 +147,8 @@ function isMac() {
|
||||
return navigator.platform.indexOf("Mac") > -1;
|
||||
}
|
||||
|
||||
export const hasTouchBar = (isMac() && isElectron());
|
||||
|
||||
function isCtrlKey(evt: KeyboardEvent | MouseEvent | JQuery.ClickEvent | JQuery.ContextMenuEvent | JQuery.TriggeredEvent | React.PointerEvent<HTMLCanvasElement>) {
|
||||
return (!isMac() && evt.ctrlKey) || (isMac() && evt.metaKey);
|
||||
}
|
||||
|
5
src/public/app/types.d.ts
vendored
5
src/public/app/types.d.ts
vendored
@ -339,6 +339,11 @@ declare global {
|
||||
mention: MentionConfig
|
||||
});
|
||||
enableReadOnlyMode(reason: string);
|
||||
commands: {
|
||||
get(name: string): {
|
||||
value: unknown;
|
||||
};
|
||||
}
|
||||
model: {
|
||||
document: {
|
||||
on(event: string, cb: () => void);
|
||||
|
@ -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<void> {
|
||||
if (this.isNote(noteId)) {
|
||||
await this.refresh();
|
||||
|
@ -1,7 +1,7 @@
|
||||
import NoteContextAwareWidget from "./note_context_aware_widget.js";
|
||||
import NoteListRenderer from "../services/note_list_renderer.js";
|
||||
import type FNote from "../entities/fnote.js";
|
||||
import type { EventData } from "../components/app_context.js";
|
||||
import type { CommandListener, CommandListenerData, EventData } from "../components/app_context.js";
|
||||
import type ViewMode from "./view_widgets/view_mode.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
@ -127,4 +127,11 @@ export default class NoteListWidget extends NoteContextAwareWidget {
|
||||
this.checkRenderStatus();
|
||||
}
|
||||
}
|
||||
|
||||
buildTouchBarCommand(data: CommandListenerData<"buildTouchBar">) {
|
||||
if (this.viewMode && "buildTouchBarCommand" in this.viewMode) {
|
||||
return (this.viewMode as CommandListener<"buildTouchBar">).buildTouchBarCommand(data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 "../components/touch_bar.js";
|
||||
import type { TreeCommandNames } from "../menus/tree_context_menu.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<div class="tree-wrapper">
|
||||
@ -1763,4 +1765,38 @@ 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<TreeCommandNames>(command, {
|
||||
node,
|
||||
notePath,
|
||||
noteId: node.data.noteId,
|
||||
selectedOrActiveBranchIds: this.getSelectedOrActiveBranchIds(node),
|
||||
selectedOrActiveNoteIds: this.getSelectedOrActiveNoteIds(node)
|
||||
});
|
||||
}
|
||||
|
||||
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")
|
||||
})
|
||||
];
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
import type { EventData } from "../../components/app_context.js";
|
||||
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 "../../components/touch_bar.js";
|
||||
import { hasTouchBar } from "../../services/utils.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<div class="note-detail-code note-detail-printable">
|
||||
@ -61,6 +64,10 @@ export default class EditableCodeTypeWidget extends AbstractCodeTypeWidget {
|
||||
});
|
||||
|
||||
this.show();
|
||||
|
||||
if (this.parent && hasTouchBar) {
|
||||
this.triggerCommand("refreshTouchBar");
|
||||
}
|
||||
}
|
||||
|
||||
getData() {
|
||||
@ -78,4 +85,19 @@ export default class EditableCodeTypeWidget extends AbstractCodeTypeWidget {
|
||||
|
||||
resolve(this.codeEditor);
|
||||
}
|
||||
|
||||
buildTouchBarCommand({ TouchBar, buildIcon }: CommandListenerData<"buildTouchBar">) {
|
||||
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"),
|
||||
click: () => appContext.triggerCommand("runActiveNote")
|
||||
}));
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,18 +2,19 @@ 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";
|
||||
import AbstractTextTypeWidget from "./abstract_text_type_widget.js";
|
||||
import link from "../../services/link.js";
|
||||
import appContext, { type EventData } from "../../components/app_context.js";
|
||||
import appContext, { type CommandListenerData, type EventData } from "../../components/app_context.js";
|
||||
import dialogService from "../../services/dialog.js";
|
||||
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 "../../components/touch_bar.js";
|
||||
import { buildConfig, buildToolbarConfig } from "./ckeditor/config.js";
|
||||
import type FNote from "../../entities/fnote.js";
|
||||
import { getMermaidConfig } from "../../services/mermaid.js";
|
||||
@ -280,6 +281,13 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
||||
CKEditorInspector.attach(editor);
|
||||
}
|
||||
|
||||
// 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;
|
||||
});
|
||||
|
||||
@ -544,4 +552,60 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
||||
await this.reinitialize(data);
|
||||
}
|
||||
|
||||
buildTouchBarCommand(data: CommandListenerData<"buildTouchBar">) {
|
||||
const { TouchBar, buildIcon } = data;
|
||||
const { TouchBarSegmentedControl, TouchBarGroup, TouchBarButton } = TouchBar;
|
||||
const { editor } = this.watchdog;
|
||||
|
||||
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 = 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, isSelected) {
|
||||
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")
|
||||
]
|
||||
})
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 openContextMenu from "./geo_map_context_menu.js";
|
||||
@ -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*/`\
|
||||
<div class="note-detail-geo-map note-detail-printable">
|
||||
@ -107,6 +108,7 @@ export default class GeoMapTypeWidget extends TypeWidget {
|
||||
private currentMarkerData: Record<string, Marker>;
|
||||
private currentTrackData: Record<string, GPX>;
|
||||
private gpxLoaded?: boolean;
|
||||
private ignoreNextZoomEvent?: boolean;
|
||||
|
||||
static getType() {
|
||||
return "geoMap";
|
||||
@ -151,6 +153,16 @@ export default class GeoMapTypeWidget extends TypeWidget {
|
||||
map.on("moveend", updateFn);
|
||||
map.on("zoomend", updateFn);
|
||||
map.on("click", (e) => this.#onMapClicked(e));
|
||||
|
||||
if (hasTouchBar) {
|
||||
map.on("zoom", () => {
|
||||
if (!this.ignoreNextZoomEvent) {
|
||||
this.triggerCommand("refreshTouchBar");
|
||||
}
|
||||
|
||||
this.ignoreNextZoomEvent = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async #restoreViewportAndZoom() {
|
||||
@ -279,6 +291,9 @@ export default class GeoMapTypeWidget extends TypeWidget {
|
||||
#changeState(newState: State) {
|
||||
this._state = newState;
|
||||
this.geoMapWidget.$container.toggleClass("placing-note", newState === State.NewNote);
|
||||
if (hasTouchBar) {
|
||||
this.triggerCommand("refreshTouchBar");
|
||||
}
|
||||
}
|
||||
|
||||
async #onMapClicked(e: LeafletMouseEvent) {
|
||||
@ -388,4 +403,30 @@ export default class GeoMapTypeWidget extends TypeWidget {
|
||||
this.moveMarker(noteId, null);
|
||||
}
|
||||
|
||||
buildTouchBarCommand({ TouchBar }: CommandListenerData<"buildTouchBar">) {
|
||||
const map = this.geoMapWidget.map;
|
||||
const that = this;
|
||||
if (!map) {
|
||||
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 }),
|
||||
enabled: (this._state === State.Normal)
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,12 +2,13 @@ import AbstractTextTypeWidget from "./abstract_text_type_widget.js";
|
||||
import libraryLoader from "../../services/library_loader.js";
|
||||
import { applySyntaxHighlight } from "../../services/syntax_highlight.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";
|
||||
import { getMermaidConfig } from "../../services/mermaid.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<div class="note-detail-readonly-text note-detail-printable">
|
||||
<div class="note-detail-readonly-text note-detail-printable" tabindex="100">
|
||||
<style>
|
||||
/* h1 should not be used at all since semantically that's a note title */
|
||||
.note-detail-readonly-text h1 { font-size: 1.8em; }
|
||||
@ -169,4 +170,20 @@ export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget {
|
||||
this.$widget.attr("dir", isRtl ? "rtl" : "ltr");
|
||||
}
|
||||
|
||||
buildTouchBarCommand({ TouchBar, buildIcon }: CommandListenerData<"buildTouchBar">) {
|
||||
return [
|
||||
new TouchBar.TouchBarSpacer({ size: "flexible" }),
|
||||
new TouchBar.TouchBarButton({
|
||||
icon: buildIcon("NSLockUnlockedTemplate"),
|
||||
click: () => {
|
||||
if (this.noteContext?.viewScope) {
|
||||
this.noteContext.viewScope.readOnlyTemporarilyDisabled = true;
|
||||
appContext.triggerEvent("readOnlyTemporarilyDisabled", { noteContext: this.noteContext });
|
||||
}
|
||||
this.refresh();
|
||||
}
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,12 +7,14 @@ import { t } from "../../services/i18n.js";
|
||||
import options from "../../services/options.js";
|
||||
import dialogService from "../../services/dialog.js";
|
||||
import attributes from "../../services/attributes.js";
|
||||
import type { EventData } from "../../components/app_context.js";
|
||||
import utils from "../../services/utils.js";
|
||||
import type { CommandListenerData, EventData } from "../../components/app_context.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";
|
||||
import debounce, { type DebouncedFunction } from "debounce";
|
||||
import type { TouchBarItem } from "../../components/touch_bar.js";
|
||||
import type { SegmentedControlSegment } from "electron";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<div class="calendar-view">
|
||||
@ -69,7 +71,7 @@ const TPL = /*html*/`
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="calendar-container">
|
||||
<div class="calendar-container" tabindex="100">
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@ -266,6 +268,10 @@ export default class CalendarView extends ViewMode {
|
||||
|
||||
this.debouncedSaveView();
|
||||
this.lastView = currentView;
|
||||
|
||||
if (hasTouchBar) {
|
||||
appContext.triggerCommand("refreshTouchBar");
|
||||
}
|
||||
}
|
||||
|
||||
async #onCalendarSelection(e: DateSelectArg) {
|
||||
@ -595,4 +601,71 @@ 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";
|
||||
let selectedIndex = 0;
|
||||
const segments: SegmentedControlSegment[] = [];
|
||||
const subItems = item.childNodes as NodeListOf<HTMLElement>;
|
||||
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 });
|
||||
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,
|
||||
selectedIndex,
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user