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)}
|
||||
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`}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 (1–31)"
|
||||
/>
|
||||
) : (
|
||||
|
|
@ -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`}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -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": {
|
||||
|
|
|
|||
Loading…
Reference in New Issue