From e24f75a1cb961ebb338aa1f7bc4c427577830831 Mon Sep 17 00:00:00 2001
From: Julien Calixte
Date: Mon, 15 Jun 2026 00:01:55 +0200
Subject: [PATCH] feat(todo): show archived tasks from done.txt in a
collapsible section
---
src/views/TodoNotes.vue | 74 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 74 insertions(+)
diff --git a/src/views/TodoNotes.vue b/src/views/TodoNotes.vue
index 9aca62d..1123977 100644
--- a/src/views/TodoNotes.vue
+++ b/src/views/TodoNotes.vue
@@ -23,6 +23,7 @@ type Prop = {
}
const TODO_PATH = "todo.txt"
+const DONE_PATH = "done.txt"
const FluxNote = defineAsyncComponent(() => import("@/components/FluxNote.vue"))
@@ -58,6 +59,34 @@ watch(
{ immediate: true }
)
+const doneFile = computed(() => store.files.find((f) => f.path === DONE_PATH))
+const doneSha = computed(() => doneFile.value?.sha ?? "")
+const donePath = computed(() => doneFile.value?.path ?? DONE_PATH)
+
+// Reuse useTodoTxtCommit as a read-only loader. We never call its `mutate`,
+// so nothing is ever written to done.txt from this view — the file is
+// produced by an external tool.
+const { items: doneItems, syncContent: syncDoneContent } = useTodoTxtCommit({
+ user: props.user,
+ repo: props.repo,
+ path: donePath,
+ initialContent: "",
+ initialSha: doneSha,
+ debounceMs: 1000
+})
+
+watch(
+ doneSha,
+ async (newSha) => {
+ if (!newSha) return
+ const base64 = await queryFileContent(props.user, props.repo, newSha)
+ if (base64) {
+ syncDoneContent(decodeBase64ToUTF8(base64), newSha)
+ }
+ },
+ { immediate: true }
+)
+
// Rank `A` = 65 .. `Z` = 90; absent priority is Infinity so it sorts last
// regardless of locale collation quirks.
const priorityRank = (p?: string): number =>
@@ -75,6 +104,10 @@ const taskEntries = computed(() => {
return out
})
+const archivedTasks = computed(() =>
+ doneItems.value.filter((line): line is Task => !isBlank(line))
+)
+
const allProjects = computed(() => {
const set = new Set()
items.value.forEach((line) => {
@@ -431,6 +464,15 @@ const createTodoFile = async () => {
>
Your todo list is empty. Add a task above.
+
+
+ Archived ({{ archivedTasks.length }})
+
+
@@ -531,5 +573,37 @@ const createTodoFile = async () => {
.todo-filter-chip {
cursor: pointer;
}
+
+ .todo-archive {
+ margin-top: 1rem;
+
+ > summary {
+ cursor: pointer;
+ opacity: 0.7;
+ font-size: 0.8rem;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.04em;
+ list-style: none;
+ }
+
+ > summary::-webkit-details-marker {
+ display: none;
+ }
+ }
+
+ .todo-archive-list {
+ list-style: none;
+ padding-left: 0;
+ margin: 0.5rem 0 0;
+ display: flex;
+ flex-direction: column;
+
+ li {
+ list-style: none;
+ opacity: 0.7;
+ padding-bottom: 0.25rem;
+ }
+ }
}