Replace offset year/month spinners with type picklist + value input

Offset Type: [Year|Month|Week|Day]  Offset Value: [n]
Cleaner UX, handles all interval types uniformly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Paul Trowbridge 2026-04-01 14:05:25 -04:00
parent d4962f4376
commit d49aac70e4
3 changed files with 40 additions and 24 deletions

View File

@ -557,8 +557,8 @@ async function openBaselineWorkbench() {
// reset form // reset form
document.getElementById('seg-description').value = ''; document.getElementById('seg-description').value = '';
document.getElementById('seg-offset-years').value = '0'; document.getElementById('seg-offset-type').value = '';
document.getElementById('seg-offset-months').value = '0'; document.getElementById('seg-offset-value').value = '0';
document.getElementById('seg-filter-rows').innerHTML = ''; document.getElementById('seg-filter-rows').innerHTML = '';
document.getElementById('seg-timeline').classList.add('hidden'); document.getElementById('seg-timeline').classList.add('hidden');
addFilterRow(); // start with one empty filter row addFilterRow(); // start with one empty filter row
@ -727,11 +727,23 @@ function updateTimelinePreview() {
const months = (to.getFullYear() - from.getFullYear()) * 12 + (to.getMonth() - from.getMonth()) + 1; const months = (to.getFullYear() - from.getFullYear()) * 12 + (to.getMonth() - from.getMonth()) + 1;
const fmt = new Intl.DateTimeFormat('en-US', { month: 'short', year: 'numeric' }); const fmt = new Intl.DateTimeFormat('en-US', { month: 'short', year: 'numeric' });
const offsetYears = parseInt(document.getElementById('seg-offset-years').value) || 0; const offsetType = document.getElementById('seg-offset-type').value;
const offsetMonths = parseInt(document.getElementById('seg-offset-months').value) || 0; const offsetValue = parseInt(document.getElementById('seg-offset-value').value) || 0;
const projFrom = new Date(from); projFrom.setFullYear(projFrom.getFullYear() + offsetYears); projFrom.setMonth(projFrom.getMonth() + offsetMonths); function applyOffset(d) {
const projTo = new Date(to); projTo.setFullYear(projTo.getFullYear() + offsetYears); projTo.setMonth(projTo.getMonth() + offsetMonths); const r = new Date(d);
if (!offsetType || !offsetValue) return r;
switch (offsetType) {
case 'year': r.setFullYear(r.getFullYear() + offsetValue); break;
case 'month': r.setMonth(r.getMonth() + offsetValue); break;
case 'week': r.setDate(r.getDate() + offsetValue * 7); break;
case 'day': r.setDate(r.getDate() + offsetValue); break;
}
return r;
}
const projFrom = applyOffset(from);
const projTo = applyOffset(to);
let html = ` let html = `
<div class="timeline-row"> <div class="timeline-row">
@ -746,12 +758,9 @@ function updateTimelinePreview() {
</div> </div>
</div>`; </div>`;
if (offsetYears || offsetMonths) { if (offsetType && offsetValue) {
const parts = [];
if (offsetYears) parts.push(`${offsetYears} yr`);
if (offsetMonths) parts.push(`${offsetMonths} mo`);
html += ` html += `
<div class="timeline-offset-indicator">+ ${parts.join(' ')} </div> <div class="timeline-offset-indicator">+ ${offsetValue} ${offsetType}${offsetValue !== 1 ? 's' : ''} </div>
<div class="timeline-row"> <div class="timeline-row">
<div class="timeline-row-label">Projected</div> <div class="timeline-row-label">Projected</div>
<div class="timeline-bar-wrap"> <div class="timeline-bar-wrap">
@ -774,12 +783,11 @@ async function submitBaselineSegment() {
const filters = getFilterRows(); const filters = getFilterRows();
if (filters.length === 0) { showStatus('Add at least one filter', 'error'); return; } if (filters.length === 0) { showStatus('Add at least one filter', 'error'); return; }
const years = parseInt(document.getElementById('seg-offset-years').value) || 0; const offsetType = document.getElementById('seg-offset-type').value;
const months = parseInt(document.getElementById('seg-offset-months').value) || 0; const offsetValue = parseInt(document.getElementById('seg-offset-value').value) || 0;
const parts = []; const date_offset = (offsetType && offsetValue)
if (years) parts.push(`${years} year${years !== 1 ? 's' : ''}`); ? `${offsetValue} ${offsetType}${offsetValue !== 1 ? 's' : ''}`
if (months) parts.push(`${months} month${months !== 1 ? 's' : ''}`); : '0 days';
const date_offset = parts.length ? parts.join(' ') : '0 days';
const body = { const body = {
filters, filters,
@ -1278,8 +1286,8 @@ document.addEventListener('DOMContentLoaded', () => {
document.getElementById('btn-add-filter-row').addEventListener('click', addFilterRow); document.getElementById('btn-add-filter-row').addEventListener('click', addFilterRow);
document.getElementById('btn-load-segment').addEventListener('click', submitBaselineSegment); document.getElementById('btn-load-segment').addEventListener('click', submitBaselineSegment);
document.getElementById('btn-clear-baseline').addEventListener('click', clearBaseline); document.getElementById('btn-clear-baseline').addEventListener('click', clearBaseline);
document.getElementById('seg-offset-years').addEventListener('input', updateTimelinePreview); document.getElementById('seg-offset-type').addEventListener('change', updateTimelinePreview);
document.getElementById('seg-offset-months').addEventListener('input', updateTimelinePreview); document.getElementById('seg-offset-value').addEventListener('input', updateTimelinePreview);
// undo in baseline segments list // undo in baseline segments list
document.getElementById('baseline-segments-list').addEventListener('click', async e => { document.getElementById('baseline-segments-list').addEventListener('click', async e => {

View File

@ -111,11 +111,17 @@
<input type="text" id="seg-description" placeholder="e.g. All orders FY2024" /> <input type="text" id="seg-description" placeholder="e.g. All orders FY2024" />
</label> </label>
<div class="offset-row"> <div class="offset-row">
<label class="baseline-field-label">Offset Years <label class="baseline-field-label">Offset Type
<input type="number" id="seg-offset-years" min="0" value="0" /> <select id="seg-offset-type">
<option value="">— none —</option>
<option value="year">Year</option>
<option value="month">Month</option>
<option value="week">Week</option>
<option value="day">Day</option>
</select>
</label> </label>
<label class="baseline-field-label">Offset Months <label class="baseline-field-label">Offset Value
<input type="number" id="seg-offset-months" min="0" value="0" /> <input type="number" id="seg-offset-value" min="0" value="0" />
</label> </label>
</div> </div>
<div class="filter-section"> <div class="filter-section">

View File

@ -478,12 +478,14 @@ body {
} }
.baseline-field-label input[type=text], .baseline-field-label input[type=text],
.baseline-field-label input[type=number] { .baseline-field-label input[type=number],
.baseline-field-label select {
border: 1px solid #dce1e7; border: 1px solid #dce1e7;
padding: 5px 8px; padding: 5px 8px;
border-radius: 3px; border-radius: 3px;
font-size: 12px; font-size: 12px;
color: #333; color: #333;
background: white;
} }
.offset-row { display: flex; gap: 10px; } .offset-row { display: flex; gap: 10px; }