From 57463e3865ad0113c9b8e89b9a29d5166b84b345 Mon Sep 17 00:00:00 2001 From: marijo Date: Tue, 9 Jun 2026 11:04:13 +0000 Subject: [PATCH] Mobile compatibility, and removed unnecessary settings --- README.md | 3 +- app.js | 22 ++++++++++++-- index.html | 5 +--- style.css | 87 +++++++++++++++++++++++++++++++++++++++++------------- 4 files changed, 88 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 754771e..efe7143 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,8 @@ The SQLite database is created automatically in `data/go.sqlite`. - Feriefridage grant yearly, default `5` days/year. - Feriefridage must be used before `31 August` and expire before September planning. - FLEX days use `7.5h` Monday-Thursday and `7h` Friday. -- Start balances are configured separately from current FLEX hours. - The planner shows configurable numbers of previous and future months around the current month. -- Monthly vacation-day corrections can be entered directly in the planner table, e.g. `+1.2` or `-2.6` days. +- Monthly vacation, feriefridage, and FLEX balances can be corrected directly in the planner table. - Each date-range entry can individually allow unpaid fallback so only that range is converted to unpaid days if balances are insufficient. ## Data diff --git a/app.js b/app.js index 3b71368..09a44df 100644 --- a/app.js +++ b/app.js @@ -10,8 +10,7 @@ const state = { const settingKeys = [ 'previous_months', 'future_months', 'vacation_days_per_month', 'feriefridage_per_year', 'feriefridage_expiry_month', - 'normal_day_hours', 'friday_hours', 'opening_vacation_days', - 'opening_feriefridage_days', 'opening_flex_hours' + 'normal_day_hours', 'friday_hours' ]; const monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; @@ -315,6 +314,25 @@ function renderPlanner() { document.querySelectorAll('.balance-override-input').forEach((input) => { input.addEventListener('change', (event) => saveBalanceOverride(event).catch((error) => toast(error.message || String(error)))); }); + syncPlannerScroll(); +} + +function syncPlannerScroll() { + const headerWrap = document.querySelector('.planner-column-header.table-wrap'); + const bodyWrap = document.querySelector('.planner-panel .table-wrap'); + if (!headerWrap || !bodyWrap) return; + + let syncing = false; + const sync = (from, to) => { + if (syncing) return; + syncing = true; + to.scrollLeft = from.scrollLeft; + requestAnimationFrame(() => { syncing = false; }); + }; + + headerWrap.addEventListener('scroll', () => sync(headerWrap, bodyWrap), { passive: true }); + bodyWrap.addEventListener('scroll', () => sync(bodyWrap, headerWrap), { passive: true }); + headerWrap.scrollLeft = bodyWrap.scrollLeft; } function renderMonthRow(month) { diff --git a/index.html b/index.html index b3ab702..7279859 100644 --- a/index.html +++ b/index.html @@ -120,10 +120,7 @@ - - - -

Start balances are the balances before the first shown month. Monthly vacation, feriefridage, and FLEX balances are edited directly in the planner table.

+

Monthly vacation, feriefridage, and FLEX balances are edited directly in the planner table. Clear a value to return to the calculated balance.

