@streamplace/components 0.8.6 → 0.8.8

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.
@@ -5,85 +5,54 @@ const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const lucide_react_native_1 = require("lucide-react-native");
6
6
  const react_1 = require("react");
7
7
  const react_native_1 = require("react-native");
8
+ const __1 = require("../..");
8
9
  const theme_1 = require("../../lib/theme/theme");
10
+ const ui_1 = require("../../ui");
11
+ const dropdown_1 = require("./dropdown");
9
12
  const text_1 = require("./text");
13
+ const { layout, px, py, borders, r, gap } = __1.zero;
10
14
  exports.Select = (0, react_1.forwardRef)(({ value, onValueChange, placeholder = "Select...", items, disabled = false, style, }, ref) => {
11
15
  const { theme } = (0, theme_1.useTheme)();
12
- const [isOpen, setIsOpen] = (0, react_1.useState)(false);
13
16
  const selectedItem = items.find((item) => item.value === value);
14
- const handleSelect = (itemValue) => {
15
- onValueChange(itemValue);
16
- setIsOpen(false);
17
- };
18
- const styles = createStyles(theme, disabled);
19
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { ref: ref, style: [styles.container, style], onPress: () => !disabled && setIsOpen(true), disabled: disabled, children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: styles.value, children: selectedItem?.label || placeholder }), (0, jsx_runtime_1.jsx)(lucide_react_native_1.ChevronDown, { size: 16, color: theme.colors.textMuted })] }), (0, jsx_runtime_1.jsx)(react_native_1.Modal, { visible: isOpen, transparent: true, animationType: "fade", onRequestClose: () => setIsOpen(false), children: (0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: styles.overlay, activeOpacity: 1, onPress: () => setIsOpen(false), children: (0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.dropdown, children: (0, jsx_runtime_1.jsx)(react_native_1.FlatList, { data: items, keyExtractor: (item) => item.value, renderItem: ({ item }) => ((0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { style: [
20
- styles.item,
21
- item.value === value && styles.selectedItem,
22
- ], onPress: () => handleSelect(item.value), children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
23
- styles.itemText,
24
- item.value === value ? styles.selectedItemText : {},
25
- ], children: item.label }), item.description && ((0, jsx_runtime_1.jsx)(text_1.Text, { style: styles.itemDescription, children: item.description }))] })), style: styles.list }) }) }) })] }));
17
+ return ((0, jsx_runtime_1.jsxs)(dropdown_1.DropdownMenu, { children: [(0, jsx_runtime_1.jsx)(dropdown_1.DropdownMenuTrigger, { disabled: disabled, children: (0, jsx_runtime_1.jsx)(react_native_1.View, { ref: ref, style: [
18
+ {
19
+ width: "100%",
20
+ paddingHorizontal: theme.spacing[3],
21
+ paddingVertical: theme.spacing[3],
22
+ borderWidth: 1,
23
+ borderColor: theme.colors.border,
24
+ borderRadius: theme.borderRadius.md,
25
+ backgroundColor: disabled
26
+ ? theme.colors.muted
27
+ : theme.colors.card,
28
+ minHeight: theme.touchTargets.minimum,
29
+ opacity: disabled ? 0.5 : 1,
30
+ },
31
+ style,
32
+ ], children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: {
33
+ flexDirection: "row",
34
+ alignItems: "center",
35
+ justifyContent: "space-between",
36
+ width: "100%",
37
+ gap: 8,
38
+ }, children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: {
39
+ fontSize: 16,
40
+ color: disabled
41
+ ? theme.colors.textDisabled
42
+ : theme.colors.text,
43
+ flex: 1,
44
+ }, children: selectedItem?.label || placeholder }), (0, jsx_runtime_1.jsx)(lucide_react_native_1.ChevronDown, { size: 16, color: theme.colors.textMuted })] }) }) }), (0, jsx_runtime_1.jsx)(dropdown_1.ResponsiveDropdownMenuContent, { align: "start", style: [
45
+ {
46
+ maxHeight: 400,
47
+ },
48
+ ], children: items.map((item, index) => ((0, jsx_runtime_1.jsxs)(react_native_1.View, { children: [(0, jsx_runtime_1.jsx)(dropdown_1.DropdownMenuItem, { onPress: () => onValueChange(item.value), children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: {
49
+ flexDirection: "row",
50
+ alignItems: "center",
51
+ justifyContent: "space-between",
52
+ width: "100%",
53
+ gap: 8,
54
+ }, children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [gap.all[1], py[1], ui_1.flex.values[1]], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: {
55
+ fontWeight: item.value === value ? "500" : "400",
56
+ }, color: item.value === value ? "primary" : "default", children: item.label }), item.description && ((0, jsx_runtime_1.jsx)(text_1.Text, { size: "sm", color: "muted", children: item.description }))] }), item.value === value ? ((0, jsx_runtime_1.jsx)(lucide_react_native_1.Check, { size: 16, color: theme.colors.primary })) : ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: { width: 16 } }))] }) }), index < items.length - 1 && (0, jsx_runtime_1.jsx)(dropdown_1.DropdownMenuSeparator, {})] }, item.value))) })] }));
26
57
  });
