test supabase plugin
This commit is contained in:
2
.env
2
.env
@@ -1 +1,3 @@
|
||||
VITE_DEV_SERVER_URL=http://localhost:5173
|
||||
SUPABASE_KEY='sb_secret_xYDyNcB7Q46ZYhDISeXRHQ_95l-N33m'
|
||||
SUPABASE_URL='https://jmuadfpmmejfvkwosaqh.supabase.co'
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,6 +7,7 @@ yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
.env
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# app.takerofnotes.com
|
||||
# Taker of Notes App
|
||||
|
||||
An Electron application with Vue
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import "dotenv/config";
|
||||
import { electronApp, optimizer, is } from "@electron-toolkit/utils";
|
||||
import { app, BrowserWindow, ipcMain, shell } from "electron";
|
||||
import { app, ipcMain, BrowserWindow, shell } from "electron";
|
||||
import filesystemPlugin from "@takerofnotes/plugin-filesystem";
|
||||
import supabasePlugin from "@takerofnotes/plugin-supabase";
|
||||
import fs from "fs/promises";
|
||||
import path, { join } from "path";
|
||||
import { Index } from "flexsearch";
|
||||
@@ -227,22 +229,18 @@ function createNoteWindow(noteId) {
|
||||
}
|
||||
}
|
||||
app.whenReady().then(async () => {
|
||||
electronApp.setAppUserModelId("com.electron");
|
||||
app.on("browser-window-created", (_, window) => {
|
||||
optimizer.watchWindowShortcuts(window);
|
||||
});
|
||||
createWindow();
|
||||
app.on("activate", function() {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow();
|
||||
});
|
||||
ipcMain.on("open-note-window", (_, noteId) => {
|
||||
createNoteWindow(noteId);
|
||||
});
|
||||
const registry = new PluginRegistry();
|
||||
registry.register(filesystemPlugin);
|
||||
const config = await new PluginConfig(filesystemPlugin).load();
|
||||
const plugin = registry.get(config.activeAdapter);
|
||||
const adapter = plugin.createAdapter(config.adapterConfig);
|
||||
registry.register(supabasePlugin);
|
||||
await new PluginConfig(filesystemPlugin).load();
|
||||
const plugin = registry.get(supabasePlugin.id);
|
||||
const adapter = plugin.createAdapter({
|
||||
supabaseKey: process.env.SUPABASE_KEY,
|
||||
supabaseUrl: process.env.SUPABASE_URL
|
||||
});
|
||||
const notesAPI = new NotesAPI(adapter);
|
||||
await notesAPI.init();
|
||||
ipcMain.handle("notesAPI:call", (_, method, args) => {
|
||||
@@ -251,6 +249,14 @@ app.whenReady().then(async () => {
|
||||
}
|
||||
return notesAPI[method](...args);
|
||||
});
|
||||
electronApp.setAppUserModelId("com.electron");
|
||||
app.on("browser-window-created", (_, window) => {
|
||||
optimizer.watchWindowShortcuts(window);
|
||||
});
|
||||
createWindow();
|
||||
app.on("activate", function() {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow();
|
||||
});
|
||||
});
|
||||
app.on("window-all-closed", () => {
|
||||
if (process.platform !== "darwin") {
|
||||
|
||||
203
package-lock.json
generated
203
package-lock.json
generated
@@ -13,6 +13,7 @@
|
||||
"@electron-toolkit/utils": "^4.0.0",
|
||||
"@fuzzco/font-loader": "^1.0.2",
|
||||
"@takerofnotes/plugin-filesystem": "^0.1.1",
|
||||
"@takerofnotes/plugin-supabase": "^0.1.0",
|
||||
"@tiptap/extension-document": "^3.19.0",
|
||||
"@tiptap/extension-image": "^3.19.0",
|
||||
"@tiptap/extension-table": "^3.19.0",
|
||||
@@ -20,6 +21,7 @@
|
||||
"@tiptap/starter-kit": "^3.19.0",
|
||||
"@tiptap/vue-3": "^3.19.0",
|
||||
"@vueuse/core": "^14.2.1",
|
||||
"dotenv": "^17.3.1",
|
||||
"electron-updater": "^6.3.9",
|
||||
"fecha": "^4.2.3",
|
||||
"flexsearch": "^0.8.212",
|
||||
@@ -2248,6 +2250,86 @@
|
||||
"url": "https://github.com/sindresorhus/is?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/auth-js": {
|
||||
"version": "2.98.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.98.0.tgz",
|
||||
"integrity": "sha512-GBH361T0peHU91AQNzOlIrjUZw9TZbB9YDRiyFgk/3Kvr3/Z1NWUZ2athWTfHhwNNi8IrW00foyFxQD9IO/Trg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/functions-js": {
|
||||
"version": "2.98.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.98.0.tgz",
|
||||
"integrity": "sha512-N/xEyiNU5Org+d+PNCpv+TWniAXRzxIURxDYsS/m2I/sfAB/HcM9aM2Dmf5edj5oWb9GxID1OBaZ8NMmPXL+Lg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/postgrest-js": {
|
||||
"version": "2.98.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.98.0.tgz",
|
||||
"integrity": "sha512-v6e9WeZuJijzUut8HyXu6gMqWFepIbaeaMIm1uKzei4yLg9bC9OtEW9O14LE/9ezqNbSAnSLO5GtOLFdm7Bpkg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/realtime-js": {
|
||||
"version": "2.98.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.98.0.tgz",
|
||||
"integrity": "sha512-rOWt28uGyFipWOSd+n0WVMr9kUXiWaa7J4hvyLCIHjRFqWm1z9CaaKAoYyfYMC1Exn3WT8WePCgiVhlAtWC2yw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/phoenix": "^1.6.6",
|
||||
"@types/ws": "^8.18.1",
|
||||
"tslib": "2.8.1",
|
||||
"ws": "^8.18.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/storage-js": {
|
||||
"version": "2.98.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.98.0.tgz",
|
||||
"integrity": "sha512-tzr2mG+v7ILSAZSfZMSL9OPyIH4z1ikgQ8EcQTKfMRz4EwmlFt3UnJaGzSOxyvF5b+fc9So7qdSUWTqGgeLokQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"iceberg-js": "^0.8.1",
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/supabase-js": {
|
||||
"version": "2.98.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.98.0.tgz",
|
||||
"integrity": "sha512-Ohc97CtInLwZyiSASz7tT9/Abm/vqnIbO9REp+PivVUII8UZsuI3bngRQnYgJdFoOIwvaEII1fX1qy8x0CyNiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@supabase/auth-js": "2.98.0",
|
||||
"@supabase/functions-js": "2.98.0",
|
||||
"@supabase/postgrest-js": "2.98.0",
|
||||
"@supabase/realtime-js": "2.98.0",
|
||||
"@supabase/storage-js": "2.98.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@szmarczak/http-timer": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
|
||||
@@ -2279,17 +2361,36 @@
|
||||
"zod": "^4.3.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@takerofnotes/plugin-supabase": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@takerofnotes/plugin-supabase/-/plugin-supabase-0.1.0.tgz",
|
||||
"integrity": "sha512-NXmiyOAjVHXSFyzOPwljngrjwe1KZEzFiQjImI5XbjxtMJiAg6TFSbqLAnZaIZqg2WpAcBdZKy941WmkXJfNXA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@supabase/supabase-js": "^2.98.0",
|
||||
"@takerofnotes/plugin-sdk": "^0.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@takerofnotes/plugin-supabase/node_modules/@takerofnotes/plugin-sdk": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@takerofnotes/plugin-sdk/-/plugin-sdk-0.2.0.tgz",
|
||||
"integrity": "sha512-6Ll+EnO/9B51jf3tKXGkByj9lRTodYJogIuCJ1xh7uTxorJ5tcpBXv49dtXNYmGYEtpVt80G26/kQzm3J54DoA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"zod": "^4.3.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/core": {
|
||||
"version": "3.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.19.0.tgz",
|
||||
"integrity": "sha512-bpqELwPW+DG8gWiD8iiFtSl4vIBooG5uVJod92Qxn3rA9nFatyXRr4kNbMJmOZ66ezUvmCjXVe/5/G4i5cyzKA==",
|
||||
"version": "3.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.20.0.tgz",
|
||||
"integrity": "sha512-aC9aROgia/SpJqhsXFiX9TsligL8d+oeoI8W3u00WI45s0VfsqjgeKQLDLF7Tu7hC+7F02teC84SAHuup003VQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/pm": "^3.19.0"
|
||||
"@tiptap/pm": "^3.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-blockquote": {
|
||||
@@ -2515,17 +2616,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-list": {
|
||||
"version": "3.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.19.0.tgz",
|
||||
"integrity": "sha512-N6nKbFB2VwMsPlCw67RlAtYSK48TAsAUgjnD+vd3ieSlIufdQnLXDFUP6hFKx9mwoUVUgZGz02RA6bkxOdYyTw==",
|
||||
"version": "3.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.20.0.tgz",
|
||||
"integrity": "sha512-+V0/gsVWAv+7vcY0MAe6D52LYTIicMSHw00wz3ISZgprSb2yQhJ4+4gurOnUrQ4Du3AnRQvxPROaofwxIQ66WQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.19.0",
|
||||
"@tiptap/pm": "^3.19.0"
|
||||
"@tiptap/core": "^3.20.0",
|
||||
"@tiptap/pm": "^3.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-list-item": {
|
||||
@@ -2665,9 +2766,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/pm": {
|
||||
"version": "3.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.19.0.tgz",
|
||||
"integrity": "sha512-789zcnM4a8OWzvbD2DL31d0wbSm9BVeO/R7PLQwLIGysDI3qzrcclyZ8yhqOEVuvPitRRwYLq+mY14jz7kY4cw==",
|
||||
"version": "3.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.20.0.tgz",
|
||||
"integrity": "sha512-jn+2KnQZn+b+VXr8EFOJKsnjVNaA4diAEr6FOazupMt8W8ro1hfpYtZ25JL87Kao/WbMze55sd8M8BDXLUKu1A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-changeset": "^2.3.0",
|
||||
@@ -2842,6 +2943,12 @@
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/phoenix": {
|
||||
"version": "1.6.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.7.tgz",
|
||||
"integrity": "sha512-oN9ive//QSBkf19rfDv45M7eZPi0eEXylht2OLEXicu5b4KoQ1OzXIw+xDSGWxSxe1JmepRR/ZH283vsu518/Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/plist": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.5.tgz",
|
||||
@@ -2877,6 +2984,15 @@
|
||||
"integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
"version": "8.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
|
||||
"integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/yauzl": {
|
||||
"version": "2.10.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
|
||||
@@ -3326,6 +3442,19 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/app-builder-lib/node_modules/dotenv": {
|
||||
"version": "16.6.1",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
|
||||
"integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/app-builder-lib/node_modules/fs-extra": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
|
||||
@@ -4435,10 +4564,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.6.1",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
|
||||
"integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
|
||||
"dev": true,
|
||||
"version": "17.3.1",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz",
|
||||
"integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
@@ -4463,6 +4591,19 @@
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv-expand/node_modules/dotenv": {
|
||||
"version": "16.6.1",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
|
||||
"integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
@@ -5683,6 +5824,15 @@
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/iceberg-js": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz",
|
||||
"integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-corefoundation": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz",
|
||||
@@ -9461,6 +9611,27 @@
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.19.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
|
||||
"integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xmlbuilder": {
|
||||
"version": "15.1.1",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz",
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"@electron-toolkit/utils": "^4.0.0",
|
||||
"@fuzzco/font-loader": "^1.0.2",
|
||||
"@takerofnotes/plugin-filesystem": "^0.1.1",
|
||||
"@takerofnotes/plugin-supabase": "^0.1.0",
|
||||
"@tiptap/extension-document": "^3.19.0",
|
||||
"@tiptap/extension-image": "^3.19.0",
|
||||
"@tiptap/extension-table": "^3.19.0",
|
||||
@@ -36,6 +37,7 @@
|
||||
"@tiptap/starter-kit": "^3.19.0",
|
||||
"@tiptap/vue-3": "^3.19.0",
|
||||
"@vueuse/core": "^14.2.1",
|
||||
"dotenv": "^17.3.1",
|
||||
"electron-updater": "^6.3.9",
|
||||
"fecha": "^4.2.3",
|
||||
"flexsearch": "^0.8.212",
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'dotenv/config'
|
||||
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
|
||||
import { app, shell, BrowserWindow, ipcMain } from 'electron'
|
||||
import filesystemPlugin from '@takerofnotes/plugin-filesystem'
|
||||
import supabasePlugin from '@takerofnotes/plugin-supabase'
|
||||
import PluginRegistry from './core/PluginRegistry.js'
|
||||
import PluginConfig from './core/PluginConfig.js'
|
||||
import NotesAPI from './core/NotesAPI.js'
|
||||
@@ -64,18 +66,6 @@ function createNoteWindow(noteId) {
|
||||
}
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
electronApp.setAppUserModelId('com.electron')
|
||||
|
||||
app.on('browser-window-created', (_, window) => {
|
||||
optimizer.watchWindowShortcuts(window)
|
||||
})
|
||||
|
||||
createWindow()
|
||||
|
||||
app.on('activate', function () {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
|
||||
// Open note in new window
|
||||
ipcMain.on('open-note-window', (_, noteId) => {
|
||||
createNoteWindow(noteId)
|
||||
@@ -86,13 +76,19 @@ app.whenReady().then(async () => {
|
||||
|
||||
// Register built-in plugins
|
||||
registry.register(filesystemPlugin)
|
||||
registry.register(supabasePlugin)
|
||||
|
||||
// Pull plugin config
|
||||
const config = await new PluginConfig(filesystemPlugin).load()
|
||||
|
||||
// Create instance of active adapter
|
||||
const plugin = registry.get(config.activeAdapter)
|
||||
const adapter = plugin.createAdapter(config.adapterConfig)
|
||||
// const plugin = registry.get(config.activeAdapter)
|
||||
const plugin = registry.get(supabasePlugin.id)
|
||||
// const adapter = plugin.createAdapter(config.adapterConfig)
|
||||
const adapter = plugin.createAdapter({
|
||||
supabaseKey: process.env.SUPABASE_KEY,
|
||||
supabaseUrl: process.env.SUPABASE_URL,
|
||||
})
|
||||
|
||||
// Init Notes API
|
||||
const notesAPI = new NotesAPI(adapter)
|
||||
@@ -105,6 +101,18 @@ app.whenReady().then(async () => {
|
||||
}
|
||||
return notesAPI[method](...args)
|
||||
})
|
||||
|
||||
electronApp.setAppUserModelId('com.electron')
|
||||
|
||||
app.on('browser-window-created', (_, window) => {
|
||||
optimizer.watchWindowShortcuts(window)
|
||||
})
|
||||
|
||||
createWindow()
|
||||
|
||||
app.on('activate', function () {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
<template>
|
||||
<lenis root :options="{ duration: 1 }">
|
||||
<div :class="classes" :style="styles">
|
||||
<Nav />
|
||||
|
||||
<router-view :key="$route.fullPath" />
|
||||
|
||||
<Menu />
|
||||
|
||||
<ScrollBar />
|
||||
</div>
|
||||
</lenis>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Lenis from './components/Lenis.vue'
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import loadFonts from '@fuzzco/font-loader'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
import Menu from '@/components/menu/Index.vue'
|
||||
import Nav from '@/components/Nav.vue'
|
||||
import ScrollBar from './components/ScrollBar.vue'
|
||||
|
||||
const { height } = useWindowSize()
|
||||
|
||||
|
||||
@@ -5,25 +5,31 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import useMenu from '@/composables/useMenu'
|
||||
import { onMounted } from 'vue'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const { menuOpen, closeMenu, openMenu } = useMenu()
|
||||
|
||||
const toggleMenu = () => {
|
||||
const state = route.query.menuOpen
|
||||
|
||||
if (state === 'true') {
|
||||
router.push({ query: { menuOpen: false } })
|
||||
if (menuOpen.value) {
|
||||
closeMenu()
|
||||
} else {
|
||||
router.push({ query: { menuOpen: true } })
|
||||
openMenu()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// Initialize menu state or perform any other necessary setup
|
||||
// Example: Check if the user is logged in and update menu accordingly
|
||||
// if (isLoggedIn()) {
|
||||
// openMenu()
|
||||
// }
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.nav {
|
||||
margin-top: size-vw(9px);
|
||||
padding-top: size-vw(9px);
|
||||
color: var(--grey-100);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -6,13 +6,19 @@
|
||||
import useOpenNote from '@/composables/useOpenNote'
|
||||
import useNotes from '@/composables/useNotes'
|
||||
|
||||
const props = defineProps({ category: String })
|
||||
const emit = defineEmits(['noteOpened'])
|
||||
|
||||
const { createNote } = useNotes()
|
||||
const { openNote } = useOpenNote()
|
||||
|
||||
const onClick = async () => {
|
||||
const note = await createNote({}, '')
|
||||
const note = await createNote(
|
||||
{
|
||||
category: props.category ?? null,
|
||||
},
|
||||
'',
|
||||
)
|
||||
openNote(note.id)
|
||||
emit('noteOpened')
|
||||
}
|
||||
|
||||
97
src/renderer/src/components/ScrollBar.vue
Normal file
97
src/renderer/src/components/ScrollBar.vue
Normal file
@@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<div v-if="showScrollBar" class="scroll-bar">
|
||||
<div class="inner" ref="inner">
|
||||
<div class="handle" ref="handle" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onBeforeUnmount, computed, watch } from 'vue'
|
||||
import { useElementSize, useWindowScroll, useWindowSize } from '@vueuse/core'
|
||||
import Tempus from 'tempus'
|
||||
import { useDragControls } from '@/composables/useDragControls'
|
||||
|
||||
const inner = ref()
|
||||
const handle = ref()
|
||||
|
||||
// Sizing
|
||||
const { height: wHeight } = useWindowSize()
|
||||
const { y: scrollY } = useWindowScroll()
|
||||
const { height: documentHeight } = useElementSize(document.documentElement)
|
||||
const { height: innerHeight } = useElementSize(inner)
|
||||
const { height: handleHeight } = useElementSize(handle)
|
||||
|
||||
// Drag controls
|
||||
// useDragControls({
|
||||
// target: handle,
|
||||
// onUpdate: ({ y }) => {
|
||||
// console.log(y.value)
|
||||
// },
|
||||
// })
|
||||
|
||||
const updateScrollbar = () => {
|
||||
const scrollHeight = documentHeight.value
|
||||
const viewportHeight = wHeight.value
|
||||
const limit = scrollHeight - viewportHeight
|
||||
|
||||
if (limit <= 0) return
|
||||
|
||||
const progress = scrollY.value / limit
|
||||
|
||||
if (handle.value) {
|
||||
handle.value.style.transform = `translate3d(0,${
|
||||
progress * (innerHeight.value - handleHeight.value)
|
||||
}px,0)`
|
||||
}
|
||||
}
|
||||
|
||||
const showScrollBar = computed(() => {
|
||||
return documentHeight.value > wHeight.value
|
||||
})
|
||||
|
||||
// RAF
|
||||
const removeRaf = ref()
|
||||
const addRaf = () => (removeRaf.value = Tempus.add(updateScrollbar))
|
||||
onBeforeUnmount(() => {
|
||||
removeRaf.value?.()
|
||||
})
|
||||
watch(
|
||||
showScrollBar,
|
||||
(show) => {
|
||||
if (show) {
|
||||
addRaf()
|
||||
} else {
|
||||
removeRaf.value?.()
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.scroll-bar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: size-vw(8px);
|
||||
will-change: transform;
|
||||
border-left: 1px solid var(--grey-100);
|
||||
|
||||
.inner {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
|
||||
.handle {
|
||||
width: 100%;
|
||||
height: size-vw(388px);
|
||||
background: var(--grey-100);
|
||||
border-radius: 20px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
will-change: transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,15 +1,17 @@
|
||||
<template>
|
||||
<transition name="menu">
|
||||
<div v-if="open" class="menu" ref="container">
|
||||
<div v-if="menuOpen" class="menu" ref="container">
|
||||
<Nav />
|
||||
|
||||
<div class="menu-wrap layout-block-inner">
|
||||
<new-note @noteOpened="closeMenu" />
|
||||
<button>+ New Capitulum</button>
|
||||
<button>Change Theme</button>
|
||||
<button>Instructio</button>
|
||||
<button>Import</button>
|
||||
<button>Export</button>
|
||||
<new-note class="menu-item" @noteOpened="closeMenu" />
|
||||
<button class="menu-item">+ New Capitulum</button>
|
||||
<button class="menu-item">Change Theme</button>
|
||||
<router-link class="menu-item" to="/instructions"
|
||||
>Instructio</router-link
|
||||
>
|
||||
<button class="menu-item">Import</button>
|
||||
<button class="menu-item">Export</button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
@@ -18,30 +20,30 @@
|
||||
<script setup>
|
||||
import NewNote from '@/components/NewNote.vue'
|
||||
import { onClickOutside } from '@vueuse/core'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { ref, watch } from 'vue'
|
||||
import Nav from '../Nav.vue'
|
||||
import useMenu from '@/composables/useMenu'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
const container = ref()
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const closeMenu = () => {
|
||||
router.push({
|
||||
query: {
|
||||
menuOpen: false,
|
||||
},
|
||||
})
|
||||
}
|
||||
const { menuOpen, closeMenu } = useMenu()
|
||||
|
||||
// Close on click outside
|
||||
onClickOutside(container, () => {
|
||||
if (!open.value) return
|
||||
|
||||
closeMenu()
|
||||
})
|
||||
|
||||
const open = computed(() => route.query.menuOpen === 'true')
|
||||
// Close on route change
|
||||
const route = useRoute()
|
||||
watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
closeMenu()
|
||||
},
|
||||
)
|
||||
|
||||
const openNewCategory = () => {}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@@ -59,13 +61,17 @@ const open = computed(() => route.query.menuOpen === 'true')
|
||||
padding-top: size-vw(3px);
|
||||
padding-bottom: size-vw(10px);
|
||||
|
||||
button {
|
||||
.menu-item {
|
||||
display: block;
|
||||
padding: size-vw(16px) 0;
|
||||
text-align: center;
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px dashed currentColor;
|
||||
}
|
||||
&:hover {
|
||||
color: var(--theme-accent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
77
src/renderer/src/composables/useDragControls.js
Normal file
77
src/renderer/src/composables/useDragControls.js
Normal file
@@ -0,0 +1,77 @@
|
||||
import { useEventListener } from '@vueuse/core'
|
||||
import { onMounted, ref, unref } from 'vue'
|
||||
|
||||
export function useDragControls(options = {}) {
|
||||
const { target = null, onUpdate = () => {} } = options
|
||||
|
||||
const x = ref(0)
|
||||
const y = ref(0)
|
||||
const isDragging = ref(false)
|
||||
|
||||
let bounds = null
|
||||
|
||||
const updateBounds = () => {
|
||||
if (target) {
|
||||
bounds = unref(target).getBoundingClientRect()
|
||||
} else {
|
||||
bounds = new DOMRect(0, 0, window.innerWidth, window.innerHeight)
|
||||
}
|
||||
}
|
||||
|
||||
const updatePosition = (clientX, clientY) => {
|
||||
if (!bounds) return
|
||||
|
||||
const relativeX = (clientX - bounds.left) / bounds.width
|
||||
const relativeY = (clientY - bounds.top) / bounds.height
|
||||
|
||||
// Clamp between 0 and 1
|
||||
x.value = Math.min(1, Math.max(0, relativeX))
|
||||
y.value = Math.min(1, Math.max(0, relativeY))
|
||||
|
||||
onUpdate?.({ x, y })
|
||||
}
|
||||
|
||||
const start = (e) => {
|
||||
isDragging.value = true
|
||||
updateBounds()
|
||||
move(e)
|
||||
}
|
||||
|
||||
const move = (e) => {
|
||||
if (!isDragging.value) return
|
||||
if (e instanceof MouseEvent) {
|
||||
updatePosition(e.clientX, e.clientY)
|
||||
} else {
|
||||
const touch = e.touches[0]
|
||||
if (touch) updatePosition(touch.clientX, touch.clientY)
|
||||
}
|
||||
}
|
||||
|
||||
const end = () => {
|
||||
isDragging.value = false
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const el = target ?? window
|
||||
|
||||
// Mouse
|
||||
useEventListener(el, 'mousedown', start)
|
||||
useEventListener(window, 'mousemove', move)
|
||||
useEventListener(window, 'mouseup', end)
|
||||
|
||||
// Touch
|
||||
useEventListener(el, 'touchstart', start, { passive: true })
|
||||
useEventListener(window, 'touchmove', move, { passive: true })
|
||||
useEventListener(window, 'touchend', end)
|
||||
useEventListener(window, 'touchcancel', end)
|
||||
|
||||
// Resize
|
||||
useEventListener(window, 'resize', updateBounds)
|
||||
})
|
||||
|
||||
return {
|
||||
x,
|
||||
y,
|
||||
isDragging,
|
||||
}
|
||||
}
|
||||
29
src/renderer/src/composables/useMenu.js
Normal file
29
src/renderer/src/composables/useMenu.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import _without from 'lodash/without'
|
||||
import { computed } from 'vue'
|
||||
|
||||
export default () => {
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const menuOpen = computed(() => route.query.menuOpen === 'true')
|
||||
|
||||
const closeMenu = () => {
|
||||
router.push({
|
||||
query: _without(route.query, 'menuOpen'),
|
||||
})
|
||||
}
|
||||
const openMenu = () => {
|
||||
router.push({
|
||||
query: {
|
||||
menuOpen: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
menuOpen,
|
||||
closeMenu,
|
||||
openMenu,
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,13 @@ import { createRouter, createWebHistory } from 'vue-router'
|
||||
import Directory from '@/views/Directory.vue'
|
||||
import Editor from '@/views/Editor.vue'
|
||||
import Category from '@/views/Category.vue'
|
||||
import Instructions from '@/views/Instructions.vue'
|
||||
|
||||
const routes = [
|
||||
{ path: '/', name: 'directory', component: Directory },
|
||||
{ path: '/note/:id', name: 'note', component: Editor },
|
||||
{ path: '/category/:id', name: 'category', component: Category },
|
||||
{ path: '/instructions', name: 'instructions', component: Instructions },
|
||||
]
|
||||
|
||||
export const router = createRouter({
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
html {
|
||||
&:not(.dev) {
|
||||
&,
|
||||
* {
|
||||
scrollbar-width: none !important;
|
||||
@@ -10,7 +9,6 @@ html {
|
||||
height: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
html.lenis {
|
||||
|
||||
@@ -57,6 +57,10 @@ pre {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// Text selection
|
||||
::selection {
|
||||
color: var(--theme-bg);
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
<div class="notes">
|
||||
<note-row v-for="note in notes" :note="note" :key="note.id" />
|
||||
</div>
|
||||
|
||||
<new-note :category="id" />
|
||||
</main>
|
||||
</template>
|
||||
|
||||
@@ -15,7 +17,8 @@ import { computed, onMounted, ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import useNotes from '@/composables/useNotes'
|
||||
import NoteRow from '@/components/NoteRow.vue'
|
||||
import CategoryRow from '../components/CategoryRow.vue'
|
||||
import CategoryRow from '@/components/CategoryRow.vue'
|
||||
import NewNote from '@/components/NewNote.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const id = route.params.id
|
||||
@@ -34,7 +37,7 @@ const categoryIndex = computed(() => {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.category {
|
||||
main.category {
|
||||
.back {
|
||||
display: block;
|
||||
opacity: 0.25;
|
||||
@@ -49,5 +52,9 @@ const categoryIndex = computed(() => {
|
||||
gap: size-vw(14px);
|
||||
margin-top: size-vw(9px);
|
||||
}
|
||||
.new-note {
|
||||
display: block;
|
||||
margin: size-vw(50px) auto 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -32,7 +32,7 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.directory {
|
||||
main.directory {
|
||||
padding-top: size-vw(18px);
|
||||
|
||||
.label {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div v-if="editor" class="editor layout-block">
|
||||
<main v-if="editor" class="editor layout-block">
|
||||
<bubble-menu :editor="editor">
|
||||
<div class="bubble-menu">
|
||||
<button
|
||||
@@ -18,7 +18,7 @@
|
||||
</bubble-menu>
|
||||
|
||||
<editor-content :editor="editor" class="editor-wrap" />
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -90,7 +90,7 @@ onMounted(async () => {
|
||||
}
|
||||
},
|
||||
}),
|
||||
Markdown,
|
||||
Markdown.configure({}),
|
||||
Image,
|
||||
],
|
||||
content: note.content,
|
||||
@@ -104,7 +104,7 @@ onBeforeUnmount(() => {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.editor {
|
||||
main.editor {
|
||||
padding-top: size-vw(8px);
|
||||
padding-bottom: size-vw(20px);
|
||||
|
||||
|
||||
74
src/renderer/src/views/Instructions.vue
Normal file
74
src/renderer/src/views/Instructions.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<main class="instructions layout-block-inner">
|
||||
<router-link class="back-link" to="/"><- Go Back</router-link>
|
||||
|
||||
<p>
|
||||
Medieval Translation Nota = Note Capitulum = Category Intructio =
|
||||
Instructions Tabula = Index/Overview *This can be disabled via
|
||||
toolbar -------------------------------------------- Program Key
|
||||
Commands cmd + s = save cmd + t = new capitulum cmd + n = new nota
|
||||
cmd + x = close window dbl click = change name / open nota paste
|
||||
hyperlink twice = activated url
|
||||
-------------------------------------------- Text Markdowns cmd + b
|
||||
= Bold cmd + u = underline --- = ---------- (ruled line break)
|
||||
/*text*/ = Desaturated text
|
||||
</p>
|
||||
<p>
|
||||
Medieval Translation Nota = Note Capitulum = Category Intructio =
|
||||
Instructions Tabula = Index/Overview *This can be disabled via
|
||||
toolbar -------------------------------------------- Program Key
|
||||
Commands cmd + s = save cmd + t = new capitulum cmd + n = new nota
|
||||
cmd + x = close window dbl click = change name / open nota paste
|
||||
hyperlink twice = activated url
|
||||
-------------------------------------------- Text Markdowns cmd + b
|
||||
= Bold cmd + u = underline --- = ---------- (ruled line break)
|
||||
/*text*/ = Desaturated text
|
||||
</p>
|
||||
<p>
|
||||
Medieval Translation Nota = Note Capitulum = Category Intructio =
|
||||
Instructions Tabula = Index/Overview *This can be disabled via
|
||||
toolbar -------------------------------------------- Program Key
|
||||
Commands cmd + s = save cmd + t = new capitulum cmd + n = new nota
|
||||
cmd + x = close window dbl click = change name / open nota paste
|
||||
hyperlink twice = activated url
|
||||
-------------------------------------------- Text Markdowns cmd + b
|
||||
= Bold cmd + u = underline --- = ---------- (ruled line break)
|
||||
/*text*/ = Desaturated text
|
||||
</p>
|
||||
<p>
|
||||
Medieval Translation Nota = Note Capitulum = Category Intructio =
|
||||
Instructions Tabula = Index/Overview *This can be disabled via
|
||||
toolbar -------------------------------------------- Program Key
|
||||
Commands cmd + s = save cmd + t = new capitulum cmd + n = new nota
|
||||
cmd + x = close window dbl click = change name / open nota paste
|
||||
hyperlink twice = activated url
|
||||
-------------------------------------------- Text Markdowns cmd + b
|
||||
= Bold cmd + u = underline --- = ---------- (ruled line break)
|
||||
/*text*/ = Desaturated text
|
||||
</p>
|
||||
<p>
|
||||
Medieval Translation Nota = Note Capitulum = Category Intructio =
|
||||
Instructions Tabula = Index/Overview *This can be disabled via
|
||||
toolbar -------------------------------------------- Program Key
|
||||
Commands cmd + s = save cmd + t = new capitulum cmd + n = new nota
|
||||
cmd + x = close window dbl click = change name / open nota paste
|
||||
hyperlink twice = activated url
|
||||
-------------------------------------------- Text Markdowns cmd + b
|
||||
= Bold cmd + u = underline --- = ---------- (ruled line break)
|
||||
/*text*/ = Desaturated text
|
||||
</p>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script setup></script>
|
||||
|
||||
<style lang="scss">
|
||||
main.instructions {
|
||||
.back-link {
|
||||
opacity: 0.25;
|
||||
display: block;
|
||||
margin-top: size-vw(9px);
|
||||
margin-bottom: size-vw(14px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user