@campxdev/react-native-blueprint 0.1.16 → 0.1.18
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.
- package/lib/global.css +672 -0
- package/lib/module/components/DataDisplay/FeedCard/FeedCard.figma.js +42 -0
- package/lib/module/components/DataDisplay/FeedCard/FeedCard.figma.js.map +1 -0
- package/lib/module/components/DataDisplay/FeedCard/FeedCard.js +261 -0
- package/lib/module/components/DataDisplay/FeedCard/FeedCard.js.map +1 -0
- package/lib/module/components/DataDisplay/Greeting/Greeting.figma.js +8 -1
- package/lib/module/components/DataDisplay/Greeting/Greeting.figma.js.map +1 -1
- package/lib/module/components/DataDisplay/Greeting/Greeting.js +75 -21
- package/lib/module/components/DataDisplay/Greeting/Greeting.js.map +1 -1
- package/lib/module/components/ui/index.js +1 -0
- package/lib/module/components/ui/index.js.map +1 -1
- package/package.json +4 -3
- package/src/components/DataDisplay/FeedCard/FeedCard.figma.tsx +43 -0
- package/src/components/DataDisplay/FeedCard/FeedCard.tsx +376 -0
- package/src/components/DataDisplay/Greeting/Greeting.figma.tsx +10 -2
- package/src/components/DataDisplay/Greeting/Greeting.tsx +107 -26
- package/src/components/ui/index.ts +1 -0
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import {
|
|
3
|
+
View as RNView,
|
|
4
|
+
Text as RNTextBase,
|
|
5
|
+
Image as RNImage,
|
|
6
|
+
type ImageSourcePropType,
|
|
7
|
+
type StyleProp,
|
|
8
|
+
type ViewStyle,
|
|
9
|
+
} from 'react-native';
|
|
10
|
+
import { cssInterop } from 'nativewind';
|
|
11
|
+
import { cva } from 'class-variance-authority';
|
|
12
|
+
|
|
13
|
+
import { cn } from '../../../lib/utils';
|
|
14
|
+
import { Button } from '../../Input/Button/Button';
|
|
15
|
+
import { Badge } from '../Badge/Badge';
|
|
16
|
+
import { Text } from '../../Input/Text/Text';
|
|
17
|
+
import { Avatar } from '../Avatar/Avatar';
|
|
18
|
+
import { AspectRatio } from '../../Layout/AspectRatio/Aspect-Ratio';
|
|
19
|
+
|
|
20
|
+
// Default placeholder image
|
|
21
|
+
const DEFAULT_MEDIA_IMAGE =
|
|
22
|
+
'https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe3e?w=400&h=224&fit=crop';
|
|
23
|
+
|
|
24
|
+
// NativeWind interop (className -> style)
|
|
25
|
+
const View = cssInterop(RNView, { className: 'style' });
|
|
26
|
+
const RNText = cssInterop(RNTextBase, { className: 'style' });
|
|
27
|
+
const Image = cssInterop(RNImage, { className: 'style' });
|
|
28
|
+
|
|
29
|
+
/* ============================================================================
|
|
30
|
+
* VARIANTS
|
|
31
|
+
* ============================================================================ */
|
|
32
|
+
|
|
33
|
+
export const FeedCardVariants = {
|
|
34
|
+
type: ['post', 'announcement'] as const,
|
|
35
|
+
} as const;
|
|
36
|
+
|
|
37
|
+
type FeedCardType = (typeof FeedCardVariants.type)[number];
|
|
38
|
+
|
|
39
|
+
const rootVariants = cva('w-full overflow-hidden rounded-3xl', {
|
|
40
|
+
variants: {
|
|
41
|
+
type: {
|
|
42
|
+
post: 'bg-surface-default',
|
|
43
|
+
announcement: 'bg-surface-default border border-border-default',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
defaultVariants: {
|
|
47
|
+
type: 'post',
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const metaRowVariants = cva('w-full flex-row p-4', {
|
|
52
|
+
variants: {
|
|
53
|
+
type: {
|
|
54
|
+
post: 'items-center gap-2',
|
|
55
|
+
announcement: 'items-center justify-between',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
defaultVariants: {
|
|
59
|
+
type: 'post',
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const mediaWrapVariants = cva('w-full overflow-hidden px-4 pb-4');
|
|
64
|
+
|
|
65
|
+
const contentWrapVariants = cva('w-full px-4 pb-4 flex-col');
|
|
66
|
+
|
|
67
|
+
const headerVariants = cva('w-full gap-1 flex-col');
|
|
68
|
+
|
|
69
|
+
const titleVariants = cva('text-base font-semibold text-text-primary');
|
|
70
|
+
|
|
71
|
+
const subtitleVariants = cva('text-xs font-medium text-text-secondary');
|
|
72
|
+
|
|
73
|
+
const bodyVariants = cva('text-sm font-medium text-text-primary');
|
|
74
|
+
|
|
75
|
+
const badgesRowVariants = cva('w-full flex-row items-start gap-2 pb-4 px-4');
|
|
76
|
+
|
|
77
|
+
const footerRowVariants = cva(
|
|
78
|
+
'w-full flex-row items-center justify-between px-4 pb-4'
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const leftButtonsVariants = cva('flex-row items-center gap-2');
|
|
82
|
+
|
|
83
|
+
const rightButtonsVariants = cva('flex-row items-center');
|
|
84
|
+
|
|
85
|
+
/* ============================================================================
|
|
86
|
+
* HELPERS
|
|
87
|
+
* ============================================================================ */
|
|
88
|
+
|
|
89
|
+
function normalizeType(v: any): FeedCardType {
|
|
90
|
+
const s = String(v ?? 'post').toLowerCase();
|
|
91
|
+
return s === 'announcement' ? 'announcement' : 'post';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* ============================================================================
|
|
95
|
+
* PROPS
|
|
96
|
+
* ============================================================================ */
|
|
97
|
+
|
|
98
|
+
export type FeedCardProps = {
|
|
99
|
+
/** Author/creator name */
|
|
100
|
+
authorName?: string;
|
|
101
|
+
|
|
102
|
+
/** Post/announcement title */
|
|
103
|
+
postTitle?: string;
|
|
104
|
+
|
|
105
|
+
/** Subtitle below title */
|
|
106
|
+
subtitle?: string;
|
|
107
|
+
|
|
108
|
+
/** Main body content */
|
|
109
|
+
postContent?: string;
|
|
110
|
+
|
|
111
|
+
/** Optional image/media */
|
|
112
|
+
image?: ImageSourcePropType;
|
|
113
|
+
|
|
114
|
+
/** Card type variant */
|
|
115
|
+
type?: FeedCardType | 'Post' | 'Announcement';
|
|
116
|
+
|
|
117
|
+
/** Visibility toggles */
|
|
118
|
+
showHeader?: boolean;
|
|
119
|
+
showLeading?: boolean;
|
|
120
|
+
showMedia?: boolean;
|
|
121
|
+
showPostContent?: boolean;
|
|
122
|
+
showSubtitle?: boolean;
|
|
123
|
+
showBadges?: boolean;
|
|
124
|
+
showFooterActions?: boolean;
|
|
125
|
+
showSecondaryButton?: boolean;
|
|
126
|
+
|
|
127
|
+
/** Badge labels */
|
|
128
|
+
badge1Text?: string;
|
|
129
|
+
badge2Text?: string;
|
|
130
|
+
|
|
131
|
+
/** Button labels */
|
|
132
|
+
primaryActionText?: string;
|
|
133
|
+
secondaryActionText?: string;
|
|
134
|
+
tertiaryActionText?: string;
|
|
135
|
+
|
|
136
|
+
/** Callbacks */
|
|
137
|
+
onPrimaryActionPress?: () => void;
|
|
138
|
+
onSecondaryActionPress?: () => void;
|
|
139
|
+
onTertiaryActionPress?: () => void;
|
|
140
|
+
|
|
141
|
+
/** Styling */
|
|
142
|
+
style?: StyleProp<ViewStyle>;
|
|
143
|
+
testID?: string;
|
|
144
|
+
className?: never;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
/* ============================================================================
|
|
148
|
+
* COMPONENT
|
|
149
|
+
* ============================================================================ */
|
|
150
|
+
|
|
151
|
+
export function FeedCard(props: FeedCardProps) {
|
|
152
|
+
const {
|
|
153
|
+
authorName = 'Author Name',
|
|
154
|
+
postTitle = 'Post Title',
|
|
155
|
+
subtitle = 'Subtitle of the card goes here',
|
|
156
|
+
postContent = 'The card may contain body content which can be truncated to 1-2 lines. Swap Content in Props.',
|
|
157
|
+
image,
|
|
158
|
+
|
|
159
|
+
type = 'post',
|
|
160
|
+
|
|
161
|
+
showHeader = true,
|
|
162
|
+
showLeading = true,
|
|
163
|
+
showMedia = true,
|
|
164
|
+
showPostContent = true,
|
|
165
|
+
showSubtitle = true,
|
|
166
|
+
showBadges = true,
|
|
167
|
+
showFooterActions = true,
|
|
168
|
+
showSecondaryButton = true,
|
|
169
|
+
|
|
170
|
+
badge1Text = 'Badge',
|
|
171
|
+
badge2Text = 'Badge',
|
|
172
|
+
|
|
173
|
+
primaryActionText = 'Button',
|
|
174
|
+
secondaryActionText = 'Button',
|
|
175
|
+
|
|
176
|
+
onPrimaryActionPress,
|
|
177
|
+
onSecondaryActionPress,
|
|
178
|
+
onTertiaryActionPress,
|
|
179
|
+
|
|
180
|
+
style,
|
|
181
|
+
testID,
|
|
182
|
+
} = props;
|
|
183
|
+
|
|
184
|
+
const cardType = normalizeType(type);
|
|
185
|
+
const isAnnouncement = cardType === 'announcement';
|
|
186
|
+
|
|
187
|
+
return (
|
|
188
|
+
<View
|
|
189
|
+
testID={testID ?? 'feed-card'}
|
|
190
|
+
className={cn(rootVariants({ type: cardType }))}
|
|
191
|
+
style={style}
|
|
192
|
+
>
|
|
193
|
+
{/* Meta Section: Author Info */}
|
|
194
|
+
<View
|
|
195
|
+
testID="feed-card-meta"
|
|
196
|
+
className={cn(metaRowVariants({ type: cardType }))}
|
|
197
|
+
>
|
|
198
|
+
{showLeading && (
|
|
199
|
+
<View
|
|
200
|
+
testID="feed-card-leading"
|
|
201
|
+
className="items-center justify-center"
|
|
202
|
+
>
|
|
203
|
+
<Avatar
|
|
204
|
+
initials={(authorName ?? 'AA').slice(0, 2).toUpperCase()}
|
|
205
|
+
size="Default"
|
|
206
|
+
type="Initials"
|
|
207
|
+
/>
|
|
208
|
+
</View>
|
|
209
|
+
)}
|
|
210
|
+
|
|
211
|
+
{/* Author Details */}
|
|
212
|
+
<View testID="feed-card-author" className="flex-col flex-1 gap-0.5">
|
|
213
|
+
<RNText
|
|
214
|
+
testID="feed-card-author-name"
|
|
215
|
+
numberOfLines={1}
|
|
216
|
+
className="text-sm font-semibold text-text-primary"
|
|
217
|
+
>
|
|
218
|
+
{authorName}
|
|
219
|
+
</RNText>
|
|
220
|
+
<RNText
|
|
221
|
+
testID="feed-card-timestamp"
|
|
222
|
+
numberOfLines={1}
|
|
223
|
+
className="text-xs font-normal text-text-secondary"
|
|
224
|
+
>
|
|
225
|
+
Posted 1 day ago
|
|
226
|
+
</RNText>
|
|
227
|
+
</View>
|
|
228
|
+
|
|
229
|
+
{/* Announcement Badge */}
|
|
230
|
+
{isAnnouncement && (
|
|
231
|
+
<Badge
|
|
232
|
+
testID="feed-card-type-badge"
|
|
233
|
+
variant="default"
|
|
234
|
+
size="sm"
|
|
235
|
+
showLeftIcon={false}
|
|
236
|
+
showRightIcon={false}
|
|
237
|
+
>
|
|
238
|
+
<Text>Announcement</Text>
|
|
239
|
+
</Badge>
|
|
240
|
+
)}
|
|
241
|
+
</View>
|
|
242
|
+
|
|
243
|
+
{/* Media Section */}
|
|
244
|
+
{showMedia && (
|
|
245
|
+
<View testID="feed-card-media-wrap" className={cn(mediaWrapVariants())}>
|
|
246
|
+
<AspectRatio variant="16:9">
|
|
247
|
+
<View className="w-full h-full bg-surface-subtle rounded-3xl overflow-hidden">
|
|
248
|
+
<Image
|
|
249
|
+
testID="feed-card-media"
|
|
250
|
+
source={image || { uri: DEFAULT_MEDIA_IMAGE }}
|
|
251
|
+
resizeMode="cover"
|
|
252
|
+
className="w-full h-full"
|
|
253
|
+
/>
|
|
254
|
+
</View>
|
|
255
|
+
</AspectRatio>
|
|
256
|
+
</View>
|
|
257
|
+
)}
|
|
258
|
+
|
|
259
|
+
{/* Content Section */}
|
|
260
|
+
{showPostContent && (
|
|
261
|
+
<View testID="feed-card-content" className={cn(contentWrapVariants())}>
|
|
262
|
+
{/* Header: Title + Subtitle */}
|
|
263
|
+
{showHeader && (
|
|
264
|
+
<View testID="feed-card-header" className={cn(headerVariants())}>
|
|
265
|
+
<RNText
|
|
266
|
+
testID="feed-card-title"
|
|
267
|
+
numberOfLines={1}
|
|
268
|
+
className={cn(titleVariants())}
|
|
269
|
+
>
|
|
270
|
+
{postTitle}
|
|
271
|
+
</RNText>
|
|
272
|
+
|
|
273
|
+
{showSubtitle && (
|
|
274
|
+
<RNText
|
|
275
|
+
testID="feed-card-subtitle"
|
|
276
|
+
numberOfLines={1}
|
|
277
|
+
className={cn(subtitleVariants())}
|
|
278
|
+
>
|
|
279
|
+
{subtitle}
|
|
280
|
+
</RNText>
|
|
281
|
+
)}
|
|
282
|
+
</View>
|
|
283
|
+
)}
|
|
284
|
+
|
|
285
|
+
{/* Body */}
|
|
286
|
+
<RNText
|
|
287
|
+
testID="feed-card-body"
|
|
288
|
+
numberOfLines={2}
|
|
289
|
+
className={cn(bodyVariants())}
|
|
290
|
+
>
|
|
291
|
+
{postContent}
|
|
292
|
+
</RNText>
|
|
293
|
+
</View>
|
|
294
|
+
)}
|
|
295
|
+
|
|
296
|
+
{/* Badges Section */}
|
|
297
|
+
{showBadges && (
|
|
298
|
+
<View testID="feed-card-badges" className={cn(badgesRowVariants())}>
|
|
299
|
+
<Badge
|
|
300
|
+
testID="feed-card-badge-1"
|
|
301
|
+
variant="default"
|
|
302
|
+
size="sm"
|
|
303
|
+
showLeftIcon={false}
|
|
304
|
+
showRightIcon={false}
|
|
305
|
+
>
|
|
306
|
+
<Text>{badge1Text}</Text>
|
|
307
|
+
</Badge>
|
|
308
|
+
<Badge
|
|
309
|
+
testID="feed-card-badge-2"
|
|
310
|
+
variant="default"
|
|
311
|
+
size="sm"
|
|
312
|
+
showLeftIcon={false}
|
|
313
|
+
showRightIcon={false}
|
|
314
|
+
>
|
|
315
|
+
<Text>{badge2Text}</Text>
|
|
316
|
+
</Badge>
|
|
317
|
+
</View>
|
|
318
|
+
)}
|
|
319
|
+
|
|
320
|
+
{/* Footer Actions */}
|
|
321
|
+
{showFooterActions && (
|
|
322
|
+
<View testID="feed-card-footer" className={cn(footerRowVariants())}>
|
|
323
|
+
<View
|
|
324
|
+
testID="feed-card-footer-left"
|
|
325
|
+
className={cn(leftButtonsVariants())}
|
|
326
|
+
>
|
|
327
|
+
<Button
|
|
328
|
+
testID="feed-card-primary-action"
|
|
329
|
+
disabled={false}
|
|
330
|
+
size="default"
|
|
331
|
+
variant="default"
|
|
332
|
+
showLeftIcon={false}
|
|
333
|
+
showRightIcon={false}
|
|
334
|
+
onPress={onPrimaryActionPress}
|
|
335
|
+
>
|
|
336
|
+
{primaryActionText}
|
|
337
|
+
</Button>
|
|
338
|
+
|
|
339
|
+
{showSecondaryButton && (
|
|
340
|
+
<Button
|
|
341
|
+
testID="feed-card-secondary-action"
|
|
342
|
+
disabled={false}
|
|
343
|
+
size="default"
|
|
344
|
+
variant="secondary"
|
|
345
|
+
showLeftIcon={false}
|
|
346
|
+
showRightIcon={false}
|
|
347
|
+
onPress={onSecondaryActionPress}
|
|
348
|
+
>
|
|
349
|
+
{secondaryActionText}
|
|
350
|
+
</Button>
|
|
351
|
+
)}
|
|
352
|
+
</View>
|
|
353
|
+
|
|
354
|
+
<View
|
|
355
|
+
testID="feed-card-footer-right"
|
|
356
|
+
className={cn(rightButtonsVariants())}
|
|
357
|
+
>
|
|
358
|
+
<Button
|
|
359
|
+
testID="feed-card-tertiary-action"
|
|
360
|
+
disabled={false}
|
|
361
|
+
size="icon"
|
|
362
|
+
variant="secondary"
|
|
363
|
+
showLeftIcon={false}
|
|
364
|
+
showRightIcon={false}
|
|
365
|
+
onPress={onTertiaryActionPress}
|
|
366
|
+
/>
|
|
367
|
+
</View>
|
|
368
|
+
</View>
|
|
369
|
+
)}
|
|
370
|
+
</View>
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
FeedCard.displayName = 'FeedCard';
|
|
375
|
+
|
|
376
|
+
export type { FeedCardProps };
|
|
@@ -2,11 +2,19 @@ import figma from '@figma/code-connect';
|
|
|
2
2
|
import { Greeting } from './Greeting';
|
|
3
3
|
|
|
4
4
|
const FIGMA_URL =
|
|
5
|
-
'https://www.figma.com/design/66WaqopqU3WXgwVtyQuTUf/React-Native-Blueprint-Library?node-id=
|
|
5
|
+
'https://www.figma.com/design/66WaqopqU3WXgwVtyQuTUf/React-Native-Blueprint-Library?node-id=495-8995';
|
|
6
6
|
|
|
7
7
|
figma.connect(Greeting, FIGMA_URL, {
|
|
8
8
|
props: {
|
|
9
|
+
ctaLayout: figma.enum('CTA Layout', {
|
|
10
|
+
'icon': 'icon',
|
|
11
|
+
'none': 'none',
|
|
12
|
+
'floating': 'floating',
|
|
13
|
+
'ai summary': 'ai summary',
|
|
14
|
+
}),
|
|
9
15
|
showNextUp: figma.boolean('Show NextUp'),
|
|
10
16
|
},
|
|
11
|
-
example: (props) =>
|
|
17
|
+
example: (props) => (
|
|
18
|
+
<Greeting ctaLayout={props.ctaLayout} showNextUp={props.showNextUp} />
|
|
19
|
+
),
|
|
12
20
|
});
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
StyleSheet,
|
|
6
|
-
View as RNView,
|
|
7
|
-
} from 'react-native';
|
|
3
|
+
import { Pressable as RNPressable, View as RNView } from 'react-native';
|
|
4
|
+
import { LinearGradient } from 'expo-linear-gradient';
|
|
8
5
|
import { cssInterop } from 'nativewind';
|
|
9
6
|
import { Calendar } from 'lucide-react-native';
|
|
10
7
|
import { cn } from '../../../lib/utils';
|
|
11
8
|
import { Text } from '../../Input/Text/Text';
|
|
12
9
|
import { Icon } from '../../ui/Icon';
|
|
10
|
+
import { Button } from '../../Input/Button/Button';
|
|
13
11
|
|
|
14
12
|
cssInterop(RNView, { className: 'style' });
|
|
15
13
|
cssInterop(RNPressable, { className: 'style' });
|
|
14
|
+
cssInterop(LinearGradient, { className: 'style' });
|
|
16
15
|
|
|
17
16
|
const View = RNView as React.ComponentType<
|
|
18
17
|
React.ComponentProps<typeof RNView> & { className?: string }
|
|
@@ -31,7 +30,9 @@ export interface GreetingProps {
|
|
|
31
30
|
greetingText?: string;
|
|
32
31
|
/** Subtitle/secondary text below greeting */
|
|
33
32
|
subtitle?: string;
|
|
34
|
-
/**
|
|
33
|
+
/** CTA (Call-to-Action) layout style */
|
|
34
|
+
ctaLayout?: 'icon' | 'none' | 'floating' | 'ai summary';
|
|
35
|
+
/** Whether to show the schedule/calendar button - deprecated, use ctaLayout instead */
|
|
35
36
|
showScheduleButton?: boolean;
|
|
36
37
|
/** Callback when schedule button is pressed */
|
|
37
38
|
onSchedulePress?: () => void;
|
|
@@ -77,7 +78,8 @@ export function Greeting({
|
|
|
77
78
|
userName = 'Marshall',
|
|
78
79
|
greetingText = 'Good Morning',
|
|
79
80
|
subtitle = 'You have 3 Classes today',
|
|
80
|
-
|
|
81
|
+
ctaLayout = 'icon',
|
|
82
|
+
showScheduleButton,
|
|
81
83
|
onSchedulePress,
|
|
82
84
|
showNextUp = true,
|
|
83
85
|
nextUpTitle = 'Digital Logic Design',
|
|
@@ -85,16 +87,51 @@ export function Greeting({
|
|
|
85
87
|
className,
|
|
86
88
|
testID,
|
|
87
89
|
}: GreetingProps) {
|
|
90
|
+
// Handle backwards compatibility: showScheduleButton prop takes precedence if explicitly set
|
|
91
|
+
const effectiveCtaLayout =
|
|
92
|
+
showScheduleButton !== undefined
|
|
93
|
+
? showScheduleButton
|
|
94
|
+
? 'icon'
|
|
95
|
+
: 'none'
|
|
96
|
+
: ctaLayout;
|
|
97
|
+
|
|
98
|
+
const isAiSummary = effectiveCtaLayout === 'ai summary';
|
|
99
|
+
const isFloating = effectiveCtaLayout === 'floating';
|
|
100
|
+
const isIconOrFloatingOrNoneOrAiSummary = [
|
|
101
|
+
'icon',
|
|
102
|
+
'floating',
|
|
103
|
+
'none',
|
|
104
|
+
'ai summary',
|
|
105
|
+
].includes(effectiveCtaLayout);
|
|
106
|
+
const isNone = effectiveCtaLayout === 'none';
|
|
107
|
+
|
|
88
108
|
return (
|
|
89
109
|
<View
|
|
90
110
|
testID={testID}
|
|
91
111
|
className={cn(
|
|
92
|
-
'w-full max-w-[400px] flex-col
|
|
112
|
+
'w-full max-w-[400px] flex-col items-start justify-end bg-surface-default',
|
|
113
|
+
// Base styling based on ctaLayout
|
|
114
|
+
isAiSummary
|
|
115
|
+
? 'gap-4 rounded-3xl border border-border-default px-0 pt-4 pb-0 overflow-hidden'
|
|
116
|
+
: isFloating
|
|
117
|
+
? 'gap-4 rounded-3xl border border-border-default px-0 pt-4 pb-0 overflow-hidden'
|
|
118
|
+
: isNone
|
|
119
|
+
? 'gap-4 rounded-3xl border border-border-default px-0 py-4'
|
|
120
|
+
: 'gap-4 rounded-3xl border border-border-default px-0 py-4',
|
|
93
121
|
className
|
|
94
122
|
)}
|
|
95
123
|
>
|
|
96
124
|
{/* Header Section: Greeting + Schedule Button */}
|
|
97
|
-
<View
|
|
125
|
+
<View
|
|
126
|
+
className={cn(
|
|
127
|
+
'w-full flex-row items-center',
|
|
128
|
+
isFloating || isAiSummary
|
|
129
|
+
? 'justify-between px-3'
|
|
130
|
+
: isNone
|
|
131
|
+
? 'px-3'
|
|
132
|
+
: 'px-3'
|
|
133
|
+
)}
|
|
134
|
+
>
|
|
98
135
|
{/* Header Content: Title and Subtitle */}
|
|
99
136
|
<View className="flex-1 flex-col gap-1">
|
|
100
137
|
<Text className="font-semibold text-base text-text-primary">
|
|
@@ -105,22 +142,32 @@ export function Greeting({
|
|
|
105
142
|
</Text>
|
|
106
143
|
</View>
|
|
107
144
|
|
|
108
|
-
{/* Schedule Button with Calendar Icon */}
|
|
109
|
-
{
|
|
145
|
+
{/* Schedule Button with Calendar Icon - Icon Layout */}
|
|
146
|
+
{effectiveCtaLayout === 'icon' && (
|
|
147
|
+
<Pressable
|
|
148
|
+
onPress={onSchedulePress}
|
|
149
|
+
hitSlop={12}
|
|
150
|
+
className="ml-3 flex-row items-center justify-center rounded-lg p-3 bg-highlight-purple"
|
|
151
|
+
>
|
|
152
|
+
<Icon as={Calendar} size={16} color="white" />
|
|
153
|
+
</Pressable>
|
|
154
|
+
)}
|
|
155
|
+
|
|
156
|
+
{/* Calendar Icon for AI Summary and Floating layouts */}
|
|
157
|
+
{isAiSummary && (
|
|
110
158
|
<Pressable
|
|
111
159
|
onPress={onSchedulePress}
|
|
112
160
|
hitSlop={12}
|
|
113
|
-
className="ml-3 flex-row items-center justify-center rounded-lg bg-highlight-purple
|
|
114
|
-
style={styles.scheduleButton}
|
|
161
|
+
className="ml-3 flex-row items-center justify-center rounded-lg p-3 bg-highlight-purple"
|
|
115
162
|
>
|
|
116
163
|
<Icon as={Calendar} size={16} color="white" />
|
|
117
164
|
</Pressable>
|
|
118
165
|
)}
|
|
119
166
|
</View>
|
|
120
167
|
|
|
121
|
-
{/* Next Up Section */}
|
|
122
|
-
{showNextUp && (
|
|
123
|
-
<View className="w-full flex-col gap-1">
|
|
168
|
+
{/* Next Up Section - For icon, none, floating, and ai summary layouts */}
|
|
169
|
+
{isIconOrFloatingOrNoneOrAiSummary && showNextUp && (
|
|
170
|
+
<View className="w-full flex-col gap-1 px-3">
|
|
124
171
|
<Text className="font-medium text-xs text-text-secondary">
|
|
125
172
|
Next up
|
|
126
173
|
</Text>
|
|
@@ -137,18 +184,52 @@ export function Greeting({
|
|
|
137
184
|
</View>
|
|
138
185
|
</View>
|
|
139
186
|
)}
|
|
187
|
+
|
|
188
|
+
{/* AI Summary Button - Purple to Red Gradient - Full Width */}
|
|
189
|
+
{isAiSummary && (
|
|
190
|
+
<LinearGradient
|
|
191
|
+
colors={['#573dab', '#f2353c']}
|
|
192
|
+
start={{ x: 0, y: 0 }}
|
|
193
|
+
end={{ x: 1, y: 0 }}
|
|
194
|
+
className="w-full items-center justify-center"
|
|
195
|
+
style={{
|
|
196
|
+
paddingVertical: 8,
|
|
197
|
+
borderBottomLeftRadius: 20,
|
|
198
|
+
borderBottomRightRadius: 20,
|
|
199
|
+
}}
|
|
200
|
+
>
|
|
201
|
+
<Pressable
|
|
202
|
+
onPress={onSchedulePress}
|
|
203
|
+
className="w-full items-center justify-center"
|
|
204
|
+
style={{ paddingVertical: 0 }}
|
|
205
|
+
>
|
|
206
|
+
<Text className="font-semibold text-sm text-white">
|
|
207
|
+
AI Summary for Today
|
|
208
|
+
</Text>
|
|
209
|
+
</Pressable>
|
|
210
|
+
</LinearGradient>
|
|
211
|
+
)}
|
|
212
|
+
|
|
213
|
+
{/* Floating Button - Full width at bottom - Card color (white) */}
|
|
214
|
+
{isFloating && (
|
|
215
|
+
<View
|
|
216
|
+
className="w-full bg-surface-default"
|
|
217
|
+
style={{ borderBottomLeftRadius: 20, borderBottomRightRadius: 20 }}
|
|
218
|
+
>
|
|
219
|
+
<Button
|
|
220
|
+
variant="outline"
|
|
221
|
+
size="default"
|
|
222
|
+
showRightIcon
|
|
223
|
+
rightIcon={Calendar}
|
|
224
|
+
onPress={onSchedulePress}
|
|
225
|
+
style={{ width: '100%' }}
|
|
226
|
+
>
|
|
227
|
+
View Schedule
|
|
228
|
+
</Button>
|
|
229
|
+
</View>
|
|
230
|
+
)}
|
|
140
231
|
</View>
|
|
141
232
|
);
|
|
142
233
|
}
|
|
143
234
|
|
|
144
235
|
Greeting.displayName = 'Greeting';
|
|
145
|
-
|
|
146
|
-
const styles = StyleSheet.create({
|
|
147
|
-
scheduleButton: {
|
|
148
|
-
shadowColor: '#573dab',
|
|
149
|
-
shadowOffset: { width: 0, height: 0 },
|
|
150
|
-
shadowOpacity: 0.5,
|
|
151
|
-
shadowRadius: 12,
|
|
152
|
-
elevation: 8,
|
|
153
|
-
},
|
|
154
|
-
});
|
|
@@ -19,6 +19,7 @@ export * from '../Layout/Bottomsheet/Bottom-Sheet';
|
|
|
19
19
|
export * from '../Input/Button/Button';
|
|
20
20
|
export * from '../DataDisplay/Card/Card';
|
|
21
21
|
export * from '../DataDisplay/CalendarItem/CalendarItem';
|
|
22
|
+
export * from '../DataDisplay/FeedCard/FeedCard';
|
|
22
23
|
export * from '../DataDisplay/Greeting/Greeting';
|
|
23
24
|
export * from '../DataDisplay/MonthCalendar/MonthCalendar';
|
|
24
25
|
export * from '../DataDisplay/DataCard/DataCard';
|