Skip to content

Commit 2c1f2b2

Browse files
committed
add profile embed
1 parent e57c6e5 commit 2c1f2b2

7 files changed

Lines changed: 264 additions & 19 deletions

File tree

bun.lock

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"@atcute/pckt": "^0.1.5",
3737
"@atcute/standard-site": "^1.0.0",
3838
"bluesky-post-embed": "^1.0.6",
39+
"bluesky-profile-card-embed": "^1.0.1",
3940
"obsidian": "latest",
4041
"remark-parse": "^11.0.0",
4142
"remark-stringify": "^11.0.0",

src/commands/publishDocument.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ async function buildDocumentRecord(plugin: AtmospherePlugin, file: TFile): Promi
145145

146146
let richContent: PubLeafletContent.Main | BlogPcktContent.Main | null = null;
147147
if (pub?.url.contains("leaflet.pub")) {
148-
richContent = markdownToLeafletContent(resolved)
148+
richContent = await markdownToLeafletContent(resolved)
149149
} else if (pub?.url.contains("pckt.blog")) {
150150
richContent = markdownToPcktContent(resolved)
151151
}

src/main.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { StandardFeedView, VIEW_ATMOSPHERE_STANDARD_FEED } from "views/standardf
66
import { ATClient } from "lib/client";
77
import { Clipper } from "lib/clipper";
88
import { registerIcons } from "./icons";
9-
import { BlueskyPostProcessor } from "./postprocessor";
9+
import { BskyEmbedProcessor } from "./postprocessor";
1010

1111
export default class AtmospherePlugin extends Plugin {
1212
settings: AtProtoSettings = DEFAULT_SETTINGS;
@@ -36,7 +36,7 @@ export default class AtmospherePlugin extends Plugin {
3636
}
3737
});
3838

39-
const bskyProcessor = new BlueskyPostProcessor();
39+
const bskyProcessor = new BskyEmbedProcessor();
4040
this.registerMarkdownPostProcessor((el, ctx) => bskyProcessor.process(el, ctx));
4141

4242
this.registerView(VIEW_TYPE_ATMOSPHERE_BOOKMARKS, (leaf) => {

src/postprocessor.ts

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,35 @@
11
import { Component, MarkdownPostProcessorContext, setIcon } from "obsidian";
2-
import { BSKY_POST_RE, bskyPostATUri } from "./util";
2+
import { BSKY_POST_RE, BSKY_PROFILE_RE, bskyPostATUri, bskyProfileActor } from "./util";
33

4-
5-
export class BlueskyPostProcessor extends Component {
4+
export class BskyEmbedProcessor extends Component {
65

76
async process(el: HTMLElement, _ctx: MarkdownPostProcessorContext) {
8-
97
if (!customElements.get("bluesky-post")) {
108
import("bluesky-post-embed");
9+
import("bluesky-profile-card-embed");
1110
}
1211

1312
const links = el.findAll("a").filter(link => {
1413
const href = link.getAttribute("href") ?? "";
15-
return BSKY_POST_RE.test(href);
14+
return BSKY_POST_RE.test(href) || BSKY_PROFILE_RE.test(href);
1615
});
1716

1817
if (links.length === 0) return;
1918

2019
for (const link of links) {
21-
const atUri = bskyPostATUri(link.getAttribute("href") ?? "");
22-
if (!atUri) continue;
23-
24-
this.attachToggle(link, atUri);
20+
const postUri = bskyPostATUri(link.getAttribute("href") ?? "");
21+
if (postUri) {
22+
this.attachToggle(link, postUri);
23+
return;
24+
}
25+
const actor = bskyProfileActor(link.getAttribute("href") ?? "");
26+
if (actor) {
27+
this.attachToggle(link, undefined, actor);
28+
}
2529
}
2630
}
2731

28-
private attachToggle(link: HTMLElement, uri: string) {
29-
const embedId = `bsky-embed-${uri.replace(/[:\/]/g, "-")}`;
30-
32+
private attachToggle(link: HTMLElement, uri?: string, actor?: string) {
3133
const btn = document.createElement("button");
3234
btn.setAttribute("aria-label", "Toggle post embed");
3335
btn.addClass("bsky-embed-toggle");
@@ -36,18 +38,32 @@ export class BlueskyPostProcessor extends Component {
3638
link.insertAdjacentElement("afterend", btn);
3739

3840
btn.addEventListener("click", () => {
41+
let embedId = "";
42+
if (uri) {
43+
embedId = `bsky-post-embed-${uri.replace(/[:\/]/g, "-")}`;
44+
} else if (actor) {
45+
embedId = `bsky-profile-${actor.replace(/[:\/]/g, "-")}`;
46+
} else {
47+
return;
48+
}
3949
const existing = document.getElementById(embedId);
4050
if (existing) {
4151
existing.remove();
4252
setIcon(btn, "message-circle");
4353
return;
4454
}
4555

46-
const embedEl = document.createElement("bluesky-post") as HTMLElement;
56+
let embedEl: HTMLElement;
57+
if (actor) {
58+
embedEl = document.createElement("bluesky-profile-card") as HTMLElement;
59+
embedEl.setAttribute("actor", actor);
60+
} else {
61+
embedEl = document.createElement("bluesky-post") as HTMLElement;
62+
embedEl.setAttribute("src", uri!);
63+
}
64+
4765
embedEl.id = embedId;
48-
embedEl.setAttribute("src", uri);
4966
embedEl.setAttribute("allow-unauthenticated", "");
50-
embedEl.addClass("bsky-post-embed-wrapper");
5167

5268
btn.insertAdjacentElement("afterend", embedEl);
5369
setIcon(btn, "x");

src/util.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,20 @@ export async function fetchOgImage(url: string): Promise<string | undefined> {
3737
}
3838

3939
export const BSKY_POST_RE = /https:\/\/bsky\.app\/profile\/([^/?#]+)\/post\/([A-Za-z0-9]+)/;
40+
export const BSKY_PROFILE_RE = /https:\/\/bsky\.app\/profile\/([^/?#]+)/;
41+
42+
export function bskyProfileActor(url: string): ActorIdentifier | null {
43+
const match = url.match(BSKY_PROFILE_RE);
44+
if (!match) return null;
45+
46+
const [, handleOrDid] = match;
47+
if (!handleOrDid) return null;
48+
49+
if (!isActorIdentifier(handleOrDid)) {
50+
return null
51+
}
52+
return handleOrDid;
53+
}
4054

4155
export function bskyPostATUri(url: string): ResourceUri | null {
4256
const match = url.match(BSKY_POST_RE);
@@ -69,7 +83,7 @@ export function UrlToRecordUri(url: string): ResourceUri | null {
6983
* Given an AT URI that may contain a handle, resolve the handle to a DID
7084
* and return the canonical AT URI
7185
*/
72-
export async function resolveHandleInAtUri(uri: ResourceUri): Promise<ResourceUri| null> {
86+
export async function resolveHandleInAtUri(uri: ResourceUri): Promise<ResourceUri | null> {
7387
const parsed = parseResourceUri(uri);
7488
if (!parsed.ok) return uri;
7589

0 commit comments

Comments
 (0)