chore: checkpoint
663ff842
2 file(s) · +141 −8
| 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> |
| 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 |