mirror of
https://github.com/zadam/trilium.git
synced 2025-10-20 15:19:01 +02:00
feat(views/board): edit the note title inline on new
This commit is contained in:
parent
545b19f978
commit
3a569499cb
@ -183,6 +183,7 @@ export class DifferentialBoardRenderer {
|
||||
const item = newCards[i];
|
||||
const noteId = item.note.noteId;
|
||||
let $existingCard = $cardContainer.find(`[data-note-id="${noteId}"]`);
|
||||
const isNewCard = !oldCardIds.includes(noteId);
|
||||
|
||||
if ($existingCard.length) {
|
||||
// Update existing card if title changed
|
||||
@ -197,8 +198,8 @@ export class DifferentialBoardRenderer {
|
||||
// Ensure card is in correct position
|
||||
this.ensureCardPosition($existingCard, i, $cardContainer);
|
||||
} else {
|
||||
// Create new card
|
||||
const $newCard = this.createCard(item.note, item.branch, column);
|
||||
// Create new card (pass isNewCard flag)
|
||||
const $newCard = this.createCard(item.note, item.branch, column, isNewCard);
|
||||
$newCard.addClass('fade-in').css('opacity', '0');
|
||||
|
||||
// Insert at correct position
|
||||
@ -264,7 +265,7 @@ export class DifferentialBoardRenderer {
|
||||
// Add cards
|
||||
for (const item of columnItems) {
|
||||
if (item.note) {
|
||||
const $noteEl = this.createCard(item.note, item.branch, column);
|
||||
const $noteEl = this.createCard(item.note, item.branch, column, false); // false = existing card
|
||||
$columnEl.append($noteEl);
|
||||
}
|
||||
}
|
||||
@ -281,7 +282,7 @@ export class DifferentialBoardRenderer {
|
||||
return $columnEl;
|
||||
}
|
||||
|
||||
private createCard(note: any, branch: any, column: string): JQuery<HTMLElement> {
|
||||
private createCard(note: any, branch: any, column: string, isNewCard: boolean = false): JQuery<HTMLElement> {
|
||||
const $iconEl = $("<span>")
|
||||
.addClass("icon")
|
||||
.addClass(note.getIcon());
|
||||
@ -291,10 +292,15 @@ export class DifferentialBoardRenderer {
|
||||
.attr("data-note-id", note.noteId)
|
||||
.attr("data-branch-id", branch.branchId)
|
||||
.attr("data-current-column", column)
|
||||
.attr("data-icon-class", note.getIcon())
|
||||
.text(note.title);
|
||||
|
||||
$noteEl.prepend($iconEl);
|
||||
$noteEl.on("click", () => appContext.triggerCommand("openInPopup", { noteIdOrPath: note.noteId }));
|
||||
|
||||
// Only add quick edit click handler for existing cards (not new ones)
|
||||
if (!isNewCard) {
|
||||
$noteEl.on("click", () => appContext.triggerCommand("openInPopup", { noteIdOrPath: note.noteId }));
|
||||
}
|
||||
|
||||
// Setup drag functionality
|
||||
this.dragHandler.setupNoteDrag($noteEl, note, branch);
|
||||
@ -327,4 +333,101 @@ export class DifferentialBoardRenderer {
|
||||
await this.performUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
startInlineEditing(noteId: string): void {
|
||||
// Use setTimeout to ensure the card is rendered before trying to edit it
|
||||
setTimeout(() => {
|
||||
const $card = this.$container.find(`[data-note-id="${noteId}"]`);
|
||||
if ($card.length) {
|
||||
this.makeCardEditable($card, noteId);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
private makeCardEditable($card: JQuery<HTMLElement>, noteId: string): void {
|
||||
if ($card.hasClass('editing')) {
|
||||
return; // Already editing
|
||||
}
|
||||
|
||||
// Get the current title (get text without icon)
|
||||
const $icon = $card.find('.icon');
|
||||
const currentTitle = $card.text().trim();
|
||||
|
||||
// Add editing class and store original click handler
|
||||
$card.addClass('editing');
|
||||
$card.off('click'); // Remove any existing click handlers temporarily
|
||||
|
||||
// Create input element
|
||||
const $input = $('<input>')
|
||||
.attr('type', 'text')
|
||||
.val(currentTitle)
|
||||
.css({
|
||||
background: 'transparent',
|
||||
border: 'none',
|
||||
outline: 'none',
|
||||
fontFamily: 'inherit',
|
||||
fontSize: 'inherit',
|
||||
color: 'inherit',
|
||||
flex: '1',
|
||||
minWidth: '0',
|
||||
padding: '0',
|
||||
marginLeft: '0.25em'
|
||||
});
|
||||
|
||||
// Create a flex container to keep icon and input inline
|
||||
const $editContainer = $('<div>')
|
||||
.css({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
width: '100%'
|
||||
});
|
||||
|
||||
// Replace content with icon + input in flex container
|
||||
$editContainer.append($icon.clone(), $input);
|
||||
$card.empty().append($editContainer);
|
||||
$input.focus().select();
|
||||
|
||||
const finishEdit = async (save: boolean = true) => {
|
||||
if (!$card.hasClass('editing')) {
|
||||
return; // Already finished
|
||||
}
|
||||
|
||||
$card.removeClass('editing');
|
||||
|
||||
let finalTitle = currentTitle;
|
||||
if (save) {
|
||||
const newTitle = $input.val() as string;
|
||||
if (newTitle.trim() && newTitle !== currentTitle) {
|
||||
try {
|
||||
// Update the note title using the board view's server call
|
||||
import('../../../services/server').then(async ({ default: server }) => {
|
||||
await server.put(`notes/${noteId}/title`, { title: newTitle.trim() });
|
||||
finalTitle = newTitle.trim();
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to update note title:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restore the card content
|
||||
const iconClass = $card.attr('data-icon-class') || 'bx bx-file';
|
||||
const $newIcon = $('<span>').addClass('icon').addClass(iconClass);
|
||||
$card.empty().append($newIcon, finalTitle);
|
||||
|
||||
// Re-attach click handler for quick edit (for existing cards)
|
||||
$card.on('click', () => appContext.triggerCommand("openInPopup", { noteIdOrPath: noteId }));
|
||||
};
|
||||
|
||||
$input.on('blur', () => finishEdit(true));
|
||||
$input.on('keydown', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
finishEdit(true);
|
||||
} else if (e.key === 'Escape') {
|
||||
e.preventDefault();
|
||||
finishEdit(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -139,6 +139,22 @@ const TPL = /*html*/`
|
||||
box-shadow: 4px 8px 16px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.board-view-container .board-note.editing {
|
||||
box-shadow: 2px 4px 8px rgba(0, 0, 0, 0.35);
|
||||
border-color: var(--main-text-color);
|
||||
}
|
||||
|
||||
.board-view-container .board-note.editing input {
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: none;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.board-view-container .board-note .icon {
|
||||
margin-right: 0.25em;
|
||||
}
|
||||
@ -270,7 +286,7 @@ export default class BoardView extends ViewMode<BoardData> {
|
||||
this.$container.empty();
|
||||
await this.initializeRenderer();
|
||||
}
|
||||
|
||||
|
||||
await this.renderer!.renderBoard();
|
||||
return this.$root;
|
||||
}
|
||||
@ -402,7 +418,8 @@ export default class BoardView extends ViewMode<BoardData> {
|
||||
|
||||
// Create a new note as a child of the parent note
|
||||
const { note: newNote } = await noteCreateService.createNote(parentNotePath, {
|
||||
activate: false
|
||||
activate: false,
|
||||
title: "New item"
|
||||
});
|
||||
|
||||
if (newNote) {
|
||||
@ -412,14 +429,18 @@ export default class BoardView extends ViewMode<BoardData> {
|
||||
// Refresh the board to show the new item
|
||||
await this.renderList();
|
||||
|
||||
// Optionally, open the new note for editing
|
||||
appContext.triggerCommand("openInPopup", { noteIdOrPath: newNote.noteId });
|
||||
// Start inline editing of the newly created card
|
||||
this.startInlineEditingCard(newNote.noteId);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to create new item:", error);
|
||||
}
|
||||
}
|
||||
|
||||
private startInlineEditingCard(noteId: string) {
|
||||
this.renderer?.startInlineEditing(noteId);
|
||||
}
|
||||
|
||||
forceFullRefresh() {
|
||||
this.renderer?.forceFullRender();
|
||||
return this.renderList();
|
||||
@ -500,7 +521,7 @@ export default class BoardView extends ViewMode<BoardData> {
|
||||
|
||||
async onEntitiesReloaded({ loadResults }: EventData<"entitiesReloaded">) {
|
||||
// Check if any changes affect our board
|
||||
const hasRelevantChanges =
|
||||
const hasRelevantChanges =
|
||||
// React to changes in "status" attribute for notes in this board
|
||||
loadResults.getAttributeRows().some(attr => attr.name === "status" && this.noteIds.includes(attr.noteId!)) ||
|
||||
// React to changes in note title
|
||||
|
Loading…
x
Reference in New Issue
Block a user