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
@@ -0,0 +1,239 @@
1
+ import React, { useMemo, useState, useEffect } from "react";
2
+ import {
3
+ Image,
4
+ Pressable,
5
+ ScrollView,
6
+ StyleSheet,
7
+ Text,
8
+ View,
9
+ useWindowDimensions,
10
+ } from "react-native";
11
+ import { ThemeType, SizesType, TypographytType, useTheme } from "../../theme";
12
+ import { GalleryModal } from "../Modals";
13
+ import { ProfileMediaNavigationItem, ProfileMediaNavigationItemProps } from "./ProfileMediaNavigationItem";
14
+
15
+ type TabItem = Omit<ProfileMediaNavigationItemProps, "isActive" | "onPress"> & {
16
+ key: string;
17
+ };
18
+
19
+ export type ProfileMediaGalleryProps = {
20
+ tabs: TabItem[];
21
+ activeTabKey?: string;
22
+ onTabPress?: (tab: TabItem, index: number) => void;
23
+ images: string[];
24
+ extraInfoLabel?: string;
25
+ extraInfoActionLabel?: string;
26
+ onExtraInfoPress?: () => void;
27
+ uploadButtonLabel?: string;
28
+ showAllButtonLabel?: string;
29
+ onUploadPress?: () => void;
30
+ onShowAllPress?: () => void;
31
+ };
32
+
33
+ const FALLBACK_IMAGES = [
34
+ "https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?auto=format&fit=crop&w=600&q=60",
35
+ "https://images.unsplash.com/photo-1503023345310-bd7c1de61c7d?auto=format&fit=crop&w=600&q=60",
36
+ "https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&w=600&q=60",
37
+ "https://images.unsplash.com/photo-1557862921-37829c790f19?auto=format&fit=crop&w=600&q=60",
38
+ "https://images.unsplash.com/photo-1524504388940-b1c1722653e1?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
+ ];
41
+
42
+ export const ProfileMediaGallery: React.FC<ProfileMediaGalleryProps> = ({
43
+ tabs = [],
44
+ activeTabKey,
45
+ onTabPress,
46
+ images = [],
47
+ extraInfoLabel = "+14 photo tags",
48
+ extraInfoActionLabel = "View",
49
+ onExtraInfoPress,
50
+ uploadButtonLabel = "Upload photo",
51
+ showAllButtonLabel = "Show all",
52
+ onUploadPress,
53
+ onShowAllPress,
54
+ }) => {
55
+ const { theme, sizes, typography } = useTheme();
56
+ const { width } = useWindowDimensions();
57
+ const styles = useMemo(() => getStyles(theme, sizes, typography), [theme, sizes, typography]);
58
+ const [internalActiveKey, setInternalActiveKey] = useState<string>(
59
+ activeTabKey ?? tabs[0]?.key ?? ""
60
+ );
61
+
62
+ useEffect(() => {
63
+ if (activeTabKey) {
64
+ setInternalActiveKey(activeTabKey);
65
+ }
66
+ }, [activeTabKey]);
67
+
68
+ const [modalVisible, setModalVisible] = useState(false);
69
+ const [modalInitialIndex, setModalInitialIndex] = useState(0);
70
+
71
+ const displayImages = images.length ? images.slice(0, 6) : FALLBACK_IMAGES;
72
+
73
+ const contentHorizontalPadding = (sizes.lg as number) * 2;
74
+ const gutter = (sizes.xs as number) * 2;
75
+ const imageSize = Math.max(
76
+ 72,
77
+ Math.floor((width - contentHorizontalPadding - gutter * 2) / 3)
78
+ );
79
+
80
+ const handleTabPress = (tab: TabItem, index: number) => {
81
+ if (!activeTabKey) {
82
+ setInternalActiveKey(tab.key);
83
+ }
84
+ onTabPress?.(tab, index);
85
+ };
86
+
87
+ const handleOpenImage = (index: number) => {
88
+ setModalInitialIndex(index);
89
+ setModalVisible(true);
90
+ };
91
+
92
+ return (
93
+ <View style={styles.wrapper}>
94
+ <ScrollView
95
+ horizontal
96
+ showsHorizontalScrollIndicator={false}
97
+ contentContainerStyle={styles.navigationContainer}
98
+ >
99
+ {tabs.map((tab, index) => (
100
+ <ProfileMediaNavigationItem
101
+ key={tab.key}
102
+ label={tab.label}
103
+ iconName={tab.iconName}
104
+ isActive={internalActiveKey === tab.key}
105
+ onPress={() => handleTabPress(tab, index)}
106
+ />
107
+ ))}
108
+ </ScrollView>
109
+
110
+ <View style={styles.galleryContainer}>
111
+ {displayImages.map((uri, index) => (
112
+ <Pressable
113
+ key={`${uri}-${index}`}
114
+ onPress={() => handleOpenImage(index)}
115
+ style={[styles.imageWrapper, { width: imageSize, height: imageSize }]}
116
+ android_ripple={{ color: "#00000022" }}
117
+ >
118
+ <Image
119
+ source={{ uri }}
120
+ style={styles.image}
121
+ resizeMode="cover"
122
+ />
123
+ </Pressable>
124
+ ))}
125
+ </View>
126
+
127
+ <View style={styles.infoRow}>
128
+ <Text style={styles.infoLabel}>{extraInfoLabel}</Text>
129
+ <Pressable onPress={onExtraInfoPress}>
130
+ <Text style={styles.infoLink}>{extraInfoActionLabel}</Text>
131
+ </Pressable>
132
+ </View>
133
+
134
+ <View style={styles.actionsRow}>
135
+ <Pressable
136
+ onPress={onUploadPress}
137
+ style={[styles.actionButton, styles.primaryActionButton]}
138
+ >
139
+ <Text style={[styles.actionButtonText, styles.primaryActionButtonText]}>
140
+ {uploadButtonLabel}
141
+ </Text>
142
+ </Pressable>
143
+ <Pressable
144
+ onPress={onShowAllPress}
145
+ style={[styles.actionButton, styles.secondaryActionButton]}
146
+ >
147
+ <Text style={[styles.actionButtonText, styles.secondaryActionButtonText]}>
148
+ {showAllButtonLabel}
149
+ </Text>
150
+ </Pressable>
151
+ </View>
152
+
153
+ <GalleryModal
154
+ visible={modalVisible}
155
+ images={displayImages}
156
+ initialIndex={modalInitialIndex}
157
+ onRequestClose={() => setModalVisible(false)}
158
+ />
159
+ </View>
160
+ );
161
+ };
162
+
163
+ const getStyles = (theme: ThemeType, sizes: SizesType, typography: TypographytType) =>
164
+ StyleSheet.create({
165
+ wrapper: {
166
+ backgroundColor: theme.card,
167
+ borderRadius: sizes.radius_lg as number,
168
+ paddingVertical: sizes.lg as number,
169
+ paddingHorizontal: sizes.lg as number,
170
+ },
171
+ navigationContainer: {
172
+ paddingBottom: sizes.sm as number,
173
+ },
174
+ galleryContainer: {
175
+ flexDirection: "row",
176
+ flexWrap: "wrap",
177
+ justifyContent: "space-between",
178
+ },
179
+ imageWrapper: {
180
+ borderRadius: sizes.radius_sm as number,
181
+ overflow: "hidden",
182
+ marginBottom: sizes.sm as number,
183
+ backgroundColor: theme.backgroundSecond,
184
+ },
185
+ image: {
186
+ width: "100%",
187
+ height: "100%",
188
+ },
189
+ infoRow: {
190
+ flexDirection: "row",
191
+ alignItems: "center",
192
+ justifyContent: "space-between",
193
+ marginTop: sizes.xs as number,
194
+ marginBottom: sizes.md as number,
195
+ },
196
+ infoLabel: {
197
+ ...(typography.bodySm as object),
198
+ color: theme.text,
199
+ fontWeight: "500",
200
+ },
201
+ infoLink: {
202
+ ...(typography.textLink as object),
203
+ fontWeight: "600",
204
+ },
205
+ actionsRow: {
206
+ flexDirection: "row",
207
+ justifyContent: "space-between",
208
+ alignItems: "center",
209
+ marginTop: sizes.xs as number,
210
+ },
211
+ actionButton: {
212
+ flex: 1,
213
+ borderRadius: sizes.radius_sm as number,
214
+ paddingVertical: sizes.sm as number,
215
+ alignItems: "center",
216
+ justifyContent: "center",
217
+ },
218
+ primaryActionButton: {
219
+ backgroundColor: theme.primary,
220
+ marginRight: sizes.sm as number,
221
+ },
222
+ secondaryActionButton: {
223
+ backgroundColor: theme.backgroundSecond,
224
+ borderWidth: 1,
225
+ borderColor: theme.border,
226
+ },
227
+ actionButtonText: {
228
+ ...(typography.bodySm as object),
229
+ fontWeight: "600",
230
+ },
231
+ primaryActionButtonText: {
232
+ color: theme.white,
233
+ },
234
+ secondaryActionButtonText: {
235
+ color: theme.text,
236
+ },
237
+ });
238
+
239
+ export default ProfileMediaGallery;
@@ -0,0 +1,73 @@
1
+ import React, { memo, useMemo } from "react";
2
+ import { Pressable, StyleSheet, Text, View } from "react-native";
3
+ import { MaterialIcons } from "@expo/vector-icons";
4
+ import { ThemeType, SizesType, TypographytType, useTheme } from "../../theme";
5
+
6
+ type IconName = React.ComponentProps<typeof MaterialIcons>["name"];
7
+
8
+ export type ProfileMediaNavigationItemProps = {
9
+ label: string;
10
+ iconName?: IconName;
11
+ isActive?: boolean;
12
+ onPress?: () => void;
13
+ };
14
+
15
+ export const ProfileMediaNavigationItem = memo(
16
+ ({ label, iconName = "photo", isActive = false, onPress }: ProfileMediaNavigationItemProps) => {
17
+ const { theme, sizes, typography } = useTheme();
18
+
19
+ const styles = useMemo(() => getStyles(theme, sizes, typography), [theme, sizes, typography]);
20
+
21
+ return (
22
+ <Pressable
23
+ onPress={onPress}
24
+ style={[styles.container, isActive ? styles.containerActive : styles.containerInactive]}
25
+ accessibilityRole="button"
26
+ accessibilityState={{ selected: isActive }}
27
+ >
28
+ {iconName ? (
29
+ <View style={styles.iconWrapper}>
30
+ <MaterialIcons
31
+ name={iconName}
32
+ size={20}
33
+ color={isActive ? theme.primary : theme.greyText}
34
+ />
35
+ </View>
36
+ ) : null}
37
+ <Text style={[styles.label, { color: isActive ? theme.primary : theme.greyText }]}>{label}</Text>
38
+ </Pressable>
39
+ );
40
+ }
41
+ );
42
+
43
+ ProfileMediaNavigationItem.displayName = "ProfileMediaNavigationItem";
44
+
45
+ const getStyles = (theme: ThemeType, sizes: SizesType, typography: TypographytType) =>
46
+ StyleSheet.create({
47
+ container: {
48
+ flexDirection: "row",
49
+ alignItems: "center",
50
+ borderRadius: sizes.radius_sm as number,
51
+ paddingHorizontal: sizes.md as number,
52
+ paddingVertical: sizes.xs as number,
53
+ marginRight: sizes.sm as number,
54
+ borderWidth: 1,
55
+ },
56
+ containerActive: {
57
+ backgroundColor: theme.white,
58
+ borderColor: theme.primary,
59
+ },
60
+ containerInactive: {
61
+ backgroundColor: theme.backgroundSecond,
62
+ borderColor: theme.border,
63
+ },
64
+ iconWrapper: {
65
+ marginRight: sizes.xs as number,
66
+ },
67
+ label: {
68
+ ...(typography.bodySm as object),
69
+ fontWeight: "500",
70
+ },
71
+ });
72
+
73
+ export default ProfileMediaNavigationItem;
@@ -0,0 +1,97 @@
1
+ import React, { memo, useMemo } from "react";
2
+ import { Image, Pressable, StyleSheet, View, StyleProp, ViewStyle } from "react-native";
3
+ import { GalleryModal } from "../Modals";
4
+ import { ThemeType, SizesType, useTheme } from "../../theme";
5
+
6
+ type BaseProps = {
7
+ photos: string[];
8
+ columns?: number;
9
+ itemSize: number;
10
+ gap?: number;
11
+ visible: boolean;
12
+ initialIndex: number;
13
+ onOpenAt: (index: number) => void;
14
+ onClose: () => void;
15
+ };
16
+
17
+ export type ProfileSelfiesGalleryViewProps = BaseProps & {
18
+ style?: StyleProp<ViewStyle>;
19
+ };
20
+
21
+ export const ProfileSelfiesGalleryView = memo(
22
+ ({
23
+ photos,
24
+ columns = 2,
25
+ itemSize,
26
+ gap,
27
+ visible,
28
+ initialIndex,
29
+ onOpenAt,
30
+ onClose,
31
+ style,
32
+ }: ProfileSelfiesGalleryViewProps) => {
33
+ const { theme, sizes } = useTheme();
34
+ const spacing = gap ?? ((sizes.sm as number) * 1.25);
35
+
36
+ const styles = useMemo(() => getStyles(theme, sizes, spacing), [theme, sizes, spacing]);
37
+
38
+ return (
39
+ <View style={[styles.wrapper, style]}>
40
+ <View style={styles.grid}>
41
+ {photos.map((photo, index) => {
42
+ const isLastInRow = (index + 1) % columns === 0;
43
+
44
+ return (
45
+ <Pressable
46
+ key={`${photo}-${index}`}
47
+ onPress={() => onOpenAt(index)}
48
+ android_ripple={{ color: "#00000022" }}
49
+ style={[
50
+ styles.imageWrapper,
51
+ { width: itemSize, height: itemSize, marginRight: isLastInRow ? 0 : spacing },
52
+ ]}
53
+ >
54
+ <Image source={{ uri: photo }} style={styles.image} resizeMode="cover" />
55
+ </Pressable>
56
+ );
57
+ })}
58
+ </View>
59
+
60
+ <GalleryModal
61
+ visible={visible}
62
+ images={photos}
63
+ initialIndex={initialIndex}
64
+ onRequestClose={onClose}
65
+ />
66
+ </View>
67
+ );
68
+ }
69
+ );
70
+
71
+ ProfileSelfiesGalleryView.displayName = "ProfileSelfiesGalleryView";
72
+
73
+ const getStyles = (theme: ThemeType, sizes: SizesType, spacing: number) =>
74
+ StyleSheet.create({
75
+ wrapper: {
76
+ backgroundColor: theme.card,
77
+ borderRadius: (sizes.radius_lg as number) + 4,
78
+ padding: sizes.lg as number,
79
+ },
80
+ grid: {
81
+ flexDirection: "row",
82
+ flexWrap: "wrap",
83
+ justifyContent: "flex-start",
84
+ },
85
+ imageWrapper: {
86
+ borderRadius: (sizes.radius_lg as number) + 2,
87
+ overflow: "hidden",
88
+ marginBottom: spacing,
89
+ backgroundColor: theme.backgroundSecond,
90
+ },
91
+ image: {
92
+ width: "100%",
93
+ height: "100%",
94
+ },
95
+ });
96
+
97
+ export default ProfileSelfiesGalleryView;
@@ -0,0 +1,86 @@
1
+ import React, { useState, useMemo } from 'react';
2
+ import { Meta, StoryFn } from '@storybook/react';
3
+ import { Dimensions, View } from 'react-native';
4
+ import { ThemeProvider } from '../../theme';
5
+ import { ProfileSelfiesGalleryView } from './ProfileSelfiesGallery.pure';
6
+
7
+ type Props = React.ComponentProps<typeof ProfileSelfiesGalleryView>;
8
+
9
+ const WINDOW_WIDTH = Dimensions.get('window').width;
10
+
11
+ const meta: Meta<Props> = {
12
+ title: 'Features/Gallery/ProfileSelfiesGallery',
13
+ component: ProfileSelfiesGalleryView,
14
+ decorators: [
15
+ (Story) => (
16
+ <ThemeProvider>
17
+ <View style={{ paddingVertical: 24, paddingHorizontal: 16 }}>
18
+ <Story />
19
+ </View>
20
+ </ThemeProvider>
21
+ ),
22
+ ],
23
+ args: {
24
+ columns: 2,
25
+ },
26
+ };
27
+
28
+ export default meta;
29
+
30
+ const Template: StoryFn<Props> = ({
31
+ visible: _visible,
32
+ initialIndex: _initialIndex,
33
+ onOpenAt: _onOpenAt,
34
+ onClose: _onClose,
35
+ itemSize: _itemSize,
36
+ ...rest
37
+ }) => {
38
+ const [visible, setVisible] = useState(false);
39
+ const [initialIndex, setInitialIndex] = useState(0);
40
+
41
+ const itemSize = useMemo(() => {
42
+ const decoratorPadding = 32; // paddingHorizontal from decorator View (16 * 2)
43
+ const wrapperPadding = 40; // padding from component wrapper (20 * 2)
44
+ const gap = rest.gap ?? 15; // default spacing from component
45
+ const columns = rest.columns ?? 2;
46
+
47
+ return Math.floor((WINDOW_WIDTH - decoratorPadding - wrapperPadding - gap * (columns - 1)) / columns);
48
+ }, [rest.columns, rest.gap]);
49
+
50
+ return (
51
+ <ProfileSelfiesGalleryView
52
+ {...rest}
53
+ itemSize={itemSize}
54
+ visible={visible}
55
+ initialIndex={initialIndex}
56
+ onOpenAt={(index) => {
57
+ setInitialIndex(index);
58
+ setVisible(true);
59
+ }}
60
+ onClose={() => setVisible(false)}
61
+ />
62
+ );
63
+ };
64
+
65
+ export const Default = Template.bind({});
66
+ Default.args = {
67
+ photos: [
68
+ 'https://images.unsplash.com/photo-1690733583113-10a2dbd4c3fb?auto=format&fit=crop&w=800&q=80',
69
+ 'https://images.unsplash.com/photo-1633332755192-727a05c4013d?auto=format&fit=crop&w=800&q=80',
70
+ 'https://images.unsplash.com/photo-1544723795-3fb6469f5b39?auto=format&fit=crop&w=800&q=80',
71
+ 'https://images.unsplash.com/photo-1517841905240-472988babdf9?auto=format&fit=crop&w=800&q=80',
72
+ 'https://images.unsplash.com/photo-1524504388940-b1c1722653e1?auto=format&fit=crop&w=800&q=80',
73
+ 'https://images.unsplash.com/photo-1520813792240-56fc4a3765a7?auto=format&fit=crop&w=800&q=80',
74
+ ],
75
+ };
76
+
77
+ export const WithCustomGap = Template.bind({});
78
+ WithCustomGap.args = {
79
+ gap: 12,
80
+ photos: [
81
+ 'https://images.unsplash.com/photo-1544005313-94ddf0286df2?auto=format&fit=crop&w=800&q=80',
82
+ 'https://images.unsplash.com/photo-1531256456869-ce942a665e80?auto=format&fit=crop&w=800&q=80',
83
+ 'https://images.unsplash.com/photo-1524504388940-b1c1722653e1?auto=format&fit=crop&w=800&q=80',
84
+ 'https://images.unsplash.com/photo-1531891437562-4301cf35b7e4?auto=format&fit=crop&w=800&q=80',
85
+ ],
86
+ };
@@ -1 +1,4 @@
1
- export * from "./AiAgentGallery.pure"
1
+ export * from "./AiAgentGallery.pure";
2
+ export * from "./ProfileMediaGallery";
3
+ export * from "./ProfileMediaNavigationItem";
4
+ export * from "./ProfileSelfiesGallery.pure";
@@ -4,7 +4,7 @@ import { Text, TouchableOpacity, View } from 'react-native';
4
4
  import HeaderDefault, { AccessType } from './HeaderDefault';
