Public:
- /escape-rooms: Leaflet + OpenStreetMap map with marker clustering and a
searchable list, both built from a cached slim JSON feed
- /escape-rooms/{id}-{slug}: room detail with a mini-map and user reviews
(rating + title + body, login required)
- /escape-rooms/suggest: visitor submission form with click-to-drop-pin map
and reCAPTCHA v3; new rooms land as pending
Data:
- EscapeRoom / EscapeRoomReview entities (soft-delete), migration
- app:escaperooms:import-osm console command pulls leisure=escape_game from
the Overpass API, upserts by (osmType, osmId), skips locked rows;
--tiled / --area / --bbox options
Admin (new "Website Admin" area, separate from Game Admin):
- src/Website/Controller/AdminEscapeRoomController.php at /admin/escape-rooms:
status-filtered list, new/edit, publish/hide/reject, delete, review removal
- game admin sidebar extracted into a block and cross-linked
Assets: leaflet + leaflet.markercluster; escaperoom-map and escaperoom-detail
Encore entries.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
83 lines
3.7 KiB
Twig
83 lines
3.7 KiB
Twig
{% extends 'base.html.twig' %}
|
|
|
|
{% block header %}
|
|
<header class="site-header">
|
|
<nav class="navbar navbar-expand-lg navbar-dark">
|
|
<div class="container">
|
|
<a class="navbar-brand" href="{{ path('website_home') }}">
|
|
<img src="{{ asset('images/logo.png') }}" alt="{{ 'site.name'|trans }}">
|
|
{{ 'site.name'|trans }}
|
|
</a>
|
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#siteNav"
|
|
aria-controls="siteNav" aria-expanded="false" aria-label="Toggle navigation">
|
|
<span class="navbar-toggler-icon"></span>
|
|
</button>
|
|
<div class="collapse navbar-collapse" id="siteNav">
|
|
<ul class="navbar-nav ms-auto align-items-lg-center gap-lg-2">
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="{{ path('website_home') }}">{{ 'nav.home'|trans }}</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="{{ path('game_dashboard') }}">{{ 'nav.game'|trans }}</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="{{ path('website_escaperooms') }}">{{ 'nav.escaperooms'|trans }}</a>
|
|
</li>
|
|
{% if app.user %}
|
|
{% if is_granted('ROLE_ADMIN') %}
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="{{ path('game_admin_dashboard') }}">{{ 'nav.admin'|trans }}</a>
|
|
</li>
|
|
{% endif %}
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="{{ path('app_profile') }}">{{ 'nav.profile'|trans }}</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="{{ path('app_logout') }}">{{ 'nav.logout'|trans }}</a>
|
|
</li>
|
|
{% else %}
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="{{ path('app_register') }}">{{ 'nav.register'|trans }}</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="btn btn-sm btn-outline-light ms-lg-2" href="{{ path('app_login') }}">{{ 'nav.login'|trans }}</a>
|
|
</li>
|
|
{% endif %}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
{% endblock %}
|
|
|
|
{% block main %}
|
|
<main class="site-main">
|
|
<div class="container py-4">
|
|
{% for label, messages in app.flashes %}
|
|
{% for message in messages %}
|
|
<div class="alert alert-{{ 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 %}
|
|
{% block body %}{% endblock %}
|
|
</div>
|
|
</main>
|
|
{% endblock %}
|
|
|
|
{% block footer %}
|
|
<footer class="site-footer py-4">
|
|
<div class="container text-center small">
|
|
<div class="mb-1">
|
|
<a href="{{ path('website_contact') }}" class="link-light">{{ 'footer.contact'|trans }}</a>
|
|
·
|
|
<a href="{{ path('website_help_wanted') }}" class="link-light">{{ 'footer.help_wanted'|trans }}</a>
|
|
·
|
|
<a href="{{ path('website_terms') }}" class="link-light">{{ 'footer.terms'|trans }}</a>
|
|
</div>
|
|
© {{ "now"|date("Y") }} {{ 'site.name'|trans }}
|
|
</div>
|
|
</footer>
|
|
{% endblock %}
|