Scaffold Symfony 8 app with Bootstrap/DataTables and Docker stack
- Symfony 8.1 webapp skeleton on PHP 8.5 (AssetMapper/importmap, no Node)
- Form-login gate: User entity, security.yaml, SecurityController,
app:user:create command, initial migration (user + messenger_messages)
- Bootstrap 5 + DataTables layout (base/login/home templates); any
table.datatable is auto-initialised
- trusted_proxies/headers wired for the shared Nginx Proxy Manager
- Docker (servers only): docker-compose.yml (php:8.5-fpm-alpine,
nginx:1.30-alpine, mariadb:12.3; host ports 8085/3310; external
docker_default network) + docker/{Dockerfile,php.ini,nginx,setup.sh,restart.sh}
- .env with CHANGEME placeholders (no secrets), .gitattributes enforces
LF so the deploy scripts stay runnable on Linux
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{% block title %}dmtools{% endblock %}</title>
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.1em%22 font-size=%22104%22>🎲</text></svg>">
|
||||
|
||||
{% block stylesheets %}{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
{% block importmap %}{{ importmap('app') }}{% endblock %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body class="d-flex flex-column">
|
||||
{% block navbar %}
|
||||
<nav class="navbar navbar-expand-lg bg-body-tertiary border-bottom">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="{{ path('app_home') }}">🎲 dmtools</a>
|
||||
{% if app.user %}
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<span class="navbar-text small">{{ app.user.userIdentifier }}</span>
|
||||
<a class="btn btn-outline-secondary btn-sm" href="{{ path('app_logout') }}">Log out</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</nav>
|
||||
{% endblock %}
|
||||
|
||||
<main class="app-main flex-grow-1">
|
||||
<div class="container">
|
||||
{% block flashes %}
|
||||
{% for label, messages in app.flashes %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{{ label == 'error' ? 'danger' : label }} alert-dismissible fade show" role="alert">
|
||||
{{ message }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}{% endblock %}
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,39 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Overview · dmtools{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h1 class="h3 mb-0">Overview</h1>
|
||||
</div>
|
||||
|
||||
<p class="text-body-secondary">
|
||||
Starting point for the Monday-evening campaign tools. The table below is a
|
||||
placeholder that shows the Bootstrap + DataTables layout wiring works
|
||||
(search, sort, paging).
|
||||
</p>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<table class="table table-striped table-hover align-middle datatable"
|
||||
data-datatable-options='{"order": [[0, "asc"]]}'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Type</th>
|
||||
<th scope="col">Location</th>
|
||||
<th scope="col">Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>Seraphina Vane</td><td>NPC</td><td>Blackreach</td><td>Owes the party a favour</td></tr>
|
||||
<tr><td>Goblin ambush</td><td>Encounter</td><td>Old Kings Road</td><td>CR 2, 6 goblins</td></tr>
|
||||
<tr><td>The Sunken Vault</td><td>Location</td><td>Lake Nydra</td><td>Water-breathing required</td></tr>
|
||||
<tr><td>Rusted Key</td><td>Item</td><td>Party inventory</td><td>Opens the vault antechamber</td></tr>
|
||||
<tr><td>Captain Dorae</td><td>NPC</td><td>Saltmarsh docks</td><td>Will smuggle cargo for coin</td></tr>
|
||||
<tr><td>Owlbear den</td><td>Encounter</td><td>Whisperwood</td><td>CR 3, mother + 2 cubs</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,44 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Sign in · dmtools{% endblock %}
|
||||
|
||||
{% block navbar %}
|
||||
<nav class="navbar bg-body-tertiary border-bottom">
|
||||
<div class="container">
|
||||
<span class="navbar-brand">🎲 dmtools</span>
|
||||
</div>
|
||||
</nav>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="card login-card shadow-sm">
|
||||
<div class="card-body p-4">
|
||||
<h1 class="h4 mb-3 text-center">Sign in</h1>
|
||||
|
||||
<form method="post">
|
||||
{% if error %}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
{{ error.messageKey|trans(error.messageData, 'security') }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">Email</label>
|
||||
<input type="email" value="{{ last_username }}" name="_username" id="username"
|
||||
class="form-control" autocomplete="email" required autofocus>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<input type="password" name="_password" id="password"
|
||||
class="form-control" autocomplete="current-password" required>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="_csrf_token" data-controller="csrf-protection"
|
||||
value="{{ csrf_token('authenticate') }}">
|
||||
|
||||
<button class="btn btn-primary w-100" type="submit">Sign in</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user