Various AT Protocol integrations with obsidian
20
fork

Configure Feed

Select the types of activity you want to include in your feed.

lint fixes

+17 -31
+8 -8
src/components/profileIcon.ts
··· 30 30 profile: ProfileData | null, 31 31 onClick?: () => void 32 32 ): HTMLElement { 33 - const wrapper = container.createEl("div", { cls: "semble-profile-icon" }); 33 + const wrapper = container.createEl("div", { cls: "atmark-profile-icon" }); 34 34 35 35 if (!profile) { 36 36 // Fallback when no profile data 37 - const placeholder = wrapper.createEl("div", { cls: "semble-avatar-placeholder" }); 37 + const placeholder = wrapper.createEl("div", { cls: "atmark-avatar-placeholder" }); 38 38 placeholder.createEl("span", { text: "?" }); 39 39 return wrapper; 40 40 } 41 41 42 - const avatarBtn = wrapper.createEl("button", { cls: "semble-avatar-btn" }); 42 + const avatarBtn = wrapper.createEl("button", { cls: "atmark-avatar-btn" }); 43 43 44 44 if (profile.avatar) { 45 - const img = avatarBtn.createEl("img", { cls: "semble-avatar-img" }); 45 + const img = avatarBtn.createEl("img", { cls: "atmark-avatar-img" }); 46 46 img.src = profile.avatar; 47 47 img.alt = profile.displayName || profile.handle; 48 48 } else { ··· 53 53 .slice(0, 2) 54 54 .join("") 55 55 .toUpperCase(); 56 - avatarBtn.createEl("span", { text: initials, cls: "semble-avatar-initials" }); 56 + avatarBtn.createEl("span", { text: initials, cls: "atmark-avatar-initials" }); 57 57 } 58 58 59 - const info = wrapper.createEl("div", { cls: "semble-profile-info" }); 59 + const info = wrapper.createEl("div", { cls: "atmark-profile-info" }); 60 60 61 61 if (profile.displayName) { 62 - info.createEl("span", { text: profile.displayName, cls: "semble-profile-name" }); 62 + info.createEl("span", { text: profile.displayName, cls: "atmark-profile-name" }); 63 63 } 64 64 65 - info.createEl("span", { text: `@${profile.handle}`, cls: "semble-profile-handle" }); 65 + info.createEl("span", { text: `@${profile.handle}`, cls: "atmark-profile-handle" }); 66 66 67 67 if (onClick) { 68 68 avatarBtn.addEventListener("click", onClick);
+3 -4
src/main.ts
··· 3 3 import { DEFAULT_SETTINGS, AtProtoSettings, SettingTab } from "./settings"; 4 4 import { createAuthenticatedClient, createPublicClient } from "./auth"; 5 5 import { getProfile } from "./lib"; 6 - import { ATmarkView, VIEW_TYPE_ATMARK } from "views/atmark"; 7 - import type { ProfileData } from "components/profileIcon"; 6 + import { ATmarkView, VIEW_TYPE_ATMARK } from "./views/atmark"; 7 + import type { ProfileData } from "./components/profileIcon"; 8 8 9 9 export default class ATmarkPlugin extends Plugin { 10 10 settings: AtProtoSettings = DEFAULT_SETTINGS; ··· 19 19 return new ATmarkView(leaf, this); 20 20 }); 21 21 22 - // eslint-disable-next-line obsidianmd/ui/sentence-case 23 - this.addRibbonIcon("layers", "Open ATmark", () => { 22 + this.addRibbonIcon("layers", "Atmark", () => { 24 23 void this.activateView(VIEW_TYPE_ATMARK); 25 24 }); 26 25
+4 -9
src/settings.ts
··· 26 26 containerEl.empty(); 27 27 28 28 new Setting(containerEl) 29 - // eslint-disable-next-line obsidianmd/ui/sentence-case 30 - .setName("Handle or DID") 31 - .setDesc("Your handle or did (e.g., user.bsky.social)") 29 + .setName("Handle") 30 + .setDesc("Your bluesky handle or identifier (e.g., user.bsky.social)") 31 + // .setDesc("user.bsky.social") 32 32 .addText((text) => 33 33 text 34 - // eslint-disable-next-line obsidianmd/ui/sentence-case 35 - .setPlaceholder("user.bsky.social") 36 34 .setValue(this.plugin.settings.identifier) 37 35 .onChange(async (value) => { 38 36 this.plugin.settings.identifier = value; ··· 42 40 43 41 new Setting(containerEl) 44 42 .setName("App password") 45 - // eslint-disable-next-line obsidianmd/ui/sentence-case 46 - .setDesc("Create one at Settings → Privacy and security → App passwords") 43 + .setDesc("Create one at https://bsky.app/settings/app-passwords") 47 44 .addText((text) => { 48 45 text.inputEl.type = "password"; 49 46 text 50 - // eslint-disable-next-line obsidianmd/ui/sentence-case 51 - .setPlaceholder("xxxx-xxxx-xxxx-xxxx") 52 47 .setValue(this.plugin.settings.appPassword) 53 48 .onChange(async (value) => { 54 49 this.plugin.settings.appPassword = value;
+2 -9
src/views/atmark.ts
··· 1 - /* eslint-disable @typescript-eslint/no-explicit-any */ 2 - /* eslint-disable @typescript-eslint/no-unsafe-member-access */ 3 - /* eslint-disable @typescript-eslint/no-unsafe-return */ 4 - /* eslint-disable @typescript-eslint/no-unsafe-call */ 5 1 import { ItemView, WorkspaceLeaf, setIcon } from "obsidian"; 6 2 import type ATmarkPlugin from "../main"; 7 3 import { renderProfileIcon } from "../components/profileIcon"; 8 4 import { CardDetailModal } from "../components/cardDetailModal"; 9 - import type { ATmarkItem } from "../sources/types"; 5 + import type { ATmarkItem, DataSource, SourceFilter } from "../sources/types"; 10 6 import { SembleSource } from "../sources/semble"; 11 7 import { BookmarkSource } from "../sources/bookmark"; 12 8 import { MarginSource } from "../sources/margin"; ··· 18 14 export class ATmarkView extends ItemView { 19 15 plugin: ATmarkPlugin; 20 16 activeSource: SourceType = "semble"; 21 - sources: Map<SourceType, { source: any; filters: Map<string, any> }> = new Map(); 17 + sources: Map<SourceType, { source: DataSource; filters: Map<string, SourceFilter> }> = new Map(); 22 18 23 19 constructor(leaf: WorkspaceLeaf, plugin: ATmarkPlugin) { 24 20 super(leaf); ··· 110 106 private renderHeader(container: HTMLElement) { 111 107 const header = container.createEl("div", { cls: "atmark-header" }); 112 108 const nav = header.createEl("div", { cls: "atmark-nav" }); 113 - 114 - // eslint-disable-next-line obsidianmd/ui/sentence-case 115 - nav.createEl("h1", { text: "ATmark", cls: "atmark-title" }); 116 109 117 110 renderProfileIcon(nav, this.plugin.profile); 118 111
-1
tsconfig.json
··· 17 17 "strictBindCallApply": true, 18 18 "allowSyntheticDefaultImports": true, 19 19 "useUnknownInCatchVariables": true, 20 - "types": ["@atcute/bluesky", "@atcute/atproto", "node"], 21 20 "lib": [ 22 21 "DOM", 23 22 "ES5",