AT protocol bookmarking platforms in obsidian
at responsive-sizing 107 lines 2.8 kB view raw
1import { Modal, Notice } from "obsidian"; 2import type ATmarkPlugin from "../main"; 3import { createCollection } from "../lib"; 4 5export class CreateCollectionModal extends Modal { 6 plugin: ATmarkPlugin; 7 onSuccess?: () => void; 8 9 constructor(plugin: ATmarkPlugin, onSuccess?: () => void) { 10 super(plugin.app); 11 this.plugin = plugin; 12 this.onSuccess = onSuccess; 13 } 14 15 onOpen() { 16 const { contentEl } = this; 17 contentEl.empty(); 18 contentEl.addClass("semble-collection-modal"); 19 20 contentEl.createEl("h2", { text: "New collection" }); 21 22 if (!this.plugin.client) { 23 contentEl.createEl("p", { text: "Not connected." }); 24 return; 25 } 26 27 const form = contentEl.createEl("form", { cls: "semble-form" }); 28 29 // Name field 30 const nameGroup = form.createEl("div", { cls: "semble-form-group" }); 31 nameGroup.createEl("label", { text: "Name", attr: { for: "collection-name" } }); 32 const nameInput = nameGroup.createEl("input", { 33 type: "text", 34 cls: "semble-input", 35 attr: { id: "collection-name", placeholder: "Collection name", required: "true" }, 36 }); 37 38 // Description field 39 const descGroup = form.createEl("div", { cls: "semble-form-group" }); 40 descGroup.createEl("label", { text: "Description", attr: { for: "collection-desc" } }); 41 const descInput = descGroup.createEl("textarea", { 42 cls: "semble-textarea", 43 attr: { id: "collection-desc", placeholder: "Optional description", rows: "3" }, 44 }); 45 46 // Action buttons 47 const actions = form.createEl("div", { cls: "semble-modal-actions" }); 48 49 const cancelBtn = actions.createEl("button", { 50 text: "Cancel", 51 cls: "semble-btn semble-btn-secondary", 52 type: "button", 53 }); 54 cancelBtn.addEventListener("click", () => this.close()); 55 56 const createBtn = actions.createEl("button", { 57 text: "Create", 58 cls: "semble-btn semble-btn-primary", 59 type: "submit", 60 }); 61 62 form.addEventListener("submit", (e) => { 63 e.preventDefault(); 64 void this.handleSubmit(nameInput, descInput, createBtn); 65 }); 66 67 // Focus name input 68 nameInput.focus(); 69 } 70 71 private async handleSubmit( 72 nameInput: HTMLInputElement, 73 descInput: HTMLTextAreaElement, 74 createBtn: HTMLButtonElement 75 ) { 76 const name = nameInput.value.trim(); 77 if (!name) { 78 new Notice("Please enter a collection name"); 79 return; 80 } 81 82 createBtn.disabled = true; 83 createBtn.textContent = "Creating..."; 84 85 try { 86 await createCollection( 87 this.plugin.client!, 88 this.plugin.settings.identifier, 89 name, 90 descInput.value.trim() 91 ); 92 93 new Notice(`Created collection "${name}"`); 94 this.close(); 95 this.onSuccess?.(); 96 } catch (err) { 97 const message = err instanceof Error ? err.message : String(err); 98 new Notice(`Failed to create collection: ${message}`); 99 createBtn.disabled = false; 100 createBtn.textContent = "Create"; 101 } 102 } 103 104 onClose() { 105 this.contentEl.empty(); 106 } 107}