crew-recommendation-ui 0.0.1

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 (43) hide show
  1. package/README.md +156 -0
  2. package/dist/Card-C6fF0ZrH.js +197 -0
  3. package/dist/Card-C6fF0ZrH.js.map +1 -0
  4. package/dist/dls/index.d.ts +8 -0
  5. package/dist/dls/index.d.ts.map +1 -0
  6. package/dist/dls/index.js +25 -0
  7. package/dist/dls/index.js.map +1 -0
  8. package/dist/dls/tokens/colors.d.ts +77 -0
  9. package/dist/dls/tokens/colors.d.ts.map +1 -0
  10. package/dist/dls/tokens/index.d.ts +215 -0
  11. package/dist/dls/tokens/index.d.ts.map +1 -0
  12. package/dist/dls/tokens/spacing.d.ts +46 -0
  13. package/dist/dls/tokens/spacing.d.ts.map +1 -0
  14. package/dist/dls/tokens/typography.d.ts +102 -0
  15. package/dist/dls/tokens/typography.d.ts.map +1 -0
  16. package/dist/index.d.ts +17 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +20 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/package.json +60 -0
  21. package/dist/recommendation/components/Card.d.ts +13 -0
  22. package/dist/recommendation/components/Card.d.ts.map +1 -0
  23. package/dist/recommendation/components/index.d.ts +6 -0
  24. package/dist/recommendation/components/index.d.ts.map +1 -0
  25. package/dist/recommendation/index.d.ts +9 -0
  26. package/dist/recommendation/index.d.ts.map +1 -0
  27. package/dist/recommendation/index.js +6 -0
  28. package/dist/recommendation/index.js.map +1 -0
  29. package/dist/recommendation/types.d.ts +71 -0
  30. package/dist/recommendation/types.d.ts.map +1 -0
  31. package/dist/typography-zz5GzgjI.js +245 -0
  32. package/dist/typography-zz5GzgjI.js.map +1 -0
  33. package/package.json +60 -0
  34. package/src/dls/index.ts +15 -0
  35. package/src/dls/tokens/colors.ts +94 -0
  36. package/src/dls/tokens/index.ts +30 -0
  37. package/src/dls/tokens/spacing.ts +62 -0
  38. package/src/dls/tokens/typography.ts +119 -0
  39. package/src/index.ts +25 -0
  40. package/src/recommendation/components/Card.tsx +191 -0
  41. package/src/recommendation/components/index.ts +14 -0
  42. package/src/recommendation/index.ts +15 -0
  43. package/src/recommendation/types.ts +87 -0
