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
···
let posts: Post[] = [];
let guestbookPosts: Post[] = [];
-
let hue: number = 1;
-
const cycleColors = async () => {
-
while (true) {
-
hue += 1;
-
if (hue > 360) {
-
hue = 0;
-
}
-
document.documentElement.style.setProperty("--primary-h", hue.toString());
-
await new Promise((resolve) => setTimeout(resolve, 10));
-
}
-
}
let clickCounter = 0;
-
const carameldansenfusion = async () => {
+
const birdbrain = async () => {
clickCounter++;
if (clickCounter >= 10) {
clickCounter = 0;
-
cycleColors();
+
document.getElementById('birdbrain').showPopover();
}
};
···
posts = initialPosts;
});
fetchGuestbookPosts().then((gbPosts) => {
-
guestbookPosts = gbPosts;
console.log(gbPosts);
+
guestbookPosts = gbPosts;
});
});
// Infinite loading function
···
█▓█▓▓█ ███▓█
████ ████
</pre>
-
<h1 onclick={carameldansenfusion} id="header">shimaenaga pds</h1>
+
<h1 onclick={birdbrain} id="header">shimaenaga pds</h1>
<p id="subtitle">a project of <a href="https://veryroundbird.house" target="_blank">veryroundbird.house</a></p>
{#if Config.SHOW_GUESTBOOK}
<div id="guestbook">
···
<div id="guestbookContents" popover>
<div id="signInfo">You can sign the guestbook <a href="{Config.GUESTBOOK_POST}" target="_blank">here</a>!</div>
<div id="guestbookPosts">
-
{#each guestbookPosts as postObject}
-
<div class="guestbookPost">
-
</div>
-
{/each}
+
{#if guestbookPosts.length > 0}
+
{#each guestbookPosts as postObject}
+
<PostComponent post={postObject as Post} />
+
{/each}
+
{:else}
+
<p class="noGuestbookPosts">No guestbook posts yet!</p>
+
{/if}
</div>
</div>
</div>
···
<InfiniteLoading on:infinite={onInfinite} distance={3000} />
</div>
</div>
+
<div id="birdbrain" popover>
+
<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>
+
</div>
</main>
+1 -2
src/lib/AccountComponent.svelte
···
<script lang="ts">
import type { AccountMetadata } from "./pdsfetch";
const { account }: { account: AccountMetadata } = $props();
-
console.log(account);
import { Config } from "../../config";
</script>
-
<button class="accountBtn" type="button" popovertarget="{account.handle.replace('.')}" title="{account.handle}">
+
<button class="accountBtn" type="button" popovertarget="{account.handle.replace('.', '')}" title="{account.handle}">
<div class="accountContainer">
{#if account.avatarCid}
<img
+34 -16
src/lib/pdsfetch.ts
···
const match = uri.match(/profile\/([\w.]+)\/post\/([\w]+)/);
if (match) {
const [, did, postId] = match;
-
return `at://${did}/app.bsky.feed.post/${postId}` as At.Did;
+
try {
+
return `at://${did}/app.bsky.feed.post/${postId}`;
+
} catch (e) {
+
console.error("Invalid Bluesky post URL format", e);
+
return null;
+
}
}
}
-
-
this.error = "Invalid Bluesky post URL format";
-
return null;
}
const fetchGuestbookPosts = async () => {
-
try {
-
const { data } = await rpc.get("app.bsky.feed.getPostThread", {
-
params: {
-
uri: convertUri(Config.GUESTBOOK_POST)
-
}
-
});
-
-
return data.records as ComAtprotoRepoListRecords.Record[];
-
} catch (e) {
-
console.error(`Error fetching replies for ${did}. Are you sure this is a Bluesky post?`, e);
-
return null;
-
}
+
const params = new URLSearchParams({ uri: convertUri(Config.GUESTBOOK_POST) });
+
const url = `https://public.api.bsky.app/xrpc/app.bsky.feed.getPostThread?${params.toString()}`;
+
+
try {
+
const response = await fetch(url, {
+
method: "GET",
+
headers: {
+
Accept: "application/json",
+
},
+
cache: "no-store",
+
});
+
+
if (!response.ok) {
+
const errorText = await response.text();
+
console.error("Fetch Error: ", errorText);
+
throw new Error(`Failed to fetch thread: ${response.statusText}`);
+
}
+
+
const data = await response.json();
+
+
if (!data.thread || !data.thread.replies) {
+
throw new Error("Invalid thread data: Missing expected properties.");
+
}
+
+
return data.thread.replies;
+
} catch (e) {
+
console.error("Is this the wrong kind of Bluesky object?", e);
+
}
}
export { getAllMetadataFromPds, getNextPosts, Post, fetchGuestbookPosts };
+16 -5
themes/birdrights/theme.css
···
#guestbookContents {
width: 100%;
max-width: 600px;
-
border: 1px var(--border-color) solid;
-
color: var(--text-color);
-
background-color: var(--content-background-color);
-
backdrop-filter: blur(5px);
height: calc(100vh - 20px);
padding: 10px;
-
border-radius: 5px;
gap: 10px;
z-index: 10;
}
···
#accountsList {
grid-template-columns: repeat(6, 1fr);
}
+
}
+
+
/* Popovers */
+
[popover] {
+
padding: 0;
+
max-width: 600px;
+
border: 1px var(--border-color) solid;
+
color: var(--text-color);
+
background-color: var(--content-background-color);
+
backdrop-filter: blur(5px);
+
border-radius: 5px;
+
z-index: 10;
+
}
+
+
[popover] iframe {
+
display: block;
}
/* Scrollbars */