Storyline: chapter structure + formatted Campaign Overview
The Storyline section is now a set of hand-written chapters. /storyline
lists them; /storyline/{slug} renders one inside a shell with a sticky
chapter nav and prev/next pager. Chapters are declared in
StorylineController::CHAPTERS, each pointing at a Twig partial under
templates/storyline/chapters/.
First chapter is the Brackenford Campaign Overview: the campaign-bible
text laid out as a long-form reading page -- numbered section headers,
a "by the numbers" / "the cast" quick-reference strip, pull-quotes for
in-world lines, GM callouts for the ticking clocks and the red herring,
and the escalation ladder. Storyline styles added to app.css.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,9 +10,46 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
#[IsGranted('IS_AUTHENTICATED_FULLY')]
|
||||
class StorylineController extends AbstractController
|
||||
{
|
||||
#[Route('/storyline', name: 'app_storyline')]
|
||||
/**
|
||||
* The storyline is a set of hand-written chapters. Each entry points at a
|
||||
* Twig partial under templates/storyline/chapters/. Add a chapter by adding
|
||||
* a row here and the matching template; order in this array is reading order.
|
||||
*
|
||||
* @var array<string, array{title: string, summary: string, template: string}>
|
||||
*/
|
||||
private const CHAPTERS = [
|
||||
'overview' => [
|
||||
'title' => 'Campaign Overview',
|
||||
'summary' => 'The whole shape of the Brackenford campaign, from the sealing of Kyuss four centuries ago to the final crisis — the truth behind the blood, the red herring around Sir Aldren, and how it can resolve.',
|
||||
'template' => 'storyline/chapters/overview.html.twig',
|
||||
],
|
||||
];
|
||||
|
||||
#[Route('/storyline', name: 'app_storyline', methods: ['GET'])]
|
||||
public function index(): Response
|
||||
{
|
||||
return $this->render('storyline/index.html.twig');
|
||||
return $this->render('storyline/index.html.twig', [
|
||||
'chapters' => self::CHAPTERS,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/storyline/{slug}', name: 'app_storyline_chapter', requirements: ['slug' => '[a-z0-9-]+'], methods: ['GET'])]
|
||||
public function chapter(string $slug): Response
|
||||
{
|
||||
if (!isset(self::CHAPTERS[$slug])) {
|
||||
throw $this->createNotFoundException('No such storyline chapter.');
|
||||
}
|
||||
|
||||
$slugs = array_keys(self::CHAPTERS);
|
||||
$pos = array_search($slug, $slugs, true);
|
||||
|
||||
return $this->render('storyline/chapter.html.twig', [
|
||||
'chapters' => self::CHAPTERS,
|
||||
'slug' => $slug,
|
||||
'number' => $pos + 1,
|
||||
'chapter' => self::CHAPTERS[$slug],
|
||||
'prev' => $pos > 0 ? $slugs[$pos - 1] : null,
|
||||
'next' => $pos < \count($slugs) - 1 ? $slugs[$pos + 1] : null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user