🐍🐍🐍
1
2$css(`
3 .bsky {
4 line-height: 1.5em;
5 }
6
7 .bsky .profile .title {
8 line-height: 1.25em;
9 text-align: center;
10 margin: auto;
11 width: fit-content;
12 border-bottom: 3px double var(--main-faded);
13 padding-left: 0.75em;
14 padding-right: 0.75em;
15 margin-top: 0.3em;
16 }
17
18 .bsky .profile .handle {
19 font-size: 0.8em;
20 text-align: center;
21 color: var(--main-faded);
22 }
23
24 .bsky .profile .avatar {
25 height: 6em;
26 border-radius: 3px;
27 flex-shrink: 0;
28 border: 1px solid var(--main-solid);
29 }
30
31 .bsky .profile .id-header {
32 display: flex;
33 padding-bottom: 1em;
34 }
35
36 .bsky .profile .names {
37 padding-top: 0em;
38 width: 100%;
39 }
40
41 .bsky .quoted {
42 position: relative;
43 overflow: visible;
44 margin-bottom: 1em;
45 max-width: calc(100% - 2em);
46 }
47
48 .bsky .quoted::before {
49 content: '“';
50 padding-right: 0.5em;
51 font-size: 2em;
52 font-family: "Garamond", "Times New Roman", "Georgia", serif;
53 }
54
55 .bsky .quoted::after {
56 content: '”';
57 padding-left: 0.5em;
58 font-size: 2em;
59 position: absolute;
60 bottom: 0px;
61 font-family: "Garamond", "Times New Roman", "Georgia", serif;
62 }
63
64 .bsky .publications .banner {
65 max-height: 15em;
66 border-radius: 3px;
67 width: 100%;
68 }
69
70 .bsky .publications .thumbnail {
71 border-radius: 3px;
72 max-width: 80%;
73 margin: auto;
74 }
75
76 .bsky a.external {
77 color: var(--main-solid);
78 }
79
80 .bsky .pin-container {
81 display: inline-flex;
82 flex-direction: column;
83 max-width: calc(100% - 2em);
84 }
85 .
86`);
87
88async function getPublicData(endpoint, params = {}) {
89 if (!endpoint) throw new Error("endpoint required");
90
91 const url = new URL(`https://public.api.bsky.app/xrpc/${endpoint}`);
92 Object.entries(params).forEach(([key, value]) => {
93 if (value !== undefined) url.searchParams.set(key, value);
94 });
95
96 const response = await fetch(url);
97 if (!response.ok) {
98 const error = await response.json().catch(() => ({}));
99 throw new Error(`Request failed: ${error.message || response.statusText}`);
100 }
101
102 return response.json();
103}
104
105const profile = await getPublicData("app.bsky.actor.getProfile", {
106 actor: "ponder.ooo"
107});
108
109const pinned = (await getPublicData("app.bsky.feed.getPosts", {
110 uris: [profile.pinnedPost.uri]
111})).posts[0];
112
113console.log(pinned);
114
115export async function main(target) {
116 const container = $div("full bsky");
117
118 const profileContainer = $div("full profile");
119
120 const publications = $div("full publications");
121
122 await $mod("layout/split", container, [{ content: [profileContainer, publications], percents: [40, 60]}]);
123
124 const idHeader = $div("id-header");
125
126 const names = $div("names");
127
128 const handle = $div("handle");
129 handle.innerText = `@${profile.handle}`;
130
131 const title = $element("h1");
132 title.innerText = profile.displayName;
133 title.classList = "title";
134
135 const description = $element("p");
136 description.innerText = profile.description;
137 description.classList = "quoted";
138
139 const avatar = $element("img");
140 avatar.src = profile.avatar;
141 avatar.classList = "avatar";
142
143 const readers = $div();
144 readers.innerText = `${profile.followersCount} readers`;
145
146 const pubCount = $div();
147 pubCount.innerText = `${profile.postsCount} publications`;
148
149 const banner = $element("img");
150 banner.src = profile.banner;
151 banner.classList = "banner";
152 publications.appendChild(banner);
153
154 if (pinned.embed?.$type === "app.bsky.embed.images#view") {
155 const pin = $div("quoted");
156
157 const pinContainer = $div("pin-container");
158
159 const pinText = $element("p");
160 pinText.innerText = pinned.record.text;
161 pinContainer.appendChild(pinText);
162
163 for (const imageData of pinned.embed.images) {
164 const image = $element("img");
165 image.src = imageData.thumb;
166 image.classList = "thumbnail";
167 pinContainer.appendChild(image);
168 }
169
170 publications.$with(pin.$with(pinContainer));
171 }
172 else if (pinned.embed?.$type === "app.bsky.embed.external#view") {
173 const pin = $div("quoted");
174
175 const pinContainer = $div("pin-container");
176
177 const pinText = $element("p");
178 pinText.innerText = pinned.record.text;
179 pinContainer.appendChild(pinText);
180
181 const embedTitle = $element("a");
182 embedTitle.href = pinned.embed.external.uri;
183 embedTitle.innerText = pinned.embed.external.title;
184 embedTitle.classList = "external";
185
186 const image = $element("img");
187 image.src = pinned.embed.external.thumb;
188 image.classList = "thumbnail";
189
190 pinContainer.appendChild(embedTitle);
191 pinContainer.appendChild(image);
192
193 pin.appendChild(pinContainer);
194 publications.appendChild(pin);
195
196 }
197 else {
198 const pin = $element("p");
199 pin.innerText = pinned.record.text;
200 pin.classList = "quoted";
201 publications.appendChild(pin);
202 }
203
204 profileContainer.$with(
205 idHeader.$with(
206 avatar,
207 names.$with(
208 title,
209 handle
210 )
211 ),
212 description,
213 pubCount,
214 readers
215 );
216
217 target.$with(container);
218
219 return { replace: true };
220}
221
222console.log(profile);
223