Add docs/spec.md as a landing page for the specification section with
a section index, conformance summary, and implementer guidance. Link
to it from the home page quick links and from core-concepts field
mapping section. Update nav to include the landing page.
DueDateModal and ScheduledDateModal were near-identical 230-line copies
that duplicated quick-date presets already provided by DateContextMenu.
Replace both with a single openTaskDatePicker method that reuses the
existing DateTimePickerModal.
Fix CSS selector in setupSwimLaneCellDragDrop that queried
.kanban-view__cards (never exists in swimlane cells) instead of
.kanban-view__tasks-container, causing performOptimisticReorder to
bail out and cards to snap back before the data update.
Extract reconstructDropTarget helper from the inlined same-column
fallback logic in setupColumnDragDrop so both column and swimlane
drop handlers share a single implementation for resolving drop
position when the user drops in empty space.
Add diagnostic logging to the swimlane drop handler matching the
column handler's pattern.
Cross-column drops onto empty space / column backgrounds caused a
~650ms snap-back because performOptimisticReorder bailed out when
dropTarget was undefined. Now appends the dragged card(s) to the
target container immediately when targetContainer is provided.
Also preserves the task's existing sort_order on cross-column empty-
space drops instead of assigning generateEndRank(), so moving a card
between columns and back retains its original relative position.
Adds a suppressRenderUntil guard to debouncedRefresh so a deferred
pendingRender from dragend cannot fire a stale render that undoes the
optimistic move.
Adds comprehensive debug logging throughout the drag-drop lifecycle
(gated behind enableDebugLogging) for diagnosing future issues.
Previously, drag-drop property changes (e.g. moving a card to a
"completed" column) only wrote the raw frontmatter value without
triggering the business-logic side effects that updateProperty handles
(completedDate, dateModified, auto-archive, webhooks, calendar sync,
dependent-task UI refresh).
Extract `applyPropertyChangeSideEffects` from TaskService.updateProperty
so callers that already perform their own atomic frontmatter write can
still fire the full side-effect chain. Wire it into both KanbanView and
TaskListView drop handlers, with derivative completedDate/dateModified
writes inlined into the same processFrontMatter call to avoid a second
round-trip. Make `updateCompletedDateInFrontmatter` public so views can
call it inside their frontmatter callback.
Debug output from drag-and-drop diagnostics was always emitted via
console.debug, which Obsidian's console does not filter by level.
Add an `enableDebugLogging` setting (default: off) so the [TN-DBG]
output is fully suppressed unless the user explicitly opts in.
- Add `enableDebugLogging` to TaskNotesSettings and DEFAULT_SETTINGS
- Add i18n strings and a toggle in the Features settings tab
- Guard KanbanView.debugLog() with an early return when disabled
- Switch remaining console.log calls to console.debug
- Inline side-effect handling into the atomic frontmatter write to
avoid a second processFrontMatter round-trip after drag-drop
Several interrelated drag-to-reorder bugs fixed:
- computeSortOrder() now scans the full vault (ignoring swimlane filters)
so invisible tasks in filtered views aren't leapfrogged during reorder
- Filter out tasks with undefined or non-LexoRank sort_orders (legacy
numeric timestamps) from neighbor lookup to prevent rankBetween()
from producing garbage values via ensureRank() fallbacks
- Fix safeGenNext() overflow: values starting with 'z' (near ceiling)
now extend via the decimal part instead of appending an integer digit,
which caused LexoRank.between() to wrap around
- Add sanity check in rankBetween() to detect out-of-range results from
LexoRank.between() and fall back to safeGenNext()
- Reconstruct dropTarget from visible cards when column-level drop fires
with null target (user drops in empty space below last card)
- Consolidate group/swimlane/sort_order into single atomic frontmatter
write per task to prevent interleaved corruption
- Add DropOperationQueue to serialize rapid drops on the same task file
- Add optimistic DOM reorder on drop for instant visual feedback
- Add post-drop render suppression to prevent stale Bases data from
overwriting optimistic positions
- Add esbuild copy-to-vault plugin for faster dev iteration
- Add .serena/ to .gitignore
The previous approach expanded max-height on the parent column, but
overflow-y: clip on the inner container still clipped translateY-shifted
cards. Padding is real layout space that grows the container's content
box, keeping shifted cards within bounds.
- Fix column expand/contract glitch: replace `transition: all` with specific
properties and remove scale(1.02) transform on dragover columns
- Fix wrong drop position when dragging upward: collapse dragged card's
layout space after browser captures drag image, removing the phantom
element that distorted sibling getBoundingClientRect values
- Replace thin 3px accent line with animated gap/slot pattern where sibling
cards shift apart via translateY to show the drop position
- Lock source column min-height during drag so collapsing the dragged card
doesn't shrink the priority bucket
- Clip overflow on cards container during drag so translateY shifts don't
cause scrollbars
- Suppress hover background-color, transform, and box-shadow on all task
cards during active drag via body-level .tn-drag-active class
- Add rAF throttling to dragover handlers (preventDefault stays synchronous)
- Support cross-column drag: detect container change, clean old, set up new
- Respect prefers-reduced-motion: reduce for shift animations
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace numeric midpoint sort_order with LexoRank string-based ordering.
This addresses robustness issues from PR review: buggy reordering when
notes lack sort_order, hardcoded "sort_order" field name, and duplicated
between-tasks logic.
- Extract rankBetween() helper with try/catch around LexoRank.between()
- Add ensureRank() to lazily assign LexoRank to unranked neighbors
- Thread sortOrderField param instead of re-reading settings per call
- Fix hardcoded "sort_order" writes in KanbanView and TaskListView
- Change sortOrder type from number to string across types and FieldMapper
- Pin lexorank dependency to 1.0.5 (no caret)
- Remove orphaned JSDoc stubs in KanbanView
- Pass swimlane params through to computeSortOrder in KanbanView
The drag-to-reorder feature hardcoded "sort_order" as the frontmatter
property name. This wires it through the existing FieldMapping system
so users can customise it in Settings > Task Properties, just like
every other property.
- sortOrderUtils: replace 3 hardcoded "sort_order" references with
plugin.settings.fieldMapping.sortOrder
- isSortOrderInSortConfig: accept sortOrderField param so the sort
config check uses the mapped name
- TaskListView / KanbanView: pass the mapped field name to all
isSortOrderInSortConfig calls
- taskPropertiesTab: add Sort Order property card in Metadata section
- en.ts: add translation keys for the new settings card
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract sort_order computation from KanbanView into sortOrderUtils.ts
as free functions (computeSortOrder, getGroupTasks, renumberAndInsert,
isSortOrderInSortConfig, stripPropertyPrefix) so both views share the
same midpoint insertion algorithm without code duplication.
Add drag-to-reorder to TaskListView:
- Container-level drag event delegation (dragenter/dragover/drop) with
unconditional e.preventDefault() as required by the HTML5 DnD spec
- Within-group reordering: cards get draggable="true" when sort_order
is in the view's sort config
- Cross-group dragging: detects group changes via a taskGroupKeys map
(populated at render time) and updates the group property via
TaskService.updateProperty alongside the sort_order write
- Deferred re-render during drag to prevent DOM destruction mid-drop
- Works in both flat and grouped modes; gracefully skipped in virtual
scrolling paths
Simplify .task-card--dragging CSS: remove rotate/scale transforms and
pointer-events:none that caused adjacent cards to steal hit-test events
during drag. Add drop indicator pseudo-elements (::before/::after) for
visual feedback in task-list-view.css.
Implement card-level drag-and-drop reordering within kanban columns.
Dragging a card above or below another card computes a new sort_order
using a midpoint insertion algorithm and writes it to frontmatter.
New capabilities:
- Card-level dragover/drop handlers with top/bottom half detection
- Visual drop indicators (accent-colored bar above or below target)
- Midpoint insertion: new_value = floor((neighbor_above + neighbor_below) / 2)
- Vault-wide neighbor lookup so filtered/hidden tasks are still
considered when computing midpoints (prevents order collisions)
- Proportional gap computation based on median spacing in the column
- Collision handling: when neighbors share identical sort_order values,
renumber all column tasks evenly across the existing value range
- Deferred re-render during drag to prevent DOM destruction mid-drop
- Same-column detection to skip unnecessary group property writes
Supporting changes:
- Add sortOrder field to TaskInfo interface and FieldMapping
- Add sort_order to FieldMapper read/write and default field mapping
- Add columnTasksCache for render-time group data
- Add sort_order to e2e vault kanban view config
- Add CSS for drop-above/drop-below position indicators