AT protocol bookmarking platforms in obsidian
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}