search and/or read your saved and liked bluesky posts
wails
go
svelte
sqlite
desktop
bluesky
1<script lang="ts">
2 import { BrowserOpenURL } from "../../../wailsjs/runtime/runtime";
3 import type { main } from "../../../wailsjs/go/models";
4 import PostText from "./PostText.svelte";
5 import { formatLongDateTime } from "../date";
6
7 interface Props {
8 post: main.SearchResult;
9 onClose: () => void;
10 }
11
12 let { post, onClose }: Props = $props();
13
14 function buildPostURL(uri: string): string {
15 const match = uri.match(/at:\/\/([^/]+)\/app\.bsky\.feed\.post\/(.+)/);
16 if (match) {
17 return `https://bsky.app/profile/${match[1]}/post/${match[2]}`;
18 }
19 return uri;
20 }
21
22 function openInBrowser() {
23 BrowserOpenURL(buildPostURL(post.uri));
24 }
25</script>
26
27<aside
28 class="border-outline bg-surface/95 flex h-full min-h-0 w-full flex-col overflow-hidden rounded-[1.25rem] border shadow-[0_24px_80px_rgba(0,0,0,0.45)] backdrop-blur xl:w-100 xl:min-w-100">
29 <header class="border-outline border-b bg-black/80 px-5 py-4">
30 <div class="flex items-start justify-between gap-4">
31 <div class="min-w-0">
32 <p class="text-muted font-mono text-[11px] tracking-[0.3em] uppercase">Reading Pane</p>
33 <h2 class="text-bright mt-2 truncate font-serif text-2xl">@{post.author_handle}</h2>
34 <p class="text-muted mt-1 font-mono text-xs">{formatLongDateTime(post.created_at)}</p>
35 </div>
36
37 <button
38 type="button"
39 onclick={onClose}
40 class="border-outline bg-surface text-muted hover:text-bright rounded-full border px-3 py-1.5 font-mono text-xs transition-colors">
41 Close
42 </button>
43 </div>
44 </header>
45
46 <div class="flex-1 overflow-y-auto px-5 py-5">
47 <div class="border-outline rounded-2xl border bg-black/60 p-5">
48 <div class="mb-5 flex flex-wrap gap-2">
49 <span
50 class="bg-primary/15 text-primary rounded-full px-3 py-1 font-mono text-[11px] tracking-[0.18em] uppercase">
51 {post.source}
52 </span>
53 <span
54 class="border-outline text-muted flex items-center gap-1 rounded-full border px-3 py-1 font-mono text-[11px]">
55 <i class="i-ri-heart-line"></i>
56 <span>{post.like_count || 0}</span>
57 </span>
58 <span class="border-outline text-muted flex items-center rounded-full border px-3 py-1 font-mono text-[11px]">
59 <i class="i-ri-repeat-line"></i>
60 <span>{post.repost_count || 0}</span>
61 </span>
62 <span class="border-outline text-muted flex items-center rounded-full border px-3 py-1 font-mono text-[11px]">
63 <i class="i-ri-message-2-line"></i>
64 <span>{post.reply_count || 0}</span>
65 </span>
66 </div>
67
68 <div class="space-y-4">
69 <p class="text-muted font-mono text-xs tracking-[0.22em] uppercase">Post</p>
70 <div class="text-bright font-mono text-sm leading-7 text-pretty">
71 <PostText text={post.text} facetsJson={post.facets} />
72 </div>
73 </div>
74 </div>
75
76 <dl class="border-outline bg-surface/80 mt-5 grid gap-4 rounded-2xl border p-4">
77 <div>
78 <dt class="text-muted font-mono text-[11px] tracking-[0.2em] uppercase">Post URI</dt>
79 <dd class="text-bright mt-1 font-mono text-xs break-all">{post.uri}</dd>
80 </div>
81 <div>
82 <dt class="text-muted font-mono text-[11px] tracking-[0.2em] uppercase">Indexed</dt>
83 <dd class="text-bright mt-1 font-mono text-xs">{formatLongDateTime(post.indexed_at)}</dd>
84 </div>
85 </dl>
86 </div>
87
88 <footer class="border-outline border-t bg-black/75 px-5 py-4">
89 <button
90 type="button"
91 onclick={openInBrowser}
92 class="border-outline bg-surface text-bright hover:bg-outline flex w-full items-center rounded-xl border px-4 py-3 font-sans text-sm transition-colors">
93 <span>Open on BlueSky</span>
94 <i class="i-ri-blue-sky-fill m-2"></i>
95 <i class="i-ri-external-link-line"></i>
96 </button>
97 </footer>
98</aside>