diff options
-rw-r--r-- | .eslintrc.js | 11 | ||||
-rw-r--r-- | src/components/Admonition.tsx | 118 | ||||
-rw-r--r-- | src/view/screens/Storybook/Admonitions.tsx | 36 | ||||
-rw-r--r-- | src/view/screens/Storybook/index.tsx | 4 |
4 files changed, 167 insertions, 2 deletions
diff --git a/.eslintrc.js b/.eslintrc.js index f6407fa6f..66e75d485 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -23,7 +23,16 @@ module.exports = { 'bsky-internal/avoid-unwrapped-text': [ 'error', { - impliedTextComponents: ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'P'], + impliedTextComponents: [ + 'H1', + 'H2', + 'H3', + 'H4', + 'H5', + 'H6', + 'P', + 'Admonition', + ], impliedTextProps: [], suggestedTextWrappers: { Button: 'ButtonText', diff --git a/src/components/Admonition.tsx b/src/components/Admonition.tsx new file mode 100644 index 000000000..7c8682119 --- /dev/null +++ b/src/components/Admonition.tsx @@ -0,0 +1,118 @@ +import React from 'react' +import {View} from 'react-native' + +import {atoms as a, useBreakpoints, useTheme} from '#/alf' +import {CircleInfo_Stroke2_Corner0_Rounded as ErrorIcon} from '#/components/icons/CircleInfo' +import {Eye_Stroke2_Corner0_Rounded as InfoIcon} from '#/components/icons/Eye' +import {Leaf_Stroke2_Corner0_Rounded as TipIcon} from '#/components/icons/Leaf' +import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' +import {Text as BaseText, TextProps} from '#/components/Typography' + +const colors = { + warning: { + light: '#DFBC00', + dark: '#BFAF1F', + }, +} + +type Context = { + type: 'info' | 'tip' | 'warning' | 'error' +} + +const Context = React.createContext<Context>({ + type: 'info', +}) + +export function Icon() { + const t = useTheme() + const {type} = React.useContext(Context) + const Icon = { + info: InfoIcon, + tip: TipIcon, + warning: WarningIcon, + error: ErrorIcon, + }[type] + const fill = { + info: t.atoms.text_contrast_medium.color, + tip: t.palette.primary_500, + warning: colors.warning.light, + error: t.palette.negative_500, + }[type] + return <Icon fill={fill} size="md" /> +} + +export function Text({ + children, + style, + ...rest +}: Pick<TextProps, 'children' | 'style'>) { + return ( + <BaseText + {...rest} + style={[ + a.flex_1, + a.text_sm, + a.leading_snug, + { + paddingTop: 1, + }, + style, + ]}> + {children} + </BaseText> + ) +} + +export function Row({children}: {children: React.ReactNode}) { + return <View style={[a.flex_row, a.gap_sm]}>{children}</View> +} + +export function Outer({ + children, + type = 'info', +}: { + children: React.ReactNode + type?: Context['type'] +}) { + const t = useTheme() + const {gtMobile} = useBreakpoints() + const borderColor = { + info: t.atoms.border_contrast_low.borderColor, + tip: t.atoms.border_contrast_low.borderColor, + warning: t.atoms.border_contrast_low.borderColor, + error: t.atoms.border_contrast_low.borderColor, + }[type] + return ( + <Context.Provider value={{type}}> + <View + style={[ + gtMobile ? a.p_md : a.p_sm, + a.rounded_sm, + a.border, + t.atoms.bg_contrast_25, + { + borderColor, + }, + ]}> + {children} + </View> + </Context.Provider> + ) +} + +export function Admonition({ + children, + type, +}: { + children: TextProps['children'] + type?: Context['type'] +}) { + return ( + <Outer type={type}> + <Row> + <Icon /> + <Text>{children}</Text> + </Row> + </Outer> + ) +} diff --git a/src/view/screens/Storybook/Admonitions.tsx b/src/view/screens/Storybook/Admonitions.tsx new file mode 100644 index 000000000..ca97ebb23 --- /dev/null +++ b/src/view/screens/Storybook/Admonitions.tsx @@ -0,0 +1,36 @@ +import React from 'react' +import {View} from 'react-native' + +import {atoms as a} from '#/alf' +import {Admonition} from '#/components/Admonition' +import {InlineLinkText} from '#/components/Link' +import {H1} from '#/components/Typography' + +export function Admonitions() { + return ( + <View style={[a.gap_md]}> + <H1>Admonitions</H1> + + <Admonition>The quick brown fox jumps over the lazy dog.</Admonition> + <Admonition type="info"> + How happy the blameless vestal's lot, the world forgetting by the world + forgot.{' '} + <InlineLinkText + label="test" + to="https://letterboxd.com/film/eternal-sunshine-of-the-spotless-mind/"> + Eternal sunshine of the spotless mind + </InlineLinkText> + ! Each pray'r accepted, and each wish resign'd. + </Admonition> + <Admonition type="tip"> + The quick brown fox jumps over the lazy dog. + </Admonition> + <Admonition type="warning"> + The quick brown fox jumps over the lazy dog. + </Admonition> + <Admonition type="error"> + The quick brown fox jumps over the lazy dog. + </Admonition> + </View> + ) +} diff --git a/src/view/screens/Storybook/index.tsx b/src/view/screens/Storybook/index.tsx index ec6bab13e..c737dad5b 100644 --- a/src/view/screens/Storybook/index.tsx +++ b/src/view/screens/Storybook/index.tsx @@ -7,6 +7,7 @@ import {CenteredView} from '#/view/com/util/Views' import {ListContained} from '#/view/screens/Storybook/ListContained' import {atoms as a, ThemeProvider, useTheme} from '#/alf' import {Button, ButtonText} from '#/components/Button' +import {Admonitions} from './Admonitions' import {Breakpoints} from './Breakpoints' import {Buttons} from './Buttons' import {Dialogs} from './Dialogs' @@ -80,7 +81,7 @@ function StorybookInner() { </Button> </View> - <Forms /> + <Admonitions /> <ThemeProvider theme="light"> <Theming /> @@ -92,6 +93,7 @@ function StorybookInner() { <Theming /> </ThemeProvider> + <Forms /> <Buttons /> <Typography /> <Spacing /> |