rn-vs-lb 1.0.65 → 1.0.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +1 -0
  2. package/components/Button/Button.stories.tsx +1 -1
  3. package/components/Button/DeleteAccountButton.stories.tsx +1 -1
  4. package/components/Button/PostButton.stories.tsx +1 -1
  5. package/components/Button/TelegramFeedbackLink.stories.tsx +1 -1
  6. package/components/Cards/BusinessIdeaCard.stories.tsx +73 -0
  7. package/components/Cards/BusinessIdeaCard.tsx +251 -0
  8. package/components/Cards/EventCard.stories.tsx +1 -1
  9. package/components/Cards/PlaceCard.stories.tsx +1 -1
  10. package/components/Cards/index.tsx +1 -0
  11. package/components/Chat/ChatItem.stories.tsx +1 -1
  12. package/components/Chat/ChatTab/ChatTabs.stories.tsx +1 -1
  13. package/components/Chat/ChatTab/SubTabButton.stories.tsx +1 -1
  14. package/components/Chat/InputMessage.stories.tsx +1 -1
  15. package/components/Chat/InputMessage.tsx +2 -1
  16. package/components/Chat/MessageItem/LinkyText.tsx +9 -1
  17. package/components/Chat/MessageItem/MessageItem.stories.tsx +1 -1
  18. package/components/Chat/MessageItem/styles.ts +3 -0
  19. package/components/Chat/PinnedMessagesBar/PinnedMessagesBar.stories.tsx +1 -1
  20. package/components/Gallery/AiAgentGallery.stories.tsx +1 -1
  21. package/components/Gallery/ProfileMediaGallery.stories.tsx +66 -0
  22. package/components/Gallery/ProfileMediaGallery.tsx +239 -0
  23. package/components/Gallery/ProfileMediaNavigationItem.tsx +73 -0
  24. package/components/Gallery/ProfileSelfiesGallery.pure.tsx +97 -0
  25. package/components/Gallery/ProfileSelfiesGallery.stories.tsx +86 -0
  26. package/components/Gallery/index.ts +4 -1
  27. package/components/Header/HeaderDefault.stories.tsx +1 -1
  28. package/components/Header/HeaderEdit.stories.tsx +1 -1
  29. package/components/Header/HeaderHome.stories.tsx +1 -1
  30. package/components/Header/HeaderSwitcher.stories.tsx +1 -1
  31. package/components/Header/HeaderWithImg.stories.tsx +1 -1
  32. package/components/Modals/GalleryModal.stories.tsx +1 -1
  33. package/components/Modals/GuestAiChatModal.stories.tsx +1 -1
  34. package/components/Modals/ReportModal.stories.tsx +1 -1
  35. package/components/Modals/ReportModal.tsx +1 -1
  36. package/components/Poll/CommentItem.stories.tsx +1 -1
  37. package/components/Poll/PollCardList.stories.tsx +1 -1
  38. package/components/Posts/EventCardList.stories.tsx +1 -1
  39. package/components/Posts/PlaceCardList.stories.tsx +1 -1
  40. package/components/Prank/HeroPrankCard.stories.tsx +47 -0
  41. package/components/Prank/HeroPrankCard.tsx +114 -0
  42. package/components/Prank/HomelessPrankPage.stories.tsx +58 -0
  43. package/components/Prank/UploadPromptCard.stories.tsx +55 -0
  44. package/components/Prank/UploadPromptCard.tsx +130 -0
  45. package/components/Prank/index.ts +5 -0
  46. package/components/Profile/ModalProfilePhoto.stories.tsx +1 -1
  47. package/components/Profile/ProfileCard/ProfileCard.stories.tsx +1 -1
  48. package/components/Profile/ProfilePhotoBanner.stories.tsx +1 -1
  49. package/components/Profile/ProfilePhotoUpload/ProfilePhotoUpload.stories.tsx +1 -1
  50. package/components/Profile/ProfileSummary/ProfileSummary.stories.tsx +52 -0
  51. package/components/Profile/ProfileSummary/ProfileSummary.tsx +188 -0
  52. package/components/Profile/ProfileTabs/UserProfileTabs.stories.tsx +1 -1
  53. package/components/Profile/index.ts +2 -0
  54. package/components/Screens/AppScreens.stories.tsx +572 -0
  55. package/components/Screens/HomeScreen.stories.tsx +159 -0
  56. package/components/Screens/HoroscopeScreen.stories.tsx +299 -0
  57. package/components/Screens/LibraryScreen.stories.tsx +97 -0
  58. package/components/Settings/AppSettingsScreen.stories.tsx +134 -0
  59. package/components/Settings/AppSettingsScreen.tsx +215 -0
  60. package/components/Settings/SettingsHeader.tsx +37 -0
  61. package/components/Settings/SettingsListItem.tsx +142 -0
  62. package/components/Settings/SettingsManageAccountButton.tsx +58 -0
  63. package/components/Settings/SettingsOptionList.tsx +82 -0
  64. package/components/Settings/SettingsProfileCard.tsx +58 -0
  65. package/components/Settings/SettingsScreen.stories.tsx +66 -0
  66. package/components/Settings/SettingsScreen.tsx +129 -0
  67. package/components/Settings/SettingsSection.tsx +56 -0
  68. package/components/Settings/SettingsToggleItem.tsx +70 -0
  69. package/components/Settings/index.ts +23 -0
  70. package/components/Specialist/Hero.stories.tsx +1 -1
  71. package/components/Specialist/PortfolioCarousel.stories.tsx +1 -1
  72. package/components/Specialist/ServicesList.stories.tsx +1 -1
  73. package/components/Tooltip/DangerTooltip.stories.tsx +1 -1
  74. package/components/Tooltip/InfoTooltip.stories.tsx +1 -1
  75. package/components/Tooltip/InfoTooltipBase.stories.tsx +1 -1
  76. package/components/Tooltip/SucceedTooltip.stories.tsx +1 -1
  77. package/components/Tooltip/WarningTooltip.stories.tsx +1 -1
  78. package/components/UI/HorizontalCardSection.stories.tsx +85 -0
  79. package/components/UI/HorizontalCardSection.tsx +199 -0
  80. package/components/UI/TabBar/BottomTabBar.stories.tsx +87 -0
  81. package/components/UI/TabBar/BottomTabBar.tsx +128 -0
  82. package/components/UI/index.ts +4 -0
  83. package/components/UserCards/AiAgentHeroCard.stories.tsx +66 -0
  84. package/components/UserCards/AiAgentHeroCard.tsx +242 -0
  85. package/components/UserCards/Organizer.stories.tsx +1 -1
  86. package/components/UserCards/SpecialistCard.stories.tsx +1 -1
  87. package/components/UserCards/StoryCard.stories.tsx +1 -1
  88. package/components/UserCards/UserProfileCard.stories.tsx +1 -1
  89. package/components/UserCards/UserRow.stories.tsx +1 -1
  90. package/components/UserCards/index.ts +2 -0
  91. package/components/index.ts +2 -0
  92. package/index.ts +1 -0
  93. package/package.json +3 -1
  94. package/theme/index.ts +2 -0
