pds dash for shimaenaga.veryroundbird.house (based off of pds.witchcraft.systems)

implement easter egg + guestbook

Changed files
+65 -42
src
themes
birdrights
+14 -19
src/App.svelte
··· 10 10 let posts: Post[] = []; 11 11 let guestbookPosts: Post[] = []; 12 12 13 - let hue: number = 1; 14 - const cycleColors = async () => { 15 - while (true) { 16 - hue += 1; 17 - if (hue > 360) { 18 - hue = 0; 19 - } 20 - document.documentElement.style.setProperty("--primary-h", hue.toString()); 21 - await new Promise((resolve) => setTimeout(resolve, 10)); 22 - } 23 - } 24 13 let clickCounter = 0; 25 - const carameldansenfusion = async () => { 14 + const birdbrain = async () => { 26 15 clickCounter++; 27 16 if (clickCounter >= 10) { 28 17 clickCounter = 0; 29 - cycleColors(); 18 + document.getElementById('birdbrain').showPopover(); 30 19 } 31 20 }; 32 21 ··· 36 25 posts = initialPosts; 37 26 }); 38 27 fetchGuestbookPosts().then((gbPosts) => { 39 - guestbookPosts = gbPosts; 40 28 console.log(gbPosts); 29 + guestbookPosts = gbPosts; 41 30 }); 42 31 }); 43 32 // Infinite loading function ··· 85 74 █▓█▓▓█ ███▓█ 86 75 ████ ████ 87 76 </pre> 88 - <h1 onclick={carameldansenfusion} id="header">shimaenaga pds</h1> 77 + <h1 onclick={birdbrain} id="header">shimaenaga pds</h1> 89 78 <p id="subtitle">a project of <a href="https://veryroundbird.house" target="_blank">veryroundbird.house</a></p> 90 79 {#if Config.SHOW_GUESTBOOK} 91 80 <div id="guestbook"> ··· 93 82 <div id="guestbookContents" popover> 94 83 <div id="signInfo">You can sign the guestbook <a href="{Config.GUESTBOOK_POST}" target="_blank">here</a>!</div> 95 84 <div id="guestbookPosts"> 96 - {#each guestbookPosts as postObject} 97 - <div class="guestbookPost"> 98 - </div> 99 - {/each} 85 + {#if guestbookPosts.length > 0} 86 + {#each guestbookPosts as postObject} 87 + <PostComponent post={postObject as Post} /> 88 + {/each} 89 + {:else} 90 + <p class="noGuestbookPosts">No guestbook posts yet!</p> 91 + {/if} 100 92 </div> 101 93 </div> 102 94 </div> ··· 120 112 <InfiniteLoading on:infinite={onInfinite} distance={3000} /> 121 113 </div> 122 114 </div> 115 + <div id="birdbrain" popover> 116 + <iframe width="560" height="315" src="https://www.youtube.com/embed/0iVlSNpq8i8?si=Ao4bcr_4HIBqsBy2" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> 117 + </div> 123 118 </main>
+1 -2
src/lib/AccountComponent.svelte
··· 1 1 <script lang="ts"> 2 2 import type { AccountMetadata } from "./pdsfetch"; 3 3 const { account }: { account: AccountMetadata } = $props(); 4 - console.log(account); 5 4 import { Config } from "../../config"; 6 5 </script> 7 6 8 - <button class="accountBtn" type="button" popovertarget="{account.handle.replace('.')}" title="{account.handle}"> 7 + <button class="accountBtn" type="button" popovertarget="{account.handle.replace('.', '')}" title="{account.handle}"> 9 8 <div class="accountContainer"> 10 9 {#if account.avatarCid} 11 10 <img
+34 -16
src/lib/pdsfetch.ts
··· 368 368 const match = uri.match(/profile\/([\w.]+)\/post\/([\w]+)/); 369 369 if (match) { 370 370 const [, did, postId] = match; 371 - return `at://${did}/app.bsky.feed.post/${postId}` as At.Did; 371 + try { 372 + return `at://${did}/app.bsky.feed.post/${postId}`; 373 + } catch (e) { 374 + console.error("Invalid Bluesky post URL format", e); 375 + return null; 376 + } 372 377 } 373 378 } 374 - 375 - this.error = "Invalid Bluesky post URL format"; 376 - return null; 377 379 } 378 380 379 381 const fetchGuestbookPosts = async () => { 380 - try { 381 - const { data } = await rpc.get("app.bsky.feed.getPostThread", { 382 - params: { 383 - uri: convertUri(Config.GUESTBOOK_POST) 384 - } 385 - }); 386 - 387 - return data.records as ComAtprotoRepoListRecords.Record[]; 388 - } catch (e) { 389 - console.error(`Error fetching replies for ${did}. Are you sure this is a Bluesky post?`, e); 390 - return null; 391 - } 382 + const params = new URLSearchParams({ uri: convertUri(Config.GUESTBOOK_POST) }); 383 + const url = `https://public.api.bsky.app/xrpc/app.bsky.feed.getPostThread?${params.toString()}`; 384 + 385 + try { 386 + const response = await fetch(url, { 387 + method: "GET", 388 + headers: { 389 + Accept: "application/json", 390 + }, 391 + cache: "no-store", 392 + }); 393 + 394 + if (!response.ok) { 395 + const errorText = await response.text(); 396 + console.error("Fetch Error: ", errorText); 397 + throw new Error(`Failed to fetch thread: ${response.statusText}`); 398 + } 399 + 400 + const data = await response.json(); 401 + 402 + if (!data.thread || !data.thread.replies) { 403 + throw new Error("Invalid thread data: Missing expected properties."); 404 + } 405 + 406 + return data.thread.replies; 407 + } catch (e) { 408 + console.error("Is this the wrong kind of Bluesky object?", e); 409 + } 392 410 } 393 411 394 412 export { getAllMetadataFromPds, getNextPosts, Post, fetchGuestbookPosts };
+16 -5
themes/birdrights/theme.css
··· 396 396 #guestbookContents { 397 397 width: 100%; 398 398 max-width: 600px; 399 - border: 1px var(--border-color) solid; 400 - color: var(--text-color); 401 - background-color: var(--content-background-color); 402 - backdrop-filter: blur(5px); 403 399 height: calc(100vh - 20px); 404 400 padding: 10px; 405 - border-radius: 5px; 406 401 gap: 10px; 407 402 z-index: 10; 408 403 } ··· 440 435 #accountsList { 441 436 grid-template-columns: repeat(6, 1fr); 442 437 } 438 + } 439 + 440 + /* Popovers */ 441 + [popover] { 442 + padding: 0; 443 + max-width: 600px; 444 + border: 1px var(--border-color) solid; 445 + color: var(--text-color); 446 + background-color: var(--content-background-color); 447 + backdrop-filter: blur(5px); 448 + border-radius: 5px; 449 + z-index: 10; 450 + } 451 + 452 + [popover] iframe { 453 + display: block; 443 454 } 444 455 445 456 /* Scrollbars */