@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.
- package/dist/components/content-metadata/content-metadata-form.js +6 -22
- package/dist/components/content-metadata/content-rights.js +18 -47
- package/dist/components/content-metadata/content-warning-badge.js +42 -0
- package/dist/components/content-metadata/content-warnings.js +15 -48
- package/dist/components/content-metadata/index.js +3 -1
- package/dist/components/mobile-player/ui/viewer-context-menu.js +17 -11
- package/dist/components/ui/checkbox.js +6 -18
- package/dist/components/ui/dropdown.js +16 -11
- package/dist/components/ui/primitives/text.js +19 -4
- package/dist/components/ui/select.js +44 -75
- package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
- package/package.json +2 -2
- package/src/components/content-metadata/content-metadata-form.tsx +9 -49
- package/src/components/content-metadata/content-rights.tsx +31 -56
- package/src/components/content-metadata/content-warning-badge.tsx +94 -0
- package/src/components/content-metadata/content-warnings.tsx +46 -58
- package/src/components/content-metadata/index.tsx +2 -0
- package/src/components/mobile-player/ui/viewer-context-menu.tsx +33 -1
- package/src/components/ui/checkbox.tsx +23 -21
- package/src/components/ui/dropdown.tsx +60 -40
- package/src/components/ui/primitives/text.tsx +24 -4
- package/src/components/ui/select.tsx +97 -125
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
}
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@streamplace/components",
|
|
3
|
-
"version": "0.8.
|
|
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": "
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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<
|
|
19
|
-
({ contentRights }, ref) => {
|
|
20
|
-
const {
|
|
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(
|
|
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 (
|
|
53
|
-
elements
|
|
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
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
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 {
|
|
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<
|
|
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
|
|
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
|
|
31
|
-
|
|
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={
|
|
42
|
-
<Text
|
|
43
|
-
|
|
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
|
|
46
|
-
|
|
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 {
|
|
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>
|