about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--public/img/banner.jpgbin0 -> 28030 bytes
-rw-r--r--src/view/com/profile/ProfileHeader.tsx177
-rw-r--r--src/view/com/util/Selector.tsx73
-rw-r--r--src/view/index.ts2
-rw-r--r--src/view/lib/assets.native.ts2
-rw-r--r--src/view/lib/assets.ts2
-rw-r--r--src/view/lib/styles.ts4
7 files changed, 222 insertions, 38 deletions
diff --git a/public/img/banner.jpg b/public/img/banner.jpg
new file mode 100644
index 000000000..097c24f7c
--- /dev/null
+++ b/public/img/banner.jpg
Binary files differdiff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx
index 4ad84b32a..08d895554 100644
--- a/src/view/com/profile/ProfileHeader.tsx
+++ b/src/view/com/profile/ProfileHeader.tsx
@@ -2,19 +2,22 @@ import React, {useState, useEffect} from 'react'
 import {observer} from 'mobx-react-lite'
 import {
   ActivityIndicator,
-  Button,
   Image,
   StyleSheet,
   Text,
   TouchableOpacity,
   View,
 } from 'react-native'
+import LinearGradient from 'react-native-linear-gradient'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {ProfileViewModel} from '../../../state/models/profile-view'
 import {useStores} from '../../../state'
 import {pluralize} from '../../lib/strings'
-import {s, colors} from '../../lib/styles'
-import {AVIS} from '../../lib/assets'
+import {s, gradients, colors} from '../../lib/styles'
+import {AVIS, BANNER} from '../../lib/assets'
 import Toast from '../util/Toast'
