Skip to content

Commit 2028cb5

Browse files
committed
feat: inline unread separator and notification redesign
1 parent b5bdc8b commit 2028cb5

File tree

7 files changed

+163
-94
lines changed

7 files changed

+163
-94
lines changed

package/src/components/Message/MessageSimple/MessageWrapper.tsx

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, { useMemo } from 'react';
22

33
import { StyleSheet, View } from 'react-native';
44

@@ -72,10 +72,11 @@ export const MessageWrapper = React.memo((props: MessageWrapperProps) => {
7272
useStateStore(channelUnreadStateStore.state, channelUnreadStateSelector);
7373
const {
7474
theme: {
75-
messageList: { messageContainer, inlineDateSeparatorContainer },
75+
messageList: { messageContainer },
7676
screenPadding,
7777
},
7878
} = useTheme();
79+
const styles = useStyles();
7980
if (!channel || channel.disconnected) {
8081
return null;
8182
}
@@ -95,7 +96,7 @@ export const MessageWrapper = React.memo((props: MessageWrapperProps) => {
9596

9697
const wrapMessageInTheme = client.userID === message.user?.id && !!myMessageTheme;
9798
const renderDateSeperator = dateSeparatorDate ? (
98-
<View style={[styles.dateSeparatorContainer, inlineDateSeparatorContainer]}>
99+
<View style={styles.dateSeparatorContainer}>
99100
<InlineDateSeparator date={dateSeparatorDate} />
100101
</View>
101102
) : null;
@@ -133,13 +134,33 @@ export const MessageWrapper = React.memo((props: MessageWrapperProps) => {
133134
{renderMessage}
134135
</View>
135136
)}
136-
{showUnreadUnderlay && <InlineUnreadIndicator />}
137+
{showUnreadUnderlay && (
138+
<View style={styles.unreadUnderlayContainer}>
139+
<InlineUnreadIndicator />
140+
</View>
141+
)}
137142
</View>
138143
);
139144
});
140145

141-
const styles = StyleSheet.create({
142-
dateSeparatorContainer: {
143-
paddingVertical: primitives.spacingXs,
144-
},
145-
});
146+
const useStyles = () => {
147+
const {
148+
theme: {
149+
messageList: { unreadUnderlayContainer, inlineDateSeparatorContainer },
150+
},
151+
} = useTheme();
152+
return useMemo(
153+
() =>
154+
StyleSheet.create({
155+
dateSeparatorContainer: {
156+
paddingVertical: primitives.spacingXs,
157+
...inlineDateSeparatorContainer,
158+
},
159+
unreadUnderlayContainer: {
160+
paddingVertical: primitives.spacingXs,
161+
...unreadUnderlayContainer,
162+
},
163+
}),
164+
[unreadUnderlayContainer, inlineDateSeparatorContainer],
165+
);
166+
};

package/src/components/MessageList/InlineUnreadIndicator.tsx

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,53 @@
1-
import React from 'react';
1+
import React, { useMemo } from 'react';
22
import { StyleSheet, Text, View } from 'react-native';
33

44
import { useTheme } from '../../contexts/themeContext/ThemeContext';
55
import { useTranslationContext } from '../../contexts/translationContext/TranslationContext';
6+
import { primitives } from '../../theme';
67

78
export const InlineUnreadIndicator = () => {
9+
const styles = useStyles();
10+
const { t } = useTranslationContext();
11+
12+
return (
13+
<View accessibilityLabel='Inline unread indicator' style={styles.container}>
14+
<Text style={styles.text}>{t('Unread Messages')}</Text>
15+
</View>
16+
);
17+
};
18+
19+
const useStyles = () => {
820
const {
921
theme: {
10-
colors: { grey, light_gray },
1122
messageList: {
1223
inlineUnreadIndicator: { container, text },
1324
},
25+
semantics,
1426
},
1527
} = useTheme();
16-
const { t } = useTranslationContext();
17-
18-
return (
19-
<View
20-
accessibilityLabel='Inline unread indicator'
21-
style={[styles.container, { backgroundColor: light_gray }, container]}
22-
>
23-
<Text style={[styles.text, { color: grey }, text]}>{t('Unread Messages')}</Text>
24-
</View>
28+
return useMemo(
29+
() =>
30+
StyleSheet.create({
31+
container: {
32+
alignItems: 'center',
33+
justifyContent: 'center',
34+
paddingVertical: primitives.spacingXs,
35+
paddingHorizontal: primitives.spacingSm,
36+
backgroundColor: semantics.backgroundCoreSurfaceSubtle,
37+
borderTopWidth: 1,
38+
borderTopColor: semantics.borderCoreSubtle,
39+
borderBottomWidth: 1,
40+
borderBottomColor: semantics.borderCoreSubtle,
41+
...container,
42+
},
43+
text: {
44+
color: semantics.chatTextSystem,
45+
fontSize: primitives.typographyFontSizeXs,
46+
fontWeight: primitives.typographyFontWeightSemiBold,
47+
lineHeight: primitives.typographyLineHeightTight,
48+
...text,
49+
},
50+
}),
51+
[semantics, container, text],
2552
);
2653
};
27-
28-
const styles = StyleSheet.create({
29-
container: {
30-
alignItems: 'center',
31-
justifyContent: 'center',
32-
marginTop: 2,
33-
padding: 10,
34-
},
35-
text: {
36-
fontSize: 12,
37-
},
38-
});

package/src/components/MessageList/MessageFlashList.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,7 +1088,7 @@ const MessageFlashListWithContext = (props: MessageFlashListPropsWithContext) =>
10881088
layout={LinearTransition.duration(200)}
10891089
style={[
10901090
styles.scrollToBottomButtonContainer,
1091-
{ bottom: messageInputFloating ? messageInputHeight : 16 },
1091+
{ bottom: messageInputFloating ? messageInputHeight : primitives.spacingMd },
10921092
]}
10931093
>
10941094
<ScrollToBottomButton
@@ -1313,13 +1313,15 @@ const useStyles = () => {
13131313
left: 0,
13141314
position: 'absolute',
13151315
right: 0,
1316-
top: primitives.spacingXs,
1316+
top: primitives.spacingMd,
13171317
...stickyHeaderContainer,
13181318
},
13191319
unreadMessagesNotificationContainer: {
1320-
alignSelf: 'center',
13211320
position: 'absolute',
1322-
top: 8,
1321+
top: primitives.spacingMd,
1322+
left: 0,
1323+
right: 0,
1324+
alignItems: 'center',
13231325
...unreadMessagesNotificationContainer,
13241326
},
13251327
}),

