feat : add language export and some image gen optimaize

This commit is contained in:
2026-09-15 17:50:20 +07:00 Unverified
parent 5f1d2bccc9
commit 072310091d
9 changed files with 307 additions and 162 deletions
+39 -5
View File
@@ -6,6 +6,11 @@ import { DownloadIcon } from "lucide-react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import {
ExportLanguageToggle,
useExportLanguage,
type ExportLanguage,
} from "@/components/public/export-language";
import { Spinner } from "@/components/ui/spinner";
import { cn } from "@/lib/utils";
@@ -21,6 +26,21 @@ function downloadFileName(value: string): string {
return value.replace(/[\\/:*?"<>|]/gu, "-");
}
export function imageExportFileName(
fileName: string,
language: ExportLanguage,
withoutNotes: boolean,
localized = true,
): string {
const selectedFileName = withoutNotes ? withoutNotesFileName(fileName) : fileName;
const languageFileName = localized
? (/\.[^.]+$/u.test(selectedFileName)
? selectedFileName.replace(/(\.[^.]+)$/u, `-${language}$1`)
: `${selectedFileName}-${language}`)
: selectedFileName;
return downloadFileName(languageFileName);
}
export function GuideImageExport({
children,
fileName,
@@ -31,6 +51,9 @@ export function GuideImageExport({
allowWithoutNotes = true,
captureClassName,
buttonLabel = "ส่งออกภาพ",
language: controlledLanguage,
showLanguageSelector = true,
localizeFileName = true,
}: {
children: ReactNode;
fileName: string;
@@ -41,12 +64,17 @@ export function GuideImageExport({
allowWithoutNotes?: boolean;
captureClassName?: string;
buttonLabel?: string;
language?: ExportLanguage;
showLanguageSelector?: boolean;
localizeFileName?: boolean;
}) {
const captureRef = useRef<HTMLDivElement>(null);
const [captureMode, setCaptureMode] = useState<
"with-notes" | "without-notes" | null
>(null);
const capturing = captureMode !== null;
const [storedLanguage, setStoredLanguage] = useExportLanguage();
const language = controlledLanguage ?? storedLanguage;
useEffect(() => {
if (!capturing) return;
@@ -88,10 +116,11 @@ export function GuideImageExport({
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.download = downloadFileName(
captureMode === "without-notes"
? withoutNotesFileName(fileName)
: fileName,
link.download = imageExportFileName(
fileName,
language,
captureMode === "without-notes",
localizeFileName,
);
link.href = url;
document.body.append(link);
@@ -109,10 +138,13 @@ export function GuideImageExport({
return () => {
cancelled = true;
};
}, [capturing, captureMode, fileName, format, height, width]);
}, [capturing, captureMode, fileName, format, height, language, localizeFileName, width]);
return (
<>
{showLanguageSelector ? (
<ExportLanguageToggle language={language} onChange={setStoredLanguage} />
) : null}
<div className="flex flex-wrap gap-2">
{(["with-notes", "without-notes"] as const).filter((mode) => allowWithoutNotes || mode === "with-notes").map((mode) => (
<Button
@@ -144,12 +176,14 @@ export function GuideImageExport({
>
<div
ref={captureRef}
data-export-language={language}
className={cn(
"bg-background p-10 text-foreground",
captureClassName,
)}
style={{ width, height }}
>
<style>{'[data-export-language="th"] [data-export-lang="en"],[data-export-language="en"] [data-export-lang="th"]{display:none!important}'}</style>
{children}
</div>
</div>,