Content warning

This commit is contained in:
Kieran 2023-07-06 16:08:51 +01:00
parent 62f5b36818
commit 76d0496ba1
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
5 changed files with 89 additions and 26 deletions

View File

@ -13,10 +13,8 @@ export function NostrProviderDialog({ provider, ...others }: { provider: StreamP
const [info, setInfo] = useState<StreamProviderInfo>();
useEffect(() => {
if (provider && !info) {
provider.info().then(v => setInfo(v));
}
}, [info, provider])
provider.info().then(v => setInfo(v));
}, [provider]);
if (!info) {
return <Spinner />
@ -74,7 +72,8 @@ export function NostrProviderDialog({ provider, ...others }: { provider: StreamP
others.onFinish?.(ex);
}} ev={streamEvent} options={{
canSetStream: false,
canSetStatus: false
canSetStatus: false,
canSetContentWarning: false
}} />}
</>
}

View File

@ -11,4 +11,10 @@
padding: 4px 10px !important;
border-radius: 12px !important;
display: unset !important;
}
.content-warning {
padding: 16px;
border-radius: 16px;
border: 1px solid #FF563F;
}

View File

@ -17,23 +17,33 @@ export interface StreamEditorProps {
canSetImage?: boolean
canSetStatus?: boolean
canSetStream?: boolean
canSetTags?: boolean
canSetContentWarning?: boolean
}
}
export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
const [title, setTitle] = useState(findTag(ev, "title") ?? "");
const [summary, setSummary] = useState(findTag(ev, "summary") ?? "");
const [image, setImage] = useState(findTag(ev, "image") ?? "");
const [stream, setStream] = useState(findTag(ev, "streaming") ?? "");
const [status, setStatus] = useState(
findTag(ev, "status") ?? StreamState.Live
);
const [start, setStart] = useState(findTag(ev, "starts"));
const [tags, setTags] = useState(
ev?.tags.filter(a => a[0] === "t").map(a => a[1]) ?? []
);
const [title, setTitle] = useState("");
const [summary, setSummary] = useState("");
const [image, setImage] = useState("");
const [stream, setStream] = useState("");
const [status, setStatus] = useState("");
const [start, setStart] = useState<string>();
const [tags, setTags] = useState<string[]>([]);
const [contentWarning, setContentWarning] = 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(() => {
if (title.length < 2) {
return false;
@ -73,6 +83,9 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
for (const tx of tags) {
eb.tag(["t", tx.trim()]);
}
if(contentWarning) {
eb.tag(["content-warning", "nsfw"])
}
return eb;
});
console.debug(evNew);
@ -91,7 +104,7 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
return (
<>
<h3>{ev ? "Edit Stream" : "New Stream"}</h3>
{(options?.canSetTitle === undefined || options.canSetTitle) && <div>
{(options?.canSetTitle ?? true) && <div>
<p>Title</p>
<div className="paper">
<input
@ -101,7 +114,7 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
onChange={(e) => setTitle(e.target.value)} />
</div>
</div>}
{(options?.canSetSummary === undefined || options.canSetSummary) && <div>
{(options?.canSetSummary ?? true) && <div>
<p>Summary</p>
<div className="paper">
<input
@ -111,7 +124,7 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
onChange={(e) => setSummary(e.target.value)} />
</div>
</div>}
{(options?.canSetImage === undefined || options.canSetImage) && <div>
{(options?.canSetImage ?? true) && <div>
<p>Cover image</p>
<div className="paper">
<input
@ -121,7 +134,7 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
onChange={(e) => setImage(e.target.value)} />
</div>
</div>}
{(options?.canSetStream === undefined || options.canSetStream) && <div>
{(options?.canSetStream ?? true) && <div>
<p>Stream Url</p>
<div className="paper">
<input
@ -132,7 +145,7 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
</div>
<small>Stream type should be HLS</small>
</div>}
{(options?.canSetStatus === undefined || options.canSetStatus) && <><div>
{(options?.canSetStatus ?? true) && <><div>
<p>Status</p>
<div className="flex g12">
{[StreamState.Live, StreamState.Planned, StreamState.Ended].map(
@ -151,7 +164,7 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
{status === StreamState.Planned && (
<div>
<p>Start Time</p>
<div className="input">
<div className="paper">
<input
type="datetime-local"
value={toDateTimeString(Number(start ?? "0"))}
@ -159,17 +172,26 @@ export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
</div>
</div>
)}</>}
<div>
{(options?.canSetTags ?? true) && <div>
<p>Tags</p>
<div className="paper">
<TagsInput
value={tags}
onChange={setTags}
placeHolder="Music,DJ,English"
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 className="warning">NSFW Content</div>
Check here if this stream contains nudity or pornographic content.
</div>
</div>}
<div>
<AsyncButton
type="button"

View File

@ -102,6 +102,34 @@ input[type="text"], textarea, input[type="datetime-local"], input[type="password
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 {
background: #171717;
border-radius: 16px;
@ -114,4 +142,12 @@ div.paper {
.scroll-lock {
overflow: hidden;
height: 100vh;
}
.warning {
color: #FF563F;
}
.border-warning {
border: 1px solid #FF563F;
}

View File

@ -56,7 +56,7 @@ function ProfileInfo({ ev }: { ev?: NostrEvent }) {
{isMine && (
<div className="actions">
{ev && (
<NewStreamDialog text="Edit" ev={ev} />
<NewStreamDialog text="Edit" ev={ev} btnClassName="btn"/>
)}
<AsyncButton
type="button"