@syra.fm/sdk 0.5.0 → 0.6.0
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/README.md +33 -4
- package/lib/commonjs/live/colors.js +54 -0
- package/lib/commonjs/live/colors.js.map +1 -0
- package/lib/commonjs/live/components/LiveRoomSheet.js +9 -8
- package/lib/commonjs/live/components/LiveRoomSheet.js.map +1 -1
- package/lib/commonjs/live/components/MiniRoomBar.js +3 -2
- package/lib/commonjs/live/components/MiniRoomBar.js.map +1 -1
- package/lib/commonjs/live/components/PodcastStreamPicker.js +1 -1
- package/lib/commonjs/live/components/RecordingsPanel.js +3 -2
- package/lib/commonjs/live/components/RecordingsPanel.js.map +1 -1
- package/lib/commonjs/live/components/RoomCard.js +110 -314
- package/lib/commonjs/live/components/RoomCard.js.map +1 -1
- package/lib/commonjs/live/index.js +31 -0
- package/lib/commonjs/live/index.js.map +1 -1
- package/lib/module/live/colors.js +49 -0
- package/lib/module/live/colors.js.map +1 -0
- package/lib/module/live/components/LiveRoomSheet.js +9 -8
- package/lib/module/live/components/LiveRoomSheet.js.map +1 -1
- package/lib/module/live/components/MiniRoomBar.js +3 -2
- package/lib/module/live/components/MiniRoomBar.js.map +1 -1
- package/lib/module/live/components/PodcastStreamPicker.js +1 -1
- package/lib/module/live/components/RecordingsPanel.js +3 -2
- package/lib/module/live/components/RecordingsPanel.js.map +1 -1
- package/lib/module/live/components/RoomCard.js +109 -314
- package/lib/module/live/components/RoomCard.js.map +1 -1
- package/lib/module/live/index.js +4 -0
- package/lib/module/live/index.js.map +1 -1
- package/lib/typescript/commonjs/live/colors.d.ts +35 -0
- package/lib/typescript/commonjs/live/colors.d.ts.map +1 -0
- package/lib/typescript/commonjs/live/components/LiveRoomSheet.d.ts.map +1 -1
- package/lib/typescript/commonjs/live/components/MiniRoomBar.d.ts.map +1 -1
- package/lib/typescript/commonjs/live/components/PodcastStreamPicker.d.ts +1 -1
- package/lib/typescript/commonjs/live/components/RecordingsPanel.d.ts.map +1 -1
- package/lib/typescript/commonjs/live/components/RoomCard.d.ts.map +1 -1
- package/lib/typescript/commonjs/live/index.d.ts +1 -0
- package/lib/typescript/commonjs/live/index.d.ts.map +1 -1
- package/lib/typescript/module/live/colors.d.ts +35 -0
- package/lib/typescript/module/live/colors.d.ts.map +1 -0
- package/lib/typescript/module/live/components/LiveRoomSheet.d.ts.map +1 -1
- package/lib/typescript/module/live/components/MiniRoomBar.d.ts.map +1 -1
- package/lib/typescript/module/live/components/PodcastStreamPicker.d.ts +1 -1
- package/lib/typescript/module/live/components/RecordingsPanel.d.ts.map +1 -1
- package/lib/typescript/module/live/components/RoomCard.d.ts.map +1 -1
- package/lib/typescript/module/live/index.d.ts +1 -0
- package/lib/typescript/module/live/index.d.ts.map +1 -1
- package/package.json +3 -13
- package/src/live/colors.ts +57 -0
- package/src/live/components/LiveRoomSheet.tsx +9 -8
- package/src/live/components/MiniRoomBar.tsx +3 -2
- package/src/live/components/PodcastStreamPicker.tsx +1 -1
- package/src/live/components/RecordingsPanel.tsx +3 -2
- package/src/live/components/RoomCard.tsx +104 -255
- package/src/live/index.ts +12 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
|
-
import { View, Text,
|
|
2
|
+
import { View, Text, TouchableOpacity, StyleProp, ViewStyle } from 'react-native';
|
|
3
3
|
import MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons';
|
|
4
4
|
import { useAuth } from '@oxyhq/services';
|
|
5
5
|
|
|
6
6
|
import { useLiveConfig } from '../context/LiveConfigContext';
|
|
7
7
|
import { AnimatedPulse } from './AnimatedPulse';
|
|
8
8
|
import { useRoomUsers, getAvatarUrl } from '../hooks/useRoomUsers';
|
|
9
|
+
import { LIVE_COLOR, LIVE_FOREGROUND_COLOR, getRoomTypeMeta, type RoomTypeMeta } from '../colors';
|
|
9
10
|
|
|
10
11
|
// --- Utility helpers ---
|
|
11
12
|
|
|
@@ -49,11 +50,6 @@ function getTimeLabel(room: RoomCardProps['room']): string {
|
|
|
49
50
|
|
|
50
51
|
// --- Constants ---
|
|
51
52
|
|
|
52
|
-
const ROOM_TYPE_META: Record<string, { icon: 'account-voice' | 'broadcast'; label: string; color: string }> = {
|
|
53
|
-
stage: { icon: 'account-voice', label: 'Stage', color: '#3B82F6' },
|
|
54
|
-
broadcast: { icon: 'broadcast', label: 'Broadcast', color: '#FF6B35' },
|
|
55
|
-
};
|
|
56
|
-
|
|
57
53
|
const MAX_SPEAKER_AVATARS = 4;
|
|
58
54
|
const SPEAKER_AVATAR_SIZE = 44;
|
|
59
55
|
|
|
@@ -131,61 +127,52 @@ export const RoomCard: React.FC<RoomCardProps> = ({
|
|
|
131
127
|
|
|
132
128
|
useRoomUsers(speakerIds);
|
|
133
129
|
|
|
134
|
-
const typeMeta = room.type
|
|
130
|
+
const typeMeta = getRoomTypeMeta(room.type);
|
|
135
131
|
const listenerCount = room.participants?.length || room.stats?.totalJoined || 0;
|
|
136
132
|
const timeLabel = getTimeLabel(room);
|
|
137
133
|
|
|
138
|
-
// --- Compact variant (
|
|
134
|
+
// --- Compact variant (post attachments, composer preview) ---
|
|
135
|
+
// It lives inside HORIZONTAL carousels, where a percentage width has no parent
|
|
136
|
+
// to resolve against — hence the intrinsic width, capped at the parent so a
|
|
137
|
+
// constrained host box (the composer preview) can still shrink it. Hosts
|
|
138
|
+
// override any of this through `style`, which wins over the className.
|
|
139
139
|
if (isCompact) {
|
|
140
140
|
return (
|
|
141
141
|
<TouchableOpacity
|
|
142
|
-
|
|
142
|
+
className="w-[200px] max-w-full min-h-[140px] justify-between rounded-2xl border border-border bg-surface p-3"
|
|
143
|
+
style={style}
|
|
143
144
|
onPress={onPress}
|
|
144
145
|
activeOpacity={onPress ? 0.7 : 1}
|
|
145
146
|
disabled={!onPress}
|
|
146
147
|
>
|
|
147
|
-
<View
|
|
148
|
+
<View className="flex-1">
|
|
148
149
|
{house && (
|
|
149
|
-
<Text
|
|
150
|
+
<Text
|
|
151
|
+
className="mb-1 text-[9px] font-bold tracking-[0.5px] text-muted-foreground"
|
|
152
|
+
numberOfLines={1}
|
|
153
|
+
>
|
|
150
154
|
{house.name.toUpperCase()}
|
|
151
155
|
</Text>
|
|
152
156
|
)}
|
|
153
|
-
<Text
|
|
157
|
+
<Text className="text-sm font-semibold leading-[18px] text-foreground" numberOfLines={2}>
|
|
154
158
|
{room.title}
|
|
155
159
|
</Text>
|
|
156
160
|
{(isLive || isScheduled || typeMeta) && (
|
|
157
|
-
<View
|
|
158
|
-
{isLive &&
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
<Text style={styles.liveText}>LIVE</Text>
|
|
162
|
-
</View>
|
|
163
|
-
)}
|
|
164
|
-
{isScheduled && (
|
|
165
|
-
<View style={[styles.scheduledBadge, { backgroundColor: theme.colors.backgroundSecondary }]}>
|
|
166
|
-
<MaterialCommunityIcons name="calendar" size={10} color={theme.colors.textSecondary} />
|
|
167
|
-
<Text style={[styles.scheduledText, { color: theme.colors.textSecondary }]}>SCHEDULED</Text>
|
|
168
|
-
</View>
|
|
169
|
-
)}
|
|
170
|
-
{typeMeta && (
|
|
171
|
-
<View style={[styles.typeBadge, { backgroundColor: typeMeta.color + '20' }]}>
|
|
172
|
-
<MaterialCommunityIcons name={typeMeta.icon} size={10} color={typeMeta.color} />
|
|
173
|
-
<Text style={[styles.typeText, { color: typeMeta.color }]}>{typeMeta.label}</Text>
|
|
174
|
-
</View>
|
|
175
|
-
)}
|
|
161
|
+
<View className="mt-1 flex-row flex-wrap gap-1">
|
|
162
|
+
{isLive && <LiveBadge />}
|
|
163
|
+
{isScheduled && <ScheduledBadge iconSize={10} iconColor={theme.colors.textSecondary} />}
|
|
164
|
+
{typeMeta && <TypeBadge meta={typeMeta} />}
|
|
176
165
|
</View>
|
|
177
166
|
)}
|
|
178
167
|
</View>
|
|
179
|
-
<View
|
|
168
|
+
<View className="mt-2 flex-row items-center gap-1">
|
|
180
169
|
<MaterialCommunityIcons name="account-group" size={14} color={theme.colors.textSecondary} />
|
|
181
|
-
<Text
|
|
182
|
-
|
|
183
|
-
</Text>
|
|
184
|
-
<Text style={{ color: theme.colors.textSecondary, fontSize: 10 }}>•</Text>
|
|
170
|
+
<Text className="text-[11px] text-muted-foreground">{listenerCount} listening</Text>
|
|
171
|
+
<Text className="text-[10px] text-muted-foreground">•</Text>
|
|
185
172
|
{hostAvatarUri && (
|
|
186
173
|
<AvatarComponent size={14} source={hostAvatarUri} shape="squircle" style={{ marginRight: 2 }} />
|
|
187
174
|
)}
|
|
188
|
-
<Text
|
|
175
|
+
<Text className="flex-1 text-[11px] text-muted-foreground" numberOfLines={1}>
|
|
189
176
|
{hostName}
|
|
190
177
|
</Text>
|
|
191
178
|
</View>
|
|
@@ -193,26 +180,30 @@ export const RoomCard: React.FC<RoomCardProps> = ({
|
|
|
193
180
|
);
|
|
194
181
|
}
|
|
195
182
|
|
|
196
|
-
// --- Default variant ---
|
|
183
|
+
// --- Default variant: a full-width, flush feed row (hairline divider, no card chrome) ---
|
|
197
184
|
return (
|
|
198
185
|
<TouchableOpacity
|
|
199
|
-
|
|
186
|
+
className="w-full gap-2 border-b border-border px-3 py-3"
|
|
187
|
+
style={style}
|
|
200
188
|
onPress={onPress}
|
|
201
189
|
activeOpacity={onPress ? 0.7 : 1}
|
|
202
190
|
disabled={!onPress}
|
|
203
191
|
>
|
|
204
192
|
{/* Section 1: House header + menu */}
|
|
205
193
|
{(house || onMenuPress) && (
|
|
206
|
-
<View
|
|
194
|
+
<View className="flex-row items-center gap-1.5">
|
|
207
195
|
{house && (
|
|
208
196
|
<>
|
|
209
|
-
<MaterialCommunityIcons name="home" size={
|
|
210
|
-
<Text
|
|
197
|
+
<MaterialCommunityIcons name="home" size={14} color={theme.colors.primary} />
|
|
198
|
+
<Text
|
|
199
|
+
className="text-[11px] font-bold tracking-[0.5px] text-muted-foreground"
|
|
200
|
+
numberOfLines={1}
|
|
201
|
+
>
|
|
211
202
|
{house.name.toUpperCase()}
|
|
212
203
|
</Text>
|
|
213
204
|
</>
|
|
214
205
|
)}
|
|
215
|
-
<View
|
|
206
|
+
<View className="flex-1" />
|
|
216
207
|
{onMenuPress && (
|
|
217
208
|
<TouchableOpacity onPress={onMenuPress} hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
|
|
218
209
|
<MaterialCommunityIcons name="dots-horizontal" size={20} color={theme.colors.textSecondary} />
|
|
@@ -223,56 +214,47 @@ export const RoomCard: React.FC<RoomCardProps> = ({
|
|
|
223
214
|
|
|
224
215
|
{/* Section 2: Title + status badges */}
|
|
225
216
|
<View>
|
|
226
|
-
<Text
|
|
217
|
+
<Text className="text-[17px] font-bold leading-[22px] text-foreground" numberOfLines={2}>
|
|
227
218
|
{room.title}
|
|
228
219
|
</Text>
|
|
229
220
|
{(isLive || isScheduled || typeMeta) && (
|
|
230
|
-
<View
|
|
231
|
-
{isLive &&
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
<Text style={styles.liveText}>LIVE</Text>
|
|
235
|
-
</View>
|
|
236
|
-
)}
|
|
237
|
-
{isScheduled && (
|
|
238
|
-
<View style={[styles.scheduledBadge, { backgroundColor: theme.colors.backgroundSecondary }]}>
|
|
239
|
-
<MaterialCommunityIcons name="calendar" size={12} color={theme.colors.textSecondary} />
|
|
240
|
-
<Text style={[styles.scheduledText, { color: theme.colors.textSecondary }]}>SCHEDULED</Text>
|
|
241
|
-
</View>
|
|
242
|
-
)}
|
|
243
|
-
{typeMeta && (
|
|
244
|
-
<View style={[styles.typeBadge, { backgroundColor: typeMeta.color + '20' }]}>
|
|
245
|
-
<MaterialCommunityIcons name={typeMeta.icon} size={10} color={typeMeta.color} />
|
|
246
|
-
<Text style={[styles.typeText, { color: typeMeta.color }]}>{typeMeta.label}</Text>
|
|
247
|
-
</View>
|
|
248
|
-
)}
|
|
221
|
+
<View className="mt-1.5 flex-row flex-wrap items-center gap-1.5">
|
|
222
|
+
{isLive && <LiveBadge />}
|
|
223
|
+
{isScheduled && <ScheduledBadge iconColor={theme.colors.textSecondary} />}
|
|
224
|
+
{typeMeta && <TypeBadge meta={typeMeta} />}
|
|
249
225
|
</View>
|
|
250
226
|
)}
|
|
251
227
|
</View>
|
|
252
228
|
|
|
253
229
|
{/* Section 3: Speaker avatars + listener count */}
|
|
254
|
-
<SpeakerRow
|
|
255
|
-
speakerIds={speakerIds}
|
|
256
|
-
listenerCount={listenerCount}
|
|
257
|
-
theme={theme}
|
|
258
|
-
/>
|
|
230
|
+
<SpeakerRow speakerIds={speakerIds} listenerCount={listenerCount} />
|
|
259
231
|
|
|
260
232
|
{/* Section 4: Metadata + save */}
|
|
261
233
|
{(timeLabel || onSave) && (
|
|
262
|
-
<View
|
|
234
|
+
<View className="flex-row items-center justify-between">
|
|
263
235
|
{timeLabel ? (
|
|
264
|
-
<Text
|
|
236
|
+
<Text className="text-[13px] text-muted-foreground">{timeLabel}</Text>
|
|
265
237
|
) : (
|
|
266
238
|
<View />
|
|
267
239
|
)}
|
|
268
240
|
{onSave && (
|
|
269
|
-
<TouchableOpacity
|
|
241
|
+
<TouchableOpacity
|
|
242
|
+
className="flex-row items-center gap-1"
|
|
243
|
+
onPress={onSave}
|
|
244
|
+
hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
|
|
245
|
+
>
|
|
270
246
|
<MaterialCommunityIcons
|
|
271
247
|
name={isSaved ? 'bookmark' : 'bookmark-outline'}
|
|
272
248
|
size={18}
|
|
273
249
|
color={isSaved ? theme.colors.primary : theme.colors.textSecondary}
|
|
274
250
|
/>
|
|
275
|
-
<Text
|
|
251
|
+
<Text
|
|
252
|
+
className={
|
|
253
|
+
isSaved
|
|
254
|
+
? 'text-[13px] font-medium text-primary'
|
|
255
|
+
: 'text-[13px] font-medium text-muted-foreground'
|
|
256
|
+
}
|
|
257
|
+
>
|
|
276
258
|
Save
|
|
277
259
|
</Text>
|
|
278
260
|
</TouchableOpacity>
|
|
@@ -283,25 +265,60 @@ export const RoomCard: React.FC<RoomCardProps> = ({
|
|
|
283
265
|
);
|
|
284
266
|
};
|
|
285
267
|
|
|
268
|
+
// --- Badges ---
|
|
269
|
+
|
|
270
|
+
// The LIVE badge is the one surface that must NOT theme with the host: it is the
|
|
271
|
+
// brand's "on air" signal, so its red comes from the shared live palette and its
|
|
272
|
+
// content sits on white regardless of light/dark mode.
|
|
273
|
+
function LiveBadge() {
|
|
274
|
+
return (
|
|
275
|
+
<View
|
|
276
|
+
className="flex-row items-center gap-1 rounded-[4px] px-2 py-1"
|
|
277
|
+
style={{ backgroundColor: LIVE_COLOR }}
|
|
278
|
+
>
|
|
279
|
+
<AnimatedPulse size={6} color={LIVE_FOREGROUND_COLOR} />
|
|
280
|
+
<Text className="text-[10px] font-bold text-white">LIVE</Text>
|
|
281
|
+
</View>
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function ScheduledBadge({ iconSize = 12, iconColor }: { iconSize?: number; iconColor: string }) {
|
|
286
|
+
return (
|
|
287
|
+
<View className="flex-row items-center gap-1 rounded-[4px] bg-muted px-2 py-1">
|
|
288
|
+
<MaterialCommunityIcons name="calendar" size={iconSize} color={iconColor} />
|
|
289
|
+
<Text className="text-[10px] font-bold text-muted-foreground">SCHEDULED</Text>
|
|
290
|
+
</View>
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function TypeBadge({ meta }: { meta: RoomTypeMeta }) {
|
|
295
|
+
return (
|
|
296
|
+
<View
|
|
297
|
+
className="flex-row items-center gap-0.5 rounded-[4px] px-1.5 py-0.5"
|
|
298
|
+
style={{ backgroundColor: meta.tintColor }}
|
|
299
|
+
>
|
|
300
|
+
<MaterialCommunityIcons name={meta.icon} size={10} color={meta.color} />
|
|
301
|
+
<Text className="text-[9px] font-bold" style={{ color: meta.color }}>
|
|
302
|
+
{meta.label}
|
|
303
|
+
</Text>
|
|
304
|
+
</View>
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
|
|
286
308
|
// --- Speaker row sub-component ---
|
|
287
309
|
|
|
288
|
-
function SpeakerRow({
|
|
289
|
-
speakerIds,
|
|
290
|
-
listenerCount,
|
|
291
|
-
theme,
|
|
292
|
-
}: {
|
|
293
|
-
speakerIds: string[];
|
|
294
|
-
listenerCount: number;
|
|
295
|
-
theme: ReturnType<ReturnType<typeof useLiveConfig>['useTheme']>;
|
|
296
|
-
}) {
|
|
310
|
+
function SpeakerRow({ speakerIds, listenerCount }: { speakerIds: string[]; listenerCount: number }) {
|
|
297
311
|
return (
|
|
298
|
-
<View
|
|
312
|
+
<View className="flex-row items-center gap-2">
|
|
299
313
|
{speakerIds.map((id) => (
|
|
300
314
|
<SpeakerAvatar key={id} userId={id} />
|
|
301
315
|
))}
|
|
302
316
|
{listenerCount > 0 && (
|
|
303
|
-
<View
|
|
304
|
-
|
|
317
|
+
<View
|
|
318
|
+
className="items-center justify-center rounded-[14px] border-2 border-border bg-muted"
|
|
319
|
+
style={{ width: SPEAKER_AVATAR_SIZE + 4, height: SPEAKER_AVATAR_SIZE + 4 }}
|
|
320
|
+
>
|
|
321
|
+
<Text className="text-sm font-bold text-muted-foreground">
|
|
305
322
|
+{formatCompact(listenerCount)}
|
|
306
323
|
</Text>
|
|
307
324
|
</View>
|
|
@@ -311,184 +328,16 @@ function SpeakerRow({
|
|
|
311
328
|
}
|
|
312
329
|
|
|
313
330
|
function SpeakerAvatar({ userId }: { userId: string }) {
|
|
314
|
-
const { useUserById, AvatarComponent, getCachedFileDownloadUrlSync
|
|
315
|
-
const theme = useTheme();
|
|
331
|
+
const { useUserById, AvatarComponent, getCachedFileDownloadUrlSync } = useLiveConfig();
|
|
316
332
|
const { oxyServices } = useAuth();
|
|
317
333
|
const profile = useUserById(userId);
|
|
318
334
|
const avatarUri = getAvatarUrl(profile, oxyServices, getCachedFileDownloadUrlSync);
|
|
319
335
|
|
|
320
336
|
return (
|
|
321
|
-
<View
|
|
322
|
-
<AvatarComponent
|
|
323
|
-
size={SPEAKER_AVATAR_SIZE}
|
|
324
|
-
source={avatarUri}
|
|
325
|
-
shape="squircle"
|
|
326
|
-
/>
|
|
337
|
+
<View className="rounded-[14px] border-2 border-border p-0.5">
|
|
338
|
+
<AvatarComponent size={SPEAKER_AVATAR_SIZE} source={avatarUri} shape="squircle" />
|
|
327
339
|
</View>
|
|
328
340
|
);
|
|
329
341
|
}
|
|
330
342
|
|
|
331
|
-
// --- Styles ---
|
|
332
|
-
|
|
333
|
-
const styles = StyleSheet.create({
|
|
334
|
-
card: {
|
|
335
|
-
borderRadius: 12,
|
|
336
|
-
borderWidth: 1,
|
|
337
|
-
padding: 16,
|
|
338
|
-
marginBottom: 12,
|
|
339
|
-
gap: 12,
|
|
340
|
-
},
|
|
341
|
-
compactCard: {
|
|
342
|
-
width: 200,
|
|
343
|
-
minHeight: 140,
|
|
344
|
-
borderRadius: 14,
|
|
345
|
-
borderWidth: 1,
|
|
346
|
-
padding: 12,
|
|
347
|
-
justifyContent: 'space-between',
|
|
348
|
-
},
|
|
349
|
-
|
|
350
|
-
// House header
|
|
351
|
-
houseRow: {
|
|
352
|
-
flexDirection: 'row',
|
|
353
|
-
alignItems: 'center',
|
|
354
|
-
gap: 6,
|
|
355
|
-
},
|
|
356
|
-
houseName: {
|
|
357
|
-
fontSize: 11,
|
|
358
|
-
fontWeight: '700',
|
|
359
|
-
letterSpacing: 0.5,
|
|
360
|
-
},
|
|
361
|
-
|
|
362
|
-
// Title
|
|
363
|
-
title: {
|
|
364
|
-
fontSize: 32,
|
|
365
|
-
fontWeight: '700',
|
|
366
|
-
lineHeight: 38,
|
|
367
|
-
},
|
|
368
|
-
|
|
369
|
-
// Badges
|
|
370
|
-
badgeRow: {
|
|
371
|
-
flexDirection: 'row',
|
|
372
|
-
alignItems: 'center',
|
|
373
|
-
gap: 6,
|
|
374
|
-
marginTop: 6,
|
|
375
|
-
},
|
|
376
|
-
liveBadge: {
|
|
377
|
-
flexDirection: 'row',
|
|
378
|
-
alignItems: 'center',
|
|
379
|
-
paddingHorizontal: 8,
|
|
380
|
-
paddingVertical: 4,
|
|
381
|
-
borderRadius: 4,
|
|
382
|
-
gap: 4,
|
|
383
|
-
},
|
|
384
|
-
liveText: {
|
|
385
|
-
fontSize: 10,
|
|
386
|
-
fontWeight: '700',
|
|
387
|
-
color: '#FFFFFF',
|
|
388
|
-
},
|
|
389
|
-
scheduledBadge: {
|
|
390
|
-
flexDirection: 'row',
|
|
391
|
-
alignItems: 'center',
|
|
392
|
-
paddingHorizontal: 8,
|
|
393
|
-
paddingVertical: 4,
|
|
394
|
-
borderRadius: 4,
|
|
395
|
-
gap: 4,
|
|
396
|
-
},
|
|
397
|
-
scheduledText: {
|
|
398
|
-
fontSize: 10,
|
|
399
|
-
fontWeight: '700',
|
|
400
|
-
},
|
|
401
|
-
typeBadge: {
|
|
402
|
-
flexDirection: 'row',
|
|
403
|
-
alignItems: 'center',
|
|
404
|
-
paddingHorizontal: 6,
|
|
405
|
-
paddingVertical: 3,
|
|
406
|
-
borderRadius: 4,
|
|
407
|
-
gap: 3,
|
|
408
|
-
},
|
|
409
|
-
typeText: {
|
|
410
|
-
fontSize: 9,
|
|
411
|
-
fontWeight: '700',
|
|
412
|
-
},
|
|
413
|
-
|
|
414
|
-
// Speaker avatars
|
|
415
|
-
avatarRow: {
|
|
416
|
-
flexDirection: 'row',
|
|
417
|
-
alignItems: 'center',
|
|
418
|
-
gap: 8,
|
|
419
|
-
},
|
|
420
|
-
avatarRing: {
|
|
421
|
-
borderRadius: 14,
|
|
422
|
-
padding: 2,
|
|
423
|
-
borderWidth: 2,
|
|
424
|
-
},
|
|
425
|
-
countTile: {
|
|
426
|
-
width: SPEAKER_AVATAR_SIZE + 4,
|
|
427
|
-
height: SPEAKER_AVATAR_SIZE + 4,
|
|
428
|
-
borderRadius: 14,
|
|
429
|
-
borderWidth: 2,
|
|
430
|
-
alignItems: 'center',
|
|
431
|
-
justifyContent: 'center',
|
|
432
|
-
gap: 2,
|
|
433
|
-
},
|
|
434
|
-
countTileText: {
|
|
435
|
-
fontSize: 14,
|
|
436
|
-
fontWeight: '700',
|
|
437
|
-
},
|
|
438
|
-
|
|
439
|
-
// Metadata
|
|
440
|
-
metaRow: {
|
|
441
|
-
flexDirection: 'row',
|
|
442
|
-
alignItems: 'center',
|
|
443
|
-
justifyContent: 'space-between',
|
|
444
|
-
},
|
|
445
|
-
metaText: {
|
|
446
|
-
fontSize: 13,
|
|
447
|
-
},
|
|
448
|
-
saveButton: {
|
|
449
|
-
flexDirection: 'row',
|
|
450
|
-
alignItems: 'center',
|
|
451
|
-
gap: 4,
|
|
452
|
-
},
|
|
453
|
-
saveText: {
|
|
454
|
-
fontSize: 13,
|
|
455
|
-
fontWeight: '500',
|
|
456
|
-
},
|
|
457
|
-
|
|
458
|
-
// Compact variant
|
|
459
|
-
compactHeader: {
|
|
460
|
-
flex: 1,
|
|
461
|
-
},
|
|
462
|
-
compactHouseName: {
|
|
463
|
-
fontSize: 9,
|
|
464
|
-
fontWeight: '700',
|
|
465
|
-
letterSpacing: 0.5,
|
|
466
|
-
marginBottom: 4,
|
|
467
|
-
},
|
|
468
|
-
compactTitle: {
|
|
469
|
-
fontSize: 14,
|
|
470
|
-
fontWeight: '600',
|
|
471
|
-
lineHeight: 18,
|
|
472
|
-
},
|
|
473
|
-
compactBadgeRow: {
|
|
474
|
-
flexDirection: 'row',
|
|
475
|
-
marginTop: 4,
|
|
476
|
-
gap: 4,
|
|
477
|
-
flexWrap: 'wrap',
|
|
478
|
-
},
|
|
479
|
-
compactFooter: {
|
|
480
|
-
flexDirection: 'row',
|
|
481
|
-
alignItems: 'center',
|
|
482
|
-
gap: 4,
|
|
483
|
-
marginTop: 8,
|
|
484
|
-
},
|
|
485
|
-
compactCount: {
|
|
486
|
-
fontSize: 11,
|
|
487
|
-
},
|
|
488
|
-
compactHost: {
|
|
489
|
-
fontSize: 11,
|
|
490
|
-
flex: 1,
|
|
491
|
-
},
|
|
492
|
-
});
|
|
493
|
-
|
|
494
343
|
export default RoomCard;
|
package/src/live/index.ts
CHANGED
|
@@ -23,6 +23,18 @@ export type {
|
|
|
23
23
|
FileDownloadService,
|
|
24
24
|
} from './types';
|
|
25
25
|
|
|
26
|
+
// Colors — the live-rooms brand palette (live-indicator red, room-type accents).
|
|
27
|
+
// Everything else themes with the host app; import these instead of re-hardcoding.
|
|
28
|
+
export {
|
|
29
|
+
LIVE_COLOR,
|
|
30
|
+
LIVE_TINT_COLOR,
|
|
31
|
+
LIVE_FOREGROUND_COLOR,
|
|
32
|
+
ROOM_TYPE_META,
|
|
33
|
+
getRoomTypeMeta,
|
|
34
|
+
type BadgedRoomType,
|
|
35
|
+
type RoomTypeMeta,
|
|
36
|
+
} from './colors';
|
|
37
|
+
|
|
26
38
|
// Validation
|
|
27
39
|
export {
|
|
28
40
|
ZRoom,
|