forked from Kieran/zap.stream
Merge branch 'main' into feat/zapgoals
This commit is contained in:
commit
669bba5828
@ -110,7 +110,7 @@ export function ChatMessage({
|
|||||||
<Icon name="signal" size={16} />
|
<Icon name="signal" size={16} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pubkey={""}
|
pubkey={ev.pubkey}
|
||||||
profile={profile}
|
profile={profile}
|
||||||
/>
|
/>
|
||||||
<Text content={ev.content} tags={ev.tags} />
|
<Text content={ev.content} tags={ev.tags} />
|
||||||
|
@ -13,10 +13,8 @@ export function NostrProviderDialog({ provider, ...others }: { provider: StreamP
|
|||||||
const [info, setInfo] = useState<StreamProviderInfo>();
|
const [info, setInfo] = useState<StreamProviderInfo>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (provider && !info) {
|
|
||||||
provider.info().then(v => setInfo(v));
|
provider.info().then(v => setInfo(v));
|
||||||
}
|
}, [provider]);
|
||||||
}, [info, provider])
|
|
||||||
|
|
||||||
if (!info) {
|
if (!info) {
|
||||||
return <Spinner />
|
return <Spinner />
|
||||||
@ -74,7 +72,8 @@ export function NostrProviderDialog({ provider, ...others }: { provider: StreamP
|
|||||||
others.onFinish?.(ex);
|
others.onFinish?.(ex);
|
||||||
}} ev={streamEvent} options={{
|
}} ev={streamEvent} options={{
|
||||||
canSetStream: false,
|
canSetStream: false,
|
||||||
canSetStatus: false
|
canSetStatus: false,
|
||||||
|
canSetContentWarning: false
|
||||||
}} />}
|
}} />}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
@ -12,3 +12,9 @@
|
|||||||
border-radius: 12px !important;
|
border-radius: 12px !important;
|
||||||
display: unset !important;
|
display: unset !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content-warning {
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 16px;
|
||||||
|
border: 1px solid #FF563F;
|
||||||
|
}
|
@ -17,23 +17,33 @@ export interface StreamEditorProps {
|
|||||||
canSetImage?: boolean
|
canSetImage?: boolean
|
||||||
canSetStatus?: boolean
|
canSetStatus?: boolean
|
||||||
canSetStream?: boolean
|
canSetStream?: boolean
|
||||||
|
canSetTags?: boolean
|
||||||
|
canSetContentWarning?: boolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
|
export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
|
||||||
const [title, setTitle] = useState(findTag(ev, "title") ?? "");
|
const [title, setTitle] = useState("");
|
||||||
const [summary, setSummary] = useState(findTag(ev, "summary") ?? "");
|
const [summary, setSummary] = useState("");
|
||||||
const [image, setImage] = useState(findTag(ev, "image") ?? "");
|
const [image, setImage] = useState("");
|
||||||
const [stream, setStream] = useState(findTag(ev, "streaming") ?? "");
|
const [stream, setStream] = useState("");
|
||||||
const [status, setStatus] = useState(
|
const [status, setStatus] = useState("");
|
||||||
findTag(ev, "status") ?? StreamState.Live
|
const [start, setStart] = useState<string>();
|
||||||
);
|
const [tags, setTags] = useState<string[]>([]);
|
||||||
const [start, setStart] = useState(findTag(ev, "starts"));
|
const [contentWarning, setContentWarning] = useState(false);
|
||||||
const [tags, setTags] = useState(
|
|
||||||
ev?.tags.filter(a => a[0] === "t").map(a => a[1]) ?? []
|
|
||||||
);
|
|
||||||
const [isValid, setIsValid] = useState(false);
|
const [isValid, setIsValid] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setTitle(findTag(ev, "title") ?? "");
|
||||||
|
setSummary(findTag(ev, "summary") ?? "");
|
||||||
|
setImage(findTag(ev, "image") ?? "");
|
||||||
|
setStream(findTag(ev, "streaming") ?? "");
|
||||||
|
setStatus(findTag(ev, "status") ?? StreamState.Live);
|
||||||
|
setStart(findTag(ev, "starts"));
|
||||||
|
setTags(ev?.tags.filter(a => a[0] === "t").map(a => a[1]) ?? []);
|
||||||
|
setContentWarning(findTag(ev, "content-warning") !== undefined);
|
||||||
|
}, [ev?.id]);
|
||||||
|
|
||||||
const validate = useCallback(() => {
|
const validate = useCallback(() => {
|
||||||
if (title.length < 2) {
|
if (title.length < 2) {
|
||||||
return false;
|
return false;
|
||||||
@ -73,6 +83,9 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
|
|||||||
for (const tx of tags) {
|
for (const tx of tags) {
|
||||||
eb.tag(["t", tx.trim()]);
|
eb.tag(["t", tx.trim()]);
|
||||||
}
|
}
|
||||||
|
if(contentWarning) {
|
||||||
|
eb.tag(["content-warning", "nsfw"])
|
||||||
|
}
|
||||||
return eb;
|
return eb;
|
||||||
});
|
});
|
||||||
console.debug(evNew);
|
console.debug(evNew);
|
||||||
@ -91,7 +104,7 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h3>{ev ? "Edit Stream" : "New Stream"}</h3>
|
<h3>{ev ? "Edit Stream" : "New Stream"}</h3>
|
||||||
{(options?.canSetTitle === undefined || options.canSetTitle) && <div>
|
{(options?.canSetTitle ?? true) && <div>
|
||||||
<p>Title</p>
|
<p>Title</p>
|
||||||
<div className="paper">
|
<div className="paper">
|
||||||
<input
|
<input
|
||||||
@ -101,7 +114,7 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
|
|||||||
onChange={(e) => setTitle(e.target.value)} />
|
onChange={(e) => setTitle(e.target.value)} />
|
||||||
</div>
|
</div>
|
||||||
</div>}
|
</div>}
|
||||||
{(options?.canSetSummary === undefined || options.canSetSummary) && <div>
|
{(options?.canSetSummary ?? true) && <div>
|
||||||
<p>Summary</p>
|
<p>Summary</p>
|
||||||
<div className="paper">
|
<div className="paper">
|
||||||
<input
|
<input
|
||||||
@ -111,7 +124,7 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
|
|||||||
onChange={(e) => setSummary(e.target.value)} />
|
onChange={(e) => setSummary(e.target.value)} />
|
||||||
</div>
|
</div>
|
||||||
</div>}
|
</div>}
|
||||||
{(options?.canSetImage === undefined || options.canSetImage) && <div>
|
{(options?.canSetImage ?? true) && <div>
|
||||||
<p>Cover image</p>
|
<p>Cover image</p>
|
||||||
<div className="paper">
|
<div className="paper">
|
||||||
<input
|
<input
|
||||||
@ -121,7 +134,7 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
|
|||||||
onChange={(e) => setImage(e.target.value)} />
|
onChange={(e) => setImage(e.target.value)} />
|
||||||
</div>
|
</div>
|
||||||
</div>}
|
</div>}
|
||||||
{(options?.canSetStream === undefined || options.canSetStream) && <div>
|
{(options?.canSetStream ?? true) && <div>
|
||||||
<p>Stream Url</p>
|
<p>Stream Url</p>
|
||||||
<div className="paper">
|
<div className="paper">
|
||||||
<input
|
<input
|
||||||
@ -132,7 +145,7 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
|
|||||||
</div>
|
</div>
|
||||||
<small>Stream type should be HLS</small>
|
<small>Stream type should be HLS</small>
|
||||||
</div>}
|
</div>}
|
||||||
{(options?.canSetStatus === undefined || options.canSetStatus) && <><div>
|
{(options?.canSetStatus ?? true) && <><div>
|
||||||
<p>Status</p>
|
<p>Status</p>
|
||||||
<div className="flex g12">
|
<div className="flex g12">
|
||||||
{[StreamState.Live, StreamState.Planned, StreamState.Ended].map(
|
{[StreamState.Live, StreamState.Planned, StreamState.Ended].map(
|
||||||
@ -151,7 +164,7 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
|
|||||||
{status === StreamState.Planned && (
|
{status === StreamState.Planned && (
|
||||||
<div>
|
<div>
|
||||||
<p>Start Time</p>
|
<p>Start Time</p>
|
||||||
<div className="input">
|
<div className="paper">
|
||||||
<input
|
<input
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
value={toDateTimeString(Number(start ?? "0"))}
|
value={toDateTimeString(Number(start ?? "0"))}
|
||||||
@ -159,7 +172,7 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}</>}
|
)}</>}
|
||||||
<div>
|
{(options?.canSetTags ?? true) && <div>
|
||||||
<p>Tags</p>
|
<p>Tags</p>
|
||||||
<div className="paper">
|
<div className="paper">
|
||||||
<TagsInput
|
<TagsInput
|
||||||
@ -169,7 +182,16 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
|
|||||||
separators={["Enter", ","]}
|
separators={["Enter", ","]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>}
|
||||||
|
{(options?.canSetContentWarning ?? true) && <div className="flex g12 content-warning">
|
||||||
|
<div>
|
||||||
|
<input type="checkbox" checked={contentWarning} onChange={e => setContentWarning(e.target.checked)} />
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="warning">NSFW Content</div>
|
||||||
|
Check here if this stream contains nudity or pornographic content.
|
||||||
|
</div>
|
||||||
|
</div>}
|
||||||
<div>
|
<div>
|
||||||
<AsyncButton
|
<AsyncButton
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -102,6 +102,34 @@ input[type="text"], textarea, input[type="datetime-local"], input[type="password
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"] {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 2px solid #333;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]:after {
|
||||||
|
content: ' ';
|
||||||
|
position: relative;
|
||||||
|
left: 40%;
|
||||||
|
top: 20%;
|
||||||
|
width: 15%;
|
||||||
|
height: 40%;
|
||||||
|
border: solid #fff;
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
transform: rotate(50deg);
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]:checked:after {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
div.paper {
|
div.paper {
|
||||||
background: #171717;
|
background: #171717;
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
@ -115,3 +143,11 @@ div.paper {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
color: #FF563F;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-warning {
|
||||||
|
border: 1px solid #FF563F;
|
||||||
|
}
|
@ -64,7 +64,7 @@ function ProfileInfo({ ev, goal }: { ev?: NostrEvent; goal?: TaggedRawEvent }) {
|
|||||||
)}
|
)}
|
||||||
{isMine && (
|
{isMine && (
|
||||||
<div className="actions">
|
<div className="actions">
|
||||||
{ev && <NewStreamDialog text="Edit" ev={ev} />}
|
{ev && <NewStreamDialog text="Edit" ev={ev} btnClassName="btn" />}
|
||||||
<AsyncButton
|
<AsyncButton
|
||||||
type="button"
|
type="button"
|
||||||
className="btn btn-red"
|
className="btn btn-red"
|
||||||
|
Loading…
Reference in New Issue
Block a user