The chapter page now fills the viewport as two horizontal panes: the
chapter scrolls in the top ~2/3, the notes sit in a fixed dock in the
bottom ~1/3, always visible while you read. Drag the divider to change
the ratio, click the "Chapter notes" header to collapse the dock to a
bar; both the height and the collapsed state persist in localStorage.
- base.html.twig: add a {% block body_class %} hook on <body>.
- chapter.html.twig sets body class "storyline-chapter-page"; the split
layout CSS is scoped to it and falls back to normal stacked flow under
768px wide or 560px tall.
- app.js publishes the navbar height as --app-nav-h so the split can size
itself to viewport-minus-navbar even when the navbar wraps.
- new chapter_notes Stimulus controller: drag-resize + collapse + persist.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
dmtools
DM tools for the Monday-evening D&D campaign.
Symfony 8 (PHP 8.5) web app with a Bootstrap 5 + DataTables front end served through Symfony AssetMapper (no Node build step). Behind a form-login gate; there is no self-registration.
- Not run in Docker locally (Windows dev box uses the Symfony CLI + local MariaDB).
- Is Dockerized on the testing and live servers, behind the shared Nginx
Proxy Manager at
https://dmtools.fvandenberg.nl.
Repo: https://gitea.fvandenberg.nl/Frank/dmtools.git
Local development (dev box)
Prerequisites: PHP 8.5 at C:\php (on PATH so the Symfony CLI discovers it —
symfony local:php:list should show 8.5), the Symfony CLI, Composer, and a local
MariaDB/MySQL (WAMP is fine). .php-version pins this directory to PHP 8.5.
# 1. Point the app at your local database + dev mode
cp .env .env.local
# then edit .env.local:
# APP_ENV=dev
# DATABASE_URL="mysql://root:@127.0.0.1:3307/dmtools?serverVersion=10.10.2-MariaDB&charset=utf8mb4"
# 2. Install and build
symfony composer install
symfony console doctrine:database:create
symfony console doctrine:migrations:migrate -n
symfony console importmap:install
# 3. First user, then run
symfony console app:user:create you@example.com --admin
symfony serve -d
symfony open:local
serverVersion must match your local engine (SELECT VERSION();).
Servers (testing + live)
Docker only. docker/setup.sh pins the compose project name to dmtools
(containers dmtools-php, dmtools-nginx, dmtools-db).
git pull
cp .env .env.local # first time only
# edit .env.local: real APP_SECRET (or let setup.sh generate it),
# DB_PASSWORD, DB_ROOT_PASSWORD, and NGINX_PORT / DB_HOST_PORT if 8085 / 3310 clash
./docker/setup.sh
docker compose -p dmtools exec php php bin/console app:user:create you@example.com --admin
Ports (bound to 127.0.0.1 on the host): nginx 8085 → :80, db 3310 → :3306.
Reverse proxy (Nginx Proxy Manager)
Add a proxy host: dmtools.fvandenberg.nl → forward to host dmtools-nginx,
port 80, scheme http; request a Let's Encrypt certificate.
NPM must be able to resolve dmtools-nginx, i.e. be on the dmtools_default
network. setup.sh connects it (nginx_app_1 by default; override with
NPM_CONTAINER=...); to do it by hand:
docker network connect dmtools_default nginx_app_1
NPM keeps that connection across restarts; it's only needed again after a
docker compose down drops the network.
Common commands
docker compose -p dmtools logs -f php
docker compose -p dmtools exec php bash
docker compose -p dmtools exec php php bin/console doctrine:migrations:migrate
./docker/restart.sh # full down + bring-up (no rebuild)
./docker/setup.sh --down # stop the stack
Layout notes
table.datatablein any Twig template is auto-initialised as a DataTable (assets/app.js). Opt out withdata-datatable="false"; pass options as JSON indata-datatable-options.assets/vendor/andpublic/assets/are generated (git-ignored);importmap:installon the server re-downloads vendored packages, so the servers need outbound HTTPS to jsDelivr at deploy time.