Files
tyx_AI_xhs/apps/web/src/export-dialog.tsx
T

41 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState } from "react";
import { useDialogFocus } from "./dialog-focus.js";
import { exportResultCopy, type ExportFlowStatus } from "./export-flow.js";
import { EXPORT_DIMENSIONS, type ExportFormat, type ExportRatio } from "./export-compositor.js";
export function ExportDialog(props: {
busy: boolean;
byteSize?: number;
onClose: () => void;
onExport: (input: { format: ExportFormat; quality?: number }) => void;
onRetry: () => void;
pendingEdit: boolean;
ratio: ExportRatio;
result?: ExportFlowStatus;
}) {
const [format, setFormat] = useState<ExportFormat>("jpg");
const [quality, setQuality] = useState(92);
const [pendingConfirmed, setPendingConfirmed] = useState(false);
const dimensions = EXPORT_DIMENSIONS[props.ratio];
const failure = props.result && props.result !== "downloaded_and_saved";
const dialogRef = useDialogFocus(props.onClose);
return <div className="editor-dialog-backdrop"><section aria-labelledby="editor-export-title" aria-modal="true" className="editor-export-dialog" ref={dialogRef} role="dialog" tabIndex={-1}>
<header><div><p>EXPORT</p><h2 id="editor-export-title">导出成品</h2></div></header>
{props.result ? <div className={`editor-export-result ${failure ? "failed" : "succeeded"}`}>
<p aria-live={failure ? "assertive" : "polite"} role={failure ? "alert" : "status"}>{exportResultCopy[props.result]}</p>
{props.byteSize ? <small>{(props.byteSize / 1024 / 1024).toFixed(2)} MB</small> : null}
<div>{props.result === "download_failed" ? <button disabled={props.busy} onClick={props.onRetry} type="button">重新下载同一次合成</button> : null}<button disabled={props.busy} onClick={props.onClose} type="button">关闭</button></div>
</div> : <>
<section className="editor-export-section"><h3>文件格式</h3><div aria-label="导出格式" className="editor-export-segments" role="group">
<button aria-pressed={format === "jpg"} data-dialog-initial-focus onClick={() => setFormat("jpg")} type="button">JPG</button>
<button aria-pressed={format === "png"} onClick={() => setFormat("png")} type="button">PNG</button>
</div></section>
{format === "jpg" ? <section className="editor-export-section"><div className="editor-export-label"><h3>JPG 质量</h3><output>{quality}</output></div><div className="editor-export-quality"><input aria-label="JPG 质量" max="100" min="80" onChange={(event) => setQuality(Number(event.target.value))} step="1" type="range" value={quality} /><input aria-label="JPG 质量数值" max="100" min="80" onChange={(event) => setQuality(Math.max(80, Math.min(100, Number(event.target.value))))} step="1" type="number" value={quality} /></div></section> : null}
<section className="editor-export-summary"><span>输出尺寸</span><strong>{dimensions.width} × {dimensions.height} px</strong><span>色彩空间</span><strong>sRGB</strong><span>预计文件大小</span><strong>合成后显示</strong></section>
{props.pendingEdit ? <label className="editor-export-pending"><strong>导出前需要提交当前修改</strong><span><input checked={pendingConfirmed} onChange={(event) => setPendingConfirmed(event.target.checked)} type="checkbox" />将应用当前修改并导出</span></label> : null}
<footer><button className="editor-primary" disabled={props.busy || (props.pendingEdit && !pendingConfirmed)} onClick={() => props.onExport({ format, ...(format === "jpg" ? { quality } : {}) })} type="button">{props.busy ? "正在导出" : "导出并下载"}</button><button disabled={props.busy} onClick={props.onClose} type="button">取消</button></footer>
</>}
</section></div>;
}