Bluesky app fork with some witchin' additions 馃挮
witchsky.app
bluesky
fork
client
1import React from 'react'
2import {type StyleProp, type TextStyle, type ViewStyle} from 'react-native'
3import {View} from 'react-native'
4
5import {usePalette} from '#/lib/hooks/usePalette'
6import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
7import {atoms as a, useBreakpoints, useTheme} from '#/alf'
8import {Button, type ButtonProps, ButtonText} from '#/components/Button'
9import {EditBig_Stroke1_Corner0_Rounded as EditIcon} from '#/components/icons/EditBig'
10import {Text} from '#/components/Typography'
11
12export type EmptyStateButtonProps = Omit<ButtonProps, 'children' | 'label'> & {
13 label: string
14 text: string
15}
16
17export function EmptyState({
18 testID,
19 icon,
20 iconSize = '3xl',
21 message,
22 style,
23 textStyle,
24 button,
25}: {
26 testID?: string
27 icon?: React.ComponentType<any> | React.ReactElement
28 iconSize?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'
29 message: string
30 style?: StyleProp<ViewStyle>
31 textStyle?: StyleProp<TextStyle>
32 button?: EmptyStateButtonProps
33}) {
34 const pal = usePalette('default')
35 const {isTabletOrDesktop} = useWebMediaQueries()
36 const t = useTheme()
37 const {gtMobile} = useBreakpoints()
38
39 const placeholderIcon = (
40 <EditIcon size="2xl" fill={t.atoms.text_contrast_medium.color} />
41 )
42
43 const renderIcon = () => {
44 if (!icon) {
45 return placeholderIcon
46 }
47
48 if (React.isValidElement(icon)) {
49 return icon
50 }
51
52 if (
53 typeof icon === 'function' ||
54 (typeof icon === 'object' && icon && 'render' in icon)
55 ) {
56 const IconComponent = icon
57 return (
58 <IconComponent
59 size={iconSize}
60 fill={t.atoms.text_contrast_medium.color}
61 style={{color: t.atoms.text_contrast_low.color}}
62 />
63 )
64 }
65
66 return placeholderIcon
67 }
68
69 return (
70 <View testID={testID} style={[a.w_full, style]}>
71 <View
72 style={[
73 a.flex_row,
74 a.align_center,
75 a.justify_center,
76 a.self_center,
77 a.rounded_full,
78 a.mt_5xl,
79 {height: 64, width: 64},
80 React.isValidElement(icon)
81 ? a.bg_transparent
82 : [isTabletOrDesktop && {marginTop: 50}],
83 ]}>
84 {renderIcon()}
85 </View>
86 <Text
87 style={[
88 {
89 color: pal.colors.textLight,
90 maxWidth: gtMobile ? '40%' : '60%',
91 },
92 a.pt_xs,
93 a.font_medium,
94 a.text_md,
95 a.leading_snug,
96 a.text_center,
97 a.self_center,
98 !button && a.mb_5xl,
99 textStyle,
100 ]}>
101 {message}
102 </Text>
103 {button && (
104 <View style={[a.flex_shrink, a.mt_xl, a.self_center, a.mb_5xl]}>
105 <Button {...button}>
106 <ButtonText>{button.text}</ButtonText>
107 </Button>
108 </View>
109 )}
110 </View>
111 )
112}