164 lines
5.5 KiB
Markdown
164 lines
5.5 KiB
Markdown
# Spine — Pico CSS styling
|
|
|
|
Styles the index page using [Pico CSS v2](https://picocss.com/) via CDN,
|
|
restructuring HTML to use Pico-native semantic elements and adding a small
|
|
custom `<style>` block for the few things Pico doesn't cover.
|
|
|
|
## CSS strategy
|
|
|
|
- **Pico CSS v2** loaded from CDN:
|
|
`https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css`
|
|
- No build step. No local CSS file. No Sass/PostCSS.
|
|
- Light/dark theme auto-switches via `prefers-color-scheme` (Pico default).
|
|
- Custom styles in a single inline `<style>` block inside `<head>`.
|
|
- **No Tabler Icons.** Format glyphs use emoji instead.
|
|
|
|
## HTML restructure
|
|
|
|
Pico styles semantic elements. The current `<div>`-heavy output is rewritten
|
|
to use Pico-native elements. Only `spine-` prefixed classes remain for
|
|
layout pieces Pico doesn't provide.
|
|
|
|
| Current element | New element | Purpose |
|
|
|---|---|---|
|
|
| `<div class="frame">` | `<article>` | Card container (Pico styles borders/padding) |
|
|
| `<div class="titlebar">` | `<header>` inside `<article>` | Title bar with book count |
|
|
| `<div class="group">WANT (3)</div>` | `<hgroup><h2>WANT</h2><small>3</small></hgroup>` | Group header with count |
|
|
| `<div class="row">` | `<div class="spine-row">` | Book row (flex, Pico has no horizontal list) |
|
|
| `<div class="detail">` | `<blockquote class="spine-detail">` | Expanded notes section |
|
|
| `<span class="pill want">` | `<mark class="want">want</mark>` | Status badge (colored per status) |
|
|
| `<span class="glyph">` | `<span class="spine-glyph">` | Format emoji |
|
|
| `<span class="title">` | `<span class="spine-title">` | Book title + author |
|
|
| `<span class="muted">` | `<small>` | Author name (Pico styles `<small>` as muted) |
|
|
| `<span class="tags">` | `<small>` with tag text | Category tags |
|
|
| `<span class="trail">` | `<span class="spine-trail">` | Recommendation trail |
|
|
|
|
## Custom CSS
|
|
|
|
In an inline `<style>` block in `<head>`:
|
|
|
|
```css
|
|
.spine-row {
|
|
display: flex; align-items: center; gap: 0.75rem;
|
|
padding: 0.4rem 0;
|
|
border-bottom: 1px solid var(--pico-muted-border-color);
|
|
}
|
|
.spine-row:last-child { border-bottom: none; }
|
|
.spine-selected { background: var(--pico-secondary-background); }
|
|
.spine-glyph { width: 1.5rem; text-align: center; flex-shrink: 0; }
|
|
.spine-title { flex: 1; min-width: 0; }
|
|
.spine-trail { font-size: 0.85em; color: var(--pico-muted-color); }
|
|
.spine-detail {
|
|
margin: 0 0 0 2rem;
|
|
border-left: 2px solid var(--pico-primary);
|
|
}
|
|
.spine-detail p { margin-bottom: 0.3rem; }
|
|
.spine-detail footer { margin-top: 0.5rem; }
|
|
|
|
/* Status pill colors */
|
|
mark.want { background: var(--pico-mark-background); color: var(--pico-mark-color); }
|
|
mark.reading { background: #faeeda; color: #854f0b; }
|
|
mark.read { background: #e1f5ee; color: #085041; }
|
|
mark.abandoned { background: var(--pico-muted-color); color: var(--pico-background-color); }
|
|
|
|
/* Pico-specific overrides */
|
|
article { margin-bottom: 0; }
|
|
article header { padding-bottom: 0.5rem; margin-bottom: 0.5rem; }
|
|
```
|
|
|
|
## Format glyphs
|
|
|
|
Emoji per format, empty string if unset:
|
|
|
|
| Format | Glyph |
|
|
|---|---|
|
|
| `hardcover` | 📖 |
|
|
| `ebook` | 📱 |
|
|
| `audiobook` | 🎧 |
|
|
| `nil` / unset | (empty) |
|
|
|
|
## Full page shell
|
|
|
|
```html
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Spine</title>
|
|
<link rel="stylesheet"
|
|
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css">
|
|
<style>…custom styles…</style>
|
|
</head>
|
|
<body>
|
|
<main class="container">
|
|
<article>
|
|
<header>
|
|
<strong>spine</strong>
|
|
<small>N books · M reading</small>
|
|
</header>
|
|
…groups and rows…
|
|
</article>
|
|
</main>
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
## Example output (Use of Weapons, expanded)
|
|
|
|
```html
|
|
<hgroup><h2>READING</h2><small>1</small></hgroup>
|
|
|
|
<div class="spine-row spine-selected">
|
|
<span class="spine-glyph">🎧</span>
|
|
<span class="spine-title">Use of Weapons <small>Iain M. Banks</small></span>
|
|
<small>:scifi: :literary:</small>
|
|
<span class="spine-trail">Priya: If you liked Player of Games, this one will wreck you</span>
|
|
<mark class="reading">reading</mark>
|
|
|
|
<blockquote class="spine-detail">
|
|
<p><small>[2026-03-02]</small> The two-track structure is doing something I can't name yet.</p>
|
|
<p><small>[2026-03-07]</small> Zakalwe's competence reads as a wound.</p>
|
|
<p><small>[2026-03-09]</small> The chapter numbering. Oh.</p>
|
|
<footer>Format: audiobook · ISBN: 978-0316029193 · Added: [2026-02-20]</footer>
|
|
</blockquote>
|
|
</div>
|
|
```
|
|
|
|
## Empty state
|
|
|
|
```html
|
|
<article>
|
|
<header><strong>spine</strong></header>
|
|
<p>No books yet.</p>
|
|
</article>
|
|
```
|
|
|
|
## Files changed
|
|
|
|
- `spine.el` — `spine-render-index` and `spine-render-empty-state` rewritten
|
|
to emit Pico-structured HTML with inline CSS
|
|
|
|
No new files. No new dependencies beyond the CDN `<link>`.
|
|
|
|
## Out of scope
|
|
|
|
- JavaScript interactivity
|
|
- Cover image display
|
|
- Write endpoints
|
|
- Per-note format
|
|
- `?id=` selection without page reload (full page reload only)
|
|
|
|
## Acceptance
|
|
|
|
- [ ] Page renders with Pico CSS applied (fonts, spacing, colors match Pico defaults)
|
|
- [ ] Light/dark mode switches with OS preference
|
|
- [ ] Groups appear in order: WANT, READING, READ — zero-book groups omitted
|
|
- [ ] `?id=...` expands the matching book's detail with reading notes
|
|
- [ ] Status pills have distinct colors per state
|
|
- [ ] Format shown as emoji glyph
|
|
- [ ] Recommendation trail shown when `REC_BY` present
|
|
- [ ] Empty state shows "No books yet."
|
|
- [ ] No console 404s (Pico CDN resolves)
|
|
- [ ] No Tabler Icons reference in output
|