finished the plugin for now!

This commit is contained in:
Ell 2022-03-20 00:20:09 +01:00
parent ee5f13570d
commit a49de1de52
8 changed files with 1281 additions and 2330 deletions

View file

@ -1,2 +0,0 @@
npm node_modules
build

View file

@ -1,23 +0,0 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"env": { "node": true },
"plugins": [
"@typescript-eslint"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"parserOptions": {
"sourceType": "module"
},
"rules": {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": ["error", { "args": "none" }],
"@typescript-eslint/ban-ts-comment": "off",
"no-prototype-builtins": "off",
"@typescript-eslint/no-empty-function": "off"
}
}

View file

@ -1,2 +1,6 @@
# ObsidianKeep # ObsidianKeep
An Obsidian plugin that integrates simply with Google Keep An Obsidian plugin that displays Google Keep in the app.
Since Google Keep doesn't allow the use of iframes, this plugin gets creative by adding a [BrowserView](https://www.electronjs.org/docs/latest/api/browser-view) for the Google Keep view. However, since they render on top of everything else, the view has to be hidden whenever a modal or menu is open. It's a compromise.
When the official [Google Keep API](https://developers.google.com/keep) is farther along and has an official JavaScript API, this plugin will start using that instead, probably.

234
main.ts
View file

@ -1,137 +1,125 @@
import { App, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting } from 'obsidian'; import { ItemView, Plugin } from 'obsidian';
import { BrowserView, BrowserWindow, remote } from 'electron';
// Remember to rename these classes and interfaces! const viewName: string = "keep";
const padding: number = 5;
interface MyPluginSettings {
mySetting: string;
}
const DEFAULT_SETTINGS: MyPluginSettings = {
mySetting: 'default'
}
export default class MyPlugin extends Plugin { export default class MyPlugin extends Plugin {
settings: MyPluginSettings;
async onload() { async onload(): Promise<void> {
await this.loadSettings(); console.log('Loading obsidian-keep');
// This creates an icon in the left ribbon. this.registerView(viewName, l => new KeepView(l));
const ribbonIconEl = this.addRibbonIcon('dice', 'Sample Plugin', (evt: MouseEvent) => {
// Called when the user clicks the icon.
new Notice('This is a notice!');
});
// Perform additional things with the ribbon
ribbonIconEl.addClass('my-plugin-ribbon-class');
// This adds a status bar item to the bottom of the app. Does not work on mobile apps.
const statusBarItemEl = this.addStatusBarItem();
statusBarItemEl.setText('Status Bar Text');
// This adds a simple command that can be triggered anywhere
this.addCommand({ this.addCommand({
id: 'open-sample-modal-simple', id: "open-keep",
name: 'Open sample modal (simple)', name: "Open Keep",
callback: () => {
new SampleModal(this.app).open();
}
});
// This adds an editor command that can perform some operation on the current editor instance
this.addCommand({
id: 'sample-editor-command',
name: 'Sample editor command',
editorCallback: (editor: Editor, view: MarkdownView) => {
console.log(editor.getSelection());
editor.replaceSelection('Sample Editor Command');
}
});
// This adds a complex command that can check whether the current state of the app allows execution of the command
this.addCommand({
id: 'open-sample-modal-complex',
name: 'Open sample modal (complex)',
checkCallback: (checking: boolean) => { checkCallback: (checking: boolean) => {
// Conditions to check if (checking)
const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView); return !this.app.workspace.getLeavesOfType(viewName).length;
if (markdownView) { this.openKeep();
// If checking is true, we're simply "checking" if the command can be run. },
// If checking is false, then we want to actually perform the operation. });
if (!checking) { this.app.workspace.onLayoutReady(() => this.openKeep());
new SampleModal(this.app).open(); }
}
// This command will only show up in Command Palette when the check function returns true private openKeep(): void {
return true; if (!this.app.workspace.getLeavesOfType(viewName).length)
} this.app.workspace.getRightLeaf(false).setViewState({ type: viewName });
}
}
export class KeepView extends ItemView {
private keep: BrowserView;
private visible: boolean;
private open: boolean;
private size: DOMRect;
async onload(): Promise<void> {
this.keep = new remote.BrowserView();
await this.keep.webContents.loadURL('https://keep.google.com');
this.registerInterval(window.setInterval(() => this.update(), 16.67));
}
onunload(): void {
this.hide();
}
onResize(): void {
this.resizeIfNecessary();
}
getViewType(): string {
return viewName;
}
getDisplayText(): string {
return "Google Keep";
}
getIcon(): string {
return "documents";
}
update() {
if (this.open) {
let covered = this.coveredByElement();
if (this.visible && covered) {
this.hide();
} else if (!this.visible && !covered) {
this.show();
} }
if (this.visible)
this.resizeIfNecessary();
}
}
hide() {
if (this.visible) {
remote.BrowserWindow.getFocusedWindow().removeBrowserView(this.keep);
this.visible = false;
}
}
show() {
if (!this.visible) {
remote.BrowserWindow.getFocusedWindow().addBrowserView(this.keep);
this.visible = true;
}
}
protected async onOpen(): Promise<void> {
this.show();
this.resizeIfNecessary();
this.open = true;
}
protected async onClose(): Promise<void> {
this.hide();
this.open = false;
}
private resizeIfNecessary(): void {
let rect = this.contentEl.getBoundingClientRect();
if (this.size && rect.x == this.size.x && rect.y == this.size.y && rect.width == this.size.width && rect.height == this.size.height)
return;
this.size = rect;
this.keep.setBounds({
x: Math.floor(rect.x) + padding,
y: Math.floor(rect.top) + padding,
width: Math.floor(rect.width) - 2 * padding,
height: Math.floor(rect.height) - 2 * padding
}); });
// This adds a settings tab so the user can configure various aspects of the plugin
this.addSettingTab(new SampleSettingTab(this.app, this));
// If the plugin hooks up any global DOM events (on parts of the app that doesn't belong to this plugin)
// Using this function will automatically remove the event listener when this plugin is disabled.
this.registerDomEvent(document, 'click', (evt: MouseEvent) => {
console.log('click', evt);
});
// When registering intervals, this function will automatically clear the interval when the plugin is disabled.
this.registerInterval(window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000));
} }
onunload() { private coveredByElement(): boolean {
let nodes = document.body.querySelectorAll(".modal-bg, .menu");
} for (let i = 0; i < nodes.length; i++) {
let rect = nodes[i].getBoundingClientRect();
async loadSettings() { if (rect.left < this.size.right && this.size.left < rect.right && rect.top < this.size.bottom && this.size.top < rect.bottom)
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); return true;
} }
return false;
async saveSettings() {
await this.saveData(this.settings);
}
}
class SampleModal extends Modal {
constructor(app: App) {
super(app);
}
onOpen() {
const { contentEl } = this;
contentEl.setText('Woah!');
}
onClose() {
const { contentEl } = this;
contentEl.empty();
}
}
class SampleSettingTab extends PluginSettingTab {
plugin: MyPlugin;
constructor(app: App, plugin: MyPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
const { containerEl } = this;
containerEl.empty();
containerEl.createEl('h2', { text: 'Settings for my awesome plugin.' });
new Setting(containerEl)
.setName('Setting #1')
.setDesc('It\'s a secret')
.addText(text => text
.setPlaceholder('Enter your secret')
.setValue(this.plugin.settings.mySetting)
.onChange(async (value) => {
console.log('Secret: ' + value);
this.plugin.settings.mySetting = value;
await this.plugin.saveSettings();
}));
} }
} }