diff --git a/style.css b/style.css index 366b56a..793caf4 100644 --- a/style.css +++ b/style.css @@ -355,27 +355,72 @@ tbody tr:hover { background: rgba(255,255,255,.04); } } @media (max-width: 680px) { - .floating-header { padding: .3rem .4rem; } - .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .28rem; } - .card { padding: .34rem .4rem; } - .card .label { font-size: .6rem; } - .card .value { font-size: .95rem; } + body { font-size: 14px; } + .floating-header { padding: .25rem .3rem; } + .cards { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .22rem; } + .card { padding: .28rem .32rem; min-width: 0; } + .card .label { font-size: .52rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } + .card .value { font-size: .82rem; line-height: 1.05; } .card .hint { display: none; } - .quick-flex-form { margin-top: .06rem; } - .quick-flex-form input { padding: .26rem .32rem; font-size: .9rem; } - .quick-flex-form button { padding: .26rem .38rem; } - .header-entries { padding: .18rem .25rem; margin: .18rem 0; } - .header-entries .table-wrap { overflow-x: auto; overflow-y: visible; } - .compact-entries-table { font-size: .68rem; } - .compact-entries-table th, .compact-entries-table td { padding: .18rem .25rem; } - .header-warning-row { gap: .3rem; } - .header-warning, .header-action-button { min-height: 1.32rem; font-size: .68rem; padding: .18rem .36rem; } - main { padding: 0 .4rem 3rem; } - .planner-column-header { margin-top: .18rem; padding-top: .16rem; } + + .header-entries { padding: .16rem .22rem; margin: .16rem 0; } + .header-entries .table-wrap { overflow-x: visible; overflow-y: visible; } + .compact-entries-table, + .compact-entries-table tbody { display: block; width: 100%; } + .compact-entries-table thead { display: none; } + .compact-entries-table tr { + display: grid; + grid-template-columns: minmax(0, 1fr) repeat(4, auto); + gap: .12rem .32rem; + align-items: center; + padding: .18rem 0; + border-bottom: 1px solid rgba(163,138,99,.22); + } + .compact-entries-table tr:last-child { border-bottom: 0; } + .compact-entries-table td { + display: block; + border-bottom: 0; + padding: 0; + white-space: normal; + line-height: 1.05; + } + .compact-entries-table td:nth-child(1) { grid-column: 1 / -1; min-width: 0; } + .compact-entries-table td:nth-child(2)::before { content: 'wd '; color: var(--muted); font-weight: 700; } + .compact-entries-table td:nth-child(3)::before { content: 'vd '; color: var(--muted); font-weight: 700; } + .compact-entries-table td:nth-child(4)::before { content: 'ff '; color: var(--muted); font-weight: 700; } + .compact-entries-table td:nth-child(5)::before { content: 'fl '; color: var(--muted); font-weight: 700; } + .compact-entries-table td:nth-child(6) { grid-column: 1 / 2; } + .compact-entries-table td:nth-child(7) { grid-column: 2 / -1; } + .compact-entries-table .entry-actions { justify-content: flex-end; gap: .18rem; } + .compact-entries-table .pill { font-size: .62rem; padding: .08rem .28rem; } + .compact-entries-table button.small { padding: .2rem .34rem; font-size: .62rem; } + .entry-date { font-size: .6rem; } + + .header-warning-row { gap: .25rem; align-items: center; } + .header-warning-list { flex: 1 1 auto; } + .header-action-list { flex: none; } + .header-warning, .header-action-button { min-height: 1.2rem; font-size: .62rem; padding: .14rem .3rem; } + + main { padding: 0 .3rem 3rem; } + .planner-column-header { margin-top: .14rem; padding-top: .12rem; } .planner-header-table th, - .planner-body-table td { padding: .42rem .32rem; } - .planner-header-table th { font-size: .68rem; } - .month-table { min-width: 680px; } - .form-grid, .form-grid.compact { grid-template-columns: 1fr; } - th, td { padding: .55rem .45rem; } + .planner-body-table td { padding: .32rem .24rem; } + .planner-header-table th { font-size: .58rem; letter-spacing: .02em; } + .month-table { min-width: 600px; } + .month-table th:nth-child(1), .month-table td:nth-child(1) { width: 6.8rem; } + .month-table th:nth-child(3), .month-table td:nth-child(3), + .month-table th:nth-child(4), .month-table td:nth-child(4), + .month-table th:nth-child(5), .month-table td:nth-child(5), + .month-table th:nth-child(6), .month-table td:nth-child(6) { width: 5.2rem; } + .month-table td.entries { min-width: 10rem; } + .month-entry { margin: .05rem 0 .18rem; } + .planner-entry-meta { display: block; margin-left: 0; font-size: .64rem; } + .planner-entry-dates { font-size: .6rem; } + .balance-override-input { width: 4.15rem; padding: .22rem .25rem; font-size: .75rem; } + + .modal { width: calc(100vw - .8rem); max-height: calc(100dvh - .8rem); padding: .75rem; overflow: auto; } + .modal-heading { margin-bottom: .7rem; } + .form-grid, .form-grid.compact { grid-template-columns: 1fr; gap: .55rem; } + input, select, textarea { padding: .62rem .68rem; } + th, td { padding: .45rem .35rem; } }