diff --git a/electron/constants.ts b/electron/constants.ts new file mode 100644 index 0000000..2af85cd --- /dev/null +++ b/electron/constants.ts @@ -0,0 +1 @@ +export const WINDOW_CLOSE_EVENT = "window-close" diff --git a/electron/preload/detect-platform.ts b/electron/detect-platform.ts similarity index 100% rename from electron/preload/detect-platform.ts rename to electron/detect-platform.ts diff --git a/src/editor/fixture.js b/electron/initial-content.ts similarity index 79% rename from src/editor/fixture.js rename to electron/initial-content.ts index ced8a58..2e8cc49 100644 --- a/src/editor/fixture.js +++ b/electron/initial-content.ts @@ -1,10 +1,21 @@ -/*export default `∞∞∞text -kuk∞∞∞javascript -oj∞∞∞prutt -hej∞∞∞python -f = lambda: 2 +1`;*/ +import { isMac } from "./detect-platform.js" -export default ` +const modChar = isMac ? "⌘" : "Ctrl" + +export const initialContent = ` +∞∞∞text +Welcome to Heynote! + +[${modChar} + Enter] Insert new note block at cursor +[${modChar} + L] Change block language +[${modChar} + Down] Goto next block +[${modChar} + Up] Goto previous block +[${modChar} + A] Select all text in a note block. Press again to select the whole scratchpad +[${modChar} + ⌥ + Up/Down]  Add additional cursor above/below +∞∞∞text-a +` + +export const initialDevContent = ` ∞∞∞text-a Welcome to Heynote! @@ -98,4 +109,4 @@ Shopping list: - Milk - Eggs - Bread -- Cheese`; +- Cheese` \ No newline at end of file diff --git a/electron/main/index.ts b/electron/main/index.ts index 4d1821e..3b3f486 100644 --- a/electron/main/index.ts +++ b/electron/main/index.ts @@ -1,7 +1,10 @@ import { app, BrowserWindow, shell, ipcMain, Menu, nativeTheme } from 'electron' import { release } from 'node:os' import { join } from 'node:path' +import * as jetpack from "fs-jetpack"; import menu from './menu' +import { initialContent, initialDevContent } from '../initial-content' +import { WINDOW_CLOSE_EVENT } from '../constants'; // The built directory structure // @@ -43,6 +46,9 @@ let win: BrowserWindow | null = null const preload = join(__dirname, '../preload/index.js') const url = process.env.VITE_DEV_SERVER_URL const indexHtml = join(process.env.DIST, 'index.html') +const isDev = !!process.env.VITE_DEV_SERVER_URL +let contentSaved = false + async function createWindow() { win = new BrowserWindow({ @@ -61,6 +67,15 @@ async function createWindow() { }, }) + win.on("close", (event) => { + // Prevent the window from closing, and send a message to the renderer which will in turn + // send a message to the main process to save the current buffer and close the window. + if (!contentSaved) { + event.preventDefault() + } + win?.webContents.send(WINDOW_CLOSE_EVENT) + }) + //nativeTheme.themeSource = "light" if (process.env.VITE_DEV_SERVER_URL) { // electron-vite-vue#298 @@ -108,26 +123,35 @@ app.on('activate', () => { } }) -// New window example arg: new windows url -ipcMain.handle('open-win', (_, arg) => { - const childWindow = new BrowserWindow({ - webPreferences: { - preload, - nodeIntegration: true, - contextIsolation: false, - }, - }) - - if (process.env.VITE_DEV_SERVER_URL) { - childWindow.loadURL(`${url}#${arg}`) - } else { - childWindow.loadFile(indexHtml, { hash: arg }) - } -}) - - ipcMain.handle('dark-mode:set', (event, mode) => { nativeTheme.themeSource = mode }) ipcMain.handle('dark-mode:get', () => nativeTheme.themeSource) + +const bufferPath = isDev ? join(app.getPath("userData"), "buffer-dev.txt") : join(app.getPath("userData"), "buffer.txt") + +ipcMain.handle('buffer-content:load', async () =>  { + if (jetpack.exists(bufferPath) === "file") { + return await jetpack.read(bufferPath, 'utf8') + } else { + return isDev? initialDevContent : initialContent + } +}); + +async function save(content) { + return await jetpack.write(bufferPath, content, { + atomic: true, + mode: '600', + }) +} + +ipcMain.handle('buffer-content:save', async (event, content) =>  { + return await save(content) +}); + +ipcMain.handle('buffer-content:saveAndQuit', async (event, content) => { + await save(content) + contentSaved = true + app.quit() +}) diff --git a/electron/preload/index.ts b/electron/preload/index.ts index 198d937..bdc7f69 100644 --- a/electron/preload/index.ts +++ b/electron/preload/index.ts @@ -1,6 +1,8 @@ const { contextBridge } = require('electron') import darkMode from "./theme-mode" -import { isMac, isWindows, isLinux } from "./detect-platform" +import { isMac, isWindows, isLinux } from "../detect-platform" +import { ipcRenderer } from "electron" +import { WINDOW_CLOSE_EVENT } from "../constants" contextBridge.exposeInMainWorld("platform", { isMac, @@ -9,6 +11,31 @@ contextBridge.exposeInMainWorld("platform", { }) contextBridge.exposeInMainWorld('darkMode', darkMode) +contextBridge.exposeInMainWorld("heynote", { + quit() { + console.log("quitting") + //ipcRenderer.invoke("app_quit") + }, + + onWindowClose(callback) { + ipcRenderer.on(WINDOW_CLOSE_EVENT, callback) + }, + + buffer: { + async load() { + return await ipcRenderer.invoke("buffer-content:load") + }, + + async save(content) { + return await ipcRenderer.invoke("buffer-content:save", content) + }, + + async saveAndQuit(content) { + return await ipcRenderer.invoke("buffer-content:saveAndQuit", content) + }, + } +}) + function domReady(condition: DocumentReadyState[] = ['complete', 'interactive']) { return new Promise((resolve) => { diff --git a/package-lock.json b/package-lock.json index 1874225..b43f565 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,8 +29,10 @@ "@rollup/plugin-node-resolve": "^15.0.1", "@vitejs/plugin-vue": "^4.0.0", "codemirror": "^6.0.1", + "debounce": "^1.2.1", "electron": "^22.0.2", "electron-builder": "^23.6.0", + "fs-jetpack": "^5.1.0", "sass": "^1.57.1", "typescript": "^4.9.4", "vite": "^4.0.3", @@ -2192,6 +2194,12 @@ "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", "dev": true }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "dev": true + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -2830,6 +2838,36 @@ "node": ">=6 <7 || >=8" } }, + "node_modules/fs-jetpack": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/fs-jetpack/-/fs-jetpack-5.1.0.tgz", + "integrity": "sha512-Xn4fDhLydXkuzepZVsr02jakLlmoARPy+YWIclo4kh0GyNGUHnTqeH/w/qIsVn50dFxtp8otPL2t/HcPJBbxUA==", + "dev": true, + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/fs-jetpack/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/fs-jetpack/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", diff --git a/package.json b/package.json index 548885d..221795b 100644 --- a/package.json +++ b/package.json @@ -47,8 +47,10 @@ "@rollup/plugin-node-resolve": "^15.0.1", "@vitejs/plugin-vue": "^4.0.0", "codemirror": "^6.0.1", + "debounce": "^1.2.1", "electron": "^22.0.2", "electron-builder": "^23.6.0", + "fs-jetpack": "^5.1.0", "sass": "^1.57.1", "typescript": "^4.9.4", "vite": "^4.0.3", diff --git a/src/components/Editor.vue b/src/components/Editor.vue index f478040..6058e1c 100644 --- a/src/components/Editor.vue +++ b/src/components/Editor.vue @@ -1,22 +1,5 @@