@streamplace/components 0.7.35 → 0.8.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 (45) hide show
  1. package/dist/components/content-metadata/content-metadata-form.js +404 -0
  2. package/dist/components/content-metadata/content-rights.js +78 -0
  3. package/dist/components/content-metadata/content-warnings.js +68 -0
  4. package/dist/components/content-metadata/index.js +11 -0
  5. package/dist/components/mobile-player/player.js +4 -0
  6. package/dist/components/mobile-player/ui/report-modal.js +3 -2
  7. package/dist/components/ui/checkbox.js +87 -0
  8. package/dist/components/ui/dialog.js +188 -83
  9. package/dist/components/ui/primitives/input.js +13 -1
  10. package/dist/components/ui/primitives/modal.js +2 -2
  11. package/dist/components/ui/select.js +89 -0
  12. package/dist/components/ui/textarea.js +23 -4
  13. package/dist/components/ui/toast.js +464 -114
  14. package/dist/components/ui/tooltip.js +103 -0
  15. package/dist/index.js +2 -0
  16. package/dist/lib/metadata-constants.js +157 -0
  17. package/dist/lib/theme/theme.js +5 -3
  18. package/dist/streamplace-provider/index.js +14 -4
  19. package/dist/streamplace-store/content-metadata-actions.js +118 -0
  20. package/dist/streamplace-store/streamplace-store.js +18 -5
  21. package/dist/streamplace-store/user.js +67 -7
  22. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
  23. package/package.json +3 -3
  24. package/src/components/content-metadata/content-metadata-form.tsx +761 -0
  25. package/src/components/content-metadata/content-rights.tsx +104 -0
  26. package/src/components/content-metadata/content-warnings.tsx +100 -0
  27. package/src/components/content-metadata/index.tsx +18 -0
  28. package/src/components/mobile-player/player.tsx +5 -0
  29. package/src/components/mobile-player/ui/report-modal.tsx +13 -7
  30. package/src/components/ui/checkbox.tsx +147 -0
  31. package/src/components/ui/dialog.tsx +319 -99
  32. package/src/components/ui/primitives/input.tsx +19 -2
  33. package/src/components/ui/primitives/modal.tsx +4 -2
  34. package/src/components/ui/select.tsx +175 -0
  35. package/src/components/ui/textarea.tsx +47 -29
  36. package/src/components/ui/toast.tsx +785 -179
  37. package/src/components/ui/tooltip.tsx +131 -0
  38. package/src/index.tsx +3 -0
  39. package/src/lib/metadata-constants.ts +180 -0
  40. package/src/lib/theme/theme.tsx +10 -6
  41. package/src/streamplace-provider/index.tsx +20 -2
  42. package/src/streamplace-store/content-metadata-actions.tsx +142 -0
  43. package/src/streamplace-store/streamplace-store.tsx +30 -4
  44. package/src/streamplace-store/user.tsx +71 -7
  45. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,404 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ContentMetadataForm = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const jsx_runtime_1 = require("react/jsx-runtime");
