Add right click context menu and improve application menu

- Add right-click context menu with undo/redo/cut/copy/paste/select all options, as well as Delete block and Move block to another buffer
- Add Delete Block and Move Block to another buffer in the application menu
- Change so that we use our custom "undo" event instead of relying on the default undo event, since there were cases when the default undo didn't trigger the CodeMirror undo reliably
This commit is contained in:
Jonatan Heyman 2025-01-09 17:03:51 +01:00
parent 0cec80be7d
commit 3107cb5368
9 changed files with 115 additions and 27 deletions

View File

@ -6,6 +6,8 @@ Here are the most notable changes in each release. For a more detailed list of c
## 2.1.0 (not yet released)
- Added support for moving the current block to another (or new) buffer. Pressing `Ctrl/Cmd+S` will now pop up a dialog where you can search for and select another buffer to which the block will be moved. It's also possible to select to create a brand new buffer to which the block will be moved.
- Add right click context menu with undo/redo/cut/copy/paste/select all as well as Delete Block and Move block to another buffer.
- Add File menu item for switching buffer
- When deleting a block, the cursor will now end up at the beginning of the next block, instead of at the end of the previous block.
- Added support for the following languages:
* Elixir

View File

@ -5,7 +5,7 @@ import fs from "fs"
import { WINDOW_CLOSE_EVENT, SETTINGS_CHANGE_EVENT } from '@/src/common/constants'
import { menu, getTrayMenu } from './menu'
import { menu, getTrayMenu, getEditorContextMenu } from './menu'
import CONFIG from "../config"
import { isDev, isLinux, isMac, isWindows } from '../detect-platform';
import { initializeAutoUpdate, checkForUpdates } from './auto-update';
@ -376,6 +376,10 @@ ipcMain.handle("setWindowTitle", (event, title) => {
win?.setTitle(title)
})
ipcMain.handle("showEditorContextMenu", () => {
getEditorContextMenu(win).popup({window:win});
})
// Initialize note/file library
async function initFileLibrary(win) {
await migrateBufferFileToLibrary(app)

View File

@ -1,10 +1,51 @@
const { app, Menu } = require("electron")
import { OPEN_SETTINGS_EVENT, REDO_EVENT, MOVE_BLOCK_EVENT } from '@/src/common/constants'
import { OPEN_SETTINGS_EVENT, UNDO_EVENT, REDO_EVENT, MOVE_BLOCK_EVENT, DELETE_BLOCK_EVENT, CHANGE_BUFFER_EVENT } from '@/src/common/constants'
import { openAboutWindow } from "./about";
import { quit } from "./index"
const isMac = process.platform === "darwin"
const undoMenuItem = {
label: 'Undo',
accelerator: 'CommandOrControl+z',
click: (menuItem, window, event) => {
window?.webContents.send(UNDO_EVENT)
},
}
const redoMenuItem = {
label: 'Redo',
accelerator: 'CommandOrControl+Shift+z',
click: (menuItem, window, event) => {
window?.webContents.send(REDO_EVENT)
},
}
const deleteBlockMenuItem = {
label: 'Delete block',
accelerator: 'CommandOrControl+Shift+D',
click: (menuItem, window, event) => {
window?.webContents.send(DELETE_BLOCK_EVENT)
},
}
const moveBlockMenuItem = {
label: 'Move block to another buffer…',
accelerator: 'CommandOrControl+S',
click: (menuItem, window, event) => {
window?.webContents.send(MOVE_BLOCK_EVENT)
},
}
const changeBufferMenuItem = {
label: 'Switch buffer…',
accelerator: 'CommandOrControl+P',
click: (menuItem, window, event) => {
window?.webContents.send(CHANGE_BUFFER_EVENT)
},
}
const template = [
// { role: 'appMenu' }
...(isMac ? [{
@ -18,6 +59,7 @@ const template = [
},
},
{ type: 'separator' },
changeBufferMenuItem,
{
label: 'Settings',
click: (menuItem, window, event) => {
@ -37,6 +79,7 @@ const template = [
}] : [{
role: 'fileMenu',
submenu: [
changeBufferMenuItem,
{
label: 'Settings',
click: (menuItem, window, event) => {
@ -62,22 +105,11 @@ const template = [
{
label: 'Edit',
submenu: [
{ role: 'undo' },
{
label: 'Redo',
accelerator: 'CommandOrControl+Shift+z',
click: (menuItem, window, event) => {
window?.webContents.send(REDO_EVENT)
},
},
undoMenuItem,
redoMenuItem,
{ type: 'separator' },
{
label: 'Move block to another buffer...',
accelerator: 'CommandOrControl+S',
click: (menuItem, window, event) => {
window?.webContents.send(MOVE_BLOCK_EVENT)
},
},
deleteBlockMenuItem,
moveBlockMenuItem,
{ type: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
@ -185,3 +217,18 @@ export function getTrayMenu(win) {
])
}
export function getEditorContextMenu(win) {
return Menu.buildFromTemplate([
undoMenuItem,
redoMenuItem,
{type: 'separator'},
{role: 'cut'},
{role: 'copy'},
{role: 'paste'},
{type: 'separator'},
{role: 'selectAll'},
{type: 'separator'},
deleteBlockMenuItem,
moveBlockMenuItem,
])
}

View File

@ -48,6 +48,10 @@ contextBridge.exposeInMainWorld("heynote", {
off(event, callback) {
ipcRenderer.off(event, callback)
},
invoke(event, ...args) {
return ipcRenderer.invoke(event, ...args)
}
},
buffer: {

View File

@ -5,7 +5,10 @@ export const WINDOW_CLOSE_EVENT = "window-close"
export const OPEN_SETTINGS_EVENT = "open-settings"
export const SETTINGS_CHANGE_EVENT = "settings-change"
export const REDO_EVENT = "redo"
export const UNDO_EVENT = "undo"
export const MOVE_BLOCK_EVENT = "move-block"
export const DELETE_BLOCK_EVENT = "delete-block"
export const CHANGE_BUFFER_EVENT = "change-buffer"
export const UPDATE_AVAILABLE_EVENT = "update-available"
export const UPDATE_NOT_AVAILABLE_EVENT = "update-not-available"

View File

@ -7,7 +7,7 @@
import { useSettingsStore } from "../stores/settings-store"
import { useEditorCacheStore } from '../stores/editor-cache'
import { OPEN_SETTINGS_EVENT, MOVE_BLOCK_EVENT } from '@/src/common/constants'
import { OPEN_SETTINGS_EVENT, MOVE_BLOCK_EVENT, CHANGE_BUFFER_EVENT } from '@/src/common/constants'
import StatusBar from './StatusBar.vue'
import Editor from './Editor.vue'
@ -48,6 +48,10 @@
window.heynote.mainProcess.on(MOVE_BLOCK_EVENT, (path) => {
this.openMoveToBufferSelector()
})
window.heynote.mainProcess.on(CHANGE_BUFFER_EVENT, () => {
this.openBufferSelector()
})
},
beforeUnmount() {

View File

@ -5,7 +5,7 @@
import { useErrorStore } from "../stores/error-store"
import { useHeynoteStore } from "../stores/heynote-store.js"
import { useEditorCacheStore } from "../stores/editor-cache"
import { REDO_EVENT, WINDOW_CLOSE_EVENT } from '@/src/common/constants';
import { REDO_EVENT, WINDOW_CLOSE_EVENT, DELETE_BLOCK_EVENT, UNDO_EVENT } from '@/src/common/constants';
const NUM_EDITOR_INSTANCES = 5
@ -22,7 +22,6 @@
syntaxTreeDebugContent: null,
editor: null,
onWindowClose: null,
onRedo: null,
}
},
@ -38,15 +37,25 @@
[this.editor.path, this.editor.getContent()],
])
}
window.heynote.mainProcess.on(WINDOW_CLOSE_EVENT, this.onWindowClose)
this.onRedo = () => {
window.heynote.mainProcess.on(UNDO_EVENT, () => {
if (this.editor) {
toRaw(this.editor).undo()
}
})
window.heynote.mainProcess.on(REDO_EVENT, () => {
if (this.editor) {
toRaw(this.editor).redo()
}
}
})
window.heynote.mainProcess.on(WINDOW_CLOSE_EVENT, this.onWindowClose)
window.heynote.mainProcess.on(REDO_EVENT, this.onRedo)
window.heynote.mainProcess.on(DELETE_BLOCK_EVENT, () => {
if (this.editor) {
toRaw(this.editor).deleteActiveBlock()
}
})
// if debugSyntaxTree prop is set, display syntax tree for debugging
if (this.debugSyntaxTree) {
@ -70,7 +79,9 @@
beforeUnmount() {
window.heynote.mainProcess.off(WINDOW_CLOSE_EVENT, this.onWindowClose)
window.heynote.mainProcess.off(REDO_EVENT, this.onRedo)
window.heynote.mainProcess.off(UNDO_EVENT)
window.heynote.mainProcess.off(REDO_EVENT)
window.heynote.mainProcess.off(DELETE_BLOCK_EVENT)
this.editorCacheStore.tearDown();
},
@ -138,13 +149,18 @@
focus() {
toRaw(this.editor).focus()
},
onContextMenu(event) {
event.preventDefault()
window.heynote.mainProcess.invoke("showEditorContextMenu")
},
},
}
</script>
<template>
<div>
<div class="editor" ref="editor"></div>
<div class="editor" ref="editor" @contextmenu="onContextMenu"></div>
<div
v-if="debugSyntaxTree"
v-html="syntaxTreeDebugContent"

View File

@ -3,7 +3,7 @@ import { EditorView, keymap, drawSelection, ViewPlugin, lineNumbers } from "@cod
import { indentUnit, forceParsing, foldGutter, ensureSyntaxTree } from "@codemirror/language"
import { markdown } from "@codemirror/lang-markdown"
import { closeBrackets } from "@codemirror/autocomplete";
import { redo } from "@codemirror/commands"
import { undo, redo } from "@codemirror/commands"
import { heynoteLight } from "./theme/light.js"
import { heynoteDark } from "./theme/dark.js"
@ -406,6 +406,10 @@ export class HeynoteEditor {
triggerCursorChange(this.view)
}
undo() {
undo(this.view)
}
redo() {
redo(this.view)
}

View File

@ -227,6 +227,10 @@ const Heynote = {
off(event, callback) {
ipcRenderer.off(event, callback)
},
invoke(event, ...args) {
}
},
settings: initialSettings,