Thread viewer for Bluesky

indentation

+128 -132
+11 -11
src/components/BiohazardDialog.svelte
··· 28 28 </script> 29 29 30 30 <DialogPanel onClose={() => onClose?.()}> 31 - <form method="get"> 32 - <i class="close fa-circle-xmark fa-regular" onclick={onClose}></i> 33 - <h2>☣️ Infohazard Warning</h2> 31 + <form method="get"> 32 + <i class="close fa-circle-xmark fa-regular" onclick={onClose}></i> 33 + <h2>☣️ Infohazard Warning</h2> 34 34 35 - <p>&ldquo;<em>This thread is not a place of honor... no highly esteemed post is commemorated here... nothing valued is here.</em>&rdquo;</p> 36 - <p>This feature allows access to comments in a thread which were hidden because one of the commenters has blocked another. Bluesky currently hides such comments to avoid escalating conflicts.</p> 37 - <p>Are you sure you want to enter?<br>(You can toggle this in the menu in top-left corner.)</p> 35 + <p>&ldquo;<em>This thread is not a place of honor... no highly esteemed post is commemorated here... nothing valued is here.</em>&rdquo;</p> 36 + <p>This feature allows access to comments in a thread which were hidden because one of the commenters has blocked another. Bluesky currently hides such comments to avoid escalating conflicts.</p> 37 + <p>Are you sure you want to enter?<br>(You can toggle this in the menu in top-left corner.)</p> 38 38 39 - <p class="submit"> 40 - <input type="submit" value="Show me the drama 😈" onclick={showBiohazard}> 41 - <input type="submit" value="Nope, I'd rather not 🙈" onclick={hideBiohazard}> 42 - </p> 43 - </form> 39 + <p class="submit"> 40 + <input type="submit" value="Show me the drama 😈" onclick={showBiohazard}> 41 + <input type="submit" value="Nope, I'd rather not 🙈" onclick={hideBiohazard}> 42 + </p> 43 + </form> 44 44 </DialogPanel> 45 45 46 46 <style>
+27 -27
src/components/LoginDialog.svelte
··· 58 58 </script> 59 59 60 60 <DialogPanel id="login" class={loginInfoVisible ? 'expanded' : ''} onClose={onOverlayClick}> 61 - <form method="get" {onsubmit}> 62 - {#if showClose} 63 - <i class="close fa-circle-xmark fa-regular" onclick={onClose}></i> 64 - {/if} 61 + <form method="get" {onsubmit}> 62 + {#if showClose} 63 + <i class="close fa-circle-xmark fa-regular" onclick={onClose}></i> 64 + {/if} 65 65 66 - <h2>🌤 Skythread</h2> 66 + <h2>🌤 Skythread</h2> 67 67 68 - <p><input type="text" id="login_handle" required autofocus placeholder="name.bsky.social" 69 - bind:value={identifier} bind:this={loginField}></p> 68 + <p><input type="text" id="login_handle" required autofocus placeholder="name.bsky.social" 69 + bind:value={identifier} bind:this={loginField}></p> 70 70 71 - <p><input type="password" id="login_password" required 72 - placeholder="&#x2731;&#x2731;&#x2731;&#x2731;&#x2731;&#x2731;&#x2731;&#x2731;" 73 - bind:value={password} bind:this={passwordField}></p> 71 + <p><input type="password" id="login_password" required 72 + placeholder="&#x2731;&#x2731;&#x2731;&#x2731;&#x2731;&#x2731;&#x2731;&#x2731;" 73 + bind:value={password} bind:this={passwordField}></p> 74 74 75 - <p class="info"> 76 - <a href="#" onclick={toggleLoginInfo}><i class="fa-regular fa-circle-question"></i> Use an "app password" here</a> 77 - </p> 78 - 79 - {#if loginInfoVisible} 80 - <div class="info-box"> 81 - <p>Skythread doesn't support OAuth yet. For now, you need to use an "app password" here, which you can generate in the Bluesky app settings.</p> 82 - <p>The password you enter here is only passed to the Bluesky API (PDS) and isn't saved anywhere. The returned access token is only stored in your browser's local storage. You can see the complete source code of this app <a href="http://tangled.org/@mackuba.eu/skythread" target="_blank">on Tangled</a>.</p> 83 - </div> 84 - {/if} 75 + <p class="info"> 76 + <a href="#" onclick={toggleLoginInfo}><i class="fa-regular fa-circle-question"></i> Use an "app password" here</a> 77 + </p> 85 78 86 - <p class="submit"> 87 - {#if !submitting} 88 - <input type="submit" value="Log in"> 89 - {:else} 90 - <i class="cloudy fa-solid fa-cloud fa-beat fa-xl"></i> 79 + {#if loginInfoVisible} 80 + <div class="info-box"> 81 + <p>Skythread doesn't support OAuth yet. For now, you need to use an "app password" here, which you can generate in the Bluesky app settings.</p> 82 + <p>The password you enter here is only passed to the Bluesky API (PDS) and isn't saved anywhere. The returned access token is only stored in your browser's local storage. You can see the complete source code of this app <a href="http://tangled.org/@mackuba.eu/skythread" target="_blank">on Tangled</a>.</p> 83 + </div> 91 84 {/if} 92 - </p> 93 - </form> 85 + 86 + <p class="submit"> 87 + {#if !submitting} 88 + <input type="submit" value="Log in"> 89 + {:else} 90 + <i class="cloudy fa-solid fa-cloud fa-beat fa-xl"></i> 91 + {/if} 92 + </p> 93 + </form> 94 94 </DialogPanel> 95 95 96 96 <style>
-2
src/pages/LikeStatsPage.svelte
··· 36 36 } 37 37 </script> 38 38 39 - <div id="like_stats_page"> 40 39 <h2>Like statistics</h2> 41 40 42 41 <form onsubmit={startScan}> ··· 58 57 <LikeStatsTable cssClass="given-likes" header="❤️ Likes from you:" users={givenLikesUsers} /> 59 58 <LikeStatsTable cssClass="received-likes" header="💛 Likes on your posts:" users={receivedLikesUsers} /> 60 59 {/if} 61 - </div> 62 60 63 61 <style> 64 62 input[type="range"] {
+56 -56
src/pages/LycanSearchPage.svelte
··· 154 154 </script> 155 155 156 156 <SearchPage> 157 - <h2>Archive search</h2> 158 - 159 - <form class="search-form"> 160 - <p class="search"> 161 - Search: 162 - <input type="text" class="search-query" autocomplete="off" 163 - disabled={importStatus != 'finished'} onkeydown={onKeyPress} bind:value={query}> 164 - </p> 165 - 166 - <div class="search-collections"> 167 - {#each collections as col} 168 - <input type="radio" name="collection" value={col.id} id="collection-{col.id}" bind:group={selectedCollection}> 169 - <label for="collection-{col.id}">{col.title}</label> 170 - {/each} 171 - </div> 172 - </form> 157 + <h2>Archive search</h2> 173 158 174 - {#if wasImporting || importStatus == 'not_started'} 175 - <div class="lycan-import"> 176 - {#if importStatus == 'not_started'} 177 - <form onsubmit={onFormSubmit}> 178 - <h4>Data not imported yet</h4> 159 + <form class="search-form"> 160 + <p class="search"> 161 + Search: 162 + <input type="text" class="search-query" autocomplete="off" 163 + disabled={importStatus != 'finished'} onkeydown={onKeyPress} bind:value={query}> 164 + </p> 179 165 180 - <p> 181 - In order to search within your likes and bookmarks, the posts you've liked or saved need to be imported into a database. 182 - This is a one-time process, but it can take several minutes or more, depending on the age of your account. 183 - </p> 184 - <p> 185 - To start the import, press the button below. You can then wait until it finishes, or close this tab and come back a bit later. 186 - After the import is complete, the database will be kept up to date automatically going forward. 187 - </p> 188 - <p> 189 - <input type="submit" value="Start import"> 190 - </p> 191 - </form> 192 - {:else} 193 - <div class="import-progress"> 194 - <h4>Import in progress</h4> 166 + <div class="search-collections"> 167 + {#each collections as col} 168 + <input type="radio" name="collection" value={col.id} id="collection-{col.id}" bind:group={selectedCollection}> 169 + <label for="collection-{col.id}">{col.title}</label> 170 + {/each} 171 + </div> 172 + </form> 195 173 196 - <p class="import-status">{importStatusLabel}</p> 174 + {#if wasImporting || importStatus == 'not_started'} 175 + <div class="lycan-import"> 176 + {#if importStatus == 'not_started'} 177 + <form onsubmit={onFormSubmit}> 178 + <h4>Data not imported yet</h4> 197 179 198 - {#if importStatus != 'error'} 199 180 <p> 200 - <progress value={importProgress}></progress> 201 - <output>{Math.round(importProgress * 100)}%</output> 181 + In order to search within your likes and bookmarks, the posts you've liked or saved need to be imported into a database. 182 + This is a one-time process, but it can take several minutes or more, depending on the age of your account. 202 183 </p> 203 - {/if} 204 - </div> 205 - {/if} 206 - </div> 207 - {/if} 184 + <p> 185 + To start the import, press the button below. You can then wait until it finishes, or close this tab and come back a bit later. 186 + After the import is complete, the database will be kept up to date automatically going forward. 187 + </p> 188 + <p> 189 + <input type="submit" value="Start import"> 190 + </p> 191 + </form> 192 + {:else} 193 + <div class="import-progress"> 194 + <h4>Import in progress</h4> 208 195 209 - <div class="results"> 210 - {#if loadingPosts} 211 - <p>...</p> 212 - {:else} 213 - {#each results as post (post.uri)} 214 - <PostComponent {post} placement="feed" {highlightedMatches} /> 215 - {/each} 216 - {#if finishedPosts} 217 - <p class="results-end">{results.length > 0 ? "No more results." : "No results."}</p> 218 - {/if} 196 + <p class="import-status">{importStatusLabel}</p> 197 + 198 + {#if importStatus != 'error'} 199 + <p> 200 + <progress value={importProgress}></progress> 201 + <output>{Math.round(importProgress * 100)}%</output> 202 + </p> 203 + {/if} 204 + </div> 205 + {/if} 206 + </div> 219 207 {/if} 220 - </div> 208 + 209 + <div class="results"> 210 + {#if loadingPosts} 211 + <p>...</p> 212 + {:else} 213 + {#each results as post (post.uri)} 214 + <PostComponent {post} placement="feed" {highlightedMatches} /> 215 + {/each} 216 + {#if finishedPosts} 217 + <p class="results-end">{results.length > 0 ? "No more results." : "No results."}</p> 218 + {/if} 219 + {/if} 220 + </div> 221 221 </SearchPage> 222 222 223 223 <style>
-2
src/pages/PostingStatsPage.svelte
··· 104 104 } 105 105 </script> 106 106 107 - <div id="posting_stats_page"> 108 107 <h2>Bluesky posting statistics</h2> 109 108 110 109 <form {onsubmit}> ··· 153 152 {#if results} 154 153 <PostingStatsTable {...tableOptions} {...results} /> 155 154 {/if} 156 - </div> 157 155 158 156 <style> 159 157 input[type="radio"] {
+34 -34
src/pages/TimelineSearchPage.svelte
··· 50 50 </script> 51 51 52 52 <SearchPage> 53 - <h2>Timeline search</h2> 53 + <h2>Timeline search</h2> 54 54 55 - <div class="timeline-search"> 56 - <form onsubmit={startScan}> 57 - <p> 58 - Fetch timeline posts: <input id="timeline_search_range" type="range" min="1" max="60" bind:value={timeRangeDays}> 59 - <label for="timeline_search_range">{numberOfDays(timeRangeDays)}</label> 60 - </p> 55 + <div class="timeline-search"> 56 + <form onsubmit={startScan}> 57 + <p> 58 + Fetch timeline posts: <input id="timeline_search_range" type="range" min="1" max="60" bind:value={timeRangeDays}> 59 + <label for="timeline_search_range">{numberOfDays(timeRangeDays)}</label> 60 + </p> 61 61 62 - <p> 63 - <input type="submit" value="{fetchInProgress ? 'Cancel' : 'Fetch timeline'}"> 62 + <p> 63 + <input type="submit" value="{fetchInProgress ? 'Cancel' : 'Fetch timeline'}"> 64 64 65 - {#if fetchInProgress} 66 - <progress max={progressMax} value={progress}></progress> 67 - {/if} 68 - </p> 69 - </form> 65 + {#if fetchInProgress} 66 + <progress max={progressMax} value={progress}></progress> 67 + {/if} 68 + </p> 69 + </form> 70 70 71 - {#if daysFetched} 72 - <p class="archive-status"> 73 - Timeline archive fetched: {numberOfDays(Math.round(daysFetched))} 74 - </p> 75 - {/if} 71 + {#if daysFetched} 72 + <p class="archive-status"> 73 + Timeline archive fetched: {numberOfDays(Math.round(daysFetched))} 74 + </p> 75 + {/if} 76 76 77 - <hr> 78 - </div> 77 + <hr> 78 + </div> 79 79 80 - {#if daysFetched} 81 - <form class="search-form"> 82 - <p class="search"> 83 - Search: 84 - <input type="text" class="search-query" autocomplete="off" onkeydown={onKeyPress} bind:value={query}> 85 - </p> 86 - </form> 80 + {#if daysFetched} 81 + <form class="search-form"> 82 + <p class="search"> 83 + Search: 84 + <input type="text" class="search-query" autocomplete="off" onkeydown={onKeyPress} bind:value={query}> 85 + </p> 86 + </form> 87 87 88 - <div class="results"> 89 - {#each results as post (post.uri)} 90 - <PostComponent {post} placement="feed" /> 91 - {/each} 92 - </div> 93 - {/if} 88 + <div class="results"> 89 + {#each results as post (post.uri)} 90 + <PostComponent {post} placement="feed" /> 91 + {/each} 92 + </div> 93 + {/if} 94 94 </SearchPage> 95 95 96 96 <style>