feat: publish modal, settings tab, plugin entry
Co-Authored-By: Claude
This commit is contained in:
99
src/main.ts
Normal file
99
src/main.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { Modal, Notice, Plugin, Setting, TFile, normalizePath } from "obsidian";
|
||||
import { DEFAULT_SETTINGS, JekyllPublishSettings } from "./settings";
|
||||
import { JekyllPublishSettingTab } from "./SettingsTab";
|
||||
import { ModalResult, PublishModal } from "./PublishModal";
|
||||
import { ChildProcessGitClient } from "./git";
|
||||
import { AskpassBridge } from "./askpass";
|
||||
import { publish } from "./publish";
|
||||
|
||||
export default class JekyllPublishPlugin extends Plugin {
|
||||
settings!: JekyllPublishSettings;
|
||||
|
||||
async onload() {
|
||||
await this.loadSettings();
|
||||
this.addSettingTab(new JekyllPublishSettingTab(this.app, this));
|
||||
this.addCommand({
|
||||
id: "publish-current-note",
|
||||
name: "Publish current note to Jekyll",
|
||||
checkCallback: (checking) => {
|
||||
const file = this.app.workspace.getActiveFile();
|
||||
if (!file) return false;
|
||||
if (!checking) void this.openPublishModal(file);
|
||||
return true;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async loadSettings() {
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
}
|
||||
async saveSettings() {
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
|
||||
private async openPublishModal(file: TFile) {
|
||||
const noteText = await this.app.vault.read(file);
|
||||
new PublishModal(this.app, this.settings, noteText, file.basename, (r) =>
|
||||
void this.runPublish(noteText, r)
|
||||
).open();
|
||||
}
|
||||
|
||||
private async runPublish(noteText: string, r: ModalResult) {
|
||||
if (!this.settings.remoteUrl.trim()) {
|
||||
new Notice("Jekyll Publish: set a remote URL in settings first.");
|
||||
return;
|
||||
}
|
||||
const dir = normalizePath(this.app.vault.configDir + "/plugins/jekyll-publish");
|
||||
const bridge = new AskpassBridge({
|
||||
dir: (this.app.vault.adapter as any).getFullPath
|
||||
? (this.app.vault.adapter as any).getFullPath(dir)
|
||||
: dir,
|
||||
onPrompt: (prompt) => this.promptCredential(prompt),
|
||||
});
|
||||
try {
|
||||
const env = await bridge.start();
|
||||
const git = new ChildProcessGitClient({ env });
|
||||
const result = await publish(
|
||||
{ noteText, ...r },
|
||||
this.settings,
|
||||
git,
|
||||
(linktext) => this.resolveImage(linktext)
|
||||
);
|
||||
const warn = result.unresolved.length ? ` (${result.unresolved.length} image(s) unresolved)` : "";
|
||||
new Notice(`Published ${result.postPath} with ${result.imageCount} image(s)${warn}`);
|
||||
} catch (e) {
|
||||
new Notice(`Publish failed: ${(e as Error).message}`);
|
||||
} finally {
|
||||
bridge.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private async resolveImage(linktext: string): Promise<Buffer | null> {
|
||||
const dest = this.app.metadataCache.getFirstLinkpathDest(linktext, "");
|
||||
if (!dest) return null;
|
||||
const ab = await this.app.vault.readBinary(dest);
|
||||
return Buffer.from(ab);
|
||||
}
|
||||
|
||||
private promptCredential(prompt: string): Promise<string> {
|
||||
return new Promise((resolve) => {
|
||||
const modal = new Modal(this.app);
|
||||
modal.titleEl.setText("Git credentials");
|
||||
modal.contentEl.createEl("p", { text: prompt });
|
||||
let value = "";
|
||||
const masked = /pass|secret|token/i.test(prompt);
|
||||
new Setting(modal.contentEl).addText((t) => {
|
||||
if (masked) t.inputEl.type = "password";
|
||||
t.onChange((v) => (value = v));
|
||||
t.inputEl.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter") { modal.close(); resolve(value); }
|
||||
});
|
||||
});
|
||||
new Setting(modal.contentEl).addButton((b) =>
|
||||
b.setButtonText("OK").setCta().onClick(() => { modal.close(); resolve(value); })
|
||||
);
|
||||
modal.onClose = () => resolve(value);
|
||||
modal.open();
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user