🐍🐍🐍
at main 223 lines 5.6 kB view raw
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