Thread viewer for Bluesky
1<script lang="ts">
2 import { getBaseLocation, linkToHashtagPage, linkToPostById, parseBlueskyPostURL } from '../router.js';
3
4 let query = $state('');
5 let searchField: HTMLInputElement;
6
7 $effect(() => {
8 searchField.focus();
9 });
10
11 function onsubmit(e: Event) {
12 e.preventDefault();
13
14 let q = query.trim();
15
16 if (!q) {
17 return;
18 }
19
20 if (q.startsWith('at://')) {
21 let target = new URL(getBaseLocation());
22 target.searchParams.set('q', q);
23 location.assign(target.toString());
24
25 } else if (q.match(/^#?((\p{Letter}|\p{Number})+)$/u)) {
26 let hashtag = q.replace(/^#/, '');
27 location.assign(linkToHashtagPage(hashtag));
28
29 } else {
30 try {
31 let { user, post } = parseBlueskyPostURL(q);
32 location.assign(linkToPostById(user, post));
33 } catch (error) {
34 console.log(error);
35 alert(error.message || "This is not a valid URL or hashtag");
36 }
37 }
38 }
39</script>
40
41<div id="search">
42 <form method="get" {onsubmit}>
43 🌤 <input type="text" placeholder="Paste a thread link or type a #hashtag" bind:value={query} bind:this={searchField}>
44 </form>
45</div>
46
47<style>
48 #search {
49 position: fixed;
50 top: 0;
51 bottom: 0;
52 left: 0;
53 right: 0;
54 display: flex;
55 align-items: center;
56 justify-content: center;
57 padding-bottom: 5%;
58 }
59
60 form {
61 border: 2px solid hsl(210, 100%, 80%);
62 border-radius: 10px;
63 padding: 15px 20px;
64 margin-left: 50px;
65 }
66
67 input {
68 font-size: 16pt;
69 width: 600px;
70 border: 0;
71 margin-left: 8px;
72 }
73
74 input:focus {
75 outline: none;
76 }
77
78 @media (prefers-color-scheme: dark) {
79 form {
80 border-color: hsl(210, 40%, 60%);
81 }
82
83 form input {
84 background-color: transparent;
85 }
86 }
87</style>