package/README.md CHANGED
@@ -78,5 +78,6 @@ yarn build-storybook
78
78
  6. **Опубликуйте релиз**. Убедившись, что версия не занята, выполните:
79
79
  ```sh
80
80
  npm publish --access public
81
+ npm publish --access public --otp=RECOVERY_CODE
81
82
  ```
82
83
  7. **Проверьте публикацию**. После успешной публикации обновите теги в git (`git tag vX.Y.Z && git push --tags`) и убедитесь, что пакет появился на npmjs.com.
@@ -6,7 +6,7 @@ import { MaterialIcons } from '@expo/vector-icons';
6
6
  import Button, { MyButtonProps } from './Button';
7
7
 
8
8
  const meta: Meta<MyButtonProps> = {
9
- title: 'Button/Base',
9
+ title: 'UI/Buttons/Base',
10
10
  component: Button,
11
11
  decorators: [
12
12
  (Story) => (
@@ -3,7 +3,7 @@ import { Meta, StoryFn } from '@storybook/react';
3
3
  import { DeleteAccountButton, DeleteAccountButtonProps } from './DeleteAccountButton';
4
4
 
5
5
  const meta: Meta<DeleteAccountButtonProps> = {
6
- title: 'Button/DeleteAccountButton',
6
+ title: 'UI/Buttons/DeleteAccountButton',
7
7
  component: DeleteAccountButton,
8
8
  };
9
9
 
@@ -3,7 +3,7 @@ import { Meta, StoryFn } from '@storybook/react';
3
3
  import PostButton from './PostButton';
4
4
 
5
5
  const meta: Meta = {
6
- title: 'Button/PostButton',
6
+ title: 'UI/Buttons/PostButton',
7
7
  component: PostButton,
8
8
  argTypes: {
9
9
  title: {
@@ -3,7 +3,7 @@ import { Meta, StoryFn } from '@storybook/react';
3
3
  import { TelegramFeedbackLink, TelegramFeedbackLinkProps } from './TelegramFeedbackLink';
4
4
 
5
5
  const meta: Meta<TelegramFeedbackLinkProps> = {
6
- title: 'Button/TelegramFeedbackLink',
6
+ title: 'UI/Buttons/TelegramFeedbackLink',
7
7
  component: TelegramFeedbackLink,
8
8
  argTypes: {
9
9
  link: {
@@ -0,0 +1,73 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import BusinessIdeaCard from './BusinessIdeaCard';
4
+ import { ThemeProvider } from '../../theme/themeContext';
5
+
6
+ const meta: Meta<typeof BusinessIdeaCard> = {
7
+ title: 'UI/Cards/BusinessIdeaCard',
8
+ component: BusinessIdeaCard,
9
+ decorators: [
10
+ (Story) => (
11
+ <ThemeProvider>
12
+ <Story />
13
+ </ThemeProvider>
14
+ ),
15
+ ],
16
+ argTypes: {
17
+ avatarUri: { control: 'text' },
18
+ channelLabel: { control: 'text' },
19
+ imageUri: { control: 'text' },
20
+ quote: { control: 'text' },
21
+ likes: { control: 'number' },
22
+ comments: { control: 'number' },
23
+ shares: { control: 'number' },
24
+ timeAgo: { control: 'text' },
25
+ liked: { control: 'boolean' },
26
+ showMore: { control: 'boolean' },
27
+ showMoreLabel: { control: 'text' },
28
+ onPressLike: { action: 'like pressed' },
29
+ onPressComment: { action: 'comment pressed' },
30
+ onPressShare: { action: 'share pressed' },
31
+ onPressMore: { action: 'more pressed' },
32
+ onPressShowMore: { action: 'show more pressed' },
33
+ },
34
+ };
35
+
36
+ export default meta;
37
+
38
+ type Story = StoryObj<typeof BusinessIdeaCard>;
39
+
40
+ export const Default: Story = {
41
+ args: {
42
+ avatarUri: 'https://i.pravatar.cc/100?img=65',
43
+ channelLabel: 'Бизнес идеи',
44
+ imageUri:
45
+ 'https://images.wsj.net/im-861283?width=700&height=467',
46
+ quote:
47
+ '«Я думаю, что мы будем жить в мире, где появятся сотни миллионов и миллиарды разных ИИ-агентов, и, возможно, их будет больше, чем людей»',
48
+ likes: 13,
49
+ comments: 7,
50
+ shares: 5,
51
+ timeAgo: '2 d ago',
52
+ showMoreLabel: 'Show more',
53
+ showMore: true,
54
+ },
55
+ };
56
+
57
+ export const WithoutAvatar: Story = {
58
+ args: {
59
+ ...Default.args,
60
+ avatarUri: '',
61
+ channelLabel: 'AI news',
62
+ },
63
+ };
64
+
65
+ export const LongQuote: Story = {
66
+ args: {
67
+ ...Default.args,
68
+ quote:
69
+ '«Мы видим, как искусственный интеллект постепенно перестает быть инструментом и становится полноценным партнером в работе. В ближайшие годы появится огромное количество агентов, которые будут помогать людям решать бытовые и профессиональные задачи, освобождая время для творчества и стратегического мышления.»',
70
+ showMore: false,
71
+ liked: true,
72
+ },
73
+ };
@@ -0,0 +1,251 @@
1
+ import React from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ Image,
6
+ TouchableOpacity,
7
+ StyleSheet,
8
+ ImageSourcePropType,
9
+ TextStyle,
10
+ } from 'react-native';
11
+ import { Ionicons } from '@expo/vector-icons';
12
+ import { useTheme, ThemeType, SizesType } from '../../theme';
13
+ import Spacer from '../UI/Spacer';
14
+ import { GlobalStyleSheetType } from '../../theme/styles/styleSheet';
15
+
16
+ export interface BusinessIdeaCardProps {
17
+ avatarUri: string;
18
+ channelLabel: string;
19
+ imageUri: string;
20
+ quote: string;
21
+ likes: number;
22
+ comments: number;
23
+ shares: number;
24
+ timeAgo: string;
25
+ showMore?: boolean;
26
+ showMoreLabel?: string;
27
+ liked?: boolean;
28
+ onPressLike?: () => void;
29
+ onPressComment?: () => void;
30
+ onPressShare?: () => void;
31
+ onPressMore?: () => void;
32
+ onPressShowMore?: () => void;
33
+ avatarPlaceholder?: ImageSourcePropType;
34
+ }
35
+
36
+ const BusinessIdeaCard: React.FC<BusinessIdeaCardProps> = ({
37
+ avatarUri,
38
+ channelLabel,
39
+ imageUri,
40
+ quote,
41
+ likes,
42
+ comments,
43
+ shares,
44
+ timeAgo,
45
+ showMore = true,
46
+ showMoreLabel = 'Show more',
47
+ liked = false,
48
+ onPressLike,
49
+ onPressComment,
50
+ onPressShare,
51
+ onPressMore,
52
+ onPressShowMore,
53
+ avatarPlaceholder,
54
+ }) => {
55
+ const { theme, sizes, commonStyles, typography, globalStyleSheet } = useTheme();
56
+ const styles = getStyles({ theme, sizes, globalStyleSheet });
57
+
58
+ const renderAvatar = () => {
59
+ if (avatarUri) {
60
+ return <Image source={{ uri: avatarUri }} style={styles.avatar} />;
61
+ }
62
+
63
+ if (avatarPlaceholder) {
64
+ return <Image source={avatarPlaceholder} style={styles.avatar} />;
65
+ }
66
+
67
+ return (
68
+ <View style={[styles.avatar, styles.avatarFallback]}>
69
+ <Ionicons name="bulb" size={18} color={theme.primary} />
70
+ </View>
71
+ );
72
+ };
73
+
74
+ return (
75
+ <View style={[commonStyles.card, commonStyles.shadow, styles.container]}>
76
+ <View style={styles.header}>
77
+ <View style={styles.headerLeft}>
78
+ {renderAvatar()}
79
+ <Text style={styles.channelLabel}>{channelLabel}</Text>
80
+ </View>
81
+ {onPressMore ? (
82
+ <TouchableOpacity onPress={onPressMore} hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
83
+ <Ionicons name="ellipsis-horizontal" size={20} color={theme.greyText} />
84
+ </TouchableOpacity>
85
+ ) : (
86
+ <Ionicons name="ellipsis-horizontal" size={20} color={theme.greyText} />
87
+ )}
88
+ </View>
89
+
90
+ <Spacer size="xs" />
91
+
92
+ <Image source={{ uri: imageUri }} style={styles.coverImage} resizeMode="cover" />
93
+
94
+ <Spacer size="sm" />
95
+
96
+ <Text style={[typography.body, styles.quote]} numberOfLines={4} ellipsizeMode="tail">
97
+ {quote}
98
+ </Text>
99
+
100
+ {showMore && (
101
+ <>
102
+ <Spacer size="xxs" />
103
+ {onPressShowMore ? (
104
+ <TouchableOpacity onPress={onPressShowMore} activeOpacity={0.7}>
105
+ <Text style={styles.showMore}>{showMoreLabel}</Text>
106
+ </TouchableOpacity>
107
+ ) : (
108
+ <Text style={styles.showMore}>{showMoreLabel}</Text>
109
+ )}
110
+ </>
111
+ )}
112
+
113
+ <Spacer size="sm" />
114
+
115
+ <View style={styles.footer}>
116
+ <View style={styles.actionsRow}>
117
+ <ActionButton
118
+ iconName={liked ? 'heart' : 'heart-outline'}
119
+ iconColor={liked ? theme.danger : theme.greyText}
120
+ label={likes}
121
+ onPress={onPressLike}
122
+ />
123
+ <ActionButton
124
+ iconName="chatbubble-ellipses-outline"
125
+ iconColor={theme.greyText}
126
+ label={comments}
127
+ onPress={onPressComment}
128
+ />
129
+ <ActionButton
130
+ iconName="arrow-redo-outline"
131
+ iconColor={theme.greyText}
132
+ label={shares}
133
+ onPress={onPressShare}
134
+ />
135
+ </View>
136
+ <Text style={styles.timeAgo}>{timeAgo}</Text>
137
+ </View>
138
+ </View>
139
+ );
140
+ };
141
+
142
+ interface StyleParams {
143
+ theme: ThemeType;
144
+ sizes: SizesType;
145
+ globalStyleSheet: GlobalStyleSheetType;
146
+ }
147
+
148
+ const getStyles = ({ theme, sizes, globalStyleSheet }: StyleParams) =>
149
+ StyleSheet.create({
150
+ container: {
151
+ padding: sizes.md,
152
+ borderRadius: sizes.radius_lg,
153
+ backgroundColor: theme.white,
154
+ },
155
+ header: {
156
+ ...globalStyleSheet.flexRowCenterBetween,
157
+ },
158
+ headerLeft: {
159
+ ...globalStyleSheet.flexRowCenterStart,
160
+ gap: sizes.xs,
161
+ },
162
+ avatar: {
163
+ width: 36,
164
+ height: 36,
165
+ borderRadius: 18,
166
+ backgroundColor: theme.backgroundSecond,
167
+ overflow: 'hidden',
168
+ },
169
+ avatarFallback: {
170
+ alignItems: 'center',
171
+ justifyContent: 'center',
172
+ },
173
+ channelLabel: {
174
+ ...globalStyleSheet.descriptionCard,
175
+ color: theme.title,
176
+ fontWeight: '600',
177
+ textTransform: 'uppercase',
178
+ letterSpacing: 0.8,
179
+ },
180
+ coverImage: {
181
+ width: '100%',
182
+ height: 220,
183
+ borderRadius: sizes.radius_sm,
184
+ backgroundColor: theme.backgroundSecond,
185
+ },
186
+ quote: {
187
+ color: theme.title,
188
+ fontStyle: 'italic',
189
+ },
190
+ showMore: {
191
+ color: theme.greyText,
192
+ fontSize: sizes.fontSm,
193
+ fontWeight: '500',
194
+ } as TextStyle,
195
+ footer: {
196
+ ...globalStyleSheet.flexRowCenterBetween,
197
+ alignItems: 'center',
198
+ },
199
+ actionsRow: {
200
+ flexDirection: 'row',
201
+ alignItems: 'center',
202
+ columnGap: sizes.md,
203
+ gap: sizes.md,
204
+ },
205
+ timeAgo: {
206
+ color: theme.greyText,
207
+ fontSize: sizes.fontSm,
208
+ } as TextStyle,
209
+ });
210
+
211
+ type ActionButtonProps = {
212
+ iconName: React.ComponentProps<typeof Ionicons>['name'];
213
+ iconColor: string;
214
+ label: number;
215
+ onPress?: () => void;
216
+ };
217
+
218
+ const ActionButton: React.FC<ActionButtonProps> = ({ iconName, iconColor, label, onPress }) => {
219
+ const { theme, sizes } = useTheme();
220
+ const styles = StyleSheet.create({
221
+ action: {
222
+ flexDirection: 'row',
223
+ alignItems: 'center',
224
+ columnGap: sizes.xs,
225
+ gap: sizes.xs,
226
+ },
227
+ label: {
228
+ color: theme.text,
229
+ fontSize: sizes.fontSm,
230
+ fontWeight: '500',
231
+ },
232
+ });
233
+
234
+ if (!onPress) {
235
+ return (
236
+ <View style={styles.action}>
237
+ <Ionicons name={iconName} size={18} color={iconColor} />
238
+ <Text style={styles.label}>{label}</Text>
239
+ </View>
240
+ );
241
+ }
242
+
243
+ return (
244
+ <TouchableOpacity onPress={onPress} activeOpacity={0.7} style={styles.action}>
245
+ <Ionicons name={iconName} size={18} color={iconColor} />
246
+ <Text style={styles.label}>{label}</Text>
247
+ </TouchableOpacity>
248
+ );
249
+ };
250
+
251
+ export default BusinessIdeaCard;
@@ -4,7 +4,7 @@ import EventCard from './EventCard';
4
4
  import { ThemeProvider } from '../../theme/themeContext';
5
5
 
6
6
  const meta: Meta<React.ComponentProps<typeof EventCard>> = {
7
- title: 'Cards/EventCard',
7
+ title: 'UI/Cards/EventCard',
8
8
  component: EventCard,
9
9
  decorators: [
10
10
  (Story) => (
@@ -4,7 +4,7 @@ import PlaceCard from './PlaceCard';
4
4
  import { ThemeProvider } from '../../theme/themeContext';
5
5
 
6
6
  const meta: Meta<React.ComponentProps<typeof PlaceCard>> = {
7
- title: 'Cards/PlaceCard',
7
+ title: 'UI/Cards/PlaceCard',
8
8
  component: PlaceCard,
9
9
  decorators: [
10
10
  (Story) => (
@@ -2,3 +2,4 @@ export { default as PlaceCard } from './PlaceCard';
2
2
  export { default as EventCard } from './EventCard';
3
3
  export { default as Organazer } from '../UserCards/Organazer';
4
4
  export { default as SpecialistCard } from '../UserCards/SpecialistCard';
5
+ export { default as BusinessIdeaCard } from './BusinessIdeaCard';
@@ -10,7 +10,7 @@ const createPressHandler = (label: string) => () => {
10
10
  };
11
11
 
12
12
  const meta: Meta<ChatItemProps> = {
13
- title: 'Chat/ChatItem',
13
+ title: 'Features/Chat/ChatItem',
14
14
  component: ChatItem,
15
15
  decorators: [
16
16
  (Story) => (
@@ -4,7 +4,7 @@ import { View } from 'react-native';
4
4
  import ChatTabs, { type ChatTab, type BotSubTab } from './ChatTabs';
5
5
 
6
6
  const meta = {
7
- title: 'Chat/ChatTabs',
7
+ title: 'Features/Chat/ChatTabs',
8
8
  component: ChatTabs,
9
9
  decorators: [(Story) => <View style={{ paddingVertical: 12 }}><Story /></View>],
10
10
  argTypes: {
@@ -4,7 +4,7 @@ import { View } from 'react-native';
4
4
  import SubTabButton from './SubTabButton';
5
5
 
6
6
  const meta = {
7
- title: 'Chat/SubTabButton',
7
+ title: 'Features/Chat/SubTabButton',
8
8
  component: SubTabButton,
9
9
  decorators: [(Story) => <View style={{ padding: 12 }}><Story /></View>],
10
10
  argTypes: {
@@ -8,7 +8,7 @@ import InputMessage, { ImageAsset } from './InputMessage';
8
8
  type Props = React.ComponentProps<typeof InputMessage>;
9
9
 
10
10
  const meta: Meta<Props> = {
11
- title: 'Chat/InputMessage',
11
+ title: 'Features/Chat/InputMessage',
12
12
  component: InputMessage,
13
13
  decorators: [
14
14
  (Story) => (
@@ -265,11 +265,12 @@ export const getStyles = (theme: ThemeType) =>
265
265
  paddingHorizontal: 10,
266
266
  paddingVertical: 6,
267
267
  borderRadius: 4,
268
+ top:4,
268
269
  borderColor: theme.white,
269
270
  },
270
271
  sendButton: {
271
272
  position: 'absolute',
272
- bottom: 9,
273
+ bottom: 8,
273
274
  right: 8,
274
275
  borderRadius: 4,
275
276
  justifyContent: 'center',
@@ -3,6 +3,7 @@ import React, { FC, useMemo } from 'react';
3
3
  import { Text } from 'react-native';
4
4
  import { ThemeType } from '../../../theme';
5
5
  import { getStyles } from './styles';
6
+ import { formatBoldText } from '../../../utils';
6
7
 
7
8
  interface LinkyTextProps {
8
9
  text: string;
@@ -21,6 +22,13 @@ export const LinkyText: FC<LinkyTextProps> = ({ text, theme, onLinkPress, onLong
21
22
  onLinkPress?.(url);
22
23
  };
23
24
 
25
+ const renderBoldParts = (segment: string, keyPrefix: string) =>
26
+ formatBoldText(segment).map((part, index) => (
27
+ <Text key={`${keyPrefix}-${index}`} style={part.bold ? styles.messageTextBold : undefined}>
28
+ {part.text}
29
+ </Text>
30
+ ));
31
+
24
32
  return (
25
33
  <Text style={styles.messageText}>
26
34
  {parts.map((part, i) =>
@@ -35,7 +43,7 @@ export const LinkyText: FC<LinkyTextProps> = ({ text, theme, onLinkPress, onLong
35
43
  {part}
36
44
  </Text>
37
45
  ) : (
38
- <Text key={i}>{part}</Text>
46
+ renderBoldParts(part, `text-${i}`)
39
47
  )
40
48
  )}
41
49
  </Text>
@@ -7,7 +7,7 @@ import MessageItem from './MessageItem';
7
7
  import { LinkPreviewData, MessageDTO, MessageItemProps } from './types';
8
8
 
9
9
  const meta: Meta<MessageItemProps> = {
10
- title: 'Chat/MessageItem',
10
+ title: 'Features/Chat/MessageItem',
11
11
  component: MessageItem,
12
12
  decorators: [
13
13
  (Story) => (
@@ -68,6 +68,9 @@ export const getStyles = ({ theme }: { theme: ThemeType }) =>
68
68
  fontSize: 15,
69
69
  color: theme.black,
70
70
  },
71
+ messageTextBold: {
72
+ fontWeight: 'bold',
73
+ },
71
74
  messageFooter: {
72
75
  flexDirection: 'row',
73
76
  alignItems: 'center',
@@ -8,7 +8,7 @@ import { MessageDTO } from '../../../types/message';
8
8
  type Props = React.ComponentProps<typeof PinnedMessagesBar>;
9
9
 
10
10
  const meta: Meta<Props> = {
11
- title: 'Chat/PinnedMessagesBar',
11
+ title: 'Features/Chat/PinnedMessagesBar',
12
12
  component: PinnedMessagesBar,
13
13
  decorators: [
14
14
  (Story) => (
@@ -7,7 +7,7 @@ import { AiAgentGalleryView } from './AiAgentGallery.pure';
7
7
  type Props = React.ComponentProps<typeof AiAgentGalleryView>;
8
8
 
9
9
  const meta: Meta<Props> = {
10
- title: 'Gallery/AiAgentGallery',
10
+ title: 'Features/Gallery/AiAgentGallery',
11
11
  component: AiAgentGalleryView,
12
12
  decorators: [
13
13
  (Story) => (
@@ -0,0 +1,66 @@
1
+ import React, { useState } from "react";
2
+ import { Meta, StoryFn } from "@storybook/react";
3
+ import { View } from "react-native";
4
+ import { ThemeProvider } from "../../theme";
5
+ import { ProfileMediaGallery, ProfileMediaGalleryProps } from "./ProfileMediaGallery";
6
+
7
+ const meta: Meta<typeof ProfileMediaGallery> = {
8
+ title: 'Features/Gallery/ProfileMediaGallery',
9
+ component: ProfileMediaGallery,
10
+ decorators: [
11
+ (Story) => (
12
+ <ThemeProvider>
13
+ <View style={{ padding: 24 }}>
14
+ <Story />
15
+ </View>
16
+ </ThemeProvider>
17
+ ),
18
+ ],
19
+ };
20
+
21
+ export default meta;
22
+
23
+ const TABS: ProfileMediaGalleryProps["tabs"] = [
24
+ { key: "photos", label: "Photos", iconName: "collections" },
25
+ { key: "videos", label: "Videos", iconName: "videocam" },
26
+ { key: "music", label: "Music", iconName: "music-note" },
27
+ { key: "albums", label: "Albums", iconName: "photo-album" },
28
+ ];
29
+
30
+ const Template: StoryFn<ProfileMediaGalleryProps> = (args) => (
31
+ <ProfileMediaGallery {...args} />
32
+ );
33
+
34
+ export const Default = Template.bind({});
35
+ Default.args = {
36
+ tabs: TABS,
37
+ images: [
38
+ "https://images.unsplash.com/photo-1503023345310-bd7c1de61c7d?auto=format&fit=crop&w=600&q=60",
39
+ "https://images.unsplash.com/photo-1520813792240-56fc4a3765a7?auto=format&fit=crop&w=600&q=60",
40
+ "https://images.unsplash.com/photo-1524504388940-b1c1722653e1?auto=format&fit=crop&w=600&q=60",
41
+ "https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=600&q=60",
42
+ "https://images.unsplash.com/photo-1492562080023-ab3db95bfbce?auto=format&fit=crop&w=600&q=60",
43
+ "https://images.unsplash.com/photo-1521572163474-6864f9cf17ab?auto=format&fit=crop&w=600&q=60",
44
+ ],
45
+ };
46
+
47
+ export const ControlledTabs: StoryFn<ProfileMediaGalleryProps> = ({ ...rest }) => {
48
+ const [activeTabKey, setActiveTabKey] = useState(rest.activeTabKey ?? TABS[0].key);
49
+
50
+ return (
51
+ <ProfileMediaGallery
52
+ {...rest}
53
+ tabs={rest.tabs ?? TABS}
54
+ activeTabKey={activeTabKey}
55
+ onTabPress={(tab, index) => {
56
+ setActiveTabKey(tab.key);
57
+ rest.onTabPress?.(tab, index);
58
+ }}
59
+ />
60
+ );
61
+ };
62
+
63
+ ControlledTabs.args = {
64
+ tabs: TABS,
65
+ images: Default.args?.images ?? [],
66
+ };