27
58
  exports.Select.displayName = "Select";
28
- function createStyles(theme, disabled) {
29
- return react_native_1.StyleSheet.create({
30
- container: {
31
- flexDirection: "row",
32
- alignItems: "center",
33
- justifyContent: "space-between",
34
- paddingHorizontal: theme.spacing[3],
35
- paddingVertical: theme.spacing[3],
36
- borderWidth: 1,
37
- borderColor: theme.colors.border,
38
- borderRadius: theme.borderRadius.md,
39
- backgroundColor: disabled ? theme.colors.muted : theme.colors.card,
40
- minHeight: theme.touchTargets.minimum,
41
- },
42
- value: {
43
- fontSize: 16,
44
- color: disabled ? theme.colors.textDisabled : theme.colors.text,
45
- flex: 1,
46
- },
47
- overlay: {
48
- flex: 1,
49
- backgroundColor: "rgba(0, 0, 0, 0.5)",
50
- justifyContent: "center",
51
- alignItems: "center",
52
- },
53
- dropdown: {
54
- backgroundColor: theme.colors.background,
55
- borderRadius: theme.borderRadius.md,
56
- borderWidth: 1,
57
- borderColor: theme.colors.border,
58
- maxHeight: 300,
59
- width: "90%",
60
- maxWidth: 400,
61
- ...theme.shadows.lg,
62
- },
63
- list: {
64
- maxHeight: 300,
65
- },
66
- item: {
67
- paddingHorizontal: theme.spacing[4],
68
- paddingVertical: theme.spacing[3],
69
- borderBottomWidth: 1,
70
- borderBottomColor: theme.colors.border,
71
- },
72
- selectedItem: {
73
- backgroundColor: theme.colors.primary,
74
- },
75
- itemText: {
76
- fontSize: 16,
77
- color: theme.colors.text,
78
- },
79
- selectedItemText: {
80
- color: theme.colors.primaryForeground,
81
- fontWeight: "500",
82
- },
83
- itemDescription: {
84
- fontSize: 14,
85
- color: theme.colors.textMuted,
86
- marginTop: theme.spacing[1],
87
- },
88
- });
89
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamplace/components",
3
- "version": "0.8.6",
3
+ "version": "0.8.8",
4
4
  "description": "Streamplace React (Native) Components",
5
5
  "main": "dist/index.js",
6
6
  "types": "src/index.tsx",
@@ -56,5 +56,5 @@
56
56
  "start": "tsc --watch --preserveWatchOutput",
57
57
  "prepare": "tsc"
58
58
  },
