your personal website on atproto - mirror
blento.app
1<script lang="ts">
2 import { Alert, Button, Input, Modal, Subheading } from '@foxui/core';
3 import type { CreationModalComponentProps } from '../types';
4 import { parseBlueskyPostUrl } from './utils';
5
6 let { item = $bindable(), oncreate, oncancel }: CreationModalComponentProps = $props();
7
8 let isValidating = $state(false);
9 let errorMessage = $state('');
10 let postUrl = $state('');
11
12 async function validateAndCreate() {
13 errorMessage = '';
14 isValidating = true;
15
16 try {
17 const parsed = parseBlueskyPostUrl(postUrl.trim());
18
19 if (!parsed) {
20 throw new Error('Invalid URL format');
21 }
22
23 // Construct AT URI using handle (will be resolved to DID when loading)
24 item.cardData.uri = `at://${parsed.handle}/app.bsky.feed.post/${parsed.rkey}`;
25 item.cardData.href = postUrl.trim();
26
27 return true;
28 } catch (err) {
29 errorMessage =
30 err instanceof Error && err.message === 'Post not found'
31 ? "Couldn't find that post. Please check the URL and try again."
32 : err instanceof Error && err.message === 'Could not resolve handle'
33 ? "Couldn't find that user. Please check the URL and try again."
34 : 'Invalid URL. Please enter a valid Bluesky post URL (e.g., https://bsky.app/profile/handle/post/rkey).';
35 return false;
36 } finally {
37 isValidating = false;
38 }
39 }
40</script>
41
42<Modal open={true} closeButton={false}>
43 <form
44 onsubmit={async () => {
45 if (await validateAndCreate()) oncreate();
46 }}
47 class="flex flex-col gap-2"
48 >
49 <Subheading>Enter a Bluesky post URL</Subheading>
50 <Input
51 bind:value={postUrl}
52 placeholder="https://bsky.app/profile/handle/post/..."
53 class="mt-4"
54 />
55
56 {#if errorMessage}
57 <Alert type="error" title="Failed to create post card"><span>{errorMessage}</span></Alert>
58 {/if}
59
60 <p class="text-base-500 dark:text-base-400 mt-2 text-xs">
61 Paste a URL from <a
62 href="https://bsky.app"
63 class="text-accent-800 dark:text-accent-300"
64 target="_blank">bsky.app</a
65 > to embed a Bluesky post.
66 </p>
67
68 <div class="mt-4 flex justify-end gap-2">
69 <Button onclick={oncancel} variant="ghost">Cancel</Button>
70 <Button type="submit" disabled={isValidating || !postUrl.trim()}
71 >{isValidating ? 'Creating...' : 'Create'}</Button
72 >
73 </div>
74 </form>
75</Modal>