update dark and ligth theme

This commit is contained in:
2026-08-10 12:35:18 +05:30
parent f397e94418
commit 6cc3c9a0b7
28 changed files with 319 additions and 105 deletions

View File

@@ -24,7 +24,7 @@ interface MockUserRecord extends AuthUser {
const USERS: MockUserRecord[] = [
{
id: 'usr_owner_01',
email: 'aravind@nealre.in',
email: 'aravind@loyaly.in',
name: 'Aravind',
role: 'owner',
organisation: 'Loyaly Retail Pvt Ltd',
@@ -39,12 +39,20 @@ const USERS: MockUserRecord[] = [
password: 'admin123',
},
{
id: 'usr_mgr_01',
email: 'priya.sharma@loyaly.ai',
name: 'Priya Sharma',
role: 'manager',
id: 'usr_owner_03',
email: 'fazul@loyaly.in',
name: 'Fazul Ilahi',
role: 'owner',
organisation: 'Loyaly Retail Pvt Ltd',
password: 'indiranagar@01',
password: 'admin123',
},
{
id: 'usr_mgr_01',
email: 'suriya@loyaly.in',
name: 'Suriya',
role: 'owner',
organisation: 'Loyaly Retail Pvt Ltd',
password: 'admin123',
},
{
id: 'usr_analyst_01',

View File

@@ -18,8 +18,8 @@ export function CommerceRecentOrders() {
<div className="rounded-xl border border-border bg-card p-4 space-y-3 shadow-sm">
<div className="flex items-center justify-between border-b border-border pb-3">
<div>
<Heading level={4} className="text-base font-bold text-white flex items-center gap-2">
<Icon icon={ICONS.purchases} size="sm" className="text-zinc-400" />
<Heading level={4} className="text-base font-bold text-primary flex items-center gap-2">
<Icon icon={ICONS.purchases} size="sm" className="text-secondary" />
Recent Orders
</Heading>
<Text size="sm" color="secondary">
@@ -29,21 +29,21 @@ export function CommerceRecentOrders() {
<Badge variant="success" label="Live Feed" />
</div>
<div className="divide-y divide-zinc-800/80">
<div className="divide-y divide-border">
{RECENT_ORDERS.map((ord) => (
<div key={ord.id} className="py-2.5 first:pt-0 last:pb-0 flex items-center justify-between text-sm">
<div>
<div className="font-bold text-white flex items-center gap-2">
<div className="font-bold text-primary flex items-center gap-2">
{ord.code}
<span className="text-xs text-zinc-400 font-normal">• {ord.customer}</span>
<span className="text-xs text-secondary font-normal">• {ord.customer}</span>
</div>
<div className="text-xs text-zinc-400 font-medium">
<div className="text-xs text-secondary font-medium">
{ord.store} ({ord.method})
</div>
</div>
<div className="text-right">
<div className="font-bold text-white tabular-nums">{ord.amount}</div>
<div className="text-xs text-zinc-400">{ord.time}</div>
<div className="font-bold text-primary tabular-nums">{ord.amount}</div>
<div className="text-xs text-secondary">{ord.time}</div>
</div>
</div>
))}

View File

@@ -13,7 +13,7 @@ export function CommerceRevenueSummary() {
return (
<div className="rounded-xl border border-border bg-card p-4 space-y-4 shadow-sm">
<div className="border-b border-border pb-3">
<Heading level={4} className="text-base font-bold text-white">
<Heading level={4} className="text-base font-bold text-primary">
Revenue Summary
</Heading>
<Text size="sm" color="secondary">

View File

@@ -34,7 +34,7 @@ export function CommerceSalesInsights() {
<div className="rounded-xl border border-border bg-card p-4 space-y-3 shadow-sm">
<div className="flex items-center justify-between border-b border-border pb-3">
<div>
<Heading level={4} className="text-base font-bold text-white flex items-center gap-2">
<Heading level={4} className="text-base font-bold text-primary flex items-center gap-2">
<Icon icon={ICONS.ai} size="sm" className="text-amber-400" />
Sales Insights
</Heading>
@@ -55,7 +55,7 @@ export function CommerceSalesInsights() {
}`}
>
<div className="flex items-center justify-between">
<span className="text-xs font-bold text-white">{item.title}</span>
<span className="text-xs font-bold text-primary">{item.title}</span>
<Badge
variant={item.intent === 'warning' ? 'warning' : 'success'}
label={item.badge}

View File

@@ -21,7 +21,7 @@ export function CommerceWorkspace() {
return (
<VStack gap={5}>
{/* Sticky Header matching Dashboard visual language */}
<div className="sticky -top-5 z-40 -mx-5 px-5 pt-5 pb-4 bg-[#0F0F10] border-b border-[#2F2F2F] shadow-sm">
<div className="sticky -top-5 z-40 -mx-5 px-5 pt-5 pb-4 bg-surface border-b border-border shadow-sm">
<PageHeader
eyebrow="Sales & Revenue Analytics"
title="Commerce"

View File

@@ -9,7 +9,7 @@ import {BUSINESS_ALERTS} from '../../services/commerceService';
export function BusinessAlerts() {
return (
<div className="space-y-3">
<Heading level={4} className="text-base font-bold text-white">
<Heading level={4} className="text-base font-bold text-primary">
Real-Time Business & Operational Alerts
</Heading>
@@ -48,7 +48,7 @@ export function BusinessAlerts() {
}
/>
<div>
<span className="text-sm font-bold text-white block">{alert.title}</span>
<span className="text-sm font-bold text-primary block">{alert.title}</span>
<Text size="sm" color="secondary" className="mt-0.5">
{alert.description}
</Text>
@@ -60,10 +60,10 @@ export function BusinessAlerts() {
/>
</div>
<div className="pt-2 border-t border-white/5 flex justify-end">
<div className="pt-2 border-t border-border flex justify-end">
<button
type="button"
className="text-xs font-bold text-white hover:text-amber-300 transition-colors flex items-center gap-1"
className="text-xs font-bold text-primary hover:text-amber-300 transition-colors flex items-center gap-1"
>
{alert.actionText} →
</button>

View File

@@ -31,7 +31,7 @@ export function OperationalFlowcharts() {
return (
<div className="rounded-xl border border-border bg-card p-5 space-y-6 shadow-sm overflow-hidden">
<div>
<Heading level={4} className="text-base font-bold text-white">
<Heading level={4} className="text-base font-bold text-primary">
Operational Flow Diagrams
</Heading>
<Text size="sm" color="secondary">
@@ -48,12 +48,12 @@ export function OperationalFlowcharts() {
<div className="flex items-center gap-2 min-w-[640px]">
{ORDER_FLOW.map((node, i) => (
<div key={node.step} className="flex items-center gap-2 flex-1">
<div className="flex-1 rounded-lg border border-zinc-700 bg-zinc-900/90 p-2.5 text-center shadow-sm">
<div className="text-xs font-bold text-white">{node.step}</div>
<div className="text-[10px] text-zinc-400 font-medium mt-0.5">{node.detail}</div>
<div className="flex-1 rounded-lg border border-border-strong bg-card p-2.5 text-center shadow-sm">
<div className="text-xs font-bold text-primary">{node.step}</div>
<div className="text-[10px] text-secondary font-medium mt-0.5">{node.detail}</div>
</div>
{i < ORDER_FLOW.length - 1 ? (
<span className="text-zinc-500 font-bold text-sm shrink-0">→</span>
<span className="text-disabled font-bold text-sm shrink-0">→</span>
) : null}
</div>
))}
@@ -72,7 +72,7 @@ export function OperationalFlowcharts() {
<div key={node.step} className="flex items-center gap-2 flex-1">
<div className="flex-1 rounded-lg border border-emerald-950/60 bg-emerald-950/20 p-2.5 text-center shadow-sm">
<div className="text-xs font-bold text-emerald-300">{node.step}</div>
<div className="text-[10px] text-zinc-400 font-medium mt-0.5">{node.detail}</div>
<div className="text-[10px] text-secondary font-medium mt-0.5">{node.detail}</div>
</div>
{i < REVENUE_FLOW.length - 1 ? (
<span className="text-emerald-600 font-bold text-sm shrink-0">→</span>
@@ -94,7 +94,7 @@ export function OperationalFlowcharts() {
<div key={node.step} className="flex items-center gap-2 flex-1">
<div className="flex-1 rounded-lg border border-indigo-950/60 bg-indigo-950/20 p-2.5 text-center shadow-sm">
<div className="text-xs font-bold text-indigo-300">{node.step}</div>
<div className="text-[10px] text-zinc-400 font-medium mt-0.5">{node.detail}</div>
<div className="text-[10px] text-secondary font-medium mt-0.5">{node.detail}</div>
</div>
{i < INVENTORY_FLOW.length - 1 ? (
<span className="text-indigo-600 font-bold text-sm shrink-0">→</span>

View File

@@ -15,14 +15,14 @@ export function OrdersChart() {
<div className="rounded-xl border border-border bg-card p-4 space-y-3 overflow-hidden shadow-sm">
<div className="flex items-center justify-between">
<div>
<Heading level={4} className="text-base font-bold text-white">
<Heading level={4} className="text-base font-bold text-primary">
Orders Volume Trend
</Heading>
<Text size="sm" color="secondary">
Completed order count grouped by hourly buckets
</Text>
</div>
<span className="text-xs font-bold text-white bg-zinc-800 px-2.5 py-1 rounded-full border border-zinc-700">
<span className="text-xs font-bold text-primary bg-muted px-2.5 py-1 rounded-full border border-border-strong">
{totalOrders.toLocaleString()} Orders
</span>
</div>

View File

@@ -19,7 +19,7 @@ export function PaymentBreakdown() {
<div className="rounded-xl border border-border bg-card p-5 space-y-4 shadow-sm overflow-hidden">
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3">
<div>
<Heading level={4} className="text-base font-bold text-white">
<Heading level={4} className="text-base font-bold text-primary">
Payment Methods Breakdown
</Heading>
<Text size="sm" color="secondary">
@@ -34,8 +34,8 @@ export function PaymentBreakdown() {
onClick={() => setSelectedMethod(null)}
className={`px-2.5 py-1 rounded-md text-xs font-bold transition-all ${
selectedMethod === null
? 'bg-zinc-700 text-white shadow-sm'
: 'bg-zinc-900/80 text-zinc-400 hover:text-white border border-zinc-800'
? 'bg-muted text-primary shadow-sm'
: 'bg-card text-secondary hover:text-primary border border-border'
}`}
>
All
@@ -49,8 +49,8 @@ export function PaymentBreakdown() {
}
className={`px-2.5 py-1 rounded-md text-xs font-bold transition-all flex items-center gap-1.5 ${
selectedMethod === item.method
? 'text-white border shadow-sm'
: 'bg-zinc-900/80 text-zinc-400 hover:text-white border border-zinc-800'
? 'text-primary border shadow-sm'
: 'bg-card text-secondary hover:text-primary border border-border'
}`}
style={{
borderColor: selectedMethod === item.method ? item.color : undefined,
@@ -68,7 +68,7 @@ export function PaymentBreakdown() {
</div>
{/* Visual Ring / Stack Bar */}
<div className="h-4 w-full rounded-full bg-zinc-800 overflow-hidden flex shadow-inner p-0.5">
<div className="h-4 w-full rounded-full bg-muted overflow-hidden flex shadow-inner p-0.5">
{paymentData.map((item) => {
const isSelected = selectedMethod === null || selectedMethod === item.method;
return (
@@ -101,10 +101,10 @@ export function PaymentBreakdown() {
}
className={`flex items-center justify-between p-3 rounded-xl cursor-pointer transition-all border ${
isSelected
? 'bg-zinc-800/90 shadow-md ring-1'
? 'bg-muted shadow-md ring-1'
: selectedMethod !== null
? 'bg-zinc-900/40 border-zinc-800/60 opacity-60 hover:opacity-100'
: 'bg-zinc-900/60 border-zinc-800 hover:border-zinc-700'
? 'bg-card border-border opacity-60 hover:opacity-100'
: 'bg-card border-border hover:border-border-strong'
}`}
style={{
borderColor: isSelected ? item.color : undefined,
@@ -116,17 +116,17 @@ export function PaymentBreakdown() {
style={{backgroundColor: item.color}}
/>
<div>
<span className="text-xs font-bold text-white block truncate">
<span className="text-xs font-bold text-primary block truncate">
{item.method}
</span>
<span className="text-[10px] font-semibold text-zinc-400">
<span className="text-[10px] font-semibold text-secondary">
{item.percentage}% share
</span>
</div>
</div>
<div className="text-right shrink-0">
<div className="text-xs font-bold text-white tabular-nums">
<div className="text-xs font-bold text-primary tabular-nums">
{item.amount}
</div>
{isSelected ? (
@@ -140,21 +140,21 @@ export function PaymentBreakdown() {
{/* Selected Channel Deep-Dive Banner */}
{activeItem ? (
<div className="p-3 rounded-lg bg-zinc-900/90 border border-zinc-700 flex items-center justify-between text-xs animate-fadeIn">
<div className="p-3 rounded-lg bg-card border border-border-strong flex items-center justify-between text-xs animate-fadeIn">
<div className="flex items-center gap-2">
<span
className="size-2.5 rounded-full"
style={{backgroundColor: activeItem.color}}
/>
<span className="font-bold text-white">{activeItem.method} Channel Details:</span>
<span className="text-zinc-300">
<span className="font-bold text-primary">{activeItem.method} Channel Details:</span>
<span className="text-secondary">
{activeItem.amount} collected across selected scope terminals.
</span>
</div>
<button
type="button"
onClick={() => setSelectedMethod(null)}
className="text-zinc-400 hover:text-white font-bold text-xs"
className="text-secondary hover:text-primary font-bold text-xs"
>
Clear Filter ✕
</button>

View File

@@ -13,7 +13,7 @@ export function RevenueChart() {
<div className="rounded-xl border border-border bg-card p-4 space-y-3 overflow-hidden shadow-sm">
<div className="flex items-center justify-between">
<div>
<Heading level={4} className="text-base font-bold text-white">
<Heading level={4} className="text-base font-bold text-primary">
Revenue Trend
</Heading>
<Text size="sm" color="secondary">

View File

@@ -9,7 +9,7 @@ export function StorePerformanceChart() {
return (
<div className="rounded-xl border border-border bg-card p-5 space-y-4 shadow-sm overflow-hidden">
<div>
<Heading level={4} className="text-base font-bold text-white">
<Heading level={4} className="text-base font-bold text-primary">
Top Performing Outlets
</Heading>
<Text size="sm" color="secondary">
@@ -23,12 +23,14 @@ export function StorePerformanceChart() {
return (
<div key={store.store} className="space-y-1">
<div className="flex justify-between items-center text-xs font-semibold">
<span className="text-white font-bold">{store.store}</span>
<span className="text-primary font-bold">{store.store}</span>
<span className="text-emerald-400 font-bold tabular-nums">
₹{(store.Revenue / 100000).toFixed(1)}L
</span>
</div>
<div className="h-6 w-full rounded-md bg-zinc-900/80 p-0.5 border border-zinc-800">
{/* bg-muted, not bg-card: the track sits INSIDE a card, so it
needs the next surface step up to read as a track at all. */}
<div className="h-6 w-full rounded-md bg-muted p-0.5 border border-border">
<div
className="h-full rounded bg-gradient-to-r from-emerald-600 to-emerald-400 transition-all duration-500"
style={{width: `${widthPercent}%`}}

View File

@@ -12,7 +12,7 @@ export function TopProductsTable() {
return (
<div className="rounded-xl border border-border bg-card overflow-hidden shadow-sm space-y-3">
<div className="p-4 border-b border-border bg-card">
<Heading level={4} className="text-base font-bold text-white">
<Heading level={4} className="text-base font-bold text-primary">
Top Selling Products Leaderboard
</Heading>
<Text size="sm" color="secondary">
@@ -23,7 +23,7 @@ export function TopProductsTable() {
<div className="overflow-x-auto w-full">
<table className="w-full text-left text-sm border-collapse">
<thead>
<tr className="border-b border-zinc-800 bg-zinc-900/60 text-white font-bold">
<tr className="border-b border-border bg-card text-primary font-bold">
<th className="px-4 py-3 text-left">Product Name</th>
<th className="px-4 py-3 text-left">Category</th>
<th className="px-4 py-3 text-right">Units Sold</th>
@@ -32,13 +32,13 @@ export function TopProductsTable() {
<th className="px-4 py-3 text-center">Stock Status</th>
</tr>
</thead>
<tbody className="divide-y divide-zinc-800/60">
<tbody className="divide-y divide-border">
{products.map((prod) => (
<tr key={prod.id} className="hover:bg-white/[0.02] transition-colors">
<td className="px-4 py-3.5 text-white font-semibold">{prod.name}</td>
<td className="px-4 py-3.5 text-zinc-300 font-medium">{prod.category}</td>
<td className="px-4 py-3.5 text-right text-white font-bold tabular-nums">{prod.unitsSold.toLocaleString()}</td>
<td className="px-4 py-3.5 text-right text-white font-bold tabular-nums">{prod.revenue}</td>
<tr key={prod.id} className="hover:bg-overlay-hover transition-colors">
<td className="px-4 py-3.5 text-primary font-semibold">{prod.name}</td>
<td className="px-4 py-3.5 text-secondary font-medium">{prod.category}</td>
<td className="px-4 py-3.5 text-right text-primary font-bold tabular-nums">{prod.unitsSold.toLocaleString()}</td>
<td className="px-4 py-3.5 text-right text-primary font-bold tabular-nums">{prod.revenue}</td>
<td className="px-4 py-3.5 text-right font-bold tabular-nums">
<span className={prod.growthDirection === 'up' ? 'text-emerald-400' : 'text-rose-400'}>
{prod.growth}

View File

@@ -29,8 +29,8 @@ export function CommerceFilterToolbar({
onClick={() => onFilterChange({...filters, dateRange: r})}
className={`px-2.5 py-1 rounded-md transition-colors capitalize ${
filters.dateRange === r
? 'bg-zinc-800 text-white font-bold'
: 'text-zinc-400 hover:text-white'
? 'bg-muted text-primary font-bold'
: 'text-secondary hover:text-primary'
}`}
>
{r === 'today' ? 'Today' : r === '7d' ? '7 Days' : r === '30d' ? '30 Days' : '90 Days'}
@@ -42,7 +42,7 @@ export function CommerceFilterToolbar({
<select
value={filters.storeId}
onChange={(e) => onFilterChange({...filters, storeId: e.target.value})}
className="h-8 rounded-lg border border-border bg-card px-2.5 text-xs font-semibold text-white outline-none focus:border-zinc-500"
className="h-8 rounded-lg border border-border bg-card px-2.5 text-xs font-semibold text-primary outline-none focus:border-border-strong"
>
<option value="all">All Active Stores</option>
<option value="indiranagar">Indiranagar Flagship</option>

View File

@@ -33,15 +33,15 @@ import {ICONS} from '@/shared/utils/icons';
const MAX_HEIGHT_PX = 132;
const PILL = [
'rounded-[28px] bg-zinc-900/90 border border-zinc-700/80 shadow-md',
'rounded-[28px] bg-card border border-border-strong shadow-md',
'transition-colors duration-150',
'focus-within:border-zinc-500 focus-within:ring-1 focus-within:ring-zinc-500',
'focus-within:border-border-strong focus-within:ring-1 focus-within:ring-border-strong',
'pl-4 pr-2 py-1.5',
].join(' ');
const FIELD = [
'flex-1 min-w-0 resize-none bg-transparent border-0 outline-none',
'text-sm font-medium text-white placeholder:text-zinc-400 placeholder:font-normal',
'text-sm font-medium text-primary placeholder:text-secondary placeholder:font-normal',
'py-2 leading-6 overflow-y-auto [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden',
].join(' ');

View File

@@ -17,11 +17,11 @@ export function ChartBlock({charts}: {charts: ChartPartSpec[]}) {
className="rounded-xl border border-border bg-card p-4 shadow-sm space-y-3 overflow-hidden"
>
<div>
<Heading level={4} className="text-base font-bold text-white">
<Heading level={4} className="text-base font-bold text-primary">
{c.title}
</Heading>
{c.subtitle ? (
<p className="text-sm font-medium text-zinc-300 mt-0.5">{c.subtitle}</p>
<p className="text-sm font-medium text-secondary mt-0.5">{c.subtitle}</p>
) : null}
</div>

View File

@@ -57,13 +57,13 @@ export function InsightCardsBlock({insights}: {insights: ReportInsight[]}) {
<div className="flex flex-wrap items-start justify-between gap-x-2 gap-y-1.5">
<div className="flex items-start gap-2 min-w-0">
<span className="text-lg shrink-0">{meta.icon}</span>
<span className="text-base font-bold text-white whitespace-normal break-words min-w-0">
<span className="text-base font-bold text-primary whitespace-normal break-words min-w-0">
{insight.title}
</span>
</div>
<div className="flex items-center gap-2 shrink-0">
{insight.confidence ? (
<span className="text-sm font-semibold text-zinc-300 font-mono tabular-nums whitespace-nowrap">
<span className="text-sm font-semibold text-secondary font-mono tabular-nums whitespace-nowrap">
{insight.confidence}% confidence
</span>
) : null}
@@ -71,14 +71,14 @@ export function InsightCardsBlock({insights}: {insights: ReportInsight[]}) {
</div>
</div>
<p className="text-sm font-medium text-zinc-200 leading-relaxed whitespace-normal break-words">
<p className="text-sm font-medium text-primary leading-relaxed whitespace-normal break-words">
{insight.explanation}
</p>
{insight.recommendedAction ? (
<div className="pt-2 flex flex-wrap items-baseline gap-x-2 gap-y-1 text-sm font-semibold">
<span className="text-amber-300 font-bold shrink-0">Action:</span>
<span className="text-white whitespace-normal break-words min-w-0">
<span className="text-primary whitespace-normal break-words min-w-0">
{insight.recommendedAction}
</span>
</div>

View File

@@ -81,7 +81,7 @@ export function KpiGridBlock({kpis}: {kpis: ReportKpi[]}) {
so a long token can still break as a last resort but ordinary
prose never breaks mid-word.
*/}
<span className="text-xs font-semibold text-zinc-300 whitespace-normal break-words min-w-0 flex-1">
<span className="text-xs font-semibold text-secondary whitespace-normal break-words min-w-0 flex-1">
{kpi.title}
</span>
{kpi.iconName ? (
@@ -98,14 +98,14 @@ export function KpiGridBlock({kpis}: {kpis: ReportKpi[]}) {
width decides whether there is room for the larger setting,
which is the question `sm:` was answering with the window's.
*/}
<span className="text-xl @xs/report:text-2xl font-bold tracking-tight text-white tabular-nums whitespace-nowrap shrink-0">
<span className="text-xl @xs/report:text-2xl font-bold tracking-tight text-primary tabular-nums whitespace-nowrap shrink-0">
{kpi.value}
</span>
{kpi.trend ? (
<span
title={kpi.trend}
className={`text-xs font-bold truncate max-w-full min-w-0 ${
isUp ? 'text-emerald-400' : isDown ? 'text-rose-400' : 'text-zinc-300'
isUp ? 'text-emerald-400' : isDown ? 'text-rose-400' : 'text-secondary'
}`}
>
{kpi.trend}

View File

@@ -16,7 +16,7 @@ export function TableBlock({tables}: {tables: TablePartSpec[]}) {
>
{t.title ? (
<div className="p-4 border-b border-border bg-card">
<Heading level={4} className="text-base font-bold text-white whitespace-normal break-words">
<Heading level={4} className="text-base font-bold text-primary whitespace-normal break-words">
{t.title}
</Heading>
</div>
@@ -38,11 +38,11 @@ export function TableBlock({tables}: {tables: TablePartSpec[]}) {
className="w-full min-w-full table-auto text-left text-sm border-collapse"
>
<thead>
<tr className="border-b border-zinc-700 bg-zinc-800/80 text-white font-bold">
<tr className="border-b border-border-strong bg-muted text-primary font-bold">
{t.columns.map((col) => (
<th
key={col.key}
className={`px-3.5 py-3.5 whitespace-nowrap text-sm font-bold text-white ${
className={`px-3.5 py-3.5 whitespace-nowrap text-sm font-bold text-primary ${
col.align === 'end'
? 'text-right'
: col.align === 'center'
@@ -55,9 +55,9 @@ export function TableBlock({tables}: {tables: TablePartSpec[]}) {
))}
</tr>
</thead>
<tbody className="divide-y divide-zinc-800/80">
<tbody className="divide-y divide-border">
{t.rows.map((row, rIdx) => (
<tr key={rIdx} className="hover:bg-white/[0.04] transition-colors">
<tr key={rIdx} className="hover:bg-overlay-hover transition-colors">
{t.columns.map((col) => {
const val = row[col.key];
const valStr = String(val ?? '');
@@ -66,7 +66,7 @@ export function TableBlock({tables}: {tables: TablePartSpec[]}) {
return (
<td
key={col.key}
className={`px-3.5 py-3.5 text-white font-semibold align-middle text-sm ${
className={`px-3.5 py-3.5 text-primary font-semibold align-middle text-sm ${
col.align === 'end'
? 'text-right tabular-nums whitespace-nowrap'
: col.align === 'center'

View File

@@ -8,9 +8,11 @@ import {Button} from '@astryxdesign/core/Button';
import {Text} from '@astryxdesign/core/Text';
import {useToast} from '@astryxdesign/core/Toast';
import {StaticPanel} from '@/shared/components/patterns/PanelCard';
import {useThemeMode} from '@/shared/providers/ThemeModeProvider';
import type {ThemeMode} from '@/shared/theme/themeMode';
/** Theme mode is deliberately absent — it lives in ThemeModeProvider. */
export interface SystemPreferences {
theme: 'dark' | 'light' | 'system';
currency: 'INR' | 'USD' | 'EUR' | 'GBP';
language: 'en' | 'hi' | 'kn' | 'ta';
dateFormat: 'DD/MM/YYYY' | 'MM/DD/YYYY' | 'YYYY-MM-DD';
@@ -18,7 +20,6 @@ export interface SystemPreferences {
}
const DEFAULT_PREFS: SystemPreferences = {
theme: 'dark',
currency: 'INR',
language: 'en',
dateFormat: 'DD/MM/YYYY',
@@ -27,6 +28,14 @@ const DEFAULT_PREFS: SystemPreferences = {
export function PreferencesForm() {
const toast = useToast();
/**
* Theme is the one preference that does NOT go through the save cycle.
* It repaints the workspace the instant it changes and persists itself to
* the theme-mode cookie, so there is nothing left for Save to commit — and
* a mode you can see but have not "saved" would be the confusing state.
* The rest of the form is still mock local state.
*/
const {mode: themeMode, setMode: setThemeMode} = useThemeMode();
const [prefs, setPrefs] = useState<SystemPreferences>(DEFAULT_PREFS);
const [savedPrefs, setSavedPrefs] = useState<SystemPreferences>(DEFAULT_PREFS);
const [isSaving, setIsSaving] = useState(false);
@@ -80,8 +89,8 @@ export function PreferencesForm() {
<FormLayout direction="horizontal">
<Selector
label="Theme Interface Mode"
value={prefs.theme}
onChange={(v) => set('theme', v as SystemPreferences['theme'])}
value={themeMode}
onChange={(v) => setThemeMode(v as ThemeMode)}
options={[
{label: 'Dark Mode (Monochrome Premium)', value: 'dark'},
{label: 'Light Mode', value: 'light'},