about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/NewskieDialog.tsx81
-rw-r--r--src/components/icons/Newskie.tsx5
-rw-r--r--src/screens/Profile/Header/Handle.tsx7
3 files changed, 92 insertions, 1 deletions
diff --git a/src/components/NewskieDialog.tsx b/src/components/NewskieDialog.tsx
new file mode 100644
index 000000000..fcdae0daa
--- /dev/null
+++ b/src/components/NewskieDialog.tsx
@@ -0,0 +1,81 @@
+import React from 'react'
+import {View} from 'react-native'
+import {AppBskyActorDefs, moderateProfile} from '@atproto/api'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+import {differenceInSeconds} from 'date-fns'
+
+import {useGetTimeAgo} from '#/lib/hooks/useTimeAgo'
+import {useModerationOpts} from '#/state/preferences/moderation-opts'
+import {HITSLOP_10} from 'lib/constants'
+import {sanitizeDisplayName} from 'lib/strings/display-names'
+import {atoms as a} from '#/alf'
+import {Button} from '#/components/Button'
+import * as Dialog from '#/components/Dialog'
+import {useDialogControl} from '#/components/Dialog'
+import {Newskie} from '#/components/icons/Newskie'
+import {Text} from '#/components/Typography'
+
+export function NewskieDialog({
+  profile,
+}: {
+  profile: AppBskyActorDefs.ProfileViewDetailed
+}) {
+  const {_} = useLingui()
+  const moderationOpts = useModerationOpts()
+  const control = useDialogControl()
+  const profileName = React.useMemo(() => {
+    const name = profile.displayName || profile.handle
+    if (!moderationOpts) return name
+    const moderation = moderateProfile(profile, moderationOpts)
+    return sanitizeDisplayName(name, moderation.ui('displayName'))
+  }, [moderationOpts, profile])
+  const timeAgo = useGetTimeAgo()
+  const createdAt = profile.createdAt as string | undefined
+  const daysOld = React.useMemo(() => {
+    if (!createdAt) return Infinity
+    return differenceInSeconds(new Date(), new Date(createdAt)) / 86400
+  }, [createdAt])
+
+  if (!createdAt || daysOld > 7) return null
+
+  return (
+    <View style={[a.pr_2xs]}>
+      <Button
+        label={_(
+          msg`This user is new here. Press for more info about when they joined.`,
+        )}
+        hitSlop={HITSLOP_10}
+        onPress={control.open}>
+        {({hovered, pressed}) => (
+          <Newskie
+            size="lg"
+            fill="#FFC404"
+            style={{
+              opacity: hovered || pressed ? 0.5 : 1,
+            }}
+          />
+        )}
+      </Button>
+
+      <Dialog.Outer control={control}>
+        <Dialog.Handle />
+        <Dialog.ScrollableInner
+          label={_(msg`New user info dialog`)}
+          style={[{width: 'auto', maxWidth: 400, minWidth: 200}]}>
+          <View style={[a.gap_sm]}>
+            <Text style={[a.font_bold, a.text_xl]}>
+              <Trans>Say hello!</Trans>
+            </Text>
+            <Text style={[a.text_md]}>
+              <Trans>
+                {profileName} joined Bluesky{' '}
+                {timeAgo(createdAt, {format: 'long'})} ago
+              </Trans>
+            </Text>
+          </View>
+        </Dialog.ScrollableInner>
+      </Dialog.Outer>
+    </View>
+  )
+}
diff --git a/src/components/icons/Newskie.tsx b/src/components/icons/Newskie.tsx
new file mode 100644
index 000000000..ddbb33201
--- /dev/null
+++ b/src/components/icons/Newskie.tsx
@@ -0,0 +1,5 @@
+import {createSinglePathSVG} from './TEMPLATE'
+
+export const Newskie = createSinglePathSVG({
+  path: 'M11.183 8.561c0 .544.348.984.892.984.545 0 .893-.44.893-.985V6.985c0-.544-.348-.985-.893-.985-.543 0-.892.44-.892.985v1.576Zm5.94 7.481c0 .539-.438.942-.976.942H8.004c-.538 0-.975-.411-.975-.95 0-2.782 2.264-5.021 5.046-5.021 2.783 0 5.047 2.247 5.047 5.03Zm-.43-4.584a.983.983 0 0 1 0-1.393l1.114-1.114a.985.985 0 0 1 1.393 1.393l-1.114 1.114a.985.985 0 0 1-1.393 0Zm2.897 3.741h1.575c.544 0 .985.349.985.892 0 .544-.44.892-.985.892h-1.67a.872.872 0 0 1-.89-.887c0-.543.44-.897.985-.897Zm-14.045.893c0-.544-.44-.892-.985-.892H2.985c-.544 0-.985.349-.985.892 0 .544.44.892.985.892H4.56c.545 0 .985-.349.985-.892Zm1.913-6.027a.985.985 0 0 1-1.393 1.393L4.95 10.344A.985.985 0 0 1 6.344 8.95l1.114 1.114Z',
+})
diff --git a/src/screens/Profile/Header/Handle.tsx b/src/screens/Profile/Header/Handle.tsx
index 9ab24fbbe..4f438a286 100644
--- a/src/screens/Profile/Header/Handle.tsx
+++ b/src/screens/Profile/Header/Handle.tsx
@@ -5,7 +5,9 @@ import {Trans} from '@lingui/macro'
 
 import {Shadow} from '#/state/cache/types'
 import {isInvalidHandle} from 'lib/strings/handles'
+import {isAndroid} from 'platform/detection'
 import {atoms as a, useTheme, web} from '#/alf'
+import {NewskieDialog} from '#/components/NewskieDialog'
 import {Text} from '#/components/Typography'
 
 export function ProfileHeaderHandle({
@@ -17,7 +19,10 @@ export function ProfileHeaderHandle({
   const invalidHandle = isInvalidHandle(profile.handle)
   const blockHide = profile.viewer?.blocking || profile.viewer?.blockedBy
   return (
-    <View style={[a.flex_row, a.gap_xs, a.align_center]} pointerEvents="none">
+    <View
+      style={[a.flex_row, a.gap_xs, a.align_center]}
+      pointerEvents={isAndroid ? 'box-only' : 'auto'}>
+      <NewskieDialog profile={profile} />
       {profile.viewer?.followedBy && !blockHide ? (
         <View style={[t.atoms.bg_contrast_25, a.rounded_xs, a.px_sm, a.py_xs]}>
           <Text style={[t.atoms.text, a.text_sm]}>