@streamplace/components 0.7.35 → 0.8.3
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 +467 -0
- package/dist/components/content-metadata/content-rights.js +78 -0
- package/dist/components/content-metadata/content-warnings.js +68 -0
- package/dist/components/content-metadata/index.js +11 -0
- package/dist/components/mobile-player/player.js +4 -0
- package/dist/components/mobile-player/ui/report-modal.js +3 -2
- package/dist/components/ui/checkbox.js +87 -0
- package/dist/components/ui/dialog.js +188 -83
- package/dist/components/ui/primitives/input.js +13 -1
- package/dist/components/ui/primitives/modal.js +2 -2
- package/dist/components/ui/select.js +89 -0
- package/dist/components/ui/textarea.js +23 -4
- package/dist/components/ui/toast.js +464 -114
- package/dist/components/ui/tooltip.js +103 -0
- package/dist/index.js +2 -0
- package/dist/lib/metadata-constants.js +157 -0
- package/dist/lib/theme/theme.js +5 -3
- package/dist/streamplace-provider/index.js +14 -4
- package/dist/streamplace-store/content-metadata-actions.js +124 -0
- package/dist/streamplace-store/streamplace-store.js +22 -5
- package/dist/streamplace-store/user.js +67 -7
- package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
- package/package.json +3 -3
- package/src/components/content-metadata/content-metadata-form.tsx +893 -0
- package/src/components/content-metadata/content-rights.tsx +104 -0
- package/src/components/content-metadata/content-warnings.tsx +100 -0
- package/src/components/content-metadata/index.tsx +10 -0
- package/src/components/mobile-player/player.tsx +5 -0
- package/src/components/mobile-player/ui/report-modal.tsx +13 -7
- package/src/components/ui/checkbox.tsx +147 -0
- package/src/components/ui/dialog.tsx +319 -99
- package/src/components/ui/primitives/input.tsx +19 -2
- package/src/components/ui/primitives/modal.tsx +4 -2
- package/src/components/ui/select.tsx +175 -0
- package/src/components/ui/textarea.tsx +47 -29
- package/src/components/ui/toast.tsx +785 -179
- package/src/components/ui/tooltip.tsx +131 -0
- package/src/index.tsx +3 -0
- package/src/lib/metadata-constants.ts +180 -0
- package/src/lib/theme/theme.tsx +10 -6
- package/src/streamplace-provider/index.tsx +20 -2
- package/src/streamplace-store/content-metadata-actions.tsx +145 -0
- package/src/streamplace-store/streamplace-store.tsx +41 -4
- package/src/streamplace-store/user.tsx +71 -7
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Tooltip = 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 theme_1 = require("../../lib/theme/theme");
|
|
8
|
+
const text_1 = require("../ui/text");
|
|
9
|
+
exports.Tooltip = (0, react_1.forwardRef)(({ content, children, position = "top", style }, ref) => {
|
|
10
|
+
const { theme } = (0, theme_1.useTheme)();
|
|
11
|
+
const [isVisible, setIsVisible] = (0, react_1.useState)(false);
|
|
12
|
+
const styles = createStyles(theme, position);
|
|
13
|
+
const handleHoverIn = () => {
|
|
14
|
+
setIsVisible(true);
|
|
15
|
+
};
|
|
16
|
+
const handleHoverOut = () => {
|
|
17
|
+
setIsVisible(false);
|
|
18
|
+
};
|
|
19
|
+
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { ref: ref, style: [styles.container, style], onPointerEnter: handleHoverIn, onPointerLeave: handleHoverOut, children: [children, isVisible && ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.tooltip, children: (0, jsx_runtime_1.jsx)(text_1.Text, { style: styles.tooltipText, children: content }) }))] }));
|
|
20
|
+
});
|
|
21
|
+
exports.Tooltip.displayName = "Tooltip";
|
|
22
|
+
function createStyles(theme, position) {
|
|
23
|
+
const positionStyles = {
|
|
24
|
+
top: {
|
|
25
|
+
tooltip: {
|
|
26
|
+
bottom: "100%",
|
|
27
|
+
left: "50%",
|
|
28
|
+
transform: [{ translateX: -50 }],
|
|
29
|
+
marginBottom: theme.spacing[1],
|
|
30
|
+
},
|
|
31
|
+
arrow: {
|
|
32
|
+
top: "100%",
|
|
33
|
+
left: "50%",
|
|
34
|
+
transform: [{ translateX: -50 }],
|
|
35
|
+
borderTopColor: theme.colors.card,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
bottom: {
|
|
39
|
+
tooltip: {
|
|
40
|
+
top: "100%",
|
|
41
|
+
left: "50%",
|
|
42
|
+
transform: [{ translateX: -50 }],
|
|
43
|
+
marginTop: theme.spacing[1],
|
|
44
|
+
},
|
|
45
|
+
arrow: {
|
|
46
|
+
bottom: "100%",
|
|
47
|
+
left: "50%",
|
|
48
|
+
transform: [{ translateX: -50 }],
|
|
49
|
+
borderBottomColor: theme.colors.card,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
left: {
|
|
53
|
+
tooltip: {
|
|
54
|
+
right: "100%",
|
|
55
|
+
top: "50%",
|
|
56
|
+
transform: [{ translateY: -50 }],
|
|
57
|
+
marginRight: theme.spacing[1],
|
|
58
|
+
},
|
|
59
|
+
arrow: {
|
|
60
|
+
left: "100%",
|
|
61
|
+
top: "50%",
|
|
62
|
+
transform: [{ translateY: -50 }],
|
|
63
|
+
borderLeftColor: theme.colors.card,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
right: {
|
|
67
|
+
tooltip: {
|
|
68
|
+
left: "100%",
|
|
69
|
+
top: "50%",
|
|
70
|
+
transform: [{ translateY: -50 }],
|
|
71
|
+
marginLeft: theme.spacing[1],
|
|
72
|
+
},
|
|
73
|
+
arrow: {
|
|
74
|
+
right: "100%",
|
|
75
|
+
top: "50%",
|
|
76
|
+
transform: [{ translateY: -50 }],
|
|
77
|
+
borderRightColor: theme.colors.card,
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
const currentPosition = positionStyles[position];
|
|
82
|
+
return react_native_1.StyleSheet.create({
|
|
83
|
+
container: {
|
|
84
|
+
position: "relative",
|
|
85
|
+
},
|
|
86
|
+
tooltip: {
|
|
87
|
+
position: "absolute",
|
|
88
|
+
backgroundColor: theme.colors.card,
|
|
89
|
+
borderRadius: theme.borderRadius.md,
|
|
90
|
+
padding: theme.spacing[2],
|
|
91
|
+
maxWidth: 200,
|
|
92
|
+
...theme.shadows.lg,
|
|
93
|
+
...currentPosition.tooltip,
|
|
94
|
+
zIndex: 1000,
|
|
95
|
+
},
|
|
96
|
+
tooltipText: {
|
|
97
|
+
color: theme.colors.text,
|
|
98
|
+
fontSize: 12,
|
|
99
|
+
lineHeight: 16,
|
|
100
|
+
textAlign: "left",
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -36,3 +36,5 @@ exports.Dashboard = tslib_1.__importStar(require("./components/dashboard"));
|
|
|
36
36
|
// Storage exports
|
|
37
37
|
var storage_1 = require("./storage");
|
|
38
38
|
Object.defineProperty(exports, "storage", { enumerable: true, get: function () { return tslib_1.__importDefault(storage_1).default; } });
|
|
39
|
+
// Content metadata components
|
|
40
|
+
tslib_1.__exportStar(require("./components/content-metadata"), exports);
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.C2PA_WARNING_LABELS = exports.LICENSE_URL_LABELS = exports.LICENSE_OPTIONS = exports.CONTENT_WARNINGS = void 0;
|
|
4
|
+
const streamplace_1 = require("streamplace");
|
|
5
|
+
// Content warnings derived from lexicon schema
|
|
6
|
+
exports.CONTENT_WARNINGS = (() => {
|
|
7
|
+
// Find the content warnings schema
|
|
8
|
+
const contentWarningsSchema = streamplace_1.schemas.find((schema) => schema.id === "place.stream.metadata.contentWarnings");
|
|
9
|
+
if (!contentWarningsSchema?.defs) {
|
|
10
|
+
throw new Error("Could not find place.stream.metadata.contentWarnings schema");
|
|
11
|
+
}
|
|
12
|
+
const contentWarningConstants = [
|
|
13
|
+
{ constant: "place.stream.metadata.contentWarnings#death", label: "Death" },
|
|
14
|
+
{
|
|
15
|
+
constant: "place.stream.metadata.contentWarnings#drugUse",
|
|
16
|
+
label: "Drug Use",
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
constant: "place.stream.metadata.contentWarnings#fantasyViolence",
|
|
20
|
+
label: "Fantasy Violence",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
constant: "place.stream.metadata.contentWarnings#flashingLights",
|
|
24
|
+
label: "Flashing Lights",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
constant: "place.stream.metadata.contentWarnings#language",
|
|
28
|
+
label: "Language",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
constant: "place.stream.metadata.contentWarnings#nudity",
|
|
32
|
+
label: "Nudity",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
constant: "place.stream.metadata.contentWarnings#PII",
|
|
36
|
+
label: "Personally Identifiable Information",
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
constant: "place.stream.metadata.contentWarnings#sexuality",
|
|
40
|
+
label: "Sexuality",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
constant: "place.stream.metadata.contentWarnings#suffering",
|
|
44
|
+
label: "Upsetting or Disturbing",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
constant: "place.stream.metadata.contentWarnings#violence",
|
|
48
|
+
label: "Violence",
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
return contentWarningConstants.map(({ constant, label }) => {
|
|
52
|
+
// Extract the key from the constant by splitting on '#'
|
|
53
|
+
const key = constant.split("#")[1];
|
|
54
|
+
const def = contentWarningsSchema.defs[key];
|
|
55
|
+
const description = def?.description || `Description for ${label}`;
|
|
56
|
+
return {
|
|
57
|
+
value: constant,
|
|
58
|
+
label: label,
|
|
59
|
+
description: description,
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
})();
|
|
63
|
+
// License options derived from lexicon schema
|
|
64
|
+
exports.LICENSE_OPTIONS = (() => {
|
|
65
|
+
// Find the content rights schema
|
|
66
|
+
const contentRightsSchema = streamplace_1.schemas.find((schema) => schema.id === "place.stream.metadata.contentRights");
|
|
67
|
+
if (!contentRightsSchema?.defs) {
|
|
68
|
+
throw new Error("Could not find place.stream.metadata.contentRights schema");
|
|
69
|
+
}
|
|
70
|
+
const licenseConstants = [
|
|
71
|
+
{
|
|
72
|
+
constant: "place.stream.metadata.contentRights#all-rights-reserved",
|
|
73
|
+
label: "All Rights Reserved",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
constant: "place.stream.metadata.contentRights#cc0_1__0",
|
|
77
|
+
label: "CC0 (Public Domain) 1.0",
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
constant: "place.stream.metadata.contentRights#cc-by_4__0",
|
|
81
|
+
label: "CC BY 4.0",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
constant: "place.stream.metadata.contentRights#cc-by-sa_4__0",
|
|
85
|
+
label: "CC BY-SA 4.0",
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
constant: "place.stream.metadata.contentRights#cc-by-nc_4__0",
|
|
89
|
+
label: "CC BY-NC 4.0",
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
constant: "place.stream.metadata.contentRights#cc-by-nc-sa_4__0",
|
|
93
|
+
label: "CC BY-NC-SA 4.0",
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
constant: "place.stream.metadata.contentRights#cc-by-nd_4__0",
|
|
97
|
+
label: "CC BY-ND 4.0",
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
constant: "place.stream.metadata.contentRights#cc-by-nc-nd_4__0",
|
|
101
|
+
label: "CC BY-NC-ND 4.0",
|
|
102
|
+
},
|
|
103
|
+
];
|
|
104
|
+
const options = licenseConstants.map(({ constant, label }) => {
|
|
105
|
+
// Extract the key from the constant by splitting on '#'
|
|
106
|
+
const key = constant.split("#")[1];
|
|
107
|
+
const def = contentRightsSchema.defs[key];
|
|
108
|
+
const description = def?.description || `Description for ${label}`;
|
|
109
|
+
return {
|
|
110
|
+
value: constant,
|
|
111
|
+
label: label,
|
|
112
|
+
description: description,
|
|
113
|
+
};
|
|
114
|
+
});
|
|
115
|
+
// Add custom license option
|
|
116
|
+
options.push({
|
|
117
|
+
value: "custom",
|
|
118
|
+
label: "Custom License",
|
|
119
|
+
description: "Custom license. Define your own terms for how others can use, adapt, or share your content.",
|
|
120
|
+
});
|
|
121
|
+
return options;
|
|
122
|
+
})();
|
|
123
|
+
// License URL labels for C2PA manifests
|
|
124
|
+
exports.LICENSE_URL_LABELS = {
|
|
125
|
+
"http://creativecommons.org/publicdomain/zero/1.0/": "CC0 - Public Domain 1.0",
|
|
126
|
+
"http://creativecommons.org/licenses/by/4.0/": "CC BY - Attribution 4.0",
|
|
127
|
+
"http://creativecommons.org/licenses/by-sa/4.0/": "CC BY-SA - Attribution ShareAlike 4.0",
|
|
128
|
+
"http://creativecommons.org/licenses/by-nc/4.0/": "CC BY-NC - Attribution NonCommercial 4.0",
|
|
129
|
+
"http://creativecommons.org/licenses/by-nc-sa/4.0/": "CC BY-NC-SA - Attribution NonCommercial ShareAlike 4.0",
|
|
130
|
+
"http://creativecommons.org/licenses/by-nd/4.0/": "CC BY-ND - Attribution NoDerivatives 4.0",
|
|
131
|
+
"http://creativecommons.org/licenses/by-nc-nd/4.0/": "CC BY-NC-ND - Attribution NonCommercial NoDerivatives 4.0",
|
|
132
|
+
"All rights reserved": "All Rights Reserved",
|
|
133
|
+
};
|
|
134
|
+
// C2PA warning labels for content warnings
|
|
135
|
+
exports.C2PA_WARNING_LABELS = {
|
|
136
|
+
"cwarn:death": "Death",
|
|
137
|
+
"cwarn:drugUse": "Drug Use",
|
|
138
|
+
"cwarn:fantasyViolence": "Fantasy Violence",
|
|
139
|
+
"cwarn:flashingLights": "Flashing Lights",
|
|
140
|
+
"cwarn:language": "Language",
|
|
141
|
+
"cwarn:nudity": "Nudity",
|
|
142
|
+
"cwarn:PII": "Personally Identifiable Information",
|
|
143
|
+
"cwarn:sexuality": "Sexuality",
|
|
144
|
+
"cwarn:suffering": "Upsetting or Disturbing",
|
|
145
|
+
"cwarn:violence": "Violence",
|
|
146
|
+
// Also support lexicon constants for backward compatibility
|
|
147
|
+
"place.stream.metadata.contentWarnings#death": "Death",
|
|
148
|
+
"place.stream.metadata.contentWarnings#drugUse": "Drug Use",
|
|
149
|
+
"place.stream.metadata.contentWarnings#fantasyViolence": "Fantasy Violence",
|
|
150
|
+
"place.stream.metadata.contentWarnings#flashingLights": "Flashing Lights",
|
|
151
|
+
"place.stream.metadata.contentWarnings#language": "Language",
|
|
152
|
+
"place.stream.metadata.contentWarnings#nudity": "Nudity",
|
|
153
|
+
"place.stream.metadata.contentWarnings#PII": "Personally Identifiable Information",
|
|
154
|
+
"place.stream.metadata.contentWarnings#sexuality": "Sexuality",
|
|
155
|
+
"place.stream.metadata.contentWarnings#suffering": "Upsetting or Disturbing",
|
|
156
|
+
"place.stream.metadata.contentWarnings#violence": "Violence",
|
|
157
|
+
};
|
package/dist/lib/theme/theme.js
CHANGED
|
@@ -166,12 +166,14 @@ function generateThemeColorsFromPalette(palette, isDark) {
|
|
|
166
166
|
mutedForeground: isDark ? palette[400] : palette[500],
|
|
167
167
|
accent: isDark ? palette[800] : palette[100],
|
|
168
168
|
accentForeground: isDark ? palette[50] : palette[900],
|
|
169
|
-
destructive:
|
|
169
|
+
destructive: tokens_1.colors.destructive[700],
|
|
170
170
|
destructiveForeground: tokens_1.colors.white,
|
|
171
|
-
success:
|
|
171
|
+
success: tokens_1.colors.success[700],
|
|
172
172
|
successForeground: tokens_1.colors.white,
|
|
173
|
-
warning:
|
|
173
|
+
warning: tokens_1.colors.warning[700],
|
|
174
174
|
warningForeground: tokens_1.colors.white,
|
|
175
|
+
info: tokens_1.colors.blue[700],
|
|
176
|
+
infoForeground: isDark ? palette[50] : palette[900],
|
|
175
177
|
border: isDark ? palette[500] + "30" : palette[200] + "30",
|
|
176
178
|
input: isDark ? palette[800] : palette[200],
|
|
177
179
|
ring: react_native_1.Platform.OS === "ios" ? tokens_1.colors.ios.systemBlue : tokens_1.colors.primary[500],
|
|
@@ -1,21 +1,31 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.StreamplaceProvider = StreamplaceProvider;
|
|
4
|
+
exports.ChatProfileCreator = ChatProfileCreator;
|
|
4
5
|
const tslib_1 = require("tslib");
|
|
5
6
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
7
|
const react_1 = require("react");
|
|
7
|
-
const streamplace_store_1 = require("../streamplace-store
|
|
8
|
+
const streamplace_store_1 = require("../streamplace-store");
|
|
9
|
+
const streamplace_store_2 = require("../streamplace-store/streamplace-store");
|
|
8
10
|
const context_1 = require("./context");
|
|
9
11
|
const poller_1 = tslib_1.__importDefault(require("./poller"));
|
|
10
12
|
function StreamplaceProvider({ children, url, oauthSession, }) {
|
|
11
|
-
console.log("session in provider is", oauthSession);
|
|
12
13
|
// todo: handle url changes?
|
|
13
|
-
const store = (0, react_1.useRef)((0,
|
|
14
|
+
const store = (0, react_1.useRef)((0, streamplace_store_2.makeStreamplaceStore)({ url })).current;
|
|
14
15
|
(0, react_1.useEffect)(() => {
|
|
15
16
|
store.setState({ url });
|
|
16
17
|
}, [url]);
|
|
17
18
|
(0, react_1.useEffect)(() => {
|
|
18
19
|
store.setState({ oauthSession });
|
|
19
20
|
}, [oauthSession]);
|
|
20
|
-
return ((0, jsx_runtime_1.jsx)(context_1.StreamplaceContext.Provider, { value: { store: store }, children: (0, jsx_runtime_1.jsx)(poller_1.default, { children: children }) }));
|
|
21
|
+
return ((0, jsx_runtime_1.jsx)(context_1.StreamplaceContext.Provider, { value: { store: store }, children: (0, jsx_runtime_1.jsx)(ChatProfileCreator, { oauthSession: oauthSession, children: (0, jsx_runtime_1.jsx)(poller_1.default, { children: children }) }) }));
|
|
22
|
+
}
|
|
23
|
+
function ChatProfileCreator({ oauthSession, children, }) {
|
|
24
|
+
const getChatProfile = (0, streamplace_store_1.useGetChatProfile)();
|
|
25
|
+
(0, react_1.useEffect)(() => {
|
|
26
|
+
if (oauthSession) {
|
|
27
|
+
getChatProfile();
|
|
28
|
+
}
|
|
29
|
+
}, [oauthSession]);
|
|
30
|
+
return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: children });
|
|
21
31
|
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useGetContentMetadata = exports.useSaveContentMetadata = exports.useGetBroadcasterDID = void 0;
|
|
4
|
+
const streamplace_store_1 = require("./streamplace-store");
|
|
5
|
+
const xrpc_1 = require("./xrpc");
|
|
6
|
+
const useGetBroadcasterDID = () => {
|
|
7
|
+
const pdsAgent = (0, xrpc_1.usePDSAgent)();
|
|
8
|
+
const did = (0, streamplace_store_1.useDID)();
|
|
9
|
+
const setBroadcasterDID = (0, streamplace_store_1.useStreamplaceStore)((state) => state.setBroadcasterDID);
|
|
10
|
+
const setServerDID = (0, streamplace_store_1.useStreamplaceStore)((state) => state.setServerDID);
|
|
11
|
+
return async () => {
|
|
12
|
+
if (!pdsAgent || !did) {
|
|
13
|
+
throw new Error("No PDS agent or DID available");
|
|
14
|
+
}
|
|
15
|
+
const result = await pdsAgent.place.stream.broadcast.getBroadcaster();
|
|
16
|
+
if (!result.success) {
|
|
17
|
+
throw new Error("Failed to get broadcaster DID");
|
|
18
|
+
}
|
|
19
|
+
setBroadcasterDID(result.data.broadcaster);
|
|
20
|
+
if (result.data.server) {
|
|
21
|
+
setServerDID(result.data.server);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
setServerDID(null);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
exports.useGetBroadcasterDID = useGetBroadcasterDID;
|
|
29
|
+
const useSaveContentMetadata = () => {
|
|
30
|
+
const pdsAgent = (0, xrpc_1.usePDSAgent)();
|
|
31
|
+
const did = (0, streamplace_store_1.useDID)();
|
|
32
|
+
const setContentMetadata = (0, streamplace_store_1.useSetContentMetadata)();
|
|
33
|
+
return async (metadataRecord) => {
|
|
34
|
+
if (!pdsAgent || !did) {
|
|
35
|
+
throw new Error("No PDS agent or DID available");
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
// Try to update existing record first
|
|
39
|
+
const result = await pdsAgent.com.atproto.repo.putRecord({
|
|
40
|
+
repo: did,
|
|
41
|
+
collection: "place.stream.metadata.configuration",
|
|
42
|
+
rkey: "self",
|
|
43
|
+
record: metadataRecord,
|
|
44
|
+
});
|
|
45
|
+
const contentMetadata = {
|
|
46
|
+
record: metadataRecord,
|
|
47
|
+
uri: result.data.uri,
|
|
48
|
+
cid: result.data.cid || "",
|
|
49
|
+
rkey: "self",
|
|
50
|
+
};
|
|
51
|
+
setContentMetadata(contentMetadata);
|
|
52
|
+
return contentMetadata;
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
// If record doesn't exist, create it
|
|
56
|
+
if (error instanceof Error &&
|
|
57
|
+
(error.message?.includes("not found") ||
|
|
58
|
+
error.message?.includes("RecordNotFound") ||
|
|
59
|
+
error.message?.includes("mst: not found") ||
|
|
60
|
+
error?.status === 404)) {
|
|
61
|
+
const createResult = await pdsAgent.com.atproto.repo.createRecord({
|
|
62
|
+
repo: did,
|
|
63
|
+
collection: "place.stream.metadata.configuration",
|
|
64
|
+
rkey: "self",
|
|
65
|
+
record: metadataRecord,
|
|
66
|
+
});
|
|
67
|
+
const contentMetadata = {
|
|
68
|
+
record: metadataRecord,
|
|
69
|
+
uri: createResult.data.uri,
|
|
70
|
+
cid: createResult.data.cid || "",
|
|
71
|
+
rkey: "self",
|
|
72
|
+
};
|
|
73
|
+
setContentMetadata(contentMetadata);
|
|
74
|
+
return contentMetadata;
|
|
75
|
+
}
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
exports.useSaveContentMetadata = useSaveContentMetadata;
|
|
81
|
+
// Simple get function
|
|
82
|
+
const useGetContentMetadata = () => {
|
|
83
|
+
const pdsAgent = (0, xrpc_1.usePDSAgent)();
|
|
84
|
+
const did = (0, streamplace_store_1.useDID)();
|
|
85
|
+
const setContentMetadata = (0, streamplace_store_1.useSetContentMetadata)();
|
|
86
|
+
return async (params) => {
|
|
87
|
+
if (!pdsAgent) {
|
|
88
|
+
throw new Error("No PDS agent available");
|
|
89
|
+
}
|
|
90
|
+
const targetDid = params?.userDid || did;
|
|
91
|
+
if (!targetDid) {
|
|
92
|
+
throw new Error("No DID provided or user not authenticated");
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
const result = await pdsAgent.com.atproto.repo.getRecord({
|
|
96
|
+
repo: targetDid,
|
|
97
|
+
collection: "place.stream.metadata.configuration",
|
|
98
|
+
rkey: params?.rkey || "self",
|
|
99
|
+
});
|
|
100
|
+
if (!result.success) {
|
|
101
|
+
throw new Error("Failed to get content metadata record");
|
|
102
|
+
}
|
|
103
|
+
const contentMetadata = {
|
|
104
|
+
record: result.data.value,
|
|
105
|
+
uri: result.data.uri,
|
|
106
|
+
cid: result.data.cid || "",
|
|
107
|
+
};
|
|
108
|
+
setContentMetadata(contentMetadata);
|
|
109
|
+
return contentMetadata;
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
// Handle record not found - this is normal for new users
|
|
113
|
+
if (error instanceof Error &&
|
|
114
|
+
(error.message?.includes("not found") ||
|
|
115
|
+
error.message?.includes("RecordNotFound") ||
|
|
116
|
+
error.message?.includes("mst: not found") ||
|
|
117
|
+
error?.status === 404)) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
exports.useGetContentMetadata = useGetContentMetadata;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.useEffectiveVolume = exports.useSetMuted = exports.useSetVolume = exports.useMuted = exports.useVolume = exports.useSetHandle = exports.useHandle = exports.useDID = exports.useUrl = exports.makeStreamplaceStore = void 0;
|
|
3
|
+
exports.useUpdateStreamRecord = exports.useCreateStreamRecord = exports.useEffectiveVolume = exports.useSetMuted = exports.useSetVolume = exports.useMuted = exports.useVolume = exports.useSetContentMetadata = exports.useContentMetadata = exports.useSetHandle = exports.useHandle = exports.useDID = exports.useUrl = exports.makeStreamplaceStore = void 0;
|
|
4
4
|
exports.getStreamplaceStoreFromContext = getStreamplaceStoreFromContext;
|
|
5
5
|
exports.useStreamplaceStore = useStreamplaceStore;
|
|
6
6
|
const tslib_1 = require("tslib");
|
|
@@ -25,6 +25,13 @@ const makeStreamplaceStore = ({ url, }) => {
|
|
|
25
25
|
oauthSession: null,
|
|
26
26
|
handle: null,
|
|
27
27
|
chatProfile: null,
|
|
28
|
+
broadcasterDID: null,
|
|
29
|
+
setBroadcasterDID: (broadcasterDID) => set({ broadcasterDID }),
|
|
30
|
+
serverDID: null,
|
|
31
|
+
setServerDID: (serverDID) => set({ serverDID }),
|
|
32
|
+
// Content metadata
|
|
33
|
+
contentMetadata: null,
|
|
34
|
+
setContentMetadata: (metadata) => set({ contentMetadata: metadata }),
|
|
28
35
|
// Volume state - start with defaults
|
|
29
36
|
volume: 1.0,
|
|
30
37
|
muted: false,
|
|
@@ -68,14 +75,13 @@ const makeStreamplaceStore = ({ url, }) => {
|
|
|
68
75
|
if (storedMuted) {
|
|
69
76
|
initialMuted = storedMuted === "true";
|
|
70
77
|
}
|
|
71
|
-
// Update the store with loaded values
|
|
72
78
|
store.setState({
|
|
73
79
|
volume: initialVolume,
|
|
74
80
|
muted: initialMuted,
|
|
75
81
|
});
|
|
76
82
|
}
|
|
77
|
-
catch (
|
|
78
|
-
console.
|
|
83
|
+
catch (error) {
|
|
84
|
+
console.error("Failed to load volume state from storage:", error);
|
|
79
85
|
}
|
|
80
86
|
})();
|
|
81
87
|
return store;
|
|
@@ -102,7 +108,15 @@ const useSetHandle = () => {
|
|
|
102
108
|
return (handle) => store.setState({ handle });
|
|
103
109
|
};
|
|
104
110
|
exports.useSetHandle = useSetHandle;
|
|
105
|
-
//
|
|
111
|
+
// Content metadata hooks
|
|
112
|
+
const useContentMetadata = () => useStreamplaceStore((x) => x.contentMetadata);
|
|
113
|
+
exports.useContentMetadata = useContentMetadata;
|
|
114
|
+
const useSetContentMetadata = () => {
|
|
115
|
+
const store = getStreamplaceStoreFromContext();
|
|
116
|
+
return (metadata) => store.setState({ contentMetadata: metadata });
|
|
117
|
+
};
|
|
118
|
+
exports.useSetContentMetadata = useSetContentMetadata;
|
|
119
|
+
// Volume/muted hooks
|
|
106
120
|
const useVolume = () => useStreamplaceStore((x) => x.volume);
|
|
107
121
|
exports.useVolume = useVolume;
|
|
108
122
|
const useMuted = () => useStreamplaceStore((x) => x.muted);
|
|
@@ -118,3 +132,6 @@ const useEffectiveVolume = () => useStreamplaceStore((state) => {
|
|
|
118
132
|
return Number.isFinite(effectiveVolume) ? effectiveVolume : 1.0;
|
|
119
133
|
});
|
|
120
134
|
exports.useEffectiveVolume = useEffectiveVolume;
|
|
135
|
+
var stream_1 = require("./stream");
|
|
136
|
+
Object.defineProperty(exports, "useCreateStreamRecord", { enumerable: true, get: function () { return stream_1.useCreateStreamRecord; } });
|
|
137
|
+
Object.defineProperty(exports, "useUpdateStreamRecord", { enumerable: true, get: function () { return stream_1.useUpdateStreamRecord; } });
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.useGetChatProfile = useGetChatProfile;
|
|
4
|
+
exports.useCreateEmptyChatProfile = useCreateEmptyChatProfile;
|
|
4
5
|
exports.useGetBskyProfile = useGetBskyProfile;
|
|
5
6
|
exports.useChatProfile = useChatProfile;
|
|
6
7
|
const streamplace_1 = require("streamplace");
|
|
@@ -10,17 +11,34 @@ function useGetChatProfile() {
|
|
|
10
11
|
const did = (0, streamplace_store_1.useDID)();
|
|
11
12
|
const pdsAgent = (0, xrpc_1.usePDSAgent)();
|
|
12
13
|
const store = (0, streamplace_store_1.getStreamplaceStoreFromContext)();
|
|
14
|
+
const createEmptyChatProfile = useCreateEmptyChatProfile();
|
|
13
15
|
return async () => {
|
|
14
16
|
if (!did || !pdsAgent) {
|
|
15
17
|
throw new Error("No DID or PDS agent");
|
|
16
18
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
let res;
|
|
20
|
+
try {
|
|
21
|
+
res = await pdsAgent.com.atproto.repo.getRecord({
|
|
22
|
+
repo: did,
|
|
23
|
+
collection: "place.stream.chat.profile",
|
|
24
|
+
rkey: "self",
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
console.error("Failed to get chat profile record, attempting creation", e);
|
|
29
|
+
}
|
|
30
|
+
if (!res || !res.success) {
|
|
31
|
+
try {
|
|
32
|
+
await createEmptyChatProfile();
|
|
33
|
+
res = await pdsAgent.com.atproto.repo.getRecord({
|
|
34
|
+
repo: did,
|
|
35
|
+
collection: "place.stream.chat.profile",
|
|
36
|
+
rkey: "self",
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
console.error("Failed to create empty chat profile record", e);
|
|
41
|
+
}
|
|
24
42
|
}
|
|
25
43
|
if (streamplace_1.PlaceStreamChatProfile.isRecord(res.data.value)) {
|
|
26
44
|
store.setState({ chatProfile: res.data.value });
|
|
@@ -30,6 +48,27 @@ function useGetChatProfile() {
|
|
|
30
48
|
}
|
|
31
49
|
};
|
|
32
50
|
}
|
|
51
|
+
function useCreateEmptyChatProfile() {
|
|
52
|
+
const did = (0, streamplace_store_1.useDID)();
|
|
53
|
+
const pdsAgent = (0, xrpc_1.usePDSAgent)();
|
|
54
|
+
return async () => {
|
|
55
|
+
if (!did || !pdsAgent) {
|
|
56
|
+
throw new Error("No DID or PDS agent");
|
|
57
|
+
}
|
|
58
|
+
const res = await pdsAgent.com.atproto.repo.putRecord({
|
|
59
|
+
repo: did,
|
|
60
|
+
collection: "place.stream.chat.profile",
|
|
61
|
+
rkey: "self",
|
|
62
|
+
record: {
|
|
63
|
+
$type: "place.stream.chat.profile",
|
|
64
|
+
color: DEFAULT_COLORS[Math.floor(Math.random() * DEFAULT_COLORS.length)],
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
if (!res.success) {
|
|
68
|
+
throw new Error("Failed to create empty chat profile record");
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
33
72
|
function useGetBskyProfile() {
|
|
34
73
|
const did = (0, streamplace_store_1.useDID)();
|
|
35
74
|
const pdsAgent = (0, xrpc_1.usePDSAgent)();
|
|
@@ -50,3 +89,24 @@ function useGetBskyProfile() {
|
|
|
50
89
|
function useChatProfile() {
|
|
51
90
|
return (0, streamplace_store_1.useStreamplaceStore)((x) => x.chatProfile);
|
|
52
91
|
}
|
|
92
|
+
const DEFAULT_COLORS = [
|
|
93
|
+
{ red: 244, green: 67, blue: 54 },
|
|
94
|
+
{ red: 233, green: 30, blue: 99 },
|
|
95
|
+
{ red: 156, green: 39, blue: 176 },
|
|
96
|
+
{ red: 103, green: 58, blue: 183 },
|
|
97
|
+
{ red: 63, green: 81, blue: 181 },
|
|
98
|
+
{ red: 33, green: 150, blue: 243 },
|
|
99
|
+
{ red: 3, green: 169, blue: 244 },
|
|
100
|
+
{ red: 0, green: 188, blue: 212 },
|
|
101
|
+
{ red: 0, green: 150, blue: 136 },
|
|
102
|
+
{ red: 76, green: 175, blue: 80 },
|
|
103
|
+
{ red: 139, green: 195, blue: 74 },
|
|
104
|
+
{ red: 205, green: 220, blue: 57 },
|
|
105
|
+
{ red: 255, green: 235, blue: 59 },
|
|
106
|
+
{ red: 255, green: 193, blue: 7 },
|
|
107
|
+
{ red: 255, green: 152, blue: 0 },
|
|
108
|
+
{ red: 255, green: 87, blue: 34 },
|
|
109
|
+
{ red: 121, green: 85, blue: 72 },
|
|
110
|
+
{ red: 158, green: 158, blue: 158 },
|
|
111
|
+
{ red: 96, green: 125, blue: 139 },
|
|
112
|
+
];
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@streamplace/components",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "Streamplace React (Native) Components",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "src/index.tsx",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"react-native-svg": "^15.0.0",
|
|
43
43
|
"react-native-webrtc": "git+https://github.com/streamplace/react-native-webrtc.git#6b8472a771ac47f89217d327058a8a4124a6ae56",
|
|
44
44
|
"react-use-websocket": "^4.13.0",
|
|
45
|
-
"streamplace": "0.
|
|
45
|
+
"streamplace": "0.8.0",
|
|
46
46
|
"viem": "^2.21.44",
|
|
47
47
|
"zustand": "^5.0.5"
|
|
48
48
|
},
|
|
@@ -54,5 +54,5 @@
|
|
|
54
54
|
"start": "tsc --watch --preserveWatchOutput",
|
|
55
55
|
"prepare": "tsc"
|
|
56
56
|
},
|
|
57
|
-
"gitHead": "
|
|
57
|
+
"gitHead": "e902ae92cbbb11832ca64b8c0e87e7ce5507c301"
|
|
58
58
|
}
|