Files
obsidian-todo-tracker/src/views/todo-item-component.ts

80 lines
2.0 KiB
TypeScript

import { Menu } from 'obsidian';
import type { TodoItem } from '../core/types';
export interface TodoItemCallbacks {
onToggle: (todo: TodoItem) => void;
onMoveClick: (todo: TodoItem) => void;
onClick: (todo: TodoItem) => void;
}
/**
* Collect all line numbers for a todo and its descendants (for drag data).
*/
export function collectChildLineNumbers(todo: TodoItem): number[] {
const lines: number[] = [];
for (const child of todo.children) {
lines.push(child.lineNumber);
lines.push(...collectChildLineNumbers(child));
}
return lines;
}
/**
* Creates a DOM element for a todo item with checkbox, right-click menu,
* drag support, and recursive child rendering.
*/
export function createTodoItemEl(
container: HTMLElement,
todo: TodoItem,
callbacks: TodoItemCallbacks
): HTMLElement {
const itemEl = container.createEl('li', { cls: 'todo-tracker-item' });
itemEl.dataset.lineNumber = String(todo.lineNumber);
// Checkbox
const checkboxEl = itemEl.createEl('input', { type: 'checkbox' });
checkboxEl.checked = todo.completed;
checkboxEl.addEventListener('change', () => {
callbacks.onToggle(todo);
});
// Text content — click to navigate to editor
const textEl = itemEl.createEl('span', { cls: 'todo-tracker-item-text' });
textEl.setText(todo.text);
if (todo.completed) {
textEl.addClass('todo-tracker-item-completed');
}
textEl.addEventListener('click', (evt) => {
evt.stopPropagation();
callbacks.onClick(todo);
});
// Right-click context menu
itemEl.addEventListener('contextmenu', (evt) => {
evt.preventDefault();
evt.stopPropagation();
const menu = new Menu();
menu.addItem((item) => {
item
.setTitle('Move to...')
.setIcon('arrow-right')
.onClick(() => {
callbacks.onMoveClick(todo);
});
});
menu.showAtMouseEvent(evt);
});
// Render children recursively
if (todo.children.length > 0) {
const nestedList = itemEl.createEl('ul', { cls: 'todo-tracker-nested-list' });
for (const child of todo.children) {
createTodoItemEl(nestedList, child, callbacks);
}
}
return itemEl;
}