Remember when you made an A+ post last year and everyone clapped bailey.tngl.io/remember-when
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

oauth from bootleg

+182 -40
+182 -40
index.html
··· 5 5 <title>Remember When</title> 6 6 <meta name="description" content="" /> 7 7 <meta name="viewport" content="width=device-width, initial-scale=1" /> 8 - <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bluesky-post-embed/dist/core.css" 9 - <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bluesky-post-embed/themes/dim.css" 10 - <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bluesky-post-embed/themes/dark.css" 11 - <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bluesky-post-embed/themes/light.css" 8 + <link 9 + rel="stylesheet" 10 + href="https://cdn.jsdelivr.net/npm/bluesky-post-embed/dist/core.css" 11 + /> 12 + <link 13 + rel="stylesheet" 14 + href="https://cdn.jsdelivr.net/npm/bluesky-post-embed/themes/dim.css" 15 + /> 16 + <link 17 + rel="stylesheet" 18 + href="https://cdn.jsdelivr.net/npm/bluesky-post-embed/themes/dark.css" 19 + /> 20 + <link 21 + rel="stylesheet" 22 + href="https://cdn.jsdelivr.net/npm/bluesky-post-embed/themes/light.css" 23 + /> 12 24 </head> 13 25 14 26 <body> 15 27 <div> 16 28 <form id="lookupForm"> 17 29 <h1>Remember when?</h1> 18 - <label>Atmosphere account:</label> 30 + <label>Check someone else's remember when?</label> 19 31 <input required id="handle" /> 20 32 <button type="submit">Remember</button> 21 33 </form> 34 + <br /> 35 + <button id="signInButton" type="button">Check yours</button> 22 36 23 37 <div id="postView"></div> 24 38 </div> 25 39 26 40 <script type="module"> 41 + const production = window.location.host !== "127.0.0.1"; 42 + let agent = null; 43 + let atClient = null; 44 + let loggedInDid = null; 45 + let loggedInHandle = null; 46 + 47 + import { 48 + configureOAuth, 49 + createAuthorizationUrl, 50 + finalizeAuthorization, 51 + OAuthUserAgent, 52 + getSession, 53 + deleteStoredSession, 54 + } from "https://cdn.jsdelivr.net/npm/@atcute/oauth-browser-client/+esm"; 55 + 27 56 import { 28 57 LocalActorResolver, 29 58 XrpcHandleResolver, ··· 68 97 }), 69 98 }); 70 99 100 + // ---- OAuth setup ---- 101 + const redirectUri = 102 + window.location.origin + window.location.pathname; 103 + 104 + const oauthScope = "atproto repo:app.bsky.feed.post?action=create"; 105 + let clientId; 106 + if (production) { 107 + clientId = `${window.location.origin}/oauth-client-metadata.json`; 108 + } else { 109 + clientId = 110 + `http://localhost?redirect_uri=${encodeURIComponent(redirectUri)}` + 111 + `&scope=${encodeURIComponent(oauthScope)}`; 112 + } 113 + configureOAuth({ 114 + metadata: { client_id: clientId, redirect_uri: redirectUri }, 115 + identityResolver: new LocalActorResolver({ 116 + handleResolver, 117 + didDocumentResolver: new CompositeDidDocumentResolver({ 118 + methods: { 119 + plc: new PlcDidDocumentResolver(), 120 + web: new WebDidDocumentResolver(), 121 + }, 122 + }), 123 + }), 124 + }); 125 + 126 + // ---- OAuth callback / session resume on load ---- 127 + async function initAuth() { 128 + // Check for OAuth callback in hash 129 + if (location.hash && location.hash.length > 1) { 130 + try { 131 + const params = new URLSearchParams( 132 + location.hash.slice(1), 133 + ); 134 + history.replaceState( 135 + null, 136 + "", 137 + location.pathname + location.search, 138 + ); 139 + const { session } = await finalizeAuthorization(params); 140 + setAuthSession(session); 141 + console.log(`Signed in as ${loggedInDid}`, "success"); 142 + return; 143 + } catch (err) { 144 + // Hash might not be OAuth params, ignore 145 + console.warn("OAuth finalize failed:", err); 146 + } 147 + } 148 + 149 + // Try to resume existing session 150 + const storedDid = localStorage.getItem("atproto_did"); 151 + if (storedDid) { 152 + try { 153 + const session = await getSession(storedDid, { 154 + allowStale: true, 155 + }); 156 + setAuthSession(session); 157 + console.log( 158 + `Session resumed for ${loggedInDid}`, 159 + "success", 160 + ); 161 + //todo load in page here 162 + } catch (err) { 163 + localStorage.removeItem("atproto_did"); 164 + console.warn("Session resume failed:", err); 165 + } 166 + } 167 + } 168 + 169 + function setAuthSession(session) { 170 + agent = new OAuthUserAgent(session); 171 + atClient = new Client({ handler: agent }); 172 + loggedInDid = session.info.sub; 173 + localStorage.setItem("atproto_did", loggedInDid); 174 + // Resolve handle from DID 175 + // resolveOwnHandle(); 176 + } 177 + 71 178 async function lookupIdentifier(event) { 72 179 try { 73 180 event.preventDefault(); ··· 78 185 } else { 79 186 did = await handleResolver.resolve(identifier); 80 187 } 188 + await doWork(did); 189 + } catch (e) { 190 + console.error(e); 191 + alert("Failed to resolve PDS endpoint: " + e.message); 192 + } 193 + } 81 194 195 + async function doWork(did) { 196 + try { 82 197 const didDoc = await didResolver.resolve(did); 83 198 const pds = getPdsEndpoint(didDoc); // #atproto_pds 84 199 await findPostsFromThatDay(did, pds); ··· 88 203 } 89 204 } 90 205 206 + async function signIn() { 207 + const handle = window.prompt( 208 + "Enter your atmosphere handle (e.g. jcsalterego.bsky.social):", 209 + ); 210 + if (!handle) return; 211 + try { 212 + const authUrl = await createAuthorizationUrl({ 213 + target: { type: "account", identifier: handle.trim() }, 214 + scope: oauthScope, 215 + }); 216 + 217 + await new Promise((r) => setTimeout(r, 200)); 218 + window.location.assign(authUrl); 219 + } catch (err) { 220 + console.error(`Auth error: ${err.message}`, "error"); 221 + console.error(err); 222 + } 223 + } 224 + 91 225 async function findPostsFromThatDay(did, pds) { 92 226 try { 93 227 const thisDayLastYear = new Date(); ··· 141 275 ); 142 276 }); 143 277 144 - const postsWithReactions = await Promise.all(postsFromThatDay.map(async (post) => { 145 - const reactions = await getReactionCounts(post.uri); 146 - console.log(reactions) 147 - return { 148 - ...post, 149 - totalReactions: reactions.likes , 150 - }; 151 - })); 278 + const postsWithReactions = await Promise.all( 279 + postsFromThatDay.map(async (post) => { 280 + const reactions = await getReactionCounts(post.uri); 281 + console.log(reactions); 282 + return { 283 + ...post, 284 + totalReactions: reactions.likes, 285 + }; 286 + }), 287 + ); 152 288 153 289 if (postsWithReactions.length > 0) { 154 - const post = postsWithReactions.sort((a, b) => b.totalReactions - a.totalReactions).slice(0, 1)[0]; 290 + const post = postsWithReactions 291 + .sort((a, b) => b.totalReactions - a.totalReactions) 292 + .slice(0, 1)[0]; 155 293 let bskyPost = document.createElement("bluesky-post"); 156 294 bskyPost.setAttribute("src", post.uri); 157 295 document 158 296 .getElementById("postView") 159 297 .appendChild(bskyPost); 160 - }else{ 298 + } else { 161 299 alert("No posts found from that day :("); 162 300 } 163 301 } catch (e) { ··· 166 304 } 167 305 } 168 306 169 - async function getReactionCounts(atUri){ 170 - const getLikes = await constellationClient.get( 171 - "blue.microcosm.links.getBacklinkDids", 172 - { 173 - params: { 174 - subject: atUri, 175 - source: "app.bsky.feed.like:subject.uri", 307 + async function getReactionCounts(atUri) { 308 + const getLikes = await constellationClient.get( 309 + "blue.microcosm.links.getBacklinkDids", 310 + { 311 + params: { 312 + subject: atUri, 313 + source: "app.bsky.feed.like:subject.uri", 314 + }, 176 315 }, 177 - }, 178 - ) 316 + ); 179 317 180 - const likes = getLikes.data.total; 318 + const likes = getLikes.data.total; 181 319 182 - const getReposts = await constellationClient.get( 183 - "blue.microcosm.links.getBacklinkDids", 184 - { 185 - params: { 186 - subject: atUri, 187 - source: "app.bsky.feed.repost:subject.uri", 320 + const getReposts = await constellationClient.get( 321 + "blue.microcosm.links.getBacklinkDids", 322 + { 323 + params: { 324 + subject: atUri, 325 + source: "app.bsky.feed.repost:subject.uri", 326 + }, 188 327 }, 189 - }, 190 - ) 328 + ); 191 329 192 - const reposts = getReposts.data.total; 330 + const reposts = getReposts.data.total; 193 331 194 - return { 195 - likes, 196 - reposts, 197 - total: likes + reposts, 198 - }; 332 + return { 333 + likes, 334 + reposts, 335 + total: likes + reposts, 336 + }; 199 337 } 200 338 201 - 202 339 //Start up code on dom loaded 203 340 document.addEventListener("DOMContentLoaded", function () { 204 341 const lookUpForm = document.getElementById("lookupForm"); 205 342 lookUpForm.addEventListener("submit", lookupIdentifier); 343 + 344 + const signInButton = document.getElementById("signInButton"); 345 + signInButton.addEventListener("click", signIn); 346 + 347 + initAuth(); 206 348 }); 207 349 </script> 208 350 </body>