feat: support content warning
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { cn } from "@lume/utils";
|
import { cn } from "@lume/utils";
|
||||||
import { useRouteContext } from "@tanstack/react-router";
|
import { useRouteContext } from "@tanstack/react-router";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import { type ReactNode, useMemo } from "react";
|
import { type ReactNode, useMemo, useState } from "react";
|
||||||
import reactStringReplace from "react-string-replace";
|
import reactStringReplace from "react-string-replace";
|
||||||
import { Hashtag } from "./mentions/hashtag";
|
import { Hashtag } from "./mentions/hashtag";
|
||||||
import { MentionNote } from "./mentions/note";
|
import { MentionNote } from "./mentions/note";
|
||||||
@@ -23,6 +23,8 @@ export function NoteContent({
|
|||||||
}) {
|
}) {
|
||||||
const { settings } = useRouteContext({ strict: false });
|
const { settings } = useRouteContext({ strict: false });
|
||||||
const event = useNoteContext();
|
const event = useNoteContext();
|
||||||
|
|
||||||
|
const warning = useMemo(() => event.warning, [event]);
|
||||||
const content = useMemo(() => {
|
const content = useMemo(() => {
|
||||||
try {
|
try {
|
||||||
// Get parsed meta
|
// Get parsed meta
|
||||||
@@ -91,8 +93,29 @@ export function NoteContent({
|
|||||||
}
|
}
|
||||||
}, [event.content]);
|
}, [event.content]);
|
||||||
|
|
||||||
|
const [blurred, setBlurred] = useState(() => warning?.length > 0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-2">
|
<div className="relative flex flex-col gap-2">
|
||||||
|
{blurred ? (
|
||||||
|
<div className="absolute inset-0 z-10 flex items-center justify-center w-full h-full bg-black/80 backdrop-blur-xl">
|
||||||
|
<div className="flex flex-col items-center justify-center gap-2 text-center">
|
||||||
|
<p className="text-sm text-white/60">
|
||||||
|
The content is hidden because the author
|
||||||
|
<br />
|
||||||
|
marked it with a warning for a reason:
|
||||||
|
</p>
|
||||||
|
<p className="text-sm font-medium text-white">{warning}</p>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setBlurred(false)}
|
||||||
|
className="inline-flex items-center justify-center px-2 mt-4 text-sm font-medium border rounded-lg text-white/70 h-9 w-max bg-white/20 hover:bg-white/30 border-white/5"
|
||||||
|
>
|
||||||
|
View anyway
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"select-text text-pretty content-break overflow-hidden",
|
"select-text text-pretty content-break overflow-hidden",
|
||||||
@@ -104,12 +127,16 @@ export function NoteContent({
|
|||||||
>
|
>
|
||||||
{content}
|
{content}
|
||||||
</div>
|
</div>
|
||||||
{settings.display_media && event.meta?.images.length ? (
|
{settings.display_media ? (
|
||||||
|
<>
|
||||||
|
{event.meta?.images.length ? (
|
||||||
<Images urls={event.meta.images} />
|
<Images urls={event.meta.images} />
|
||||||
) : null}
|
) : null}
|
||||||
{settings.display_media && event.meta?.videos.length ? (
|
{event.meta?.videos.length ? (
|
||||||
<Videos urls={event.meta.videos} />
|
<Videos urls={event.meta.videos} />
|
||||||
) : null}
|
) : null}
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,11 +25,6 @@ export class LumeEvent {
|
|||||||
Object.assign(this, event);
|
Object.assign(this, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
get isWarning() {
|
|
||||||
const tag = this.tags.find((tag) => tag[0] === "content-warning");
|
|
||||||
return tag?.[1]; // return: reason;
|
|
||||||
}
|
|
||||||
|
|
||||||
get isQuote() {
|
get isQuote() {
|
||||||
return this.tags.filter((tag) => tag[0] === "q").length > 0;
|
return this.tags.filter((tag) => tag[0] === "q").length > 0;
|
||||||
}
|
}
|
||||||
@@ -95,6 +90,26 @@ export class LumeEvent {
|
|||||||
return { id, relayHint };
|
return { id, relayHint };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get warning() {
|
||||||
|
const warningTag = this.tags.filter(
|
||||||
|
(tag) => tag[0] === "content-warning",
|
||||||
|
)?.[0];
|
||||||
|
|
||||||
|
if (warningTag) {
|
||||||
|
return warningTag[1];
|
||||||
|
} else {
|
||||||
|
const nsfwTag = this.tags.filter(
|
||||||
|
(tag) => tag[0] === "t" && tag[1] === "NSFW",
|
||||||
|
)?.[0];
|
||||||
|
|
||||||
|
if (nsfwTag) {
|
||||||
|
return "NSFW";
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async getAllReplies() {
|
public async getAllReplies() {
|
||||||
const query = await commands.getReplies(this.id);
|
const query = await commands.getReplies(this.id);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user