AT protocol bookmarking platforms in obsidian
1import { getSubscribedPublications } from "lib/standardsite";
2import ATmarkPlugin from "main";
3import { ItemView, WorkspaceLeaf } from "obsidian";
4import { SiteStandardPublication } from "@atcute/standard-site";
5import { ATRecord } from "lib";
6
7export const VIEW_STANDARD_FEED = "standard-site-feed";
8
9export class StandardFeedView extends ItemView {
10 plugin: ATmarkPlugin;
11
12 constructor(leaf: WorkspaceLeaf, plugin: ATmarkPlugin) {
13 super(leaf);
14 this.plugin = plugin;
15 }
16
17 getViewType() {
18 return VIEW_STANDARD_FEED;
19 }
20
21 getDisplayText() {
22 return "Feed";
23 }
24
25 getIcon() {
26 return "rss";
27 }
28
29 async onOpen() {
30 await this.render();
31 }
32
33 async render() {
34 const container = this.contentEl;
35 container.empty();
36 container.addClass("standard-site-view");
37 this.renderHeader(container);
38
39 const loading = container.createEl("p", { text: "Loading feed..." });
40
41 try {
42 const pubs = await getSubscribedPublications(this.plugin.client, this.plugin.settings.identifier);
43 loading.remove();
44
45 if (pubs.length === 0) {
46 container.createEl("p", { text: "No subscriptions found. Subscribe to publications first." });
47 return;
48 }
49
50 const list = container.createEl("div", { cls: "standard-site-list" });
51
52 for (const pub of pubs) {
53 this.renderPublicationCard(list, pub);
54 }
55 } catch (error) {
56 loading.remove();
57 const message = error instanceof Error ? error.message : String(error);
58 container.createEl("p", { text: `Failed to load feed: ${message}`, cls: "standard-site-error" });
59 }
60 }
61
62 private renderPublicationCard(container: HTMLElement, pub: ATRecord<SiteStandardPublication.Main>) {
63 const card = container.createEl("div", { cls: "standard-site-publication" });
64
65 // Header with name
66 const header = card.createEl("div", { cls: "standard-site-publication-header" });
67 header.createEl("h3", {
68 text: pub.value.name,
69 cls: "standard-site-publication-name"
70 });
71
72 // Body
73 const body = card.createEl("div", { cls: "standard-site-publication-body" });
74
75 // URL
76 const urlLine = body.createEl("div", { cls: "standard-site-publication-url" });
77 const link = urlLine.createEl("a", { text: pub.value.url, href: pub.value.url });
78 link.setAttr("target", "_blank");
79
80 // Description
81 if (pub.value.description) {
82 body.createEl("p", {
83 text: pub.value.description,
84 cls: "standard-site-publication-description"
85 });
86 }
87
88 // Make card clickable
89 card.addClass("clickable");
90 card.addEventListener("click", (e) => {
91 // Don't trigger if clicking the link
92 if ((e.target as HTMLElement).tagName !== "A") {
93 window.open(pub.value.url, "_blank");
94 }
95 });
96 }
97
98 renderHeader(container: HTMLElement) {
99 const header = container.createEl("div", { cls: "standard-site-header" });
100 header.createEl("h2", { text: "Subscriptions" });
101 }
102}