6
+ const react_1 = require("react");
7
+ const react_native_1 = require("react-native");
8
+ const metadata_constants_1 = require("../../lib/metadata-constants");
9
+ const content_metadata_actions_1 = require("../../streamplace-store/content-metadata-actions");
10
+ const streamplace_store_1 = require("../../streamplace-store/streamplace-store");
11
+ const xrpc_1 = require("../../streamplace-store/xrpc");
12
+ const zero = tslib_1.__importStar(require("../../ui"));
13
+ const button_1 = require("../ui/button");
14
+ const checkbox_1 = require("../ui/checkbox");
15
+ const input_1 = require("../ui/input");
16
+ const select_1 = require("../ui/select");
17
+ const text_1 = require("../ui/text");
18
+ const textarea_1 = require("../ui/textarea");
19
+ const toast_1 = require("../ui/toast");
20
+ const tooltip_1 = require("../ui/tooltip");
21
+ const { p, r, bg, borders, w, text, layout, gap, flex } = zero;
22
+ // ButtonSelector component (same as in livestream-panel)
23
+ const ButtonSelector = ({ values, selectedValue, setSelectedValue, disabledValues = [], style = [], }) => ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: [layout.flex.row, gap.all[1], ...style], children: values.map(({ label, value }) => ((0, jsx_runtime_1.jsx)(button_1.Button, { variant: selectedValue === value ? "primary" : "secondary", size: "pill", disabled: disabledValues.includes(value), onPress: () => setSelectedValue(value), style: [
24
+ r.md,
25
+ {
26
+ opacity: disabledValues.includes(value) ? 0.5 : 1,
27
+ },
28
+ ], children: (0, jsx_runtime_1.jsx)(text_1.Text, { style: [
29
+ selectedValue === value ? text.white : text.gray[300],
30
+ { fontSize: 14, fontWeight: "600" },
31
+ ], children: label }) }, value))) }));
32
+ exports.ContentMetadataForm = (0, react_1.forwardRef)(({ showUpdateButton = false, onMetadataChange, initialMetadata, style }, ref) => {
33
+ const pdsAgent = (0, xrpc_1.usePDSAgent)();
34
+ const did = (0, streamplace_store_1.useDID)();
35
+ const getContentMetadata = (0, content_metadata_actions_1.useGetContentMetadata)();
36
+ const saveContentMetadata = (0, content_metadata_actions_1.useSaveContentMetadata)();
37
+ const toast = (0, toast_1.useToast)();
38
+ // Local state for metadata
39
+ const [contentWarnings, setContentWarnings] = (0, react_1.useState)([]);
40
+ const [distributionPolicy, setDistributionPolicy] = (0, react_1.useState)({});
41
+ const [contentRights, setContentRights] = (0, react_1.useState)({});
42
+ const [selectedLicense, setSelectedLicense] = (0, react_1.useState)("");
43
+ const [customLicenseText, setCustomLicenseText] = (0, react_1.useState)("");
44
+ const [customDateTime, setCustomDateTime] = (0, react_1.useState)("");
45
+ const [loading, setLoading] = (0, react_1.useState)(false);
46
+ const [hasMetadata, setHasMetadata] = (0, react_1.useState)(false);
47
+ // State for section toggles
48
+ const [activeSection, setActiveSection] = (0, react_1.useState)("contentWarnings");
49
+ const currentYear = new Date().getFullYear();
50
+ // Load existing metadata on mount or from initialMetadata prop
51
+ (0, react_1.useEffect)(() => {
52
+ if (initialMetadata) {
53
+ // Use provided initial metadata
54
+ if (initialMetadata.contentWarnings?.warnings) {
55
+ setContentWarnings(initialMetadata.contentWarnings.warnings);
56
+ }
57
+ if (initialMetadata.distributionPolicy) {
58
+ setDistributionPolicy(initialMetadata.distributionPolicy);
59
+ setCustomDateTime(initialMetadata.distributionPolicy.deleteAfter
60
+ ? String(initialMetadata.distributionPolicy.deleteAfter)
61
+ : "");
62
+ }
63
+ if (initialMetadata.contentRights) {
64
+ setContentRights(initialMetadata.contentRights);
65
+ setSelectedLicense(initialMetadata.contentRights.license || "");
66
+ }
67
+ return;
68
+ }
69
+ const loadMetadata = async () => {
70
+ if (!pdsAgent || !did)
71
+ return;
72
+ try {
73
+ const metadata = await getContentMetadata();
74
+ if (metadata?.record) {
75
+ setHasMetadata(true);
76
+ if (metadata.record.contentWarnings?.warnings) {
77
+ setContentWarnings(metadata.record.contentWarnings.warnings);
78
+ }
79
+ if (metadata.record.distributionPolicy) {
80
+ setDistributionPolicy(metadata.record.distributionPolicy);
81
+ setCustomDateTime(metadata.record.distributionPolicy.deleteAfter
82
+ ? String(metadata.record.distributionPolicy.deleteAfter)
83
+ : "");
84
+ }
85
+ if (metadata.record.contentRights) {
86
+ setContentRights(metadata.record.contentRights);
87
+ setSelectedLicense(metadata.record.contentRights.license || "");
88
+ }
89
+ }
90
+ }
91
+ catch (error) {
92
+ // No existing metadata is fine
93
+ console.log("No existing metadata found");
94
+ }
95
+ };
96
+ loadMetadata();
97
+ }, [pdsAgent, did, initialMetadata]);
98
+ const handleContentWarningChange = (0, react_1.useCallback)((warning, checked) => {
99
+ const newWarnings = checked
100
+ ? [...contentWarnings, warning]
101
+ : contentWarnings.filter((w) => w !== warning);
102
+ setContentWarnings(newWarnings);
103
+ if (onMetadataChange) {
104
+ onMetadataChange({
105
+ contentWarnings: { warnings: newWarnings },
106
+ distributionPolicy,
107
+ contentRights,
108
+ });
109
+ }
110
+ }, [contentWarnings, distributionPolicy, contentRights, onMetadataChange]);
111
+ // Notify parent component when metadata changes
112
+ (0, react_1.useEffect)(() => {
113
+ if (onMetadataChange) {
114
+ onMetadataChange({
115
+ contentWarnings: { warnings: contentWarnings },
116
+ distributionPolicy,
117
+ contentRights,
118
+ });
119
+ }
120
+ }, [contentWarnings, distributionPolicy, contentRights, onMetadataChange]);
121
+ // Handle distribution policy changes
122
+ const handleDistributionPolicyChange = (0, react_1.useCallback)((deleteAfter) => {
123
+ let duration = parseInt(deleteAfter, 10);
124
+ if (isNaN(duration) || duration < 0) {
125
+ duration = 0;
126
+ }
127
+ const newPolicy = duration > 0 ? { deleteAfter: duration } : {};
128
+ console.log("newPolicy", newPolicy);
129
+ setDistributionPolicy(newPolicy);
130
+ if (onMetadataChange) {
131
+ onMetadataChange({
132
+ contentWarnings: { warnings: contentWarnings },
133
+ distributionPolicy: newPolicy,
134
+ contentRights,
135
+ });
136
+ }
137
+ }, [
138
+ contentWarnings,
139
+ contentRights,
140
+ onMetadataChange,
141
+ distributionPolicy,
142
+ setDistributionPolicy,
143
+ ]);
144
+ // Handle content rights changes
145
+ const handleContentRightsChange = (0, react_1.useCallback)((field, value) => {
146
+ const newRights = { ...contentRights, [field]: value };
147
+ setContentRights(newRights);
148
+ if (onMetadataChange) {
149
+ onMetadataChange({
150
+ contentWarnings: { warnings: contentWarnings },
151
+ distributionPolicy,
152
+ contentRights: newRights,
153
+ });
154
+ }
155
+ }, [contentWarnings, distributionPolicy, contentRights, onMetadataChange]);
156
+ const handleSave = (0, react_1.useCallback)(async () => {
157
+ setLoading(true);
158
+ try {
159
+ // Build the metadata object, only including non-empty fields
160
+ const metadata = {};
161
+ // Only include contentWarnings if it has values
162
+ if (contentWarnings && contentWarnings.length > 0) {
163
+ metadata.contentWarnings = contentWarnings;
164
+ }
165
+ // Only include distributionPolicy if it has a deleteAfter value
166
+ const duration = parseInt(customDateTime, 10);
167
+ if (!isNaN(duration) && duration > 0) {
168
+ metadata.distributionPolicy = { deleteAfter: duration };
169
+ setCustomDateTime(`${duration}`);
170
+ }
171
+ else {
172
+ setCustomDateTime("");
173
+ }
174
+ // Only include contentRights if it has actual values
175
+ const rightsWithLicense = {
176
+ ...contentRights,
177
+ license: selectedLicense === "custom"
178
+ ? customLicenseText
179
+ : selectedLicense || undefined,
180
+ };
181
+ // Filter out empty values from contentRights and convert copyrightYear to number
182
+ const filteredRights = Object.fromEntries(Object.entries(rightsWithLicense)
183
+ .filter(([_, value]) => value !== undefined && value !== null && value !== "")
184
+ .map(([key, value]) => {
185
+ // Convert copyrightYear to integer as per lexicon
186
+ if (key === "copyrightYear" && typeof value === "string") {
187
+ const year = parseInt(value, 10);
188
+ return [key, isNaN(year) ? undefined : year];
189
+ }
190
+ return [key, value];
191
+ })
192
+ .filter(([_, value]) => value !== undefined));
193
+ if (Object.keys(filteredRights).length > 0) {
194
+ metadata.contentRights = filteredRights;
195
+ }
196
+ await saveContentMetadata(metadata);
197
+ setHasMetadata(true);
198
+ // Show success toast
199
+ toast.show(hasMetadata ? "Content metadata updated" : "Content metadata created", "Your settings have been saved successfully");
200
+ }
201
+ catch (error) {
202
+ console.error("Failed to save metadata:", error);
203
+ // Show error toast
204
+ toast.show("Failed to save metadata", "Please try again later");
205
+ }
206
+ finally {
207
+ setLoading(false);
208
+ }
209
+ }, [
210
+ contentWarnings,
211
+ contentRights,
212
+ selectedLicense,
213
+ customLicenseText,
214
+ customDateTime,
215
+ hasMetadata,
216
+ saveContentMetadata,
217
+ ]);
218
+ return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsx)(react_native_1.ScrollView, { ref: ref, style: [{ flex: 1 }, style], showsVerticalScrollIndicator: false, contentContainerStyle: { flexGrow: 1 }, children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [gap.all[8], w.percent[100], { alignItems: "stretch" }], children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { style: [gap.all[4], w.percent[100]], children: (0, jsx_runtime_1.jsx)(ButtonSelector, { values: [
219
+ { label: "Content Warnings", value: "contentWarnings" },
220
+ { label: "Content Rights", value: "contentRights" },
221
+ { label: "Distribution", value: "distribution" },
222
+ ], selectedValue: activeSection, setSelectedValue: setActiveSection, style: [{ marginVertical: -2, flexDirection: "column" }] }) }), activeSection === "contentWarnings" && ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [gap.all[3], w.percent[100]], children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
223
+ layout.flex.row,
224
+ layout.flex.alignCenter,
225
+ w.percent[100],
226
+ ], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
227
+ text.neutral[300],
228
+ {
229
+ minWidth: 100,
230
+ textAlign: "left",
231
+ paddingBottom: 8,
232
+ fontSize: 14,
233
+ },
234
+ ], children: "Content Warnings" }), (0, jsx_runtime_1.jsx)(text_1.Text, { style: [text.gray[500], { fontSize: 12, paddingBottom: 8 }], children: "optional" })] }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [gap.all[2], w.percent[100]], children: metadata_constants_1.CONTENT_WARNINGS.map((warning) => ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: [w.percent[100]], children: (0, jsx_runtime_1.jsx)(tooltip_1.Tooltip, { content: warning.description, position: "top", children: (0, jsx_runtime_1.jsx)(checkbox_1.Checkbox, { checked: contentWarnings.includes(warning.value), onCheckedChange: (checked) => handleContentWarningChange(warning.value, checked), label: warning.label, style: [{ fontSize: 12 }] }) }) }, warning.value))) })] })), activeSection === "contentRights" && ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [gap.all[3], w.percent[100]], children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
235
+ layout.flex.row,
236
+ layout.flex.alignCenter,
237
+ w.percent[100],
238
+ ], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
239
+ text.neutral[300],
240
+ {
241
+ minWidth: 100,
242
+ textAlign: "left",
243
+ paddingBottom: 8,
244
+ fontSize: 14,
245
+ },
246
+ ], children: "Content Rights" }), (0, jsx_runtime_1.jsx)(text_1.Text, { style: [text.gray[500], { fontSize: 12, paddingBottom: 8 }], children: "optional" })] }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [gap.all[3], w.percent[100]], children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
247
+ layout.flex.row,
248
+ layout.flex.alignCenter,
249
+ w.percent[100],
250
+ ], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
251
+ text.neutral[300],
252
+ {
253
+ minWidth: 100,
254
+ textAlign: "left",
255
+ paddingBottom: 8,
256
+ fontSize: 14,
257
+ },
258
+ ], children: "Copyright Year" }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [flex.values[1]], children: (0, jsx_runtime_1.jsx)(input_1.Input, { value: contentRights.copyrightYear?.toString() || "", onChange: (value) => handleContentRightsChange("copyrightYear", value), placeholder: currentYear.toString(), variant: "filled", inputStyle: [
259
+ p[3],
260
+ r.md,
261
+ bg.neutral[800],
262
+ text.white,
263
+ borders.width.thin,
264
+ borders.color.neutral[600],
265
+ w.percent[100],
266
+ ] }) })] }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
267
+ layout.flex.row,
268
+ layout.flex.alignCenter,
269
+ w.percent[100],
270
+ ], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
271
+ text.neutral[300],
272
+ {
273
+ minWidth: 100,
274
+ textAlign: "left",
275
+ paddingBottom: 8,
276
+ fontSize: 14,
277
+ },
278
+ ], children: "License" }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [flex.values[1]], children: (0, jsx_runtime_1.jsx)(select_1.Select, { value: selectedLicense, onValueChange: (value) => {
279
+ setSelectedLicense(value);
280
+ handleContentRightsChange("license", value === "custom" ? customLicenseText : value);
281
+ }, placeholder: "Select a license", items: metadata_constants_1.LICENSE_OPTIONS.map((opt) => ({
282
+ label: opt.label,
283
+ value: opt.value,
284
+ description: opt.description,
285
+ })), style: [
286
+ p[3],
287
+ r.md,
288
+ bg.neutral[800],
289
+ text.white,
290
+ borders.width.thin,
291
+ borders.color.neutral[600],
292
+ w.percent[100],
293
+ ] }) })] }), selectedLicense === "custom" && ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
294
+ layout.flex.row,
295
+ layout.flex.alignCenter,
296
+ w.percent[100],
297
+ ], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
298
+ text.neutral[300],
299
+ {
300
+ minWidth: 100,
301
+ textAlign: "left",
302
+ paddingBottom: 8,
303
+ fontSize: 14,
304
+ },
305
+ ], children: "Custom License" }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [flex.values[1]], children: (0, jsx_runtime_1.jsx)(textarea_1.Textarea, { value: customLicenseText, onChangeText: (value) => {
306
+ setCustomLicenseText(value);
307
+ if (selectedLicense === "custom") {
308
+ handleContentRightsChange("license", value);
309
+ }
310
+ }, placeholder: "Enter your custom license terms...", style: [
311
+ p[3],
312
+ r.md,
313
+ bg.neutral[800],
314
+ text.white,
315
+ borders.width.thin,
316
+ borders.color.neutral[600],
317
+ w.percent[100],
318
+ ] }) })] })), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
319
+ layout.flex.row,
320
+ layout.flex.alignCenter,
321
+ w.percent[100],
322
+ ], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
323
+ text.neutral[300],
324
+ {
325
+ minWidth: 100,
326
+ textAlign: "left",
327
+ paddingBottom: 8,
328
+ fontSize: 14,
329
+ },
330
+ ], children: "Copyright Notice" }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [flex.values[1]], children: (0, jsx_runtime_1.jsx)(textarea_1.Textarea, { value: contentRights.copyrightNotice || "", onChangeText: (value) => handleContentRightsChange("copyrightNotice", value), placeholder: "Enter your copyright notice...", style: [
331
+ p[3],
332
+ r.md,
333
+ bg.neutral[800],
334
+ text.white,
335
+ borders.width.thin,
336
+ borders.color.neutral[600],
337
+ w.percent[100],
338
+ ] }) })] }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
339
+ layout.flex.row,
340
+ layout.flex.alignCenter,
341
+ w.percent[100],
342
+ ], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
343
+ text.neutral[300],
344
+ {
345
+ minWidth: 100,
346
+ textAlign: "left",
347
+ paddingBottom: 8,
348
+ fontSize: 14,
349
+ },
350
+ ], children: "Credit Line" }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [flex.values[1]], children: (0, jsx_runtime_1.jsx)(textarea_1.Textarea, { value: contentRights.creditLine || "", onChangeText: (value) => handleContentRightsChange("creditLine", value), placeholder: "Enter your credit line...", style: [
351
+ p[3],
352
+ r.md,
353
+ bg.neutral[800],
354
+ text.white,
355
+ borders.width.thin,
356
+ borders.color.neutral[600],
357
+ w.percent[100],
358
+ ] }) })] })] })] })), activeSection === "distribution" && ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [gap.all[3], w.percent[100]], children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
359
+ layout.flex.row,
360
+ layout.flex.alignCenter,
361
+ w.percent[100],
362
+ ], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
363
+ text.neutral[300],
364
+ { minWidth: 100, textAlign: "left", paddingBottom: 8 },
365
+ ], children: "Distribution" }), (0, jsx_runtime_1.jsx)(text_1.Text, { style: [text.gray[500], { fontSize: 12, paddingBottom: 8 }], children: "optional" })] }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [gap.all[3], w.percent[100]], children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
366
+ layout.flex.row,
367
+ layout.flex.alignCenter,
368
+ w.percent[100],
369
+ ], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
370
+ text.neutral[300],
371
+ {
372
+ minWidth: 100,
373
+ textAlign: "left",
374
+ paddingBottom: 8,
375
+ fontSize: 14,
376
+ },
377
+ ], children: "Delete After" }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [flex.values[1]], children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
378
+ text.gray[500],
379
+ { fontSize: 12, paddingBottom: 4 },
380
+ ], children: "Duration in seconds (e.g., 300 for 5 minutes) or 0 to allow archiving your stream" }), (0, jsx_runtime_1.jsx)(input_1.Input, { value: customDateTime, onChange: (value) => {
381
+ setCustomDateTime(value);
382
+ handleDistributionPolicyChange(value);
383
+ }, keyboardType: "numeric", variant: "filled", inputStyle: [
384
+ p[3],
385
+ r.md,
386
+ bg.neutral[800],
387
+ text.white,
388
+ borders.width.thin,
389
+ borders.color.neutral[600],
390
+ w.percent[100],
391
+ ] })] })] }) })] })), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [layout.flex.center, w.percent[100]], children: (0, jsx_runtime_1.jsx)(button_1.Button, { onPress: handleSave, loading: loading, disabled: loading, style: [
392
+ bg.primary[500],
393
+ r.md,
394
+ gap.all[3],
395
+ { minWidth: 200 },
396
+ layout.flex.center,
397
+ { opacity: loading ? 0.5 : 1 },
398
+ ], children: (0, jsx_runtime_1.jsx)(text_1.Text, { style: [
399
+ text.white,
400
+ w.percent[100],
401
+ { fontSize: 16, fontWeight: "bold" },
402
+ ], children: hasMetadata ? "Update Metadata" : "Save Metadata" }) }) })] }) }) }));
403
+ });
404
+ exports.ContentMetadataForm.displayName = "ContentMetadataForm";
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ContentRights = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const react_native_1 = require("react-native");
7
+ const metadata_constants_1 = require("../../lib/metadata-constants");
8
+ const theme_1 = require("../../lib/theme/theme");
9
+ const text_1 = require("../ui/text");
10
+ exports.ContentRights = (0, react_1.forwardRef)(({ contentRights }, ref) => {
11
+ const { theme } = (0, theme_1.useTheme)();
12
+ if (!contentRights || Object.keys(contentRights).length === 0) {
13
+ return null;
14
+ }
15
+ const styles = createStyles(theme);
16
+ const formatLicense = (license) => {
17
+ return metadata_constants_1.LICENSE_URL_LABELS[license] || license;
18
+ };
19
+ // Display rights in bottom metadata view
20
+ const elements = [];
21
+ // TODO: Map DID to handle creator
22
+ // if (contentRights.creator) {
23
+ // elements.push(`Creator: ${contentRights.creator}`);
24
+ // }
25
+ if (contentRights.copyrightYear) {
26
+ elements.push(`© ${contentRights.copyrightYear.toString()}`);
27
+ }
28
+ if (contentRights.license) {
29
+ elements.push(formatLicense(contentRights.license));
30
+ }
31
+ if (contentRights.copyrightNotice) {
32
+ elements.push(contentRights.copyrightNotice);
33
+ }
34
+ if (contentRights.creditLine) {
35
+ elements.push(contentRights.creditLine);
36
+ }
37
+ return ((0, jsx_runtime_1.jsx)(react_native_1.View, { ref: ref, style: styles.compactContainer, children: (0, jsx_runtime_1.jsx)(text_1.Text, { style: styles.compactText, children: elements.join(" • ") }) }));
38
+ });
39
+ exports.ContentRights.displayName = "ContentRights";
40
+ function createStyles(theme) {
41
+ return react_native_1.StyleSheet.create({
42
+ container: {
43
+ paddingVertical: theme.spacing[3],
44
+ },
45
+ title: {
46
+ fontSize: 14,
47
+ fontWeight: "600",
48
+ color: theme.colors.text,
49
+ marginBottom: theme.spacing[2],
50
+ },
51
+ content: {
52
+ gap: theme.spacing[2],
53
+ },
54
+ row: {
55
+ flexDirection: "row",
56
+ gap: theme.spacing[2],
57
+ },
58
+ label: {
59
+ fontSize: 13,
60
+ color: theme.colors.textMuted,
61
+ },
62
+ value: {
63
+ fontSize: 13,
64
+ color: theme.colors.text,
65
+ },
66
+ compactContainer: {
67
+ flexDirection: "row",
68
+ gap: theme.spacing[2],
69
+ flexWrap: "wrap",
70
+ marginTop: theme.spacing[1],
71
+ },
72
+ compactText: {
73
+ fontSize: 14,
74
+ fontWeight: "500",
75
+ color: theme.colors.text,
76
+ },
77
+ });
78
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ContentWarnings = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const react_native_1 = require("react-native");
7
+ const metadata_constants_1 = require("../../lib/metadata-constants");
8
+ const theme_1 = require("../../lib/theme/theme");
9
+ const text_1 = require("../ui/text");
10
+ exports.ContentWarnings = (0, react_1.forwardRef)(({ warnings, compact = false }, ref) => {
11
+ const { theme } = (0, theme_1.useTheme)();
12
+ if (!warnings || warnings.length === 0) {
13
+ return null;
14
+ }
15
+ const styles = createStyles(theme, compact);
16
+ const getWarningLabel = (warning) => {
17
+ return metadata_constants_1.C2PA_WARNING_LABELS[warning] || warning;
18
+ };
19
+ if (compact) {
20
+ return ((0, jsx_runtime_1.jsx)(react_native_1.View, { ref: ref, style: styles.compactContainer, children: warnings.map((warning, index) => ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.compactWarning, children: (0, jsx_runtime_1.jsx)(text_1.Text, { style: styles.compactWarningText, children: getWarningLabel(warning) }) }, index))) }));
21
+ }
22
+ return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { ref: ref, style: styles.container, children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: styles.title, children: "Content Warnings" }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.warningsContainer, children: warnings.map((warning, index) => ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.warning, children: (0, jsx_runtime_1.jsx)(text_1.Text, { style: styles.warningText, children: getWarningLabel(warning) }) }, index))) })] }));
23
+ });
24
+ exports.ContentWarnings.displayName = "ContentWarnings";
25
+ function createStyles(theme, compact) {
26
+ return react_native_1.StyleSheet.create({
27
+ container: {
28
+ flexDirection: "column",
29
+ gap: theme.spacing[2],
30
+ },
31
+ title: {
32
+ fontSize: 14,
33
+ fontWeight: "600",
34
+ color: theme.colors.text,
35
+ },
36
+ warningsContainer: {
37
+ flexDirection: "row",
38
+ flexWrap: "wrap",
39
+ gap: theme.spacing[2],
40
+ },
41
+ warning: {
42
+ backgroundColor: theme.colors.warning,
43
+ borderRadius: theme.borderRadius.md,
44
+ padding: theme.spacing[2],
45
+ },
46
+ warningText: {
47
+ color: theme.colors.warningForeground,
48
+ fontSize: 12,
49
+ fontWeight: "500",
50
+ },
51
+ compactContainer: {
52
+ flexDirection: "row",
53
+ flexWrap: "wrap",
54
+ gap: theme.spacing[1],
55
+ },
56
+ compactWarning: {
57
+ backgroundColor: theme.colors.warning,
58
+ borderRadius: theme.borderRadius.full,
59
+ paddingHorizontal: 10,
60
+ paddingVertical: 4,
61
+ },
62
+ compactWarningText: {
63
+ color: theme.colors.warningForeground,
64
+ fontSize: 14,
65
+ fontWeight: "600",
66
+ },
67
+ });
68
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ContentWarnings = exports.ContentRights = exports.ContentMetadataForm = void 0;
4
+ // Main form component
5
+ var content_metadata_form_1 = require("./content-metadata-form");
6
+ Object.defineProperty(exports, "ContentMetadataForm", { enumerable: true, get: function () { return content_metadata_form_1.ContentMetadataForm; } });
7
+ // Display components
8
+ var content_rights_1 = require("./content-rights");
9
+ Object.defineProperty(exports, "ContentRights", { enumerable: true, get: function () { return content_rights_1.ContentRights; } });
10
+ var content_warnings_1 = require("./content-warnings");
11
+ Object.defineProperty(exports, "ContentWarnings", { enumerable: true, get: function () { return content_warnings_1.ContentWarnings; } });
@@ -18,12 +18,16 @@ function Player(props) {
18
18
  const setIngest = (0, player_store_1.usePlayerStore)((x) => x.setIngestConnectionState);
19
19
  const clearControlsTimeout = (0, player_store_1.usePlayerStore)((x) => x.clearControlsTimeout);
20
20
  const setReportingURL = (0, player_store_1.usePlayerStore)((x) => x.setReportingURL);
21
+ const setEmbedded = (0, player_store_1.usePlayerStore)((x) => x.setEmbedded);
21
22
  const reportModalOpen = (0, player_store_1.usePlayerStore)((x) => x.reportModalOpen);
22
23
  const setReportModalOpen = (0, player_store_1.usePlayerStore)((x) => x.setReportModalOpen);
23
24
  const reportSubject = (0, player_store_1.usePlayerStore)((x) => x.reportSubject);
24
25
  (0, react_1.useEffect)(() => {
25
26
  setReportingURL(props.reportingURL ?? null);
26
27
  }, [props.reportingURL]);
28
+ (0, react_1.useEffect)(() => {
29
+ setEmbedded(props.embedded ?? false);
30
+ }, [props.embedded]);
27
31
  // Will call back every few seconds to send health updates
28
32
  usePlayerStatus();
29
33
  (0, react_1.useEffect)(() => {
@@ -47,6 +47,7 @@ const ReportModal = ({ open, onOpenChange, onSubmit, subject, title = "Report",
47
47
  const [additionalComments, setAdditionalComments] = (0, react_1.useState)("");
48
48
  const [isSubmitting, setIsSubmitting] = (0, react_1.useState)(false);
49
49
  const [submitError, setSubmitError] = (0, react_1.useState)(null);
50
+ const { theme } = (0, ui_1.useTheme)();
50
51
  const submitReport = (0, livestream_store_1.useSubmitReport)();
51
52
  const handleCancel = () => {
52
53
  setSelectedReason(null);
@@ -74,7 +75,7 @@ const ReportModal = ({ open, onOpenChange, onSubmit, subject, title = "Report",
74
75
  setIsSubmitting(false);
75
76
  }
76
77
  };
77
- return ((0, jsx_runtime_1.jsxs)(ui_1.Dialog, { open: open, onOpenChange: onOpenChange, title: title, description: description, showCloseButton: true, variant: "default", size: "md", dismissible: false, position: "center", children: [(0, jsx_runtime_1.jsxs)(ui_1.ModalContent, { style: [__1.zero.pb[2]], children: [REPORT_REASONS.map((reason) => ((0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { onPress: () => setSelectedReason(reason.value), style: [
78
+ return ((0, jsx_runtime_1.jsxs)(ui_1.ResponsiveDialog, { open: open, onOpenChange: onOpenChange, title: title, description: description, showCloseButton: true, variant: "default", size: "md", dismissible: false, position: "center", children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [__1.zero.pb[2]], children: [REPORT_REASONS.map((reason) => ((0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { onPress: () => setSelectedReason(reason.value), style: [
78
79
  __1.zero.layout.flex.row,
79
80
  __1.zero.gap.all[2],
80
81
  __1.zero.py[3],
@@ -84,7 +85,7 @@ const ReportModal = ({ open, onOpenChange, onSubmit, subject, title = "Report",
84
85
  selectedReason === reason.value && {
85
86
  backgroundColor: "rgba(0, 122, 255, 0.1)",
86
87
  },
87
- ], children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { children: selectedReason === reason.value ? (0, jsx_runtime_1.jsx)(lucide_react_native_1.CheckCircle, {}) : (0, jsx_runtime_1.jsx)(lucide_react_native_1.Circle, {}) }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [__1.zero.layout.flex.column, __1.zero.gap.all[1], __1.zero.flex[1]], children: [(0, jsx_runtime_1.jsx)(ui_1.Text, { style: [{ fontWeight: "600" }], children: reason.label }), (0, jsx_runtime_1.jsx)(ui_1.Text, { style: [{ fontSize: 14, color: "rgba(255,255,255,0.7)" }], children: reason.description })] })] }, reason.value))), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [__1.zero.pb[4], __1.zero.mt[4], __1.zero.px[2]], children: [(0, jsx_runtime_1.jsx)(ui_1.Text, { style: [__1.zero.mb[2]], children: "Additional Comments (optional)" }), (0, jsx_runtime_1.jsx)(ui_1.Textarea, { maxLength: 500, numberOfLines: 3, value: additionalComments, onChangeText: setAdditionalComments, placeholder: "Provide additional context for this report..." }), submitError && ((0, jsx_runtime_1.jsx)(ui_1.Text, { style: [__1.zero.mt[2], { color: "red", fontSize: 14 }], children: submitError }))] })] }), (0, jsx_runtime_1.jsxs)(ui_1.DialogFooter, { children: [(0, jsx_runtime_1.jsx)(ui_1.Button, { variant: "secondary", onPress: handleCancel, disabled: isSubmitting, children: (0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Cancel" }) }), (0, jsx_runtime_1.jsx)(ui_1.Button, { variant: "primary", onPress: handleSubmit, disabled: !selectedReason || isSubmitting, children: isSubmitting ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(lucide_react_native_1.Loader2, { style: [{ marginRight: 8 }] }), (0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Submitting..." })] })) : ((0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Submit" })) })] })] }));
88
+ ], children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { children: selectedReason === reason.value ? ((0, jsx_runtime_1.jsx)(lucide_react_native_1.CheckCircle, { color: theme.colors.foreground })) : ((0, jsx_runtime_1.jsx)(lucide_react_native_1.Circle, { color: theme.colors.foreground })) }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [__1.zero.layout.flex.column, __1.zero.gap.all[1], __1.zero.flex[1]], children: [(0, jsx_runtime_1.jsx)(ui_1.Text, { style: [{ fontWeight: "600" }], children: reason.label }), (0, jsx_runtime_1.jsx)(ui_1.Text, { style: [{ fontSize: 14, color: "rgba(255,255,255,0.7)" }], children: reason.description })] })] }, reason.value))), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [__1.zero.pb[4], __1.zero.mt[4], __1.zero.px[2]], children: [(0, jsx_runtime_1.jsx)(ui_1.Text, { style: [__1.zero.mb[2]], children: "Additional Comments (optional)" }), (0, jsx_runtime_1.jsx)(ui_1.Textarea, { maxLength: 500, numberOfLines: 3, value: additionalComments, onChangeText: setAdditionalComments, placeholder: "Provide additional context for this report..." }), submitError && ((0, jsx_runtime_1.jsx)(ui_1.Text, { style: [__1.zero.mt[2], { color: "red", fontSize: 14 }], children: submitError }))] })] }), (0, jsx_runtime_1.jsxs)(ui_1.DialogFooter, { children: [(0, jsx_runtime_1.jsx)(ui_1.Button, { variant: "secondary", onPress: handleCancel, disabled: isSubmitting, children: (0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Cancel" }) }), (0, jsx_runtime_1.jsx)(ui_1.Button, { variant: "primary", onPress: handleSubmit, disabled: !selectedReason || isSubmitting, children: isSubmitting ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(lucide_react_native_1.Loader2, { style: [{ marginRight: 8 }] }), (0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Submitting..." })] })) : ((0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Submit" })) })] })] }));
88
89
  };
89
90
  exports.ReportModal = ReportModal;
90
91
  exports.default = exports.ReportModal;