feat(voiceover): surface script context and spoiler warnings on script pages
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
parent
92117374b7
commit
11ed89fd10
2 changed files with 44 additions and 4 deletions
|
|
@ -4,8 +4,9 @@ import { getPayload } from "payload";
|
||||||
import { headers as nextHeaders } from "next/headers";
|
import { headers as nextHeaders } from "next/headers";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { notFound, redirect } from "next/navigation";
|
import { notFound, redirect } from "next/navigation";
|
||||||
import { ArrowLeftIcon, MicIcon } from "lucide-react";
|
import { ArrowLeftIcon, MicIcon, TriangleAlertIcon } from "lucide-react";
|
||||||
|
|
||||||
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
import { VoiceoverRecorder } from "@/components/frontend/voiceover/VoiceoverRecorder";
|
import { VoiceoverRecorder } from "@/components/frontend/voiceover/VoiceoverRecorder";
|
||||||
import { getScriptForUser } from "@/lib/voiceover";
|
import { getScriptForUser } from "@/lib/voiceover";
|
||||||
import { isPayloadUser } from "@/utils/access-control/isPayloadUser";
|
import { isPayloadUser } from "@/utils/access-control/isPayloadUser";
|
||||||
|
|
@ -50,12 +51,30 @@ export default async function VoiceoverScriptPage({
|
||||||
<MicIcon className="mt-0.5 size-5 shrink-0 text-muted-foreground" />
|
<MicIcon className="mt-0.5 size-5 shrink-0 text-muted-foreground" />
|
||||||
<div className="flex min-w-0 flex-col gap-1">
|
<div className="flex min-w-0 flex-col gap-1">
|
||||||
<h1 className="text-lg font-semibold">{script.title}</h1>
|
<h1 className="text-lg font-semibold">{script.title}</h1>
|
||||||
|
{script.description?.trim() && (
|
||||||
|
<p className="text-sm text-foreground/80">{script.description}</p>
|
||||||
|
)}
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Read the script at your pace, then submit one clear take for review.
|
Read the script at your pace, then submit one clear take for review.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{script.spoiler && (
|
||||||
|
<Card className="border-amber-500/40">
|
||||||
|
<CardContent className="flex items-start gap-3 p-4 text-sm">
|
||||||
|
<TriangleAlertIcon className="mt-0.5 size-4 shrink-0 text-amber-400" />
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
<p className="font-medium text-amber-300">Potential campaign spoilers ahead</p>
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
This script may include, infer, or otherwise expose campaign spoilers. Read on only
|
||||||
|
if you are comfortable with that.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
<VoiceoverRecorder script={script} />
|
<VoiceoverRecorder script={script} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,14 @@ import { headers as nextHeaders } from "next/headers";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { getPayload } from "payload";
|
import { getPayload } from "payload";
|
||||||
import config from "@payload-config";
|
import config from "@payload-config";
|
||||||
import { ArrowRightIcon, CheckCircle2Icon, Clock3Icon, MicIcon, SparklesIcon } from "lucide-react";
|
import {
|
||||||
|
ArrowRightIcon,
|
||||||
|
CheckCircle2Icon,
|
||||||
|
Clock3Icon,
|
||||||
|
MicIcon,
|
||||||
|
SparklesIcon,
|
||||||
|
TriangleAlertIcon,
|
||||||
|
} from "lucide-react";
|
||||||
|
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
@ -64,6 +71,15 @@ function SubmissionStatuses({ script }: { readonly script: VoiceoverScriptView }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function SpoilerBadge() {
|
||||||
|
return (
|
||||||
|
<Badge variant="outline" className="gap-1 border-amber-500/40 text-amber-300">
|
||||||
|
<TriangleAlertIcon className="size-3" />
|
||||||
|
Spoilers
|
||||||
|
</Badge>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function ScriptCard({ script }: { readonly script: VoiceoverScriptView }) {
|
function ScriptCard({ script }: { readonly script: VoiceoverScriptView }) {
|
||||||
const isOpen = script.status === "open";
|
const isOpen = script.status === "open";
|
||||||
|
|
||||||
|
|
@ -84,9 +100,14 @@ function ScriptCard({ script }: { readonly script: VoiceoverScriptView }) {
|
||||||
script.title
|
script.title
|
||||||
)}
|
)}
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<CardDescription>Voiceover script #{script.id}</CardDescription>
|
<CardDescription>
|
||||||
|
{script.description?.trim() || `Voiceover script #${script.id}`}
|
||||||
|
</CardDescription>
|
||||||
|
</div>
|
||||||
|
<div className="flex shrink-0 flex-wrap items-center justify-end gap-2">
|
||||||
|
{script.spoiler && <SpoilerBadge />}
|
||||||
|
<ScriptAvailability status={script.status} />
|
||||||
</div>
|
</div>
|
||||||
<ScriptAvailability status={script.status} />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue