an independent Bluesky client using Constellation, PDS Queries, and other services reddwarf.app
frontend spa bluesky reddwarf microcosm client app

post content hider

+251 -86
+2
src/auto-imports.d.ts
··· 24 const IconMdiCheck: typeof import('~icons/mdi/check.jsx').default 25 const IconMdiCheckCircle: typeof import('~icons/mdi/check-circle.jsx').default 26 const IconMdiCheckboxMultipleMarked: typeof import('~icons/mdi/checkbox-multiple-marked.jsx').default 27 const IconMdiClock: typeof import('~icons/mdi/clock.jsx').default 28 const IconMdiClockOutline: typeof import('~icons/mdi/clock-outline.jsx').default 29 const IconMdiClose: typeof import('~icons/mdi/close.jsx').default ··· 42 const IconMdiShield: typeof import('~icons/mdi/shield.jsx').default 43 const IconMdiShieldOutline: typeof import('~icons/mdi/shield-outline.jsx').default 44 const IconMdiVerified: typeof import('~icons/mdi/verified.jsx').default 45 }
··· 24 const IconMdiCheck: typeof import('~icons/mdi/check.jsx').default 25 const IconMdiCheckCircle: typeof import('~icons/mdi/check-circle.jsx').default 26 const IconMdiCheckboxMultipleMarked: typeof import('~icons/mdi/checkbox-multiple-marked.jsx').default 27 + const IconMdiChevronDown: typeof import('~icons/mdi/chevron-down.jsx').default 28 const IconMdiClock: typeof import('~icons/mdi/clock.jsx').default 29 const IconMdiClockOutline: typeof import('~icons/mdi/clock-outline.jsx').default 30 const IconMdiClose: typeof import('~icons/mdi/close.jsx').default ··· 43 const IconMdiShield: typeof import('~icons/mdi/shield.jsx').default 44 const IconMdiShieldOutline: typeof import('~icons/mdi/shield-outline.jsx').default 45 const IconMdiVerified: typeof import('~icons/mdi/verified.jsx').default 46 + const IconMdiWarning: typeof import('~icons/mdi/warning.jsx').default 47 }
+77
src/components/LogoSvg.tsx
··· 76 </svg>) 77 } 78 79 // defaultpfp 80 export function DefaultPFP(props: SVGProps<SVGSVGElement>) { 81 return (
··· 76 </svg>) 77 } 78 79 + // candidate for default 80 + export function WheyMadeModernistMonogram2Partial(props: SVGProps<SVGSVGElement>) { 81 + return ( 82 + <svg 83 + viewBox="0 0 512 512" 84 + version="1.1" 85 + xmlns="http://www.w3.org/2000/svg" 86 + {...props} 87 + > 88 + <title>Logotype 2partial</title> 89 + <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> 90 + <g id="Logotype-partial" transform="translate(25, 25)" fill="currentColor"> 91 + <path d="M231,2.27373675e-13 C358.577777,2.27373675e-13 462,103.422223 462,231 C462,358.577777 358.577777,462 231,462 Z" id="Half"></path> 92 + <circle id="Oval" cx="115.5" cy="115.5" r="115.5"></circle> 93 + <path d="M0.082,231 L0.083,231.001 L3.82032351,231.030947 C129.607985,233.070408 230.954808,335.652489 230.999823,461.916004 L231.000162,461.999838 L230.877,461.999 L230.999838,461.99916 C230.999838,461.97144 230.999833,461.943722 230.999823,461.916004 L0.083,231.001 L0.00032417037,231 L0.0312715054,234.82001 C2.07117982,360.63597 104.698104,462.000162 230.999838,462.000162 L230.877,461.999 L0,461.999838 L0,231.000324 L0.082,231 Z" id="Combined-Shape"></path> 94 + </g> 95 + <rect id="Rectangle" fill="currentColor" x="25" y="25" width="116" height="231"></rect> 96 + </g> 97 + </svg> 98 + ) 99 + } 100 + 101 + export function WheyMade5Square(props: SVGProps<SVGSVGElement>) { 102 + return ( 103 + <svg 104 + viewBox="0 0 512 512" 105 + version="1.1" 106 + xmlns="http://www.w3.org/2000/svg" 107 + transform='rotate(135)' 108 + {...props} 109 + > 110 + <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> 111 + <g id="Logotype-5Square" transform="translate(0.4991, -0.0005)" fill="currentColor"> 112 + <path d="M255.500876,25.0005352 C383.078653,25.0005352 486.500876,128.422758 486.500876,256.000535 C486.500876,356.786979 421.955067,442.497942 331.945007,474.051864 L331.3,474.272 L381.857,512 L0.000430968674,512.000535 L1.42108547e-14,130.312 L37.229,180.2 L37.4495474,179.556404 C68.6040527,90.6857123 152.553212,26.6386865 251.680869,25.0314826 L255.500876,25.0005352 Z M512,288.919 L512.000431,512.000535 L482.724,512 L480.160326,311.436715 L512,288.919 Z M50.543,362.647 L0.0982429603,511.403168 L148.855,460.958 L146.179023,459.545342 C106.285176,438.073726 73.427685,405.216235 51.9560695,365.322388 L50.543,362.647 Z M262.03074,422.579291 L148.855,460.958 L149.343076,461.216735 C181.12821,477.692535 217.227543,487.000535 255.500876,487.000535 C281.016431,487.000535 305.565765,482.863646 328.514742,475.224002 L331.3,474.272 L262.03074,422.579291 Z M37.229,180.2 L36.2774093,182.986669 C28.6377649,205.935647 24.500876,230.48498 24.500876,256.000535 C24.500876,294.273868 33.808876,330.373202 50.2846761,362.158335 L50.543,362.647 L88.9221204,249.470671 L37.229,180.2 Z M512.000431,0.00053522388 L512,91.44 L441.863205,69.6382067 L420.216,-2.84217094e-14 L512.000431,0.00053522388 Z M222.228,-2.84217094e-14 L200.064696,31.3410852 L1.42108547e-14,28.784 L0.000430968674,0.00053522388 L222.228,-2.84217094e-14 Z" id="Combined-Shape"></path> 113 + </g> 114 + </g> 115 + </svg> 116 + ) 117 + } 118 + 119 + 120 + export function WheyMadeBoubaKiki(props: SVGProps<SVGSVGElement>) { 121 + return ( 122 + <svg 123 + viewBox="0 0 1047 1047" 124 + version="1.1" 125 + xmlns="http://www.w3.org/2000/svg" 126 + {...props} 127 + > 128 + <title>Logotype-1.5Nonequal15nonequal</title> 129 + <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> 130 + <g id="Logotype-1.5Nonequal" transform="translate(0.6169, 0.861)" fill="currentColor"> 131 + <path d="M700.664553,340.034383 C715.327713,340.002333 729.11121,347.025376 737.704071,358.906959 L799.154445,443.876074 C811.895531,461.493523 834.561151,468.85803 855.224183,462.094237 L954.882173,429.472402 C978.810344,421.639806 1004.55753,434.687847 1012.39013,458.616018 C1016.95178,472.551607 1014.5318,487.830732 1005.88708,499.674639 L944.065863,584.374318 C931.247885,601.935903 931.247885,625.767946 944.065863,643.32953 L1005.88708,728.02921 C1020.73054,748.365847 1016.27743,776.884946 995.940794,791.7284 C984.096887,800.373117 968.817762,802.793093 954.882173,798.231446 L855.224183,765.609612 C834.561151,758.845819 811.895531,766.210325 799.154445,783.827774 L737.704071,868.796889 C722.949658,889.198219 694.450298,893.775951 674.048968,879.021538 C662.167385,870.428678 655.144342,856.64518 655.176392,841.982021 L655.405588,737.120939 C655.425626,727.953131 652.946531,719.22295 648.520961,711.691065 C709.97811,670.185396 750.383113,599.880758 750.383113,520.139025 C750.383113,452.082396 720.952137,390.89974 674.123265,348.624137 C681.586594,343.239367 690.752706,340.056047 700.664553,340.034383 Z M390.074839,115.030765 L389.612789,326.427069 L392.214218,327.263752 C329.654126,368.59486 288.383113,439.547262 288.383113,520.139025 C288.383113,522.478677 288.417896,524.810206 288.486973,527.133121 L390.074839,667.594601 L389.612789,456.198297 L590.805403,391.312683 L392.214218,327.263752 C428.68754,303.167195 472.397099,289.139025 519.383113,289.139025 C578.904262,289.139025 633.167544,311.650627 674.123265,348.624137 C662.616835,356.926725 655.143026,370.456226 655.176392,385.721828 L655.405588,490.582909 C655.453109,512.324748 641.444985,531.605276 620.752583,538.278678 L520.952943,570.464556 C506.997546,574.965241 496.0589,585.903886 491.558216,599.859283 C483.830293,623.821465 496.990761,649.51137 520.952943,657.239293 L620.752583,689.425171 C632.719689,693.284622 642.451108,701.360771 648.520961,711.691065 C611.659126,736.598693 567.219158,751.139025 519.383113,751.139025 C394.144989,751.139025 292.184563,651.475345 288.486973,527.133121 L266.193017,496.299812 L65.2859657,562.064299 L189.915403,391.312683 L65.2859657,220.561067 L266.193017,286.325554 L390.074839,115.030765 Z" id="Combined-Shape"></path> 132 + </g> 133 + </g> 134 + </svg> 135 + ) 136 + } 137 + 138 + export function WheyMadeBoubaKikiLarge(props: SVGProps<SVGSVGElement>) { 139 + return ( 140 + <svg 141 + viewBox="0 100 1047 847" 142 + version="1.1" 143 + xmlns="http://www.w3.org/2000/svg" 144 + {...props} 145 + > 146 + <title>Logotype-Large1.5Nonequall15nonequal</title> 147 + <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> 148 + <g id="Logotype-Large1.5Nonequal" transform="translate(0.6169, 0.861)" fill="currentColor"> 149 + <path d="M700.664553,340.034383 C715.327713,340.002333 729.11121,347.025376 737.704071,358.906959 L799.154445,443.876074 C811.895531,461.493523 834.561151,468.85803 855.224183,462.094237 L954.882173,429.472402 C978.810344,421.639806 1004.55753,434.687847 1012.39013,458.616018 C1016.95178,472.551607 1014.5318,487.830732 1005.88708,499.674639 L944.065863,584.374318 C931.247885,601.935903 931.247885,625.767946 944.065863,643.32953 L1005.88708,728.02921 C1020.73054,748.365847 1016.27743,776.884946 995.940794,791.7284 C984.096887,800.373117 968.817762,802.793093 954.882173,798.231446 L855.224183,765.609612 C834.561151,758.845819 811.895531,766.210325 799.154445,783.827774 L737.704071,868.796889 C722.949658,889.198219 694.450298,893.775951 674.048968,879.021538 C662.167385,870.428678 655.144342,856.64518 655.176392,841.982021 L655.405588,737.120939 C655.453109,715.379101 641.444985,696.098573 620.752583,689.425171 L520.952943,657.239293 C496.990761,649.51137 483.830293,623.821465 491.558216,599.859283 C496.0589,585.903886 506.997546,574.965241 520.952943,570.464556 L620.752583,538.278678 C641.444985,531.605276 655.453109,512.324748 655.405588,490.582909 L655.176392,385.721828 C655.121361,360.544379 675.487105,340.089413 700.664553,340.034383 Z M390.074839,115.030765 L389.612789,326.427069 L590.805403,391.312683 L389.612789,456.198297 L390.074839,667.594601 L266.193017,496.299812 L65.2859657,562.064299 L189.915403,391.312683 L65.2859657,220.561067 L266.193017,286.325554 L390.074839,115.030765 Z" id="Combined-Shape"></path> 150 + </g> 151 + </g> 152 + </svg> 153 + ) 154 + } 155 + 156 // defaultpfp 157 export function DefaultPFP(props: SVGProps<SVGSVGElement>) { 158 return (
+172 -86
src/components/UniversalPostRenderer.tsx
··· 21 import { useAuth } from "~/providers/UnifiedAuthProvider"; 22 import { renderSnack } from "~/routes/__root"; 23 //import { ModerationInner } from "~/routes/moderation"; 24 - import { 25 - FollowButton, 26 - Mutual, 27 - } from "~/routes/profile.$did"; 28 import type { LightboxProps } from "~/routes/profile.$did/post.$rkey.image.$i"; 29 import type { ContentLabel } from "~/types/moderation"; 30 import { ··· 580 const { isLoading: authorModLoading, labels: authorLabels } = useModeration( 581 post.author.did, 582 ); 583 const hideAuthorLabels = authorLabels.filter( 584 - label => label.preference === 'hide' 585 ); 586 const warnAuthorLabels = authorLabels.filter( 587 - label => label.preference === 'warn' 588 ); 589 - 590 591 const parsed = new AtUri(post.uri); 592 const navigate = useNavigate(); ··· 671 const isMainItem = false; 672 const setMainItem = (any: any) => { }; 673 674 - if (hideAuthorLabels.length > 0 ) { 675 - return null 676 } 677 678 return ( ··· 917 </div> 918 </div> 919 {/* <ModerationInner subject={post.author.did} /> */} 920 - {authorModLoading ? 921 - ( 922 <div className="flex flex-wrap flex-row gap-1 my-1"> 923 - <div 924 - className="text-xs bg-gray-100 dark:bg-gray-800 px-1 py-0.5 rounded-full flex flex-row items-center gap-1" 925 - > 926 - {/* <img 927 src={resolvedpfp || defaultpfp} 928 alt="avatar" 929 className={`rounded-full object-cover border border-gray-300 dark:border-gray-800 bg-gray-300 dark:bg-gray-600`} ··· 932 height: 12, 933 }} 934 /> */} 935 - <span className="font-medium">loading badges...</span> 936 - </div> 937 </div> 938 - ) 939 - : 940 - ( 941 - <div className="flex flex-wrap flex-row gap-1 my-1"> 942 - {warnAuthorLabels.map((label, index) => ( 943 - <SmallAuthorLabelBadge label={label} key={label.cts + label.sourceDid + label.val} /> 944 - ))} 945 - </div> 946 - ) 947 - } 948 {!!feedviewpostreplyhandle && ( 949 <div 950 style={{ ··· 968 </div> 969 )} 970 {/* <ModerationInner subject={post.uri} /> */} 971 - <div 972 - style={{ 973 - fontSize: 16, 974 - marginBottom: !post.embed || concise ? 0 : 8, 975 - whiteSpace: "pre-wrap", 976 - textAlign: "left", 977 - overflowWrap: "anywhere", 978 - wordBreak: "break-word", 979 - ...(concise && { 980 - display: "-webkit-box", 981 - WebkitBoxOrient: "vertical", 982 - WebkitLineClamp: 2, 983 - overflow: "hidden", 984 - }), 985 - }} 986 - className="text-gray-900 dark:text-gray-100" 987 - > 988 - {fedi ? ( 989 - <> 990 - <span 991 - className="dangerousFediContent" 992 - dangerouslySetInnerHTML={{ 993 - __html: DOMPurify.sanitize(fedi), 994 - }} 995 - /> 996 - </> 997 - ) : ( 998 <> 999 - {renderTextWithFacets({ 1000 - text: (post.record as { text?: string }).text ?? "", 1001 - facets: (post.record.facets as Facet[]) ?? [], 1002 - navigate: navigate, 1003 - })} 1004 </> 1005 )} 1006 - </div> 1007 - {post.embed && depth < 1 && !concise ? ( 1008 - <PostEmbeds 1009 - embed={post.embed} 1010 - viewContext={PostEmbedViewContext.Feed} 1011 - salt={salt} 1012 - navigate={navigate} 1013 - postid={{ did: post.author.did, rkey: parsed.rkey }} 1014 - nopics={nopics} 1015 - lightboxCallback={lightboxCallback} 1016 - constellationLinks={constellationLinks} 1017 - /> 1018 - ) : null} 1019 - {post.embed && depth > 0 && ( 1020 - <> 1021 - <div className="border-gray-300 dark:border-gray-800 p-3 rounded-xl border italic text-gray-400 text-[14px]"> 1022 - (there is an embed here thats too deep to render) 1023 - </div> 1024 - </> 1025 - )} 1026 <div 1027 style={{ 1028 paddingTop: post.embed && !concise && depth < 1 ? 4 : 0, ··· 1078 }} 1079 aria-label="Repost or quote post" 1080 > 1081 - {hasRetweeted ? <IconMdiRepeat color="#5CEFAA" /> : <IconMdiRepeat />} 1082 {post.repostCount ?? 0} 1083 </div> 1084 </DropdownMenu.Trigger> ··· 1123 ...(liked ? { color: "#EC4899" } : {}), 1124 }} 1125 > 1126 - {liked ? <IconMdiCardsHeart /> : <IconMdiCardsHeartOutline />} 1127 {(post.likeCount || 0) + (liked ? 1 : 0)} 1128 </HitSlopButton> 1129 <div style={{ display: "flex", gap: 8 }}> ··· 1186 FeedEmbedRecordWithMedia = "FeedEmbedRecordWithMedia", 1187 } 1188 1189 1190 - export function SmallAuthorLabelBadge({ label, large }: { label: ContentLabel, large?: boolean }) { 1191 /* 1192 -{" "} 1193 {label.preference} (from {label.sourceDid}) ··· 1197 1198 const [imgcdn] = useAtom(imgCDNAtom); 1199 1200 - 1201 const { data: opProfile } = useQueryProfile( 1202 `at://${label.sourceDid}/app.bsky.actor.profile/self`, 1203 ); 1204 1205 - const resolvedpfp = getAvatarUrl(opProfile, label.sourceDid, imgcdn) 1206 1207 return ( 1208 <div ··· 1219 /> 1220 <span className="font-medium">{info.name || label.val}</span> 1221 </div> 1222 - ) 1223 - }
··· 21 import { useAuth } from "~/providers/UnifiedAuthProvider"; 22 import { renderSnack } from "~/routes/__root"; 23 //import { ModerationInner } from "~/routes/moderation"; 24 + import { FollowButton, Mutual } from "~/routes/profile.$did"; 25 import type { LightboxProps } from "~/routes/profile.$did/post.$rkey.image.$i"; 26 import type { ContentLabel } from "~/types/moderation"; 27 import { ··· 577 const { isLoading: authorModLoading, labels: authorLabels } = useModeration( 578 post.author.did, 579 ); 580 + const { isLoading: contentModLoading, labels: contentLabels } = useModeration( 581 + post.uri, 582 + ); 583 const hideAuthorLabels = authorLabels.filter( 584 + (label) => label.preference === "hide", 585 ); 586 const warnAuthorLabels = authorLabels.filter( 587 + (label) => label.preference === "warn", 588 ); 589 + const hideContentLabels = contentLabels.filter( 590 + (label) => label.preference === "hide", 591 + ); 592 + const warnContentLabels = contentLabels.filter( 593 + (label) => label.preference === "warn", 594 + ); 595 596 const parsed = new AtUri(post.uri); 597 const navigate = useNavigate(); ··· 676 const isMainItem = false; 677 const setMainItem = (any: any) => { }; 678 679 + const showContentWarning = warnContentLabels.length > 0; 680 + 681 + const [isOpen, setIsOpen] = useState(!showContentWarning); 682 + 683 + 684 + if (hideAuthorLabels.length > 0 || hideContentLabels.length > 0) { 685 + return null; 686 } 687 688 return ( ··· 927 </div> 928 </div> 929 {/* <ModerationInner subject={post.author.did} /> */} 930 + {authorModLoading ? ( 931 <div className="flex flex-wrap flex-row gap-1 my-1"> 932 + <div className="text-xs bg-gray-100 dark:bg-gray-800 px-1 py-0.5 rounded-full flex flex-row items-center gap-1"> 933 + {/* <img 934 src={resolvedpfp || defaultpfp} 935 alt="avatar" 936 className={`rounded-full object-cover border border-gray-300 dark:border-gray-800 bg-gray-300 dark:bg-gray-600`} ··· 939 height: 12, 940 }} 941 /> */} 942 + <span className="font-medium">loading badges...</span> 943 </div> 944 + </div> 945 + ) : ( 946 + <div className="flex flex-wrap flex-row gap-1 my-1"> 947 + {warnAuthorLabels.map((label, index) => ( 948 + <SmallAuthorLabelBadge 949 + label={label} 950 + key={label.cts + label.sourceDid + label.val} 951 + /> 952 + ))} 953 + </div> 954 + )} 955 {!!feedviewpostreplyhandle && ( 956 <div 957 style={{ ··· 975 </div> 976 )} 977 {/* <ModerationInner subject={post.uri} /> */} 978 + {showContentWarning && ( 979 + <ContentWarning 980 + labels={warnContentLabels} 981 + isOpen={isOpen} 982 + onPress={(e) => { 983 + e.stopPropagation(); 984 + setIsOpen(!isOpen) 985 + }} 986 + /> 987 + )} 988 + {isOpen && (<> 989 + <div 990 + style={{ 991 + fontSize: 16, 992 + marginBottom: !post.embed || concise ? 0 : 8, 993 + whiteSpace: "pre-wrap", 994 + textAlign: "left", 995 + overflowWrap: "anywhere", 996 + wordBreak: "break-word", 997 + ...(concise && { 998 + display: "-webkit-box", 999 + WebkitBoxOrient: "vertical", 1000 + WebkitLineClamp: 2, 1001 + overflow: "hidden", 1002 + }), 1003 + }} 1004 + className="text-gray-900 dark:text-gray-100" 1005 + > 1006 + {fedi ? ( 1007 + <> 1008 + <span 1009 + className="dangerousFediContent" 1010 + dangerouslySetInnerHTML={{ 1011 + __html: DOMPurify.sanitize(fedi), 1012 + }} 1013 + /> 1014 + </> 1015 + ) : ( 1016 + <> 1017 + {renderTextWithFacets({ 1018 + text: (post.record as { text?: string }).text ?? "", 1019 + facets: (post.record.facets as Facet[]) ?? [], 1020 + navigate: navigate, 1021 + })} 1022 + </> 1023 + )} 1024 + </div> 1025 + {post.embed && depth < 1 && !concise ? ( 1026 + <PostEmbeds 1027 + embed={post.embed} 1028 + viewContext={PostEmbedViewContext.Feed} 1029 + salt={salt} 1030 + navigate={navigate} 1031 + postid={{ did: post.author.did, rkey: parsed.rkey }} 1032 + nopics={nopics} 1033 + lightboxCallback={lightboxCallback} 1034 + constellationLinks={constellationLinks} 1035 + /> 1036 + ) : null} 1037 + {post.embed && depth > 0 && ( 1038 <> 1039 + <div className="border-gray-300 dark:border-gray-800 p-3 rounded-xl border italic text-gray-400 text-[14px]"> 1040 + (there is an embed here thats too deep to render) 1041 + </div> 1042 </> 1043 )} 1044 + </>)} 1045 <div 1046 style={{ 1047 paddingTop: post.embed && !concise && depth < 1 ? 4 : 0, ··· 1097 }} 1098 aria-label="Repost or quote post" 1099 > 1100 + {hasRetweeted ? ( 1101 + <IconMdiRepeat color="#5CEFAA" /> 1102 + ) : ( 1103 + <IconMdiRepeat /> 1104 + )} 1105 {post.repostCount ?? 0} 1106 </div> 1107 </DropdownMenu.Trigger> ··· 1146 ...(liked ? { color: "#EC4899" } : {}), 1147 }} 1148 > 1149 + {liked ? ( 1150 + <IconMdiCardsHeart /> 1151 + ) : ( 1152 + <IconMdiCardsHeartOutline /> 1153 + )} 1154 {(post.likeCount || 0) + (liked ? 1 : 0)} 1155 </HitSlopButton> 1156 <div style={{ display: "flex", gap: 8 }}> ··· 1213 FeedEmbedRecordWithMedia = "FeedEmbedRecordWithMedia", 1214 } 1215 1216 + export function ContentWarning({ 1217 + labels, 1218 + isOpen, 1219 + onPress, 1220 + }: { 1221 + labels: ContentLabel[]; 1222 + isOpen: boolean; 1223 + onPress: React.MouseEventHandler<HTMLDivElement>; 1224 + }) { 1225 + const { getLabelInfo } = useLabelInfo(); 1226 1227 + // Pre-calculate text for cleaner JSX 1228 + const labelText = labels 1229 + .map((label) => getLabelInfo(label.sourceDid, label.val).name) 1230 + .join(", "); 1231 + 1232 + return ( 1233 + <div className="mb-2 w-full select-none" onClick={onPress}> 1234 + <div 1235 + className={` 1236 + group flex items-center justify-between 1237 + w-full px-4 py-3 1238 + rounded-full 1239 + border border-gray-200 dark:border-gray-700 1240 + bg-gray-100 dark:bg-gray-800 1241 + cursor-pointer 1242 + transition-all duration-200 ease-out 1243 + hover:bg-gray-200 dark:hover:bg-gray-700 1244 + `} 1245 + > 1246 + <div className="flex items-center gap-3 overflow-hidden"> 1247 + {/* Icon Container */} 1248 + <div className="flex items-center justify-center text-gray-500 dark:text-gray-400"> 1249 + <IconMdiWarning className="text-xl" /> 1250 + </div> 1251 + 1252 + {/* Label Text */} 1253 + <span className="text-sm font-semibold text-gray-900 dark:text-gray-100 truncate"> 1254 + {labelText} 1255 + </span> 1256 + </div> 1257 + 1258 + {/* Chevron */} 1259 + <div className="flex items-center justify-center text-gray-500 dark:text-gray-400 pl-2 gap-2 text-sm"> 1260 + {isOpen ? "hide" : "show"} 1261 + <IconMdiChevronDown 1262 + className={`text-xl transition-transform duration-300 ease-[cubic-bezier(0.2,0,0,1)] ${isOpen ? "rotate-180" : "" 1263 + }`} 1264 + /> 1265 + </div> 1266 + </div> 1267 + </div> 1268 + ); 1269 + } 1270 + 1271 + export function SmallAuthorLabelBadge({ 1272 + label, 1273 + large, 1274 + }: { 1275 + label: ContentLabel; 1276 + large?: boolean; 1277 + }) { 1278 /* 1279 -{" "} 1280 {label.preference} (from {label.sourceDid}) ··· 1284 1285 const [imgcdn] = useAtom(imgCDNAtom); 1286 1287 const { data: opProfile } = useQueryProfile( 1288 `at://${label.sourceDid}/app.bsky.actor.profile/self`, 1289 ); 1290 1291 + const resolvedpfp = getAvatarUrl(opProfile, label.sourceDid, imgcdn); 1292 1293 return ( 1294 <div ··· 1305 /> 1306 <span className="font-medium">{info.name || label.val}</span> 1307 </div> 1308 + ); 1309 + }