package/src/components/MessageList/MessageList.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,15 @@ const useStyles = () => {
126126
left: 0,
127127
position: 'absolute',
128128
right: 0,
129-
top: primitives.spacingXs,
129+
top: primitives.spacingMd,
130130
...stickyHeaderContainer,
131131
},
132132
unreadMessagesNotificationContainer: {
133-
alignSelf: 'center',
134133
position: 'absolute',
135-
top: 8,
134+
top: primitives.spacingMd,
135+
left: 0,
136+
right: 0,
137+
alignItems: 'center',
136138
...unreadMessagesNotificationContainer,
137139
},
138140
}),
@@ -1310,7 +1312,7 @@ const MessageListWithContext = (props: MessageListPropsWithContext) => {
13101312
<Animated.View
13111313
layout={LinearTransition.duration(200)}
13121314
style={[
1313-
{ bottom: messageInputFloating ? messageInputHeight : 16 },
1315+
{ bottom: messageInputFloating ? messageInputHeight : primitives.spacingMd },
13141316
styles.scrollToBottomButtonContainer,
13151317
]}
13161318
>

package/src/components/MessageList/UnreadMessagesNotification.tsx

Lines changed: 61 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
import React from 'react';
2-
import { Pressable, StyleSheet, Text } from 'react-native';
1+
import React, { useMemo } from 'react';
2+
import { StyleSheet, View } from 'react-native';
33

44
import { useChannelContext } from '../../contexts/channelContext/ChannelContext';
55
import { useTheme } from '../../contexts/themeContext/ThemeContext';
66
import { useTranslationContext } from '../../contexts/translationContext/TranslationContext';
7+
import { ArrowUp } from '../../icons/ArrowUp';
78
import { NewClose } from '../../icons/NewClose';
9+
import { primitives } from '../../theme';
10+
import { Button } from '../ui';
811

912
export type UnreadMessagesNotificationProps = {
1013
/**
@@ -48,57 +51,67 @@ export const UnreadMessagesNotification = (props: UnreadMessagesNotificationProp
4851
}
4952
};
5053

54+
const styles = useStyles();
55+
56+
return (
57+
<View style={styles.container}>
58+
<View style={styles.leftButtonContainer}>
59+
<Button
60+
variant='secondary'
61+
type='ghost'
62+
LeadingIcon={ArrowUp}
63+
label={t('Unread Messages')}
64+
onPress={handleOnPress}
65+
size='md'
66+
/>
67+
</View>
68+
<View style={styles.rightButtonContainer}>
69+
<Button
70+
variant='secondary'
71+
type='ghost'
72+
iconOnly
73+
LeadingIcon={NewClose}
74+
onPress={handleClose}
75+
size='md'
76+
/>
77+
</View>
78+
</View>
79+
);
80+
};
81+
82+
const useStyles = () => {
5183
const {
5284
theme: {
53-
colors: { text_low_emphasis, white_snow },
5485
messageList: {
55-
unreadMessagesNotification: { closeButtonContainer, closeIcon, container, text },
86+
unreadMessagesNotification: { container, leftButtonContainer, rightButtonContainer },
5687
},
88+
semantics,
5789
},
5890
} = useTheme();
59-
60-
return (
61-
<Pressable
62-
onPress={handleOnPress}
63-
style={({ pressed }) => [
64-
styles.container,
65-
{ backgroundColor: text_low_emphasis, opacity: pressed ? 0.8 : 1 },
66-
container,
67-
]}
68-
>
69-
<Text style={[styles.text, { color: white_snow }, text]}>{t('Unread Messages')}</Text>
70-
<Pressable
71-
onPress={handleClose}
72-
style={({ pressed }) => [
73-
{
74-
opacity: pressed ? 0.8 : 1,
75-
},
76-
closeButtonContainer,
77-
]}
78-
>
79-
<NewClose pathFill={white_snow} {...closeIcon} />
80-
</Pressable>
81-
</Pressable>
91+
return useMemo(
92+
() =>
93+
StyleSheet.create({
94+
container: {
95+
borderRadius: primitives.radiusMax,
96+
borderWidth: 1,
97+
borderColor: semantics.borderCoreDefault,
98+
backgroundColor: semantics.backgroundCoreApp,
99+
flexDirection: 'row',
100+
alignItems: 'center',
101+
...primitives.lightElevation4,
102+
...container,
103+
},
104+
leftButtonContainer: {
105+
flexShrink: 0,
106+
borderRightWidth: 1,
107+
borderRightColor: semantics.borderCoreDefault,
108+
...leftButtonContainer,
109+
},
110+
rightButtonContainer: {
111+
flexShrink: 0,
112+
...rightButtonContainer,
113+
},
114+
}),
115+
[semantics, container, leftButtonContainer, rightButtonContainer],
82116
);
83117
};
84-
85-
const styles = StyleSheet.create({
86-
container: {
87-
borderRadius: 20,
88-
elevation: 4,
89-
flexDirection: 'row',
90-
paddingHorizontal: 16,
91-
paddingVertical: 8,
92-
shadowColor: '#000',
93-
shadowOffset: {
94-
height: 2,
95-
width: 0,
96-
},
97-
shadowOpacity: 0.23,
98-
shadowRadius: 2.62,
99-
},
100-
text: {
101-
fontWeight: '500',
102-
marginRight: 8,
103-
},
104-
});

package/src/contexts/themeContext/utils/theme.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,7 @@ export type Theme = {
488488
listContainer: ViewStyle;
489489
messageContainer: ViewStyle;
490490
inlineDateSeparatorContainer: ViewStyle;
491+
unreadUnderlayContainer: ViewStyle;
491492
messageSystem: {
492493
container: ViewStyle;
493494
dateText: TextStyle;
@@ -505,10 +506,9 @@ export type Theme = {
505506
typingIndicatorContainer: ViewStyle;
506507
unreadMessagesNotificationContainer: ViewStyle;
507508
unreadMessagesNotification: {
508-
closeButtonContainer: ViewStyle;
509-
closeIcon: IconProps;
510509
container: ViewStyle;
511-
text: TextStyle;
510+
leftButtonContainer: ViewStyle;
511+
rightButtonContainer: ViewStyle;
512512
};
513513
};
514514
messageMenu: {
@@ -1383,6 +1383,7 @@ export const defaultTheme: Theme = {
13831383
listContainer: {},
13841384
messageContainer: {},
13851385
inlineDateSeparatorContainer: {},
1386+
unreadUnderlayContainer: {},
13861387
messageSystem: {
13871388
container: {},
13881389
dateText: {},
@@ -1399,10 +1400,9 @@ export const defaultTheme: Theme = {
13991400
stickyHeaderContainer: {},
14001401
typingIndicatorContainer: {},
14011402
unreadMessagesNotification: {
1402-
closeButtonContainer: {},
1403-
closeIcon: {},
14041403
container: {},
1405-
text: {},
1404+
leftButtonContainer: {},
1405+
rightButtonContainer: {},
14061406
},
14071407
unreadMessagesNotificationContainer: {},
14081408
},

package/src/icons/ArrowUp.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React from 'react';
2+
import Svg, { Path } from 'react-native-svg';
3+
4+
import { IconProps } from './utils/base';
5+
6+
export const ArrowUp = ({ height, width, ...rest }: IconProps) => (
7+
<Svg height={height} viewBox='0 0 20 20' fill='none' width={width}>
8+
<Path
9+
d='M4.79175 8.33333L10.0001 3.125L15.2084 8.33333M10.0001 16.875V3.75'
10+
strokeWidth={1.5}
11+
strokeLinecap='round'
12+
strokeLinejoin='round'
13+
{...rest}
14+
/>
15+
</Svg>
16+
);

0 commit comments

Comments
 (0)