Retro Bulletin Board Systems on atproto. Web app and TUI. lazy mirror of alyraffauf/atbbs atbbs.xyz
forums python tui atproto bbs
3
fork

Configure Feed

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

web/SysopModerate: add common ModerationListItem

+59 -42
+59 -42
web/src/pages/SysopModerate.tsx
··· 7 7 import { usePageTitle } from "../hooks/usePageTitle"; 8 8 import { useModerationMutations } from "../hooks/useModerationMutations"; 9 9 10 + interface ModerationListItemProps { 11 + label: string; 12 + href: string; 13 + title: string; 14 + actionLabel: string; 15 + onAction?: () => void; 16 + } 17 + 18 + function ModerationListItem({ 19 + label, 20 + href, 21 + title, 22 + actionLabel, 23 + onAction, 24 + }: ModerationListItemProps) { 25 + return ( 26 + <div 27 + title={title} 28 + className="flex items-center justify-between gap-3 px-3 py-2 -mx-3 rounded hover:bg-neutral-800" 29 + > 30 + <a 31 + href={href} 32 + target="_blank" 33 + rel="noreferrer" 34 + aria-label={`${label} (opens in new tab)`} 35 + className="truncate text-neutral-300 hover:text-neutral-200" 36 + > 37 + {label} 38 + </a> 39 + {onAction && ( 40 + <button 41 + onClick={onAction} 42 + className="text-xs text-neutral-400 hover:text-red-400 shrink-0" 43 + > 44 + {actionLabel} 45 + </button> 46 + )} 47 + </div> 48 + ); 49 + } 50 + 10 51 export default function SysopModerate() { 11 52 const { user } = useAuth(); 12 53 const [identifier, setIdentifier] = useState(""); ··· 59 100 <label className="block text-neutral-400 mb-3">Banned Users</label> 60 101 <div className="space-y-1 mb-3"> 61 102 {Object.keys(banRkeys).map((did) => ( 62 - <div 103 + <ModerationListItem 63 104 key={did} 64 105 title={did} 65 - className="flex items-center justify-between gap-3 px-3 py-2 -mx-3 rounded hover:bg-neutral-800" 66 - > 67 - <a 68 - href={`https://pdsls.dev/at/${did}`} 69 - target="_blank" 70 - rel="noreferrer" 71 - aria-label={`${bannedHandles[did] ?? did} (opens in new tab)`} 72 - className="truncate text-neutral-300 hover:text-neutral-200" 73 - > 74 - {bannedHandles[did] ?? did} 75 - </a> 76 - {banRkeys[did] && ( 77 - <button 78 - onClick={() => onUnban(banRkeys[did])} 79 - className="text-xs text-neutral-400 hover:text-red-400 shrink-0" 80 - > 81 - unban 82 - </button> 83 - )} 84 - </div> 106 + label={bannedHandles[did] ?? did} 107 + href={`https://pdsls.dev/at/${did}`} 108 + actionLabel="unban" 109 + onAction={ 110 + banRkeys[did] ? () => onUnban(banRkeys[did]) : undefined 111 + } 112 + /> 85 113 ))} 86 114 </div> 87 115 <div className="flex gap-2"> ··· 99 127 <label className="block text-neutral-400 mb-3">Hidden Posts</label> 100 128 <div className="space-y-1 mb-3"> 101 129 {hidden.map((post) => ( 102 - <div 130 + <ModerationListItem 103 131 key={post.uri} 104 132 title={post.uri} 105 - className="flex items-center justify-between gap-3 px-3 py-2 -mx-3 rounded hover:bg-neutral-800" 106 - > 107 - <a 108 - href={`https://pdsls.dev/${post.uri}`} 109 - target="_blank" 110 - rel="noreferrer" 111 - aria-label={`${post.handle} — ${post.title || post.body} (opens in new tab)`} 112 - className="truncate text-neutral-300 hover:text-neutral-200" 113 - > 114 - {post.handle} — {post.title || post.body} 115 - </a> 116 - {hideRkeys[post.uri] && ( 117 - <button 118 - onClick={() => onUnhide(hideRkeys[post.uri])} 119 - className="text-xs text-neutral-400 hover:text-red-400 shrink-0" 120 - > 121 - unhide 122 - </button> 123 - )} 124 - </div> 133 + label={`${post.handle} — ${post.title || post.body}`} 134 + href={`https://pdsls.dev/${post.uri}`} 135 + actionLabel="unhide" 136 + onAction={ 137 + hideRkeys[post.uri] 138 + ? () => onUnhide(hideRkeys[post.uri]) 139 + : undefined 140 + } 141 + /> 125 142 ))} 126 143 </div> 127 144 <div className="flex gap-2">