about summary refs log tree commit diff
path: root/src/components/moderation/ContentHider.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/moderation/ContentHider.tsx')
-rw-r--r--src/components/moderation/ContentHider.tsx182
1 files changed, 182 insertions, 0 deletions
diff --git a/src/components/moderation/ContentHider.tsx b/src/components/moderation/ContentHider.tsx
new file mode 100644
index 000000000..1e8f36d31
--- /dev/null
+++ b/src/components/moderation/ContentHider.tsx
@@ -0,0 +1,182 @@
+import React from 'react'
+import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
+import {ModerationUI} from '@atproto/api'
+import {useLingui} from '@lingui/react'
+import {msg, Trans} from '@lingui/macro'
+
+import {useModerationCauseDescription} from '#/lib/moderation/useModerationCauseDescription'
+import {isJustAMute} from '#/lib/moderation'
+import {sanitizeDisplayName} from '#/lib/strings/display-names'
+
+import {atoms as a, useTheme, useBreakpoints, web} from '#/alf'
+import {Button} from '#/components/Button'
+import {Text} from '#/components/Typography'
+import {
+  ModerationDetailsDialog,
+  useModerationDetailsDialogControl,
+} from '#/components/moderation/ModerationDetailsDialog'
+
+export function ContentHider({
+  testID,
+  modui,
+  ignoreMute,
+  style,
+  childContainerStyle,
+  children,
+}: React.PropsWithChildren<{
+  testID?: string
+  modui: ModerationUI | undefined
+  ignoreMute?: boolean
+  style?: StyleProp<ViewStyle>
+  childContainerStyle?: StyleProp<ViewStyle>
+}>) {
+  const t = useTheme()
+  const {_} = useLingui()
+  const {gtMobile} = useBreakpoints()
+  const [override, setOverride] = React.useState(false)
+  const control = useModerationDetailsDialogControl()
+
+  const blur = modui?.blurs[0]
+  const desc = useModerationCauseDescription(blur)
+
+  if (!blur || (ignoreMute && isJustAMute(modui))) {
+    return (
+      <View testID={testID} style={[styles.outer, style]}>
+        {children}
+      </View>
+    )
+  }
+
+  return (
+    <View testID={testID} style={[a.overflow_hidden, style]}>
+      <ModerationDetailsDialog control={control} modcause={blur} />
+
+      <Button
+        onPress={() => {
+          if (!modui.noOverride) {
+            setOverride(v => !v)
+          } else {
+            control.open()
+          }
+        }}
+        label={desc.name}
+        accessibilityHint={
+          modui.noOverride
+            ? _(msg`Learn more about the moderation applied to this content.`)
+            : override
+            ? _(msg`Hide the content`)
+            : _(msg`Show the content`)
+        }>
+        {state => (
+          <View
+            style={[
+              a.flex_row,
+              a.w_full,
+              a.justify_start,
+              a.align_center,
+              a.py_md,
+              a.px_lg,
+              a.gap_xs,
+              a.rounded_sm,
+              t.atoms.bg_contrast_25,
+              gtMobile && [a.gap_sm, a.py_lg, a.mt_xs, a.px_xl],
+              (state.hovered || state.pressed) && t.atoms.bg_contrast_50,
+            ]}>
+            <desc.icon
+              size="md"
+              fill={t.atoms.text_contrast_medium.color}
+              style={{marginLeft: -2}}
+            />
+            <Text
+              style={[
+                a.flex_1,
+                a.text_left,
+                a.font_bold,
+                a.leading_snug,
+                gtMobile && [a.font_semibold],
+                t.atoms.text_contrast_medium,
+                web({
+                  marginBottom: 1,
+                }),
+              ]}>
+              {desc.name}
+            </Text>
+            {!modui.noOverride && (
+              <Text
+                style={[
+                  a.font_bold,
+                  a.leading_snug,
+                  gtMobile && [a.font_semibold],
+                  t.atoms.text_contrast_high,
+                  web({
+                    marginBottom: 1,
+                  }),
+                ]}>
+                {override ? <Trans>Hide</Trans> : <Trans>Show</Trans>}
+              </Text>
+            )}
+          </View>
+        )}
+      </Button>
+
+      {desc.source && blur.type === 'label' && !override && (
+        <Button
+          onPress={() => {
+            control.open()
+          }}
+          label={_(
+            msg`Learn more about the moderation applied to this content.`,
+          )}
+          style={[a.pt_sm]}>
+          {state => (
+            <Text
+              style={[
+                a.flex_1,
+                a.text_sm,
+                a.font_normal,
+                a.leading_snug,
+                t.atoms.text_contrast_medium,
+                a.text_left,
+              ]}>
+              {desc.sourceType === 'user' ? (
+                <Trans>Labeled by the author.</Trans>
+              ) : (
+                <Trans>Labeled by {sanitizeDisplayName(desc.source!)}.</Trans>
+              )}{' '}
+              <Text
+                style={[
+                  {color: t.palette.primary_500},
+                  a.text_sm,
+                  state.hovered && [web({textDecoration: 'underline'})],
+                ]}>
+                <Trans>Learn more.</Trans>
+              </Text>
+            </Text>
+          )}
+        </Button>
+      )}
+
+      {override && <View style={childContainerStyle}>{children}</View>}
+    </View>
+  )
+}
+
+const styles = StyleSheet.create({
+  outer: {
+    overflow: 'hidden',
+  },
+  cover: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    gap: 6,
+    borderRadius: 8,
+    marginTop: 4,
+    paddingVertical: 14,
+    paddingLeft: 14,
+    paddingRight: 18,
+  },
+  showBtn: {
+    marginLeft: 'auto',
+    alignSelf: 'center',
+  },
+})