+import {Link} from '../util/Link'
+import {Selector, SelectorItem} from '../util/Selector'
 
 export const ProfileHeader = observer(function ProfileHeader({
   user,
@@ -35,6 +38,11 @@ export const ProfileHeader = observer(function ProfileHeader({
     newView.setup().catch(err => console.error('Failed to fetch profile', err))
   }, [user, view?.params.user, store])
 
+  const selectorItems: SelectorItem[] = [
+    {label: 'Posts', onSelect() {}},
+    {label: 'Badges', onSelect() {}},
+  ]
+
   const onPressToggleFollow = () => {
     view?.toggleFollowing().then(
       () => {
@@ -51,6 +59,12 @@ export const ProfileHeader = observer(function ProfileHeader({
       err => console.error('Failed to toggle follow', err),
     )
   }
+  const onPressEditProfile = () => {
+    // TODO
+  }
+  const onPressMenu = () => {
+    // TODO
+  }
   const onPressFollowers = () => {
     store.nav.navigate(`/profile/${user}/followers`)
   }
@@ -84,40 +98,79 @@ export const ProfileHeader = observer(function ProfileHeader({
 
   // loaded
   // =
+  const isMe = store.me.did === view.did
   return (
     <View style={styles.outer}>
+      <Image style={styles.banner} source={BANNER} />
       <Image style={styles.avi} source={AVIS[view.name] || AVIS['alice.com']} />
-      <View style={[styles.nameLine, s.mb2]}>
-        <Text style={[s.bold, s.f18, s.mr2]}>{view.displayName}</Text>
-        <Text style={[s.gray5]}>@{view.name}</Text>
-      </View>
-      {view.description && (
-        <Text style={[s.mb5, s.f15, s['lh15-1.3']]}>{view.description}</Text>
-      )}
-      <View style={s.flexRow}>
-        <TouchableOpacity
-          style={[s.flexRow, s.mr10]}
-          onPress={onPressFollowers}>
-          <Text style={[s.bold, s.mr2]}>{view.followersCount}</Text>
-          <Text style={s.gray5}>
-            {pluralize(view.followersCount, 'follower')}
-          </Text>
-        </TouchableOpacity>
-        <TouchableOpacity style={[s.flexRow, s.mr10]} onPress={onPressFollows}>
-          <Text style={[s.bold, s.mr2]}>{view.followsCount}</Text>
-          <Text style={s.gray5}>following</Text>
-        </TouchableOpacity>
-        <View style={[s.flexRow, s.mr10]}>
-          <Text style={[s.bold, s.mr2]}>{view.postsCount}</Text>
-          <Text style={s.gray5}>{pluralize(view.postsCount, 'post')}</Text>
+      <View style={styles.content}>
+        <View style={[styles.displayNameLine]}>
+          <Text style={styles.displayName}>{view.displayName}</Text>
         </View>
+        <View style={styles.badgesLine}>
+          <FontAwesomeIcon icon="shield" style={s.mr5} size={12} />
+          <Link href="/" title="Badge TODO">
+            <Text style={[s.f12, s.bold]}>
+              Employee <Text style={[s.blue3]}>@blueskyweb.xyz</Text>
+            </Text>
+          </Link>
+        </View>
+        <View style={[styles.buttonsLine]}>
+          {isMe ? (
+            <TouchableOpacity
+              onPress={onPressEditProfile}
+              style={[styles.mainBtn, styles.btn]}>
+              <Text style={[s.fw600, s.f16]}>Edit Profile</Text>
+            </TouchableOpacity>
+          ) : view.myState.hasFollowed ? (
+            <TouchableOpacity
+              onPress={onPressToggleFollow}
+              style={[styles.mainBtn, styles.btn]}>
+              <Text style={[s.fw600, s.f16]}>Following</Text>
+            </TouchableOpacity>
+          ) : (
+            <TouchableOpacity onPress={onPressToggleFollow}>
+              <LinearGradient
+                colors={[gradients.primary.start, gradients.primary.end]}
+                start={{x: 0, y: 0}}
+                end={{x: 1, y: 1}}
+                style={[styles.followBtn]}>
+                <FontAwesomeIcon icon="plus" style={[s.white, s.mr5]} />
+                <Text style={[s.white, s.fw600, s.f16]}>Follow</Text>
+              </LinearGradient>
+            </TouchableOpacity>
+          )}
+          <TouchableOpacity
+            onPress={onPressMenu}
+            style={[styles.btn, styles.secondaryBtn, s.ml10]}>
+            <FontAwesomeIcon icon="ellipsis" style={[s.gray5]} />
+          </TouchableOpacity>
+        </View>
+        <View style={[s.flexRow, s.mb10]}>
+          <TouchableOpacity
+            style={[s.flexRow, s.mr10]}
+            onPress={onPressFollowers}>
+            <Text style={[s.bold, s.mr2]}>{view.followersCount}</Text>
+            <Text style={s.gray5}>
+              {pluralize(view.followersCount, 'follower')}
+            </Text>
+          </TouchableOpacity>
+          <TouchableOpacity
+            style={[s.flexRow, s.mr10]}
+            onPress={onPressFollows}>
+            <Text style={[s.bold, s.mr2]}>{view.followsCount}</Text>
+            <Text style={s.gray5}>following</Text>
+          </TouchableOpacity>
+          <View style={[s.flexRow, s.mr10]}>
+            <Text style={[s.bold, s.mr2]}>{view.postsCount}</Text>
+            <Text style={s.gray5}>{pluralize(view.postsCount, 'post')}</Text>
+          </View>
+        </View>
+        {view.description && (
+          <Text style={[s.mb10, s.f15, s['lh15-1.3']]}>{view.description}</Text>
+        )}
       </View>
-      <View>
-        <Button
-          title={view.myState.hasFollowed ? 'Unfollow' : 'Follow'}
-          onPress={onPressToggleFollow}
-        />
-      </View>
+      <Selector items={selectorItems} />
     </View>
   )
 })
@@ -125,18 +178,66 @@ export const ProfileHeader = observer(function ProfileHeader({
 const styles = StyleSheet.create({
   outer: {
     backgroundColor: colors.white,
-    padding: 10,
     borderBottomWidth: 1,
     borderColor: colors.gray2,
   },
+  banner: {
+    width: '100%',
+    height: 120,
+  },
   avi: {
-    width: 60,
-    height: 60,
-    borderRadius: 30,
+    position: 'absolute',
+    top: 80,
+    left: 10,
+    width: 80,
+    height: 80,
+    borderRadius: 40,
     resizeMode: 'cover',
+    borderWidth: 2,
+    borderColor: colors.white,
+  },
+  content: {
+    paddingTop: 8,
+    paddingHorizontal: 14,
+    paddingBottom: 4,
   },
-  nameLine: {
+  displayNameLine: {
+    paddingLeft: 86,
+    marginBottom: 14,
+  },
+  displayName: {
+    fontSize: 24,
+    fontWeight: 'bold',
+  },
+  badgesLine: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    marginBottom: 10,
+  },
+  buttonsLine: {
+    flexDirection: 'row',
+    marginBottom: 12,
+  },
+  followBtn: {
     flexDirection: 'row',
-    alignItems: 'flex-end',
+    alignItems: 'center',
+    justifyContent: 'center',
+    paddingVertical: 8,
+    paddingHorizontal: 60,
+    borderRadius: 30,
+  },
+  btn: {
+    alignItems: 'center',
+    justifyContent: 'center',
+    paddingVertical: 8,
+    borderRadius: 30,
+    borderWidth: 1,
+    borderColor: colors.gray2,
+  },
+  mainBtn: {
+    paddingHorizontal: 40,
+  },
+  secondaryBtn: {
+    paddingHorizontal: 12,
   },
 })
diff --git a/src/view/com/util/Selector.tsx b/src/view/com/util/Selector.tsx
new file mode 100644
index 000000000..ef7c65d59
--- /dev/null
+++ b/src/view/com/util/Selector.tsx
@@ -0,0 +1,73 @@
+import React, {useState} from 'react'
+import {
+  StyleProp,
+  StyleSheet,
+  Text,
+  TouchableWithoutFeedback,
+  View,
+  ViewStyle,
+} from 'react-native'
+import {colors} from '../../lib/styles'
+
+export interface SelectorItem {
+  label: string
+}
+
+export function Selector({
+  style,
+  items,
+  onSelect,
+}: {
+  style?: StyleProp<ViewStyle>
+  items: SelectorItem[]
+  onSelect?: (index: number) => void
+}) {
+  const [selectedIndex, setSelectedIndex] = useState<number>(0)
+  const onPressItem = (index: number) => {
+    setSelectedIndex(index)
+    onSelect?.(index)
+  }
+
+  return (
+    <View style={[styles.outer, style]}>
+      {items.map((item, i) => {
+        const selected = i === selectedIndex
+        return (
+          <TouchableWithoutFeedback key={i} onPress={() => onPressItem(i)}>
+            <View style={selected ? styles.itemSelected : styles.item}>
+              <Text style={selected ? styles.labelSelected : styles.label}>
+                {item.label}
+              </Text>
+            </View>
+          </TouchableWithoutFeedback>
+        )
+      })}
+    </View>
+  )
+}
+
+const styles = StyleSheet.create({
+  outer: {
+    flexDirection: 'row',
+    paddingHorizontal: 14,
+  },
+  item: {
+    paddingBottom: 12,
+    marginRight: 20,
+  },
+  label: {
+    fontWeight: '600',
+    fontSize: 16,
+    color: colors.gray5,
+  },
+  itemSelected: {
+    paddingBottom: 8,
+    marginRight: 20,
+    borderBottomWidth: 4,
+    borderBottomColor: colors.purple3,
+  },
+  labelSelected: {
+    fontWeight: '600',
+    fontSize: 16,
+  },
+})
diff --git a/src/view/index.ts b/src/view/index.ts
index af24030c8..c4b8fa9f9 100644
--- a/src/view/index.ts
+++ b/src/view/index.ts
@@ -26,6 +26,7 @@ import {faPenNib} from '@fortawesome/free-solid-svg-icons/faPenNib'
 import {faPlus} from '@fortawesome/free-solid-svg-icons/faPlus'
 import {faShare} from '@fortawesome/free-solid-svg-icons/faShare'
 import {faShareFromSquare} from '@fortawesome/free-solid-svg-icons/faShareFromSquare'
+import {faShield} from '@fortawesome/free-solid-svg-icons/faShield'
 import {faRetweet} from '@fortawesome/free-solid-svg-icons/faRetweet'
 import {faUser} from '@fortawesome/free-regular-svg-icons/faUser'
 import {faUsers} from '@fortawesome/free-solid-svg-icons/faUsers'
@@ -60,6 +61,7 @@ export function setup() {
     faRetweet,
     faShare,
     faShareFromSquare,
+    faShield,
     faUser,
     faUsers,
     faX,
diff --git a/src/view/lib/assets.native.ts b/src/view/lib/assets.native.ts
index af5ee2bac..a341e02a9 100644
--- a/src/view/lib/assets.native.ts
+++ b/src/view/lib/assets.native.ts
@@ -5,3 +5,5 @@ export const AVIS: Record<string, ImageSourcePropType> = {
   'bob.com': require('../../../public/img/bob.jpg'),
   'carla.com': require('../../../public/img/carla.jpg'),
 }
+
+export const BANNER: ImageSourcePropType = require('../../../public/img/banner.jpg')
diff --git a/src/view/lib/assets.ts b/src/view/lib/assets.ts
index 7d0584a41..1575101d2 100644
--- a/src/view/lib/assets.ts
+++ b/src/view/lib/assets.ts
@@ -5,3 +5,5 @@ export const AVIS: Record<string, ImageSourcePropType> = {
   'bob.com': {uri: '/img/bob.jpg'},
   'carla.com': {uri: '/img/carla.jpg'},
 }
+
+export const BANNER: ImageSourcePropType = {uri: '/img/banner.jpg'}
diff --git a/src/view/lib/styles.ts b/src/view/lib/styles.ts
index 82fe41546..17a24707b 100644
--- a/src/view/lib/styles.ts
+++ b/src/view/lib/styles.ts
@@ -62,6 +62,10 @@ export const s = StyleSheet.create({
   fw200: {fontWeight: '200'},
 
   // font sizes
+  f9: {fontSize: 9},
+  f10: {fontSize: 10},
+  f11: {fontSize: 11},
+  f12: {fontSize: 12},
   f13: {fontSize: 13},
   f14: {fontSize: 14},
   f15: {fontSize: 15},