-
Finished the planner end to end. Corrected rollover and yearly accounting, recurring targets, savings rules, and targeted dormant restorations. Added editing/deletion for income, expenses, targets, and categories. Rebuilt dashboard, analytics, calendar, settings, exports, authentication, and responsive mobile UI. Added original artwork at [financial-flow.png](/Users/tyemeclifford/Documents/GH/budget/public/assets/images/financial-flow.png), generated with built-in Imagegen using an abstract financial-momentum landscape prompt. Added [self-test.php](/Users/tyemeclifford/Documents/GH/budget/scripts/self-test.php). Verification passed: automated accounting/export tests, full browser workflow, responsive 390px layout, light/dark themes, and no console errors. Tested with FrankenPHP v1.12.4. Live Mailgun delivery was not attempted without credentials.
This commit is contained in:
+28
-4
@@ -13,9 +13,11 @@
|
||||
document.querySelectorAll('[data-trend-chart]').forEach(drawTrendChart);
|
||||
});
|
||||
|
||||
document.querySelector('[data-menu-toggle]')?.addEventListener('click', () => {
|
||||
document.querySelector('#sidebar')?.classList.toggle('open');
|
||||
});
|
||||
const sidebar = document.querySelector('#sidebar');
|
||||
const closeMenu = () => sidebar?.classList.remove('open');
|
||||
document.querySelector('[data-menu-toggle]')?.addEventListener('click', () => sidebar?.classList.toggle('open'));
|
||||
document.querySelector('[data-menu-close]')?.addEventListener('click', closeMenu);
|
||||
sidebar?.querySelectorAll('a').forEach((link) => link.addEventListener('click', closeMenu));
|
||||
|
||||
document.querySelector('[data-month-picker]')?.addEventListener('change', (event) => {
|
||||
const picker = event.currentTarget;
|
||||
@@ -34,12 +36,19 @@
|
||||
if (event.target === dialog) dialog.close();
|
||||
});
|
||||
});
|
||||
const requestedDialog = new URLSearchParams(window.location.search).get('open');
|
||||
if (requestedDialog) document.getElementById(requestedDialog)?.showModal();
|
||||
|
||||
document.querySelectorAll('[data-confirm]').forEach((form) => {
|
||||
form.addEventListener('submit', (event) => {
|
||||
if (!window.confirm(form.dataset.confirm)) event.preventDefault();
|
||||
});
|
||||
});
|
||||
document.querySelectorAll('[data-confirm-button]').forEach((button) => {
|
||||
button.addEventListener('click', (event) => {
|
||||
if (!window.confirm(button.dataset.confirmButton)) event.preventDefault();
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('.flash button').forEach((button) => {
|
||||
button.addEventListener('click', () => button.closest('.flash')?.remove());
|
||||
@@ -71,6 +80,21 @@
|
||||
});
|
||||
}
|
||||
|
||||
document.querySelectorAll('[data-dead-transfer-form]').forEach((form) => {
|
||||
const direction = form.querySelector('[name="direction"]');
|
||||
const restoreFields = form.querySelector('[data-restore-fields]');
|
||||
const restoreType = form.querySelector('[data-restore-type]');
|
||||
const restoreItem = form.querySelector('[data-restore-item]');
|
||||
const syncRestoreFields = () => {
|
||||
const restoring = direction?.value === 'restore';
|
||||
if (restoreFields) restoreFields.hidden = !restoring;
|
||||
if (restoreItem) restoreItem.hidden = !restoring || restoreType?.value !== 'item';
|
||||
};
|
||||
direction?.addEventListener('change', syncRestoreFields);
|
||||
restoreType?.addEventListener('change', syncRestoreFields);
|
||||
syncRestoreFields();
|
||||
});
|
||||
|
||||
function drawTrendChart(canvas) {
|
||||
let data;
|
||||
try {
|
||||
@@ -91,7 +115,7 @@
|
||||
const styles = getComputedStyle(document.documentElement);
|
||||
const text = styles.getPropertyValue('--muted').trim();
|
||||
const border = styles.getPropertyValue('--border-strong').trim();
|
||||
const purple = styles.getPropertyValue('--purple-bright').trim();
|
||||
const purple = styles.getPropertyValue('--purple-light').trim();
|
||||
const pink = styles.getPropertyValue('--pink').trim();
|
||||
const padding = { top: 20, right: 12, bottom: 32, left: 48 };
|
||||
const plotWidth = width - padding.left - padding.right;
|
||||
|
||||
Reference in New Issue
Block a user