add pills
This commit is contained in:
@@ -96,16 +96,30 @@ class OrgTodoListView extends ItemView {
|
|||||||
|
|
||||||
root.createEl("h4", { text: "TODO list" });
|
root.createEl("h4", { text: "TODO list" });
|
||||||
|
|
||||||
const input = root.createEl("input", {
|
const filterWrap = root.createDiv({ cls: "org-todo-filterwrap" });
|
||||||
|
this.pillsEl = filterWrap.createDiv({ cls: "org-todo-pills" });
|
||||||
|
|
||||||
|
const input = filterWrap.createEl("input", {
|
||||||
type: "text",
|
type: "text",
|
||||||
placeholder: "Filter… (text or #tag)",
|
placeholder: "Filter… (text or #tag)",
|
||||||
});
|
});
|
||||||
input.addClass("org-todo-filter");
|
input.addClass("org-todo-filter");
|
||||||
|
this.inputEl = input;
|
||||||
input.addEventListener("input", () => {
|
input.addEventListener("input", () => {
|
||||||
this.filterText = input.value.toLowerCase();
|
this.filterText = input.value.toLowerCase();
|
||||||
this.renderList();
|
this.renderList();
|
||||||
this.renderTagBar();
|
this.renderTagBar();
|
||||||
});
|
});
|
||||||
|
// Backspace on an empty box removes the last pill — standard token-input feel.
|
||||||
|
input.addEventListener("keydown", (e) => {
|
||||||
|
if (e.key === "Backspace" && input.value === "" && this.activeTags.size > 0) {
|
||||||
|
const last = [...this.activeTags].pop();
|
||||||
|
this.activeTags.delete(last);
|
||||||
|
this.renderPills();
|
||||||
|
this.renderList();
|
||||||
|
this.renderTagBar();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const toggleWrap = root.createDiv({ cls: "org-todo-toggle" });
|
const toggleWrap = root.createDiv({ cls: "org-todo-toggle" });
|
||||||
const cb = toggleWrap.createEl("input", { type: "checkbox" });
|
const cb = toggleWrap.createEl("input", { type: "checkbox" });
|
||||||
@@ -123,6 +137,7 @@ class OrgTodoListView extends ItemView {
|
|||||||
this.tasks = await this.scanVault();
|
this.tasks = await this.scanVault();
|
||||||
this.renderList();
|
this.renderList();
|
||||||
this.renderTagBar();
|
this.renderTagBar();
|
||||||
|
this.renderPills();
|
||||||
}
|
}
|
||||||
|
|
||||||
async scanFile(file) {
|
async scanFile(file) {
|
||||||
@@ -177,6 +192,7 @@ class OrgTodoListView extends ItemView {
|
|||||||
this.tasks = this.tasks.filter((t) => t.file.path !== path);
|
this.tasks = this.tasks.filter((t) => t.file.path !== path);
|
||||||
this.renderList();
|
this.renderList();
|
||||||
this.renderTagBar();
|
this.renderTagBar();
|
||||||
|
this.renderPills();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rescan one file and splice its tasks in, replacing its previous entries.
|
// Rescan one file and splice its tasks in, replacing its previous entries.
|
||||||
@@ -187,8 +203,22 @@ class OrgTodoListView extends ItemView {
|
|||||||
for (const t of fresh) this.tasks.push(t);
|
for (const t of fresh) this.tasks.push(t);
|
||||||
this.renderList();
|
this.renderList();
|
||||||
this.renderTagBar();
|
this.renderTagBar();
|
||||||
|
this.renderPills();
|
||||||
|
}
|
||||||
|
renderPills() {
|
||||||
|
this.pillsEl.empty();
|
||||||
|
for (const tag of [...this.activeTags].sort()) {
|
||||||
|
const pill = this.pillsEl.createSpan({ cls: "org-todo-pill" });
|
||||||
|
pill.createSpan({ text: "#" + tag });
|
||||||
|
const x = pill.createSpan({ text: "×", cls: "org-todo-pill-x" });
|
||||||
|
x.addEventListener("click", () => {
|
||||||
|
this.activeTags.delete(tag);
|
||||||
|
this.renderPills();
|
||||||
|
this.renderList();
|
||||||
|
this.renderTagBar();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTagBar() {
|
renderTagBar() {
|
||||||
this.tagBarEl.empty();
|
this.tagBarEl.empty();
|
||||||
|
|
||||||
@@ -215,6 +245,7 @@ class OrgTodoListView extends ItemView {
|
|||||||
chip.addEventListener("click", () => {
|
chip.addEventListener("click", () => {
|
||||||
if (this.activeTags.has(tag)) this.activeTags.delete(tag);
|
if (this.activeTags.has(tag)) this.activeTags.delete(tag);
|
||||||
else this.activeTags.add(tag);
|
else this.activeTags.add(tag);
|
||||||
|
this.renderPills();
|
||||||
this.renderList();
|
this.renderList();
|
||||||
this.renderTagBar();
|
this.renderTagBar();
|
||||||
});
|
});
|
||||||
|
|||||||
+37
-2
@@ -1,10 +1,45 @@
|
|||||||
.org-todo-root {
|
.org-todo-root {
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
}
|
}
|
||||||
.org-todo-filter {
|
.org-todo-filterwrap {
|
||||||
width: 100%;
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
border: 1px solid var(--background-modifier-border);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 4px 6px;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
.org-todo-pills {
|
||||||
|
display: contents; /* pills participate directly in the wrap's flex layout */
|
||||||
|
}
|
||||||
|
.org-todo-pill {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
font-size: 0.78em;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--interactive-accent);
|
||||||
|
color: var(--text-on-accent);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.org-todo-pill-x {
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
.org-todo-pill-x:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.org-todo-filter {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 80px;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
.org-todo-toggle {
|
.org-todo-toggle {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
Reference in New Issue
Block a user