fix: ui bugs
This commit is contained in:
parent
cfe267d540
commit
7ecdc917d6
@ -19,6 +19,7 @@ import {
|
||||
} from "recharts"
|
||||
import { Loader2, Sparkles } from "lucide-react"
|
||||
import { useTheme } from "@/components/ThemeProvider"
|
||||
import { chartTooltipProps } from "@/lib/charts/rechartsTooltip"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
type ModelEvaluationPayload = {
|
||||
@ -120,8 +121,7 @@ export default function AiAnalyticsPage() {
|
||||
|
||||
const chartMuted = isLight ? "#64748b" : "#94a3b8"
|
||||
const gridStroke = isLight ? "rgba(0,0,0,0.06)" : "rgba(255,255,255,0.08)"
|
||||
const tooltipBg = isLight ? "#ffffff" : "#0f172a"
|
||||
const tooltipBorder = isLight ? "#e2e8f0" : "rgba(255,255,255,0.12)"
|
||||
const tt = useMemo(() => chartTooltipProps(isLight), [isLight])
|
||||
|
||||
const barData = useMemo(
|
||||
() =>
|
||||
@ -284,15 +284,7 @@ export default function AiAnalyticsPage() {
|
||||
tickLine={false}
|
||||
tickFormatter={(v) => `${v}%`}
|
||||
/>
|
||||
<Tooltip
|
||||
contentStyle={{
|
||||
borderRadius: 12,
|
||||
border: `1px solid ${tooltipBorder}`,
|
||||
background: tooltipBg,
|
||||
fontWeight: 600,
|
||||
}}
|
||||
formatter={(v) => [`${Number(v ?? 0)}%`, "F1"]}
|
||||
/>
|
||||
<Tooltip {...tt} formatter={(v) => [`${Number(v ?? 0)}%`, "F1"]} />
|
||||
<Line type="monotone" dataKey="f1" stroke="#6366f1" strokeWidth={3} dot={{ r: 4 }} activeDot={{ r: 6 }} />
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
@ -402,12 +394,7 @@ export default function AiAnalyticsPage() {
|
||||
tickLine={false}
|
||||
/>
|
||||
<Tooltip
|
||||
contentStyle={{
|
||||
borderRadius: 12,
|
||||
border: `1px solid ${tooltipBorder}`,
|
||||
background: tooltipBg,
|
||||
fontWeight: 600,
|
||||
}}
|
||||
{...tt}
|
||||
formatter={(value, _name, item) => {
|
||||
const g = (item as { payload?: { gmailAutoReplies?: number } })?.payload
|
||||
?.gmailAutoReplies
|
||||
@ -460,13 +447,8 @@ export default function AiAnalyticsPage() {
|
||||
tickLine={false}
|
||||
/>
|
||||
<Tooltip
|
||||
{...tt}
|
||||
cursor={{ fill: isLight ? "rgba(99,102,241,0.06)" : "rgba(255,255,255,0.05)" }}
|
||||
contentStyle={{
|
||||
borderRadius: 12,
|
||||
border: `1px solid ${tooltipBorder}`,
|
||||
background: tooltipBg,
|
||||
fontWeight: 600,
|
||||
}}
|
||||
/>
|
||||
<Bar dataKey="count" radius={[0, 6, 6, 0]} barSize={18}>
|
||||
{barData.map((entry, i) => (
|
||||
@ -508,14 +490,9 @@ export default function AiAnalyticsPage() {
|
||||
tickLine={false}
|
||||
tickFormatter={(v) => `${v}m`}
|
||||
/>
|
||||
<Legend wrapperStyle={{ fontSize: 11, fontWeight: 600 }} />
|
||||
<Legend wrapperStyle={{ fontSize: 11, fontWeight: 600, color: chartMuted }} />
|
||||
<Tooltip
|
||||
contentStyle={{
|
||||
borderRadius: 12,
|
||||
border: `1px solid ${tooltipBorder}`,
|
||||
background: tooltipBg,
|
||||
fontWeight: 600,
|
||||
}}
|
||||
{...tt}
|
||||
formatter={(value, name) =>
|
||||
name === "AI"
|
||||
? [`${Number(value ?? 0)} min (median)`, "AI"]
|
||||
|
||||
@ -34,6 +34,7 @@ import {
|
||||
Legend,
|
||||
} from "recharts"
|
||||
import { useTheme } from "@/components/ThemeProvider"
|
||||
import { chartTooltipProps } from "@/lib/charts/rechartsTooltip"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
type TimeRange = "7days" | "30days" | "1year"
|
||||
@ -212,6 +213,7 @@ export default function DashboardPage() {
|
||||
const currency = business?.currency ?? "USD"
|
||||
const gridStroke = isLight ? "rgba(0,0,0,0.06)" : "rgba(255,255,255,0.08)"
|
||||
const chartMuted = isLight ? "#64748b" : "#94a3b8"
|
||||
const chartTt = chartTooltipProps(isLight)
|
||||
const donutColors = ["#6366f1", "#a855f7", "#f43f5e", "#f97316"]
|
||||
|
||||
const kpiAccent: Record<string, string> = {
|
||||
@ -384,12 +386,7 @@ export default function DashboardPage() {
|
||||
tickFormatter={(v) => formatMoney(Number(v), currency)}
|
||||
/>
|
||||
<Tooltip
|
||||
contentStyle={{
|
||||
borderRadius: 12,
|
||||
border: isLight ? "1px solid #e2e8f0" : "1px solid rgba(255,255,255,0.12)",
|
||||
background: isLight ? "#fff" : "#0f172a",
|
||||
fontWeight: 700,
|
||||
}}
|
||||
{...chartTt}
|
||||
formatter={(v) => [formatMoney(Number(v ?? 0), currency), "Profit (est.)"]}
|
||||
/>
|
||||
<Bar dataKey="profit" fill="#22c55e" radius={[6, 6, 0, 0]} />
|
||||
@ -425,16 +422,13 @@ export default function DashboardPage() {
|
||||
<Cell key={i} fill={donutColors[i % donutColors.length]} />
|
||||
))}
|
||||
</Pie>
|
||||
<Legend verticalAlign="middle" align="right" layout="vertical" wrapperStyle={{ fontSize: 11, fontWeight: 600 }} />
|
||||
<Tooltip
|
||||
formatter={(v) => formatMoney(Number(v ?? 0), currency)}
|
||||
contentStyle={{
|
||||
borderRadius: 12,
|
||||
border: isLight ? "1px solid #e2e8f0" : "1px solid rgba(255,255,255,0.12)",
|
||||
background: isLight ? "#fff" : "#0f172a",
|
||||
fontWeight: 700,
|
||||
}}
|
||||
<Legend
|
||||
verticalAlign="middle"
|
||||
align="right"
|
||||
layout="vertical"
|
||||
wrapperStyle={{ fontSize: 11, fontWeight: 600, color: chartMuted }}
|
||||
/>
|
||||
<Tooltip {...chartTt} formatter={(v) => formatMoney(Number(v ?? 0), currency)} />
|
||||
</PieChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
@ -479,8 +473,8 @@ export default function DashboardPage() {
|
||||
<div className={cn("px-4 md:px-6 py-4 border-b flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2", isLight ? "border-slate-100" : "border-white/10")}>
|
||||
<h3 className={cn("text-lg font-bold", isLight ? "text-slate-900" : "text-white")}>Product-level margins (est.)</h3>
|
||||
</div>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm">
|
||||
<div className="table-horizontal-scroll">
|
||||
<table className="w-full text-sm min-w-[520px]">
|
||||
<thead>
|
||||
<tr className={cn("text-left text-[10px] uppercase font-bold tracking-wider", isLight ? "bg-slate-50 text-slate-500" : "bg-white/[0.06] text-slate-400")}>
|
||||
<th className="px-4 py-3">Product</th>
|
||||
@ -520,7 +514,9 @@ export default function DashboardPage() {
|
||||
)}
|
||||
>
|
||||
<Lightbulb className={cn("w-5 h-5 shrink-0 mt-0.5", isLight ? "text-amber-600" : "text-amber-300")} />
|
||||
<p className={cn("text-sm font-medium leading-relaxed", isLight ? "text-amber-950" : "text-amber-50")}>{business.aiInsight}</p>
|
||||
<p className={cn("text-sm font-medium leading-relaxed", isLight ? "text-amber-950" : "text-amber-50")}>
|
||||
{business.aiInsight}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@ -590,13 +586,9 @@ export default function DashboardPage() {
|
||||
tickFormatter={(val) => `$${val > 999 ? (val / 1000).toFixed(1) + "k" : val}`}
|
||||
/>
|
||||
<Tooltip
|
||||
{...chartTt}
|
||||
contentStyle={{
|
||||
borderRadius: "12px",
|
||||
border: isLight ? "1px solid #e2e8f0" : "1px solid rgba(255,255,255,0.1)",
|
||||
background: isLight ? "#ffffff" : "#0f172a",
|
||||
color: isLight ? "#1e293b" : "#f1f5f9",
|
||||
fontWeight: 700,
|
||||
boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.1)",
|
||||
...chartTt.contentStyle,
|
||||
backdropFilter: isLight ? "none" : "blur(12px)",
|
||||
}}
|
||||
formatter={(value) => {
|
||||
|
||||
@ -199,9 +199,10 @@ html {
|
||||
-webkit-transform: translateZ(0);
|
||||
}
|
||||
|
||||
/* Scrollbar styling */
|
||||
/* Scrollbar styling — width + height so horizontal tracks aren’t oversized fat bars */
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
@ -218,6 +219,30 @@ html {
|
||||
background: rgba(16, 185, 129, 0.5);
|
||||
}
|
||||
|
||||
html[data-theme="light"] ::-webkit-scrollbar-track {
|
||||
background: var(--dashboard-bg, #f9fafb);
|
||||
}
|
||||
|
||||
html[data-theme="light"] ::-webkit-scrollbar-thumb {
|
||||
background: rgba(15, 23, 42, 0.18);
|
||||
}
|
||||
|
||||
html[data-theme="light"] ::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(79, 70, 229, 0.35);
|
||||
}
|
||||
|
||||
/* Nested horizontal scroll (e.g. data tables): thin bar, avoids a heavy slab above footers */
|
||||
.table-horizontal-scroll {
|
||||
overflow-x: auto;
|
||||
overflow-y: visible;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(255, 255, 255, 0.18) transparent;
|
||||
}
|
||||
|
||||
html[data-theme="light"] .table-horizontal-scroll {
|
||||
scrollbar-color: rgba(15, 23, 42, 0.22) transparent;
|
||||
}
|
||||
|
||||
/* Smooth scrolling container optimization */
|
||||
[data-scroll-container] {
|
||||
scroll-behavior: smooth;
|
||||
|
||||
@ -255,8 +255,9 @@ export default function SupplierDashboardPage() {
|
||||
<XAxis dataKey="label" tick={{ fill: "rgb(148 163 184)", fontSize: 12 }} />
|
||||
<YAxis tick={{ fill: "rgb(148 163 184)", fontSize: 12 }} />
|
||||
<Tooltip
|
||||
contentStyle={{ backgroundColor: "rgb(30 41 59)", border: "1px solid rgb(51 65 85)", borderRadius: "8px" }}
|
||||
contentStyle={{ backgroundColor: "rgb(30 41 59)", border: "1px solid rgb(51 65 85)", borderRadius: "8px", color: "rgb(248 250 252)" }}
|
||||
labelStyle={{ color: "rgb(248 250 252)" }}
|
||||
itemStyle={{ color: "rgb(248 250 252)" }}
|
||||
formatter={(value) => {
|
||||
const num =
|
||||
typeof value === "number" ? value : Number(value)
|
||||
|
||||
31
src/lib/charts/rechartsTooltip.ts
Normal file
31
src/lib/charts/rechartsTooltip.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import type { CSSProperties } from "react"
|
||||
|
||||
export type RechartsTooltipChrome = {
|
||||
contentStyle: CSSProperties
|
||||
labelStyle: CSSProperties
|
||||
itemStyle: CSSProperties
|
||||
wrapperStyle: CSSProperties
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme-aware defaults for Recharts <Tooltip />. Recharts often ignores `color` on
|
||||
* `contentStyle` for label/value rows — labelStyle + itemStyle keep dark mode readable.
|
||||
*/
|
||||
export function chartTooltipProps(isLight: boolean): RechartsTooltipChrome {
|
||||
const fg = isLight ? "#0f172a" : "#f8fafc"
|
||||
return {
|
||||
contentStyle: {
|
||||
borderRadius: 12,
|
||||
border: isLight ? "1px solid #e2e8f0" : "1px solid rgba(255,255,255,0.16)",
|
||||
background: isLight ? "#ffffff" : "#334155",
|
||||
color: fg,
|
||||
fontWeight: 700,
|
||||
boxShadow: isLight
|
||||
? "0 10px 15px -3px rgba(15, 23, 42, 0.08)"
|
||||
: "0 14px 28px rgba(0, 0, 0, 0.55)",
|
||||
},
|
||||
labelStyle: { color: fg, fontWeight: 700 },
|
||||
itemStyle: { color: fg },
|
||||
wrapperStyle: { outline: "none", zIndex: 50 },
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user