Each chapter page gets a collapsible "Chapter notes" card at the top — a free-text log the DM fills during play (the story the party tells after the Crooked Goose, names given to NPCs, threads for next time). Saved per chapter slug with a "saved <timestamp>" marker, same shape as the Enemy/NPC game-notes field. New: ChapterNote entity (slug-keyed, unique) + repository findOrCreate(), ChapterNoteType form, chapter_note table migration (ENGINE = InnoDB pinned). The storyline chapter route now also accepts POST to save. Chapters stay hand-written Twig; only the mutable notes live in the DB. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
70 lines
3.3 KiB
Twig
70 lines
3.3 KiB
Twig
{% extends 'base.html.twig' %}
|
|
|
|
{% block title %}{{ chapter.title }} · Storyline · dmtools{% endblock %}
|
|
|
|
{% block body %}
|
|
<div class="row g-4 storyline-layout">
|
|
<nav class="col-lg-3 order-lg-2">
|
|
<div class="storyline-toc">
|
|
<a href="{{ path('app_storyline') }}" class="text-decoration-none small d-inline-block mb-2">← All chapters</a>
|
|
<div class="text-uppercase small text-body-secondary fw-semibold mb-2" style="letter-spacing:.08em">Chapters</div>
|
|
<ol class="list-unstyled mb-0">
|
|
{% for s, c in chapters %}
|
|
<li>
|
|
<a href="{{ path('app_storyline_chapter', {slug: s}) }}"
|
|
class="storyline-toc-link{{ s == slug ? ' is-active' }}">
|
|
<span class="storyline-toc-num">{{ c.tag }}</span>{{ c.title }}
|
|
</a>
|
|
</li>
|
|
{% endfor %}
|
|
</ol>
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="col-lg-9 order-lg-1">
|
|
<details class="card shadow-sm mb-4 storyline-notes" open>
|
|
<summary class="card-header d-flex justify-content-between align-items-center">
|
|
<span>📝 Chapter notes</span>
|
|
{% if note.updatedAt %}
|
|
<span class="text-body-secondary small fw-normal">saved {{ note.updatedAt|date('Y-m-d H:i') }}</span>
|
|
{% endif %}
|
|
</summary>
|
|
<div class="card-body">
|
|
<p class="text-body-secondary small mb-2">
|
|
Your running log for this chapter — what actually happened at the table.
|
|
</p>
|
|
{{ form_start(form) }}
|
|
{{ form_row(form.notes) }}
|
|
<button class="btn btn-primary mt-2">Save notes</button>
|
|
{{ form_end(form) }}
|
|
</div>
|
|
</details>
|
|
|
|
<article class="storyline-doc">
|
|
<header class="storyline-doc-head">
|
|
<div class="storyline-eyebrow">Storyline · {{ chapter.eyebrow }}</div>
|
|
<h1>{{ chapter.title }}</h1>
|
|
<p class="storyline-standfirst">{{ chapter.summary }}</p>
|
|
</header>
|
|
|
|
{{ include(chapter.template) }}
|
|
</article>
|
|
|
|
<nav class="storyline-pager">
|
|
{% if prev %}
|
|
<a href="{{ path('app_storyline_chapter', {slug: prev}) }}" class="storyline-pager-link">
|
|
<span class="storyline-pager-dir">← Previous</span>
|
|
<span class="storyline-pager-title">{{ chapters[prev].title }}</span>
|
|
</a>
|
|
{% else %}<span></span>{% endif %}
|
|
{% if next %}
|
|
<a href="{{ path('app_storyline_chapter', {slug: next}) }}" class="storyline-pager-link text-lg-end">
|
|
<span class="storyline-pager-dir">Next →</span>
|
|
<span class="storyline-pager-title">{{ chapters[next].title }}</span>
|
|
</a>
|
|
{% else %}<span></span>{% endif %}
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|