187 lines
7.7 KiB
TypeScript
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>
|
|
);
|
|
}
|