style: enlarge leaderboard report dialog
This commit is contained in:
1 parent
d59f9e218f
commit
0d91c74289
1 file changed
+98
-101
@@ -25,7 +25,7 @@ import {
|
|||||||
Users,
|
Users,
|
||||||
type LucideIcon,
|
type LucideIcon,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { useEffect, useId, useMemo, useRef, useState } from "react";
|
import { useEffect, useId, useMemo, useRef, useState, type ReactNode } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
@@ -521,9 +521,87 @@ function TrendBars({ points, compact = false }: { points: AdminLeaderboardTrendP
|
|||||||
const displayedSeries = metric === "all" ? series : [activeSeries];
|
const displayedSeries = metric === "all" ? series : [activeSeries];
|
||||||
const totalFor = (key: TrendMetric) => visible.reduce((sum, point) => sum + Number(point[key] ?? 0), 0);
|
const totalFor = (key: TrendMetric) => visible.reduce((sum, point) => sum + Number(point[key] ?? 0), 0);
|
||||||
const activeDays = visible.filter((point) => point.runs > 0 || point.questions > 0 || point.tokens > 0).length;
|
const activeDays = visible.filter((point) => point.runs > 0 || point.questions > 0 || point.tokens > 0).length;
|
||||||
|
const metricCards = ({ includeAll = true, large = false }: { includeAll?: boolean; large?: boolean } = {}) => (
|
||||||
|
<div className={cn("grid gap-2", includeAll ? "sm:grid-cols-2 xl:grid-cols-5" : "sm:grid-cols-4")}>
|
||||||
|
{includeAll && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setMetric("all")}
|
||||||
|
className={cn(
|
||||||
|
"min-w-0 rounded-lg border px-3 py-2 text-left transition hover:-translate-y-0.5 hover:shadow-sm",
|
||||||
|
large && "px-4 py-3",
|
||||||
|
metric === "all"
|
||||||
|
? "border-[#C1121F] bg-[#FFF1F1] shadow-sm dark:border-[#F2B8BB]/40 dark:bg-[#3A1215]"
|
||||||
|
: "border-[#F1D6D6] bg-white dark:border-[#462123] dark:bg-[#230D0F]",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<span className="inline-flex rounded-full bg-[#FFF1F1] px-2 py-0.5 text-xs font-medium text-[#C1121F]">全部趋势</span>
|
||||||
|
<span className={cn("mt-2 block font-semibold tabular-nums text-[#231815] dark:text-white", large ? "text-2xl" : "text-lg")}>
|
||||||
|
{fmtNumber(visible.reduce((sum, point) => sum + point.runs + point.questions + point.users, 0))}
|
||||||
|
</span>
|
||||||
|
{large && <span className="mt-1 block truncate text-xs text-[#8B6B6B] dark:text-[#D8B8B8]">同时显示运行、问答、活跃与 Token</span>}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{series.map((item) => (
|
||||||
|
<button
|
||||||
|
key={item.key}
|
||||||
|
type="button"
|
||||||
|
onClick={() => setMetric(item.key)}
|
||||||
|
className={cn(
|
||||||
|
"min-w-0 rounded-lg border px-3 py-2 text-left transition hover:-translate-y-0.5 hover:shadow-sm",
|
||||||
|
large && "px-4 py-3",
|
||||||
|
metric === item.key
|
||||||
|
? "border-[#C1121F] bg-[#FFF1F1] shadow-sm dark:border-[#F2B8BB]/40 dark:bg-[#3A1215]"
|
||||||
|
: "border-[#F1D6D6] bg-white dark:border-[#462123] dark:bg-[#230D0F]",
|
||||||
|
)}
|
||||||
|
title={item.description}
|
||||||
|
>
|
||||||
|
<span className={cn("inline-flex rounded-full px-2 py-0.5 text-xs font-medium", item.soft)}>{item.label}</span>
|
||||||
|
<span className={cn("mt-2 block truncate font-semibold tabular-nums text-[#111827] dark:text-white", large ? "text-2xl" : compact ? "text-base" : "text-lg")}>
|
||||||
|
{fmtNumber(totalFor(item.key))}
|
||||||
|
</span>
|
||||||
|
{(large || compact) && <span className="mt-1 block truncate text-[11px] text-[#8B6B6B] dark:text-[#D8B8B8]">{item.description}</span>}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const analysisDialog = (title: string, description: ReactNode) => (
|
||||||
|
<Dialog>
|
||||||
|
<DialogTrigger asChild>
|
||||||
|
<Button variant="outline" size="sm" className={compact ? "h-8" : undefined}>
|
||||||
|
<Maximize2 className="mr-1 size-4" />
|
||||||
|
{compact ? "放大" : "放大分析"}
|
||||||
|
</Button>
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent className="flex h-[92vh] w-[96vw] max-w-none flex-col gap-4 overflow-hidden p-5 sm:max-w-none">
|
||||||
|
<DialogHeader className="shrink-0 pr-10">
|
||||||
|
<DialogTitle>{title}</DialogTitle>
|
||||||
|
<DialogDescription>{description}</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<div className="shrink-0">{metricCards({ includeAll: true, large: true })}</div>
|
||||||
|
<div className="grid min-h-0 flex-1 gap-3 lg:grid-cols-[260px_minmax(0,1fr)]">
|
||||||
|
<div className="rounded-lg border border-[#F1D6D6] bg-white p-4 dark:border-[#462123] dark:bg-[#230D0F]">
|
||||||
|
<div className="text-xs text-[#7A5A5A] dark:text-[#D8B8B8]">当前查看</div>
|
||||||
|
<div className="mt-2 text-2xl font-semibold text-[#111827] dark:text-white">{metric === "all" ? "全部指标" : activeSeries.label}</div>
|
||||||
|
<div className="mt-5 text-xs text-[#7A5A5A] dark:text-[#D8B8B8]">最新 {metric === "all" ? "运行" : activeSeries.label}</div>
|
||||||
|
<div className="mt-2 text-4xl font-semibold tabular-nums text-[#111827] dark:text-white">{fmtNumber(latestValue)}</div>
|
||||||
|
<div className={cn("mt-3 text-sm", delta >= 0 ? "text-[#C1121F]" : "text-[#7F1D1D] dark:text-[#FCA5A5]")}>
|
||||||
|
较上一日 {delta >= 0 ? "+" : ""}{fmtNumber(delta)}
|
||||||
|
</div>
|
||||||
|
<div className="mt-5 text-xs text-[#7A5A5A] dark:text-[#D8B8B8]">
|
||||||
|
峰值 {peak.date} / {fmtNumber(Number(peak[activeMetric] ?? 0))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{chart(true)}
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
|
||||||
const chart = (large = false) => (
|
const chart = (large = false) => (
|
||||||
<div className={cn("min-w-0 overflow-hidden rounded-xl border border-[#E5E7EB] bg-[#F9FAFB] p-3 dark:border-[#3F3F46] dark:bg-[#18181B]", large && "p-5")}>
|
<div className={cn("min-w-0 overflow-hidden rounded-xl border border-[#E5E7EB] bg-[#F9FAFB] p-3 dark:border-[#3F3F46] dark:bg-[#18181B]", large && "flex min-h-0 p-5")}>
|
||||||
<svg viewBox={`0 0 ${width} ${height}`} className={cn("w-full", large ? "h-[520px]" : compact ? "h-56" : "h-72")} role="img" aria-label="使用趋势折线图">
|
<svg viewBox={`0 0 ${width} ${height}`} className={cn("w-full", large ? "h-full min-h-[420px]" : compact ? "h-56" : "h-72")} role="img" aria-label="使用趋势折线图">
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient id={`trend-area-${chartId}-${activeMetric}`} x1="0" x2="0" y1="0" y2="1">
|
<linearGradient id={`trend-area-${chartId}-${activeMetric}`} x1="0" x2="0" y1="0" y2="1">
|
||||||
<stop offset="0%" stopColor={activeSeries.color} stopOpacity="0.22" />
|
<stop offset="0%" stopColor={activeSeries.color} stopOpacity="0.22" />
|
||||||
@@ -598,47 +676,13 @@ function TrendBars({ points, compact = false }: { points: AdminLeaderboardTrendP
|
|||||||
if (compact) {
|
if (compact) {
|
||||||
return (
|
return (
|
||||||
<div className="min-w-0 space-y-3">
|
<div className="min-w-0 space-y-3">
|
||||||
<div className="grid gap-2 sm:grid-cols-4">
|
{metricCards({ includeAll: false })}
|
||||||
{series.map((item) => (
|
|
||||||
<button
|
|
||||||
key={item.key}
|
|
||||||
type="button"
|
|
||||||
onClick={() => setMetric(item.key)}
|
|
||||||
className={cn(
|
|
||||||
"min-w-0 rounded-lg border px-3 py-2 text-left transition hover:border-[#C1121F]",
|
|
||||||
metric === item.key
|
|
||||||
? "border-[#C1121F] bg-[#FFF1F1] dark:bg-[#3A1215]"
|
|
||||||
: "border-[#F1D6D6] bg-white dark:border-[#462123] dark:bg-[#230D0F]",
|
|
||||||
)}
|
|
||||||
title={item.description}
|
|
||||||
>
|
|
||||||
<span className={cn("inline-flex rounded-full px-2 py-0.5 text-xs font-medium", item.soft)}>{item.label}</span>
|
|
||||||
<span className="mt-2 block truncate text-base font-semibold tabular-nums text-[#231815] dark:text-white">
|
|
||||||
{fmtNumber(totalFor(item.key))}
|
|
||||||
</span>
|
|
||||||
<span className="mt-1 block truncate text-[11px] text-[#8B6B6B] dark:text-[#D8B8B8]">{item.description}</span>
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-wrap items-center justify-between gap-2 text-xs text-[#7A5A5A] dark:text-[#D8B8B8]">
|
<div className="flex flex-wrap items-center justify-between gap-2 text-xs text-[#7A5A5A] dark:text-[#D8B8B8]">
|
||||||
<span>每个点代表 1 天;当前显示 {metric === "all" ? "全部指标" : activeSeries.label},覆盖 {activeDays} 个活跃日。</span>
|
<span>每个点代表 1 天;当前显示 {metric === "all" ? "全部指标" : activeSeries.label},覆盖 {activeDays} 个活跃日。</span>
|
||||||
<Dialog>
|
{analysisDialog(
|
||||||
<DialogTrigger asChild>
|
"个人使用趋势",
|
||||||
<Button variant="outline" size="sm" className="h-8">
|
"每个折线点代表一天。运行=发起次数,问答=有效提问,活跃=有行为的用户数,Token=模型输入输出消耗。",
|
||||||
<Maximize2 className="mr-1 size-4" />
|
)}
|
||||||
放大
|
|
||||||
</Button>
|
|
||||||
</DialogTrigger>
|
|
||||||
<DialogContent className="max-w-[min(1180px,calc(100vw-2rem))]">
|
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle>个人使用趋势</DialogTitle>
|
|
||||||
<DialogDescription>
|
|
||||||
每个折线点代表一天。运行=发起次数,问答=有效提问,活跃=有行为的用户数,Token=模型输入输出消耗。
|
|
||||||
</DialogDescription>
|
|
||||||
</DialogHeader>
|
|
||||||
{chart(true)}
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
</div>
|
</div>
|
||||||
{chart(false)}
|
{chart(false)}
|
||||||
</div>
|
</div>
|
||||||
@@ -651,58 +695,11 @@ function TrendBars({ points, compact = false }: { points: AdminLeaderboardTrendP
|
|||||||
每个折线点代表一天;点击指标卡可单独查看运行、问答、活跃或 Token,全部趋势会同时展示四条多色折线。
|
每个折线点代表一天;点击指标卡可单独查看运行、问答、活跃或 Token,全部趋势会同时展示四条多色折线。
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||||
<div className="grid gap-2 sm:grid-cols-2 xl:grid-cols-5">
|
<div className="min-w-0 flex-1">{metricCards()}</div>
|
||||||
<button
|
{analysisDialog(
|
||||||
type="button"
|
"时间趋势分析",
|
||||||
onClick={() => setMetric("all")}
|
<>当前查看 {metric === "all" ? "全部指标" : activeSeries.label},峰值 {peak.date} / {fmtNumber(Number(peak[activeMetric] ?? 0))}。</>,
|
||||||
className={cn(
|
)}
|
||||||
"rounded-lg border px-3 py-2 text-left transition hover:-translate-y-0.5 hover:shadow-sm",
|
|
||||||
metric === "all"
|
|
||||||
? "border-[#C1121F] bg-[#FFF1F1] shadow-sm dark:border-[#F2B8BB]/40 dark:bg-[#3A1215]"
|
|
||||||
: "border-[#F1D6D6] bg-white dark:border-[#462123] dark:bg-[#230D0F]",
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<span className="inline-flex rounded-full bg-[#FFF1F1] px-2 py-0.5 text-xs font-medium text-[#C1121F]">全部趋势</span>
|
|
||||||
<span className="mt-2 block text-lg font-semibold tabular-nums text-[#231815] dark:text-white">
|
|
||||||
{fmtNumber(visible.reduce((sum, point) => sum + point.runs + point.questions + point.users, 0))}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
{series.map((item) => (
|
|
||||||
<button
|
|
||||||
key={item.key}
|
|
||||||
type="button"
|
|
||||||
onClick={() => setMetric(item.key)}
|
|
||||||
className={cn(
|
|
||||||
"rounded-lg border px-3 py-2 text-left transition hover:-translate-y-0.5 hover:shadow-sm",
|
|
||||||
metric === item.key
|
|
||||||
? "border-[#C1121F] bg-[#FFF1F1] shadow-sm dark:border-[#F2B8BB]/40 dark:bg-[#3A1215]"
|
|
||||||
: "border-[#F1D6D6] bg-white dark:border-[#462123] dark:bg-[#230D0F]",
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<span className={cn("inline-flex rounded-full px-2 py-0.5 text-xs font-medium", item.soft)}>{item.label}</span>
|
|
||||||
<span className="mt-2 block text-lg font-semibold tabular-nums text-[#111827] dark:text-white">
|
|
||||||
{fmtNumber(visible.reduce((sum, point) => sum + Number(point[item.key] ?? 0), 0))}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<Dialog>
|
|
||||||
<DialogTrigger asChild>
|
|
||||||
<Button variant="outline" size="sm">
|
|
||||||
<Maximize2 className="mr-1 size-4" />
|
|
||||||
放大分析
|
|
||||||
</Button>
|
|
||||||
</DialogTrigger>
|
|
||||||
<DialogContent className="max-w-[min(1180px,calc(100vw-2rem))]">
|
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle>时间趋势分析</DialogTitle>
|
|
||||||
<DialogDescription>
|
|
||||||
当前查看 {metric === "all" ? "全部指标" : activeSeries.label},峰值 {peak.date} / {fmtNumber(Number(peak[activeMetric] ?? 0))}。
|
|
||||||
</DialogDescription>
|
|
||||||
</DialogHeader>
|
|
||||||
{chart(true)}
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="grid gap-3 lg:grid-cols-[220px_minmax(0,1fr)]">
|
<div className="grid gap-3 lg:grid-cols-[220px_minmax(0,1fr)]">
|
||||||
<div className="rounded-xl border border-[#F1D6D6] bg-white p-4 dark:border-[#462123] dark:bg-[#230D0F]">
|
<div className="rounded-xl border border-[#F1D6D6] bg-white p-4 dark:border-[#462123] dark:bg-[#230D0F]">
|
||||||
@@ -1260,14 +1257,14 @@ export default function AdminUserLeaderboardPage() {
|
|||||||
AI 报告
|
AI 报告
|
||||||
</Button>
|
</Button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent className="max-w-[min(920px,calc(100vw-2rem))]">
|
<DialogContent className="flex h-[92vh] w-[96vw] max-w-none flex-col gap-0 overflow-hidden p-0 sm:max-w-none">
|
||||||
<DialogHeader>
|
<DialogHeader className="shrink-0 border-b border-[#F1D6D6] px-6 py-5 pr-12 dark:border-[#462123]">
|
||||||
<DialogTitle>AI 榜单分析报告</DialogTitle>
|
<DialogTitle>AI 榜单分析报告</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
基于当前时间段的问答、用户、技能、模型和趋势统计生成运营分析。
|
基于当前时间段的问答、用户、技能、模型和趋势统计生成运营分析。
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-[#F1D6D6] bg-white p-3 dark:border-[#462123] dark:bg-[#230D0F]">
|
<div className="mx-6 mt-4 flex shrink-0 flex-wrap items-center justify-between gap-3 rounded-lg border border-[#F1D6D6] bg-white p-3 dark:border-[#462123] dark:bg-[#230D0F]">
|
||||||
<div className="flex min-w-0 flex-wrap items-center gap-2">
|
<div className="flex min-w-0 flex-wrap items-center gap-2">
|
||||||
<Select value={reportModelName} onValueChange={setReportModelName} disabled={reportGenerating || reportModelsLoading}>
|
<Select value={reportModelName} onValueChange={setReportModelName} disabled={reportGenerating || reportModelsLoading}>
|
||||||
<SelectTrigger className="h-9 w-[260px] border-[#F1D6D6] bg-white dark:border-[#462123] dark:bg-[#19090A]">
|
<SelectTrigger className="h-9 w-[260px] border-[#F1D6D6] bg-white dark:border-[#462123] dark:bg-[#19090A]">
|
||||||
@@ -1292,7 +1289,7 @@ export default function AdminUserLeaderboardPage() {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{data && (
|
{data && (
|
||||||
<div className="grid gap-3 md:grid-cols-3">
|
<div className="mx-6 mt-4 grid shrink-0 gap-3 md:grid-cols-3">
|
||||||
<section className="rounded-lg border border-[#F1D6D6] bg-white p-3 dark:border-[#462123] dark:bg-[#230D0F]">
|
<section className="rounded-lg border border-[#F1D6D6] bg-white p-3 dark:border-[#462123] dark:bg-[#230D0F]">
|
||||||
<div className="mb-2 flex items-center gap-2 text-sm font-semibold text-[#231815] dark:text-white">
|
<div className="mb-2 flex items-center gap-2 text-sm font-semibold text-[#231815] dark:text-white">
|
||||||
<MessageSquareText className="size-4 text-[#C1121F]" />
|
<MessageSquareText className="size-4 text-[#C1121F]" />
|
||||||
@@ -1339,7 +1336,7 @@ export default function AdminUserLeaderboardPage() {
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<ScrollArea className="max-h-[70vh] rounded-lg border border-[#F1D6D6] bg-[#FFF7F7] p-4 dark:border-[#462123] dark:bg-[#19090A]">
|
<ScrollArea className="mx-6 mt-4 min-h-0 flex-1 rounded-lg border border-[#F1D6D6] bg-[#FFF7F7] p-5 dark:border-[#462123] dark:bg-[#19090A]">
|
||||||
{reportStatus === "idle" && !reportText && (
|
{reportStatus === "idle" && !reportText && (
|
||||||
<div className="flex items-center justify-center py-12 text-sm text-[#7A5A5A] dark:text-[#D8B8B8]">
|
<div className="flex items-center justify-center py-12 text-sm text-[#7A5A5A] dark:text-[#D8B8B8]">
|
||||||
选择模型后点击生成;同一时间段、同一模型和同一统计设置会直接读取已保存报告。
|
选择模型后点击生成;同一时间段、同一模型和同一统计设置会直接读取已保存报告。
|
||||||
@@ -1357,13 +1354,13 @@ export default function AdminUserLeaderboardPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{reportText && (
|
{reportText && (
|
||||||
<div className="rounded-lg bg-white px-5 py-4 text-sm leading-7 text-[#231815] shadow-sm dark:bg-[#230D0F] dark:text-white [&_blockquote]:border-l-4 [&_blockquote]:border-[#C1121F] [&_blockquote]:bg-[#FFF7F7] [&_blockquote]:px-3 [&_blockquote]:py-2 [&_code]:rounded [&_code]:bg-[#FFF1F1] [&_code]:px-1 [&_h1]:mb-4 [&_h1]:text-xl [&_h1]:font-semibold [&_h2]:mb-3 [&_h2]:mt-5 [&_h2]:border-b [&_h2]:border-[#F1D6D6] [&_h2]:pb-2 [&_h2]:text-lg [&_h2]:font-semibold [&_h3]:mb-2 [&_h3]:mt-4 [&_h3]:font-semibold [&_li]:my-1 [&_ol]:pl-5 [&_p]:my-2 [&_strong]:text-[#C1121F] [&_table]:my-3 [&_table]:w-full [&_table]:border-collapse [&_td]:border [&_td]:border-[#F1D6D6] [&_td]:p-2 [&_th]:border [&_th]:border-[#F1D6D6] [&_th]:bg-[#FFF1F1] [&_th]:p-2 [&_ul]:pl-5 dark:[&_blockquote]:bg-[#19090A] dark:[&_code]:bg-[#19090A] dark:[&_strong]:text-[#F2B8BB] dark:[&_th]:bg-[#19090A]">
|
<div className="rounded-lg bg-white px-8 py-6 text-base leading-8 text-[#231815] shadow-sm dark:bg-[#230D0F] dark:text-white [&_blockquote]:border-l-4 [&_blockquote]:border-[#C1121F] [&_blockquote]:bg-[#FFF7F7] [&_blockquote]:px-4 [&_blockquote]:py-3 [&_code]:rounded [&_code]:bg-[#FFF1F1] [&_code]:px-1.5 [&_h1]:mb-5 [&_h1]:text-2xl [&_h1]:font-semibold [&_h2]:mb-4 [&_h2]:mt-7 [&_h2]:border-b [&_h2]:border-[#F1D6D6] [&_h2]:pb-3 [&_h2]:text-xl [&_h2]:font-semibold [&_h3]:mb-3 [&_h3]:mt-5 [&_h3]:text-lg [&_h3]:font-semibold [&_li]:my-1.5 [&_ol]:pl-6 [&_p]:my-3 [&_strong]:text-[#C1121F] [&_table]:my-4 [&_table]:w-full [&_table]:border-collapse [&_td]:border [&_td]:border-[#F1D6D6] [&_td]:p-3 [&_th]:border [&_th]:border-[#F1D6D6] [&_th]:bg-[#FFF1F1] [&_th]:p-3 [&_ul]:pl-6 dark:[&_blockquote]:bg-[#19090A] dark:[&_code]:bg-[#19090A] dark:[&_strong]:text-[#F2B8BB] dark:[&_th]:bg-[#19090A]">
|
||||||
<MarkdownContent content={reportText} isLoading={reportGenerating} rehypePlugins={[]} />
|
<MarkdownContent content={reportText} isLoading={reportGenerating} rehypePlugins={[]} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
{reportText && (
|
{reportText && (
|
||||||
<div className="flex justify-end">
|
<div className="mt-4 flex shrink-0 justify-end border-t border-[#F1D6D6] px-6 py-4 dark:border-[#462123]">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={exportReportAsWord}
|
onClick={exportReportAsWord}
|
||||||
|
|||||||
Reference in new issue
Block a user