mattermost-mobile/app/components/section_notice/index.tsx
Daniel Espino García 1d8568ade8
Improve markdown code (#9164)
* Improve markdown code

* Add missing changes

* Simplify style composition

* Address feedback

* Fix color issue introduced by channel banner
2025-11-04 10:05:56 +01:00

263 lines
8.1 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useMemo} from 'react';
import {Pressable, Text, View} from 'react-native';
import Tag from '@components/tag';
import {useTheme} from '@context/theme';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';
import CompassIcon from '../compass_icon';
import Markdown from '../markdown';
import SectionNoticeButton from './section_notice_button';
import type {AvailableScreens} from '@typings/screens/navigation';
type Props = {
title: string;
text?: string;
primaryButton?: SectionNoticeButtonProps;
secondaryButton?: SectionNoticeButtonProps;
linkButton?: SectionNoticeButtonProps;
type?: 'info' | 'success' | 'danger' | 'welcome' | 'warning' | 'hint';
isDismissable?: boolean;
onDismissClick?: () => void;
location: AvailableScreens;
tags?: string[];
testID?: string;
squareCorners?: boolean;
}
const iconByType = {
info: 'information-outline',
hint: 'lightbulb-outline',
success: 'check',
danger: 'alert-outline',
warning: 'alert-outline',
welcome: undefined,
};
const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
return {
container: {
borderWidth: 1,
borderStyle: 'solid',
},
roundCorners: {
borderRadius: 4,
},
content: {
flexDirection: 'row',
alignItems: 'flex-start',
padding: 16,
gap: 12,
},
body: {
flexDirection: 'column',
gap: 8,
flex: 1,
},
actions: {
marginTop: 8,
gap: 8,
},
title: {
margin: 0,
color: theme.centerChannelColor,
...typography('Body', 100, 'SemiBold'),
},
welcomeTitle: {
margin: 0,
color: theme.centerChannelColor,
...typography('Heading', 400, 'SemiBold'),
},
baseText: {
color: theme.centerChannelColor,
...typography('Body', 100, 'Regular'),
},
infoText: {
color: theme.centerChannelColor,
},
infoIcon: {
color: theme.sidebarTextActiveBorder,
},
infoContainer: {
borderColor: changeOpacity(theme.sidebarTextActiveBorder, 0.16),
backgroundColor: changeOpacity(theme.sidebarTextActiveBorder, 0.08),
},
successText: {
color: theme.centerChannelColor,
},
successIcon: {
color: theme.onlineIndicator,
},
successContainer: {
borderColor: changeOpacity(theme.onlineIndicator, 0.16),
backgroundColor: changeOpacity(theme.onlineIndicator, 0.08),
},
dangerText: {
color: theme.dndIndicator,
},
dangerIcon: {
color: theme.errorTextColor,
},
dangerContainer: {
borderColor: changeOpacity(theme.dndIndicator, 0.16),
backgroundColor: changeOpacity(theme.dndIndicator, 0.08),
},
warningText: {
color: theme.awayIndicator,
},
warningIcon: {
color: theme.sidebarTextActiveBorder,
},
warningContainer: {
borderColor: changeOpacity(theme.awayIndicator, 0.16),
backgroundColor: changeOpacity(theme.awayIndicator, 0.08),
},
welcomeText: {
color: theme.centerChannelColor,
},
welcomeIcon: {
color: theme.centerChannelColor,
},
welcomeContainer: {
borderColor: changeOpacity(theme.centerChannelColor, 0.08),
backgroundColor: changeOpacity(theme.centerChannelColor, 0.04),
},
hintText: {
color: theme.centerChannelColor,
},
hintIcon: {
color: theme.sidebarTextActiveBorder,
},
hintContainer: {
borderColor: changeOpacity(theme.sidebarTextActiveBorder, 0.16),
backgroundColor: changeOpacity(theme.sidebarTextActiveBorder, 0.08),
},
dismissIcon: {
position: 'absolute',
alignItems: 'center',
justifyContent: 'center',
right: 10,
top: 10,
width: 32,
height: 32,
},
tagsContainer: {
flexDirection: 'row',
flexWrap: 'wrap',
gap: 4,
},
};
});
const SectionNotice = ({
title,
isDismissable,
linkButton,
onDismissClick,
primaryButton,
secondaryButton,
text,
type = 'info',
location,
tags,
squareCorners,
testID,
}: Props) => {
const theme = useTheme();
const styles = getStyleFromTheme(theme);
const icon = iconByType[type];
const showDismiss = Boolean(isDismissable && onDismissClick);
const hasButtons = primaryButton || secondaryButton || linkButton;
const showTags = tags && tags.length > 0;
const combinedContainerStyle = useMemo(() => [
styles.container,
styles[`${type}Container`],
!squareCorners && styles.roundCorners,
], [styles, type, squareCorners]);
const iconStyle = useMemo(() => styles[`${type}Icon`], [styles, type]);
return (
<View
style={combinedContainerStyle}
testID={testID || 'sectionNoticeContainer'}
>
<View style={styles.content}>
{icon && (
<CompassIcon
name={icon}
style={iconStyle}
size={20}
testID='sectionNoticeHeaderIcon'
/>
)}
<View style={styles.body}>
<Text style={styles.title}>{title}</Text>
{text && (
<Markdown
theme={theme}
location={location}
baseTextStyle={styles.baseText}
value={text}
/>
)}
{showTags && (
<View style={styles.tagsContainer}>
{tags.map((tag) => (
<Tag
key={tag}
testID={`tag.${tag}`}
message={tag}
/>
))}
</View>
)}
{hasButtons && (
<View style={styles.actions}>
{primaryButton && (
<SectionNoticeButton
button={primaryButton}
emphasis='primary'
/>
)}
{secondaryButton && (
<SectionNoticeButton
button={secondaryButton}
emphasis='tertiary'
/>
)}
{linkButton && (
<SectionNoticeButton
button={linkButton}
emphasis='link'
/>
)}
</View>
)}
</View>
</View>
{showDismiss && (
<Pressable
style={styles.dismissIcon}
role={'button'}
onPress={onDismissClick}
testID={'sectionNoticeDismissButton'}
>
<CompassIcon
name={'close'}
size={18}
/>
</Pressable>
)}
</View>
);
};
export default SectionNotice;