fix: ui bugs

This commit is contained in:
root 2026-05-02 14:18:45 +05:00
parent cfe267d540
commit 7ecdc917d6
5 changed files with 82 additions and 56 deletions

View File

@ -19,6 +19,7 @@ import {
} from "recharts" } from "recharts"
import { Loader2, Sparkles } from "lucide-react" import { Loader2, Sparkles } from "lucide-react"
import { useTheme } from "@/components/ThemeProvider" import { useTheme } from "@/components/ThemeProvider"
import { chartTooltipProps } from "@/lib/charts/rechartsTooltip"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"
type ModelEvaluationPayload = { type ModelEvaluationPayload = {
@ -120,8 +121,7 @@ export default function AiAnalyticsPage() {
const chartMuted = isLight ? "#64748b" : "#94a3b8" const chartMuted = isLight ? "#64748b" : "#94a3b8"
const gridStroke = isLight ? "rgba(0,0,0,0.06)" : "rgba(255,255,255,0.08)" const gridStroke = isLight ? "rgba(0,0,0,0.06)" : "rgba(255,255,255,0.08)"
const tooltipBg = isLight ? "#ffffff" : "#0f172a" const tt = useMemo(() => chartTooltipProps(isLight), [isLight])
const tooltipBorder = isLight ? "#e2e8f0" : "rgba(255,255,255,0.12)"
const barData = useMemo( const barData = useMemo(
() => () =>
@ -284,15 +284,7 @@ export default function AiAnalyticsPage() {
tickLine={false} tickLine={false}
tickFormatter={(v) => `${v}%`} tickFormatter={(v) => `${v}%`}
/> />
<Tooltip <Tooltip {...tt} formatter={(v) => [`${Number(v ?? 0)}%`, "F1"]} />
contentStyle={{
borderRadius: 12,
border: `1px solid ${tooltipBorder}`,
background: tooltipBg,
fontWeight: 600,
}}
formatter={(v) => [`${Number(v ?? 0)}%`, "F1"]}
/>
<Line type="monotone" dataKey="f1" stroke="#6366f1" strokeWidth={3} dot={{ r: 4 }} activeDot={{ r: 6 }} /> <Line type="monotone" dataKey="f1" stroke="#6366f1" strokeWidth={3} dot={{ r: 4 }} activeDot={{ r: 6 }} />
</LineChart> </LineChart>
</ResponsiveContainer> </ResponsiveContainer>
@ -402,12 +394,7 @@ export default function AiAnalyticsPage() {
tickLine={false} tickLine={false}
/> />
<Tooltip <Tooltip
contentStyle={{ {...tt}
borderRadius: 12,
border: `1px solid ${tooltipBorder}`,
background: tooltipBg,
fontWeight: 600,
}}
formatter={(value, _name, item) => { formatter={(value, _name, item) => {
const g = (item as { payload?: { gmailAutoReplies?: number } })?.payload const g = (item as { payload?: { gmailAutoReplies?: number } })?.payload
?.gmailAutoReplies ?.gmailAutoReplies
@ -460,13 +447,8 @@ export default function AiAnalyticsPage() {
tickLine={false} tickLine={false}
/> />
<Tooltip <Tooltip
{...tt}
cursor={{ fill: isLight ? "rgba(99,102,241,0.06)" : "rgba(255,255,255,0.05)" }} 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}> <Bar dataKey="count" radius={[0, 6, 6, 0]} barSize={18}>
{barData.map((entry, i) => ( {barData.map((entry, i) => (
@ -508,14 +490,9 @@ export default function AiAnalyticsPage() {
tickLine={false} tickLine={false}
tickFormatter={(v) => `${v}m`} tickFormatter={(v) => `${v}m`}
/> />
<Legend wrapperStyle={{ fontSize: 11, fontWeight: 600 }} /> <Legend wrapperStyle={{ fontSize: 11, fontWeight: 600, color: chartMuted }} />
<Tooltip <Tooltip
contentStyle={{ {...tt}
borderRadius: 12,
border: `1px solid ${tooltipBorder}`,
background: tooltipBg,
fontWeight: 600,
}}
formatter={(value, name) => formatter={(value, name) =>
name === "AI" name === "AI"
? [`${Number(value ?? 0)} min (median)`, "AI"] ? [`${Number(value ?? 0)} min (median)`, "AI"]

View File

@ -34,6 +34,7 @@ import {
Legend, Legend,
} from "recharts" } from "recharts"
import { useTheme } from "@/components/ThemeProvider" import { useTheme } from "@/components/ThemeProvider"
import { chartTooltipProps } from "@/lib/charts/rechartsTooltip"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"
type TimeRange = "7days" | "30days" | "1year" type TimeRange = "7days" | "30days" | "1year"
@ -212,6 +213,7 @@ export default function DashboardPage() {
const currency = business?.currency ?? "USD" const currency = business?.currency ?? "USD"
const gridStroke = isLight ? "rgba(0,0,0,0.06)" : "rgba(255,255,255,0.08)" const gridStroke = isLight ? "rgba(0,0,0,0.06)" : "rgba(255,255,255,0.08)"
const chartMuted = isLight ? "#64748b" : "#94a3b8" const chartMuted = isLight ? "#64748b" : "#94a3b8"
const chartTt = chartTooltipProps(isLight)
const donutColors = ["#6366f1", "#a855f7", "#f43f5e", "#f97316"] const donutColors = ["#6366f1", "#a855f7", "#f43f5e", "#f97316"]
const kpiAccent: Record<string, string> = { const kpiAccent: Record<string, string> = {
@ -384,12 +386,7 @@ export default function DashboardPage() {
tickFormatter={(v) => formatMoney(Number(v), currency)} tickFormatter={(v) => formatMoney(Number(v), currency)}
/> />
<Tooltip <Tooltip
contentStyle={{ {...chartTt}
borderRadius: 12,
border: isLight ? "1px solid #e2e8f0" : "1px solid rgba(255,255,255,0.12)",
background: isLight ? "#fff" : "#0f172a",
fontWeight: 700,
}}
formatter={(v) => [formatMoney(Number(v ?? 0), currency), "Profit (est.)"]} formatter={(v) => [formatMoney(Number(v ?? 0), currency), "Profit (est.)"]}
/> />
<Bar dataKey="profit" fill="#22c55e" radius={[6, 6, 0, 0]} /> <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]} /> <Cell key={i} fill={donutColors[i % donutColors.length]} />
))} ))}
</Pie> </Pie>
<Legend verticalAlign="middle" align="right" layout="vertical" wrapperStyle={{ fontSize: 11, fontWeight: 600 }} /> <Legend
<Tooltip verticalAlign="middle"
formatter={(v) => formatMoney(Number(v ?? 0), currency)} align="right"
contentStyle={{ layout="vertical"
borderRadius: 12, wrapperStyle={{ fontSize: 11, fontWeight: 600, color: chartMuted }}
border: isLight ? "1px solid #e2e8f0" : "1px solid rgba(255,255,255,0.12)",
background: isLight ? "#fff" : "#0f172a",
fontWeight: 700,
}}
/> />
<Tooltip {...chartTt} formatter={(v) => formatMoney(Number(v ?? 0), currency)} />
</PieChart> </PieChart>
</ResponsiveContainer> </ResponsiveContainer>
</div> </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")}> <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> <h3 className={cn("text-lg font-bold", isLight ? "text-slate-900" : "text-white")}>Product-level margins (est.)</h3>
</div> </div>
<div className="overflow-x-auto"> <div className="table-horizontal-scroll">
<table className="w-full text-sm"> <table className="w-full text-sm min-w-[520px]">
<thead> <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")}> <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> <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")} /> <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>
</div> </div>
)} )}
@ -590,13 +586,9 @@ export default function DashboardPage() {
tickFormatter={(val) => `$${val > 999 ? (val / 1000).toFixed(1) + "k" : val}`} tickFormatter={(val) => `$${val > 999 ? (val / 1000).toFixed(1) + "k" : val}`}
/> />
<Tooltip <Tooltip
{...chartTt}
contentStyle={{ contentStyle={{
borderRadius: "12px", ...chartTt.contentStyle,
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)",
backdropFilter: isLight ? "none" : "blur(12px)", backdropFilter: isLight ? "none" : "blur(12px)",
}} }}
formatter={(value) => { formatter={(value) => {

View File

@ -199,9 +199,10 @@ html {
-webkit-transform: translateZ(0); -webkit-transform: translateZ(0);
} }
/* Scrollbar styling */ /* Scrollbar styling — width + height so horizontal tracks aren’t oversized fat bars */
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 6px; width: 6px;
height: 6px;
} }
::-webkit-scrollbar-track { ::-webkit-scrollbar-track {
@ -218,6 +219,30 @@ html {
background: rgba(16, 185, 129, 0.5); 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 */ /* Smooth scrolling container optimization */
[data-scroll-container] { [data-scroll-container] {
scroll-behavior: smooth; scroll-behavior: smooth;

View File

@ -255,8 +255,9 @@ export default function SupplierDashboardPage() {
<XAxis dataKey="label" tick={{ fill: "rgb(148 163 184)", fontSize: 12 }} /> <XAxis dataKey="label" tick={{ fill: "rgb(148 163 184)", fontSize: 12 }} />
<YAxis tick={{ fill: "rgb(148 163 184)", fontSize: 12 }} /> <YAxis tick={{ fill: "rgb(148 163 184)", fontSize: 12 }} />
<Tooltip <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)" }} labelStyle={{ color: "rgb(248 250 252)" }}
itemStyle={{ color: "rgb(248 250 252)" }}
formatter={(value) => { formatter={(value) => {
const num = const num =
typeof value === "number" ? value : Number(value) typeof value === "number" ? value : Number(value)

View 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 },
}
}