@umituz/react-native-design-system 2.6.103 → 2.6.105
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/package.json +1 -1
- package/src/atoms/card/AtomicCard.tsx +183 -0
- package/src/atoms/card/configs/cardPaddingConfig.ts +19 -0
- package/src/atoms/card/index.ts +2 -0
- package/src/atoms/card/styles/cardStyles.ts +98 -0
- package/src/atoms/card/types.ts +77 -0
- package/src/atoms/index.ts +3 -4
- package/src/exports/molecules.ts +7 -11
- package/src/molecules/action-footer/types.ts +1 -1
- package/src/molecules/filter-group/FilterGroup.tsx +1 -1
- package/src/molecules/hero-section/types.ts +1 -1
- package/src/molecules/index.ts +5 -10
- package/src/molecules/info-grid/InfoGrid.tsx +102 -0
- package/src/molecules/info-grid/index.ts +3 -0
- package/src/molecules/info-grid/types.ts +17 -0
- package/src/theme/infrastructure/providers/DesignSystemProvider.tsx +0 -1
- package/src/atoms/AtomicCard.tsx +0 -104
- package/src/molecules/GlowingCard/GlowingCard.tsx +0 -81
- package/src/molecules/GlowingCard/README.md +0 -306
- package/src/molecules/GlowingCard/index.ts +0 -1
- package/src/molecules/info-card/InfoCard.tsx +0 -44
- package/src/molecules/info-card/index.ts +0 -3
- package/src/molecules/info-card/types.ts +0 -9
- package/src/molecules/media-card/MediaCard.tsx +0 -157
- package/src/molecules/media-card/README.md +0 -282
- package/src/molecules/media-card/index.ts +0 -2
- package/src/molecules/media-card/types.ts +0 -40
package/src/atoms/AtomicCard.tsx
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AtomicCard Component
|
|
3
|
-
*
|
|
4
|
-
* A simple, styled card container component
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import React from 'react';
|
|
8
|
-
import {
|
|
9
|
-
View,
|
|
10
|
-
Pressable,
|
|
11
|
-
StyleSheet,
|
|
12
|
-
type ViewStyle,
|
|
13
|
-
type StyleProp,
|
|
14
|
-
type GestureResponderEvent,
|
|
15
|
-
} from 'react-native';
|
|
16
|
-
import { useAppDesignTokens } from '../theme';
|
|
17
|
-
|
|
18
|
-
export type AtomicCardVariant = 'elevated' | 'outlined' | 'filled';
|
|
19
|
-
export type AtomicCardPadding = 'none' | 'sm' | 'md' | 'lg';
|
|
20
|
-
|
|
21
|
-
export interface AtomicCardProps {
|
|
22
|
-
children: React.ReactNode;
|
|
23
|
-
variant?: AtomicCardVariant;
|
|
24
|
-
padding?: AtomicCardPadding;
|
|
25
|
-
style?: StyleProp<ViewStyle>;
|
|
26
|
-
testID?: string;
|
|
27
|
-
onPress?: (event: GestureResponderEvent) => void;
|
|
28
|
-
disabled?: boolean;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export const AtomicCard: React.FC<AtomicCardProps> = ({
|
|
32
|
-
children,
|
|
33
|
-
variant = 'elevated',
|
|
34
|
-
padding = 'md',
|
|
35
|
-
style,
|
|
36
|
-
testID,
|
|
37
|
-
onPress,
|
|
38
|
-
disabled,
|
|
39
|
-
}) => {
|
|
40
|
-
const tokens = useAppDesignTokens();
|
|
41
|
-
|
|
42
|
-
const paddingValues: Record<AtomicCardPadding, number> = {
|
|
43
|
-
none: 0,
|
|
44
|
-
sm: tokens.spacing.sm,
|
|
45
|
-
md: tokens.spacing.md,
|
|
46
|
-
lg: tokens.spacing.lg,
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const getVariantStyle = (): ViewStyle => {
|
|
50
|
-
switch (variant) {
|
|
51
|
-
case 'elevated':
|
|
52
|
-
return {
|
|
53
|
-
backgroundColor: tokens.colors.surface,
|
|
54
|
-
borderWidth: 1,
|
|
55
|
-
borderColor: tokens.colors.outlineVariant || tokens.colors.outline,
|
|
56
|
-
};
|
|
57
|
-
case 'outlined':
|
|
58
|
-
return {
|
|
59
|
-
backgroundColor: tokens.colors.surface,
|
|
60
|
-
borderWidth: 1,
|
|
61
|
-
borderColor: tokens.colors.outline,
|
|
62
|
-
};
|
|
63
|
-
case 'filled':
|
|
64
|
-
return {
|
|
65
|
-
backgroundColor: tokens.colors.surfaceVariant,
|
|
66
|
-
};
|
|
67
|
-
default:
|
|
68
|
-
return {};
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const cardStyle = [
|
|
73
|
-
styles.card,
|
|
74
|
-
{ borderRadius: tokens.borders.radius.md },
|
|
75
|
-
{ padding: paddingValues[padding] },
|
|
76
|
-
getVariantStyle(),
|
|
77
|
-
style,
|
|
78
|
-
];
|
|
79
|
-
|
|
80
|
-
if (onPress) {
|
|
81
|
-
return (
|
|
82
|
-
<Pressable
|
|
83
|
-
style={cardStyle}
|
|
84
|
-
testID={testID}
|
|
85
|
-
onPress={onPress}
|
|
86
|
-
disabled={disabled}
|
|
87
|
-
>
|
|
88
|
-
{children}
|
|
89
|
-
</Pressable>
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return (
|
|
94
|
-
<View style={cardStyle} testID={testID}>
|
|
95
|
-
{children}
|
|
96
|
-
</View>
|
|
97
|
-
);
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const styles = StyleSheet.create({
|
|
101
|
-
card: {
|
|
102
|
-
overflow: 'hidden',
|
|
103
|
-
},
|
|
104
|
-
});
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { View, StyleSheet, StyleProp, ViewStyle, Pressable, GestureResponderEvent } from 'react-native';
|
|
3
|
-
import { useAppDesignTokens } from '../../theme';
|
|
4
|
-
|
|
5
|
-
export interface GlowingCardProps {
|
|
6
|
-
children: React.ReactNode;
|
|
7
|
-
glowColor?: string;
|
|
8
|
-
intensity?: number; // 0 to 1, default 1
|
|
9
|
-
style?: StyleProp<ViewStyle>;
|
|
10
|
-
onPress?: (event: GestureResponderEvent) => void;
|
|
11
|
-
testID?: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* GlowingCard
|
|
16
|
-
*
|
|
17
|
-
* A card component with a neon-like glow effect using shadows.
|
|
18
|
-
*/
|
|
19
|
-
export const GlowingCard: React.FC<GlowingCardProps> = ({
|
|
20
|
-
children,
|
|
21
|
-
glowColor,
|
|
22
|
-
intensity = 1,
|
|
23
|
-
style,
|
|
24
|
-
onPress,
|
|
25
|
-
testID,
|
|
26
|
-
}) => {
|
|
27
|
-
const tokens = useAppDesignTokens();
|
|
28
|
-
const resolvedColor = glowColor || tokens.colors.primary;
|
|
29
|
-
|
|
30
|
-
const shadowStyle: ViewStyle = {
|
|
31
|
-
shadowColor: resolvedColor,
|
|
32
|
-
shadowOffset: { width: 0, height: 0 },
|
|
33
|
-
shadowOpacity: 0.6 * intensity,
|
|
34
|
-
shadowRadius: 10 * intensity,
|
|
35
|
-
elevation: 8 * intensity, // Android elevation
|
|
36
|
-
// We allow the style prop to override backgroundColor, default to surface if not provided
|
|
37
|
-
backgroundColor: tokens.colors.surface,
|
|
38
|
-
borderRadius: tokens.borders.radius.md,
|
|
39
|
-
borderColor: resolvedColor,
|
|
40
|
-
borderWidth: 1,
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
// Extract background color from style if present to override default
|
|
44
|
-
const styleObj = StyleSheet.flatten(style) || {};
|
|
45
|
-
const finalBackgroundColor = styleObj.backgroundColor || shadowStyle.backgroundColor;
|
|
46
|
-
|
|
47
|
-
const containerStyle = [
|
|
48
|
-
styles.container,
|
|
49
|
-
shadowStyle,
|
|
50
|
-
style,
|
|
51
|
-
// Ensure background color is consistent
|
|
52
|
-
{ backgroundColor: finalBackgroundColor }
|
|
53
|
-
];
|
|
54
|
-
|
|
55
|
-
if (onPress) {
|
|
56
|
-
return (
|
|
57
|
-
<Pressable
|
|
58
|
-
style={({ pressed }) => [
|
|
59
|
-
containerStyle,
|
|
60
|
-
pressed && { opacity: 0.9, transform: [{ scale: 0.98 }] }
|
|
61
|
-
]}
|
|
62
|
-
onPress={onPress}
|
|
63
|
-
testID={testID}
|
|
64
|
-
>
|
|
65
|
-
{children}
|
|
66
|
-
</Pressable>
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return (
|
|
71
|
-
<View style={containerStyle} testID={testID}>
|
|
72
|
-
{children}
|
|
73
|
-
</View>
|
|
74
|
-
);
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
const styles = StyleSheet.create({
|
|
78
|
-
container: {
|
|
79
|
-
overflow: 'hidden', // Clip content to border radius
|
|
80
|
-
},
|
|
81
|
-
});
|
|
@@ -1,306 +0,0 @@
|
|
|
1
|
-
# GlowingCard
|
|
2
|
-
|
|
3
|
-
A card component with neon-like glowing shadow effect for highlighting important content and creating visual emphasis.
|
|
4
|
-
|
|
5
|
-
## Import & Usage
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
import { GlowingCard } from 'react-native-design-system/src/molecules/GlowingCard';
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
**Location:** `src/molecules/GlowingCard/GlowingCard.tsx`
|
|
12
|
-
|
|
13
|
-
## Basic Usage
|
|
14
|
-
|
|
15
|
-
```tsx
|
|
16
|
-
<GlowingCard glowColor="#6366f1" intensity={0.5}>
|
|
17
|
-
<YourContent />
|
|
18
|
-
</GlowingCard>
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Strategy
|
|
22
|
-
|
|
23
|
-
**Purpose**: Create visual emphasis and draw attention to specific content through glowing effects.
|
|
24
|
-
|
|
25
|
-
**When to Use**:
|
|
26
|
-
- Featured products or items
|
|
27
|
-
- Premium content highlighting
|
|
28
|
-
- Important announcements
|
|
29
|
-
- Achievement badges
|
|
30
|
-
- Limited-time offers
|
|
31
|
-
- User highlights (verified users, contributors)
|
|
32
|
-
|
|
33
|
-
**When NOT to Use**:
|
|
34
|
-
- Regular content cards (use AtomicCard instead)
|
|
35
|
-
- Multiple items on same screen (causes visual clutter)
|
|
36
|
-
- Background elements
|
|
37
|
-
- Non-essential content
|
|
38
|
-
|
|
39
|
-
## Rules
|
|
40
|
-
|
|
41
|
-
### Required
|
|
42
|
-
|
|
43
|
-
1. **MUST** provide a `glowColor` prop
|
|
44
|
-
2. **MUST** keep `intensity` between 0.3 and 0.8
|
|
45
|
-
3. **ALWAYS** use sparingly (max 1-2 per screen)
|
|
46
|
-
4. **MUST** ensure sufficient contrast with glow color
|
|
47
|
-
5. **SHOULD** have purpose (highlight featured content)
|
|
48
|
-
|
|
49
|
-
### Intensity Guidelines
|
|
50
|
-
|
|
51
|
-
1. **Subtle emphasis**: 0.3 - 0.5
|
|
52
|
-
2. **Medium emphasis**: 0.5 - 0.7
|
|
53
|
-
3. **Strong emphasis**: 0.7 - 0.8
|
|
54
|
-
|
|
55
|
-
**Never use intensity > 0.8** (too distracting)
|
|
56
|
-
|
|
57
|
-
### Color Selection
|
|
58
|
-
|
|
59
|
-
1. **MUST** use theme colors when possible
|
|
60
|
-
2. **SHOULD** match content purpose
|
|
61
|
-
3. **NEVER** use pure neon colors (#00FF00, #FF00FF, etc.)
|
|
62
|
-
|
|
63
|
-
## Forbidden
|
|
64
|
-
|
|
65
|
-
❌ **NEVER** do these:
|
|
66
|
-
|
|
67
|
-
```tsx
|
|
68
|
-
// ❌ No glow color
|
|
69
|
-
<GlowingCard>
|
|
70
|
-
<Content />
|
|
71
|
-
</GlowingCard>
|
|
72
|
-
|
|
73
|
-
// ❌ Too high intensity
|
|
74
|
-
<GlowingCard glowColor="#6366f1" intensity={1.0}>
|
|
75
|
-
<Content />
|
|
76
|
-
</GlowingCard>
|
|
77
|
-
|
|
78
|
-
// ❌ Too many glowing cards
|
|
79
|
-
<View>
|
|
80
|
-
<GlowingCard glowColor="#6366f1"><Content1 /></GlowingCard>
|
|
81
|
-
<GlowingCard glowColor="#10b981"><Content2 /></GlowingCard>
|
|
82
|
-
<GlowingCard glowColor="#f59e0b"><Content3 /></GlowingCard>
|
|
83
|
-
{/* ❌ Max 1-2 per screen */}
|
|
84
|
-
</View>
|
|
85
|
-
|
|
86
|
-
// ❌ Neon colors
|
|
87
|
-
<GlowingCard glowColor="#00FF00" intensity={0.8}>
|
|
88
|
-
<Content />
|
|
89
|
-
</GlowingCard>
|
|
90
|
-
|
|
91
|
-
// ❌ Non-essential content
|
|
92
|
-
<GlowingCard glowColor="#6366f1">
|
|
93
|
-
<RegularContent /> {/* ❌ Use AtomicCard instead */}
|
|
94
|
-
</GlowingCard>
|
|
95
|
-
|
|
96
|
-
// ❌ Nested GlowingCards
|
|
97
|
-
<GlowingCard glowColor="#6366f1">
|
|
98
|
-
<GlowingCard glowColor="#10b981">
|
|
99
|
-
<Content />
|
|
100
|
-
</GlowingCard>
|
|
101
|
-
</GlowingCard>
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
## Best Practices
|
|
105
|
-
|
|
106
|
-
### Featured Content
|
|
107
|
-
|
|
108
|
-
✅ **DO**:
|
|
109
|
-
```tsx
|
|
110
|
-
<GlowingCard
|
|
111
|
-
glowColor={tokens.colors.primary}
|
|
112
|
-
intensity={0.6}
|
|
113
|
-
onPress={() => navigateTo(featuredItem)}
|
|
114
|
-
>
|
|
115
|
-
<FeaturedProductCard product={featuredProduct} />
|
|
116
|
-
</GlowingCard>
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
❌ **DON'T**:
|
|
120
|
-
```tsx
|
|
121
|
-
<GlowingCard glowColor="#ff0000" intensity={0.9}>
|
|
122
|
-
<RegularProduct />
|
|
123
|
-
</GlowingCard>
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
### Achievement Badges
|
|
127
|
-
|
|
128
|
-
✅ **DO**:
|
|
129
|
-
```tsx
|
|
130
|
-
<GlowingCard
|
|
131
|
-
glowColor="#f59e0b"
|
|
132
|
-
intensity={0.5}
|
|
133
|
-
style={{ width: 120, height: 120 }}
|
|
134
|
-
>
|
|
135
|
-
<AchievementBadge achievement={achievement} />
|
|
136
|
-
</GlowingCard>
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### User Highlights
|
|
140
|
-
|
|
141
|
-
✅ **DO**:
|
|
142
|
-
```tsx
|
|
143
|
-
<GlowingCard glowColor="#8b5cf6" intensity={0.4}>
|
|
144
|
-
<UserHighlight user={verifiedUser} />
|
|
145
|
-
</GlowingCard>
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### Color by Purpose
|
|
149
|
-
|
|
150
|
-
✅ **DO**:
|
|
151
|
-
- Primary actions: Theme primary color
|
|
152
|
-
- Success: Green (#10b981, #22c55e)
|
|
153
|
-
- Warning: Orange/Amber (#f59e0b, #f97316)
|
|
154
|
-
- Error: Red (#ef4444, #dc2626)
|
|
155
|
-
- Info: Blue (#3b82f6, #2563eb)
|
|
156
|
-
|
|
157
|
-
❌ **DON'T**:
|
|
158
|
-
```tsx
|
|
159
|
-
// ❌ Random colors
|
|
160
|
-
<GlowingCard glowColor="#123456" />
|
|
161
|
-
|
|
162
|
-
// ❌ Too bright
|
|
163
|
-
<GlowingCard glowColor="#00FF00" />
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
## AI Coding Guidelines
|
|
167
|
-
|
|
168
|
-
### For AI Agents
|
|
169
|
-
|
|
170
|
-
When generating GlowingCard components, follow these rules:
|
|
171
|
-
|
|
172
|
-
1. **Always import from correct path**:
|
|
173
|
-
```typescript
|
|
174
|
-
import { GlowingCard } from 'react-native-design-system/src/molecules/GlowingCard';
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
2. **Always specify glowColor**:
|
|
178
|
-
```tsx
|
|
179
|
-
<GlowingCard
|
|
180
|
-
glowColor={根据内容选择合适的颜色}
|
|
181
|
-
intensity={0.5-0.7之间的值}
|
|
182
|
-
>
|
|
183
|
-
{content}
|
|
184
|
-
</GlowingCard>
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
3. **Never use without purpose**:
|
|
188
|
-
```tsx
|
|
189
|
-
// ❌ Bad - arbitrary use
|
|
190
|
-
<GlowingCard glowColor="#6366f1">
|
|
191
|
-
<RegularContent />
|
|
192
|
-
</GlowingCard>
|
|
193
|
-
|
|
194
|
-
// ✅ Good - featured content
|
|
195
|
-
{isFeatured && (
|
|
196
|
-
<GlowingCard glowColor="#6366f1" intensity={0.6}>
|
|
197
|
-
<FeaturedContent />
|
|
198
|
-
</GlowingCard>
|
|
199
|
-
)}
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
4. **Always limit usage on screen**:
|
|
203
|
-
```tsx
|
|
204
|
-
// ✅ Good - conditional highlighting
|
|
205
|
-
<View>
|
|
206
|
-
{items.map((item, index) =>
|
|
207
|
-
item.isFeatured ? (
|
|
208
|
-
<GlowingCard key={item.id} glowColor="#6366f1" intensity={0.6}>
|
|
209
|
-
<ItemCard item={item} />
|
|
210
|
-
</GlowingCard>
|
|
211
|
-
) : (
|
|
212
|
-
<AtomicCard key={item.id}>
|
|
213
|
-
<ItemCard item={item} />
|
|
214
|
-
</AtomicCard>
|
|
215
|
-
)
|
|
216
|
-
)}
|
|
217
|
-
</View>
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
5. **Always use semantic colors**:
|
|
221
|
-
```tsx
|
|
222
|
-
// ✅ Good - color by purpose
|
|
223
|
-
const getGlowColor = (type: 'success' | 'warning' | 'error') => {
|
|
224
|
-
switch (type) {
|
|
225
|
-
case 'success': return '#10b981';
|
|
226
|
-
case 'warning': return '#f59e0b';
|
|
227
|
-
case 'error': return '#ef4444';
|
|
228
|
-
default: return tokens.colors.primary;
|
|
229
|
-
}
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
<GlowingCard glowColor={getGlowColor(type)} />
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
### Common Patterns
|
|
236
|
-
|
|
237
|
-
#### Featured Product
|
|
238
|
-
```tsx
|
|
239
|
-
<GlowingCard
|
|
240
|
-
glowColor="#6366f1"
|
|
241
|
-
intensity={0.6}
|
|
242
|
-
onPress={() => navigation.navigate('Product', { productId: product.id })}
|
|
243
|
-
>
|
|
244
|
-
<ProductCard product={product} variant="featured" />
|
|
245
|
-
</GlowingCard>
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
#### Achievement Badge
|
|
249
|
-
```tsx
|
|
250
|
-
<GlowingCard
|
|
251
|
-
glowColor="#f59e0b"
|
|
252
|
-
intensity={0.5}
|
|
253
|
-
style={{ margin: 8 }}
|
|
254
|
-
>
|
|
255
|
-
<AchievementBadge achievement={achievement} />
|
|
256
|
-
</GlowingCard>
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
#### Notification Card
|
|
260
|
-
```tsx
|
|
261
|
-
<GlowingCard
|
|
262
|
-
glowColor={notification.urgency === 'high' ? '#ef4444' : '#3b82f6'}
|
|
263
|
-
intensity={notification.urgency === 'high' ? 0.7 : 0.4}
|
|
264
|
-
onPress={() => markAsRead(notification.id)}
|
|
265
|
-
>
|
|
266
|
-
<NotificationCard notification={notification} />
|
|
267
|
-
</GlowingCard>
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
## Props Reference
|
|
271
|
-
|
|
272
|
-
| Prop | Type | Required | Default | Description |
|
|
273
|
-
|------|------|----------|---------|-------------|
|
|
274
|
-
| `glowColor` | `string` | **Yes** | Theme primary color | Glow color (hex) |
|
|
275
|
-
| `intensity` | `number` | No | `0.5` | Glow intensity (0-1) |
|
|
276
|
-
| `borderWidth` | `number` | No | `0` | Border width |
|
|
277
|
-
| `borderColor` | `string` | No | Same as glowColor | Border color |
|
|
278
|
-
| `onPress` | `() => void` | No | - | Press callback |
|
|
279
|
-
| `style` | `ViewStyle` | No | - | Custom container style |
|
|
280
|
-
| `children` | `ReactNode` | **Yes** | - | Card content |
|
|
281
|
-
|
|
282
|
-
## Accessibility
|
|
283
|
-
|
|
284
|
-
- ✅ Screen reader announces card content
|
|
285
|
-
- ✅ Touch target size maintained (min 44x44pt)
|
|
286
|
-
- ✅ Focus indicators for pressable cards
|
|
287
|
-
- ✅ Sufficient color contrast with glow
|
|
288
|
-
- ✅ Semantic structure preserved
|
|
289
|
-
|
|
290
|
-
## Performance Tips
|
|
291
|
-
|
|
292
|
-
1. **Use sparingly**: Only for highlights (1-2 per screen max)
|
|
293
|
-
2. **Lower intensity**: Better performance with 0.3-0.5
|
|
294
|
-
3. **Avoid animation**: Static glow more performant
|
|
295
|
-
4. **Conditional rendering**: Don't use for every card
|
|
296
|
-
5. **Memo content**: Memo card content to prevent re-renders
|
|
297
|
-
|
|
298
|
-
## Related Components
|
|
299
|
-
|
|
300
|
-
- [`AtomicCard`](../../atoms/AtomicCard/README.md) - Base card component
|
|
301
|
-
- [`MediaCard`](../media-card/README.md) - Media card component
|
|
302
|
-
- [`AtomicIcon`](../../atoms/AtomicIcon/README.md) - Icon component
|
|
303
|
-
|
|
304
|
-
## License
|
|
305
|
-
|
|
306
|
-
MIT
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './GlowingCard';
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import { View, StyleSheet } from 'react-native';
|
|
4
|
-
import { AtomicText } from '../../atoms/AtomicText';
|
|
5
|
-
import { useAppDesignTokens } from '../../theme';
|
|
6
|
-
import type { InfoCardProps } from './types';
|
|
7
|
-
|
|
8
|
-
export const InfoCard: React.FC<InfoCardProps> = ({
|
|
9
|
-
title,
|
|
10
|
-
content,
|
|
11
|
-
style,
|
|
12
|
-
}) => {
|
|
13
|
-
const tokens = useAppDesignTokens();
|
|
14
|
-
|
|
15
|
-
const styles = StyleSheet.create({
|
|
16
|
-
container: {
|
|
17
|
-
backgroundColor: tokens.colors.surface,
|
|
18
|
-
borderRadius: tokens.borders.radius.xl,
|
|
19
|
-
padding: tokens.spacing.lg,
|
|
20
|
-
borderWidth: 1,
|
|
21
|
-
borderColor: tokens.colors.outlineVariant,
|
|
22
|
-
},
|
|
23
|
-
title: {
|
|
24
|
-
...tokens.typography.labelLarge,
|
|
25
|
-
color: tokens.colors.primary,
|
|
26
|
-
fontWeight: '800', // Using string as expected by RN
|
|
27
|
-
textTransform: 'uppercase',
|
|
28
|
-
letterSpacing: 1,
|
|
29
|
-
marginBottom: tokens.spacing.xs,
|
|
30
|
-
},
|
|
31
|
-
content: {
|
|
32
|
-
...tokens.typography.bodyMedium,
|
|
33
|
-
color: tokens.colors.textPrimary,
|
|
34
|
-
lineHeight: 22,
|
|
35
|
-
},
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<View style={[styles.container, style]}>
|
|
40
|
-
<AtomicText style={styles.title}>{title}</AtomicText>
|
|
41
|
-
<AtomicText style={styles.content}>{content}</AtomicText>
|
|
42
|
-
</View>
|
|
43
|
-
);
|
|
44
|
-
};
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AtomicMediaCard - Reusable media card component
|
|
3
|
-
*
|
|
4
|
-
* Displays an image with optional overlay text, badge, and selection state.
|
|
5
|
-
* Used for grids of images, memes, templates, etc.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import React from 'react';
|
|
9
|
-
import {
|
|
10
|
-
View,
|
|
11
|
-
StyleSheet,
|
|
12
|
-
TouchableOpacity,
|
|
13
|
-
Image,
|
|
14
|
-
type ImageStyle,
|
|
15
|
-
} from 'react-native';
|
|
16
|
-
import { AtomicText, AtomicIcon } from '../../atoms';
|
|
17
|
-
import { useAppDesignTokens } from '../../theme';
|
|
18
|
-
|
|
19
|
-
import type { MediaCardProps } from './types';
|
|
20
|
-
|
|
21
|
-
export const MediaCard: React.FC<MediaCardProps> = ({
|
|
22
|
-
uri,
|
|
23
|
-
title,
|
|
24
|
-
subtitle,
|
|
25
|
-
badge,
|
|
26
|
-
selected = false,
|
|
27
|
-
size = 'md',
|
|
28
|
-
aspectRatio = 0.8,
|
|
29
|
-
overlayPosition = 'bottom',
|
|
30
|
-
showOverlay = true,
|
|
31
|
-
onPress,
|
|
32
|
-
width,
|
|
33
|
-
testID,
|
|
34
|
-
}) => {
|
|
35
|
-
const tokens = useAppDesignTokens();
|
|
36
|
-
|
|
37
|
-
const sizeConfig = {
|
|
38
|
-
sm: { width: width || 120, borderRadius: tokens.radius.sm },
|
|
39
|
-
md: { width: width || 144, borderRadius: tokens.radius.md },
|
|
40
|
-
lg: { width: width || 160, borderRadius: tokens.radius.lg },
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const config = sizeConfig[size];
|
|
44
|
-
const height = config.width / aspectRatio;
|
|
45
|
-
|
|
46
|
-
const styles = StyleSheet.create({
|
|
47
|
-
container: {
|
|
48
|
-
width: config.width,
|
|
49
|
-
height,
|
|
50
|
-
borderRadius: config.borderRadius,
|
|
51
|
-
overflow: 'hidden',
|
|
52
|
-
backgroundColor: tokens.colors.surfaceVariant,
|
|
53
|
-
borderWidth: selected ? tokens.borders.width.medium : tokens.borders.width.thin,
|
|
54
|
-
borderColor: selected ? tokens.colors.primary : tokens.colors.outline,
|
|
55
|
-
},
|
|
56
|
-
image: {
|
|
57
|
-
width: '100%',
|
|
58
|
-
height: '100%',
|
|
59
|
-
} as ImageStyle,
|
|
60
|
-
badge: {
|
|
61
|
-
position: 'absolute',
|
|
62
|
-
top: tokens.spacing.sm,
|
|
63
|
-
right: tokens.spacing.sm,
|
|
64
|
-
backgroundColor: tokens.colors.primary,
|
|
65
|
-
paddingHorizontal: tokens.spacing.sm,
|
|
66
|
-
paddingVertical: tokens.spacing.xs,
|
|
67
|
-
borderRadius: tokens.borders.radius.full,
|
|
68
|
-
zIndex: 10,
|
|
69
|
-
},
|
|
70
|
-
badgeText: {
|
|
71
|
-
color: tokens.colors.onPrimary,
|
|
72
|
-
fontSize: tokens.typography.labelSmall.fontSize,
|
|
73
|
-
fontWeight: 'bold',
|
|
74
|
-
},
|
|
75
|
-
overlay: {
|
|
76
|
-
position: 'absolute',
|
|
77
|
-
bottom: 0,
|
|
78
|
-
left: 0,
|
|
79
|
-
right: 0,
|
|
80
|
-
backgroundColor: tokens.colors.surfaceVariant,
|
|
81
|
-
opacity: 0.95,
|
|
82
|
-
justifyContent: 'flex-end',
|
|
83
|
-
paddingVertical: tokens.spacing.md,
|
|
84
|
-
paddingHorizontal: tokens.spacing.sm,
|
|
85
|
-
},
|
|
86
|
-
textContainer: {
|
|
87
|
-
width: '100%',
|
|
88
|
-
},
|
|
89
|
-
title: {
|
|
90
|
-
fontSize: tokens.typography.bodyMedium.fontSize,
|
|
91
|
-
fontWeight: 'bold',
|
|
92
|
-
color: tokens.colors.textInverse,
|
|
93
|
-
textAlign: 'left',
|
|
94
|
-
marginBottom: tokens.spacing.xs,
|
|
95
|
-
},
|
|
96
|
-
subtitle: {
|
|
97
|
-
fontSize: tokens.typography.bodySmall.fontSize,
|
|
98
|
-
color: tokens.colors.textSecondary,
|
|
99
|
-
opacity: 0.9,
|
|
100
|
-
textAlign: 'left',
|
|
101
|
-
},
|
|
102
|
-
checkCircle: {
|
|
103
|
-
position: 'absolute',
|
|
104
|
-
top: tokens.spacing.sm,
|
|
105
|
-
right: tokens.spacing.sm,
|
|
106
|
-
backgroundColor: tokens.colors.primary,
|
|
107
|
-
borderRadius: tokens.borders.radius.full,
|
|
108
|
-
width: tokens.spacing.lg,
|
|
109
|
-
height: tokens.spacing.lg,
|
|
110
|
-
alignItems: 'center',
|
|
111
|
-
justifyContent: 'center',
|
|
112
|
-
},
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
const CardWrapper = onPress ? TouchableOpacity : View;
|
|
116
|
-
const wrapperProps = onPress
|
|
117
|
-
? {
|
|
118
|
-
onPress,
|
|
119
|
-
activeOpacity: 0.8,
|
|
120
|
-
testID,
|
|
121
|
-
}
|
|
122
|
-
: { testID };
|
|
123
|
-
|
|
124
|
-
return (
|
|
125
|
-
<CardWrapper style={styles.container} {...wrapperProps}>
|
|
126
|
-
{badge && (
|
|
127
|
-
<View style={styles.badge}>
|
|
128
|
-
<AtomicText style={styles.badgeText}>{badge}</AtomicText>
|
|
129
|
-
</View>
|
|
130
|
-
)}
|
|
131
|
-
<Image source={{ uri }} style={styles.image} resizeMode="cover" />
|
|
132
|
-
|
|
133
|
-
{showOverlay && (title || subtitle) && (
|
|
134
|
-
<View style={styles.overlay}>
|
|
135
|
-
<View style={styles.textContainer}>
|
|
136
|
-
{title && (
|
|
137
|
-
<AtomicText style={styles.title} numberOfLines={1}>
|
|
138
|
-
{title}
|
|
139
|
-
</AtomicText>
|
|
140
|
-
)}
|
|
141
|
-
{subtitle && (
|
|
142
|
-
<AtomicText style={styles.subtitle} numberOfLines={1}>
|
|
143
|
-
{subtitle}
|
|
144
|
-
</AtomicText>
|
|
145
|
-
)}
|
|
146
|
-
</View>
|
|
147
|
-
</View>
|
|
148
|
-
)}
|
|
149
|
-
|
|
150
|
-
{selected && (
|
|
151
|
-
<View style={styles.checkCircle}>
|
|
152
|
-
<AtomicIcon name="checkmark-outline" size="sm" color="onPrimary" />
|
|
153
|
-
</View>
|
|
154
|
-
)}
|
|
155
|
-
</CardWrapper>
|
|
156
|
-
);
|
|
157
|
-
};
|