Various AT Protocol integrations with obsidian
at filter-collections-toggle 139 lines 4.3 kB view raw
1import { Modal, Notice } from "obsidian"; 2import type AtmospherePlugin from "../main"; 3import { createSembleCollection, createMarginCollection } from "../lib"; 4 5type SourceName = "semble" | "margin"; 6 7export class CreateCollectionModal extends Modal { 8 plugin: AtmospherePlugin; 9 availableSources: SourceName[]; 10 selectedSource: SourceName; 11 onSuccess?: () => void; 12 13 constructor(plugin: AtmospherePlugin, availableSources: SourceName[], onSuccess?: () => void) { 14 super(plugin.app); 15 this.plugin = plugin; 16 this.availableSources = availableSources; 17 this.selectedSource = availableSources[0]!; 18 this.onSuccess = onSuccess; 19 } 20 21 onOpen() { this.render(); } 22 23 private render() { 24 const { contentEl } = this; 25 contentEl.empty(); 26 contentEl.addClass("atmosphere-modal"); 27 contentEl.createEl("h2", { text: "New collection" }); 28 29 if (!this.plugin.client) { 30 contentEl.createEl("p", { text: "Not connected." }); 31 return; 32 } 33 34 if (this.availableSources.length > 1) { 35 const toggleRow = contentEl.createEl("div", { cls: "atmosphere-source-toggle-row" }); 36 for (const source of this.availableSources) { 37 const btn = toggleRow.createEl("button", { 38 text: source.charAt(0).toUpperCase() + source.slice(1), 39 cls: "atmosphere-source-toggle-btn" + (this.selectedSource === source ? " is-active" : ""), 40 type: "button", 41 }); 42 btn.addEventListener("click", () => { this.selectedSource = source; this.render(); }); 43 } 44 } 45 46 const form = contentEl.createEl("form", { cls: "atmosphere-form" }); 47 48 const nameGroup = form.createEl("div", { cls: "atmosphere-form-group" }); 49 nameGroup.createEl("label", { text: "Name", attr: { for: "collection-name" } }); 50 const nameInput = nameGroup.createEl("input", { 51 type: "text", 52 cls: "atmosphere-input", 53 attr: { id: "collection-name", placeholder: "Collection name", required: "true" }, 54 }); 55 56 let iconInput: HTMLInputElement | null = null; 57 if (this.selectedSource === "margin") { 58 const iconGroup = form.createEl("div", { cls: "atmosphere-form-group" }); 59 iconGroup.createEl("label", { text: "Icon (optional)", attr: { for: "collection-icon" } }); 60 iconInput = iconGroup.createEl("input", { 61 type: "text", 62 cls: "atmosphere-input", 63 attr: { id: "collection-icon" }, 64 }); 65 } 66 67 const descGroup = form.createEl("div", { cls: "atmosphere-form-group" }); 68 descGroup.createEl("label", { text: "Description", attr: { for: "collection-desc" } }); 69 const descInput = descGroup.createEl("textarea", { 70 cls: "atmosphere-textarea", 71 attr: { id: "collection-desc", placeholder: "Optional description", rows: "3" }, 72 }); 73 74 const actions = form.createEl("div", { cls: "atmosphere-modal-actions" }); 75 actions.createEl("button", { 76 text: "Cancel", 77 cls: "atmosphere-btn atmosphere-btn-secondary", 78 type: "button", 79 }).addEventListener("click", () => this.close()); 80 81 const createBtn = actions.createEl("button", { 82 text: "Create", 83 cls: "atmosphere-btn atmosphere-btn-primary", 84 type: "submit", 85 }); 86 87 form.addEventListener("submit", (e) => { 88 e.preventDefault(); 89 void this.handleSubmit(nameInput, iconInput, descInput, createBtn); 90 }); 91 92 nameInput.focus(); 93 } 94 95 private async handleSubmit( 96 nameInput: HTMLInputElement, 97 iconInput: HTMLInputElement | null, 98 descInput: HTMLTextAreaElement, 99 createBtn: HTMLButtonElement 100 ) { 101 const name = nameInput.value.trim(); 102 if (!name) { 103 new Notice("Please enter a collection name"); 104 return; 105 } 106 107 createBtn.disabled = true; 108 createBtn.textContent = "Creating..."; 109 110 try { 111 if (this.selectedSource === "margin") { 112 await createMarginCollection( 113 this.plugin.client, 114 this.plugin.settings.did!, 115 name, 116 descInput.value.trim() || undefined, 117 iconInput?.value.trim() || undefined 118 ); 119 } else { 120 await createSembleCollection( 121 this.plugin.client, 122 this.plugin.settings.did!, 123 name, 124 descInput.value.trim() 125 ); 126 } 127 new Notice(`Created collection "${name}"`); 128 this.close(); 129 this.onSuccess?.(); 130 } catch (err) { 131 const message = err instanceof Error ? err.message : String(err); 132 new Notice(`Failed to create collection: ${message}`); 133 createBtn.disabled = false; 134 createBtn.textContent = "Create"; 135 } 136 } 137 138 onClose() { this.contentEl.empty(); } 139}