mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import React from 'react'
2import {View} from 'react-native'
3import {BSKY_LABELER_DID, ModerationCause} from '@atproto/api'
4import {Trans} from '@lingui/macro'
5
6import {useModerationCauseDescription} from '#/lib/moderation/useModerationCauseDescription'
7import {UserAvatar} from '#/view/com/util/UserAvatar'
8import {atoms as a, useTheme, ViewStyleProp} from '#/alf'
9import {Button} from '#/components/Button'
10import {
11 ModerationDetailsDialog,
12 useModerationDetailsDialogControl,
13} from '#/components/moderation/ModerationDetailsDialog'
14import {Text} from '#/components/Typography'
15
16export type AppModerationCause =
17 | ModerationCause
18 | {
19 type: 'reply-hidden'
20 source: {type: 'user'; did: string}
21 priority: 6
22 downgraded?: boolean
23 }
24
25export type CommonProps = {
26 size?: 'sm' | 'lg'
27}
28
29export function Row({
30 children,
31 style,
32 size = 'sm',
33}: {children: React.ReactNode | React.ReactNode[]} & CommonProps &
34 ViewStyleProp) {
35 const styles = React.useMemo(() => {
36 switch (size) {
37 case 'lg':
38 return [{gap: 5}]
39 case 'sm':
40 default:
41 return [{gap: 3}]
42 }
43 }, [size])
44 return (
45 <View style={[a.flex_row, a.flex_wrap, a.gap_xs, styles, style]}>
46 {children}
47 </View>
48 )
49}
50
51export type LabelProps = {
52 cause: AppModerationCause
53 disableDetailsDialog?: boolean
54 noBg?: boolean
55} & CommonProps
56
57export function Label({
58 cause,
59 size = 'sm',
60 disableDetailsDialog,
61 noBg,
62}: LabelProps) {
63 const t = useTheme()
64 const control = useModerationDetailsDialogControl()
65 const desc = useModerationCauseDescription(cause)
66 const isLabeler = Boolean(desc.sourceType && desc.sourceDid)
67 const isBlueskyLabel =
68 desc.sourceType === 'labeler' && desc.sourceDid === BSKY_LABELER_DID
69
70 const {outer, avi, text} = React.useMemo(() => {
71 switch (size) {
72 case 'lg': {
73 return {
74 outer: [
75 t.atoms.bg_contrast_25,
76 {
77 gap: 5,
78 paddingHorizontal: 5,
79 paddingVertical: 5,
80 },
81 ],
82 avi: 16,
83 text: [a.text_sm],
84 }
85 }
86 case 'sm':
87 default: {
88 return {
89 outer: [
90 !noBg && t.atoms.bg_contrast_25,
91 {
92 gap: 3,
93 paddingHorizontal: 3,
94 paddingVertical: 3,
95 },
96 ],
97 avi: 12,
98 text: [a.text_xs],
99 }
100 }
101 }
102 }, [t, size, noBg])
103
104 return (
105 <>
106 <Button
107 disabled={disableDetailsDialog}
108 label={desc.name}
109 onPress={e => {
110 e.preventDefault()
111 e.stopPropagation()
112 control.open()
113 }}>
114 {({hovered, pressed}) => (
115 <View
116 style={[
117 a.flex_row,
118 a.align_center,
119 a.rounded_full,
120 outer,
121 (hovered || pressed) && t.atoms.bg_contrast_50,
122 ]}>
123 {isBlueskyLabel || !isLabeler ? (
124 <desc.icon
125 width={avi}
126 fill={t.atoms.text_contrast_medium.color}
127 />
128 ) : (
129 <UserAvatar avatar={desc.sourceAvi} size={avi} />
130 )}
131
132 <Text
133 style={[
134 text,
135 a.font_semibold,
136 a.leading_tight,
137 t.atoms.text_contrast_medium,
138 {paddingRight: 3},
139 ]}>
140 {desc.name}
141 </Text>
142 </View>
143 )}
144 </Button>
145
146 {!disableDetailsDialog && (
147 <ModerationDetailsDialog control={control} modcause={cause} />
148 )}
149 </>
150 )
151}
152
153export function FollowsYou({size = 'sm'}: CommonProps) {
154 const t = useTheme()
155
156 const variantStyles = React.useMemo(() => {
157 switch (size) {
158 case 'sm':
159 case 'lg':
160 default:
161 return [
162 {
163 paddingHorizontal: 6,
164 paddingVertical: 3,
165 borderRadius: 4,
166 },
167 ]
168 }
169 }, [size])
170
171 return (
172 <View style={[variantStyles, a.justify_center, t.atoms.bg_contrast_25]}>
173 <Text style={[a.text_xs, a.leading_tight]}>
174 <Trans>Follows You</Trans>
175 </Text>
176 </View>
177 )
178}