59
- "gitHead": "a40860f005ba4da989cfe1a5c39d29fa3564fea6"
59
+ "gitHead": "87db57ebb4908da9997777417493d55e64d08c6d"
60
60
  }
@@ -376,26 +376,11 @@ export const ContentMetadataForm = forwardRef<any, ContentMetadataFormProps>(
376
376
  layout.flex.row,
377
377
  layout.flex.alignCenter,
378
378
  w.percent[100],
379
+ gap.all[2],
379
380
  ]}
380
381
  >
381
- <Text
382
- style={[
383
- text.neutral[300],
384
- {
385
- minWidth: 100,
386
- textAlign: "left",
387
- paddingBottom: 8,
388
- fontSize: 14,
389
- },
390
- ]}
391
- >
392
- Content Warnings
393
- </Text>
394
- <Text
395
- style={[text.gray[500], { fontSize: 12, paddingBottom: 8 }]}
396
- >
397
- optional
398
- </Text>
382
+ <Text>Content Warnings</Text>
383
+ <Text muted>(optional)</Text>
399
384
  </View>
400
385
  <View style={[gap.all[2], w.percent[100]]}>
401
386
  {CONTENT_WARNINGS.map((warning) => (
@@ -424,26 +409,11 @@ export const ContentMetadataForm = forwardRef<any, ContentMetadataFormProps>(
424
409
  layout.flex.row,
425
410
  layout.flex.alignCenter,
426
411
  w.percent[100],
412
+ gap.all[2],
427
413
  ]}
428
414
  >
429
- <Text
430
- style={[
431
- text.neutral[300],
432
- {
433
- minWidth: 100,
434
- textAlign: "left",
435
- paddingBottom: 8,
436
- fontSize: 14,
437
- },
438
- ]}
439
- >
440
- Content Rights
441
- </Text>
442
- <Text
443
- style={[text.gray[500], { fontSize: 12, paddingBottom: 8 }]}
444
- >
445
- optional
446
- </Text>
415
+ <Text>Content Rights</Text>
416
+ <Text muted>(optional)</Text>
447
417
  </View>
448
418
 
449
419
  <View style={[gap.all[3], w.percent[100]]}>
@@ -674,21 +644,11 @@ export const ContentMetadataForm = forwardRef<any, ContentMetadataFormProps>(
674
644
  layout.flex.row,
675
645
  layout.flex.alignCenter,
676
646
  w.percent[100],
647
+ gap.all[2],
677
648
  ]}
678
649
  >
679
- <Text
680
- style={[
681
- text.neutral[300],
682
- { minWidth: 100, textAlign: "left", paddingBottom: 8 },
683
- ]}
684
- >
685
- Distribution
686
- </Text>
687
- <Text
688
- style={[text.gray[500], { fontSize: 12, paddingBottom: 8 }]}
689
- >
690
- optional
691
- </Text>
650
+ <Text>Distribution</Text>
651
+ <Text muted>(optional)</Text>
692
652
  </View>
693
653
 
694
654
  {/* allow everyone to distribute your content */}
@@ -1,10 +1,12 @@
1
- import { forwardRef } from "react";
2
- import { StyleSheet, View } from "react-native";
1
+ import { forwardRef, type ComponentProps } from "react";
2
+ import { StyleSheet } from "react-native";
3
+ import { useTheme, zero } from "../..";
3
4
  import { LICENSE_URL_LABELS } from "../../lib/metadata-constants";
4
- import { useTheme } from "../../lib/theme/theme";
5
5
  import { Text } from "../ui/text";
6
6
 
7
- export interface ContentRightsProps {
7
+ const { layout, gap, mt, text: textStyles } = zero;
8
+
9
+ export interface ContentRightsProps extends ComponentProps<typeof Text> {
8
10
  contentRights: {
9
11
  creator?: string;
10
12
  copyrightNotice?: string;
@@ -15,16 +17,13 @@ export interface ContentRightsProps {
15
17
  compact?: boolean;
16
18
  }
17
19
 
18
- export const ContentRights = forwardRef<any, ContentRightsProps>(
19
- ({ contentRights }, ref) => {
20
- const { theme } = useTheme();
21
-
20
+ export const ContentRights = forwardRef<Text, ContentRightsProps>(
21
+ ({ contentRights, compact, ...rest }, ref) => {
22
+ const { zero } = useTheme();
22
23
  if (!contentRights || Object.keys(contentRights).length === 0) {
23
24
  return null;
24
25
  }
25
26
 
26
- const styles = createStyles(theme);
27
-
28
27
  const formatLicense = (license: string) => {
29
28
  return LICENSE_URL_LABELS[license] || license;
30
29
  };
@@ -38,7 +37,11 @@ export const ContentRights = forwardRef<any, ContentRightsProps>(
38
37
  // }
39
38
 
40
39
  if (contentRights.copyrightYear) {
41
- elements.push(`© ${contentRights.copyrightYear.toString()}`);
40
+ elements.push(
41
+ `© ${contentRights.copyrightYear.toString()}${contentRights.creditLine ? " " + contentRights.creditLine : ""}`,
42
+ );
43
+ } else if (contentRights.creditLine) {
44
+ elements.push(contentRights.creditLine);
42
45
  }
43
46
 
44
47
  if (contentRights.license) {
@@ -49,56 +52,28 @@ export const ContentRights = forwardRef<any, ContentRightsProps>(
49
52
  elements.push(contentRights.copyrightNotice);
50
53
  }
51
54
 
52
- if (contentRights.creditLine) {
53
- elements.push(contentRights.creditLine);
55
+ if (elements.length > 0) {
56
+ elements[0] = "Stream content is " + elements[0];
57
+ }
58
+
59
+ if (elements.length == 0) {
60
+ return null;
54
61
  }
55
62
 
56
63
  return (
57
- <View ref={ref} style={styles.compactContainer}>
58
- <Text style={styles.compactText}>{elements.join(" • ")}</Text>
59
- </View>
64
+ <Text
65
+ ref={ref}
66
+ style={[
67
+ zero.text.mutedForeground,
68
+ mt[1],
69
+ StyleSheet.flatten(rest.style),
70
+ ]}
71
+ {...rest}
72
+ >
73
+ {elements.join(" • ")}
74
+ </Text>
60
75
  );
61
76
  },
62
77
  );
63
78
 
64
79
  ContentRights.displayName = "ContentRights";
65
-
66
- function createStyles(theme: any) {
67
- return StyleSheet.create({
68
- container: {
69
- paddingVertical: theme.spacing[3],
70
- },
71
- title: {
72
- fontSize: 14,
73
- fontWeight: "600",
74
- color: theme.colors.text,
75
- marginBottom: theme.spacing[2],
76
- },
77
- content: {
78
- gap: theme.spacing[2],
79
- },
80
- row: {
81
- flexDirection: "row",
82
- gap: theme.spacing[2],
83
- },
84
- label: {
85
- fontSize: 13,
86
- color: theme.colors.textMuted,
87
- },
88
- value: {
89
- fontSize: 13,
90
- color: theme.colors.text,
91
- },
92
- compactContainer: {
93
- flexDirection: "row",
94
- gap: theme.spacing[2],
95
- flexWrap: "wrap",
96
- marginTop: theme.spacing[1],
97
- },
98
- compactText: {
99
- fontSize: 14,
100
- fontWeight: "500",
101
- color: theme.colors.text,
102
- },
103
- });
104
- }
@@ -0,0 +1,94 @@
1
+ import { AlertTriangle, ChevronDown } from "lucide-react-native";
2
+ import { View } from "react-native";
3
+ import { zero } from "../..";
4
+ import { C2PA_WARNING_LABELS } from "../../lib/metadata-constants";
5
+ import { useTheme } from "../../lib/theme/theme";
6
+ import { pt, r } from "../../ui";
7
+ import {
8
+ DropdownMenu,
9
+ DropdownMenuTrigger,
10
+ ResponsiveDropdownMenuContent,
11
+ } from "../ui/dropdown";
12
+ import { Text } from "../ui/text";
13
+
14
+ const { px, py, gap, layout } = zero;
15
+
16
+ export interface ContentWarningBadgeProps {
17
+ warnings: string[];
18
+ }
19
+
20
+ export function ContentWarningBadge({ warnings }: ContentWarningBadgeProps) {
21
+ const { theme } = useTheme();
22
+
23
+ const getWarningLabel = (warning: string): string => {
24
+ return C2PA_WARNING_LABELS[warning] || warning;
25
+ };
26
+
27
+ if (!warnings || warnings.length === 0) {
28
+ return null;
29
+ }
30
+
31
+ return (
32
+ <DropdownMenu>
33
+ <DropdownMenuTrigger>
34
+ <View
35
+ style={[
36
+ layout.flex.row,
37
+ layout.flex.align.center,
38
+ gap.all[2],
39
+ px[3],
40
+ py[2],
41
+ r.md,
42
+ { backgroundColor: theme.colors.warning + "20" },
43
+ ]}
44
+ >
45
+ <AlertTriangle size={14} color={theme.colors.warningForeground} />
46
+ <Text
47
+ size="sm"
48
+ weight="semibold"
49
+ style={{ color: theme.colors.warningForeground }}
50
+ >
51
+ Intended for certain audiences
52
+ </Text>
53
+ <ChevronDown size={14} color={theme.colors.warningForeground} />
54
+ </View>
55
+ </DropdownMenuTrigger>
56
+
57
+ <ResponsiveDropdownMenuContent>
58
+ <View style={[layout.flex.column, px[2], pt[2]]}>
59
+ <Text>Heads up!</Text>
60
+ <Text>This stream may contain:</Text>
61
+ </View>
62
+ <View
63
+ style={[
64
+ layout.flex.row,
65
+ { flexWrap: "wrap" },
66
+ gap.all[2],
67
+ px[2],
68
+ py[2],
69
+ ]}
70
+ >
71
+ {warnings.map((warning, index) => (
72
+ <View
73
+ key={index}
74
+ style={[
75
+ { backgroundColor: theme.colors.warning },
76
+ px[3],
77
+ py[1],
78
+ r.full,
79
+ ]}
80
+ >
81
+ <Text
82
+ size="sm"
83
+ weight="semibold"
84
+ style={{ color: theme.colors.warningForeground }}
85
+ >
86
+ {getWarningLabel(warning)}
87
+ </Text>
88
+ </View>
89
+ ))}
90
+ </View>
91
+ </ResponsiveDropdownMenuContent>
92
+ </DropdownMenu>
93
+ );
94
+ }
@@ -1,34 +1,50 @@
1
1
  import { forwardRef } from "react";
2
- import { StyleSheet, View } from "react-native";
2
+ import { View } from "react-native";
3
+ import { zero } from "../..";
3
4
  import { C2PA_WARNING_LABELS } from "../../lib/metadata-constants";
4
5
  import { useTheme } from "../../lib/theme/theme";
5
6
  import { Text } from "../ui/text";
6
7
 
8
+ const { layout, gap, bg, r, p, px, py, text: textStyles, borders } = zero;
9
+
7
10
  export interface ContentWarningsProps {
8
11
  warnings: string[];
9
12
  compact?: boolean;
10
13
  }
11
14
 
12
- export const ContentWarnings = forwardRef<any, ContentWarningsProps>(
13
- ({ warnings, compact = false }, ref) => {
15
+ export const ContentWarnings = forwardRef<View, ContentWarningsProps>(
16
+ ({ warnings, compact = false, ...rest }, ref) => {
14
17
  const { theme } = useTheme();
15
18
 
16
19
  if (!warnings || warnings.length === 0) {
17
20
  return null;
18
21
  }
19
22
 
20
- const styles = createStyles(theme, compact);
21
-
22
23
  const getWarningLabel = (warning: string): string => {
23
24
  return C2PA_WARNING_LABELS[warning] || warning;
24
25
  };
25
26
 
26
27
  if (compact) {
27
28
  return (
28
- <View ref={ref} style={styles.compactContainer}>
29
+ <View
30
+ ref={ref}
31
+ style={[layout.flex.row, layout.flex.wrap.wrap, gap.all[1]]}
32
+ {...rest}
33
+ >
29
34
  {warnings.map((warning, index) => (
30
- <View key={index} style={styles.compactWarning}>
31
- <Text style={styles.compactWarningText}>
35
+ <View
36
+ key={index}
37
+ style={[
38
+ { backgroundColor: theme.colors.warning },
39
+ r.full,
40
+ px[2],
41
+ { paddingVertical: 2 },
42
+ ]}
43
+ >
44
+ <Text
45
+ size="sm"
46
+ style={[{ color: theme.colors.warningForeground }]}
47
+ >
32
48
  {getWarningLabel(warning)}
33
49
  </Text>
34
50
  </View>
@@ -38,12 +54,29 @@ export const ContentWarnings = forwardRef<any, ContentWarningsProps>(
38
54
  }
39
55
 
40
56
  return (
41
- <View ref={ref} style={styles.container}>
42
- <Text style={styles.title}>Content Warnings</Text>
43
- <View style={styles.warningsContainer}>
57
+ <View ref={ref} style={[layout.flex.column, gap.all[2]]} {...rest}>
58
+ <Text
59
+ style={[{ fontSize: 14, fontWeight: "600" }, textStyles.gray[900]]}
60
+ >
61
+ Content Warnings
62
+ </Text>
63
+ <View style={[layout.flex.row, layout.flex.wrap.wrap, gap.all[2]]}>
44
64
  {warnings.map((warning, index) => (
45
- <View key={index} style={styles.warning}>
46
- <Text style={styles.warningText}>{getWarningLabel(warning)}</Text>
65
+ <View
66
+ key={index}
67
+ style={[
68
+ { backgroundColor: theme.colors.warning },
69
+ r.full,
70
+ px[3],
71
+ py[1],
72
+ ]}
73
+ >
74
+ <Text
75
+ size="sm"
76
+ style={[{ color: theme.colors.warningForeground }]}
77
+ >
78
+ {getWarningLabel(warning)}
79
+ </Text>
47
80
  </View>
48
81
  ))}
49
82
  </View>
@@ -53,48 +86,3 @@ export const ContentWarnings = forwardRef<any, ContentWarningsProps>(
53
86
  );
54
87
 
55
88
  ContentWarnings.displayName = "ContentWarnings";
56
-
57
- function createStyles(theme: any, compact: boolean) {
58
- return StyleSheet.create({
59
- container: {
60
- flexDirection: "column",
61
- gap: theme.spacing[2],
62
- },
63
- title: {
64
- fontSize: 14,
65
- fontWeight: "600",
66
- color: theme.colors.text,
67
- },
68
- warningsContainer: {
69
- flexDirection: "row",
70
- flexWrap: "wrap",
71
- gap: theme.spacing[2],
72
- },
73
- warning: {
74
- backgroundColor: theme.colors.warning,
75
- borderRadius: theme.borderRadius.md,
76
- padding: theme.spacing[2],
77
- },
78
- warningText: {
79
- color: theme.colors.warningForeground,
80
- fontSize: 12,
81
- fontWeight: "500",
82
- },
83
- compactContainer: {
84
- flexDirection: "row",
85
- flexWrap: "wrap",
86
- gap: theme.spacing[1],
87
- },
88
- compactWarning: {
89
- backgroundColor: theme.colors.warning,
90
- borderRadius: theme.borderRadius.full,
91
- paddingHorizontal: 10,
92
- paddingVertical: 4,
93
- },
94
- compactWarningText: {
95
- color: theme.colors.warningForeground,
96
- fontSize: 14,
97
- fontWeight: "600",
98
- },
99
- });
100
- }
@@ -3,8 +3,10 @@ export { ContentMetadataForm } from "./content-metadata-form";
3
3
 
4
4
  // Display components
5
5
  export { ContentRights } from "./content-rights";
6
+ export { ContentWarningBadge } from "./content-warning-badge";
6
7
  export { ContentWarnings } from "./content-warnings";
7
8
 
8
9
  export type { ContentRightsProps } from "./content-rights";
9
10
 
11
+ export type { ContentWarningBadgeProps } from "./content-warning-badge";
10
12
  export type { ContentWarningsProps } from "./content-warnings";
@@ -1,11 +1,18 @@
1
1
  import { useRootContext } from "@rn-primitives/dropdown-menu";
2
2
  import { Menu } from "lucide-react-native";
3
3
  import { Image, Linking, Platform, Pressable, View } from "react-native";
4
- import { useAvatars, useLivestreamInfo, zero } from "../../..";
4
+ import {
5
+ ContentRights,
6
+ ContentWarnings,
7
+ useAvatars,
8
+ useLivestreamInfo,
9
+ zero,
10
+ } from "../../..";
5
11
  import { colors } from "../../../lib/theme";
6
12
  import { useLivestreamStore } from "../../../livestream-store";
7
13
  import { PlayerProtocol, usePlayerStore } from "../../../player-store/";
8
14
  import { useGraphManager } from "../../../streamplace-store/graph";
15
+ import { gap, pt, px } from "../../../ui";
9
16
  import {
10
17
  DropdownMenu,
11
18
  DropdownMenuCheckboxItem,
@@ -42,8 +49,15 @@ export function ContextMenu({
42
49
  const setReportSubject = usePlayerStore((x) => x.setReportSubject);
43
50
 
44
51
  const { profile } = useLivestreamInfo();
52
+
53
+ console.log("profile", profile);
45
54
  const avatars = useAvatars(profile?.did ? [profile?.did] : []);
46
55
  const ls = useLivestreamStore((x) => x.livestream);
56
+ const segment = useLivestreamStore((x) => x.segment);
57
+
58
+ // Get content rights from the latest segment
59
+ const contentRights = segment?.contentRights;
60
+ const contentWarnings = segment?.contentWarnings?.warnings || [];
47
61
 
48
62
  let graphManager = useGraphManager(profile?.did);
49
63
 
@@ -160,6 +174,7 @@ export function ContextMenu({
160
174
  </DropdownMenuItem>
161
175
  </DropdownMenuGroup>
162
176
  )}
177
+
163
178
  <DropdownMenuGroup title="Resolution">
164
179
  <DropdownMenuRadioGroup value={quality} onValueChange={setQuality}>
165
180
  <DropdownMenuRadioItem value="source">
@@ -196,6 +211,23 @@ export function ContextMenu({
196
211
  setReportSubject={setReportSubject}
197
212
  />
198
213
  </DropdownMenuGroup>
214
+ <View style={[pt[3], px[2], gap.all[2]]}>
215
+ {contentWarnings && contentWarnings.length > 0 && (
216
+ <View style={[gap.all[1]]}>
217
+ <Text size="base" color="muted">
218
+ Stream may contain
219
+ </Text>
220
+ <ContentWarnings warnings={contentWarnings} compact={true} />
221
+ </View>
222
+ )}
223
+ {contentRights && Object.keys(contentRights).length > 0 && (
224
+ <ContentRights
225
+ contentRights={contentRights}
226
+ size="xs"
227
+ color="muted"
228
+ />
229
+ )}
230
+ </View>
199
231
  </DropdownMenuContent>
200
232
  </Portal>
201
233
  </DropdownMenu>