Add drag & drop for entries and per-stay band colours
Calendar chips can be dragged onto another in-range day (multi-day entries shift end_date by the same delta in one PATCH); day-editor rows get a drag handle to reorder within a day, patching sort_order only for changed positions. Continues/dropoff ghost chips and stay bands are not draggable; touch devices fall back to the existing click/edit flow. Each stay band now gets a deterministic colour from an 8-hue palette by chronological index, mirrored as dots in the summary Areas list.
This commit is contained in:
@@ -22,6 +22,7 @@ import {
|
||||
import { createFlightRoute, renderSegmentLines } from './segments.js';
|
||||
import { createRentalDetails, renderRentalLine } from './rental.js';
|
||||
import { createCostForm } from './costForm.js';
|
||||
import { enableRowReorder } from './dragdrop.js';
|
||||
|
||||
export function openDayEditor(tctx, date) {
|
||||
// A form-state object for the entry currently being added/edited.
|
||||
@@ -87,21 +88,35 @@ export function openDayEditor(tctx, date) {
|
||||
if (!dayEntries.length) {
|
||||
list.appendChild(el('p', { class: 'muted entry-empty' }, 'Nothing planned for this day yet.'));
|
||||
} else {
|
||||
for (const entry of dayEntries) list.appendChild(entryRow(entry));
|
||||
// Reordering only makes sense with 2+ entries — then each row gets a drag
|
||||
// handle and dropping recomputes sort_order (see enableRowReorder).
|
||||
const reorderable = dayEntries.length > 1;
|
||||
const rows = [];
|
||||
for (const entry of dayEntries) {
|
||||
const { node, handle } = entryRow(entry, reorderable);
|
||||
rows.push({ node, handle, entry });
|
||||
list.appendChild(node);
|
||||
}
|
||||
if (reorderable) enableRowReorder(rows, () => tctx.refreshTrip());
|
||||
}
|
||||
|
||||
mount(panel, header, list, formSection(dayEntries));
|
||||
panel.scrollTop = 0;
|
||||
}
|
||||
|
||||
function entryRow(entry) {
|
||||
// Returns { node, handle } — handle is the drag grip (null unless reorderable).
|
||||
function entryRow(entry, reorderable) {
|
||||
const info = typeInfo(entry.type);
|
||||
const time = formatTimeRange(entry.start_time, entry.end_time);
|
||||
const hasPrice = entry.price != null;
|
||||
const flight = hasSegments(entry);
|
||||
return el(
|
||||
const handle = reorderable
|
||||
? el('span', { class: 'entry-drag-handle', title: 'Drag to reorder', 'aria-hidden': 'true' }, '⋮⋮')
|
||||
: null;
|
||||
const node = el(
|
||||
'div',
|
||||
{ class: 'entry-row', style: { '--chip': info.color } },
|
||||
handle,
|
||||
el('span', { class: 'entry-icon' }, info.icon),
|
||||
el(
|
||||
'div',
|
||||
@@ -142,6 +157,7 @@ export function openDayEditor(tctx, date) {
|
||||
el('button', { class: 'icon-btn danger', title: 'Delete', onClick: () => onDelete(entry) }, '🗑'),
|
||||
),
|
||||
);
|
||||
return { node, handle };
|
||||
}
|
||||
|
||||
// "until 8 Aug · 3 days" for stays; "5 Aug 20:50 → 7 Aug 06:30" otherwise.
|
||||
|
||||
Reference in New Issue
Block a user