From fa1992f20012618ece12000f733f9436ee1ba59c Mon Sep 17 00:00:00 2001 From: gator Date: Thu, 17 Sep 2026 02:43:12 +0000 Subject: [PATCH] book.html: let a book be named, because a filename is not a title Uploading "Memory Road interior 12-28.pdf" produced a book, a run and a storyboard all headed "Memory Road interior 12-28". The title is derived from the filename because that is the only thing an upload carries, and publishers name files after print runs. Guessing harder is the wrong fix - stripping "interior 12-28" would be a rule that works on one file. Letting the author type the title takes eight lines and is right for every file. The author field goes in at the same time; it costs nothing and a trailer should know whose book it is. --- book.html | 46 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/book.html b/book.html index 84ec8b5..2763094 100644 --- a/book.html +++ b/book.html @@ -25,6 +25,9 @@ border:1px dashed var(--line);border-radius:12px;padding:18px} .pick.on{border-color:var(--accent);border-style:solid} .pick .or{color:var(--muted);font-size:13px} + .rename{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px} + .rename input{font:inherit;font-size:13px;background:transparent;color:var(--ink); + border:1px solid var(--line);border-radius:8px;padding:6px 9px} .writers{display:flex;flex-wrap:wrap;gap:10px;margin-top:8px} .wr{display:flex;gap:8px;align-items:center;border:1px solid var(--line); border-radius:10px;padding:9px 12px;cursor:pointer} @@ -125,7 +128,7 @@ function readFileB64(file) { if (!email) return; navBar("trailer"); - var BOOKS = [], PICKED = null, WRITERS = [], CHOSEN = {}, LEAD = ""; + var BOOKS = [], PICKED = null, WRITERS = [], CHOSEN = {}, LEAD = "", EDIT = null; var pollTimer = null; // ---------------------------------------------------------------- books @@ -141,17 +144,30 @@ function readFileB64(file) { } else { sub = "reading the manuscript…"; } + // A filename is not a title. Publishers name files after print runs, so + // the derived title is a starting point the author can correct. + var rename = EDIT === b.id + ? '
' + + '' + + '' + + '' + + '' + + '
' + : ''; return '
' + '
' + '

' + esc(b.title || "Untitled") + '

' - + '
' + sub + (b.created_at ? ' · ' + esc(when(b.created_at)) : '') + '
' + + '
' + (b.author ? esc(b.author) + ' · ' : '') + sub + + (b.created_at ? ' · ' + esc(when(b.created_at)) : '') + '
' + (st === "failed" && b.note ? '
' + esc(b.note) + '
' : '') + + rename + '
' + '
' + '' + esc(st) + '' + (st === "ready" ? '' + + '' : '') + '' + '
'; @@ -179,13 +195,26 @@ function readFileB64(file) { } document.getElementById("books").addEventListener("click", async function (e) { - var pick = e.target.getAttribute("data-pick"); - var del = e.target.getAttribute("data-del"); + var t = e.target; + var pick = t.getAttribute("data-pick"), del = t.getAttribute("data-del"); + var edit = t.getAttribute("data-edit"), save = t.getAttribute("data-save"); + if (t.getAttribute("data-cancel")) { EDIT = null; paintBooks(); return; } + if (edit) { EDIT = edit; paintBooks(); return; } + if (save) { + var title = document.getElementById("rt").value.trim(); + var author = document.getElementById("ra").value.trim(); + if (!title) { showMsg("msg", "A book needs a title."); return; } + t.disabled = true; + var u = await api("update_book", { book_id: save, title: title, author: author }); + if (!u.ok) { showMsg("msg", u.error || "That did not save."); t.disabled = false; return; } + hideMsg("msg"); EDIT = null; loadBooks(); + return; + } if (pick) { PICKED = pick; hideMsg("msg"); paintBooks(); paintQuote(); return; } if (del) { - e.target.disabled = true; + t.disabled = true; var r = await api("delete_book", { book_id: del }); - if (!r.ok) { showMsg("msg", r.error || "Could not remove that."); e.target.disabled = false; return; } + if (!r.ok) { showMsg("msg", r.error || "Could not remove that."); t.disabled = false; return; } if (PICKED === del) PICKED = null; loadBooks(); } @@ -227,6 +256,9 @@ function readFileB64(file) { resetPick(); if (!r.ok) { showMsg("msg", r.error || "That upload did not go through."); return; } PICKED = null; + // Straight into rename: the derived title is a guess and this is the one + // moment the author is looking at it. + EDIT = r.book && r.book.id; loadBooks(); } @@ -275,7 +307,7 @@ function readFileB64(file) { // Writing is the cheap half. Drawing the storyboards is priced separately, // per writer, once you have read the scripts. el.innerHTML = n + " writer" + (n > 1 ? "s" : "") - + " · about $" + (n * 0.6).toFixed(2) + " to write" + + " · about $" + (n * 0.85).toFixed(2) + " to write a full-length novel" + " · storyboards are priced separately once you have read them"; }