Bluesky app fork with some witchin' additions 馃挮 witchsky.app
bluesky fork client
119
fork

Configure Feed

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

at a876aae44ea07494ebea9727350aa060b81f317b 150 lines 3.4 kB view raw
1import {createContext, useContext} from 'react' 2import {type StyleProp, View, type ViewStyle} from 'react-native' 3 4import {atoms as a, useBreakpoints, useTheme} from '#/alf' 5import {Button as BaseButton, type ButtonProps} from '#/components/Button' 6import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfoIcon} from '#/components/icons/CircleInfo' 7import {CircleX_Stroke2_Corner0_Rounded as CircleXIcon} from '#/components/icons/CircleX' 8import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' 9import {Text as BaseText, type TextProps} from '#/components/Typography' 10import {EmojiSad_Stroke2_Corner0_Rounded as EmojiSadIcon} from './icons/Emoji' 11 12type Context = { 13 type: 'info' | 'tip' | 'warning' | 'error' | 'apology' 14} 15 16const Context = createContext<Context>({ 17 type: 'info', 18}) 19Context.displayName = 'AdmonitionContext' 20 21export function Icon() { 22 const t = useTheme() 23 const {type} = useContext(Context) 24 const Icon = { 25 info: CircleInfoIcon, 26 tip: CircleInfoIcon, 27 warning: WarningIcon, 28 error: CircleXIcon, 29 apology: EmojiSadIcon, 30 }[type] 31 const fill = { 32 info: t.atoms.text_contrast_medium.color, 33 tip: t.palette.primary_500, 34 warning: t.palette.yellow, 35 error: t.palette.negative_500, 36 apology: t.atoms.text_contrast_medium.color, 37 }[type] 38 return <Icon fill={fill} size="md" /> 39} 40 41export function Content({ 42 children, 43 style, 44 ...rest 45}: { 46 children: React.ReactNode 47 style?: StyleProp<ViewStyle> 48}) { 49 return ( 50 <View 51 style={[a.gap_sm, a.flex_1, {minHeight: 20}, a.justify_center, style]} 52 {...rest}> 53 {children} 54 </View> 55 ) 56} 57 58export function Text({ 59 children, 60 style, 61 ...rest 62}: Pick<TextProps, 'children' | 'style'>) { 63 return ( 64 <BaseText {...rest} style={[a.text_sm, a.leading_snug, a.pr_md, style]}> 65 {children} 66 </BaseText> 67 ) 68} 69 70export function Button({ 71 children, 72 ...props 73}: Omit<ButtonProps, 'size' | 'variant'>) { 74 return ( 75 <BaseButton size="tiny" {...props}> 76 {children} 77 </BaseButton> 78 ) 79} 80 81export function Row({ 82 children, 83 style, 84}: { 85 children: React.ReactNode 86 style?: StyleProp<ViewStyle> 87}) { 88 return ( 89 <View style={[a.w_full, a.flex_row, a.align_start, a.gap_sm, style]}> 90 {children} 91 </View> 92 ) 93} 94 95export function Outer({ 96 children, 97 type = 'info', 98 style, 99}: { 100 children: React.ReactNode 101 type?: Context['type'] 102 style?: StyleProp<ViewStyle> 103}) { 104 const t = useTheme() 105 const {gtMobile} = useBreakpoints() 106 const borderColor = { 107 info: t.atoms.border_contrast_high.borderColor, 108 tip: t.palette.primary_500, 109 warning: t.palette.yellow, 110 error: t.palette.negative_500, 111 apology: t.atoms.border_contrast_high.borderColor, 112 }[type] 113 return ( 114 <Context.Provider value={{type}}> 115 <View 116 style={[ 117 gtMobile ? a.p_md : a.p_sm, 118 a.p_md, 119 a.rounded_sm, 120 a.border, 121 t.atoms.bg, 122 {borderColor}, 123 style, 124 ]}> 125 {children} 126 </View> 127 </Context.Provider> 128 ) 129} 130 131export function Admonition({ 132 children, 133 type, 134 style, 135}: { 136 children: TextProps['children'] 137 type?: Context['type'] 138 style?: StyleProp<ViewStyle> 139}) { 140 return ( 141 <Outer type={type} style={style}> 142 <Row> 143 <Icon /> 144 <Content> 145 <Text>{children}</Text> 146 </Content> 147 </Row> 148 </Outer> 149 ) 150}