diff --git a/CHANGELOG.md b/CHANGELOG.md index d5e54af..a5c601d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,28 @@ not from the output of `docker push`. --- +## 2026-08-12 — A chapter you can see, in the colour you chose + +**Images** — web `sha256:…`, server unchanged at `sha256:ed0b9970…` + +**Fixed** +- **A chapter did not show until the notebook had a note in it.** "Nothing here" + was asked of the notes alone, so a notebook whose only contents were chapters + showed the empty-list panel with the chapters hidden behind it — making a + chapter in a fresh notebook appeared to do nothing at all. It is now asked of + every row, and a notebook with chapters but no loose notes says so in one line + rather than looking like a list that failed to load. + +**Changed** +- **A chapter's colour is chosen while it is being made**, in the same dialog as + its name. It is what tells one chapter from the next, and having to right-click + a fresh one to say which it is meant two visits for one decision. Renaming and + recolouring later are one entry in its menu, and one write. +- **The word *here* is gone.** The line along the top of the pane says which of + the two places you are in; saying it twice was noise. + +--- + ## 2026-08-12 — A filed note stays filed **Images** — web `sha256:2041f103…`, server `sha256:ed0b9970…` diff --git a/e2e/chapters.mjs b/e2e/chapters.mjs index 473806c..ecac39f 100644 --- a/e2e/chapters.mjs +++ b/e2e/chapters.mjs @@ -24,10 +24,14 @@ try { const titles = () => p.locator("[data-note-row] [data-note-title]").evaluateAll((els) => els.map((e) => e.textContent.trim())); - const addChapter = async (name) => { + /* The colour is chosen while the chapter is being made. It is what tells one + chapter from the next, and having to right-click a fresh one to say which + it is meant two visits for a single decision. */ + const addChapter = async (name, colour = null) => { await p.locator("[data-add-chapter]").click(); await p.waitForTimeout(600); await p.getByLabel("Chapter name").fill(name); + if (colour) await p.locator(`[data-colour-option="${colour}"]`).click(); await p.getByRole("button", { name: "Create", exact: true }).click(); await p.waitForTimeout(2000); }; @@ -66,6 +70,31 @@ try { const server = (await api(p, "GET", "/chapters")).body; check(server.length === 1 && server[0].name === "Rechnungen", "the server has it", JSON.stringify(server)); + /* ── in an empty notebook too ── + * "Nothing here" was asked of the notes alone, so a notebook whose only + * contents were chapters showed the empty-list panel with the chapters hidden + * behind it: making a chapter in a fresh notebook appeared to do nothing. */ + await createNotebook(p, "Leeres Buch"); + await p.locator("button").filter({ hasText: "Leeres Buch" }).first().click(); + await p.waitForTimeout(1000); + await addChapter("Nur ein Kapitel", "#a371f7"); + check( + (await p.locator("[data-chapter-row]").count()) === 1, + "a chapter shows in a notebook that has no notes at all", + String(await p.locator("[data-chapter-row]").count()) + ); + const madeWithColour = (await api(p, "GET", "/chapters")).body.find((c) => c.name === "Nur ein Kapitel"); + check( + madeWithColour?.color === "#a371f7", + "and the colour picked while making it is stored with it", + String(madeWithColour?.color) + ); + check( + (await p.locator("[data-no-loose-notes]").count()) === 1, + "and the list says why it is otherwise empty rather than looking broken" + ); + await openNotebook(); + /* ── filing a note ── */ check( (await p.locator("[data-move-note]").count()) === 0, diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 7a0ea72..c7fe846 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -640,9 +640,17 @@ export default function App() { setInChapter(!!next); }; + /* Named and coloured in one go. The colour is what tells one chapter from the + next, so asking for it while the chapter is being made is one decision + rather than a second visit through the right-click menu. */ const addChapter = () => { if (!activeNotebook) return; - setNamingChapter({ title: "New chapter", value: "", onSave: (name) => data.createChapter(activeNotebook.id, name) }); + setNamingChapter({ + title: "New chapter", + value: "", + color: null, + onSave: (name, color) => data.createChapter(activeNotebook.id, name, color), + }); }; const chapterContextMenu = (e, chapter) => { @@ -653,24 +661,25 @@ export default function App() { y: e.clientY, items: [ { - label: "Rename", + label: "Rename or recolour", icon: I.edit, action: () => setNamingChapter({ - title: "Rename chapter", + title: "Chapter", value: chapter.name, - onSave: (name) => data.renameChapter(chapter.id, name), + color: chapter.color ?? null, + onSave: (name, color) => data.editChapter(chapter.id, { name, color }), }), }, { label: "Colour", icon: I.edit, submenu: [ - { label: "None", colorDot: T.faint, action: () => data.recolourChapter(chapter.id, null) }, + { label: "None", colorDot: T.faint, action: () => data.editChapter(chapter.id, { color: null }) }, ...CHAPTER_COLORS.map((c) => ({ label: c.label, colorDot: c.value, - action: () => data.recolourChapter(chapter.id, c.value), + action: () => data.editChapter(chapter.id, { color: c.value }), })), ], }, @@ -769,11 +778,6 @@ export default function App() { paddingLeft: 8, }} > - {inChapter && ( -
- · new notes land here -
- )} {chapterNotes.length === 0 && (
Nothing in here yet.
)} @@ -984,9 +988,6 @@ export default function App() { > {openChapter.name} - {inChapter && ( - · here - )} + ); + })} + + + )}