mirror of
https://github.com/heyman/heynote.git
synced 2025-03-08 20:11:38 +01:00
- 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
289 lines
7.9 KiB
JavaScript
289 lines
7.9 KiB
JavaScript
import { Exception } from "sass";
|
|
import { SETTINGS_CHANGE_EVENT, OPEN_SETTINGS_EVENT } from "@/src/common/constants";
|
|
import { NoteFormat } from "../src/common/note-format";
|
|
|
|
const NOTE_KEY_PREFIX = "heynote-library__"
|
|
|
|
const mediaMatch = window.matchMedia('(prefers-color-scheme: dark)')
|
|
let themeCallback = null
|
|
mediaMatch.addEventListener("change", async (event) => {
|
|
if (themeCallback) {
|
|
themeCallback((await Heynote.themeMode.get()).computed)
|
|
}
|
|
})
|
|
|
|
const isMobileDevice = window.matchMedia("(max-width: 600px)").matches
|
|
|
|
let autoUpdateCallbacks = null
|
|
let currencyData = null
|
|
|
|
let platform
|
|
|
|
// In the latest version of Playwright, the window.navigator.userAgentData.platform is not reported correctly on Mac,
|
|
// wo we'll fallback to deprecated window.navigator.platform which still works
|
|
if (__TESTS__ && window.navigator.platform.indexOf("Mac") !== -1) {
|
|
platform = {
|
|
isMac: true,
|
|
isWindows: false,
|
|
isLinux: false,
|
|
}
|
|
} else {
|
|
const uaPlatform = window.navigator?.userAgentData?.platform || window.navigator.platform
|
|
if (uaPlatform.indexOf("Win") !== -1) {
|
|
platform = {
|
|
isMac: false,
|
|
isWindows: true,
|
|
isLinux: false,
|
|
}
|
|
} else if (uaPlatform.indexOf("Linux") !== -1) {
|
|
platform = {
|
|
isMac: false,
|
|
isWindows: false,
|
|
isLinux: true,
|
|
}
|
|
} else {
|
|
platform = {
|
|
isMac: true,
|
|
isWindows: false,
|
|
isLinux: false,
|
|
}
|
|
}
|
|
}
|
|
platform.isWebApp = true
|
|
|
|
|
|
class IpcRenderer {
|
|
constructor() {
|
|
this.callbacks = {}
|
|
}
|
|
|
|
on(event, callback) {
|
|
if (!this.callbacks[event]) {
|
|
this.callbacks[event] = []
|
|
}
|
|
this.callbacks[event].push(callback)
|
|
}
|
|
|
|
off(event, callback) {
|
|
if (this.callbacks[event]) {
|
|
this.callbacks[event] = this.callbacks[event].filter(cb => cb !== callback)
|
|
}
|
|
}
|
|
|
|
send(event, ...args) {
|
|
if (this.callbacks[event]) {
|
|
for (const callback of this.callbacks[event]) {
|
|
callback(null, ...args)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const ipcRenderer = new IpcRenderer()
|
|
|
|
// get initial settings
|
|
let settingsData = localStorage.getItem("settings")
|
|
let initialSettings = {
|
|
keymap: "default",
|
|
emacsMetaKey: "alt",
|
|
showLineNumberGutter: true,
|
|
showFoldGutter: true,
|
|
bracketClosing: false,
|
|
}
|
|
if (settingsData !== null) {
|
|
initialSettings = Object.assign(initialSettings, JSON.parse(settingsData))
|
|
}
|
|
|
|
function noteKey(path) {
|
|
return NOTE_KEY_PREFIX + path
|
|
}
|
|
|
|
function getNoteMetadata(content) {
|
|
const firstSeparator = content.indexOf("\n∞∞∞")
|
|
if (firstSeparator === -1) {
|
|
return null
|
|
}
|
|
try {
|
|
const metadata = JSON.parse(content.slice(0, firstSeparator).trim())
|
|
return {"name": metadata.name}
|
|
} catch (e) {
|
|
return {}
|
|
}
|
|
}
|
|
|
|
// Migrate single buffer (Heynote pre 2.0) in localStorage to notes library
|
|
// At some point we can remove this migration code
|
|
function migrateBufferFileToLibrary() {
|
|
if (!("buffer" in localStorage)) {
|
|
// nothing to migrate
|
|
return
|
|
}
|
|
if (Object.keys(localStorage).filter(key => key.startsWith(NOTE_KEY_PREFIX)).length > 0) {
|
|
// already migrated
|
|
return
|
|
}
|
|
|
|
console.log("Migrating single buffer to notes library")
|
|
|
|
let content = localStorage.getItem("buffer")
|
|
const metadata = getNoteMetadata(content)
|
|
if (!metadata || !metadata.name) {
|
|
console.log("Adding metadata to Scratch note")
|
|
const note = NoteFormat.load(content)
|
|
note.metadata.name = "Scratch"
|
|
content = note.serialize()
|
|
}
|
|
localStorage.setItem("heynote-library__scratch.txt", content)
|
|
localStorage.removeItem("buffer")
|
|
}
|
|
migrateBufferFileToLibrary()
|
|
|
|
const Heynote = {
|
|
platform: platform,
|
|
defaultFontFamily: "Hack",
|
|
defaultFontSize: isMobileDevice ? 16 : 12,
|
|
|
|
buffer: {
|
|
async load(path) {
|
|
//console.log("loading", path)
|
|
const content = localStorage.getItem(noteKey(path))
|
|
return content === null ? '{"formatVersion":"1.0.0","name":"Scratch"}\n∞∞∞text-a\n' : content
|
|
},
|
|
|
|
async save(path, content) {
|
|
//console.log("saving", path, content)
|
|
localStorage.setItem(noteKey(path), content)
|
|
},
|
|
|
|
async create(path, content) {
|
|
localStorage.setItem(noteKey(path), content)
|
|
},
|
|
|
|
async delete(path) {
|
|
localStorage.removeItem(noteKey(path))
|
|
},
|
|
|
|
async move(path, newPath) {
|
|
const content = localStorage.getItem(noteKey(path))
|
|
localStorage.setItem(noteKey(newPath), content)
|
|
localStorage.removeItem(noteKey(path))
|
|
},
|
|
|
|
async saveAndQuit(contents) {
|
|
|
|
},
|
|
|
|
async exists(path) {
|
|
return localStorage.getItem(noteKey(path)) !== null
|
|
},
|
|
|
|
async getList() {
|
|
//return {"scratch.txt": {name:"Scratch"}}
|
|
const notes = {}
|
|
for (let [key, content] of Object.entries(localStorage)) {
|
|
if (key.startsWith(NOTE_KEY_PREFIX)) {
|
|
const path = key.slice(NOTE_KEY_PREFIX.length)
|
|
notes[path] = getNoteMetadata(content)
|
|
}
|
|
}
|
|
return notes
|
|
},
|
|
|
|
async getDirectoryList() {
|
|
const directories = new Set()
|
|
for (let key in localStorage) {
|
|
if (key.startsWith(NOTE_KEY_PREFIX)) {
|
|
const path = key.slice(NOTE_KEY_PREFIX.length)
|
|
const parts = path.split("/")
|
|
if (parts.length > 1) {
|
|
for (let i = 1; i < parts.length; i++) {
|
|
directories.add(parts.slice(0, i).join("/"))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//console.log("directories", directories)
|
|
return [...directories]
|
|
},
|
|
|
|
async close(path) {
|
|
|
|
},
|
|
|
|
_onChangeCallbacks: {},
|
|
addOnChangeCallback(path, callback) {
|
|
|
|
},
|
|
removeOnChangeCallback(path, callback) {
|
|
|
|
},
|
|
},
|
|
|
|
mainProcess: {
|
|
on(event, callback) {
|
|
ipcRenderer.on(event, callback)
|
|
},
|
|
|
|
off(event, callback) {
|
|
ipcRenderer.off(event, callback)
|
|
},
|
|
|
|
invoke(event, ...args) {
|
|
|
|
}
|
|
},
|
|
|
|
settings: initialSettings,
|
|
|
|
setSettings(settings) {
|
|
localStorage.setItem("settings", JSON.stringify(settings))
|
|
ipcRenderer.send(SETTINGS_CHANGE_EVENT, settings)
|
|
},
|
|
|
|
themeMode: {
|
|
set: (mode) => {
|
|
localStorage.setItem("theme", mode)
|
|
themeCallback(mode)
|
|
//console.log("set theme to", mode)
|
|
},
|
|
get: async () => {
|
|
const theme = localStorage.getItem("theme") || "system"
|
|
const systemTheme = mediaMatch.matches ? "dark" : "light"
|
|
return {
|
|
theme: theme,
|
|
computed: theme === "system" ? systemTheme : theme,
|
|
}
|
|
},
|
|
onChange: (callback) => {
|
|
themeCallback = callback
|
|
},
|
|
removeListener() {
|
|
themeCallback = null
|
|
},
|
|
initial: localStorage.getItem("theme") || "system",
|
|
},
|
|
|
|
getCurrencyData: async () => {
|
|
if (currencyData !== null) {
|
|
return currencyData
|
|
}
|
|
const response = await fetch("https://currencies.heynote.com/rates.json", {cache: "no-cache"})
|
|
currencyData = JSON.parse(await response.text())
|
|
return currencyData
|
|
},
|
|
|
|
async getVersion() {
|
|
return __APP_VERSION__ + " (" + __GIT_HASH__ + ")"
|
|
},
|
|
|
|
async getInitErrors() {
|
|
|
|
},
|
|
|
|
setWindowTitle(title) {
|
|
document.title = title + " - Heynote"
|
|
},
|
|
}
|
|
|
|
export { Heynote, ipcRenderer}
|