chore: checkpoint 663ff842
Steve · 2026-01-03 16:08 2 file(s) · +141 −8
src/pages/now.astro +76 −0
18 18
      <li>Testing out different fountain pen inks</li>
19 19
      <li>Reading The Dispossessed</li>
20 20
    </ul>
21 +
22 +
  <h2 class="text-xl font-semibold pt-12">Updates</h2>
23 +
  <div id="posts-container">
24 +
    <p>Loading...</p>
21 25
  </div>
26 +
27 +
  <script>
28 +
    import { AtpAgent } from '@atproto/api';
29 +
30 +
    const urlParams = new URLSearchParams(window.location.search);
31 +
    const rkey = urlParams.get('rkey');
32 +
    const DID = 'did:plc:ia2zdnhjaokf5lazhxrmj6eu';
33 +
    const atUri = `at://${DID}/app.bsky.feed.post/${rkey}`;
34 +
35 +
    const agent = new AtpAgent({ service: 'https://public.api.bsky.app' });
36 +
37 +
    agent.app.bsky.feed.getAuthorFeed({
38 +
      actor: DID,
39 +
      limit: 20,
40 +
      filter: 'posts_no_replies'
41 +
    })
42 +
    .then(({ data }) => {
43 +
      const posts = data.feed;
44 +
45 +
      if (posts.length === 0) {
46 +
        document.getElementById('posts-container').innerHTML = '<p>No recent posts found.</p>';
47 +
        return;
48 +
      }
49 +
50 +
      const postsHTML = posts.map(feedItem => {
51 +
        const post = feedItem.post;
52 +
        const createdAt = new Date(post.record.createdAt).toLocaleDateString();
53 +
54 +
        // Handle images
55 +
        let imagesHTML = '';
56 +
        if (post.embed && post.embed.images) {
57 +
          const imageElements = post.embed.images.map(image => {
58 +
            return `
59 +
              <img
60 +
                src="${image.fullsize}"
61 +
                alt="${image.alt || 'Image from post'}"
62 +
                class="max-w-full h-auto"
63 +
                loading="lazy"
64 +
              />
65 +
            `;
66 +
          }).join('');
67 +
68 +
          imagesHTML = `
69 +
            <div class="mt-3 grid gap-2 ${post.embed.images.length === 1 ? 'grid-cols-1' : 'grid-cols-2'}">
70 +
              ${imageElements}
71 +
            </div>
72 +
          `;
73 +
        }
74 +
75 +
        return `
76 +
          <article class="border-b pb-4 mb-6 last:border-b-0">
77 +
            <p class="mb-2">${post.record.text}</p>
78 +
            ${imagesHTML}
79 +
            <time class="text-sm text-gray-500 mt-2 block">${createdAt}</time>
80 +
          </article>
81 +
        `;
82 +
      }).join('');
83 +
84 +
      document.getElementById('posts-container').innerHTML = `
85 +
        <div class="space-y-4">
86 +
          <div>${postsHTML}</div>
87 +
        </div>
88 +
      `;
89 +
    })
90 +
    .catch(err => {
91 +
      console.error('Error fetching posts:', err);
92 +
      document.getElementById('posts-container').innerHTML =
93 +
        '<p>Error loading recent posts.</p>';
94 +
    });
95 +
  </script>
96 +
  </div>
97 +
22 98
</PageLayout>
src/pages/pds/index.astro +65 −8
21 21
22 22
    const agent = new AtpAgent({ service: 'https://public.api.bsky.app' });
23 23
24 +
    function renderPost(post) {
25 +
      const createdAt = new Date(post.record.createdAt).toLocaleDateString();
26 +
27 +
      // Handle images and other embeds
28 +
      let embedHTML = '';
29 +
      if (post.embed) {
30 +
        // Handle images
31 +
        if (post.embed.images) {
32 +
          const imageElements = post.embed.images.map(image => `
33 +
            <img
34 +
              src="${image.fullsize}"
35 +
              alt="${image.alt || 'Image from post'}"
36 +
              class="rounded-lg max-w-full h-auto cursor-pointer"
37 +
              loading="lazy"
38 +
              onclick="window.open('${image.fullsize}', '_blank')"
39 +
            />
40 +
          `).join('');
41 +
42 +
          embedHTML = `
43 +
            <div class="mt-4 grid gap-2 ${post.embed.images.length === 1 ? 'grid-cols-1' : 'grid-cols-2'}">
44 +
              ${imageElements}
45 +
            </div>
46 +
          `;
47 +
        }
48 +
        // Handle external links
49 +
        else if (post.embed.external) {
50 +
          const external = post.embed.external;
51 +
          embedHTML = `
52 +
            <a href="${external.uri}" target="_blank" rel="noopener noreferrer"
53 +
               class="block mt-4 p-4 border rounded-lg hover:bg-gray-50 transition-colors">
54 +
              ${external.thumb ? `<img src="${external.thumb}" alt="Link preview" class="w-full h-32 object-cover rounded mb-3" />` : ''}
55 +
              <div class="font-medium text-lg">${external.title || 'External Link'}</div>
56 +
              ${external.description ? `<div class="text-sm text-gray-600 mt-1">${external.description}</div>` : ''}
57 +
              <div class="text-xs text-gray-400 mt-2">${external.uri}</div>
58 +
            </a>
59 +
          `;
60 +
        }
61 +
        // Handle quoted posts
62 +
        else if (post.embed.record) {
63 +
          const quotedPost = post.embed.record;
64 +
          embedHTML = `
65 +
            <div class="mt-4 p-4 border-l-4 border-blue-400 bg-gray-50 rounded">
66 +
              <div class="text-sm text-gray-600 mb-2">Quoting:</div>
67 +
              <div>${quotedPost.value?.text || 'Quoted post'}</div>
68 +
              <div class="text-xs text-gray-400 mt-2">
69 +
                ${quotedPost.value?.createdAt ? new Date(quotedPost.value.createdAt).toLocaleDateString() : ''}
70 +
              </div>
71 +
            </div>
72 +
          `;
73 +
        }
74 +
      }
75 +
76 +
      return `
77 +
        <article class="max-w-2xl mx-auto">
78 +
          <h1 class="mb-4">${post.record.text}</h1>
79 +
          ${embedHTML}
80 +
          <div class="mt-6 pt-4 border-t">
81 +
            <time class="text-sm text-gray-500">${createdAt}</time>
82 +
          </div>
83 +
        </article>
84 +
      `;
85 +
    }
86 +
24 87
    agent.app.bsky.feed.getPostThread({ uri: atUri })
25 88
      .then(({ data }) => {
26 89
        const post = data.thread.post;
27 90
28 -
        document.getElementById('post-container').innerHTML = `
29 -
          <article>
30 -
            <h1>${post.record.text}</h1>
31 -
            <time>${new Date(post.record.createdAt).toLocaleDateString()}</time>
32 -
          </article>
33 -
        `;
34 -
91 +
        document.getElementById('post-container').innerHTML = renderPost(post);
35 92
        document.title = post.record.text;
36 93
      })
37 94
      .catch(err => {
38 95
        console.error('Error fetching post:', err);
39 96
        document.getElementById('post-container').innerHTML =
40 -
          `<p>Post not found: ${err.message}</p>`;
97 +
          `<p class="text-red-600">Post not found: ${err.message}</p>`;
41 98
      });
42 99
  </script>
43 100