Files
buzz-sheet/components/public/artifact-image-export.tsx
T

187 lines
7.7 KiB
TypeScript

"use client";
import { useState, type ReactNode } from "react";
import { DownloadIcon } from "lucide-react";
import { GuideImageExport } from "@/components/public/guide-image-export";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Field, FieldGroup, FieldLabel } from "@/components/ui/field";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
const sectionOptions = [
["tierlist", "Artifact Tierlist"],
["best-stats", "Best Main Stats & Substats"],
["target-stats", "Target Stats"],
["talents", "Talent Priority"],
] as const;
type ArtifactExportSection = (typeof sectionOptions)[number][0];
export function ArtifactImageExport({
children,
fileName,
hasNote,
targetConditionLabels,
recommendedConditionLabels,
}: {
children: ReactNode;
fileName: string;
hasNote: boolean;
targetConditionLabels: readonly string[];
recommendedConditionLabels: readonly string[];
}) {
const [sections, setSections] = useState<Set<ArtifactExportSection>>(
() => new Set(sectionOptions.map(([value]) => value)),
);
const [includeNote, setIncludeNote] = useState(true);
const [recommendedCondition, setRecommendedCondition] = useState("0");
const [targetCondition, setTargetCondition] = useState("0");
const showNote = hasNote && includeNote;
const entireSection = sections.size === sectionOptions.length;
const hiddenSections = sectionOptions
.filter(([value]) => !sections.has(value))
.map(([value]) => `[data-artifact-export-section="${value}"]{display:none!important}`)
.join("");
const targetRule = `[data-target-condition]:not([data-target-condition="${targetCondition}"]){display:none!important}`;
const recommendedRule = `[data-recommended-condition]:not([data-recommended-condition="${recommendedCondition}"]){display:none!important}`;
const noteRule = showNote
? ""
: '[data-artifact-export-section="note"]{display:none!important}';
const onlySection = sections.size === 1 ? [...sections][0] : null;
const exportWidth = onlySection === "best-stats"
? 700
: onlySection === "target-stats" || onlySection === "talents"
? 800
: 1200;
const exportHeight = onlySection === "best-stats" ? 700 : undefined;
const hideEmptyRightColumn = !showNote && !sections.has("target-stats") && !sections.has("talents")
? ".artifact-export-right{display:none!important}"
: "";
const layoutRules = onlySection === "tierlist"
? ".artifact-export-grid{grid-template-columns:1fr!important}.artifact-export-tierlist{display:grid!important;grid-template-columns:repeat(2,minmax(0,1fr));gap:1.25rem}"
: onlySection === "best-stats"
? ".artifact-export-root{height:100%!important}.artifact-export-grid{grid-template-columns:1fr!important}.artifact-export-left{display:flex!important;flex-direction:column!important}.artifact-export-main-stats,.artifact-export-substats{width:480px!important;max-width:100%!important;margin-inline:auto!important}.artifact-export-main-stats{order:1!important}.artifact-export-substats{order:2!important}.artifact-export-right{width:100%!important}.guide-export-watermark{top:auto!important;bottom:16px!important}"
: onlySection === "target-stats" || onlySection === "talents"
? ".artifact-export-grid{display:block!important}.artifact-export-right{width:560px!important;max-width:100%;margin-left:auto!important;margin-right:auto!important;justify-self:center!important}"
: "";
return (
<Dialog>
<DialogTrigger render={<Button type="button" variant="outline" size="sm" />}>
<DownloadIcon data-icon="inline-start" />
ส่งออกภาพ
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>เลือกข้อมูลสำหรับส่งออก</DialogTitle>
<DialogDescription>
เลือกได้หลายส่วน หรือเลือก Entire Section เพื่อส่งออกทั้งหมด
</DialogDescription>
</DialogHeader>
<FieldGroup>
<Field orientation="horizontal">
<Checkbox
id="artifact-export-entire"
checked={entireSection}
onCheckedChange={(checked) => setSections(
checked ? new Set(sectionOptions.map(([value]) => value)) : new Set(),
)}
/>
<FieldLabel htmlFor="artifact-export-entire">Entire Section</FieldLabel>
</Field>
{sectionOptions.map(([value, label]) => (
<Field key={value} orientation="horizontal">
<Checkbox
id={`artifact-export-${value}`}
checked={sections.has(value)}
onCheckedChange={(checked) => {
setSections((current) => {
const next = new Set(current);
if (checked) next.add(value);
else next.delete(value);
return next;
});
}}
/>
<FieldLabel htmlFor={`artifact-export-${value}`}>{label}</FieldLabel>
</Field>
))}
{hasNote ? (
<Field orientation="horizontal">
<Checkbox
id="artifact-export-note"
checked={includeNote}
onCheckedChange={(checked) => setIncludeNote(checked === true)}
/>
<FieldLabel htmlFor="artifact-export-note">Add Note</FieldLabel>
</Field>
) : null}
</FieldGroup>
{sections.has("best-stats") && recommendedConditionLabels.length > 1 ? (
<div className="flex flex-col gap-2">
<p className="text-sm font-medium">Recommended Stats condition</p>
<ToggleGroup
variant="outline"
value={[recommendedCondition]}
onValueChange={(values) => {
if (values[0]) setRecommendedCondition(values[0]);
}}
>
{recommendedConditionLabels.map((label, index) => (
<ToggleGroupItem
key={index}
value={String(index)}
className="aria-pressed:bg-primary aria-pressed:text-primary-foreground"
>
{label}
</ToggleGroupItem>
))}
</ToggleGroup>
</div>
) : null}
{sections.has("target-stats") && targetConditionLabels.length > 1 ? (
<div className="flex flex-col gap-2">
<p className="text-sm font-medium">Target Stats condition</p>
<ToggleGroup
variant="outline"
value={[targetCondition]}
onValueChange={(values) => {
if (values[0]) setTargetCondition(values[0]);
}}
>
{targetConditionLabels.map((label, index) => (
<ToggleGroupItem
key={index}
value={String(index)}
className="aria-pressed:bg-primary aria-pressed:text-primary-foreground"
>
{label}
</ToggleGroupItem>
))}
</ToggleGroup>
</div>
) : null}
<GuideImageExport
fileName={fileName}
width={exportWidth}
height={exportHeight}
disabled={sections.size === 0}
captureClassName="p-0"
>
<style>{hiddenSections + targetRule + recommendedRule + noteRule + hideEmptyRightColumn + layoutRules}</style>
{children}
</GuideImageExport>
</DialogContent>
</Dialog>
);
}