chore: bump version to v0.28.4.4
This commit is contained in:
parent
3b44fe3cbc
commit
92cc667947
|
|
@ -108,7 +108,7 @@ function EditableCell({ row, field, threshold, defaultPaymentDate, refresh }) {
|
||||||
onChange={e => setValue(e.target.value)}
|
onChange={e => setValue(e.target.value)}
|
||||||
onBlur={commit}
|
onBlur={commit}
|
||||||
onKeyDown={onKeyDown}
|
onKeyDown={onKeyDown}
|
||||||
className="h-7 w-28 text-right font-mono text-sm bg-background/80 border-border/60"
|
className="tracker-number h-7 w-28 text-right text-sm font-medium bg-background/80 border-border/60"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -118,7 +118,7 @@ function EditableCell({ row, field, threshold, defaultPaymentDate, refresh }) {
|
||||||
onClick={startEdit}
|
onClick={startEdit}
|
||||||
title={`Click to edit ${field === 'amount' ? 'payment amount' : 'paid date'}`}
|
title={`Click to edit ${field === 'amount' ? 'payment amount' : 'paid date'}`}
|
||||||
className={cn(
|
className={cn(
|
||||||
'cursor-pointer rounded-md px-1.5 py-0.5 text-sm font-mono',
|
'tracker-number cursor-pointer rounded-md px-1.5 py-0.5 text-sm font-semibold',
|
||||||
'transition-all duration-150 hover:bg-accent hover:ring-1 hover:ring-border',
|
'transition-all duration-150 hover:bg-accent hover:ring-1 hover:ring-border',
|
||||||
isEmpty && 'text-muted-foreground',
|
isEmpty && 'text-muted-foreground',
|
||||||
mismatch && 'text-amber-500',
|
mismatch && 'text-amber-500',
|
||||||
|
|
@ -185,7 +185,7 @@ export const MobileTrackerRow = React.memo(function MobileTrackerRow({ row, year
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => onEditBill?.(row)}
|
onClick={() => onEditBill?.(row)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'min-w-0 truncate text-left text-sm font-semibold leading-tight text-foreground',
|
'min-w-0 truncate text-left text-[15px] font-semibold leading-tight text-foreground',
|
||||||
'underline-offset-2 transition-colors hover:text-primary hover:underline',
|
'underline-offset-2 transition-colors hover:text-primary hover:underline',
|
||||||
isSkipped && 'line-through',
|
isSkipped && 'line-through',
|
||||||
)}
|
)}
|
||||||
|
|
@ -206,7 +206,7 @@ export const MobileTrackerRow = React.memo(function MobileTrackerRow({ row, year
|
||||||
<div className="grid grid-cols-2 gap-x-3 gap-y-2 text-xs text-muted-foreground sm:grid-cols-4">
|
<div className="grid grid-cols-2 gap-x-3 gap-y-2 text-xs text-muted-foreground sm:grid-cols-4">
|
||||||
<div>
|
<div>
|
||||||
<p className="uppercase tracking-wide text-muted-foreground/60">Due</p>
|
<p className="uppercase tracking-wide text-muted-foreground/60">Due</p>
|
||||||
<p className="mt-0.5 font-mono text-sm text-foreground">{fmtDate(row.due_date)}</p>
|
<p className="tracker-number mt-0.5 text-sm font-medium text-foreground/90">{fmtDate(row.due_date)}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="uppercase tracking-wide text-muted-foreground/60">Category</p>
|
<p className="uppercase tracking-wide text-muted-foreground/60">Category</p>
|
||||||
|
|
@ -214,13 +214,13 @@ export const MobileTrackerRow = React.memo(function MobileTrackerRow({ row, year
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="uppercase tracking-wide text-muted-foreground/60">Expected</p>
|
<p className="uppercase tracking-wide text-muted-foreground/60">Expected</p>
|
||||||
<p className={cn('mt-0.5 font-mono text-sm', row.actual_amount != null ? 'text-amber-500' : 'text-foreground')}>
|
<p className={cn('tracker-number mt-0.5 text-sm font-semibold', row.actual_amount != null ? 'text-amber-300' : 'text-foreground')}>
|
||||||
{fmt(threshold)}
|
{fmt(threshold)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="uppercase tracking-wide text-muted-foreground/60">Remaining</p>
|
<p className="uppercase tracking-wide text-muted-foreground/60">Remaining</p>
|
||||||
<p className={cn('mt-0.5 font-mono text-sm', remaining > 0 ? 'text-foreground' : 'text-emerald-500')}>
|
<p className={cn('tracker-number mt-0.5 text-sm font-semibold', remaining > 0 ? 'text-foreground' : 'text-emerald-300')}>
|
||||||
{fmt(remaining)}
|
{fmt(remaining)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -230,11 +230,11 @@ export const MobileTrackerRow = React.memo(function MobileTrackerRow({ row, year
|
||||||
<div className="grid grid-cols-2 gap-2 text-xs sm:flex sm:items-center">
|
<div className="grid grid-cols-2 gap-2 text-xs sm:flex sm:items-center">
|
||||||
<div className="rounded-md bg-muted/45 px-2 py-1.5">
|
<div className="rounded-md bg-muted/45 px-2 py-1.5">
|
||||||
<span className="text-muted-foreground">Paid </span>
|
<span className="text-muted-foreground">Paid </span>
|
||||||
<span className="font-mono text-emerald-500">{row.total_paid > 0 ? fmt(row.total_paid) : '—'}</span>
|
<span className="tracker-number font-semibold text-emerald-300">{row.total_paid > 0 ? fmt(row.total_paid) : '—'}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-md bg-muted/45 px-2 py-1.5">
|
<div className="rounded-md bg-muted/45 px-2 py-1.5">
|
||||||
<span className="text-muted-foreground">Date </span>
|
<span className="text-muted-foreground">Date </span>
|
||||||
<span className="font-mono text-foreground">{row.last_paid_date ? fmtDate(row.last_paid_date) : '—'}</span>
|
<span className="tracker-number font-medium text-foreground">{row.last_paid_date ? fmtDate(row.last_paid_date) : '—'}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -245,7 +245,7 @@ export const MobileTrackerRow = React.memo(function MobileTrackerRow({ row, year
|
||||||
ref={amountRef}
|
ref={amountRef}
|
||||||
type="number" min="0" step="0.01"
|
type="number" min="0" step="0.01"
|
||||||
defaultValue={threshold}
|
defaultValue={threshold}
|
||||||
className="h-8 w-24 text-right font-mono text-sm bg-background/70 border-border/60"
|
className="tracker-number h-8 w-24 text-right text-sm font-medium bg-background/70 border-border/60"
|
||||||
title="Payment amount"
|
title="Payment amount"
|
||||||
aria-label={`${row.name} payment amount`}
|
aria-label={`${row.name} payment amount`}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,14 @@
|
||||||
@apply surface overflow-hidden shadow-sm;
|
@apply surface overflow-hidden shadow-sm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tracker-number {
|
||||||
|
font-family: Inter, Roboto, ui-sans-serif, system-ui, sans-serif;
|
||||||
|
font-variant-numeric: tabular-nums lining-nums;
|
||||||
|
font-feature-settings: "tnum" 1, "lnum" 1;
|
||||||
|
-webkit-font-smoothing: auto;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
}
|
||||||
|
|
||||||
/* Custom Scrollbar */
|
/* Custom Scrollbar */
|
||||||
.scrollbar-thin {
|
.scrollbar-thin {
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
|
|
|
||||||
|
|
@ -477,7 +477,7 @@ function PaymentProgress({ row, threshold, onOpen, onMarkFullAmount, compact = f
|
||||||
title="View payment history"
|
title="View payment history"
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between gap-2 text-xs">
|
<div className="flex items-center justify-between gap-2 text-xs">
|
||||||
<span className={cn('font-mono', summary.paid > 0 ? 'text-emerald-500' : 'text-muted-foreground')}>
|
<span className={cn('tracker-number text-[13px] font-semibold', summary.paid > 0 ? 'text-emerald-300' : 'text-muted-foreground/85')}>
|
||||||
{amountLabel}
|
{amountLabel}
|
||||||
</span>
|
</span>
|
||||||
{summary.count > 1 && (
|
{summary.count > 1 && (
|
||||||
|
|
@ -1456,7 +1456,7 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className={cn(
|
className={cn(
|
||||||
'font-medium text-sm leading-tight transition-colors',
|
'text-[15px] font-semibold leading-tight text-foreground transition-colors',
|
||||||
'hover:underline decoration-muted-foreground/50 underline-offset-2',
|
'hover:underline decoration-muted-foreground/50 underline-offset-2',
|
||||||
isSkipped && 'line-through',
|
isSkipped && 'line-through',
|
||||||
)}
|
)}
|
||||||
|
|
@ -1464,7 +1464,7 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
|
||||||
{row.name}
|
{row.name}
|
||||||
</a>
|
</a>
|
||||||
) : (
|
) : (
|
||||||
<span className={cn('font-medium text-sm leading-tight', isSkipped && 'line-through')}>
|
<span className={cn('text-[15px] font-semibold leading-tight text-foreground', isSkipped && 'line-through')}>
|
||||||
{row.name}
|
{row.name}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
@ -1478,7 +1478,7 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{row.category_name && (
|
{row.category_name && (
|
||||||
<p className="text-[11px] text-muted-foreground mt-0.5">{row.category_name}</p>
|
<p className="mt-0.5 text-xs text-muted-foreground/85">{row.category_name}</p>
|
||||||
)}
|
)}
|
||||||
{/* Monthly notes shown inline under the bill name */}
|
{/* Monthly notes shown inline under the bill name */}
|
||||||
{row.monthly_notes && (
|
{row.monthly_notes && (
|
||||||
|
|
@ -1492,7 +1492,7 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
||||||
{/* Due */}
|
{/* Due */}
|
||||||
<TableCell className="w-[10%] py-3 text-sm font-mono text-muted-foreground">
|
<TableCell className="tracker-number w-[10%] py-3 text-[13px] font-medium text-foreground/75">
|
||||||
{editingDue ? (
|
{editingDue ? (
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
|
|
@ -1505,7 +1505,7 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
|
||||||
if (e.key === 'Enter') e.currentTarget.blur();
|
if (e.key === 'Enter') e.currentTarget.blur();
|
||||||
if (e.key === 'Escape') { setEditingDue(false); }
|
if (e.key === 'Escape') { setEditingDue(false); }
|
||||||
}}
|
}}
|
||||||
className="w-12 rounded border border-border bg-transparent px-1 py-0.5 text-sm font-mono text-foreground outline-none focus:ring-[2px] focus:ring-ring/50"
|
className="tracker-number w-12 rounded border border-border bg-transparent px-1 py-0.5 text-sm font-medium text-foreground outline-none focus:ring-[2px] focus:ring-ring/50"
|
||||||
title="Day of month (1–31)"
|
title="Day of month (1–31)"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -1521,7 +1521,7 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
||||||
{/* Expected / Actual — shows actual_amount in amber when it overrides the template */}
|
{/* Expected / Actual — shows actual_amount in amber when it overrides the template */}
|
||||||
<TableCell className="w-[10%] py-3 text-right font-mono text-sm">
|
<TableCell className="tracker-number w-[10%] py-3 text-right text-[13px] font-semibold">
|
||||||
{editingExpected ? (
|
{editingExpected ? (
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
|
|
@ -1534,13 +1534,13 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
|
||||||
if (e.key === 'Enter') e.currentTarget.blur();
|
if (e.key === 'Enter') e.currentTarget.blur();
|
||||||
if (e.key === 'Escape') { setEditingExpected(false); }
|
if (e.key === 'Escape') { setEditingExpected(false); }
|
||||||
}}
|
}}
|
||||||
className="w-24 rounded border border-border bg-transparent px-1 py-0.5 text-right text-sm font-mono text-foreground outline-none focus:ring-[2px] focus:ring-ring/50"
|
className="tracker-number w-24 rounded border border-border bg-transparent px-1 py-0.5 text-right text-sm font-semibold text-foreground outline-none focus:ring-[2px] focus:ring-ring/50"
|
||||||
/>
|
/>
|
||||||
) : effectiveActual != null ? (
|
) : effectiveActual != null ? (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => { setExpectedDraft(String(effectiveActual)); setEditingExpected(true); }}
|
onClick={() => { setExpectedDraft(String(effectiveActual)); setEditingExpected(true); }}
|
||||||
className="rounded px-1 py-0.5 text-amber-500 transition-colors hover:bg-accent"
|
className="rounded px-1 py-0.5 text-amber-300 transition-colors hover:bg-accent"
|
||||||
title={`Monthly override — click to edit. Template default: ${fmt(row.expected_amount)}`}
|
title={`Monthly override — click to edit. Template default: ${fmt(row.expected_amount)}`}
|
||||||
>
|
>
|
||||||
{fmt(effectiveActual)}
|
{fmt(effectiveActual)}
|
||||||
|
|
@ -1550,7 +1550,7 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => { setExpectedDraft(String(row.expected_amount)); setEditingExpected(true); }}
|
onClick={() => { setExpectedDraft(String(row.expected_amount)); setEditingExpected(true); }}
|
||||||
className="rounded px-1 py-0.5 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
|
className="rounded px-1 py-0.5 text-foreground/85 transition-colors hover:bg-accent hover:text-foreground"
|
||||||
title="Click to edit expected amount"
|
title="Click to edit expected amount"
|
||||||
>
|
>
|
||||||
{fmt(row.expected_amount)}
|
{fmt(row.expected_amount)}
|
||||||
|
|
@ -1571,7 +1571,7 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
||||||
{/* Previous month paid */}
|
{/* Previous month paid */}
|
||||||
<TableCell className="w-[10%] py-3 text-right font-mono text-sm text-muted-foreground/70">
|
<TableCell className="tracker-number w-[10%] py-3 text-right text-[13px] font-medium text-muted-foreground/80">
|
||||||
{row.previous_month_paid > 0 ? fmt(row.previous_month_paid) : '—'}
|
{row.previous_month_paid > 0 ? fmt(row.previous_month_paid) : '—'}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
||||||
|
|
@ -1586,11 +1586,11 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
||||||
{/* Paid date */}
|
{/* Paid date */}
|
||||||
<TableCell className="w-[10%] py-3 text-sm text-muted-foreground">
|
<TableCell className="w-[10%] py-3 text-[13px] text-foreground/75">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setPaymentLedgerOpen(true)}
|
onClick={() => setPaymentLedgerOpen(true)}
|
||||||
className="rounded-md px-1.5 py-0.5 font-mono transition-colors hover:bg-accent hover:text-foreground"
|
className="tracker-number rounded-md px-1.5 py-0.5 font-medium transition-colors hover:bg-accent hover:text-foreground"
|
||||||
title="View payment history"
|
title="View payment history"
|
||||||
>
|
>
|
||||||
{row.last_paid_date ? fmtDate(row.last_paid_date) : '—'}
|
{row.last_paid_date ? fmtDate(row.last_paid_date) : '—'}
|
||||||
|
|
@ -1650,7 +1650,7 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
|
||||||
ref={amountRef}
|
ref={amountRef}
|
||||||
type="number" min="0" step="0.01"
|
type="number" min="0" step="0.01"
|
||||||
defaultValue={summary.remaining || threshold}
|
defaultValue={summary.remaining || threshold}
|
||||||
className="h-7 w-20 text-right font-mono text-sm bg-background/50 border-border/50"
|
className="tracker-number h-7 w-20 text-right text-sm font-medium bg-background/50 border-border/50"
|
||||||
title="Payment amount"
|
title="Payment amount"
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -1855,7 +1855,7 @@ function MobileTrackerRow({ row, year, month, refresh, index, onEditBill }) {
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className={cn(
|
className={cn(
|
||||||
'min-w-0 truncate text-sm font-semibold leading-tight text-foreground',
|
'min-w-0 truncate text-[15px] font-semibold leading-tight text-foreground',
|
||||||
'underline-offset-2 transition-colors hover:text-primary hover:underline',
|
'underline-offset-2 transition-colors hover:text-primary hover:underline',
|
||||||
isSkipped && 'line-through',
|
isSkipped && 'line-through',
|
||||||
)}
|
)}
|
||||||
|
|
@ -1863,7 +1863,7 @@ function MobileTrackerRow({ row, year, month, refresh, index, onEditBill }) {
|
||||||
{row.name}
|
{row.name}
|
||||||
</a>
|
</a>
|
||||||
) : (
|
) : (
|
||||||
<span className={cn('min-w-0 truncate text-sm font-semibold leading-tight text-foreground', isSkipped && 'line-through')}>
|
<span className={cn('min-w-0 truncate text-[15px] font-semibold leading-tight text-foreground', isSkipped && 'line-through')}>
|
||||||
{row.name}
|
{row.name}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
@ -1888,7 +1888,7 @@ function MobileTrackerRow({ row, year, month, refresh, index, onEditBill }) {
|
||||||
<div className="grid grid-cols-2 gap-x-3 gap-y-2 text-xs text-muted-foreground sm:grid-cols-4">
|
<div className="grid grid-cols-2 gap-x-3 gap-y-2 text-xs text-muted-foreground sm:grid-cols-4">
|
||||||
<div>
|
<div>
|
||||||
<p className="uppercase tracking-wide text-muted-foreground/60">Due</p>
|
<p className="uppercase tracking-wide text-muted-foreground/60">Due</p>
|
||||||
<p className="mt-0.5 font-mono text-sm text-foreground">{fmtDate(row.due_date)}</p>
|
<p className="tracker-number mt-0.5 text-sm font-medium text-foreground/90">{fmtDate(row.due_date)}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="uppercase tracking-wide text-muted-foreground/60">Category</p>
|
<p className="uppercase tracking-wide text-muted-foreground/60">Category</p>
|
||||||
|
|
@ -1896,19 +1896,19 @@ function MobileTrackerRow({ row, year, month, refresh, index, onEditBill }) {
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="uppercase tracking-wide text-muted-foreground/60">Expected</p>
|
<p className="uppercase tracking-wide text-muted-foreground/60">Expected</p>
|
||||||
<p className={cn('mt-0.5 font-mono text-sm', row.actual_amount != null ? 'text-amber-500' : 'text-foreground')}>
|
<p className={cn('tracker-number mt-0.5 text-sm font-semibold', row.actual_amount != null ? 'text-amber-300' : 'text-foreground')}>
|
||||||
{fmt(threshold)}
|
{fmt(threshold)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="uppercase tracking-wide text-muted-foreground/60">Last Month</p>
|
<p className="uppercase tracking-wide text-muted-foreground/60">Last Month</p>
|
||||||
<p className="mt-0.5 font-mono text-sm text-muted-foreground/70">
|
<p className="tracker-number mt-0.5 text-sm font-medium text-muted-foreground/80">
|
||||||
{fmt(row.previous_month_paid)}
|
{fmt(row.previous_month_paid)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="uppercase tracking-wide text-muted-foreground/60">Remaining</p>
|
<p className="uppercase tracking-wide text-muted-foreground/60">Remaining</p>
|
||||||
<p className={cn('mt-0.5 font-mono text-sm', remaining > 0 ? 'text-foreground' : 'text-emerald-500')}>
|
<p className={cn('tracker-number mt-0.5 text-sm font-semibold', remaining > 0 ? 'text-foreground' : 'text-emerald-300')}>
|
||||||
{fmt(remaining)}
|
{fmt(remaining)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1922,14 +1922,14 @@ function MobileTrackerRow({ row, year, month, refresh, index, onEditBill }) {
|
||||||
<div className="grid grid-cols-2 gap-2 text-xs sm:flex sm:items-center">
|
<div className="grid grid-cols-2 gap-2 text-xs sm:flex sm:items-center">
|
||||||
<div className="rounded-md bg-muted/45 px-2 py-1.5">
|
<div className="rounded-md bg-muted/45 px-2 py-1.5">
|
||||||
<span className="text-muted-foreground">Paid </span>
|
<span className="text-muted-foreground">Paid </span>
|
||||||
<span className="font-mono text-emerald-500">{row.total_paid > 0 ? fmt(row.total_paid) : '—'}</span>
|
<span className="tracker-number font-semibold text-emerald-300">{row.total_paid > 0 ? fmt(row.total_paid) : '—'}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-md bg-muted/45 px-2 py-1.5">
|
<div className="rounded-md bg-muted/45 px-2 py-1.5">
|
||||||
<span className="text-muted-foreground">Date </span>
|
<span className="text-muted-foreground">Date </span>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setPaymentLedgerOpen(true)}
|
onClick={() => setPaymentLedgerOpen(true)}
|
||||||
className="rounded font-mono text-foreground underline-offset-2 hover:underline"
|
className="tracker-number rounded font-medium text-foreground underline-offset-2 hover:underline"
|
||||||
>
|
>
|
||||||
{row.last_paid_date ? fmtDate(row.last_paid_date) : '—'}
|
{row.last_paid_date ? fmtDate(row.last_paid_date) : '—'}
|
||||||
{summary.count > 1 && <span className="ml-1 text-[10px] text-muted-foreground">({summary.count})</span>}
|
{summary.count > 1 && <span className="ml-1 text-[10px] text-muted-foreground">({summary.count})</span>}
|
||||||
|
|
@ -1953,7 +1953,7 @@ function MobileTrackerRow({ row, year, month, refresh, index, onEditBill }) {
|
||||||
ref={amountRef}
|
ref={amountRef}
|
||||||
type="number" min="0" step="0.01"
|
type="number" min="0" step="0.01"
|
||||||
defaultValue={summary.remaining || threshold}
|
defaultValue={summary.remaining || threshold}
|
||||||
className="h-8 w-24 text-right font-mono text-sm bg-background/70 border-border/60"
|
className="tracker-number h-8 w-24 text-right text-sm font-medium bg-background/70 border-border/60"
|
||||||
title="Payment amount"
|
title="Payment amount"
|
||||||
aria-label={`${row.name} payment amount`}
|
aria-label={`${row.name} payment amount`}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "bill-tracker",
|
"name": "bill-tracker",
|
||||||
"version": "0.28.4.3",
|
"version": "0.28.4.4",
|
||||||
"description": "Monthly bill tracking system",
|
"description": "Monthly bill tracking system",
|
||||||
"main": "server.js",
|
"main": "server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue