Add NPC database table with server-side DataTable and per-NPC game notes
- Npc entity (village spreadsheet columns) + game_notes text field for
the DM's live play notes, plus updated_at touched on every change
- Race / VillageStatus / BloodCartInvolvement / MysteryImportance as
string-backed PHP enums, rendered as dropdowns on the edit form
- /npcs: server-side DataTables (paging, global search and column sort
all run in the backend via NpcRepository::findForDataTable); name cell
links to the edit page, game notes shown truncated
- /npcs/{id}: Bootstrap-themed edit form (all fields + a large game
notes textarea); Symfony forms now use the bootstrap_5 theme
- app.js: generic server-side DataTable wiring driven by data-* on the
<table>/<th> (data-datatable-src, data-row-url, data-format)
- app:npc:import console command - upserts from data/npcs.csv by
(family, name), never overwrites game_notes; --purge / --dry-run
- data/npcs.csv: 180 villagers exported from the working spreadsheet
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}{{ npc.name }} · NPC's · dmtools{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<div>
|
||||
<a href="{{ path('app_npcs') }}" class="text-decoration-none small">← All NPC's</a>
|
||||
<h1 class="h3 mb-0">{{ npc.name }}</h1>
|
||||
</div>
|
||||
{% if npc.updatedAt %}
|
||||
<span class="text-body-secondary small">Updated {{ npc.updatedAt|date('Y-m-d H:i') }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{{ form_start(form) }}
|
||||
<div class="row g-4">
|
||||
<div class="col-lg-5">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header">Details</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-8">{{ form_row(form.name) }}</div>
|
||||
<div class="col-4">{{ form_row(form.age) }}</div>
|
||||
</div>
|
||||
{{ form_row(form.family) }}
|
||||
{{ form_row(form.race) }}
|
||||
{{ form_row(form.occupation) }}
|
||||
{{ form_row(form.villageStatus) }}
|
||||
{{ form_row(form.bloodCartInvolvement) }}
|
||||
{{ form_row(form.mysteryImportance) }}
|
||||
{{ form_row(form.relationships) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-7">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header">Game notes</div>
|
||||
<div class="card-body">
|
||||
{{ form_row(form.gameNotes, {label: false}) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 d-flex gap-2">
|
||||
<button class="btn btn-primary">Save</button>
|
||||
<a href="{{ path('app_npcs') }}" class="btn btn-outline-secondary">Cancel</a>
|
||||
</div>
|
||||
{{ form_end(form) }}
|
||||
{% endblock %}
|
||||
@@ -3,9 +3,32 @@
|
||||
{% block title %}NPC's · dmtools{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
{{ include('_partials/page_placeholder.html.twig', {
|
||||
title: "NPC's",
|
||||
icon: '🧙',
|
||||
blurb: 'Non-player characters will live here — searchable list with faction, location and notes. Data model to be designed.',
|
||||
}) }}
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h1 class="h3 mb-0">NPC's</h1>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<table class="table table-striped table-hover align-middle datatable w-100"
|
||||
data-datatable-src="{{ path('app_npcs_data') }}"
|
||||
data-row-url="{{ path('app_npcs') }}/__ID__"
|
||||
data-datatable-options='{"order": [[0, "asc"]]}'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-data="name" data-format="link">Name</th>
|
||||
<th data-data="family">Family</th>
|
||||
<th data-data="age">Age</th>
|
||||
<th data-data="race">Race</th>
|
||||
<th data-data="occupation">Occupation</th>
|
||||
<th data-data="villageStatus">Village status</th>
|
||||
<th data-data="bloodCartInvolvement">Blood cart</th>
|
||||
<th data-data="mysteryImportance">Mystery</th>
|
||||
<th data-data="gameNotes" data-format="truncate" data-orderable="false">Game notes</th>
|
||||
<th data-data="updatedAt">Updated</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user