tangled
alpha
login
or
join now
jordanreger.com
/
htmlsky
0
fork
atom
An HTML-only Bluesky frontend
0
fork
atom
overview
issues
pulls
pipelines
minor formatting changes
jordanreger.com
2 years ago
c301f25a
18c003b9
+73
-72
3 changed files
expand all
collapse all
unified
split
actor.js
deno.json
main.js
+60
-53
actor.js
···
1
1
import { agent } from "./main.js";
2
2
-
import { getFacets, getDescriptionFacets } from "./facets.js";
2
2
+
import { getFacets } from "./facets.js";
3
3
4
4
const DateTimeFormat = new Intl.DateTimeFormat("en-US", {
5
5
dateStyle: "short",
···
29
29
30
30
actor.username = actor.displayName ? actor.displayName : actor.handle;
31
31
actor.avatar = actor.avatar ? actor.avatar : "/static/avatar.jpg";
32
32
+
actor.description = actor.description ? `<tr><td colspan="2"><p>${await getFacets(actor.description).then((res) => res.replaceAll("\n", "<br>"))}</p></td></tr><tr><td colspan="2"> </td></tr>` : "";
32
33
33
34
return `
34
35
<head>
···
48
49
</h1>
49
50
</td>
50
51
</tr>
51
51
-
${
52
52
-
actor.description
53
53
-
? `<tr>
54
54
-
<td colspan="2">
55
55
-
<p>${await getDescriptionFacets(actor.description).then((res) => res.replaceAll("\n", "<br>"))}</p>
56
56
-
</td>
57
57
-
</tr>
58
58
-
<tr>
59
59
-
<td colspan="2"> </td>
60
60
-
</tr>`
61
61
-
: ``
62
62
-
}
52
52
+
${actor.description}
63
53
<tr>
64
54
<td colspan="2">
65
55
<a href="./followers/"><b>${actor.followersCount}</b> followers</a>
···
87
77
for (const post of feed) {
88
78
if (post.reply) {
89
79
const reply = post.reply.parent ? post.reply.parent : post.reply.root;
90
90
-
const author = reply.author;
91
80
if (reply.notFound || reply.blocked) {
92
81
feedList.push(`
93
93
-
<tr>
94
94
-
<td>
95
95
-
<table>
96
96
-
<tr><td>
97
97
-
Post was deleted.
98
98
-
</td></tr>
99
99
-
</table>
100
100
-
</td>
101
101
-
</tr>
82
82
+
<tr><td>
83
83
+
<table>
84
84
+
<tr><td>
85
85
+
Post not found.
86
86
+
</td></tr>
87
87
+
</table>
88
88
+
</td></tr>
102
89
`);
103
90
} else {
104
91
feedList.push(`
105
92
<tr>
106
93
<td>
107
94
<table>
108
108
-
<tr><td><b>${reply.author.displayName ? reply.author.displayName : reply.author.handle}</b> (<a href="/profile/${reply.author.handle !== "handle.invalid" ? reply.author.handle : reply.author.did}/">@${reply.author.handle}</a>) · ${DateTimeFormat.format(new Date(reply.record.createdAt))}</td></tr>
109
109
-
<tr><td>${await getFacets(reply.record.text).then((res) => res.replaceAll("\n", "<br>"))}</td></tr>
110
110
-
<tr><td><b>${reply.replyCount}</b> replies · <b>${reply.repostCount}</b> reposts · <b>${reply.likeCount}</b> likes</td></tr>
95
95
+
<tr><td>
96
96
+
<b>${reply.author.displayName ? reply.author.displayName : reply.author.handle}</b> (<a href="/profile/${reply.author.handle !== "handle.invalid" ? reply.author.handle : reply.author.did}/">@${reply.author.handle}</a>) · ${DateTimeFormat.format(new Date(reply.record.createdAt))}
97
97
+
</td></tr>
98
98
+
<tr><td>
99
99
+
<p>${await getFacets(reply.record.text).then((res) => res.replaceAll("\n", "<br>"))}</p>
100
100
+
</td></tr>
101
101
+
<tr><td>
102
102
+
<b>${reply.replyCount}</b> replies ·
103
103
+
<b>${reply.repostCount}</b> reposts ·
104
104
+
<b>${reply.likeCount}</b> likes
105
105
+
</td></tr>
111
106
</table>
112
107
</td>
113
108
</tr>
···
119
114
const author = post.post.author;
120
115
121
116
feedList.push(`
122
122
-
<tr>
123
123
-
<td>
124
124
-
${post.reply ? `<blockquote>` : ``}
125
125
-
<table>
117
117
+
<tr><td>
118
118
+
${post.reply ? `<blockquote>` : ``}
119
119
+
<table>
126
120
${actor.did !== author.did ? `<tr><td><i>Reposted by ${actor.displayName ? actor.displayName : actor.handle}</i></td></tr>` : ``}
127
127
-
<tr><td><b>${author.displayName ? author.displayName : author.handle}</b> (<a href="/profile/${author.handle !== "handle.invalid" ? author.handle : author.did }/">@${author.handle}</a>) · ${DateTimeFormat.format(new Date(record.createdAt))}</td></tr>
128
128
-
<tr><td><p>${await getFacets(record.text).then((res) => res.replaceAll("\n", "<br>"))}</p></td></tr>
121
121
+
<tr><td>
122
122
+
<b>${author.displayName ? author.displayName : author.handle}</b> (<a href="/profile/${author.handle !== "handle.invalid" ? author.handle : author.did }/">@${author.handle}</a>)
123
123
+
·
124
124
+
${DateTimeFormat.format(new Date(record.createdAt))}
125
125
+
</td></tr>
129
126
<tr><td>
130
130
-
${/*post.post.record.embed ? `<pre>${JSON.stringify(post.post.record.embed, null, 2)}</pre>` : */``}
127
127
+
<p>${await getFacets(record.text).then((res) => res.replaceAll("\n", "<br>"))}</p>
131
128
</td></tr>
132
132
-
<tr><td><b>${post.post.replyCount}</b> replies · <b>${post.post.repostCount}</b> reposts · <b>${post.post.likeCount}</b> likes</td></tr>
133
133
-
</table>
134
134
-
${post.reply ? `</blockquote><hr>` : `<hr>`}
135
135
-
</td>
136
136
-
</tr>
129
129
+
<tr><td>
130
130
+
${/*post.post.record.embed ? `<pre>${JSON.stringify(post.post.record.embed, null, 2)}</pre>` : */``}
131
131
+
</td></tr>
132
132
+
<tr><td>
133
133
+
<b>${post.post.replyCount}</b> replies ·
134
134
+
<b>${post.post.repostCount}</b> reposts ·
135
135
+
<b>${post.post.likeCount}</b> likes
136
136
+
</td></tr>
137
137
+
</table>
138
138
+
${post.reply ? `</blockquote><hr>` : `<hr>`}
139
139
+
</td></tr>
137
140
`);
138
141
}
139
142
140
143
if (cursor) {
141
144
feedList.push(`
142
142
-
<tr>
143
143
-
<td><br><a href="?cursor=${cursor}">Next page</a></td>
144
144
-
</tr>
145
145
+
<tr><td>
146
146
+
<br>
147
147
+
<a href="?cursor=${cursor}">Next page</a>
148
148
+
</td></tr>
145
149
`);
146
150
}
147
151
···
166
170
const followersList = [];
167
171
for (const follower of followers) {
168
172
followersList.push(`
169
169
-
<tr>
170
170
-
<td><b>${follower.displayName ? follower.displayName : follower.handle}</b> (<a href="/profile/${follower.handle !== "handle.invalid" ? follower.handle : follower.did}/">@${follower.handle}</a>)</td>
171
171
-
</tr>`);
173
173
+
<tr><td>
174
174
+
<b>${follower.displayName ? follower.displayName : follower.handle}</b> (<a href="/profile/${follower.handle !== "handle.invalid" ? follower.handle : follower.did}/">@${follower.handle}</a>)
175
175
+
</td></tr>`);
172
176
}
173
177
174
178
if (cursor) {
175
179
followersList.push(`
176
176
-
<tr>
177
177
-
<td><br><a href="?cursor=${cursor}">Next page</a></td>
178
178
-
</tr>
180
180
+
<tr><td>
181
181
+
<br>
182
182
+
<a href="?cursor=${cursor}">Next page</a>
183
183
+
</td></tr>
179
184
`);
180
185
}
181
186
···
205
210
const followsList = [];
206
211
for (const follow of follows) {
207
212
followsList.push(`
208
208
-
<tr>
209
209
-
<td><b>${follow.displayName ? follow.displayName : follow.handle}</b> (<a href="/profile/${follow.handle !== "handle.invalid" ? follow.handle : follow.did}/">@${follow.handle}</a>)</td>
210
210
-
</tr>`);
213
213
+
<tr><td>
214
214
+
<b>${follow.displayName ? follow.displayName : follow.handle}</b> (<a href="/profile/${follow.handle !== "handle.invalid" ? follow.handle : follow.did}/">@${follow.handle}</a>)
215
215
+
</td>
216
216
+
</tr>`);
211
217
}
212
218
213
219
if (cursor) {
214
220
followsList.push(`
215
215
-
<tr>
216
216
-
<td><br><a href="?cursor=${cursor}">Next page</a></td>
217
217
-
</tr>
221
221
+
<tr><td>
222
222
+
<br>
223
223
+
<a href="?cursor=${cursor}">Next page</a>
224
224
+
</td></tr>
218
225
`);
219
226
}
220
227
+1
-1
deno.json
···
1
1
{
2
2
"tasks": {
3
3
-
"dev": "deno run -A --watch main.js",
3
3
+
"dev": "deno run -A --watch --quiet main.js",
4
4
"clean": "deno fmt && deno lint"
5
5
}
6
6
}
+12
-18
main.js
···
30
30
31
31
try {
32
32
// PROFILE
33
33
-
const profilePattern = new URLPattern({ pathname: "/profile/:actor/" });
33
33
+
const profilePattern = new URLPattern({ pathname: "/profile/:identifier/:page?/" });
34
34
if (profilePattern.test(url)) {
35
35
-
const actorName = profilePattern.exec(url)?.pathname.groups.actor;
36
36
-
const actor = new Actor(actorName);
35
35
+
const identifier = profilePattern.exec(url)?.pathname.groups.identifier,
36
36
+
page = profilePattern.exec(url)?.pathname.groups.page;
37
37
+
38
38
+
// TODO: move API calls out
39
39
+
40
40
+
const actor = new Actor(identifier);
37
41
const cursor = query.get("cursor");
38
38
-
if (cursor) return new Response(await actor.HTML(cursor), html_headers);
39
39
-
else return new Response(await actor.HTML(), html_headers);
40
40
-
}
41
42
42
42
-
// RAW PROFILE
43
43
-
const rawProfilePattern = new URLPattern({
44
44
-
pathname: "/raw/profile/:actor/",
45
45
-
});
46
46
-
if (rawProfilePattern.test(url)) {
47
47
-
const actorName = rawProfilePattern.exec(url)?.pathname.groups.actor;
48
48
-
const actor = new Actor(actorName);
43
43
+
// TODO: move pages here
49
44
50
50
-
return new Response(await actor.Raw(), json_headers);
45
45
+
if (cursor) return new Response(await actor.HTML(cursor), html_headers);
46
46
+
else return new Response(await actor.HTML(), html_headers);
51
47
}
52
48
53
53
-
// FOLLOWERS, FOLLOWING
54
54
-
const pageProfilePattern = new URLPattern({
55
55
-
pathname: "/profile/:actor/:page/",
56
56
-
});
49
49
+
/*
57
50
if (pageProfilePattern.test(url)) {
58
51
const actorName = pageProfilePattern.exec(url)?.pathname.groups.actor;
59
52
const pageName = pageProfilePattern.exec(url)?.pathname.groups.page;
···
72
65
} else return new Response(await actor.Follows(), html_headers);
73
66
}
74
67
}
68
68
+
*/
75
69
} catch (error) {
76
70
return new Response(
77
71
`<head><meta name="color-scheme" content="light dark"></head>\n${error}`,