Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add left column of web shell

+129 -69
+9 -7
src/view/com/discover/SuggestedFollows.tsx
··· 1 1 import React, {useEffect, useState} from 'react' 2 2 import { 3 3 ActivityIndicator, 4 - FlatList, 5 4 StyleSheet, 6 5 TouchableOpacity, 7 6 View, ··· 13 12 } from '@fortawesome/react-native-fontawesome' 14 13 import {observer} from 'mobx-react-lite' 15 14 import _omit from 'lodash.omit' 15 + import {CenteredView, FlatList} from '../util/Views' 16 16 import {ErrorScreen} from '../util/error/ErrorScreen' 17 17 import {Link} from '../util/Link' 18 18 import {Text} from '../util/text/Text' ··· 120 120 return ( 121 121 <View style={styles.container}> 122 122 {view.hasError ? ( 123 - <ErrorScreen 124 - title="Failed to load suggestions" 125 - message="There was an error while trying to load suggested follows." 126 - details={view.error} 127 - onPressTryAgain={onRefresh} 128 - /> 123 + <CenteredView> 124 + <ErrorScreen 125 + title="Failed to load suggestions" 126 + message="There was an error while trying to load suggested follows." 127 + details={view.error} 128 + onPressTryAgain={onRefresh} 129 + /> 130 + </CenteredView> 129 131 ) : view.isEmpty ? ( 130 132 <View /> 131 133 ) : (
-4
src/view/com/util/BlurView.web.tsx
··· 24 24 } 25 25 26 26 const styles = StyleSheet.create({ 27 - blur: { 28 - // @ts-ignore using an RNW-specific attribute here -prf 29 - backdropFilter: 'blur(5px)', 30 - }, 31 27 dark: { 32 28 backgroundColor: '#0008', 33 29 },
+4 -1
src/view/lib/icons.tsx
··· 47 47 export function HomeIcon({ 48 48 style, 49 49 size, 50 + strokeWidth = 4, 50 51 }: { 51 52 style?: StyleProp<ViewStyle> 52 53 size?: string | number 54 + strokeWidth?: number 53 55 }) { 54 56 return ( 55 57 <Svg ··· 57 59 width={size || 24} 58 60 height={size || 24} 59 61 stroke="currentColor" 62 + fill="none" 60 63 style={style}> 61 64 <Path 62 - strokeWidth={4} 65 + strokeWidth={strokeWidth} 63 66 d="M 23.951 2 C 23.631 2.011 23.323 2.124 23.072 2.322 L 8.859 13.52 C 7.055 14.941 6 17.114 6 19.41 L 6 38.5 C 6 39.864 7.136 41 8.5 41 L 18.5 41 C 19.864 41 21 39.864 21 38.5 L 21 28.5 C 21 28.205 21.205 28 21.5 28 L 26.5 28 C 26.795 28 27 28.205 27 28.5 L 27 38.5 C 27 39.864 28.136 41 29.5 41 L 39.5 41 C 40.864 41 42 39.864 42 38.5 L 42 19.41 C 42 17.114 40.945 14.941 39.141 13.52 L 24.928 2.322 C 24.65 2.103 24.304 1.989 23.951 2 Z" 64 67 /> 65 68 </Svg>
+3 -3
src/view/screens/Search.tsx
··· 1 1 import React, {useEffect, useState, useMemo, useRef} from 'react' 2 2 import { 3 3 Keyboard, 4 - ScrollView, 5 4 StyleSheet, 6 5 TextInput, 7 6 TouchableOpacity, 8 7 View, 9 8 } from 'react-native' 10 9 import {ViewHeader} from '../com/util/ViewHeader' 10 + import {CenteredView, ScrollView} from '../com/util/Views' 11 11 import {SuggestedFollows} from '../com/discover/SuggestedFollows' 12 12 import {UserAvatar} from '../com/util/UserAvatar' 13 13 import {Text} from '../com/util/text/Text' ··· 54 54 return ( 55 55 <View style={[pal.view, styles.container]}> 56 56 <ViewHeader title="Search" /> 57 - <View style={[pal.view, pal.border, styles.inputContainer]}> 57 + <CenteredView style={[pal.view, pal.border, styles.inputContainer]}> 58 58 <MagnifyingGlassIcon style={[pal.text, styles.inputIcon]} /> 59 59 <TextInput 60 60 testID="searchTextInput" ··· 66 66 style={[pal.text, styles.input]} 67 67 onChangeText={onChangeQuery} 68 68 /> 69 - </View> 69 + </CenteredView> 70 70 <View style={styles.outputContainer}> 71 71 {query ? ( 72 72 <ScrollView testID="searchScrollView" onScroll={Keyboard.dismiss}>
+2 -1
src/view/shell/web/index.tsx
··· 3 3 import {View, StyleSheet, Text} from 'react-native' 4 4 import {useStores} from '../../../state' 5 5 import {match, MatchResult} from '../../routes' 6 - // import {DesktopLeftColumn} from './left-column' 6 + import {DesktopLeftColumn} from './left-column' 7 7 // import {DesktopRightColumn} from './right-column' 8 8 import {Login} from '../../screens/Login' 9 9 import {ErrorBoundary} from '../../com/util/ErrorBoundary' ··· 34 34 </ErrorBoundary> 35 35 </View> 36 36 ))} 37 + <DesktopLeftColumn /> 37 38 </View> 38 39 ) 39 40 // TODO
+111 -53
src/view/shell/web/left-column.tsx
··· 1 1 import React from 'react' 2 - import {View} from 'react-native' 3 - 4 - // export const NavItem: React.FC<{label: string; screen: string}> = ({ 5 - // label, 6 - // screen, 7 - // }) => { 8 - // const Link = <></> // TODO 9 - // return ( 10 - // <View> 11 - // <Pressable 12 - // style={state => [ 13 - // // @ts-ignore it does exist! (react-native-web) -prf 14 - // state.hovered && styles.navItemHovered, 15 - // ]}> 16 - // <Link 17 - // style={[ 18 - // styles.navItemLink, 19 - // false /* TODO route.name === screen*/ && styles.navItemLinkSelected, 20 - // ]} 21 - // to={{screen, params: {}}}> 22 - // {label} 23 - // </Link> 24 - // </Pressable> 25 - // </View> 26 - // ) 27 - // } 2 + import {Pressable, StyleSheet, View} from 'react-native' 3 + import {observer} from 'mobx-react-lite' 4 + import {Link} from '../../com/util/Link' 5 + import {Text} from '../../com/util/text/Text' 6 + import {colors} from '../../lib/styles' 7 + import {useStores} from '../../../state' 8 + import {usePalette} from '../../lib/hooks/usePalette' 9 + import { 10 + HomeIcon, 11 + HomeIconSolid, 12 + BellIcon, 13 + BellIconSolid, 14 + MagnifyingGlassIcon, 15 + CogIcon, 16 + } from '../../lib/icons' 28 17 29 - export const DesktopLeftColumn: React.FC = () => { 30 - // TODO 31 - return <View /> 32 - // return ( 33 - // <View style={styles.container}> 34 - // <NavItem screen="Home" label="Home" /> 35 - // <NavItem screen="Search" label="Search" /> 36 - // <NavItem screen="Notifications" label="Notifications" /> 37 - // </View> 38 - // ) 18 + interface NavItemProps { 19 + label: string 20 + count?: number 21 + href: string 22 + icon: JSX.Element 23 + iconFilled: JSX.Element 39 24 } 25 + export const NavItem = observer( 26 + ({label, count, href, icon, iconFilled}: NavItemProps) => { 27 + const store = useStores() 28 + const pal = usePalette('default') 29 + const isCurrent = store.nav.tab.current.url === href 30 + return ( 31 + <Pressable 32 + style={state => [ 33 + // @ts-ignore Pressable state differs for RNW -prf 34 + state.hovered && {backgroundColor: pal.colors.backgroundLight}, 35 + ]}> 36 + <Link style={styles.navItem} href={href}> 37 + <View style={styles.navItemIconWrapper}> 38 + {isCurrent ? iconFilled : icon} 39 + {typeof count === 'number' && count > 0 && ( 40 + <Text type="button" style={styles.navItemCount}> 41 + {count} 42 + </Text> 43 + )} 44 + </View> 45 + <Text type={isCurrent ? 'xl-bold' : 'xl-medium'}>{label}</Text> 46 + </Link> 47 + </Pressable> 48 + ) 49 + }, 50 + ) 40 51 41 - // const styles = StyleSheet.create({ 42 - // container: { 43 - // position: 'absolute', 44 - // left: 'calc(50vw - 500px)', 45 - // width: '200px', 46 - // height: '100%', 47 - // }, 48 - // navItemHovered: { 49 - // backgroundColor: 'gray', 50 - // }, 51 - // navItemLink: { 52 - // padding: '1rem', 53 - // }, 54 - // navItemLinkSelected: { 55 - // color: 'blue', 56 - // }, 57 - // }) 52 + export const DesktopLeftColumn = observer(() => { 53 + const store = useStores() 54 + const pal = usePalette('default') 55 + return ( 56 + <View style={[styles.container, pal.border]}> 57 + <NavItem 58 + href="/" 59 + label="Home" 60 + icon={<HomeIcon />} 61 + iconFilled={<HomeIconSolid />} 62 + /> 63 + <NavItem 64 + href="/search" 65 + label="Search" 66 + icon={<MagnifyingGlassIcon />} 67 + iconFilled={<MagnifyingGlassIcon strokeWidth={4} />} 68 + /> 69 + <NavItem 70 + href="/notifications" 71 + label="Notifications" 72 + count={store.me.notificationCount} 73 + icon={<BellIcon />} 74 + iconFilled={<BellIconSolid />} 75 + /> 76 + <NavItem 77 + href="/settings" 78 + label="Settings" 79 + icon={<CogIcon strokeWidth={1.5} />} 80 + iconFilled={<CogIcon strokeWidth={2} />} 81 + /> 82 + </View> 83 + ) 84 + }) 85 + 86 + const styles = StyleSheet.create({ 87 + container: { 88 + position: 'absolute', 89 + left: 'calc(50vw - 500px)', 90 + width: '200px', 91 + height: '100%', 92 + borderRightWidth: 1, 93 + }, 94 + navItem: { 95 + padding: '1rem', 96 + flexDirection: 'row', 97 + alignItems: 'center', 98 + }, 99 + navItemIconWrapper: { 100 + flexDirection: 'row', 101 + width: 30, 102 + justifyContent: 'center', 103 + marginRight: 5, 104 + }, 105 + navItemCount: { 106 + position: 'absolute', 107 + top: -5, 108 + left: 15, 109 + backgroundColor: colors.red3, 110 + color: colors.white, 111 + fontSize: 12, 112 + paddingHorizontal: 4, 113 + borderRadius: 4, 114 + }, 115 + })