about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEric Bailey <git@esb.lol>2024-09-10 14:23:30 -0500
committerEric Bailey <git@esb.lol>2024-09-11 19:58:16 -0500
commit3c8b3b47823475b93a92dcf82a4cabbda625c323 (patch)
tree3d65f28f89142148579c6caa005c212327fc315b
parent76c584d981f195a580e132b786e101b3d0d32380 (diff)
downloadvoidsky-3c8b3b47823475b93a92dcf82a4cabbda625c323.tar.zst
Progress on desktoip
-rw-r--r--src/alf/index.tsx18
-rw-r--r--src/components/dialogs/nudges/TenMillion.tsx330
-rw-r--r--src/view/icons/Logomark.tsx29
3 files changed, 331 insertions, 46 deletions
diff --git a/src/alf/index.tsx b/src/alf/index.tsx
index 5fa7d3b1a..d699de6a5 100644
--- a/src/alf/index.tsx
+++ b/src/alf/index.tsx
@@ -18,9 +18,17 @@ export * from '#/alf/util/themeSelector'
 export const Context = React.createContext<{
   themeName: ThemeName
   theme: Theme
+  themes: ReturnType<typeof createThemes>
 }>({
   themeName: 'light',
   theme: defaultTheme,
+  themes: createThemes({
+    hues: {
+      primary: BLUE_HUE,
+      negative: RED_HUE,
+      positive: GREEN_HUE,
+    },
+  }),
 })
 
 export function ThemeProvider({
@@ -42,18 +50,22 @@ export function ThemeProvider({
     <Context.Provider
       value={React.useMemo(
         () => ({
+          themes,
           themeName: themeName,
           theme: theme,
         }),
-        [theme, themeName],
+        [theme, themeName, themes],
       )}>
       {children}
     </Context.Provider>
   )
 }
 
-export function useTheme() {
-  return React.useContext(Context).theme
+export function useTheme(theme?: ThemeName) {
+  const ctx = React.useContext(Context)
+  return React.useMemo(() => {
+    return theme ? ctx.themes[theme] : ctx.theme
+  }, [theme, ctx])
 }
 
 export function useBreakpoints() {
diff --git a/src/components/dialogs/nudges/TenMillion.tsx b/src/components/dialogs/nudges/TenMillion.tsx
index 9b5d5eae6..869056977 100644
--- a/src/components/dialogs/nudges/TenMillion.tsx
+++ b/src/components/dialogs/nudges/TenMillion.tsx
@@ -1,25 +1,74 @@
 import React from 'react'
-import {useLingui} from '@lingui/react'
-import {msg} from '@lingui/macro'
 import {View} from 'react-native'
 import ViewShot from 'react-native-view-shot'
+import {moderateProfile} from '@atproto/api'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 
-import {atoms as a, useBreakpoints, tokens} from '#/alf'
+import {sanitizeDisplayName} from '#/lib/strings/display-names'
+import {sanitizeHandle} from '#/lib/strings/handles'
+import {isNative} from '#/platform/detection'
+import {useModerationOpts} from '#/state/preferences/moderation-opts'
+import {useProfileQuery} from '#/state/queries/profile'
+import {useSession} from '#/state/session'
+import {useComposerControls} from 'state/shell'
+import {formatCount} from '#/view/com/util/numeric/format'
+import {UserAvatar} from '#/view/com/util/UserAvatar'
+import {Logomark} from '#/view/icons/Logomark'
+import {
+  atoms as a,
+  ThemeProvider,
+  tokens,
+  useBreakpoints,
+  useTheme,
+} from '#/alf'
+import {Button, ButtonIcon, ButtonText} from '#/components/Button'
 import * as Dialog from '#/components/Dialog'
-import {Text} from '#/components/Typography'
+import {useContext} from '#/components/dialogs/nudges'
+import {Divider} from '#/components/Divider'
 import {GradientFill} from '#/components/GradientFill'
-import {Button, ButtonText} from '#/components/Button'
-import {useComposerControls} from 'state/shell'
+import {ArrowOutOfBox_Stroke2_Corner0_Rounded as Share} from '#/components/icons/ArrowOutOfBox'
+import {Image_Stroke2_Corner0_Rounded as ImageIcon} from '#/components/icons/Image'
+import {Loader} from '#/components/Loader'
+import {Text} from '#/components/Typography'
 
-import {useContext} from '#/components/dialogs/nudges'
+const RATIO = 8 / 10
+const WIDTH = 2000
+const HEIGHT = WIDTH * RATIO
+
+function getFontSize(count: number) {
+  const length = count.toString().length
+  if (length < 7) {
+    return 80
+  } else if (length < 5) {
+    return 100
+  } else {
+    return 70
+  }
+}
 
 export function TenMillion() {
-  const {_} = useLingui()
+  const t = useTheme()
+  const lightTheme = useTheme('light')
+  const {_, i18n} = useLingui()
   const {controls} = useContext()
   const {gtMobile} = useBreakpoints()
   const {openComposer} = useComposerControls()
-
   const imageRef = React.useRef<ViewShot>(null)
+  const {currentAccount} = useSession()
+  const {isLoading: isProfileLoading, data: profile} = useProfileQuery({
+    did: currentAccount!.did,
+  }) // TODO PWI
+  const moderationOpts = useModerationOpts()
+  const moderation = React.useMemo(() => {
+    return profile && moderationOpts
+      ? moderateProfile(profile, moderationOpts)
+      : undefined
+  }, [profile, moderationOpts])
+
+  const isLoading = isProfileLoading || !moderation || !profile
+
+  const userNumber = 56738
 
   const share = () => {
     if (imageRef.current && imageRef.current.capture) {
@@ -31,8 +80,8 @@ export function TenMillion() {
               imageUris: [
                 {
                   uri,
-                  width: 1000,
-                  height: 1000,
+                  width: WIDTH,
+                  height: HEIGHT,
                 },
               ],
             })
@@ -48,52 +97,247 @@ export function TenMillion() {
 
       <Dialog.ScrollableInner
         label={_(msg`Ten Million`)}
-        style={
-          [
-            // gtMobile ? {width: 'auto', maxWidth: 400, minWidth: 200} : a.w_full,
-          ]
-        }>
+        style={[
+          {
+            padding: 0,
+          },
+          // gtMobile ? {width: 'auto', maxWidth: 400, minWidth: 200} : a.w_full,
+        ]}>
         <View
           style={[
-            a.relative,
-            a.w_full,
+            a.rounded_md,
             a.overflow_hidden,
-            {
-              paddingTop: '100%',
+            isNative && {
+              borderTopLeftRadius: 40,
+              borderTopRightRadius: 40,
             },
           ]}>
-          <ViewShot
-            ref={imageRef}
-            options={{width: 2e3, height: 2e3}}
-            style={[a.absolute, a.inset_0]}>
+          <ThemeProvider theme="light">
             <View
               style={[
-                a.absolute,
-                a.inset_0,
-                a.align_center,
-                a.justify_center,
+                a.relative,
+                a.w_full,
+                a.overflow_hidden,
+                {
+                  paddingTop: '80%',
+                },
+              ]}>
+              <ViewShot
+                ref={imageRef}
+                options={{width: WIDTH, height: HEIGHT}}
+                style={[a.absolute, a.inset_0]}>
+                <View
+                  style={[
+                    a.absolute,
+                    a.inset_0,
+                    a.align_center,
+                    a.justify_center,
+                    {
+                      top: -1,
+                      bottom: -1,
+                      left: -1,
+                      right: -1,
+                      paddingVertical: 32,
+                      paddingHorizontal: 48,
+                    },
+                  ]}>
+                  <GradientFill gradient={tokens.gradients.bonfire} />
+
+                  {isLoading ? (
+                    <Loader size="xl" fill="white" />
+                  ) : (
+                    <View
+                      style={[
+                        a.flex_1,
+                        a.w_full,
+                        a.align_center,
+                        a.justify_center,
+                        a.rounded_md,
+                        {
+                          backgroundColor: 'white',
+                          shadowRadius: 32,
+                          shadowOpacity: 0.1,
+                          elevation: 24,
+                          shadowColor: tokens.gradients.bonfire.values[0][1],
+                        },
+                      ]}>
+                      <View
+                        style={[
+                          a.absolute,
+                          a.px_xl,
+                          a.py_xl,
+                          {
+                            top: 0,
+                            left: 0,
+                          },
+                        ]}>
+                        <Logomark fill={t.palette.primary_500} width={36} />
+                      </View>
+
+                      {/* Centered content */}
+                      <View
+                        style={[
+                          {
+                            paddingBottom: 48,
+                          },
+                        ]}>
+                        <Text
+                          style={[
+                            a.text_md,
+                            a.font_bold,
+                            a.text_center,
+                            a.pb_xs,
+                            lightTheme.atoms.text_contrast_medium,
+                          ]}>
+                          <Trans>
+                            Celebrating {formatCount(i18n, 10000000)} users
+                          </Trans>{' '}
+                          🎉
+                        </Text>
+                        <Text
+                          style={[
+                            a.relative,
+                            a.text_center,
+                            {
+                              fontStyle: 'italic',
+                              fontSize: getFontSize(userNumber),
+                              fontWeight: '900',
+                              letterSpacing: -2,
+                            },
+                          ]}>
+                          <Text
+                            style={[
+                              a.absolute,
+                              {
+                                color: t.palette.primary_500,
+                                fontSize: 32,
+                                left: -18,
+                                top: 8,
+                              },
+                            ]}>
+                            #
+                          </Text>
+                          {i18n.number(userNumber)}
+                        </Text>
+                      </View>
+                      {/* End centered content */}
+
+                      <View
+                        style={[
+                          a.absolute,
+                          a.px_xl,
+                          a.py_xl,
+                          {
+                            bottom: 0,
+                            left: 0,
+                            right: 0,
+                          },
+                        ]}>
+                        <View style={[a.flex_row, a.align_center, a.gap_sm]}>
+                          <UserAvatar
+                            size={36}
+                            avatar={profile.avatar}
+                            moderation={moderation.ui('avatar')}
+                          />
+                          <View style={[a.gap_2xs, a.flex_1]}>
+                            <Text style={[a.text_sm, a.font_bold]}>
+                              {sanitizeDisplayName(
+                                profile.displayName ||
+                                  sanitizeHandle(profile.handle),
+                                moderation.ui('displayName'),
+                              )}
+                            </Text>
+                            <View style={[a.flex_row, a.justify_between]}>
+                              <Text
+                                style={[
+                                  a.text_sm,
+                                  a.font_semibold,
+                                  lightTheme.atoms.text_contrast_medium,
+                                ]}>
+                                {sanitizeHandle(profile.handle, '@')}
+                              </Text>
+
+                              {profile.createdAt && (
+                                <Text
+                                  style={[
+                                    a.text_sm,
+                                    a.font_semibold,
+                                    lightTheme.atoms.text_contrast_low,
+                                  ]}>
+                                  {i18n.date(profile.createdAt, {
+                                    dateStyle: 'long',
+                                  })}
+                                </Text>
+                              )}
+                            </View>
+                          </View>
+                        </View>
+                      </View>
+                    </View>
+                  )}
+                </View>
+              </ViewShot>
+            </View>
+          </ThemeProvider>
+
+          <View style={[gtMobile ? a.p_2xl : a.p_xl]}>
+            <Text
+              style={[
+                a.text_5xl,
+                a.pb_lg,
                 {
-                  top: -1,
-                  bottom: -1,
-                  left: -1,
-                  right: -1,
+                  fontWeight: '900',
                 },
               ]}>
-              <GradientFill gradient={tokens.gradients.midnight} />
+              You're part of the next wave of the internet.
+            </Text>
+
+            <Text style={[a.leading_snug, a.text_lg, a.pb_xl]}>
+              Online culture is too important to be controlled by a few
+              corporations.{' '}
+              <Text style={[a.leading_snug, a.text_lg, a.italic]}>
+                We’re dedicated to building an open foundation for the social
+                internet so that we can all shape its future.
+              </Text>
+            </Text>
+
+            <Divider />
+
+            <View
+              style={[
+                a.flex_row,
+                a.align_center,
+                a.justify_end,
+                a.gap_md,
+                a.pt_xl,
+              ]}>
+              <Text style={[a.text_md, a.italic, t.atoms.text_contrast_medium]}>
+                Brag a little ;)
+              </Text>
 
-              <Text>10 milly, babyyy</Text>
+              <Button
+                label={_(msg`Share image externally`)}
+                size="large"
+                variant="solid"
+                color="secondary"
+                shape="square"
+                onPress={share}>
+                <ButtonIcon icon={Share} />
+              </Button>
+              <Button
+                label={_(msg`Share image in post`)}
+                size="large"
+                variant="solid"
+                color="primary"
+                onPress={share}>
+                <ButtonText>{_(msg`Share post`)}</ButtonText>
+                <ButtonIcon position="right" icon={ImageIcon} />
+              </Button>
             </View>
-          </ViewShot>
+          </View>
         </View>
 
-        <Button
-          label={_(msg`Generate`)}
-          size="medium"
-          variant="solid"
-          color="primary"
-          onPress={share}>
-          <ButtonText>{_(msg`Generate`)}</ButtonText>
-        </Button>
+        <Dialog.Close />
       </Dialog.ScrollableInner>
     </Dialog.Outer>
   )
diff --git a/src/view/icons/Logomark.tsx b/src/view/icons/Logomark.tsx
new file mode 100644
index 000000000..5715a1a40
--- /dev/null
+++ b/src/view/icons/Logomark.tsx
@@ -0,0 +1,29 @@
+import React from 'react'
+import Svg, {Path, PathProps, SvgProps} from 'react-native-svg'
+
+import {usePalette} from '#/lib/hooks/usePalette'
+
+const ratio = 54 / 61
+
+export function Logomark({
+  fill,
+  ...rest
+}: {fill?: PathProps['fill']} & SvgProps) {
+  const pal = usePalette('default')
+  // @ts-ignore it's fiiiiine
+  const size = parseInt(rest.width || 32)
+
+  return (
+    <Svg
+      fill="none"
+      viewBox="0 0 61 54"
+      {...rest}
+      width={size}
+      height={Number(size) * ratio}>
+      <Path
+        fill={fill || pal.text.color}
+        d="M13.223 3.602C20.215 8.832 27.738 19.439 30.5 25.13c2.762-5.691 10.284-16.297 17.278-21.528C52.824-.172 61-3.093 61 6.2c0 1.856-1.068 15.59-1.694 17.82-2.178 7.752-10.112 9.73-17.17 8.532 12.337 2.092 15.475 9.021 8.697 15.95-12.872 13.159-18.5-3.302-19.943-7.52-.264-.773-.388-1.135-.39-.827-.002-.308-.126.054-.39.827-1.442 4.218-7.071 20.679-19.943 7.52-6.778-6.929-3.64-13.858 8.697-15.95-7.058 1.197-14.992-.78-17.17-8.532C1.068 21.79 0 8.056 0 6.2 0-3.093 8.176-.172 13.223 3.602Z"
+      />
+    </Svg>
+  )
+}