Storyline: unfoldable section list per chapter in the sidebar
Each chapter in the right-hand menu gets a caret that unfolds its numbered sections (e.g. the prologue's 28 scenes); clicking one jumps straight to it. The chapter you're reading starts unfolded, other chapters' sections link across (/storyline/overview#section-…), and the section at the top of the pane is highlighted as you scroll. - ChapterOutline service parses each rendered chapter for its <h2 class="storyline-section"> headings, adds anchor ids and returns the outline; the controller renders all chapters once to feed the sidebar. - storyline-toc Stimulus controller: fold/unfold, in-pane jump, scroll-spy (works in the split view and in the small-screen window-scroll fallback). - Tests for the outline parser. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,13 +12,33 @@
|
||||
<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">
|
||||
<ol class="list-unstyled mb-0" data-controller="storyline-toc">
|
||||
{% 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>
|
||||
{% set open = s == slug %}
|
||||
<li class="storyline-toc-item{{ open ? ' is-open' }}">
|
||||
<div class="storyline-toc-row">
|
||||
{% if sections[s] is not empty %}
|
||||
<button type="button" class="storyline-toc-fold" data-action="storyline-toc#fold"
|
||||
aria-expanded="{{ open ? 'true' : 'false' }}"
|
||||
aria-label="Show sections of {{ c.title }}">▸</button>
|
||||
{% else %}<span class="storyline-toc-fold"></span>{% endif %}
|
||||
<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>
|
||||
</div>
|
||||
{% if sections[s] is not empty %}
|
||||
<ol class="storyline-toc-sections list-unstyled">
|
||||
{% for sec in sections[s] %}
|
||||
<li>
|
||||
<a href="{{ s == slug ? '#' ~ sec.id : path('app_storyline_chapter', {slug: s}) ~ '#' ~ sec.id }}"
|
||||
class="storyline-toc-sub" {% if s == slug %}data-storyline-toc-target="link"{% endif %}>
|
||||
<span class="storyline-toc-num">{{ sec.num }}</span>{{ sec.title }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
@@ -33,7 +53,7 @@
|
||||
<p class="storyline-standfirst">{{ chapter.summary }}</p>
|
||||
</header>
|
||||
|
||||
{{ include(chapter.template) }}
|
||||
{{ body|raw }}
|
||||
</article>
|
||||
|
||||
<nav class="storyline-pager">
|
||||
|
||||
Reference in New Issue
Block a user