@@ -0,0 +1,191 @@
1
+ import React from 'react';
2
+ import { clsx } from 'clsx';
3
+ import { colors, spacing, textStyles } from '../../dls/tokens';
4
+ import type { BaseRecommendationItem, RecommendationCardProps } from '../types';
5
+
6
+ /**
7
+ * Base Recommendation Card Component
8
+ *
9
+ * This is a generic card that can display any recommendation item.
10
+ * Specific card types (Hotel, Flight, Cab) will extend this.
11
+ */
12
+ export const Card = <T extends BaseRecommendationItem>({
13
+ item,
14
+ onSelect,
15
+ onExpand,
16
+ isSelected = false,
17
+ isExpanded = false,
18
+ }: RecommendationCardProps<T>) => {
19
+ const handleClick = () => {
20
+ if (onExpand) {
21
+ onExpand(item);
22
+ }
23
+ };
24
+
25
+ const handleSelect = (e: React.MouseEvent) => {
26
+ e.stopPropagation();
27
+ if (onSelect) {
28
+ onSelect(item);
29
+ }
30
+ };
31
+
32
+ // Get the first image URL
33
+ const imageUrl = item.image_signed_urls?.[0] || item.image?.[0]?.data;
34
+
35
+ return (
36
+ <div
37
+ onClick={handleClick}
38
+ className={clsx(
39
+ 'recommendation-card',
40
+ isSelected && 'recommendation-card--selected',
41
+ isExpanded && 'recommendation-card--expanded'
42
+ )}
43
+ style={{
44
+ display: 'flex',
45
+ flexDirection: 'column',
46
+ backgroundColor: isSelected ? colors.card.selected.dark : colors.card.background.dark,
47
+ borderRadius: 16,
48
+ overflow: 'hidden',
49
+ cursor: 'pointer',
50
+ transition: 'all 0.2s ease-in-out',
51
+ border: `1px solid ${isSelected ? colors.primary[500] : colors.card.border.dark}`,
52
+ }}
53
+ >
54
+ {/* Image Section */}
55
+ {imageUrl && (
56
+ <div
57
+ style={{
58
+ width: '100%',
59
+ height: 180,
60
+ overflow: 'hidden',
61
+ }}
62
+ >
63
+ <img
64
+ src={imageUrl}
65
+ alt={item.title}
66
+ style={{
67
+ width: '100%',
68
+ height: '100%',
69
+ objectFit: 'cover',
70
+ }}
71
+ />
72
+ </div>
73
+ )}
74
+
75
+ {/* Content Section */}
76
+ <div
77
+ style={{
78
+ padding: spacing[4],
79
+ display: 'flex',
80
+ flexDirection: 'column',
81
+ gap: spacing[2],
82
+ }}
83
+ >
84
+ {/* Title */}
85
+ <h3
86
+ style={{
87
+ ...textStyles.cardTitle,
88
+ color: colors.neutral[0],
89
+ margin: 0,
90
+ }}
91
+ >
92
+ {item.title}
93
+ </h3>
94
+
95
+ {/* Subtitle */}
96
+ {item.subtitle && (
97
+ <p
98
+ style={{
99
+ ...textStyles.cardSubtitle,
100
+ color: colors.neutral[400],
101
+ margin: 0,
102
+ }}
103
+ >
104
+ {item.subtitle}
105
+ </p>
106
+ )}
107
+
108
+ {/* Tags */}
109
+ {item.tags && item.tags.length > 0 && (
110
+ <div
111
+ style={{
112
+ display: 'flex',
113
+ flexWrap: 'wrap',
114
+ gap: spacing[1],
115
+ }}
116
+ >
117
+ {item.tags.map((tag, index) => (
118
+ <span
119
+ key={index}
120
+ style={{
121
+ ...textStyles.caption,
122
+ backgroundColor: colors.primary[900],
123
+ color: colors.primary[300],
124
+ padding: `${spacing[0.5]}px ${spacing[2]}px`,
125
+ borderRadius: 4,
126
+ }}
127
+ >
128
+ {tag}
129
+ </span>
130
+ ))}
131
+ </div>
132
+ )}
133
+
134
+ {/* Price Section */}
135
+ <div
136
+ style={{
137
+ display: 'flex',
138
+ alignItems: 'baseline',
139
+ gap: spacing[2],
140
+ marginTop: spacing[2],
141
+ }}
142
+ >
143
+ <span
144
+ style={{
145
+ ...textStyles.cardPrice,
146
+ color: colors.neutral[0],
147
+ }}
148
+ >
149
+ {item.price}
150
+ </span>
151
+ {item.originalPrice && (
152
+ <span
153
+ style={{
154
+ ...textStyles.bodySmall,
155
+ color: colors.neutral[500],
156
+ textDecoration: 'line-through',
157
+ }}
158
+ >
159
+ {item.originalPrice}
160
+ </span>
161
+ )}
162
+ </div>
163
+
164
+ {/* Select Button */}
165
+ <button
166
+ onClick={handleSelect}
167
+ style={{
168
+ marginTop: spacing[2],
169
+ padding: `${spacing[2]}px ${spacing[4]}px`,
170
+ backgroundColor: isSelected ? colors.success[600] : colors.primary[600],
171
+ color: colors.neutral[0],
172
+ border: 'none',
173
+ borderRadius: 8,
174
+ cursor: 'pointer',
175
+ ...textStyles.label,
176
+ transition: 'background-color 0.2s ease-in-out',
177
+ }}
178
+ >
179
+ {isSelected ? '✓ Selected' : 'Select'}
180
+ </button>
181
+ </div>
182
+ </div>
183
+ );
184
+ };
185
+
186
+ Card.displayName = 'RecommendationCard';
187
+
188
+ export default Card;
189
+
190
+
191
+
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Recommendation Components
3
+ * Export all card components from here
4
+ */
5
+
6
+ export { Card, default as RecommendationCard } from './Card';
7
+
8
+ // Future exports:
9
+ // export { HotelCard } from './HotelCard';
10
+ // export { FlightCard } from './FlightCard';
11
+ // export { CabCard } from './CabCard';
12
+
13
+
14
+
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Recommendation Listing Module
3
+ *
4
+ * Contains all recommendation card components and types
5
+ * for displaying hotels, flights, cabs, etc.
6
+ */
7
+
8
+ // Export types
9
+ export * from './types';
10
+
11
+ // Export components
12
+ export * from './components';
13
+
14
+
15
+
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Types for recommendation listing components
3
+ */
4
+
5
+ export interface ProductImage {
6
+ data: string;
7
+ url?: string;
8
+ }
9
+
10
+ export interface BaseRecommendationItem {
11
+ id: string;
12
+ title: string;
13
+ subtitle?: string;
14
+ description?: string;
15
+ price: string;
16
+ originalPrice?: string;
17
+ image?: ProductImage[];
18
+ image_signed_urls?: string[];
19
+ recommended?: boolean;
20
+ tags?: string[];
21
+ }
22
+
23
+ // Hotel specific
24
+ export interface HotelItem extends BaseRecommendationItem {
25
+ type: 'hotel';
26
+ rating?: string;
27
+ ratingCount?: string;
28
+ location?: string;
29
+ amenities?: string[];
30
+ checkIn?: string;
31
+ checkOut?: string;
32
+ }
33
+
34
+ // Flight specific
35
+ export interface FlightItem extends BaseRecommendationItem {
36
+ type: 'flight';
37
+ airlineName?: string;
38
+ economyType?: string;
39
+ date?: string;
40
+ takeoffTime?: string;
41
+ takeoffLocation?: string;
42
+ landingTime?: string;
43
+ landingLocation?: string;
44
+ duration?: string;
45
+ layoverText?: string;
46
+ isRoundTrip?: boolean;
47
+ }
48
+
49
+ // Cab specific
50
+ export interface CabItem extends BaseRecommendationItem {
51
+ type: 'cab';
52
+ providerName?: string;
53
+ carType?: string;
54
+ carName?: string;
55
+ pickupLocation?: string;
56
+ dropLocation?: string;
57
+ estimatedTime?: string;
58
+ }
59
+
60
+ // Union type for all recommendation items
61
+ export type RecommendationItem = HotelItem | FlightItem | CabItem;
62
+
63
+ // Props for the recommendation card component
64
+ export interface RecommendationCardProps<T extends BaseRecommendationItem = BaseRecommendationItem> {
65
+ item: T;
66
+ onSelect?: (item: T) => void;
67
+ onExpand?: (item: T) => void;
68
+ isSelected?: boolean;
69
+ isExpanded?: boolean;
70
+ showVote?: boolean;
71
+ voteCount?: number;
72
+ onVote?: (itemId: string) => void;
73
+ }
74
+
75
+ // Props for the recommendation listing component
76
+ export interface RecommendationListingProps {
77
+ items: RecommendationItem[];
78
+ type: 'hotel' | 'flight' | 'cab' | 'restaurant' | 'gifting';
79
+ onItemSelect?: (item: RecommendationItem) => void;
80
+ onItemExpand?: (item: RecommendationItem) => void;
81
+ selectedItemId?: string;
82
+ expandedItemId?: string;
83
+ showVoting?: boolean;
84
+ }
85
+
86
+
87
+