Check select-all, filtered total, deposit slip layout fixes

- Add select-all checkbox to checks table header; checks/unchecks all
  visible (filtered) rows; supports indeterminate state
- Add summary bar below checks toolbar showing count and total amount
  of filtered checks
- Deposit slip: output to full 8.5x11 letter page for trimming
- Deposit slip: remove beige left strip fill (white background)
- Deposit slip: remove vertical separator between depositor/bank info
- Deposit slip: stack bank info below account info instead of side-by-side
- Deposit slip: lower date underline position
- Deposit slip left strip: flip text orientation to read tilt-left
  (rotate 90 instead of -90; reposition all strip element anchors)
- Deposit slip left strip: center MICR and labels in strip width
- Deposit slip total: include decimal point in rotated digit amount
This commit is contained in:
2026-03-13 09:48:21 -06:00
parent 4fb7fd209c
commit ac5670039a
4 changed files with 174 additions and 117 deletions
+8
View File
@@ -79,6 +79,14 @@ header {
.toolbar-right { display: flex; align-items: center; gap: 8px; }
.toolbar label { font-size: 12px; font-weight: 500; color: var(--text-muted); }
.checks-summary {
padding: 3px 12px;
font-size: 12px;
color: var(--text-muted);
flex-shrink: 0;
min-height: 20px;
}
select {
border: 1px solid var(--border);
border-radius: 4px;
+3 -1
View File
@@ -45,11 +45,13 @@
</div>
</div>
<div id="checks-summary" class="checks-summary"></div>
<div class="table-wrap">
<table id="checks-table">
<thead>
<tr>
<th class="col-select"></th>
<th class="col-select"><input type="checkbox" id="select-all-checks" title="Select all"></th>
<th class="col-no sortable" data-col="check_no"># <span class="sort-indicator"></span></th>
<th class="col-date sortable" data-col="check_date">Date <span class="sort-indicator"></span></th>
<th class="col-payee sortable" data-col="payee">Payee <span class="sort-indicator"></span></th>
+47
View File
@@ -97,11 +97,15 @@ function renderTable() {
if (checks.length === 0) {
tbody.innerHTML = '<tr class="empty-row"><td colspan="8">No checks found.</td></tr>';
updateSortIndicators();
updateSelectAll();
updateChecksSummary();
return;
}
tbody.innerHTML = checks.map(renderRow).join('');
updateSortIndicators();
updateSelectAll();
updateChecksSummary();
// Attach row-level event listeners
tbody.querySelectorAll('input[type="checkbox"]').forEach(cb => {
@@ -188,6 +192,36 @@ function updateSortIndicators() {
});
}
function updateSelectAll() {
const selectAll = document.getElementById('select-all-checks');
const checks = filteredAndSortedChecks();
if (checks.length === 0) {
selectAll.checked = false;
selectAll.indeterminate = false;
return;
}
const nSelected = checks.filter(c => state.selected.has(c.id)).length;
selectAll.indeterminate = nSelected > 0 && nSelected < checks.length;
selectAll.checked = nSelected === checks.length;
}
function updateChecksSummary() {
const el = document.getElementById('checks-summary');
const filtered = filteredAndSortedChecks();
const all = state.checks.length;
const fmt = n => new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(n);
if (all === 0) { el.textContent = ''; return; }
const filteredTotal = filtered.reduce((s, c) => s + (parseFloat(c.amount) || 0), 0);
const isFiltered = filtered.length < all;
if (isFiltered) {
el.textContent = `${filtered.length} of ${all} checks · ${fmt(filteredTotal)}`;
} else {
el.textContent = `${all} check${all !== 1 ? 's' : ''} · ${fmt(filteredTotal)}`;
}
}
function refreshPdfButton() {
const n = state.selected.size;
@@ -206,6 +240,7 @@ function onCheckboxChange(cb) {
state.selected.delete(id);
}
refreshPdfButton();
updateSelectAll();
}
// ── Slide-in panel ───────────────────────────────────────────────────────────
@@ -916,6 +951,18 @@ function init() {
renderTable();
});
// Select-all checkbox
document.getElementById('select-all-checks').addEventListener('change', e => {
const checks = filteredAndSortedChecks();
if (e.target.checked) {
checks.forEach(c => state.selected.add(c.id));
} else {
checks.forEach(c => state.selected.delete(c.id));
}
renderTable();
refreshPdfButton();
});
// New check
document.getElementById('btn-new-check').addEventListener('click', () => openPanel());