5
5
 
6
6
  const meta: Meta = {
7
- title: 'Header/HeaderDefault',
7
+ title: 'Layout/Header/HeaderDefault',
8
8
  component: HeaderDefault,
9
9
  args: {
10
10
  title: 'Community event',
@@ -4,7 +4,7 @@ import { View } from 'react-native';
4
4
  import { HeaderEdit } from './HeaderEdit';
5
5
 
6
6
  const meta: Meta = {
7
- title: 'Header/HeaderEdit',
7
+ title: 'Layout/Header/HeaderEdit',
8
8
  component: HeaderEdit,
9
9
  args: {
10
10
  isPinned: false,
@@ -4,7 +4,7 @@ import { Text, View } from 'react-native';
4
4
  import { HeaderHome } from './HeaderHome';
5
5
 
6
6
  const meta: Meta<typeof HeaderHome> = {
7
- title: 'Header/HeaderHome',
7
+ title: 'Layout/Header/HeaderHome',
8
8
  component: HeaderHome,
9
9
  argTypes: {
10
10
  onPress: { action: 'header press' },
@@ -4,7 +4,7 @@ import { View, Text } from 'react-native';
4
4
  import { HeaderSwitcher } from './HeaderSwitcher';
5
5
 
6
6
  const meta: Meta<typeof HeaderSwitcher> = {
7
- title: 'Header/HeaderSwitcher',
7
+ title: 'Layout/Header/HeaderSwitcher',
8
8
  component: HeaderSwitcher,
9
9
  args: {
10
10
  isFirst: true,
@@ -4,7 +4,7 @@ import { View } from 'react-native';
4
4
  import HeaderWithImg from './HeaderWithImg';
5
5
 
6
6
  const meta: Meta = {
7
- title: 'Header/HeaderWithImg',
7
+ title: 'Layout/Header/HeaderWithImg',
8
8
  component: HeaderWithImg,
9
9
  args: {
10
10
  imgUrl: 'https://placekitten.com/200/200',
@@ -10,7 +10,7 @@ const IMAGES = [
10
10
  ];
11
11
 
12
12
  const meta = {
13
- title: 'Modals/GalleryModal',
13
+ title: 'Features/Modals/GalleryModal',
14
14
  component: GalleryModal,
15
15
  decorators: [(Story) => <View style={{ flex: 1 }}><Story /></View>],
16
16
  argTypes: { onRequestClose: { action: 'onRequestClose' } },
@@ -24,7 +24,7 @@ const sampleMessages: PureChatMessage[] = [
24
24
  const defaultLimitLabel = (remaining: number, limit: number) => `Осталось сообщений: ${remaining} / ${limit}`;
25
25
 
26
26
  const meta = {
27
- title: 'Modals/GuestAiChatModal',
27
+ title: 'Features/Modals/GuestAiChatModal',
28
28
  component: GuestAiChatModalView,
29
29
  argTypes: {
30
30
  onClose: { action: 'close modal' },
@@ -31,7 +31,7 @@ const postReasonOptions = [
31
31
  ];
32
32
 
33
33
  const meta: Meta<ReportModalProps> = {
34
- title: 'Modals/ReportModal',
34
+ title: 'Features/Modals/ReportModal',
35
35
  component: ReportModal,
36
36
  argTypes: {
37
37
  type: {
@@ -62,7 +62,7 @@ const ReportModal: React.FC<Props> = ({
62
62
  <View style={styles.container}>
63
63
  <Text style={styles.title}>{title}</Text>
64
64
  <ScrollView style={styles.reasonsContainer}>
65
- {reasons.map((reason) => (
65
+ {reasons?.map((reason) => (
66
66
  <TouchableOpacity
67
67
  key={reason}
68
68
  style={[
@@ -46,7 +46,7 @@ const generateComments = (count: number): Comment[] =>
46
46
  }));
47
47
 
48
48
  const meta: Meta<Props> = {
49
- title: 'Poll/CommentItem',
49
+ title: 'Features/Poll/CommentItem',
50
50
  component: CommentItem,
51
51
  decorators: [
52
52
  (Story) => (
@@ -4,7 +4,7 @@ import { View } from 'react-native';
4
4
  import PollCardList from './PollCardList';
5
5
 
6
6
  const meta: Meta<React.ComponentProps<typeof PollCardList>> = {
7
- title: 'Poll/PollCardList',
7
+ title: 'Features/Poll/PollCardList',
8
8
  component: PollCardList,
9
9
  decorators: [
10
10
  (Story) => (
@@ -7,7 +7,7 @@ import EventCardList from './EventCardList';
7
7
  type Props = React.ComponentProps<typeof EventCardList>;
8
8
 
9
9
  const meta: Meta<Props> = {
10
- title: 'Posts/EventCardList',
10
+ title: 'Features/Posts/EventCardList',
11
11
  component: EventCardList,
12
12
  decorators: [
13
13
  (Story) => (
@@ -4,7 +4,7 @@ import { View } from 'react-native';
4
4
  import PlaceCardList from './PlaceCardList';
5
5
 
6
6
  const meta: Meta<React.ComponentProps<typeof PlaceCardList>> = {
7
- title: 'Posts/PlaceCardList',
7
+ title: 'Features/Posts/PlaceCardList',
8
8
  component: PlaceCardList,
9
9
  decorators: [
10
10
  (Story) => (
@@ -0,0 +1,47 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import React from 'react';
3
+ import { View } from 'react-native';
4
+
5
+ import { ThemeProvider } from '../../theme';
6
+ import HeroPrankCard from './HeroPrankCard';
7
+
8
+ const meta: Meta<typeof HeroPrankCard> = {
9
+ title: 'Features/Prank/HeroPrankCard',
10
+ component: HeroPrankCard,
11
+ decorators: [
12
+ (Story) => (
13
+ <ThemeProvider>
14
+ <View style={{ padding: 24, backgroundColor: '#070C1F', flex: 1 }}>
15
+ <Story />
16
+ </View>
17
+ </ThemeProvider>
18
+ ),
19
+ ],
20
+ args: {
21
+ imageUri:
22
+ 'https://images.unsplash.com/photo-1621447462558-42b4d8bc5d9b?auto=format&fit=crop&w=900&q=80',
23
+ title: 'Homeless Prank',
24
+ description: 'Prank your loved ones with a unknown guest in your home!',
25
+ },
26
+ parameters: {
27
+ backgrounds: {
28
+ default: 'dark',
29
+ values: [
30
+ { name: 'dark', value: '#070C1F' },
31
+ { name: 'light', value: '#f5f5f5' },
32
+ ],
33
+ },
34
+ },
35
+ };
36
+
37
+ export default meta;
38
+
39
+ type Story = StoryObj<typeof HeroPrankCard>;
40
+
41
+ export const Default: Story = {};
42
+
43
+ export const WithAction: Story = {
44
+ args: {
45
+ onPress: () => console.log('Hero card pressed'),
46
+ },
47
+ };