feat: update HTTP handlers and templates for shelf model

This commit is contained in:
2026-06-21 22:58:52 -04:00
parent 346fd7af5b
commit c4248dcc89
3 changed files with 11 additions and 26 deletions
+1 -1
View File
@@ -407,7 +407,7 @@ Set by test harnesses that only need the model functions.")
(if books (if books
(insert (spine-render "index.mustache" (insert (spine-render "index.mustache"
(spine-index-model books shelf-filter (cadr (assoc "id" query))))) (spine-index-model books shelf-filter (cadr (assoc "id" query)))))
(insert (spine-render-empty-state)))) (insert (spine-render-empty-state)))))
(defun httpd/add (proc uri-path query request) (defun httpd/add (proc uri-path query request)
"Handle /add: GET shows form, POST creates a book." "Handle /add: GET shows form, POST creates a book."
+5 -4
View File
@@ -60,10 +60,11 @@
<form method="post" action="/add"> <form method="post" action="/add">
<label>Date added <input type="date" name="date_added" /></label> <label>Date added <input type="date" name="date_added" /></label>
<label>Title * <input type="text" name="title" required autofocus /></label> <label>Title * <input type="text" name="title" required autofocus /></label>
<label>Author <input type="text" name="author" list="authors-list" /></label> <label>Author <input type="text" name="author" /></label>
<datalist id="authors-list">{{#existing_authors}}<option value="{{.}}">{{/existing_authors}}</datalist> <label>Shelf * <select name="shelf" required>
<label>Category <input type="text" name="category" list="categories-list" /></label> <option value="">— select —</option>
<datalist id="categories-list">{{#existing_categories}}<option value="{{.}}">{{/existing_categories}}</datalist> {{#shelves}}<option value="{{.}}">{{.}}</option>{{/shelves}}
</select></label>
<label>Format <select name="format"><option value="">—</option><option value="hardcover">Hardcover</option><option value="ebook">eBook</option><option value="audiobook">Audiobook</option></select></label> <label>Format <select name="format"><option value="">—</option><option value="hardcover">Hardcover</option><option value="ebook">eBook</option><option value="audiobook">Audiobook</option></select></label>
<label>ISBN <input type="text" name="isbn" /></label> <label>ISBN <input type="text" name="isbn" /></label>
<label>Cover (path) <input type="text" name="cover" placeholder="covers/filename.jpg" /></label> <label>Cover (path) <input type="text" name="cover" placeholder="covers/filename.jpg" /></label>
+5 -21
View File
@@ -40,10 +40,6 @@
.group { padding:10px 14px 4px; font-size:11px; letter-spacing:0.04em; color: var(--text-tertiary); } .group { padding:10px 14px 4px; font-size:11px; letter-spacing:0.04em; color: var(--text-tertiary); }
.row { display:flex; align-items:center; gap:10px; padding:5px 14px; font-size:13px; } .row { display:flex; align-items:center; gap:10px; padding:5px 14px; font-size:13px; }
.glyph { font-size:15px; color:var(--text-tertiary); width:16px; } .glyph { font-size:15px; color:var(--text-tertiary); width:16px; }
.pill { padding:1px 7px; border-radius:var(--radius-md); font-size:11px; }
.pill.want { background:var(--bg-info); color:var(--text-info); }
.pill.reading { background:var(--bg-warning); color:var(--text-warning); }
.pill.read { background:var(--bg-success); color:var(--text-success); }
.title { flex:1; min-width:0; } .title { flex:1; min-width:0; }
.muted { color:var(--text-tertiary); } .muted { color:var(--text-tertiary); }
.tags { color:var(--text-info); font-size:12px; } .tags { color:var(--text-info); font-size:12px; }
@@ -66,30 +62,22 @@
<div class="frame"> <div class="frame">
<div class="titlebar"> <div class="titlebar">
<span style="font-weight:500;">spine</span> <span style="font-weight:500;">spine</span>
<span class="muted">{{total_books}} books · {{reading_count}} reading</span> <span class="muted">{{total_books}} books · {{shelf_count}} shelves</span>
</div> </div>
{{#current_filter}}
<div class="filter-bar"> <div class="filter-bar">
<a href="/index">Concise view</a> <a href="/index"{{^current_shelf}} style="font-weight:600"{{/current_shelf}}>All</a>
</div> {{#shelf_nav}}
{{/current_filter}}
{{^current_filter}}
<div class="filter-bar">
<a href="/index?filter=all">All books ({{total_books}})</a>
&nbsp;·&nbsp; &nbsp;·&nbsp;
<a href="/index?filter=want">Want list</a> <a href="{{href}}"{{#current}} style="font-weight:600"{{/current}}>{{name}}</a>
&nbsp;·&nbsp; {{/shelf_nav}}
<a href="/index?filter=read">Read ({{reading_count}})</a>
</div> </div>
{{/current_filter}}
{{#groups}} {{#groups}}
<div class="group">{{label}} · {{count}}</div> <div class="group">{{label}} · {{count}}</div>
{{#books}} {{#books}}
<div class="row{{#selected}} selected{{/selected}}"> <div class="row{{#selected}} selected{{/selected}}">
<i class="ti {{format_icon}} glyph" aria-hidden="true"></i> <i class="ti {{format_icon}} glyph" aria-hidden="true"></i>
<span class="pill {{status_class}}">{{status_label}}</span>
<span class="title">{{title}} <span class="muted">· {{author}}</span></span> <span class="title">{{title}} <span class="muted">· {{author}}</span></span>
{{#tags_inline}}<span class="tags">{{tags_inline}}</span>{{/tags_inline}} {{#tags_inline}}<span class="tags">{{tags_inline}}</span>{{/tags_inline}}
{{#rec_via}}<span class="trail">via {{rec_via}}</span>{{/rec_via}} {{#rec_via}}<span class="trail">via {{rec_via}}</span>{{/rec_via}}
@@ -106,10 +94,6 @@
{{/books}} {{/books}}
{{/groups}} {{/groups}}
{{#summary_groups}}
<div class="group"><a href="{{href}}" style="color:var(--text-info);text-decoration:none">{{label}} · {{count}}</a></div>
{{/summary_groups}}
{{#minibuffer}} {{#minibuffer}}
<div class="minibuffer"> <div class="minibuffer">
<span class="muted">M-x</span> <span class="muted">M-x</span>