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