appview-less bluesky client
27
fork

Configure Feed

Select the types of activity you want to include in your feed.

add blocks management in moderation tab

dawn c64c146b 3ddf6456

+71 -7
+1 -1
src/components/ProfileActions.svelte
··· 135 135 bind:position={actionsPos} 136 136 placement="bottom-end" 137 137 > 138 - {#if !blockedByTarget} 138 + {#if !blockedByTarget && !userBlocked} 139 139 {@render dropdownItem( 140 140 follow ? 'heroicons:user-minus-20-solid' : 'heroicons:user-plus-20-solid', 141 141 follow ? 'unfollow' : 'follow',
+69 -6
src/components/SettingsModerationTab.svelte
··· 3 3 import VirtualList from '@tutorlatin/svelte-tiny-virtual-list'; 4 4 import type { Did } from '@atcute/lexicons'; 5 5 import type { Preferences } from '$lib/at/pocket'; 6 + import { allBacklinks, createBlock, deleteBlock, clients } from '$lib/state.svelte'; 7 + import { blockSource } from '$lib'; 6 8 7 9 interface Props { 8 10 mutes: Did[]; 9 11 currentPrefs: Preferences | null; 10 12 onAddMute: (did: Did) => void; 11 13 onRemoveMute: (did: Did) => void; 14 + selectedAccount: Did | null; 12 15 } 13 16 14 - let { mutes, currentPrefs, onAddMute, onRemoveMute }: Props = $props(); 17 + let { mutes, currentPrefs, onAddMute, onRemoveMute, selectedAccount }: Props = $props(); 15 18 16 19 let newMuteInput = $state(''); 20 + let newBlockInput = $state(''); 17 21 18 22 const handleAddMute = () => { 19 23 if (!newMuteInput.trim()) return; ··· 21 25 onAddMute(did); 22 26 newMuteInput = ''; 23 27 }; 28 + 29 + const blocks = $derived.by(() => { 30 + if (!selectedAccount) return []; 31 + const blockMap = allBacklinks.get(blockSource); 32 + if (!blockMap) return []; 33 + const blockedDids: Did[] = []; 34 + for (const [subjectUri, didMap] of blockMap) { 35 + if (didMap.has(selectedAccount)) { 36 + const did = subjectUri.replace('at://', '') as Did; 37 + blockedDids.push(did); 38 + } 39 + } 40 + return blockedDids; 41 + }); 42 + 43 + const handleAddBlock = async () => { 44 + if (!newBlockInput.trim() || !selectedAccount) return; 45 + const client = clients.get(selectedAccount); 46 + if (!client) return; 47 + const did = newBlockInput.trim() as Did; 48 + await createBlock(client, did); 49 + newBlockInput = ''; 50 + }; 51 + 52 + const handleRemoveBlock = async (did: Did) => { 53 + if (!selectedAccount) return; 54 + const client = clients.get(selectedAccount); 55 + if (!client) return; 56 + await deleteBlock(client, did); 57 + }; 24 58 </script> 25 59 26 60 <div class="space-y-4 p-4"> ··· 57 91 {/if} 58 92 </div> 59 93 </div> 60 - {#if currentPrefs} 61 - <p class="text-xs opacity-50"> 62 - last synced: {new Date(currentPrefs.updatedAt).toLocaleString()} 63 - </p> 64 - {/if} 94 + 95 + <div> 96 + <h3 class="settings-header">blocked accounts</h3> 97 + <div class="settings-box space-y-2"> 98 + <div class="flex gap-2"> 99 + <input 100 + type="text" 101 + bind:value={newBlockInput} 102 + placeholder="did:plc:..." 103 + class="single-line-input flex-1" 104 + /> 105 + <button onclick={handleAddBlock} class="action-button">add</button> 106 + </div> 107 + {#if blocks.length > 0} 108 + <div class="h-fit"> 109 + <VirtualList 110 + height={Math.min(blocks.length, 6) * 44} 111 + itemCount={blocks.length} 112 + itemSize={44} 113 + > 114 + {#snippet item({ index, style }: { index: number; style: string })} 115 + <MutedAccountItem 116 + {style} 117 + did={blocks[index]} 118 + onRemove={() => handleRemoveBlock(blocks[index])} 119 + /> 120 + {/snippet} 121 + </VirtualList> 122 + </div> 123 + {:else} 124 + <p class="py-2 text-center text-sm opacity-50">no blocked accounts</p> 125 + {/if} 126 + </div> 127 + </div> 65 128 </div>
+1
src/components/SettingsView.svelte
··· 163 163 {currentPrefs} 164 164 onAddMute={handleAddMute} 165 165 onRemoveMute={handleRemoveMute} 166 + {selectedAccount} 166 167 /> 167 168 {:else if tab === 'style'} 168 169 <SettingsStyleTab bind:localSettings />