Hook up data

This commit is contained in:
Eric Bailey
2024-02-14 19:05:37 -06:00
parent cc635ae949
commit 7313e70ca7
12 changed files with 751 additions and 391 deletions
+27 -18
View File
@@ -48,25 +48,30 @@ export type VariantProps = {
shape?: ButtonShape
}
export type ButtonProps = React.PropsWithChildren<
Pick<PressableProps, 'disabled' | 'onPress' | 'testID'> &
AccessibilityProps &
VariantProps & {
testID?: string
label: string
style?: StyleProp<ViewStyle>
}
>
export type ButtonState = {
hovered: boolean
focused: boolean
pressed: boolean
disabled: boolean
}
export type ButtonProps = Pick<
PressableProps,
'disabled' | 'onPress' | 'testID'
> &
AccessibilityProps &
VariantProps & {
testID?: string
label: string
style?: StyleProp<ViewStyle>
children:
| React.ReactNode
| string
| ((state: VariantProps & ButtonState) => React.ReactNode | string)
}
export type ButtonTextProps = TextProps & VariantProps & {disabled?: boolean}
const Context = React.createContext<
VariantProps & {
hovered: boolean
focused: boolean
pressed: boolean
disabled: boolean
}
>({
const Context = React.createContext<VariantProps & ButtonState>({
hovered: false,
focused: false,
pressed: false,
@@ -394,6 +399,8 @@ export function Button({
<Context.Provider value={context}>
{typeof children === 'string' ? (
<ButtonText>{children}</ButtonText>
) : typeof children === 'function' ? (
children(context)
) : (
children
)}
@@ -514,9 +521,11 @@ export function ButtonText({children, style, ...rest}: ButtonTextProps) {
export function ButtonIcon({
icon: Comp,
position,
size: iconSize,
}: {
icon: React.ComponentType<SVGIconProps>
position?: 'left' | 'right'
size?: SVGIconProps['size']
}) {
const {size, disabled} = useButtonContext()
const textStyles = useSharedButtonTextStyles()
@@ -532,7 +541,7 @@ export function ButtonIcon({
},
]}>
<Comp
size={size === 'large' ? 'md' : 'sm'}
size={iconSize ?? (size === 'large' ? 'md' : 'sm')}
style={[{color: textStyles.color, pointerEvents: 'none'}]}
/>
</View>
+27 -22
View File
@@ -10,6 +10,8 @@ import {Portal} from '#/components/Portal'
import {DialogOuterProps, DialogInnerProps} from '#/components/Dialog/types'
import {Context} from '#/components/Dialog/context'
import {Button, ButtonIcon} from '#/components/Button'
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
export {useDialogControl, useDialogContext} from '#/components/Dialog/context'
export * from '#/components/Dialog/types'
@@ -171,25 +173,28 @@ export function Handle() {
return null
}
/**
* TODO(eric) unused rn
*/
// export function Close() {
// const {_} = useLingui()
// const t = useTheme()
// const {close} = useDialogContext()
// return (
// <View
// style={[
// a.absolute,
// a.z_10,
// {
// top: a.pt_lg.paddingTop,
// right: a.pr_lg.paddingRight,
// },
// ]}>
// <Button onPress={close} label={_(msg`Close active dialog`)}>
// </Button>
// </View>
// )
// }
export function Close() {
const {_} = useLingui()
const {close} = React.useContext(Context)
return (
<View
style={[
a.absolute,
a.z_10,
{
top: a.pt_md.paddingTop,
right: a.pr_md.paddingRight,
},
]}>
<Button
size="small"
variant="ghost"
color="primary"
shape="round"
onPress={close}
label={_(msg`Close active dialog`)}>
<ButtonIcon icon={X} size="md" />
</Button>
</View>
)
}
-133
View File
@@ -1,133 +0,0 @@
import React from 'react'
import {View} from 'react-native'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import LinearGradient from 'react-native-linear-gradient'
import {AppBskyModerationDefs} from '@atproto/api'
import {atoms as a, useTheme, tokens, web} from '#/alf'
import {Link, useLinkContext} from '#/components/Link'
import {Text} from '#/components/Typography'
import {RichText} from '#/components/RichText'
import {RaisingHande4Finger_Stroke2_Corner0_Rounded as RaisingHand} from '#/components/icons/RaisingHand'
import {useModServiceInfoQuery} from '#/state/queries/modservice'
type ModerationServiceCardProps = {
modservice: AppBskyModerationDefs.ModServiceViewDetailed
}
export function ModerationServiceCard({
modservice,
}: ModerationServiceCardProps) {
const {_} = useLingui()
return (
<Link
to={{
screen: 'ProfileModservice',
params: {
name: modservice.creator.handle,
},
}}
label={_(
msg`View the moderation service provided by @${modservice.creator.handle}`,
)}>
<Inner modservice={modservice} />
</Link>
)
}
function Inner({modservice}: ModerationServiceCardProps) {
const t = useTheme()
const {hovered, pressed, focused} = useLinkContext()
return (
<View
style={[
a.flex_row,
a.align_center,
a.justify_between,
a.gap_sm,
a.w_full,
a.rounded_sm,
a.pt_md,
a.pb_sm,
a.pl_lg,
a.pr_sm,
a.overflow_hidden,
web({
transition: 'transform 0.2s cubic-bezier(.02,.73,.27,.99)',
}),
{
transform: [{scale: pressed || hovered || focused ? 0.992 : 1}],
},
]}>
<LinearGradient
colors={tokens.gradients.midnight.values.map(c => c[1])}
locations={tokens.gradients.midnight.values.map(c => c[0])}
start={{x: 0, y: 0}}
end={{x: 1, y: 1}}
style={[a.absolute, a.inset_0]}
/>
<View style={[a.z_10]}>
<Text
style={[a.text_md, a.font_bold, a.pb_2xs, {color: t.palette.white}]}>
{/* TODO */}
{modservice.displayName || 'Mod service'}
</Text>
{modservice.description ? (
<RichText
value={modservice.description}
style={[{color: t.palette.white}]}
/>
) : (
<Text>
<Trans>
Moderation service managed by @{modservice.creator.handle}
</Trans>
</Text>
)}
</View>
<RaisingHand size="xl" style={[a.z_10]} fill={t.palette.white} />
</View>
)
}
export function ModerationServiceCardSkeleton() {
return (
<View>
<Text>Loading</Text>
</View>
)
}
export function Loader({
did,
loading: LoadingComponent = ModerationServiceCardSkeleton,
error: ErrorComponent,
component: Component,
}: {
did: string
loading?: React.ComponentType<{}>
error?: React.ComponentType<{error: string}>
component: React.ComponentType<{
modservice: AppBskyModerationDefs.ModServiceViewDetailed
}>
}) {
const {isLoading, data, error} = useModServiceInfoQuery({did})
return isLoading ? (
LoadingComponent ? (
<LoadingComponent />
) : null
) : error || !data ? (
ErrorComponent ? (
<ErrorComponent error={error?.message || 'Unknown error'} />
) : null
) : (
<Component modservice={data} />
)
}
@@ -0,0 +1,74 @@
import React from 'react'
import {View} from 'react-native'
import {Trans} from '@lingui/macro'
import {atoms as a, useTheme, ViewStyleProp, flatten} from '#/alf'
import {Text} from '#/components/Typography'
import {RichText} from '#/components/RichText'
import {RaisingHande4Finger_Stroke2_Corner0_Rounded as RaisingHand} from '#/components/icons/RaisingHand'
import {UserAvatar} from '#/view/com/util/UserAvatar'
export function Outer({
children,
style,
}: React.PropsWithChildren<ViewStyleProp>) {
const t = useTheme()
return (
<View
style={[
a.flex_row,
a.align_center,
a.gap_sm,
a.w_full,
a.rounded_sm,
a.pt_md,
a.pb_md,
a.pl_md,
a.pr_md,
a.overflow_hidden,
a.border,
t.atoms.border_contrast_low,
t.atoms.bg_contrast_25,
flatten(style),
]}>
<View style={[a.flex_row, a.align_center, a.w_full, a.gap_md]}>
{children}
</View>
</View>
)
}
export function Avatar({avatar}: {avatar?: string}) {
return <UserAvatar type="list" size={40} avatar={avatar} />
}
export function Content({
title,
description,
handle,
}: {
title: string
description?: string
handle: string
}) {
const t = useTheme()
return (
<View style={[a.flex_1, a.flex_row, a.align_center, a.justify_between]}>
<View>
<Text style={[a.text_md, a.font_bold, a.pb_2xs]}>{title}</Text>
{description ? (
<RichText value={description} style={[]} />
) : (
<Text>
<Trans>Moderation service managed by @{handle}</Trans>
</Text>
)}
</View>
<RaisingHand size="xl" style={[a.z_10]} fill={t.palette.primary_500} />
</View>
)
}
@@ -0,0 +1,73 @@
import React from 'react'
import {View} from 'react-native'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {AppBskyModerationDefs} from '@atproto/api'
import {Link as InternalLink, LinkProps} from '#/components/Link'
import {Text} from '#/components/Typography'
import {useModServiceInfoQuery} from '#/state/queries/modservice'
export * as Card from '#/components/ModerationServiceCard/Card'
type ModerationServiceProps = {
modservice: AppBskyModerationDefs.ModServiceViewDetailed
}
export function Link({
children,
modservice,
}: ModerationServiceProps & Pick<LinkProps, 'children'>) {
const {_} = useLingui()
return (
<InternalLink
to={{
screen: 'ProfileModservice',
params: {
name: modservice.creator.handle,
},
}}
label={_(
msg`View the moderation service provided by @${modservice.creator.handle}`,
)}>
{children}
</InternalLink>
)
}
export function ModerationServiceCardSkeleton() {
return (
<View>
<Text>Loading</Text>
</View>
)
}
export function Loader({
did,
loading: LoadingComponent = ModerationServiceCardSkeleton,
error: ErrorComponent,
component: Component,
}: {
did: string
loading?: React.ComponentType<{}>
error?: React.ComponentType<{error: string}>
component: React.ComponentType<{
modservice: AppBskyModerationDefs.ModServiceViewDetailed
}>
}) {
const {isLoading, data, error} = useModServiceInfoQuery({did})
return isLoading ? (
LoadingComponent ? (
<LoadingComponent />
) : null
) : error || !data ? (
ErrorComponent ? (
<ErrorComponent error={error?.message || 'Unknown error'} />
) : null
) : (
<Component modservice={data} />
)
}
+5
View File
@@ -0,0 +1,5 @@
import {createSinglePathSVG} from './TEMPLATE'
export const TimesLarge_Stroke2_Corner0_Rounded = createSinglePathSVG({
path: 'M4.293 4.293a1 1 0 0 1 1.414 0L12 10.586l6.293-6.293a1 1 0 1 1 1.414 1.414L13.414 12l6.293 6.293a1 1 0 0 1-1.414 1.414L12 13.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L10.586 12 4.293 5.707a1 1 0 0 1 0-1.414Z',
})