+1
-2
live-embed/index.html
+1
-2
live-embed/index.html
···
2
2
<html lang="en">
3
3
<head>
4
4
<meta charset="UTF-8" />
5
-
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
5
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
-
<title>Vite + React + TS</title>
6
+
<title>zero bluesky live-updating post rendering</title>
8
7
</head>
9
8
<body>
10
9
<div id="root"></div>
+5
live-embed/src/App.css
+5
live-embed/src/App.css
+18
-2
live-embed/src/App.tsx
+18
-2
live-embed/src/App.tsx
···
44
44
45
45
return (
46
46
<>
47
-
<h1>zero bluesky infra post rendering</h1>
48
-
<p className="with">with live-updating interaction counts</p>
47
+
<h1>zero bluesky infra post rendering (WIP)</h1>
48
+
<p className="with">with real-time interaction count updates</p>
49
49
<div className="posts">
50
50
{currentPair.map(p => (
51
51
<Post key={p} atUri={p} updatedLinks={updates[p]} />
52
52
))}
53
53
</div>
54
+
55
+
<div className="explain">
56
+
<h2>How does it work?</h2>
57
+
<ul>
58
+
<li><strong>Post content</strong>: fetches direct from PDS with <a href="https://github.com/mary-ext/atcute" target="_blank">atcute</a>.</li>
59
+
<li><strong>Interaction counts</strong>: queries <a href="https://constellation.microcosm.blue/" target="_blank">constellation</a>.</li>
60
+
<li><strong>Interaction updates</strong>: subscribes to <a href="https://spacedust.microcosm.blue/" target="_blank">spacedust</a>.</li>
61
+
<li>There is no backend.</li>
62
+
</ul>
63
+
<p>The post selection takes a couple top posts from the public bluesky Discover feed so I guess it's kind of cheating but hey.</p>
64
+
<p>Oh and media files load from Bluesky's CDN so that's also cheating.</p>
65
+
66
+
<h2>If you actually want to embed a post</h2>
67
+
<p>See <a href="https://mary-ext.codeberg.page/bluesky-embed/" target="_blank"><code><bluesky-embed></code></a> from <a href="https://mary.my.id" target="_blank">mary</a>. It's a very solid post renderer, unlike this demo.</p>
68
+
</div>
69
+
54
70
</>
55
71
)
56
72
}
+9
live-embed/src/Post.css
+9
live-embed/src/Post.css
···
1
1
.post {
2
2
background-color: rgb(32, 41, 53);
3
3
border: 1px solid rgb(46, 64, 82);
4
+
border-radius: 0.1em;
4
5
display: flex;
6
+
flex-basis: 20em;
5
7
flex-direction: column;
8
+
min-width: 12em;
6
9
max-width: 24em;
7
10
}
8
11
···
31
34
.stat.like:before {
32
35
content: "♡ ";
33
36
}
37
+
38
+
@media (prefers-color-scheme: light) {
39
+
.post {
40
+
background-color: rgb(241, 243, 245);
41
+
}
42
+
}
+1
-1
live-embed/src/constellation.ts
+1
-1
live-embed/src/constellation.ts
···
16
16
) {
17
17
const url = new URL('/links/all', endpoint);
18
18
url.searchParams.set('target', atUri);
19
-
const res = await fetch(url);
19
+
const res = await fetch(url, { signal: AbortSignal.timeout(4000) });
20
20
if (!res.ok) throw new Error(res);
21
21
const { links } = await res.json();
22
22
+4
live-embed/src/index.css
+4
live-embed/src/index.css