fix(report): toast a missing English edition and tint export selection

Opening the export sheet now says once, at the top, why English is unavailable. Selected borders, radios and checks use the theme color while fills stay neutral.

Co-Authored-By: Grok (agent loop)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jesse-ux
2026-10-21 23:13:15 +08:00
co-authored by Grok (agent loop) Cursor
parent 9812f31737
commit a2f65842e6
12 changed files with 194 additions and 28 deletions
+4 -4
View File
@@ -4108,15 +4108,15 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
.report-export-field { display: grid; gap: var(--space-2); }
.report-export-segment { display: grid; grid-template-columns: 1fr 1fr; padding: 3px; border-radius: var(--radius-md); background: var(--color-canvas-muted); }
.report-export-segment button { border: 0; border-radius: calc(var(--radius-md) - 2px); background: transparent; color: var(--color-ink-secondary); font: inherit; font-size: var(--type-body-sm); cursor: pointer; }
.report-export-segment button[aria-checked="true"] { background: var(--color-canvas); color: var(--color-ink); font-weight: 600; box-shadow: 0 1px 2px color-mix(in srgb, var(--color-ink) 12%, transparent); }
.report-export-segment button[aria-checked="true"] { background: var(--color-canvas); color: var(--color-action); font-weight: 600; box-shadow: 0 1px 2px color-mix(in srgb, var(--color-ink) 12%, transparent), inset 0 0 0 1px var(--color-action-strong); }
.report-export-caption { margin: 0; color: var(--color-ink-tertiary); font-size: var(--type-caption); line-height: 1.5; }
.report-export-modes { display: grid; gap: var(--space-2); }
.report-export-mode { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); border: 1px solid var(--color-border); border-radius: var(--radius-md); background: transparent; color: var(--color-ink); font: inherit; text-align: left; cursor: pointer; }
.report-export-mode[aria-checked="true"] { border-color: var(--color-ink-secondary); background: var(--color-canvas-muted); }
.report-export-mode[aria-checked="true"] { border-color: var(--color-action-strong); background: transparent; }
.report-export-mode strong { display: block; font-size: var(--type-body-md); font-weight: 600; }
.report-export-mode small { display: block; margin-top: 2px; color: var(--color-ink-tertiary); font-size: var(--type-caption); }
.report-export-radio { flex-shrink: 0; width: 18px; height: 18px; border: 1.5px solid var(--color-border-strong); border-radius: 50%; }
.report-export-mode[aria-checked="true"] .report-export-radio { border: 5px solid var(--color-ink); }
.report-export-mode[aria-checked="true"] .report-export-radio { border: 5px solid var(--color-action-strong); }
.report-export-list { display: grid; gap: var(--space-1); }
.report-export-group + .report-export-group { border-top: 1px solid var(--color-border); padding-top: var(--space-1); }
.report-export-group-head { display: flex; align-items: center; }
@@ -4127,7 +4127,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
.report-export-row small { margin-left: var(--space-2); color: var(--color-ink-tertiary); font-size: var(--type-caption); font-weight: 400; font-variant-numeric: tabular-nums; }
.report-export-box { flex-shrink: 0; display: grid; place-items: center; width: 18px; height: 18px; border: 1.5px solid var(--color-border-strong); border-radius: 4px; color: var(--color-canvas); }
.report-export-box svg { width: 13px; height: 13px; stroke-width: 3; }
.report-export-row:is([aria-checked="true"], [aria-checked="mixed"]) .report-export-box { border-color: var(--color-ink); background: var(--color-ink); }
.report-export-row:is([aria-checked="true"], [aria-checked="mixed"]) .report-export-box { border-color: var(--color-action-strong); background: var(--color-action-strong); }
.report-export-expand { flex-shrink: 0; border: 0; background: transparent; color: var(--color-ink-secondary); cursor: pointer; }
.report-export-expand svg { width: 18px; height: 18px; transition: transform 140ms ease-out; }
.report-export-expand[aria-expanded="true"] svg { transform: rotate(90deg); }
@@ -4,7 +4,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
import { Check, ChevronRight, Minus, X } from "lucide-react";
import { detectPrintRestriction } from "@/lib/client-report-export";
import { downloadMarkdownReport } from "@/lib/consultation-report-export";
import { notifyError, notifySuccess } from "@/lib/notify";
import { notifyError, notifyInfo, notifySuccess } from "@/lib/notify";
import { exportByteSize, exportFilename, formatExportSize, joinExportBlocks, type ReportExportBlock } from "@/lib/report-export-blocks";
import { Button } from "@/components/ui/button";
import type { EnglishEditionStatus, ReportLanguage } from "@/lib/report-language";
@@ -52,11 +52,22 @@ export function ReportExportDrawer({ editions, initialLanguage = "zh", englishEd
const element = dialog.current;
const previous = document.activeElement;
element?.showModal();
// Once per open. The sheet remounts every time it opens, so this mount effect
// is the open. Later picks and language switches must not raise it again.
// Same id collapses React Strict Mode's double invoke into one toast.
if (!hasEnglish) {
notifyInfo(
englishEdition === "unavailable"
? "这份报告的英文版没有生成成功,只能导出中文版。"
: "这份报告生成于英文版上线前,重新生成即可获得中英两版。",
{ id: "report-export-english" },
);
}
return () => {
element?.close();
if (previous instanceof HTMLElement && previous.isConnected) previous.focus({ preventScroll: true });
};
}, []);
}, []); // eslint-disable-line react-hooks/exhaustive-deps -- notify once per open, after showModal
function switchLanguage(next: ReportLanguage) {
if (next === language) return;
@@ -119,11 +130,7 @@ export function ReportExportDrawer({ editions, initialLanguage = "zh", englishEd
</div>
<p className="report-export-caption">拿去问 ChatGPT、Claude 等 AI,建议选 English,术语与原典一致。</p>
</div>
) : (
<p className="report-export-caption">
{englishEdition === "unavailable" ? "这份报告的英文版没有生成成功,只能导出中文版。" : "这份报告生成于英文版上线前,重新生成即可获得中英两版。"}
</p>
)}
) : null}
<div className="report-export-modes" role="radiogroup" aria-label="导出范围">
<button type="button" role="radio" aria-checked={mode === "whole"} className="report-export-mode" onClick={() => setMode("whole")}>