tangled
alpha
login
or
join now
treethought.xyz
/
obsidian-atmark
8
fork
atom
AT protocol bookmarking platforms in obsidian
8
fork
atom
overview
issues
pulls
pipelines
fix lint
treethought
2 months ago
8d48f42c
7cb1968a
+86
-70
4 changed files
expand all
collapse all
unified
split
src
components
createCollectionModal.ts
editCardModal.ts
views
cards.ts
collections.ts
+35
-27
src/components/createCollectionModal.ts
···
17
17
contentEl.empty();
18
18
contentEl.addClass("semble-collection-modal");
19
19
20
20
-
contentEl.createEl("h2", { text: "New Collection" });
20
20
+
contentEl.createEl("h2", { text: "New collection" });
21
21
22
22
if (!this.plugin.client) {
23
23
contentEl.createEl("p", { text: "Not connected." });
···
59
59
type: "submit",
60
60
});
61
61
62
62
-
form.addEventListener("submit", async (e) => {
62
62
+
form.addEventListener("submit", (e) => {
63
63
e.preventDefault();
64
64
+
void this.handleSubmit(nameInput, descInput, createBtn);
65
65
+
});
64
66
65
65
-
const name = nameInput.value.trim();
66
66
-
if (!name) {
67
67
-
new Notice("Please enter a collection name");
68
68
-
return;
69
69
-
}
67
67
+
// Focus name input
68
68
+
nameInput.focus();
69
69
+
}
70
70
71
71
-
createBtn.disabled = true;
72
72
-
createBtn.textContent = "Creating...";
71
71
+
private async handleSubmit(
72
72
+
nameInput: HTMLInputElement,
73
73
+
descInput: HTMLTextAreaElement,
74
74
+
createBtn: HTMLButtonElement
75
75
+
) {
76
76
+
const name = nameInput.value.trim();
77
77
+
if (!name) {
78
78
+
new Notice("Please enter a collection name");
79
79
+
return;
80
80
+
}
73
81
74
74
-
try {
75
75
-
await createCollection(
76
76
-
this.plugin.client!,
77
77
-
this.plugin.settings.identifier,
78
78
-
name,
79
79
-
descInput.value.trim()
80
80
-
);
82
82
+
createBtn.disabled = true;
83
83
+
createBtn.textContent = "Creating...";
81
84
82
82
-
new Notice(`Created collection "${name}"`);
83
83
-
this.close();
84
84
-
this.onSuccess?.();
85
85
-
} catch (e) {
86
86
-
new Notice(`Failed to create collection: ${e}`);
87
87
-
createBtn.disabled = false;
88
88
-
createBtn.textContent = "Create";
89
89
-
}
90
90
-
});
85
85
+
try {
86
86
+
await createCollection(
87
87
+
this.plugin.client!,
88
88
+
this.plugin.settings.identifier,
89
89
+
name,
90
90
+
descInput.value.trim()
91
91
+
);
91
92
92
92
-
// Focus name input
93
93
-
nameInput.focus();
93
93
+
new Notice(`Created collection "${name}"`);
94
94
+
this.close();
95
95
+
this.onSuccess?.();
96
96
+
} catch (err) {
97
97
+
const message = err instanceof Error ? err.message : String(err);
98
98
+
new Notice(`Failed to create collection: ${message}`);
99
99
+
createBtn.disabled = false;
100
100
+
createBtn.textContent = "Create";
101
101
+
}
94
102
}
95
103
96
104
onClose() {
+20
-17
src/components/editCardModal.ts
···
42
42
contentEl.empty();
43
43
contentEl.addClass("semble-collection-modal");
44
44
45
45
-
contentEl.createEl("h2", { text: "Edit Collections" });
45
45
+
contentEl.createEl("h2", { text: "Edit collections" });
46
46
47
47
if (!this.plugin.client) {
48
48
contentEl.createEl("p", { text: "Not connected." });
···
89
89
}));
90
90
91
91
this.renderCollectionList(contentEl);
92
92
-
} catch (e) {
92
92
+
} catch (err) {
93
93
loading.remove();
94
94
-
contentEl.createEl("p", { text: `Error: ${e}`, cls: "semble-error" });
94
94
+
const message = err instanceof Error ? err.message : String(err);
95
95
+
contentEl.createEl("p", { text: `Error: ${message}`, cls: "semble-error" });
95
96
}
96
97
}
97
98
···
119
120
const actions = contentEl.createEl("div", { cls: "semble-modal-actions" });
120
121
121
122
const deleteBtn = actions.createEl("button", { text: "Delete", cls: "semble-btn semble-btn-danger" });
122
122
-
deleteBtn.addEventListener("click", () => this.confirmDelete(contentEl));
123
123
+
deleteBtn.addEventListener("click", () => { this.confirmDelete(contentEl); });
123
124
124
124
-
const spacer = actions.createEl("div", { cls: "semble-spacer" });
125
125
+
actions.createEl("div", { cls: "semble-spacer" });
125
126
126
127
const cancelBtn = actions.createEl("button", { text: "Cancel", cls: "semble-btn semble-btn-secondary" });
127
127
-
cancelBtn.addEventListener("click", () => this.close());
128
128
+
cancelBtn.addEventListener("click", () => { this.close(); });
128
129
129
130
const saveBtn = actions.createEl("button", { text: "Save", cls: "semble-btn semble-btn-primary" });
130
131
saveBtn.id = "semble-save-btn";
131
132
saveBtn.disabled = true;
132
132
-
saveBtn.addEventListener("click", () => this.saveChanges());
133
133
+
saveBtn.addEventListener("click", () => { void this.saveChanges(); });
133
134
}
134
135
135
136
private confirmDelete(contentEl: HTMLElement) {
136
137
contentEl.empty();
137
137
-
contentEl.createEl("h2", { text: "Delete Card" });
138
138
+
contentEl.createEl("h2", { text: "Delete card" });
138
139
contentEl.createEl("p", { text: "Delete this card?", cls: "semble-warning-text" });
139
140
140
141
const actions = contentEl.createEl("div", { cls: "semble-modal-actions" });
···
142
143
const cancelBtn = actions.createEl("button", { text: "Cancel", cls: "semble-btn semble-btn-secondary" });
143
144
cancelBtn.addEventListener("click", () => {
144
145
// Re-render the modal
145
145
-
this.onOpen();
146
146
+
void this.onOpen();
146
147
});
147
148
148
149
const confirmBtn = actions.createEl("button", { text: "Delete", cls: "semble-btn semble-btn-danger" });
149
149
-
confirmBtn.addEventListener("click", () => this.deleteCard());
150
150
+
confirmBtn.addEventListener("click", () => { void this.deleteCard(); });
150
151
}
151
152
152
153
private async deleteCard() {
···
160
161
const rkey = this.cardUri.split("/").pop();
161
162
if (!rkey) {
162
163
contentEl.empty();
163
163
-
contentEl.createEl("p", { text: "Invalid card URI.", cls: "semble-error" });
164
164
+
contentEl.createEl("p", { text: "Invalid card uri.", cls: "semble-error" });
164
165
return;
165
166
}
166
167
···
174
175
new Notice("Card deleted");
175
176
this.close();
176
177
this.onSuccess?.();
177
177
-
} catch (e) {
178
178
+
} catch (err) {
178
179
contentEl.empty();
179
179
-
contentEl.createEl("p", { text: `Failed to delete: ${e}`, cls: "semble-error" });
180
180
+
const message = err instanceof Error ? err.message : String(err);
181
181
+
contentEl.createEl("p", { text: `Failed to delete: ${message}`, cls: "semble-error" });
180
182
}
181
183
}
182
184
183
185
private updateSaveButton() {
184
184
-
const saveBtn = document.getElementById("semble-save-btn") as HTMLButtonElement;
186
186
+
const saveBtn = document.getElementById("semble-save-btn") as HTMLButtonElement | null;
185
187
if (!saveBtn) return;
186
188
187
189
// Check if any changes were made
···
235
237
this.cardUri,
236
238
this.cardCid,
237
239
state.collection.uri,
238
238
-
collectionResp.data.cid as string
240
240
+
String(collectionResp.data.cid)
239
241
);
240
242
}
241
243
···
251
253
252
254
this.close();
253
255
this.onSuccess?.();
254
254
-
} catch (e) {
256
256
+
} catch (err) {
255
257
contentEl.empty();
256
256
-
contentEl.createEl("p", { text: `Failed to save: ${e}`, cls: "semble-error" });
258
258
+
const message = err instanceof Error ? err.message : String(err);
259
259
+
contentEl.createEl("p", { text: `Failed to save: ${message}`, cls: "semble-error" });
257
260
}
258
261
}
259
262
+16
-13
src/views/cards.ts
···
51
51
setCollection(uri: string | null, name: string) {
52
52
this.collectionUri = uri;
53
53
this.collectionName = name;
54
54
-
this.render();
54
54
+
void this.render();
55
55
}
56
56
57
57
async onOpen() {
···
84
84
const links = allLinks.filter((link) => link.value.collection.uri === collectionUri);
85
85
86
86
// Get cards in collection
87
87
-
const cardUris = new Set(links.map((link) => link.value.card.uri as string));
88
88
-
const cards = allCards.filter((card) => cardUris.has(card.uri as string));
87
87
+
const cardUris = new Set(links.map((link) => String(link.value.card.uri)));
88
88
+
const cards = allCards.filter((card) => cardUris.has(String(card.uri)));
89
89
90
90
return cards;
91
91
}
···
111
111
} else {
112
112
cards = await this.getAllCards();
113
113
}
114
114
-
} catch (e) {
114
114
+
} catch (err) {
115
115
loading.remove();
116
116
-
container.createEl("p", { text: `Failed to load cards: ${e}`, cls: "semble-error" });
116
116
+
const message = err instanceof Error ? err.message : String(err);
117
117
+
container.createEl("p", { text: `Failed to load cards: ${message}`, cls: "semble-error" });
117
118
return;
118
119
}
119
120
120
121
const collectionsResp = await getCollections(this.plugin.client, this.plugin.settings.identifier);
121
122
if (!collectionsResp.ok) {
122
123
loading.remove();
123
123
-
container.createEl("p", { text: `Failed to load collections: ${collectionsResp.data?.error}`, cls: "semble-error" });
124
124
+
const errorMsg = collectionsResp.data?.error ? String(collectionsResp.data.error) : "Unknown error";
125
125
+
container.createEl("p", { text: `Failed to load collections: ${errorMsg}`, cls: "semble-error" });
124
126
return;
125
127
}
126
128
const collections = collectionsResp.data?.records as unknown as CollectionRecord[];
···
139
141
for (const record of cards) {
140
142
try {
141
143
this.renderCard(grid, record);
142
142
-
} catch (e) {
143
143
-
console.log(JSON.stringify(record.value, null, 2));
144
144
-
console.error(`Failed to render card ${record.uri}: ${e}`);
144
144
+
} catch (err) {
145
145
+
const message = err instanceof Error ? err.message : String(err);
146
146
+
console.error(`Failed to render card ${record.uri}: ${message}`);
145
147
}
146
148
}
147
147
-
} catch (e) {
149
149
+
} catch (err) {
148
150
loading.remove();
149
149
-
container.createEl("p", { text: `Failed to load: ${e}`, cls: "semble-error" });
151
151
+
const message = err instanceof Error ? err.message : String(err);
152
152
+
container.createEl("p", { text: `Failed to load: ${message}`, cls: "semble-error" });
150
153
}
151
154
}
152
155
···
159
162
const backBtn = nav.createEl("button", { cls: "semble-back-btn" });
160
163
setIcon(backBtn, "arrow-left");
161
164
backBtn.addEventListener("click", () => {
162
162
-
this.plugin.activateView(VIEW_TYPE_SEMBLE_COLLECTIONS);
165
165
+
void this.plugin.activateView(VIEW_TYPE_SEMBLE_COLLECTIONS);
163
166
});
164
167
165
168
nav.createEl("span", { text: "Semble", cls: "semble-brand" });
···
208
211
addBtn.addEventListener("click", (e) => {
209
212
e.stopPropagation();
210
213
new EditCardModal(this.plugin, record.uri, record.cid, () => {
211
211
-
this.render();
214
214
+
void this.render();
212
215
}).open();
213
216
});
214
217
+15
-13
src/views/collections.ts
···
26
26
}
27
27
28
28
getDisplayText() {
29
29
-
return "Semble Collections";
29
29
+
return "Semble collections";
30
30
}
31
31
32
32
getIcon() {
···
45
45
const view = leaf.view as SembleCardsView;
46
46
view.setCollection(uri, name);
47
47
48
48
-
workspace.revealLeaf(leaf);
48
48
+
void workspace.revealLeaf(leaf);
49
49
}
50
50
51
51
async render() {
···
76
76
77
77
const createBtn = toolbar.createEl("button", { cls: "semble-create-btn" });
78
78
setIcon(createBtn, "plus");
79
79
-
createBtn.createEl("span", { text: "New Collection" });
79
79
+
createBtn.createEl("span", { text: "New collection" });
80
80
createBtn.addEventListener("click", () => {
81
81
-
new CreateCollectionModal(this.plugin, () => this.render()).open();
81
81
+
new CreateCollectionModal(this.plugin, () => { void this.render(); }).open();
82
82
});
83
83
84
84
const allCardsBtn = toolbar.createEl("button", { cls: "semble-toolbar-btn" });
85
85
setIcon(allCardsBtn, "layers");
86
86
-
allCardsBtn.createEl("span", { text: "All Cards" });
86
86
+
allCardsBtn.createEl("span", { text: "All cards" });
87
87
allCardsBtn.addEventListener("click", () => {
88
88
-
this.plugin.activateView(VIEW_TYPE_SEMBLE_CARDS);
88
88
+
void this.plugin.activateView(VIEW_TYPE_SEMBLE_CARDS);
89
89
});
90
90
91
91
const loading = container.createEl("p", { text: "Loading..." });
···
95
95
loading.remove();
96
96
97
97
if (!resp.ok) {
98
98
-
container.createEl("p", { text: `Error: ${resp.data?.error}`, cls: "semble-error" });
98
98
+
const errorMsg = resp.data?.error ? String(resp.data.error) : "Unknown error";
99
99
+
container.createEl("p", { text: `Error: ${errorMsg}`, cls: "semble-error" });
99
100
return;
100
101
}
101
102
···
113
114
const card = grid.createEl("div", { cls: "semble-card" });
114
115
115
116
card.addEventListener("click", () => {
116
116
-
this.plugin.openCollection(record.uri, col.name);
117
117
+
void this.plugin.openCollection(record.uri, col.name);
117
118
});
118
119
119
119
-
const header = card.createEl("div", { cls: "semble-card-header" });
120
120
-
header.createEl("span", { text: col.name, cls: "semble-card-title" });
120
120
+
const cardHeader = card.createEl("div", { cls: "semble-card-header" });
121
121
+
cardHeader.createEl("span", { text: col.name, cls: "semble-card-title" });
121
122
122
122
-
const accessIcon = header.createEl("span", {
123
123
+
const accessIcon = cardHeader.createEl("span", {
123
124
cls: `semble-access-icon semble-access-${col.accessType.toLowerCase()}`,
124
125
attr: { "aria-label": col.accessType },
125
126
});
···
143
144
});
144
145
}
145
146
}
146
146
-
} catch (e) {
147
147
+
} catch (err) {
147
148
loading.remove();
148
148
-
container.createEl("p", { text: `Failed to load: ${e}`, cls: "semble-error" });
149
149
+
const message = err instanceof Error ? err.message : String(err);
150
150
+
container.createEl("p", { text: `Failed to load: ${message}`, cls: "semble-error" });
149
151
}
150
152
}
151
153