View file

@ -3,7 +3,7 @@
"name": "Obsidian Keep", "name": "Obsidian Keep",
"version": "1.0.0", "version": "1.0.0",
"minAppVersion": "0.13.33", "minAppVersion": "0.13.33",
"description": "An Obsidian plugin that integrates simply with Google Keep", "description": "An Obsidian plugin that displays Google Keep in the app",
"author": "Ellpeck", "author": "Ellpeck",
"authorUrl": "https://ellpeck.de", "authorUrl": "https://ellpeck.de",
"isDesktopOnly": false "isDesktopOnly": false

3334
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
{ {
"name": "obsidian-keep", "name": "obsidian-keep",
"version": "1.0.0", "version": "1.0.0",
"description": "An Obsidian plugin that integrates simply with Google Keep", "description": "An Obsidian plugin that displays Google Keep in the app",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
"dev": "node esbuild.config.mjs", "dev": "node esbuild.config.mjs",
@ -9,13 +9,12 @@
"version": "node version-bump.mjs && git add manifest.json versions.json" "version": "node version-bump.mjs && git add manifest.json versions.json"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "Ellpeck",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@types/node": "^16.11.6", "@types/node": "^16.11.6",
"@typescript-eslint/eslint-plugin": "^5.2.0",
"@typescript-eslint/parser": "^5.2.0",
"builtin-modules": "^3.2.0", "builtin-modules": "^3.2.0",
"electron": "^13.6.2",
"esbuild": "0.13.12", "esbuild": "0.13.12",
"obsidian": "latest", "obsidian": "latest",
"tslib": "2.3.1", "tslib": "2.3.1",

View file

@ -1 +0,0 @@