Files
Escapepage/templates/website/escape_room/index.html.twig
T
FrankandClaude Sonnet 5 008887ab60 Add physical escape room map, reviews, and website admin
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>
2026-08-31 00:24:03 +02:00

75 lines
2.4 KiB
Twig

{% extends 'layout/site.html.twig' %}
{% block title %}Escape room map | {{ 'site.name'|trans }}{% endblock %}
{% block stylesheets %}
{{ parent() }}
{{ encore_entry_link_tags('escaperoom-map') }}
<style>
#escaperoom-map {
height: 70vh;
min-height: 420px;
width: 100%;
border-radius: 8px;
z-index: 0;
}
.escaperoom-list-wrap {
background: #fff;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, .07);
overflow: hidden;
}
.escaperoom-list-wrap table {
width: 100%;
border-collapse: collapse;
font-size: .9rem;
}
.escaperoom-list-wrap th,
.escaperoom-list-wrap td {
padding: .6rem .9rem;
text-align: left;
}
</style>
{% endblock %}
{% block body %}
{% set detailTemplate = path('website_escaperoom_show', {id: 987654321, slug: 'zzslugzz'})|replace({'987654321': '__ID__', 'zzslugzz': '__SLUG__'}) %}
<div class="d-flex flex-wrap align-items-baseline justify-content-between mb-3">
<div>
<h1 class="display-6 fw-bold mb-1">Physical escape rooms</h1>
<p class="text-secondary mb-0">Zoom in to find rooms near you, then open one to read and leave reviews.</p>
</div>
<div class="text-end">
<div id="escaperoom-status" class="small text-secondary">{{ publishedCount }} rooms on the map</div>
<a href="{{ path('website_escaperoom_suggest') }}" class="btn btn-sm btn-outline-primary mt-1">Suggest a room</a>
</div>
</div>
<div id="escaperoom-map"
data-endpoint="{{ path('website_escaperooms_data') }}"
data-detail-template="{{ detailTemplate }}"
class="mb-4"></div>
<div class="escaperoom-list-wrap">
<table id="escaperoom-list">
<thead>
<tr>
<th>Name</th>
<th>City</th>
<th>Country</th>
<th>Rating</th>
</tr>
</thead>
<tbody>
<tr><td colspan="4" class="text-center text-secondary py-4">Loading rooms…</td></tr>
</tbody>
</table>
</div>
{% endblock %}
{% block javascripts %}
{{ parent() }}
{{ encore_entry_script_tags('escaperoom-map') }}
{% endblock %}