diff --git a/frontend/css/app.css b/frontend/css/app.css index 11b1804..69b1152 100644 --- a/frontend/css/app.css +++ b/frontend/css/app.css @@ -1479,6 +1479,13 @@ a { color: var(--primary); text-decoration: none; } } .cal-manage-table td { padding: 6px 8px 6px 0; border-bottom: 1px solid var(--border-light); vertical-align: middle; } .cal-manage-table tbody tr:last-child td { border-bottom: none; } +/* Drag-resizable columns: a grab handle on each header's right edge. */ +.cal-manage-table th { position: relative; } +.cal-manage-table th .col-resizer { + position: absolute; top: 0; right: 0; width: 8px; height: 100%; + cursor: col-resize; user-select: none; touch-action: none; +} +.cal-manage-table th .col-resizer:hover { background: var(--border); } .ct-acc-row td { padding-top: 14px; background: none; } .ct-acc-row td:first-child { font-size: 13px; } .ct-cal-row .ct-indent { padding-left: 16px; } diff --git a/frontend/js/calendar.js b/frontend/js/calendar.js index f66dfa1..3380098 100644 --- a/frontend/js/calendar.js +++ b/frontend/js/calendar.js @@ -3717,6 +3717,55 @@ function renderHiddenCalendars() { }); } +/** Make the calendar-management table's columns drag-resizable. Widths persist + * in localStorage and are re-applied on every re-render. */ +function initResizableCalTable(table) { + if (!table || !table.tHead) return; + const ths = Array.from(table.tHead.rows[0].cells); + let saved = null; + try { saved = JSON.parse(localStorage.getItem('calTableColWidths') || 'null'); } catch { saved = null; } + // Measure natural widths, then lock to px + fixed layout so dragging one + // column doesn't reflow the others. + const natural = ths.map(th => th.offsetWidth); + ths.forEach((th, i) => { + const w = (Array.isArray(saved) && saved[i]) ? saved[i] : natural[i]; + th.style.width = Math.max(60, w || 80) + 'px'; + }); + table.style.tableLayout = 'fixed'; + const sync = () => { + const total = ths.reduce((s, t) => s + (parseFloat(t.style.width) || 0), 0); + table.style.width = total + 'px'; + }; + sync(); + ths.forEach((th, i) => { + if (i >= ths.length - 1) return; // no handle on the last (trash) column + const res = document.createElement('div'); + res.className = 'col-resizer'; + th.appendChild(res); + res.addEventListener('mousedown', e => { + e.preventDefault(); + e.stopPropagation(); + const startX = e.clientX, startW = th.offsetWidth; + document.body.style.cursor = 'col-resize'; + const onMove = ev => { + th.style.width = Math.max(60, startW + (ev.clientX - startX)) + 'px'; + sync(); + }; + const onUp = () => { + document.removeEventListener('mousemove', onMove); + document.removeEventListener('mouseup', onUp); + document.body.style.cursor = ''; + try { + localStorage.setItem('calTableColWidths', + JSON.stringify(ths.map(t => Math.round(parseFloat(t.style.width) || 0)))); + } catch {} + }; + document.addEventListener('mousemove', onMove); + document.addEventListener('mouseup', onUp); + }); + }); +} + function renderCalendarTable() { const container = document.getElementById('cal-settings-table'); if (!container) return; @@ -3880,6 +3929,8 @@ function renderCalendarTable() {
${rows} `; + initResizableCalTable(container.querySelector('.cal-manage-table')); + // Visibility eye toggle container.querySelectorAll('.ct-eye[data-ct-hid]').forEach(btn => { btn.addEventListener('click', async () => {