@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.
Files changed (53) hide show
  1. package/README.md +33 -4
  2. package/lib/commonjs/live/colors.js +54 -0
  3. package/lib/commonjs/live/colors.js.map +1 -0
  4. package/lib/commonjs/live/components/LiveRoomSheet.js +9 -8
  5. package/lib/commonjs/live/components/LiveRoomSheet.js.map +1 -1
  6. package/lib/commonjs/live/components/MiniRoomBar.js +3 -2
  7. package/lib/commonjs/live/components/MiniRoomBar.js.map +1 -1
  8. package/lib/commonjs/live/components/PodcastStreamPicker.js +1 -1
  9. package/lib/commonjs/live/components/RecordingsPanel.js +3 -2
  10. package/lib/commonjs/live/components/RecordingsPanel.js.map +1 -1
  11. package/lib/commonjs/live/components/RoomCard.js +110 -314
  12. package/lib/commonjs/live/components/RoomCard.js.map +1 -1
  13. package/lib/commonjs/live/index.js +31 -0
  14. package/lib/commonjs/live/index.js.map +1 -1
  15. package/lib/module/live/colors.js +49 -0
  16. package/lib/module/live/colors.js.map +1 -0
  17. package/lib/module/live/components/LiveRoomSheet.js +9 -8
  18. package/lib/module/live/components/LiveRoomSheet.js.map +1 -1
  19. package/lib/module/live/components/MiniRoomBar.js +3 -2
  20. package/lib/module/live/components/MiniRoomBar.js.map +1 -1
  21. package/lib/module/live/components/PodcastStreamPicker.js +1 -1
  22. package/lib/module/live/components/RecordingsPanel.js +3 -2
  23. package/lib/module/live/components/RecordingsPanel.js.map +1 -1
  24. package/lib/module/live/components/RoomCard.js +109 -314
  25. package/lib/module/live/components/RoomCard.js.map +1 -1
  26. package/lib/module/live/index.js +4 -0
  27. package/lib/module/live/index.js.map +1 -1
  28. package/lib/typescript/commonjs/live/colors.d.ts +35 -0
  29. package/lib/typescript/commonjs/live/colors.d.ts.map +1 -0
  30. package/lib/typescript/commonjs/live/components/LiveRoomSheet.d.ts.map +1 -1
  31. package/lib/typescript/commonjs/live/components/MiniRoomBar.d.ts.map +1 -1
  32. package/lib/typescript/commonjs/live/components/PodcastStreamPicker.d.ts +1 -1
  33. package/lib/typescript/commonjs/live/components/RecordingsPanel.d.ts.map +1 -1
  34. package/lib/typescript/commonjs/live/components/RoomCard.d.ts.map +1 -1
  35. package/lib/typescript/commonjs/live/index.d.ts +1 -0
  36. package/lib/typescript/commonjs/live/index.d.ts.map +1 -1
  37. package/lib/typescript/module/live/colors.d.ts +35 -0
  38. package/lib/typescript/module/live/colors.d.ts.map +1 -0
  39. package/lib/typescript/module/live/components/LiveRoomSheet.d.ts.map +1 -1
  40. package/lib/typescript/module/live/components/MiniRoomBar.d.ts.map +1 -1
  41. package/lib/typescript/module/live/components/PodcastStreamPicker.d.ts +1 -1
  42. package/lib/typescript/module/live/components/RecordingsPanel.d.ts.map +1 -1
  43. package/lib/typescript/module/live/components/RoomCard.d.ts.map +1 -1
  44. package/lib/typescript/module/live/index.d.ts +1 -0
  45. package/lib/typescript/module/live/index.d.ts.map +1 -1
  46. package/package.json +3 -13
  47. package/src/live/colors.ts +57 -0
  48. package/src/live/components/LiveRoomSheet.tsx +9 -8
  49. package/src/live/components/MiniRoomBar.tsx +3 -2
  50. package/src/live/components/PodcastStreamPicker.tsx +1 -1
  51. package/src/live/components/RecordingsPanel.tsx +3 -2
  52. package/src/live/components/RoomCard.tsx +104 -255
  53. package/src/live/index.ts +12 -0
@@ -1,11 +1,12 @@
1
1
  import React, { useMemo } from 'react';
2
- import { View, Text, StyleSheet, TouchableOpacity, StyleProp, ViewStyle } from 'react-native';
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 && room.type !== 'talk' ? ROOM_TYPE_META[room.type] : null;
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 (kept simple) ---
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
- style={[styles.compactCard, { backgroundColor: theme.colors.card, borderColor: theme.colors.border }, style]}
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 style={styles.compactHeader}>
148
+ <View className="flex-1">
148
149
  {house && (
149
- <Text style={[styles.compactHouseName, { color: theme.colors.textSecondary }]} numberOfLines={1}>
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 style={[styles.compactTitle, { color: theme.colors.text }]} numberOfLines={2}>
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 style={styles.compactBadgeRow}>
158
- {isLive && (
159
- <View style={[styles.liveBadge, { backgroundColor: '#FF4458' }]}>
160
- <AnimatedPulse size={6} />
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 style={styles.compactFooter}>
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 style={[styles.compactCount, { color: theme.colors.textSecondary }]}>
182
- {listenerCount} listening
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 style={[styles.compactHost, { color: theme.colors.textSecondary }]} numberOfLines={1}>
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
- style={[styles.card, { backgroundColor: theme.colors.card, borderColor: theme.colors.border }, style]}
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 style={styles.houseRow}>
194
+ <View className="flex-row items-center gap-1.5">
207
195
  {house && (
208
196
  <>
209
- <MaterialCommunityIcons name="home" size={16} color={theme.colors.primary} />
210
- <Text style={[styles.houseName, { color: theme.colors.textSecondary }]} numberOfLines={1}>
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 style={{ flex: 1 }} />
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 style={[styles.title, { color: theme.colors.text }]} numberOfLines={2}>
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 style={styles.badgeRow}>
231
- {isLive && (
232
- <View style={[styles.liveBadge, { backgroundColor: '#FF4458' }]}>
233
- <AnimatedPulse size={6} />
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 style={styles.metaRow}>
234
+ <View className="flex-row items-center justify-between">
263
235
  {timeLabel ? (
264
- <Text style={[styles.metaText, { color: theme.colors.textSecondary }]}>{timeLabel}</Text>
236
+ <Text className="text-[13px] text-muted-foreground">{timeLabel}</Text>
265
237
  ) : (
266
238
  <View />
267
239
  )}
268
240
  {onSave && (
269
- <TouchableOpacity onPress={onSave} style={styles.saveButton} hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
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 style={[styles.saveText, { color: isSaved ? theme.colors.primary : theme.colors.textSecondary }]}>
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 style={styles.avatarRow}>
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 style={[styles.countTile, { backgroundColor: theme.colors.backgroundSecondary, borderColor: theme.colors.border }]}>
304
- <Text style={[styles.countTileText, { color: theme.colors.textSecondary }]}>
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, useTheme } = useLiveConfig();
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 style={[styles.avatarRing, { borderColor: theme.colors.border }]}>
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,