Update admonition component (#9068)

* update admonition component

* fix linting, adominition alighment

* design tweak

* edge cases for admonition, update storybook

* Update src/components/Admonition.tsx

Co-authored-by: Samuel Newman <mozzius@protonmail.com>

* fix mobile version

* change button style

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
This commit is contained in:
Chenyu
2025-09-30 05:27:19 -07:00
committed by GitHub
parent c7ce827bfe
commit f82a6188e6
7 changed files with 130 additions and 37 deletions
+44 -24
View File
@@ -3,17 +3,13 @@ import {type StyleProp, View, type ViewStyle} from 'react-native'
import {atoms as a, useBreakpoints, useTheme} from '#/alf' import {atoms as a, useBreakpoints, useTheme} from '#/alf'
import {Button as BaseButton, type ButtonProps} from '#/components/Button' import {Button as BaseButton, type ButtonProps} from '#/components/Button'
import {CircleInfo_Stroke2_Corner0_Rounded as ErrorIcon} from '#/components/icons/CircleInfo' import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfoIcon} from '#/components/icons/CircleInfo'
import {Eye_Stroke2_Corner0_Rounded as InfoIcon} from '#/components/icons/Eye' import {CircleX_Stroke2_Corner0_Rounded as CircleXIcon} from '#/components/icons/CircleX'
import {Leaf_Stroke2_Corner0_Rounded as TipIcon} from '#/components/icons/Leaf'
import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning'
import {Text as BaseText, type TextProps} from '#/components/Typography' import {Text as BaseText, type TextProps} from '#/components/Typography'
export const colors = { export const colors = {
warning: { warning: '#FFC404',
light: '#DFBC00',
dark: '#BFAF1F',
},
} }
type Context = { type Context = {
@@ -29,29 +25,44 @@ export function Icon() {
const t = useTheme() const t = useTheme()
const {type} = useContext(Context) const {type} = useContext(Context)
const Icon = { const Icon = {
info: InfoIcon, info: CircleInfoIcon,
tip: TipIcon, tip: CircleInfoIcon,
warning: WarningIcon, warning: WarningIcon,
error: ErrorIcon, error: CircleXIcon,
}[type] }[type]
const fill = { const fill = {
info: t.atoms.text_contrast_medium.color, info: t.atoms.text_contrast_medium.color,
tip: t.palette.primary_500, tip: t.palette.primary_500,
warning: colors.warning.light, warning: colors.warning,
error: t.palette.negative_500, error: t.palette.negative_500,
}[type] }[type]
return <Icon fill={fill} size="md" /> return <Icon fill={fill} size="md" />
} }
export function Content({
children,
style,
...rest
}: {
children: React.ReactNode
style?: StyleProp<ViewStyle>
}) {
return (
<View
style={[a.gap_sm, a.flex_1, {minHeight: 20}, a.justify_center, style]}
{...rest}>
{children}
</View>
)
}
export function Text({ export function Text({
children, children,
style, style,
...rest ...rest
}: Pick<TextProps, 'children' | 'style'>) { }: Pick<TextProps, 'children' | 'style'>) {
return ( return (
<BaseText <BaseText {...rest} style={[a.text_sm, a.leading_snug, a.pr_md, style]}>
{...rest}
style={[a.flex_1, a.text_sm, a.leading_snug, a.pr_md, style]}>
{children} {children}
</BaseText> </BaseText>
) )
@@ -60,17 +71,23 @@ export function Text({
export function Button({ export function Button({
children, children,
...props ...props
}: Omit<ButtonProps, 'size' | 'variant' | 'color'>) { }: Omit<ButtonProps, 'size' | 'variant'>) {
return ( return (
<BaseButton size="tiny" variant="outline" color="secondary" {...props}> <BaseButton size="tiny" {...props}>
{children} {children}
</BaseButton> </BaseButton>
) )
} }
export function Row({children}: {children: React.ReactNode}) { export function Row({
children,
style,
}: {
children: React.ReactNode
style?: StyleProp<ViewStyle>
}) {
return ( return (
<View style={[a.flex_1, a.flex_row, a.align_center, a.gap_sm]}> <View style={[a.flex_1, a.flex_row, a.align_start, a.gap_sm, style]}>
{children} {children}
</View> </View>
) )
@@ -88,19 +105,20 @@ export function Outer({
const t = useTheme() const t = useTheme()
const {gtMobile} = useBreakpoints() const {gtMobile} = useBreakpoints()
const borderColor = { const borderColor = {
info: t.atoms.border_contrast_low.borderColor, info: t.atoms.border_contrast_high.borderColor,
tip: t.atoms.border_contrast_low.borderColor, tip: t.palette.primary_500,
warning: t.atoms.border_contrast_low.borderColor, warning: colors.warning,
error: t.atoms.border_contrast_low.borderColor, error: t.palette.negative_500,
}[type] }[type]
return ( return (
<Context.Provider value={{type}}> <Context.Provider value={{type}}>
<View <View
style={[ style={[
gtMobile ? a.p_md : a.p_sm, gtMobile ? a.p_md : a.p_sm,
a.p_md,
a.rounded_sm, a.rounded_sm,
a.border, a.border,
t.atoms.bg_contrast_25, t.atoms.bg,
{borderColor}, {borderColor},
style, style,
]}> ]}>
@@ -123,7 +141,9 @@ export function Admonition({
<Outer type={type} style={style}> <Outer type={type} style={style}>
<Row> <Row>
<Icon /> <Icon />
<Text>{children}</Text> <Content>
<Text>{children}</Text>
</Content>
</Row> </Row>
</Outer> </Outer>
) )
@@ -219,10 +219,13 @@ function Inner(props: ReportDialogProps) {
<Admonition.Outer type="error"> <Admonition.Outer type="error">
<Admonition.Row> <Admonition.Row>
<Admonition.Icon /> <Admonition.Icon />
<Admonition.Text> <Admonition.Content>
<Trans>Something went wrong, please try again</Trans> <Admonition.Text>
</Admonition.Text> <Trans>Something went wrong, please try again</Trans>
</Admonition.Text>
</Admonition.Content>
<Admonition.Button <Admonition.Button
color="negative_subtle"
label={_(msg`Retry loading report options`)} label={_(msg`Retry loading report options`)}
onPress={() => refetchLabelers()}> onPress={() => refetchLabelers()}>
<ButtonText> <ButtonText>
@@ -621,7 +621,7 @@ function BackdatedPostIndicator({post}: {post: AppBskyFeedDefs.PostView}) {
if (!isBackdated) return null if (!isBackdated) return null
const orange = t.name === 'light' ? colors.warning.dark : colors.warning.light const orange = colors.warning
return ( return (
<> <>
+1 -1
View File
@@ -195,7 +195,7 @@ function AppPasswordCard({
</View> </View>
{appPassword.privileged && ( {appPassword.privileged && (
<View style={[a.flex_row, a.gap_sm, a.align_center, a.mt_md]}> <View style={[a.flex_row, a.gap_sm, a.align_center, a.mt_md]}>
<WarningIcon style={[{color: colors.warning[t.scheme]}]} /> <WarningIcon style={[{color: colors.warning}]} />
<Text style={t.atoms.text_contrast_high}> <Text style={t.atoms.text_contrast_high}>
<Trans>Allows access to direct messages</Trans> <Trans>Allows access to direct messages</Trans>
</Text> </Text>
@@ -134,7 +134,7 @@ export function ActivityNotificationSettingsScreen({}: Props) {
<Admonition.Outer type="tip"> <Admonition.Outer type="tip">
<Admonition.Row> <Admonition.Row>
<Admonition.Icon /> <Admonition.Icon />
<View style={[a.flex_1, a.gap_sm]}> <Admonition.Content>
<Admonition.Text> <Admonition.Text>
<Trans> <Trans>
Enable notifications for an account by visiting their Enable notifications for an account by visiting their
@@ -166,7 +166,7 @@ export function ActivityNotificationSettingsScreen({}: Props) {
. .
</Trans> </Trans>
</Admonition.Text> </Admonition.Text>
</View> </Admonition.Content>
</Admonition.Row> </Admonition.Row>
</Admonition.Outer> </Admonition.Outer>
) : ( ) : (
@@ -1,4 +1,3 @@
import {View} from 'react-native'
import {type AppBskyNotificationDeclaration} from '@atproto/api' import {type AppBskyNotificationDeclaration} from '@atproto/api'
import {msg, Trans} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
@@ -112,7 +111,7 @@ export function PrivacyAndSecuritySettingsScreen({}: Props) {
<Admonition.Outer type="tip" style={[a.flex_1]}> <Admonition.Outer type="tip" style={[a.flex_1]}>
<Admonition.Row> <Admonition.Row>
<Admonition.Icon /> <Admonition.Icon />
<View style={[a.flex_1, a.gap_sm]}> <Admonition.Content>
<Admonition.Text> <Admonition.Text>
<Trans> <Trans>
Note: Bluesky is an open and public network. This setting Note: Bluesky is an open and public network. This setting
@@ -131,7 +130,7 @@ export function PrivacyAndSecuritySettingsScreen({}: Props) {
<Trans>Learn more about what is public on Bluesky.</Trans> <Trans>Learn more about what is public on Bluesky.</Trans>
</InlineLinkText> </InlineLinkText>
</Admonition.Text> </Admonition.Text>
</View> </Admonition.Content>
</Admonition.Row> </Admonition.Row>
</Admonition.Outer> </Admonition.Outer>
</SettingsList.Item> </SettingsList.Item>
+74 -3
View File
@@ -1,11 +1,27 @@
import {View} from 'react-native' import {Text as RNText, View} from 'react-native'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {atoms as a} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {Admonition} from '#/components/Admonition' import {
Admonition,
Button as AdmonitionButton,
Content as AdmonitionContent,
Icon as AdmonitionIcon,
Outer as AdmonitionOuter,
Row as AdmonitionRow,
Text as AdmonitionText,
} from '#/components/Admonition'
import {ButtonIcon, ButtonText} from '#/components/Button'
import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as Retry} from '#/components/icons/ArrowRotateCounterClockwise'
import {BellRinging_Filled_Corner0_Rounded as BellRingingFilledIcon} from '#/components/icons/BellRinging'
import {InlineLinkText} from '#/components/Link' import {InlineLinkText} from '#/components/Link'
import {H1} from '#/components/Typography' import {H1} from '#/components/Typography'
export function Admonitions() { export function Admonitions() {
const {_} = useLingui()
const t = useTheme()
return ( return (
<View style={[a.gap_md]}> <View style={[a.gap_md]}>
<H1>Admonitions</H1> <H1>Admonitions</H1>
@@ -30,6 +46,61 @@ export function Admonitions() {
<Admonition type="error"> <Admonition type="error">
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.
</Admonition> </Admonition>
<AdmonitionOuter type="error">
<AdmonitionRow>
<AdmonitionIcon />
<AdmonitionContent>
<AdmonitionText>
<Trans>Something went wrong, please try again</Trans>
</AdmonitionText>
</AdmonitionContent>
<AdmonitionButton
color="negative_subtle"
label={_(msg`Retry loading report options`)}
onPress={() => {}}>
<ButtonText>
<Trans>Retry</Trans>
</ButtonText>
<ButtonIcon icon={Retry} />
</AdmonitionButton>
</AdmonitionRow>
</AdmonitionOuter>
<AdmonitionOuter type="tip">
<AdmonitionRow>
<AdmonitionIcon />
<AdmonitionContent>
<AdmonitionText>
<Trans>
Enable notifications for an account by visiting their profile
and pressing the{' '}
<RNText style={[a.font_bold, t.atoms.text_contrast_high]}>
bell icon
</RNText>{' '}
<BellRingingFilledIcon
size="xs"
style={t.atoms.text_contrast_high}
/>
.
</Trans>
</AdmonitionText>
<AdmonitionText>
<Trans>
If you want to restrict who can receive notifications for your
account's activity, you can change this in{' '}
<InlineLinkText
label={_(msg`Privacy and Security settings`)}
to={{screen: 'ActivityPrivacySettings'}}
style={[a.font_bold]}>
Settings &rarr; Privacy and Security
</InlineLinkText>
.
</Trans>
</AdmonitionText>
</AdmonitionContent>
</AdmonitionRow>
</AdmonitionOuter>
</View> </View>
) )
} }