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 120 lines 2.8 kB view raw
1import {createContext, useContext} from 'react' 2import {View, type ViewStyle} from 'react-native' 3 4import {atoms as a, tokens, useTheme} from '#/alf' 5import {type Props as SVGIconProps} from '#/components/icons/common' 6import {Text} from '#/components/Typography' 7 8const PanelContext = createContext<{active: boolean}>({active: false}) 9 10/** 11 * A nice container for Toggles. See the Threadgate dialog for an example. 12 */ 13export function Panel({ 14 children, 15 active = false, 16 adjacent, 17}: { 18 children: React.ReactNode 19 active?: boolean 20 adjacent?: 'leading' | 'trailing' | 'both' 21}) { 22 const t = useTheme() 23 24 const leading = adjacent === 'leading' || adjacent === 'both' 25 const trailing = adjacent === 'trailing' || adjacent === 'both' 26 const rounding = { 27 borderTopLeftRadius: leading 28 ? tokens.borderRadius.xs 29 : tokens.borderRadius.md, 30 borderTopRightRadius: leading 31 ? tokens.borderRadius.xs 32 : tokens.borderRadius.md, 33 borderBottomLeftRadius: trailing 34 ? tokens.borderRadius.xs 35 : tokens.borderRadius.md, 36 borderBottomRightRadius: trailing 37 ? tokens.borderRadius.xs 38 : tokens.borderRadius.md, 39 } satisfies ViewStyle 40 41 return ( 42 <View 43 style={[ 44 a.w_full, 45 a.flex_row, 46 a.align_center, 47 a.gap_sm, 48 a.px_md, 49 a.py_md, 50 {minHeight: tokens.space._2xl + tokens.space.md * 2}, 51 rounding, 52 active 53 ? {backgroundColor: t.palette.primary_50} 54 : t.atoms.bg_contrast_50, 55 ]}> 56 <PanelContext value={{active}}>{children}</PanelContext> 57 </View> 58 ) 59} 60 61export function PanelText({ 62 children, 63 icon, 64}: { 65 children: React.ReactNode 66 icon?: React.ComponentType<SVGIconProps> 67}) { 68 const t = useTheme() 69 const ctx = useContext(PanelContext) 70 71 const text = ( 72 <Text 73 style={[ 74 a.text_md, 75 a.flex_1, 76 ctx.active 77 ? [a.font_medium, t.atoms.text] 78 : [t.atoms.text_contrast_medium], 79 ]}> 80 {children} 81 </Text> 82 ) 83 84 if (icon) { 85 // eslint-disable-next-line bsky-internal/avoid-unwrapped-text 86 return ( 87 <View style={[a.flex_row, a.align_center, a.gap_xs, a.flex_1]}> 88 <PanelIcon icon={icon} /> 89 {text} 90 </View> 91 ) 92 } 93 94 return text 95} 96 97export function PanelIcon({ 98 icon: Icon, 99}: { 100 icon: React.ComponentType<SVGIconProps> 101}) { 102 const t = useTheme() 103 const ctx = useContext(PanelContext) 104 return ( 105 <Icon 106 style={[ 107 ctx.active ? t.atoms.text : t.atoms.text_contrast_medium, 108 a.flex_shrink_0, 109 ]} 110 size="md" 111 /> 112 ) 113} 114 115/** 116 * A group of panels. TODO: auto-leading/trailing 117 */ 118export function PanelGroup({children}: {children: React.ReactNode}) { 119 return <View style={[a.w_full, a.gap_2xs]}>{children}</View> 120}