chore: bump version to v0.28.4.4

This commit is contained in:
null 2026-05-28 20:14:00 -05:00
parent 3b44fe3cbc
commit 92cc667947
4 changed files with 41 additions and 33 deletions

View File

@ -108,7 +108,7 @@ function EditableCell({ row, field, threshold, defaultPaymentDate, refresh }) {
onChange={e => setValue(e.target.value)}
onBlur={commit}
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}
title={`Click to edit ${field === 'amount' ? 'payment amount' : 'paid date'}`}
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',
isEmpty && 'text-muted-foreground',
mismatch && 'text-amber-500',
@ -185,7 +185,7 @@ export const MobileTrackerRow = React.memo(function MobileTrackerRow({ row, year
type="button"
onClick={() => onEditBill?.(row)}
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',
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>
<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>
<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>
<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)}
</p>
</div>
<div>
<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)}
</p>
</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="rounded-md bg-muted/45 px-2 py-1.5">
<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 className="rounded-md bg-muted/45 px-2 py-1.5">
<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>
@ -245,7 +245,7 @@ export const MobileTrackerRow = React.memo(function MobileTrackerRow({ row, year
ref={amountRef}
type="number" min="0" step="0.01"
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"
aria-label={`${row.name} payment amount`}
/>

View File

@ -150,6 +150,14 @@
@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 */
.scrollbar-thin {
scrollbar-width: thin;

View File

@ -477,7 +477,7 @@ function PaymentProgress({ row, threshold, onOpen, onMarkFullAmount, compact = f
title="View payment history"
>
<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}
</span>
{summary.count > 1 && (
@ -1456,7 +1456,7 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
target="_blank"
rel="noreferrer"
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',
isSkipped && 'line-through',
)}
@ -1464,7 +1464,7 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
{row.name}
</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}
</span>
)}
@ -1478,7 +1478,7 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
</Button>
</div>
{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 */}
{row.monthly_notes && (
@ -1492,7 +1492,7 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
</TableCell>
{/* 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 ? (
<input
type="number"
@ -1505,7 +1505,7 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
if (e.key === 'Enter') e.currentTarget.blur();
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 (131)"
/>
) : (
@ -1521,7 +1521,7 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
</TableCell>
{/* 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 ? (
<input
type="number"
@ -1534,13 +1534,13 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
if (e.key === 'Enter') e.currentTarget.blur();
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 ? (
<button
type="button"
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)}`}
>
{fmt(effectiveActual)}
@ -1550,7 +1550,7 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
<button
type="button"
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"
>
{fmt(row.expected_amount)}
@ -1571,7 +1571,7 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
</TableCell>
{/* 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) : '—'}
</TableCell>
@ -1586,11 +1586,11 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
</TableCell>
{/* 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
type="button"
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"
>
{row.last_paid_date ? fmtDate(row.last_paid_date) : '—'}
@ -1650,7 +1650,7 @@ function Row({ row, year, month, refresh, index, onEditBill }) {
ref={amountRef}
type="number" min="0" step="0.01"
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"
/>
<Button
@ -1855,7 +1855,7 @@ function MobileTrackerRow({ row, year, month, refresh, index, onEditBill }) {
target="_blank"
rel="noreferrer"
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',
isSkipped && 'line-through',
)}
@ -1863,7 +1863,7 @@ function MobileTrackerRow({ row, year, month, refresh, index, onEditBill }) {
{row.name}
</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}
</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>
<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>
<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>
<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)}
</p>
</div>
<div>
<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)}
</p>
</div>
<div>
<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)}
</p>
</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="rounded-md bg-muted/45 px-2 py-1.5">
<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 className="rounded-md bg-muted/45 px-2 py-1.5">
<span className="text-muted-foreground">Date </span>
<button
type="button"
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) : '—'}
{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}
type="number" min="0" step="0.01"
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"
aria-label={`${row.name} payment amount`}
/>

View File

@ -1,6 +1,6 @@
{
"name": "bill-tracker",
"version": "0.28.4.3",
"version": "0.28.4.4",
"description": "Monthly bill tracking system",
"main": "server.js",
"scripts": {