finished system!

This commit is contained in:
Ell 2022-03-22 13:17:10 +01:00
parent 672288135e
commit cdbd29448a
5 changed files with 158 additions and 64 deletions

View file

@ -1,5 +1,5 @@
# Obsidian Custom Frames # Obsidian Custom Frames
An Obsidian plugin that allows adding iframes with custom styling as editor tabs An Obsidian plugin that allows adding iframes with custom styling as editor tabs. Also comes with presets for Google Keep, Bring and more.
![A screenshot of the Obsidian Custom Frames plugin in action](screenshot.png) ![A screenshot of the Obsidian Custom Frames plugin in action](screenshot.png)

202
main.ts
View file

@ -1,20 +1,32 @@
import { App, ItemView, Plugin, PluginSettingTab, Setting, WorkspaceLeaf } from 'obsidian'; import { App, ButtonComponent, DropdownComponent, ItemView, Plugin, PluginSettingTab, Setting, WorkspaceLeaf } from "obsidian";
import { remote, webContents } from 'electron'; import { remote } from "electron";
const viewName: string = "keep";
const defaultSettings: CustomFramesSettings = { const defaultSettings: CustomFramesSettings = {
minimumWidth: 370, frames: [],
padding: 5, padding: 5
css: `/* hide the menu bar and the "Keep" logo and text */ };
const presets: Record<string, CustomFrame> = {
"keep": {
url: "https://keep.google.com",
displayName: "Google Keep",
minimumWidth: 370,
customCss: `/* hide the menu bar and the "Keep" text */
.PvRhvb-qAWA2, .gb_2d.gb_Zc { .PvRhvb-qAWA2, .gb_2d.gb_Zc {
display: none !important; display: none !important;
}` }`
}
}; };
interface CustomFramesSettings { interface CustomFramesSettings {
minimumWidth: number; frames: CustomFrame[];
padding: number; padding: number;
css: string; }
interface CustomFrame {
url: string;
displayName: string;
minimumWidth: number;
customCss: string;
} }
export default class CustomFramesPlugin extends Plugin { export default class CustomFramesPlugin extends Plugin {
@ -24,24 +36,31 @@ export default class CustomFramesPlugin extends Plugin {
async onload(): Promise<void> { async onload(): Promise<void> {
await this.loadSettings(); await this.loadSettings();
this.registerView(viewName, l => new CustomFrameView(l, this.settings)); for (let frame of this.settings.frames) {
this.addCommand({ if (!frame.url || !frame.displayName)
id: "open-keep", continue;
name: "Open Keep", let name = `custom-frames-${frame.displayName.toLowerCase().replace(/\s/g, "-")}`;
checkCallback: (checking: boolean) => { try {
if (checking) console.log(`Registering frame ${name} for URL ${frame.url}`);
return !this.app.workspace.getLeavesOfType(viewName).length;
this.openKeep(); this.registerView(name, l => new CustomFrameView(l, this.settings, frame, name));
}, this.addCommand({
}); id: `open-${name}`,
name: `Open ${frame.displayName}`,
checkCallback: (checking: boolean) => {
if (this.app.workspace.getLeavesOfType(name).length)
return false;
if (!checking)
this.app.workspace.getRightLeaf(false).setViewState({ type: name });
return true;
},
});
} catch {
console.error(`Couldn't register frame ${name}, is there already one with the same name?`);
}
}
this.addSettingTab(new CustomFramesSettingTab(this.app, this)); this.addSettingTab(new CustomFramesSettingTab(this.app, this));
this.app.workspace.onLayoutReady(() => this.openKeep());
}
private openKeep(): void {
if (!this.app.workspace.getLeavesOfType(viewName).length)
this.app.workspace.getRightLeaf(false).setViewState({ type: viewName });
} }
async loadSettings() { async loadSettings() {
@ -56,48 +75,52 @@ export default class CustomFramesPlugin extends Plugin {
class CustomFrameView extends ItemView { class CustomFrameView extends ItemView {
private settings: CustomFramesSettings; private settings: CustomFramesSettings;
private frame: CustomFrame;
private name: string;
constructor(leaf: WorkspaceLeaf, settings: CustomFramesSettings) { constructor(leaf: WorkspaceLeaf, settings: CustomFramesSettings, frame: CustomFrame, name: string) {
super(leaf); super(leaf);
this.settings = settings; this.settings = settings;
this.frame = frame;
this.name = name;
} }
onload(): void { onload(): void {
this.contentEl.empty(); this.contentEl.empty();
this.contentEl.addClass("obsidian-keep-view"); this.contentEl.addClass("custom-frames-view");
let frame = this.contentEl.createEl("iframe"); let frame = this.contentEl.createEl("iframe");
frame.addClass("custom-frames-frame");
frame.setAttribute("style", `padding: ${this.settings.padding}px`); frame.setAttribute("style", `padding: ${this.settings.padding}px`);
frame.addClass("obsidian-keep-frame");
frame.onload = () => { frame.onload = () => {
for (let other of remote.getCurrentWebContents().mainFrame.frames) { for (let other of remote.getCurrentWebContents().mainFrame.frames) {
if (frame.src.contains(new URL(other.url).host)) { if (frame.src.contains(new URL(other.url).host)) {
other.executeJavaScript(` other.executeJavaScript(`
let style = document.createElement("style"); let style = document.createElement("style");
style.textContent = \`${this.settings.css}\`; style.textContent = \`${this.frame.customCss}\`;
document.head.appendChild(style); document.head.appendChild(style);
`); `);
} }
} }
if (this.settings.minimumWidth) { if (this.frame.minimumWidth) {
let parent = this.contentEl.closest<HTMLElement>(".workspace-split.mod-horizontal"); let parent = this.contentEl.closest<HTMLElement>(".workspace-split.mod-horizontal");
if (parent) { if (parent) {
let minWidth = `${this.settings.minimumWidth + 2 * this.settings.padding}px`; let minWidth = `${this.frame.minimumWidth + 2 * this.settings.padding}px`;
if (parent.style.width < minWidth) if (parent.style.width < minWidth)
parent.style.width = minWidth; parent.style.width = minWidth;
} }
} }
}; };
frame.src = "https://keep.google.com"; frame.src = this.frame.url;
} }
getViewType(): string { getViewType(): string {
return viewName; return this.name;
} }
getDisplayText(): string { getDisplayText(): string {
return "Google Keep"; return this.frame.displayName;
} }
getIcon(): string { getIcon(): string {
@ -116,22 +139,12 @@ class CustomFramesSettingTab extends PluginSettingTab {
display(): void { display(): void {
this.containerEl.empty(); this.containerEl.empty();
this.containerEl.createEl('h2', { text: 'Obsidian Custom Frames Settings' }); this.containerEl.createEl("h2", { text: "Custom Frames Settings" });
this.containerEl.createEl("p", { text: "Note that Obsidian has to be restarted or reloaded for most of these settings to take effect." });
new Setting(this.containerEl) new Setting(this.containerEl)
.setName("Minimum View Width") .setName("Frame Padding")
.setDesc("The width that the Google Keep view should be adjusted to automatically if it is lower. Set to 0 to disable.") .setDesc("The padding that should be left around the inside of custom frame tabs, in pixels.")
.addText(t => {
t.inputEl.type = "number";
t.setValue(String(this.plugin.settings.minimumWidth));
t.onChange(async v => {
this.plugin.settings.minimumWidth = v.length ? Number(v) : defaultSettings.minimumWidth;
await this.plugin.saveSettings();
});
});
new Setting(this.containerEl)
.setName("View Padding")
.setDesc("The padding that should be left around the inside of the Google Keep view, in pixels.")
.addText(t => { .addText(t => {
t.inputEl.type = "number"; t.inputEl.type = "number";
t.setValue(String(this.plugin.settings.padding)); t.setValue(String(this.plugin.settings.padding));
@ -140,17 +153,90 @@ class CustomFramesSettingTab extends PluginSettingTab {
await this.plugin.saveSettings(); await this.plugin.saveSettings();
}); });
}); });
new Setting(this.containerEl)
.setName("Additional CSS") for (let frame of this.plugin.settings.frames) {
.setDesc("A snippet of additional CSS that should be applied to the Google Keep embed. By default, this hides a lot of unnecessary information to make the embed take up less horizontal space.") let heading = this.containerEl.createEl("h3", { text: frame.displayName || "Unnamed Frame" });
.addTextArea(t => {
t.inputEl.rows = 10; new Setting(this.containerEl)
t.inputEl.cols = 50; .setName("Display Name")
t.setValue(this.plugin.settings.css); .setDesc("The display name that this frame should have.")
t.onChange(async v => { .addText(t => {
this.plugin.settings.css = v.length ? v : defaultSettings.css; t.setValue(frame.displayName);
await this.plugin.saveSettings(); t.onChange(async v => {
frame.displayName = v;
heading.setText(frame.displayName || "Unnamed Frame");
await this.plugin.saveSettings();
});
}); });
new Setting(this.containerEl)
.setName("URL")
.setDesc("The URL that should be opened in this frame.")
.addText(t => {
t.setValue(frame.url);
t.onChange(async v => {
frame.url = v;
await this.plugin.saveSettings();
});
});
new Setting(this.containerEl)
.setName("Minimum Width")
.setDesc("The width that this frame's tab should be adjusted to automatically if it is lower. Set to 0 to disable.")
.addText(t => {
t.inputEl.type = "number";
t.setValue(String(frame.minimumWidth));
t.onChange(async v => {
frame.minimumWidth = v.length ? Number(v) : 0;
await this.plugin.saveSettings();
});
});
new Setting(this.containerEl)
.setName("Additional CSS")
.setDesc("A snippet of additional CSS that should be applied to this frame.")
.addTextArea(t => {
t.inputEl.rows = 10;
t.inputEl.cols = 50;
t.setValue(frame.customCss);
t.onChange(async v => {
frame.customCss = v;
await this.plugin.saveSettings();
});
});
new ButtonComponent(this.containerEl)
.setButtonText("Remove Frame")
.onClick(async () => {
this.plugin.settings.frames.remove(frame);
await this.plugin.saveSettings();
this.display();
});
}
this.containerEl.createEl("hr");
this.containerEl.createEl("p", { text: "Create a new frame, either from a preset shipped with the plugin, or a custom one that you can edit yourself. Each frame's tab can be opened using the 'Custom Frames: Open' command." });
let addDiv = this.containerEl.createDiv();
addDiv.addClass("custom-frames-add");
let dropdown = new DropdownComponent(addDiv);
dropdown.addOption("new", "Custom");
for (let key of Object.keys(presets))
dropdown.addOption(key, `${presets[key].displayName} Preset`);
new ButtonComponent(addDiv)
.setButtonText("Add Frame")
.onClick(async () => {
let option = dropdown.getValue();
if (option == "new") {
this.plugin.settings.frames.push({
url: "",
displayName: "",
minimumWidth: 0,
customCss: ""
});
}
else {
this.plugin.settings.frames.push(presets[option]);
}
await this.plugin.saveSettings();
this.display();
}); });
} }
} }

View file

@ -1,9 +1,9 @@
{ {
"id": "obsidian-custom-frames", "id": "obsidian-custom-frames",
"name": "Obsidian Custom Frames", "name": "Custom Frames",
"version": "1.1.1", "version": "1.1.1",
"minAppVersion": "0.13.33", "minAppVersion": "0.13.33",
"description": "An Obsidian plugin that allows adding iframes with custom styling as editor tabs", "description": "A plugin that allows adding iframes with custom styling as editor tabs. Also comes with presets for Google Keep, Bring and more.",
"author": "Ellpeck", "author": "Ellpeck",
"authorUrl": "https://ellpeck.de", "authorUrl": "https://ellpeck.de",
"isDesktopOnly": true "isDesktopOnly": true

View file

@ -1,7 +1,7 @@
{ {
"name": "obsidian-custom-frames", "name": "obsidian-custom-frames",
"version": "1.1.1", "version": "1.1.1",
"description": "An Obsidian plugin that allows adding iframes with custom styling as editor tabs", "description": "An Obsidian plugin that allows adding iframes with custom styling as editor tabs. Also comes with presets for Google Keep, Bring and more.",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
"dev": "node esbuild.config.mjs", "dev": "node esbuild.config.mjs",

View file

@ -1,10 +1,18 @@
.obsidian-keep-view { .custom-frames-view {
padding: 0 !important; padding: 0 !important;
overflow: hidden !important; overflow: hidden !important;
} }
.obsidian-keep-frame { .custom-frames-frame {
width: 100%; width: 100%;
height: 100%; height: 100%;
border: none; border: none;
} }
.custom-frames-add {
padding: 0 0 18px 0;
}
.custom-frames-add button {
margin-left: 10px;
}