AT protocol bookmarking platforms in obsidian
1import { Modal, Notice } from "obsidian";
2import type ATmarkPlugin from "../main";
3import { createMarginCollection } from "../lib";
4
5export class CreateMarginCollectionModal 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("atmark-modal");
19
20 contentEl.createEl("h2", { text: "New margin collection" });
21
22 if (!this.plugin.client) {
23 // contentEl.createEl("p", { text: "Not Logged In. Please Login Using Settings." });
24 return;
25 }
26
27 const form = contentEl.createEl("form", { cls: "atmark-form" });
28
29 // Name field
30 const nameGroup = form.createEl("div", { cls: "atmark-form-group" });
31 nameGroup.createEl("label", { text: "Name", attr: { for: "collection-name" } });
32 const nameInput = nameGroup.createEl("input", {
33 type: "text",
34 cls: "atmark-input",
35 attr: { id: "collection-name", placeholder: "Collection name", required: "true" },
36 });
37
38 // Icon field
39 const iconGroup = form.createEl("div", { cls: "atmark-form-group" });
40 iconGroup.createEl("label", { text: "Icon (optional)", attr: { for: "collection-icon" } });
41 const iconInput = iconGroup.createEl("input", {
42 type: "text",
43 cls: "atmark-input",
44 attr: { id: "collection-icon" },
45 });
46
47 // Description field
48 const descGroup = form.createEl("div", { cls: "atmark-form-group" });
49 descGroup.createEl("label", { text: "Description", attr: { for: "collection-desc" } });
50 const descInput = descGroup.createEl("textarea", {
51 cls: "atmark-textarea",
52 attr: { id: "collection-desc", placeholder: "Optional description", rows: "3" },
53 });
54
55 // Action buttons
56 const actions = form.createEl("div", { cls: "atmark-modal-actions" });
57
58 const cancelBtn = actions.createEl("button", {
59 text: "Cancel",
60 cls: "atmark-btn atmark-btn-secondary",
61 type: "button",
62 });
63 cancelBtn.addEventListener("click", () => this.close());
64
65 const createBtn = actions.createEl("button", {
66 text: "Create",
67 cls: "atmark-btn atmark-btn-primary",
68 type: "submit",
69 });
70
71 form.addEventListener("submit", (e) => {
72 e.preventDefault();
73 void this.handleSubmit(nameInput, iconInput, descInput, createBtn);
74 });
75
76 // Focus name input
77 nameInput.focus();
78 }
79
80 private async handleSubmit(
81 nameInput: HTMLInputElement,
82 iconInput: HTMLInputElement,
83 descInput: HTMLTextAreaElement,
84 createBtn: HTMLButtonElement
85 ) {
86 const name = nameInput.value.trim();
87 if (!name) {
88 new Notice("Please enter a collection name");
89 return;
90 }
91
92 createBtn.disabled = true;
93 createBtn.textContent = "Creating...";
94
95 try {
96 await createMarginCollection(
97 this.plugin.client!,
98 this.plugin.settings.identifier,
99 name,
100 descInput.value.trim() || undefined,
101 iconInput.value.trim() || undefined
102 );
103
104 new Notice(`Created collection "${name}"`);
105 this.close();
106 this.onSuccess?.();
107 } catch (err) {
108 const message = err instanceof Error ? err.message : String(err);
109 new Notice(`Failed to create collection: ${message}`);
110 createBtn.disabled = false;
111 createBtn.textContent = "Create";
112 }
113 }
114
115 onClose() {
116 this.contentEl.empty();
117 }
118}