@streamplace/components 0.9.4 → 0.9.6
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/chat/mod-view.d.ts.map +1 -1
- package/dist/components/chat/mod-view.js +7 -79
- package/dist/components/chat/mod-view.js.map +1 -1
- package/dist/components/chat/update-stream-title-dialog.d.ts +9 -0
- package/dist/components/chat/update-stream-title-dialog.d.ts.map +1 -0
- package/dist/components/chat/update-stream-title-dialog.js +74 -0
- package/dist/components/chat/update-stream-title-dialog.js.map +1 -0
- package/dist/components/content-metadata/content-metadata-form.d.ts.map +1 -1
- package/dist/components/content-metadata/content-metadata-form.js +7 -8
- package/dist/components/content-metadata/content-metadata-form.js.map +1 -1
- package/dist/components/ui/admonition.d.ts +14 -0
- package/dist/components/ui/admonition.d.ts.map +1 -0
- package/dist/components/ui/admonition.js +117 -0
- package/dist/components/ui/admonition.js.map +1 -0
- package/dist/components/ui/button.d.ts +1 -0
- package/dist/components/ui/button.d.ts.map +1 -1
- package/dist/components/ui/button.js +2 -2
- package/dist/components/ui/button.js.map +1 -1
- package/dist/components/ui/index.d.ts +1 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +1 -0
- package/dist/components/ui/index.js.map +1 -1
- package/dist/components/ui/primitives/button.d.ts +3 -2
- package/dist/components/ui/primitives/button.d.ts.map +1 -1
- package/dist/components/ui/primitives/button.js +20 -2
- package/dist/components/ui/primitives/button.js.map +1 -1
- package/dist/components/ui/resizeable.d.ts.map +1 -1
- package/dist/components/ui/resizeable.js +2 -1
- package/dist/components/ui/resizeable.js.map +1 -1
- package/dist/components/ui/text.d.ts +2 -1
- package/dist/components/ui/text.d.ts.map +1 -1
- package/dist/components/ui/text.js.map +1 -1
- package/dist/components/ui/textarea.d.ts.map +1 -1
- package/dist/components/ui/textarea.js +3 -1
- package/dist/components/ui/textarea.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/theme/atoms.d.ts +148 -148
- package/dist/lib/theme/tokens.d.ts +11 -11
- package/dist/lib/theme/tokens.js +11 -11
- package/dist/utils/did.d.ts +13 -0
- package/dist/utils/did.d.ts.map +1 -0
- package/dist/utils/did.js +43 -0
- package/dist/utils/did.js.map +1 -0
- package/locales/en-US/settings.ftl +2 -1
- package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
- package/package.json +2 -2
- package/src/components/chat/mod-view.tsx +0 -205
- package/src/components/chat/update-stream-title-dialog.tsx +169 -0
- package/src/components/content-metadata/content-metadata-form.tsx +37 -10
- package/src/components/ui/admonition.tsx +177 -0
- package/src/components/ui/button.tsx +3 -0
- package/src/components/ui/index.ts +1 -0
- package/src/components/ui/primitives/button.tsx +37 -11
- package/src/components/ui/resizeable.tsx +2 -1
- package/src/components/ui/text.tsx +11 -1
- package/src/components/ui/textarea.tsx +3 -0
- package/src/index.tsx +2 -0
- package/src/lib/theme/tokens.ts +11 -11
- package/src/utils/did.ts +61 -0
|
@@ -329,17 +329,17 @@ export declare const colors: {
|
|
|
329
329
|
readonly 950: "#052e16";
|
|
330
330
|
};
|
|
331
331
|
readonly warning: {
|
|
332
|
-
readonly 50: "#
|
|
333
|
-
readonly 100: "#
|
|
334
|
-
readonly 200: "#
|
|
335
|
-
readonly 300: "#
|
|
336
|
-
readonly 400: "#
|
|
337
|
-
readonly 500: "#
|
|
338
|
-
readonly 600: "#
|
|
339
|
-
readonly 700: "#
|
|
340
|
-
readonly 800: "#
|
|
341
|
-
readonly 900: "#
|
|
342
|
-
readonly 950: "#
|
|
332
|
+
readonly 50: "#fffaf0";
|
|
333
|
+
readonly 100: "#ffe6c7";
|
|
334
|
+
readonly 200: "#ffd99e";
|
|
335
|
+
readonly 300: "#ffcc75";
|
|
336
|
+
readonly 400: "#ffb94e";
|
|
337
|
+
readonly 500: "#ff9e1f";
|
|
338
|
+
readonly 600: "#e67e00";
|
|
339
|
+
readonly 700: "#cc6600";
|
|
340
|
+
readonly 800: "#998c00";
|
|
341
|
+
readonly 900: "#664200";
|
|
342
|
+
readonly 950: "#332900";
|
|
343
343
|
};
|
|
344
344
|
readonly ios: {
|
|
345
345
|
readonly systemBlue: "#007AFF";
|
package/dist/lib/theme/tokens.js
CHANGED
|
@@ -335,17 +335,17 @@ exports.colors = {
|
|
|
335
335
|
950: "#052e16",
|
|
336
336
|
},
|
|
337
337
|
warning: {
|
|
338
|
-
50: "#
|
|
339
|
-
100: "#
|
|
340
|
-
200: "#
|
|
341
|
-
300: "#
|
|
342
|
-
400: "#
|
|
343
|
-
500: "#
|
|
344
|
-
600: "#
|
|
345
|
-
700: "#
|
|
346
|
-
800: "#
|
|
347
|
-
900: "#
|
|
348
|
-
950: "#
|
|
338
|
+
50: "#fffaf0",
|
|
339
|
+
100: "#ffe6c7",
|
|
340
|
+
200: "#ffd99e",
|
|
341
|
+
300: "#ffcc75",
|
|
342
|
+
400: "#ffb94e",
|
|
343
|
+
500: "#ff9e1f",
|
|
344
|
+
600: "#e67e00",
|
|
345
|
+
700: "#cc6600",
|
|
346
|
+
800: "#998c00",
|
|
347
|
+
900: "#664200",
|
|
348
|
+
950: "#332900",
|
|
349
349
|
},
|
|
350
350
|
// iOS system colors (adaptive)
|
|
351
351
|
ios: {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface DIDDocument {
|
|
2
|
+
id: string;
|
|
3
|
+
service?: Array<{
|
|
4
|
+
id: string;
|
|
5
|
+
type?: string;
|
|
6
|
+
serviceEndpoint?: string;
|
|
7
|
+
}>;
|
|
8
|
+
[key: string]: any;
|
|
9
|
+
}
|
|
10
|
+
export declare function resolveDIDDocument(did: string): Promise<DIDDocument>;
|
|
11
|
+
export declare function getPDSServiceEndpoint(didDoc: DIDDocument): string;
|
|
12
|
+
export declare function getBlob(did: string, cid: string, didDoc?: DIDDocument): Promise<Blob>;
|
|
13
|
+
//# sourceMappingURL=did.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"did.d.ts","sourceRoot":"","sources":["../../src/utils/did.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,KAAK,CAAC;QACd,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC,CAAC;IACH,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAsB1E;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAQjE;AAED,wBAAsB,OAAO,CAC3B,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAYf"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveDIDDocument = resolveDIDDocument;
|
|
4
|
+
exports.getPDSServiceEndpoint = getPDSServiceEndpoint;
|
|
5
|
+
exports.getBlob = getBlob;
|
|
6
|
+
async function resolveDIDDocument(did) {
|
|
7
|
+
let didDocUrl;
|
|
8
|
+
if (did.startsWith("did:web:")) {
|
|
9
|
+
// For did:web, construct the URL directly
|
|
10
|
+
const domain = did.replace("did:web:", "").replace(/:/g, "/");
|
|
11
|
+
didDocUrl = `https://${domain}/.well-known/did.json`;
|
|
12
|
+
}
|
|
13
|
+
else if (did.startsWith("did:plc:")) {
|
|
14
|
+
// For did:plc, use plc.directory
|
|
15
|
+
didDocUrl = `https://plc.directory/${did}`;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
throw new Error(`Unsupported DID method: ${did}`);
|
|
19
|
+
}
|
|
20
|
+
const response = await fetch(didDocUrl);
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
throw new Error(`Failed to resolve DID document for ${did}: ${response.status}`);
|
|
23
|
+
}
|
|
24
|
+
return response.json();
|
|
25
|
+
}
|
|
26
|
+
function getPDSServiceEndpoint(didDoc) {
|
|
27
|
+
const pdsService = didDoc.service?.find((s) => s.id === "#atproto_pds");
|
|
28
|
+
if (!pdsService?.serviceEndpoint) {
|
|
29
|
+
throw new Error("No PDS service endpoint found in DID document");
|
|
30
|
+
}
|
|
31
|
+
return pdsService.serviceEndpoint;
|
|
32
|
+
}
|
|
33
|
+
async function getBlob(did, cid, didDoc) {
|
|
34
|
+
const doc = didDoc || (await resolveDIDDocument(did));
|
|
35
|
+
const pdsEndpoint = getPDSServiceEndpoint(doc);
|
|
36
|
+
const blobUrl = `${pdsEndpoint}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${cid}`;
|
|
37
|
+
const response = await fetch(blobUrl);
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
throw new Error(`Failed to fetch blob: ${response.status}`);
|
|
40
|
+
}
|
|
41
|
+
return response.blob();
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=did.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"did.js","sourceRoot":"","sources":["../../src/utils/did.ts"],"names":[],"mappings":";;AAUA,gDAsBC;AAED,sDAQC;AAED,0BAgBC;AAlDM,KAAK,UAAU,kBAAkB,CAAC,GAAW;IAClD,IAAI,SAAiB,CAAC;IAEtB,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,0CAA0C;QAC1C,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC9D,SAAS,GAAG,WAAW,MAAM,uBAAuB,CAAC;IACvD,CAAC;SAAM,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QACtC,iCAAiC;QACjC,SAAS,GAAG,yBAAyB,GAAG,EAAE,CAAC;IAC7C,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC;IACxC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CACb,sCAAsC,GAAG,KAAK,QAAQ,CAAC,MAAM,EAAE,CAChE,CAAC;IACJ,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,SAAgB,qBAAqB,CAAC,MAAmB;IACvD,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,cAAc,CAAC,CAAC;IAExE,IAAI,CAAC,UAAU,EAAE,eAAe,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACnE,CAAC;IAED,OAAO,UAAU,CAAC,eAAe,CAAC;AACpC,CAAC;AAEM,KAAK,UAAU,OAAO,CAC3B,GAAW,EACX,GAAW,EACX,MAAoB;IAEpB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC;IACtD,MAAM,WAAW,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAE/C,MAAM,OAAO,GAAG,GAAG,WAAW,sCAAsC,GAAG,QAAQ,GAAG,EAAE,CAAC;IAErF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC;IACtC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,yBAAyB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC"}
|
|
@@ -121,7 +121,7 @@ inactive = Inactive
|
|
|
121
121
|
active = Active
|
|
122
122
|
|
|
123
123
|
## Multistreaming
|
|
124
|
-
|
|
124
|
+
multistream = Multistreaming
|
|
125
125
|
multistream-targets = Multistream Targets
|
|
126
126
|
multistream-description = Automatically push your Streamplace livestreams to other streaming services like Twitch or YouTube.
|
|
127
127
|
create-multistream-target = Create Multistream Target
|
|
@@ -168,6 +168,7 @@ need-setup-live-dashboard = Need to set up streaming first? Visit the live dashb
|
|
|
168
168
|
no-languages-found = No languages found
|
|
169
169
|
|
|
170
170
|
## Branding Administration
|
|
171
|
+
branding = Branding
|
|
171
172
|
branding-admin = Branding Administration
|
|
172
173
|
branding-admin-description = Customize your Streamplace instance. Note that settings may take a few hours to propagate.
|
|
173
174
|
branding-login-required = Please log in to manage branding
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@streamplace/components",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6",
|
|
4
4
|
"description": "Streamplace React (Native) Components",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "src/index.tsx",
|
|
@@ -80,5 +80,5 @@
|
|
|
80
80
|
"i18n:watch": "nodemon --watch 'locales/**/*.ftl' --exec 'node scripts/compile-translations.js'",
|
|
81
81
|
"i18n:extract": "i18next-cli extract && node scripts/migrate-i18n.js"
|
|
82
82
|
},
|
|
83
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "5ea7ad20a8cbf83a0f554ba1348972cc34d9b518"
|
|
84
84
|
}
|
|
@@ -5,7 +5,6 @@ import { usePlayerStore } from "../../player-store";
|
|
|
5
5
|
import {
|
|
6
6
|
useCreateBlockRecord,
|
|
7
7
|
useCreateHideChatRecord,
|
|
8
|
-
useUpdateLivestreamRecord,
|
|
9
8
|
} from "../../streamplace-store/block";
|
|
10
9
|
import {
|
|
11
10
|
ModerationPermissions,
|
|
@@ -17,24 +16,19 @@ import { Linking } from "react-native";
|
|
|
17
16
|
import { ChatMessageViewHydrated } from "streamplace";
|
|
18
17
|
import {
|
|
19
18
|
useDeleteChatMessage,
|
|
20
|
-
useLivestream,
|
|
21
19
|
useLivestreamStore,
|
|
22
20
|
} from "../../livestream-store";
|
|
23
21
|
import { useStreamplaceStore } from "../../streamplace-store";
|
|
24
22
|
import { formatHandle, formatHandleWithAt } from "../../utils/format-handle";
|
|
25
23
|
import {
|
|
26
24
|
atoms,
|
|
27
|
-
Button,
|
|
28
|
-
DialogFooter,
|
|
29
25
|
DropdownMenu,
|
|
30
26
|
DropdownMenuGroup,
|
|
31
27
|
DropdownMenuItem,
|
|
32
28
|
DropdownMenuTrigger,
|
|
33
29
|
layout,
|
|
34
|
-
ResponsiveDialog,
|
|
35
30
|
ResponsiveDropdownMenuContent,
|
|
36
31
|
Text,
|
|
37
|
-
Textarea,
|
|
38
32
|
useToast,
|
|
39
33
|
View,
|
|
40
34
|
} from "../ui";
|
|
@@ -61,10 +55,6 @@ export const ModView = forwardRef<ModViewRef, ModViewProps>(() => {
|
|
|
61
55
|
let [messageRemoved, setMessageRemoved] = useState(false);
|
|
62
56
|
let { createBlock, isLoading: isBlockLoading } = useCreateBlockRecord();
|
|
63
57
|
let { createHideChat, isLoading: isHideLoading } = useCreateHideChatRecord();
|
|
64
|
-
let { updateLivestream, isLoading: isUpdateTitleLoading } =
|
|
65
|
-
useUpdateLivestreamRecord();
|
|
66
|
-
const livestream = useLivestream();
|
|
67
|
-
const [showUpdateTitleDialog, setShowUpdateTitleDialog] = useState(false);
|
|
68
58
|
|
|
69
59
|
const setReportModalOpen = usePlayerStore((x) => x.setReportModalOpen);
|
|
70
60
|
const setReportSubject = usePlayerStore((x) => x.setReportSubject);
|
|
@@ -135,9 +125,6 @@ export const ModView = forwardRef<ModViewRef, ModViewProps>(() => {
|
|
|
135
125
|
createHideChat={createHideChat}
|
|
136
126
|
createBlock={createBlock}
|
|
137
127
|
toast={toast}
|
|
138
|
-
setShowUpdateTitleDialog={setShowUpdateTitleDialog}
|
|
139
|
-
isUpdateTitleLoading={isUpdateTitleLoading}
|
|
140
|
-
livestream={livestream}
|
|
141
128
|
setReportModalOpen={setReportModalOpen}
|
|
142
129
|
setReportSubject={setReportSubject}
|
|
143
130
|
deleteChatMessage={deleteChatMessage}
|
|
@@ -145,17 +132,6 @@ export const ModView = forwardRef<ModViewRef, ModViewProps>(() => {
|
|
|
145
132
|
)}
|
|
146
133
|
</ResponsiveDropdownMenuContent>
|
|
147
134
|
</DropdownMenu>
|
|
148
|
-
|
|
149
|
-
{/* Update Stream Title Dialog - rendered outside dropdown */}
|
|
150
|
-
{showUpdateTitleDialog && (
|
|
151
|
-
<UpdateStreamTitleDialog
|
|
152
|
-
livestream={livestream}
|
|
153
|
-
streamerDID={streamerDID}
|
|
154
|
-
updateLivestream={updateLivestream}
|
|
155
|
-
isLoading={isUpdateTitleLoading}
|
|
156
|
-
onClose={() => setShowUpdateTitleDialog(false)}
|
|
157
|
-
/>
|
|
158
|
-
)}
|
|
159
135
|
</>
|
|
160
136
|
);
|
|
161
137
|
});
|
|
@@ -173,9 +149,6 @@ interface ModViewContentProps {
|
|
|
173
149
|
createHideChat: (uri: string, streamerDID?: string) => Promise<any>;
|
|
174
150
|
createBlock: (did: string, streamerDID?: string) => Promise<any>;
|
|
175
151
|
toast: ReturnType<typeof useToast>;
|
|
176
|
-
setShowUpdateTitleDialog: (show: boolean) => void;
|
|
177
|
-
isUpdateTitleLoading: boolean;
|
|
178
|
-
livestream: any;
|
|
179
152
|
setReportModalOpen: (open: boolean) => void;
|
|
180
153
|
setReportSubject: (subject: any) => void;
|
|
181
154
|
deleteChatMessage: (uri: string) => Promise<any>;
|
|
@@ -194,9 +167,6 @@ function ModViewContent({
|
|
|
194
167
|
createHideChat,
|
|
195
168
|
createBlock,
|
|
196
169
|
toast,
|
|
197
|
-
setShowUpdateTitleDialog,
|
|
198
|
-
isUpdateTitleLoading,
|
|
199
|
-
livestream,
|
|
200
170
|
setReportModalOpen,
|
|
201
171
|
setReportSubject,
|
|
202
172
|
deleteChatMessage,
|
|
@@ -290,23 +260,6 @@ function ModViewContent({
|
|
|
290
260
|
</DropdownMenuGroup>
|
|
291
261
|
)}
|
|
292
262
|
|
|
293
|
-
{modPermissions.canManageLivestream && (
|
|
294
|
-
<DropdownMenuGroup key="stream-actions" title={`Stream actions`}>
|
|
295
|
-
<DropdownMenuItem
|
|
296
|
-
onPress={() => {
|
|
297
|
-
setShowUpdateTitleDialog(true);
|
|
298
|
-
}}
|
|
299
|
-
disabled={isUpdateTitleLoading || !livestream}
|
|
300
|
-
>
|
|
301
|
-
<Text
|
|
302
|
-
color={isUpdateTitleLoading || !livestream ? "muted" : "primary"}
|
|
303
|
-
>
|
|
304
|
-
{isUpdateTitleLoading ? "Updating..." : "Update stream title"}
|
|
305
|
-
</Text>
|
|
306
|
-
</DropdownMenuItem>
|
|
307
|
-
</DropdownMenuGroup>
|
|
308
|
-
)}
|
|
309
|
-
|
|
310
263
|
<DropdownMenuGroup key="user-actions" title={`User actions`}>
|
|
311
264
|
<DropdownMenuItem
|
|
312
265
|
onPress={() => {
|
|
@@ -418,161 +371,3 @@ export function ReportButton({
|
|
|
418
371
|
</DropdownMenuItem>
|
|
419
372
|
);
|
|
420
373
|
}
|
|
421
|
-
|
|
422
|
-
interface UpdateStreamTitleDialogProps {
|
|
423
|
-
livestream: any;
|
|
424
|
-
streamerDID?: string;
|
|
425
|
-
updateLivestream: (
|
|
426
|
-
livestreamUri: string,
|
|
427
|
-
title: string,
|
|
428
|
-
streamerDID?: string,
|
|
429
|
-
) => Promise<any>;
|
|
430
|
-
isLoading: boolean;
|
|
431
|
-
onClose: () => void;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
function UpdateStreamTitleDialog({
|
|
435
|
-
livestream,
|
|
436
|
-
streamerDID,
|
|
437
|
-
updateLivestream,
|
|
438
|
-
isLoading,
|
|
439
|
-
onClose,
|
|
440
|
-
}: UpdateStreamTitleDialogProps) {
|
|
441
|
-
const [title, setTitle] = useState(livestream?.record?.title || "");
|
|
442
|
-
const [error, setError] = useState<string | null>(null);
|
|
443
|
-
const toast = useToast();
|
|
444
|
-
|
|
445
|
-
useEffect(() => {
|
|
446
|
-
if (livestream?.record?.title) {
|
|
447
|
-
setTitle(livestream.record.title);
|
|
448
|
-
}
|
|
449
|
-
}, [livestream?.record?.title]);
|
|
450
|
-
|
|
451
|
-
const handleUpdate = async () => {
|
|
452
|
-
setError(null);
|
|
453
|
-
|
|
454
|
-
if (!title.trim()) {
|
|
455
|
-
setError("Please enter a stream title");
|
|
456
|
-
return;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
if (!livestream?.uri) {
|
|
460
|
-
setError("No livestream found");
|
|
461
|
-
return;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
try {
|
|
465
|
-
await updateLivestream(livestream.uri, title.trim(), streamerDID);
|
|
466
|
-
toast.show(
|
|
467
|
-
"Stream title updated",
|
|
468
|
-
"The stream title has been successfully updated.",
|
|
469
|
-
{ duration: 3 },
|
|
470
|
-
);
|
|
471
|
-
onClose();
|
|
472
|
-
} catch (err) {
|
|
473
|
-
setError(
|
|
474
|
-
err instanceof Error ? err.message : "Failed to update stream title",
|
|
475
|
-
);
|
|
476
|
-
}
|
|
477
|
-
};
|
|
478
|
-
|
|
479
|
-
return (
|
|
480
|
-
<ResponsiveDialog
|
|
481
|
-
open={true}
|
|
482
|
-
onOpenChange={(open) => {
|
|
483
|
-
if (!open) {
|
|
484
|
-
onClose();
|
|
485
|
-
setError(null);
|
|
486
|
-
setTitle(livestream?.record?.title || "");
|
|
487
|
-
}
|
|
488
|
-
}}
|
|
489
|
-
title="Update Stream Title"
|
|
490
|
-
description="Update the title of the livestream."
|
|
491
|
-
size="md"
|
|
492
|
-
dismissible={false}
|
|
493
|
-
>
|
|
494
|
-
<View style={[{ padding: 16, paddingBottom: 0 }]}>
|
|
495
|
-
<View style={[{ marginBottom: 16 }]}>
|
|
496
|
-
<Text
|
|
497
|
-
style={[
|
|
498
|
-
{ color: atoms.colors.gray[300], fontSize: 13, marginBottom: 8 },
|
|
499
|
-
]}
|
|
500
|
-
>
|
|
501
|
-
Stream Title
|
|
502
|
-
</Text>
|
|
503
|
-
<Textarea
|
|
504
|
-
value={title}
|
|
505
|
-
onChangeText={(text) => {
|
|
506
|
-
setTitle(text);
|
|
507
|
-
setError(null);
|
|
508
|
-
}}
|
|
509
|
-
placeholder="Enter stream title..."
|
|
510
|
-
maxLength={140}
|
|
511
|
-
multiline
|
|
512
|
-
style={[
|
|
513
|
-
{
|
|
514
|
-
padding: 12,
|
|
515
|
-
borderRadius: 8,
|
|
516
|
-
backgroundColor: atoms.colors.neutral[800],
|
|
517
|
-
color: atoms.colors.white,
|
|
518
|
-
borderWidth: 1,
|
|
519
|
-
borderColor: atoms.colors.neutral[600],
|
|
520
|
-
minHeight: 100,
|
|
521
|
-
fontSize: 16,
|
|
522
|
-
},
|
|
523
|
-
]}
|
|
524
|
-
/>
|
|
525
|
-
<Text
|
|
526
|
-
style={[
|
|
527
|
-
{ color: atoms.colors.gray[400], fontSize: 12, marginTop: 4 },
|
|
528
|
-
]}
|
|
529
|
-
>
|
|
530
|
-
{title.length}/140 characters
|
|
531
|
-
</Text>
|
|
532
|
-
</View>
|
|
533
|
-
|
|
534
|
-
{error && (
|
|
535
|
-
<View
|
|
536
|
-
style={[
|
|
537
|
-
{
|
|
538
|
-
backgroundColor: atoms.colors.red[900],
|
|
539
|
-
padding: 12,
|
|
540
|
-
borderRadius: 8,
|
|
541
|
-
borderWidth: 1,
|
|
542
|
-
borderColor: atoms.colors.red[700],
|
|
543
|
-
marginBottom: 16,
|
|
544
|
-
},
|
|
545
|
-
]}
|
|
546
|
-
>
|
|
547
|
-
<Text style={[{ color: atoms.colors.red[400], fontSize: 13 }]}>
|
|
548
|
-
{error}
|
|
549
|
-
</Text>
|
|
550
|
-
</View>
|
|
551
|
-
)}
|
|
552
|
-
</View>
|
|
553
|
-
|
|
554
|
-
<DialogFooter>
|
|
555
|
-
<Button
|
|
556
|
-
width="min"
|
|
557
|
-
variant="secondary"
|
|
558
|
-
onPress={() => {
|
|
559
|
-
onClose();
|
|
560
|
-
setError(null);
|
|
561
|
-
setTitle(livestream?.record?.title || "");
|
|
562
|
-
}}
|
|
563
|
-
disabled={isLoading}
|
|
564
|
-
>
|
|
565
|
-
<Text>Cancel</Text>
|
|
566
|
-
</Button>
|
|
567
|
-
<Button
|
|
568
|
-
variant="primary"
|
|
569
|
-
width="min"
|
|
570
|
-
onPress={handleUpdate}
|
|
571
|
-
disabled={isLoading || !title.trim()}
|
|
572
|
-
>
|
|
573
|
-
<Text>{isLoading ? "Updating..." : "Update Title"}</Text>
|
|
574
|
-
</Button>
|
|
575
|
-
</DialogFooter>
|
|
576
|
-
</ResponsiveDialog>
|
|
577
|
-
);
|
|
578
|
-
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
atoms,
|
|
4
|
+
Button,
|
|
5
|
+
DialogFooter,
|
|
6
|
+
ResponsiveDialog,
|
|
7
|
+
Text,
|
|
8
|
+
Textarea,
|
|
9
|
+
useToast,
|
|
10
|
+
View,
|
|
11
|
+
} from "../ui";
|
|
12
|
+
|
|
13
|
+
export interface UpdateStreamTitleDialogProps {
|
|
14
|
+
livestream: any;
|
|
15
|
+
streamerDID?: string;
|
|
16
|
+
updateLivestream: (
|
|
17
|
+
livestreamUri: string,
|
|
18
|
+
title: string,
|
|
19
|
+
streamerDID?: string,
|
|
20
|
+
) => Promise<any>;
|
|
21
|
+
isLoading: boolean;
|
|
22
|
+
onClose: () => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function UpdateStreamTitleDialog({
|
|
26
|
+
livestream,
|
|
27
|
+
streamerDID,
|
|
28
|
+
updateLivestream,
|
|
29
|
+
isLoading,
|
|
30
|
+
onClose,
|
|
31
|
+
}: UpdateStreamTitleDialogProps) {
|
|
32
|
+
const [title, setTitle] = useState(livestream?.record?.title || "");
|
|
33
|
+
const [error, setError] = useState<string | null>(null);
|
|
34
|
+
const toast = useToast();
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (livestream?.record?.title) {
|
|
38
|
+
setTitle(livestream.record.title);
|
|
39
|
+
}
|
|
40
|
+
}, [livestream?.record?.title]);
|
|
41
|
+
|
|
42
|
+
const handleUpdate = async () => {
|
|
43
|
+
setError(null);
|
|
44
|
+
|
|
45
|
+
if (!title.trim()) {
|
|
46
|
+
setError("Please enter a stream title");
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!livestream?.uri) {
|
|
51
|
+
setError("No livestream found");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
await updateLivestream(livestream.uri, title.trim(), streamerDID);
|
|
57
|
+
toast.show(
|
|
58
|
+
"Stream title updated",
|
|
59
|
+
"The stream title has been successfully updated.",
|
|
60
|
+
{ duration: 3 },
|
|
61
|
+
);
|
|
62
|
+
onClose();
|
|
63
|
+
} catch (err) {
|
|
64
|
+
setError(
|
|
65
|
+
err instanceof Error ? err.message : "Failed to update stream title",
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<ResponsiveDialog
|
|
72
|
+
open={true}
|
|
73
|
+
onOpenChange={(open) => {
|
|
74
|
+
if (!open) {
|
|
75
|
+
onClose();
|
|
76
|
+
setError(null);
|
|
77
|
+
setTitle(livestream?.record?.title || "");
|
|
78
|
+
}
|
|
79
|
+
}}
|
|
80
|
+
title="Update Stream Title"
|
|
81
|
+
description="Update the title of the livestream."
|
|
82
|
+
size="md"
|
|
83
|
+
dismissible={false}
|
|
84
|
+
>
|
|
85
|
+
<View style={[{ padding: 16, paddingBottom: 0 }]}>
|
|
86
|
+
<View style={[{ marginBottom: 16 }]}>
|
|
87
|
+
<Text
|
|
88
|
+
style={[
|
|
89
|
+
{ color: atoms.colors.gray[300], fontSize: 13, marginBottom: 8 },
|
|
90
|
+
]}
|
|
91
|
+
>
|
|
92
|
+
Stream Title
|
|
93
|
+
</Text>
|
|
94
|
+
<Textarea
|
|
95
|
+
value={title}
|
|
96
|
+
onChangeText={(text) => {
|
|
97
|
+
setTitle(text);
|
|
98
|
+
setError(null);
|
|
99
|
+
}}
|
|
100
|
+
placeholder="Enter stream title..."
|
|
101
|
+
maxLength={140}
|
|
102
|
+
multiline
|
|
103
|
+
style={[
|
|
104
|
+
{
|
|
105
|
+
padding: 12,
|
|
106
|
+
borderRadius: 8,
|
|
107
|
+
backgroundColor: atoms.colors.neutral[800],
|
|
108
|
+
color: atoms.colors.white,
|
|
109
|
+
borderWidth: 1,
|
|
110
|
+
borderColor: atoms.colors.neutral[600],
|
|
111
|
+
minHeight: 100,
|
|
112
|
+
fontSize: 16,
|
|
113
|
+
},
|
|
114
|
+
]}
|
|
115
|
+
/>
|
|
116
|
+
<Text
|
|
117
|
+
style={[
|
|
118
|
+
{ color: atoms.colors.gray[400], fontSize: 12, marginTop: 4 },
|
|
119
|
+
]}
|
|
120
|
+
>
|
|
121
|
+
{title.length}/140 characters
|
|
122
|
+
</Text>
|
|
123
|
+
</View>
|
|
124
|
+
|
|
125
|
+
{error && (
|
|
126
|
+
<View
|
|
127
|
+
style={[
|
|
128
|
+
{
|
|
129
|
+
backgroundColor: atoms.colors.red[900],
|
|
130
|
+
padding: 12,
|
|
131
|
+
borderRadius: 8,
|
|
132
|
+
borderWidth: 1,
|
|
133
|
+
borderColor: atoms.colors.red[700],
|
|
134
|
+
marginBottom: 16,
|
|
135
|
+
},
|
|
136
|
+
]}
|
|
137
|
+
>
|
|
138
|
+
<Text style={[{ color: atoms.colors.red[400], fontSize: 13 }]}>
|
|
139
|
+
{error}
|
|
140
|
+
</Text>
|
|
141
|
+
</View>
|
|
142
|
+
)}
|
|
143
|
+
</View>
|
|
144
|
+
|
|
145
|
+
<DialogFooter>
|
|
146
|
+
<Button
|
|
147
|
+
width="min"
|
|
148
|
+
variant="secondary"
|
|
149
|
+
onPress={() => {
|
|
150
|
+
onClose();
|
|
151
|
+
setError(null);
|
|
152
|
+
setTitle(livestream?.record?.title || "");
|
|
153
|
+
}}
|
|
154
|
+
disabled={isLoading}
|
|
155
|
+
>
|
|
156
|
+
<Text>Cancel</Text>
|
|
157
|
+
</Button>
|
|
158
|
+
<Button
|
|
159
|
+
variant="primary"
|
|
160
|
+
width="min"
|
|
161
|
+
onPress={handleUpdate}
|
|
162
|
+
disabled={isLoading || !title.trim()}
|
|
163
|
+
>
|
|
164
|
+
<Text>{isLoading ? "Updating..." : "Update Title"}</Text>
|
|
165
|
+
</Button>
|
|
166
|
+
</DialogFooter>
|
|
167
|
+
</ResponsiveDialog>
|
|
168
|
+
);
|
|
169
|
+
}
|