123 lines
5.3 KiB
Plaintext
123 lines
5.3 KiB
Plaintext
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<meta name="color-scheme" content="light dark" />
|
|
<title>Spine — Direction A (agenda)</title>
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2.1.1/css/pico.min.css" />
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tabler-icons/3.31.0/iconfont/tabler-icons.min.css" />
|
|
<style>
|
|
.agenda { font-family: var(--pico-font-family-monospace); padding: 0; overflow: hidden; }
|
|
.agenda > header, .agenda > footer { margin: 0; padding: .6rem .9rem; font-size: .85rem; }
|
|
.agenda > header { display: flex; justify-content: space-between; align-items: center; }
|
|
.group { padding: .65rem .9rem .2rem; font-size: .7rem; letter-spacing: .04em; color: var(--pico-muted-color); }
|
|
.row { display: flex; align-items: center; gap: .6rem; padding: .3rem .9rem; font-size: .85rem; }
|
|
.row.selected { background: var(--pico-card-sectioning-background-color); border-left: 2px solid var(--pico-primary); }
|
|
.row.selected .title { font-weight: 500; }
|
|
.row.selected .glyph { color: var(--pico-color); }
|
|
.glyph { width: 1rem; color: var(--pico-muted-color); flex-shrink: 0; }
|
|
.title { flex: 1; min-width: 0; }
|
|
.muted { color: var(--pico-muted-color); }
|
|
.tags { color: var(--pico-primary); font-size: .8rem; }
|
|
.trail { color: var(--pico-muted-color); font-size: .8rem; }
|
|
.pill { padding: .05rem .45rem; border-radius: var(--pico-border-radius); font-size: .7rem; font-weight: 500; }
|
|
.pill.want { background: #e6f1fb; color: #0c447c; }
|
|
.pill.reading { background: #faeeda; color: #854f0b; }
|
|
.pill.read { background: #e1f5ee; color: #085041; }
|
|
.detail { padding: .5rem .9rem .7rem 2rem; background: var(--pico-card-sectioning-background-color);
|
|
border-left: 2px solid var(--pico-primary); font-size: .8rem; }
|
|
.logline { display: flex; gap: .5rem; margin-bottom: .3rem; }
|
|
.logline:last-child { margin-bottom: 0; }
|
|
.logdate { color: var(--pico-muted-color); white-space: nowrap; }
|
|
.endpad { height: .4rem; }
|
|
.minibuffer { display: flex; gap: .5rem; align-items: center; }
|
|
.minibuffer .text { border-left: 2px solid var(--pico-primary); padding-left: .4rem; }
|
|
.caret { opacity: .5; }
|
|
@media (prefers-color-scheme: dark) {
|
|
.pill.want { background: #14304a; color: #b5d4f4; }
|
|
.pill.reading { background: #3a2c12; color: #fac775; }
|
|
.pill.read { background: #103a30; color: #9fe1cb; }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
{{!
|
|
View model for this template:
|
|
{
|
|
app_title: string,
|
|
total_books: number,
|
|
reading_count: number,
|
|
groups: [
|
|
{
|
|
label: string, e.g. "on deck"
|
|
count: number,
|
|
books: [
|
|
{
|
|
format_icon: string, Tabler class, e.g. "ti-headphones" (data layer maps FORMAT -> icon)
|
|
status_class: string, "want" | "reading" | "read" (maps Org TODO state -> pill style)
|
|
status_label: string, text shown in the pill
|
|
title: string,
|
|
author: string,
|
|
tags_inline: string?, optional, e.g. ":scifi:literary:"
|
|
rec_via: string?, optional, REC_BY -> rendered as "via {name}"
|
|
rating_display: string?, optional, e.g. "★★★★☆"
|
|
selected: boolean?, marks the in-focus row (expands detail)
|
|
detail: { optional; render when a row is expanded
|
|
meta: string, e.g. "started [2026-02-20] · hardcover · 62% · rating —"
|
|
notes: [ { date: string, text: string } ] reading log
|
|
}?
|
|
}
|
|
]
|
|
}
|
|
],
|
|
minibuffer: { command: string, text: string }? optional capture line
|
|
}
|
|
}}
|
|
<main class="container">
|
|
<article class="agenda" style="max-width: 720px; margin-inline: auto;">
|
|
<header>
|
|
<nav>
|
|
<ul><li><strong>{{app_title}}</strong></li></ul>
|
|
<ul>
|
|
<li><span class="muted">{{total_books}} books · {{reading_count}} reading</span></li>
|
|
<li><a role="button" href="/add" class="secondary">Add book</a></li>
|
|
</ul>
|
|
</nav>
|
|
</header>
|
|
|
|
{{#groups}}
|
|
<div class="group">{{label}} · {{count}}</div>
|
|
{{#books}}
|
|
<div class="row{{#selected}} selected{{/selected}}">
|
|
<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>
|
|
{{#tags_inline}}<span class="tags">{{tags_inline}}</span>{{/tags_inline}}
|
|
{{#rec_via}}<span class="trail">via {{rec_via}}</span>{{/rec_via}}
|
|
{{#rating_display}}<span class="trail">{{rating_display}}</span>{{/rating_display}}
|
|
</div>
|
|
{{#detail}}
|
|
<div class="detail">
|
|
<div class="muted" style="margin-bottom: .5rem;">{{meta}}</div>
|
|
{{#notes}}
|
|
<div class="logline"><span class="logdate">{{date}}</span><span>{{text}}</span></div>
|
|
{{/notes}}
|
|
</div>
|
|
{{/detail}}
|
|
{{/books}}
|
|
{{/groups}}
|
|
<div class="endpad"></div>
|
|
|
|
{{#minibuffer}}
|
|
<footer class="minibuffer">
|
|
<span class="muted">M-x</span>
|
|
<span>{{command}}</span>
|
|
<span class="text">{{text}}<span class="caret">▏</span></span>
|
|
</footer>
|
|
{{/minibuffer}}
|
|
</article>
|
|
</main>
|
|
</body>
|
|
</html>
|