@campxdev/react-native-blueprint 0.1.20 → 0.1.24
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/global.css +3 -3
- package/lib/global.css +1 -1
- package/lib/module/assets/icons/Image.png +0 -0
- package/lib/module/components/DataDisplay/Avatar/Avatar.js +1 -1
- package/lib/module/components/DataDisplay/Avatar/Avatar.js.map +1 -1
- package/lib/module/components/DataDisplay/Banner/Banner.figma.js +17 -3
- package/lib/module/components/DataDisplay/Banner/Banner.figma.js.map +1 -1
- package/lib/module/components/DataDisplay/Banner/Banner.js +138 -34
- package/lib/module/components/DataDisplay/Banner/Banner.js.map +1 -1
- package/lib/module/components/DataDisplay/CalendarItem/CalendarItem.js +2 -2
- package/lib/module/components/DataDisplay/CalendarItem/CalendarItem.js.map +1 -1
- package/lib/module/components/DataDisplay/Card/Card.figma.js +11 -4
- package/lib/module/components/DataDisplay/Card/Card.figma.js.map +1 -1
- package/lib/module/components/DataDisplay/Card/Card.js +119 -65
- package/lib/module/components/DataDisplay/Card/Card.js.map +1 -1
- package/lib/module/components/DataDisplay/ChatBubble/ChatBubble.figma.js +54 -0
- package/lib/module/components/DataDisplay/ChatBubble/ChatBubble.figma.js.map +1 -0
- package/lib/module/components/DataDisplay/ChatBubble/ChatBubble.js +318 -0
- package/lib/module/components/DataDisplay/ChatBubble/ChatBubble.js.map +1 -0
- package/lib/module/components/DataDisplay/ChatBubble/index.js +4 -0
- package/lib/module/components/DataDisplay/ChatBubble/index.js.map +1 -0
- package/lib/module/components/DataDisplay/FeedCard/AttachmentDetails.js +69 -0
- package/lib/module/components/DataDisplay/FeedCard/AttachmentDetails.js.map +1 -0
- package/lib/module/components/DataDisplay/FeedCard/FeedCard.figma.js +19 -17
- package/lib/module/components/DataDisplay/FeedCard/FeedCard.figma.js.map +1 -1
- package/lib/module/components/DataDisplay/FeedCard/FeedCard.js +30 -19
- package/lib/module/components/DataDisplay/FeedCard/FeedCard.js.map +1 -1
- package/lib/module/components/DataDisplay/Greeting/Greeting.figma.js +5 -5
- package/lib/module/components/DataDisplay/Greeting/Greeting.figma.js.map +1 -1
- package/lib/module/components/DataDisplay/Greeting/Greeting.js +46 -70
- package/lib/module/components/DataDisplay/Greeting/Greeting.js.map +1 -1
- package/lib/module/components/DataDisplay/ProfileCard/ProfileCard.figma.js +16 -0
- package/lib/module/components/DataDisplay/ProfileCard/ProfileCard.figma.js.map +1 -0
- package/lib/module/components/DataDisplay/ProfileCard/ProfileCard.js +111 -0
- package/lib/module/components/DataDisplay/ProfileCard/ProfileCard.js.map +1 -0
- package/lib/module/components/DataDisplay/ProfileCard/index.js +4 -0
- package/lib/module/components/DataDisplay/ProfileCard/index.js.map +1 -0
- package/lib/module/components/Input/Button/Button.js +11 -9
- package/lib/module/components/Input/Button/Button.js.map +1 -1
- package/lib/module/components/Navigation/Appbar/AppBar.figma.js +18 -6
- package/lib/module/components/Navigation/Appbar/AppBar.figma.js.map +1 -1
- package/lib/module/components/Navigation/Appbar/AppBar.js +36 -9
- package/lib/module/components/Navigation/Appbar/AppBar.js.map +1 -1
- package/lib/module/components/Navigation/Popover/Popover.js +1 -1
- package/lib/module/components/Navigation/Popover/Popover.js.map +1 -1
- package/lib/module/components/ui/index.js +2 -0
- package/lib/module/components/ui/index.js.map +1 -1
- package/lib/module/lib/theme.js +2 -2
- package/lib/module/patterns/pattern-components/AccountPattern/AccountPattern.figma.js +196 -0
- package/lib/module/patterns/pattern-components/AccountPattern/AccountPattern.figma.js.map +1 -0
- package/lib/module/patterns/pattern-components/AccountPattern/AccountPattern.js +255 -0
- package/lib/module/patterns/pattern-components/AccountPattern/AccountPattern.js.map +1 -0
- package/lib/module/patterns/pattern-components/AccountPattern/index.js +4 -0
- package/lib/module/patterns/pattern-components/AccountPattern/index.js.map +1 -0
- package/lib/module/patterns/pattern-components/CalendarPattern/CalendarPattern.figma.js +1 -1
- package/lib/module/patterns/pattern-components/CardListPattern/CardListPattern.js +2 -4
- package/lib/module/patterns/pattern-components/CardListPattern/CardListPattern.js.map +1 -1
- package/lib/module/patterns/pattern-components/FeedPattern/FeedPattern.figma.js +144 -0
- package/lib/module/patterns/pattern-components/FeedPattern/FeedPattern.figma.js.map +1 -0
- package/lib/module/patterns/pattern-components/FeedPattern/FeedPattern.js +213 -0
- package/lib/module/patterns/pattern-components/FeedPattern/FeedPattern.js.map +1 -0
- package/lib/module/patterns/pattern-components/FeedPattern/index.js +4 -0
- package/lib/module/patterns/pattern-components/FeedPattern/index.js.map +1 -0
- package/lib/module/patterns/pattern-components/HomeFacultyPattern/HomeFacultyPattern.figma.js +70 -0
- package/lib/module/patterns/pattern-components/HomeFacultyPattern/HomeFacultyPattern.figma.js.map +1 -0
- package/lib/module/patterns/pattern-components/HomeFacultyPattern/HomeFacultyPattern.js +260 -0
- package/lib/module/patterns/pattern-components/HomeFacultyPattern/HomeFacultyPattern.js.map +1 -0
- package/lib/module/patterns/pattern-components/HomeFacultyPattern/index.js +4 -0
- package/lib/module/patterns/pattern-components/HomeFacultyPattern/index.js.map +1 -0
- package/lib/module/patterns/pattern-components/HomeParentPattern/HomeParentPattern.figma.js +82 -0
- package/lib/module/patterns/pattern-components/HomeParentPattern/HomeParentPattern.figma.js.map +1 -0
- package/lib/module/patterns/pattern-components/HomeParentPattern/HomeParentPattern.js +256 -0
- package/lib/module/patterns/pattern-components/HomeParentPattern/HomeParentPattern.js.map +1 -0
- package/lib/module/patterns/pattern-components/HomeParentPattern/index.js +4 -0
- package/lib/module/patterns/pattern-components/HomeParentPattern/index.js.map +1 -0
- package/lib/module/patterns/pattern-components/HomeStudentPattern/HomeStudentPattern.figma.js +73 -0
- package/lib/module/patterns/pattern-components/HomeStudentPattern/HomeStudentPattern.figma.js.map +1 -0
- package/lib/module/patterns/pattern-components/HomeStudentPattern/HomeStudentPattern.js +283 -0
- package/lib/module/patterns/pattern-components/HomeStudentPattern/HomeStudentPattern.js.map +1 -0
- package/lib/module/patterns/pattern-components/HomeStudentPattern/index.js +4 -0
- package/lib/module/patterns/pattern-components/HomeStudentPattern/index.js.map +1 -0
- package/lib/module/patterns/pattern-components/index.js +5 -0
- package/lib/module/patterns/pattern-components/index.js.map +1 -1
- package/package.json +27 -1
- package/src/assets/icons/Image.png +0 -0
- package/src/components/DataDisplay/Avatar/Avatar.tsx +24 -21
- package/src/components/DataDisplay/Banner/Banner.figma.tsx +18 -3
- package/src/components/DataDisplay/Banner/Banner.tsx +153 -26
- package/src/components/DataDisplay/CalendarItem/CalendarItem.tsx +2 -2
- package/src/components/DataDisplay/Card/Card.figma.tsx +7 -3
- package/src/components/DataDisplay/Card/Card.tsx +152 -101
- package/src/components/DataDisplay/ChatBubble/ChatBubble.figma.tsx +54 -0
- package/src/components/DataDisplay/ChatBubble/ChatBubble.tsx +404 -0
- package/src/components/DataDisplay/ChatBubble/index.ts +8 -0
- package/src/components/DataDisplay/FeedCard/AttachmentDetails.tsx +96 -0
- package/src/components/DataDisplay/FeedCard/FeedCard.figma.tsx +17 -15
- package/src/components/DataDisplay/FeedCard/FeedCard.tsx +66 -35
- package/src/components/DataDisplay/Greeting/Greeting.figma.tsx +5 -5
- package/src/components/DataDisplay/Greeting/Greeting.tsx +58 -96
- package/src/components/DataDisplay/ProfileCard/ProfileCard.figma.tsx +17 -0
- package/src/components/DataDisplay/ProfileCard/ProfileCard.tsx +173 -0
- package/src/components/DataDisplay/ProfileCard/index.ts +1 -0
- package/src/components/Input/Button/Button.tsx +18 -10
- package/src/components/Navigation/Appbar/AppBar.figma.tsx +18 -6
- package/src/components/Navigation/Appbar/AppBar.tsx +58 -13
- package/src/components/Navigation/Popover/Popover.tsx +3 -3
- package/src/components/ui/index.ts +2 -0
- package/src/lib/theme.ts +2 -2
- package/src/patterns/pattern-components/AccountPattern/AccountPattern.figma.tsx +193 -0
- package/src/patterns/pattern-components/AccountPattern/AccountPattern.tsx +301 -0
- package/src/patterns/pattern-components/AccountPattern/index.ts +1 -0
- package/src/patterns/pattern-components/CalendarPattern/CalendarPattern.figma.tsx +1 -1
- package/src/patterns/pattern-components/CardListPattern/CardListPattern.tsx +4 -9
- package/src/patterns/pattern-components/FeedPattern/FeedPattern.figma.tsx +146 -0
- package/src/patterns/pattern-components/FeedPattern/FeedPattern.tsx +264 -0
- package/src/patterns/pattern-components/FeedPattern/index.ts +2 -0
- package/src/patterns/pattern-components/HomeFacultyPattern/HomeFacultyPattern.figma.tsx +66 -0
- package/src/patterns/pattern-components/HomeFacultyPattern/HomeFacultyPattern.tsx +326 -0
- package/src/patterns/pattern-components/HomeFacultyPattern/index.ts +2 -0
- package/src/patterns/pattern-components/HomeParentPattern/HomeParentPattern.figma.tsx +75 -0
- package/src/patterns/pattern-components/HomeParentPattern/HomeParentPattern.tsx +328 -0
- package/src/patterns/pattern-components/HomeParentPattern/index.ts +2 -0
- package/src/patterns/pattern-components/HomeStudentPattern/HomeStudentPattern.figma.tsx +66 -0
- package/src/patterns/pattern-components/HomeStudentPattern/HomeStudentPattern.tsx +355 -0
- package/src/patterns/pattern-components/HomeStudentPattern/index.ts +2 -0
- package/src/patterns/pattern-components/index.ts +5 -0
|
@@ -15,11 +15,10 @@ import { Button } from '../../Input/Button/Button';
|
|
|
15
15
|
import { Badge } from '../Badge/Badge';
|
|
16
16
|
import { Text } from '../../Input/Text/Text';
|
|
17
17
|
import { Avatar } from '../Avatar/Avatar';
|
|
18
|
-
import {
|
|
18
|
+
import { AttachmentDetails } from './AttachmentDetails';
|
|
19
19
|
|
|
20
|
-
//
|
|
21
|
-
const
|
|
22
|
-
'https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe3e?w=400&h=224&fit=crop';
|
|
20
|
+
// Gradient image asset (same as Card demo)
|
|
21
|
+
const GRADIENT_IMAGE = require('../../../assets/icons/Image.png');
|
|
23
22
|
|
|
24
23
|
// NativeWind interop (className -> style)
|
|
25
24
|
const View = cssInterop(RNView, { className: 'style' });
|
|
@@ -36,23 +35,26 @@ export const FeedCardVariants = {
|
|
|
36
35
|
|
|
37
36
|
type FeedCardType = (typeof FeedCardVariants.type)[number];
|
|
38
37
|
|
|
39
|
-
const rootVariants = cva(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
const rootVariants = cva(
|
|
39
|
+
'w-full overflow-hidden rounded-lg bg-surface-default',
|
|
40
|
+
{
|
|
41
|
+
variants: {
|
|
42
|
+
type: {
|
|
43
|
+
post: '',
|
|
44
|
+
announcement: 'border border-border-default',
|
|
45
|
+
},
|
|
44
46
|
},
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
47
|
+
defaultVariants: {
|
|
48
|
+
type: 'post',
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
);
|
|
50
52
|
|
|
51
|
-
const metaRowVariants = cva('w-full flex-row p-4', {
|
|
53
|
+
const metaRowVariants = cva('w-full flex-row p-4 items-center', {
|
|
52
54
|
variants: {
|
|
53
55
|
type: {
|
|
54
|
-
post: '
|
|
55
|
-
announcement: '
|
|
56
|
+
post: 'gap-2',
|
|
57
|
+
announcement: 'justify-between gap-2',
|
|
56
58
|
},
|
|
57
59
|
},
|
|
58
60
|
defaultVariants: {
|
|
@@ -60,9 +62,9 @@ const metaRowVariants = cva('w-full flex-row p-4', {
|
|
|
60
62
|
},
|
|
61
63
|
});
|
|
62
64
|
|
|
63
|
-
const mediaWrapVariants = cva('w-full overflow-hidden px-4 pb-
|
|
65
|
+
const mediaWrapVariants = cva('w-full overflow-hidden px-4 pb-0 pt-0');
|
|
64
66
|
|
|
65
|
-
const contentWrapVariants = cva('w-full px-4 pb-4 flex-col');
|
|
67
|
+
const contentWrapVariants = cva('w-full px-4 pb-4 flex-col gap-4');
|
|
66
68
|
|
|
67
69
|
const headerVariants = cva('w-full gap-1 flex-col');
|
|
68
70
|
|
|
@@ -111,6 +113,15 @@ export type FeedCardProps = {
|
|
|
111
113
|
/** Optional image/media */
|
|
112
114
|
image?: ImageSourcePropType;
|
|
113
115
|
|
|
116
|
+
/** Media type variant */
|
|
117
|
+
mediaType?: 'image' | 'file';
|
|
118
|
+
|
|
119
|
+
/** File attachment details (for file media type) */
|
|
120
|
+
fileName?: string;
|
|
121
|
+
filePages?: number;
|
|
122
|
+
fileSizeMB?: number;
|
|
123
|
+
fileType?: string;
|
|
124
|
+
|
|
114
125
|
/** Card type variant */
|
|
115
126
|
type?: FeedCardType | 'Post' | 'Announcement';
|
|
116
127
|
|
|
@@ -120,6 +131,7 @@ export type FeedCardProps = {
|
|
|
120
131
|
showMedia?: boolean;
|
|
121
132
|
showPostContent?: boolean;
|
|
122
133
|
showSubtitle?: boolean;
|
|
134
|
+
showBody?: boolean;
|
|
123
135
|
showBadges?: boolean;
|
|
124
136
|
showFooterActions?: boolean;
|
|
125
137
|
showSecondaryButton?: boolean;
|
|
@@ -155,6 +167,11 @@ export function FeedCard(props: FeedCardProps) {
|
|
|
155
167
|
subtitle = 'Subtitle of the card goes here',
|
|
156
168
|
postContent = 'The card may contain body content which can be truncated to 1-2 lines. Swap Content in Props.',
|
|
157
169
|
image,
|
|
170
|
+
mediaType = 'image',
|
|
171
|
+
fileName = 'File Name',
|
|
172
|
+
filePages = 27,
|
|
173
|
+
fileSizeMB = 3,
|
|
174
|
+
fileType = 'PDF',
|
|
158
175
|
|
|
159
176
|
type = 'post',
|
|
160
177
|
|
|
@@ -163,6 +180,7 @@ export function FeedCard(props: FeedCardProps) {
|
|
|
163
180
|
showMedia = true,
|
|
164
181
|
showPostContent = true,
|
|
165
182
|
showSubtitle = true,
|
|
183
|
+
showBody = true,
|
|
166
184
|
showBadges = true,
|
|
167
185
|
showFooterActions = true,
|
|
168
186
|
showSecondaryButton = true,
|
|
@@ -243,16 +261,26 @@ export function FeedCard(props: FeedCardProps) {
|
|
|
243
261
|
{/* Media Section */}
|
|
244
262
|
{showMedia && (
|
|
245
263
|
<View testID="feed-card-media-wrap" className={cn(mediaWrapVariants())}>
|
|
246
|
-
<
|
|
247
|
-
|
|
248
|
-
<
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
264
|
+
<View className="w-full pb-4">
|
|
265
|
+
{mediaType === 'image' ? (
|
|
266
|
+
<View className="w-full aspect-[16/9] bg-surface-subtle rounded-xl overflow-hidden">
|
|
267
|
+
<Image
|
|
268
|
+
testID="feed-card-media"
|
|
269
|
+
source={image || GRADIENT_IMAGE}
|
|
270
|
+
resizeMode="cover"
|
|
271
|
+
className="w-full h-full"
|
|
272
|
+
/>
|
|
273
|
+
</View>
|
|
274
|
+
) : (
|
|
275
|
+
<AttachmentDetails
|
|
276
|
+
testID="feed-card-attachment"
|
|
277
|
+
fileName={fileName}
|
|
278
|
+
pages={filePages}
|
|
279
|
+
sizeMB={fileSizeMB}
|
|
280
|
+
fileType={fileType}
|
|
253
281
|
/>
|
|
254
|
-
|
|
255
|
-
</
|
|
282
|
+
)}
|
|
283
|
+
</View>
|
|
256
284
|
</View>
|
|
257
285
|
)}
|
|
258
286
|
|
|
@@ -265,6 +293,7 @@ export function FeedCard(props: FeedCardProps) {
|
|
|
265
293
|
<RNText
|
|
266
294
|
testID="feed-card-title"
|
|
267
295
|
numberOfLines={1}
|
|
296
|
+
ellipsizeMode="tail"
|
|
268
297
|
className={cn(titleVariants())}
|
|
269
298
|
>
|
|
270
299
|
{postTitle}
|
|
@@ -283,13 +312,15 @@ export function FeedCard(props: FeedCardProps) {
|
|
|
283
312
|
)}
|
|
284
313
|
|
|
285
314
|
{/* Body */}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
315
|
+
{showBody && (
|
|
316
|
+
<RNText
|
|
317
|
+
testID="feed-card-body"
|
|
318
|
+
numberOfLines={2}
|
|
319
|
+
className={cn(bodyVariants())}
|
|
320
|
+
>
|
|
321
|
+
{postContent}
|
|
322
|
+
</RNText>
|
|
323
|
+
)}
|
|
293
324
|
</View>
|
|
294
325
|
)}
|
|
295
326
|
|
|
@@ -6,11 +6,11 @@ const FIGMA_URL =
|
|
|
6
6
|
|
|
7
7
|
figma.connect(Greeting, FIGMA_URL, {
|
|
8
8
|
props: {
|
|
9
|
-
ctaLayout: figma.enum('
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
ctaLayout: figma.enum('ctaLayout', {
|
|
10
|
+
icon: 'icon',
|
|
11
|
+
row: 'row',
|
|
12
|
+
none: 'none',
|
|
13
|
+
floating: 'floating',
|
|
14
14
|
}),
|
|
15
15
|
showNextUp: figma.boolean('Show NextUp'),
|
|
16
16
|
},
|
|
@@ -16,10 +16,6 @@ cssInterop(LinearGradient, { className: 'style' });
|
|
|
16
16
|
const View = RNView as React.ComponentType<
|
|
17
17
|
React.ComponentProps<typeof RNView> & { className?: string }
|
|
18
18
|
>;
|
|
19
|
-
const Pressable = RNPressable as React.ComponentType<
|
|
20
|
-
React.ComponentProps<typeof RNPressable> & { className?: string }
|
|
21
|
-
>;
|
|
22
|
-
|
|
23
19
|
/**
|
|
24
20
|
* Props for the Greeting component
|
|
25
21
|
*/
|
|
@@ -31,9 +27,7 @@ export interface GreetingProps {
|
|
|
31
27
|
/** Subtitle/secondary text below greeting */
|
|
32
28
|
subtitle?: string;
|
|
33
29
|
/** CTA (Call-to-Action) layout style */
|
|
34
|
-
ctaLayout?: 'icon' | 'none' | 'floating' | '
|
|
35
|
-
/** Whether to show the schedule/calendar button - deprecated, use ctaLayout instead */
|
|
36
|
-
showScheduleButton?: boolean;
|
|
30
|
+
ctaLayout?: 'icon' | 'none' | 'floating' | 'row';
|
|
37
31
|
/** Callback when schedule button is pressed */
|
|
38
32
|
onSchedulePress?: () => void;
|
|
39
33
|
/** Whether to show the "Next up" section */
|
|
@@ -52,12 +46,16 @@ export interface GreetingProps {
|
|
|
52
46
|
* Greeting - A personalized greeting card with schedule information
|
|
53
47
|
*
|
|
54
48
|
* Displays a personalized greeting with user name, class information, and upcoming
|
|
55
|
-
* class details.
|
|
56
|
-
* "Next up" section with course name and time
|
|
49
|
+
* class details. Supports multiple CTA layouts: icon button, row button, floating button,
|
|
50
|
+
* or none. Features "Next up" section with course name and time.
|
|
57
51
|
*
|
|
58
|
-
* Design from Figma: node-id=
|
|
52
|
+
* Design from Figma: node-id=495-8995
|
|
59
53
|
* - Header: "Hey {name}, {greeting}" + Subtitle
|
|
60
|
-
* -
|
|
54
|
+
* - CTA Layouts:
|
|
55
|
+
* - icon: Calendar icon button in header
|
|
56
|
+
* - row: Full-width button below content
|
|
57
|
+
* - floating: Full-width button at bottom with separate styling
|
|
58
|
+
* - none: No CTA button
|
|
61
59
|
* - Next Up: Course name + divider dot + time
|
|
62
60
|
*
|
|
63
61
|
* @component
|
|
@@ -70,6 +68,7 @@ export interface GreetingProps {
|
|
|
70
68
|
* nextUpTitle="Digital Logic Design"
|
|
71
69
|
* nextUpTime="10:00 AM"
|
|
72
70
|
* showNextUp={true}
|
|
71
|
+
* ctaLayout="icon"
|
|
73
72
|
* onSchedulePress={() => navigate('Schedule')}
|
|
74
73
|
* />
|
|
75
74
|
* ```
|
|
@@ -79,7 +78,6 @@ export function Greeting({
|
|
|
79
78
|
greetingText = 'Good Morning',
|
|
80
79
|
subtitle = 'You have 3 Classes today',
|
|
81
80
|
ctaLayout = 'icon',
|
|
82
|
-
showScheduleButton,
|
|
83
81
|
onSchedulePress,
|
|
84
82
|
showNextUp = true,
|
|
85
83
|
nextUpTitle = 'Digital Logic Design',
|
|
@@ -87,49 +85,31 @@ export function Greeting({
|
|
|
87
85
|
className,
|
|
88
86
|
testID,
|
|
89
87
|
}: GreetingProps) {
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
|
|
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';
|
|
88
|
+
const isFloating = ctaLayout === 'floating';
|
|
89
|
+
const isRow = ctaLayout === 'row';
|
|
90
|
+
const isIcon = ctaLayout === 'icon';
|
|
107
91
|
|
|
108
92
|
return (
|
|
109
93
|
<View
|
|
110
94
|
testID={testID}
|
|
111
95
|
className={cn(
|
|
112
|
-
'w-full max-w-[400px] flex-col items-start justify-end bg-surface-default',
|
|
96
|
+
'w-full max-w-[400px] flex-col items-start justify-end bg-surface-default rounded-xl border border-border-default',
|
|
113
97
|
// Base styling based on ctaLayout
|
|
114
|
-
|
|
115
|
-
? 'gap-
|
|
116
|
-
:
|
|
117
|
-
? 'gap-4
|
|
118
|
-
:
|
|
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',
|
|
98
|
+
isFloating
|
|
99
|
+
? 'gap-5 px-0 py-5'
|
|
100
|
+
: isRow
|
|
101
|
+
? 'gap-4 px-0 pt-4 pb-0'
|
|
102
|
+
: 'gap-4 px-0 py-3',
|
|
121
103
|
className
|
|
122
104
|
)}
|
|
123
105
|
>
|
|
124
|
-
{/* Header Section: Greeting +
|
|
106
|
+
{/* Header Section: Greeting + Optional Calendar Icon */}
|
|
125
107
|
<View
|
|
126
108
|
className={cn(
|
|
127
|
-
'w-full flex-row
|
|
128
|
-
isFloating
|
|
129
|
-
? 'justify-between px-3'
|
|
130
|
-
:
|
|
131
|
-
? 'px-3'
|
|
132
|
-
: 'px-3'
|
|
109
|
+
'w-full flex-row',
|
|
110
|
+
isFloating
|
|
111
|
+
? 'justify-between px-3 items-start'
|
|
112
|
+
: 'justify-between px-3 items-center'
|
|
133
113
|
)}
|
|
134
114
|
>
|
|
135
115
|
{/* Header Content: Title and Subtitle */}
|
|
@@ -142,32 +122,36 @@ export function Greeting({
|
|
|
142
122
|
</Text>
|
|
143
123
|
</View>
|
|
144
124
|
|
|
145
|
-
{/* Schedule Button
|
|
146
|
-
{
|
|
147
|
-
<
|
|
125
|
+
{/* Schedule Button - Icon Layout (top-right in icon layout) */}
|
|
126
|
+
{isIcon && (
|
|
127
|
+
<Button
|
|
128
|
+
variant="default"
|
|
129
|
+
size="icon"
|
|
130
|
+
showLeftIcon
|
|
131
|
+
leftIcon={<Icon as={Calendar} size={16} color="white" />}
|
|
148
132
|
onPress={onSchedulePress}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
>
|
|
152
|
-
<Icon as={Calendar} size={16} color="white" />
|
|
153
|
-
</Pressable>
|
|
133
|
+
style={{ marginLeft: 12 }}
|
|
134
|
+
/>
|
|
154
135
|
)}
|
|
155
136
|
|
|
156
|
-
{/*
|
|
157
|
-
{
|
|
158
|
-
<
|
|
137
|
+
{/* Schedule Button - Floating Layout (top-right in floating layout) */}
|
|
138
|
+
{isFloating && (
|
|
139
|
+
<Button
|
|
140
|
+
variant="default"
|
|
141
|
+
size="default"
|
|
159
142
|
onPress={onSchedulePress}
|
|
160
|
-
|
|
161
|
-
className="ml-3 flex-row items-center justify-center rounded-lg p-3 bg-highlight-purple"
|
|
143
|
+
style={{ marginLeft: 12 }}
|
|
162
144
|
>
|
|
163
|
-
|
|
164
|
-
</
|
|
145
|
+
My Schedule
|
|
146
|
+
</Button>
|
|
165
147
|
)}
|
|
166
148
|
</View>
|
|
167
149
|
|
|
168
|
-
{/* Next Up Section - For icon,
|
|
169
|
-
{
|
|
170
|
-
<View
|
|
150
|
+
{/* Next Up Section - For icon, row, none, and floating layouts */}
|
|
151
|
+
{showNextUp && (
|
|
152
|
+
<View
|
|
153
|
+
className={cn('w-full flex-col gap-1', isFloating ? 'px-3' : 'px-3')}
|
|
154
|
+
>
|
|
171
155
|
<Text className="font-medium text-xs text-text-secondary">
|
|
172
156
|
Next up
|
|
173
157
|
</Text>
|
|
@@ -185,44 +169,22 @@ export function Greeting({
|
|
|
185
169
|
</View>
|
|
186
170
|
)}
|
|
187
171
|
|
|
188
|
-
{/*
|
|
189
|
-
{
|
|
190
|
-
<
|
|
191
|
-
|
|
192
|
-
|
|
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
|
-
)}
|
|
172
|
+
{/* Divider and Button Container for Row Layout */}
|
|
173
|
+
{isRow && (
|
|
174
|
+
<View className="w-full flex-col">
|
|
175
|
+
{/* Divider Line */}
|
|
176
|
+
<View className="w-full border-t border-border-default" />
|
|
212
177
|
|
|
213
|
-
|
|
214
|
-
{isFloating && (
|
|
215
|
-
<View
|
|
216
|
-
className="w-full bg-surface-default"
|
|
217
|
-
style={{ borderBottomLeftRadius: 20, borderBottomRightRadius: 20 }}
|
|
218
|
-
>
|
|
178
|
+
{/* Row Button - Full width ghost button */}
|
|
219
179
|
<Button
|
|
220
|
-
variant="
|
|
180
|
+
variant="ghost"
|
|
221
181
|
size="default"
|
|
222
|
-
|
|
223
|
-
|
|
182
|
+
showLeftIcon
|
|
183
|
+
leftIcon={<Icon as={Calendar} size={16} />}
|
|
224
184
|
onPress={onSchedulePress}
|
|
225
|
-
style={{
|
|
185
|
+
style={{
|
|
186
|
+
width: '100%',
|
|
187
|
+
}}
|
|
226
188
|
>
|
|
227
189
|
View Schedule
|
|
228
190
|
</Button>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import figma from '@figma/code-connect';
|
|
2
|
+
import { ProfileCard } from './ProfileCard';
|
|
3
|
+
|
|
4
|
+
const FIGMA_URL =
|
|
5
|
+
'https://www.figma.com/design/66WaqopqU3WXgwVtyQuTUf/React-Native-Blueprint-Library?node-id=637-2039';
|
|
6
|
+
|
|
7
|
+
figma.connect(ProfileCard, FIGMA_URL, {
|
|
8
|
+
example: () => (
|
|
9
|
+
<ProfileCard
|
|
10
|
+
userName="Marshall Mathers"
|
|
11
|
+
userID="3472732323"
|
|
12
|
+
avatarInitials="MM"
|
|
13
|
+
avatarType="image"
|
|
14
|
+
onPress={() => console.log('Profile card pressed')}
|
|
15
|
+
/>
|
|
16
|
+
),
|
|
17
|
+
});
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import {
|
|
3
|
+
View as RNView,
|
|
4
|
+
Text as RNTextBase,
|
|
5
|
+
Pressable as RNPressable,
|
|
6
|
+
Image as RNImage,
|
|
7
|
+
type StyleProp,
|
|
8
|
+
type ViewStyle,
|
|
9
|
+
} from 'react-native';
|
|
10
|
+
import { cssInterop } from 'nativewind';
|
|
11
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
12
|
+
import { ChevronRight } from 'lucide-react-native';
|
|
13
|
+
|
|
14
|
+
import { cn } from '../../../lib/utils';
|
|
15
|
+
|
|
16
|
+
// NativeWind interop (className -> style)
|
|
17
|
+
const View = cssInterop(RNView, { className: 'style' });
|
|
18
|
+
const RNText = cssInterop(RNTextBase, { className: 'style' });
|
|
19
|
+
const Pressable = cssInterop(RNPressable, { className: 'style' });
|
|
20
|
+
|
|
21
|
+
/* -----------------------------------------------------
|
|
22
|
+
* Variants
|
|
23
|
+
* --------------------------------------------------- */
|
|
24
|
+
|
|
25
|
+
export const ProfileCardVariants = {} as const;
|
|
26
|
+
|
|
27
|
+
const rootVariants = cva(
|
|
28
|
+
'w-full rounded-[20px] overflow-hidden flex-row items-center justify-between gap-3 px-3 py-3 bg-highlight-highlight-purple',
|
|
29
|
+
{
|
|
30
|
+
variants: {},
|
|
31
|
+
defaultVariants: {},
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const profileCardStyle = (style?: any) => ({
|
|
36
|
+
...style,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const contentContainerVariants = cva('flex-1 flex-row items-center gap-3');
|
|
40
|
+
|
|
41
|
+
const infoColumnVariants = cva('flex-1 flex-col gap-1 justify-center');
|
|
42
|
+
|
|
43
|
+
const nameTextVariants = cva(
|
|
44
|
+
"font-['Geist:SemiBold',sans-serif] font-semibold text-base text-white"
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const idTextVariants = cva(
|
|
48
|
+
"font-['Geist:Medium',sans-serif] font-medium text-xs text-white opacity-70"
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const trailingIconVariants = cva('items-center justify-center rounded-lg p-2');
|
|
52
|
+
|
|
53
|
+
/* -----------------------------------------------------
|
|
54
|
+
* Props
|
|
55
|
+
* --------------------------------------------------- */
|
|
56
|
+
|
|
57
|
+
export type ProfileCardProps = VariantProps<typeof rootVariants> & {
|
|
58
|
+
/** User name */
|
|
59
|
+
userName?: string;
|
|
60
|
+
|
|
61
|
+
/** User ID or identifier */
|
|
62
|
+
userID?: string;
|
|
63
|
+
|
|
64
|
+
/** Avatar initials */
|
|
65
|
+
avatarInitials?: string;
|
|
66
|
+
|
|
67
|
+
/** Avatar image source */
|
|
68
|
+
avatarSource?: any;
|
|
69
|
+
|
|
70
|
+
/** Avatar type */
|
|
71
|
+
avatarType?: 'initials' | 'image' | 'icon';
|
|
72
|
+
|
|
73
|
+
/** Callback when profile card is pressed */
|
|
74
|
+
onPress?: () => void;
|
|
75
|
+
|
|
76
|
+
/** Used to override the default root style. */
|
|
77
|
+
style?: StyleProp<ViewStyle>;
|
|
78
|
+
|
|
79
|
+
/** Used to locate this view in end-to-end tests. */
|
|
80
|
+
testID?: string;
|
|
81
|
+
|
|
82
|
+
/** Strictly block passing className */
|
|
83
|
+
className?: never;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/* -----------------------------------------------------
|
|
87
|
+
* Component
|
|
88
|
+
* --------------------------------------------------- */
|
|
89
|
+
|
|
90
|
+
export function ProfileCard(props: ProfileCardProps) {
|
|
91
|
+
const {
|
|
92
|
+
userName = 'Marshall Mathers',
|
|
93
|
+
userID = '3472732323',
|
|
94
|
+
avatarInitials = 'MM',
|
|
95
|
+
avatarSource,
|
|
96
|
+
avatarType = 'initials',
|
|
97
|
+
onPress,
|
|
98
|
+
style,
|
|
99
|
+
testID,
|
|
100
|
+
} = props;
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<Pressable
|
|
104
|
+
testID={testID ?? 'profile-card'}
|
|
105
|
+
onPress={onPress}
|
|
106
|
+
className={cn(rootVariants())}
|
|
107
|
+
style={profileCardStyle(style)}
|
|
108
|
+
hitSlop={8}
|
|
109
|
+
>
|
|
110
|
+
<View
|
|
111
|
+
testID="profile-card-content"
|
|
112
|
+
className={cn(contentContainerVariants())}
|
|
113
|
+
>
|
|
114
|
+
{/* Avatar - Square */}
|
|
115
|
+
<View
|
|
116
|
+
testID="profile-card-avatar-wrapper"
|
|
117
|
+
className="rounded-[12px] overflow-hidden items-center justify-center bg-surface-subtle"
|
|
118
|
+
style={{
|
|
119
|
+
width: '80',
|
|
120
|
+
height: '80',
|
|
121
|
+
}}
|
|
122
|
+
>
|
|
123
|
+
{avatarType === 'image' && avatarSource ? (
|
|
124
|
+
<RNImage
|
|
125
|
+
testID="profile-card-avatar-image"
|
|
126
|
+
source={avatarSource}
|
|
127
|
+
className="w-full h-full"
|
|
128
|
+
/>
|
|
129
|
+
) : (
|
|
130
|
+
<RNText
|
|
131
|
+
testID="profile-card-avatar-initials"
|
|
132
|
+
className="font-semibold text-xl text-muted-foreground"
|
|
133
|
+
>
|
|
134
|
+
{avatarInitials}
|
|
135
|
+
</RNText>
|
|
136
|
+
)}
|
|
137
|
+
</View>
|
|
138
|
+
|
|
139
|
+
{/* User Info */}
|
|
140
|
+
<View testID="profile-card-info" className={cn(infoColumnVariants())}>
|
|
141
|
+
<RNText
|
|
142
|
+
testID="profile-card-name"
|
|
143
|
+
numberOfLines={1}
|
|
144
|
+
className={cn(nameTextVariants())}
|
|
145
|
+
>
|
|
146
|
+
{userName}
|
|
147
|
+
</RNText>
|
|
148
|
+
|
|
149
|
+
<RNText
|
|
150
|
+
testID="profile-card-id"
|
|
151
|
+
numberOfLines={1}
|
|
152
|
+
className={cn(idTextVariants())}
|
|
153
|
+
>
|
|
154
|
+
{userID}
|
|
155
|
+
</RNText>
|
|
156
|
+
</View>
|
|
157
|
+
</View>
|
|
158
|
+
|
|
159
|
+
{/* Trailing Icon */}
|
|
160
|
+
<View
|
|
161
|
+
testID="profile-card-trailing"
|
|
162
|
+
className={cn(trailingIconVariants())}
|
|
163
|
+
>
|
|
164
|
+
<ChevronRight size={16} color="white" />
|
|
165
|
+
</View>
|
|
166
|
+
</Pressable>
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
ProfileCard.displayName = 'ProfileCard';
|
|
171
|
+
|
|
172
|
+
export { rootVariants };
|
|
173
|
+
export type { ProfileCardProps };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ProfileCard';
|