left4me/l4d2web/templates/blueprint_detail.html
mwiegand a4e9f6cd26
feat(l4d2-web): blueprint overlay picker — drag-list + add-dropdown
Replace the per-row checkbox + numeric Order table on the blueprint
detail page with a drag-to-reorder list of selected overlays plus a
native <select> for adding more. Removing uses an × button per row;
the option sorted-inserts back into the dropdown alphabetically.

Native HTML5 drag-and-drop, no library, no JS-disabled fallback.
Server contract is unchanged: each list row owns one hidden
<input name="overlay_ids">, DOM order = submission order, and the
existing fallback_position branch in ordered_overlay_ids_from_form
absorbs the now-omitted overlay_position_<id> fields.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 21:37:11 +02:00

60 lines
3 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "base.html" %}
{% block title %}Blueprint {{ blueprint.name }} | left4me{% endblock %}
{% block content %}
<section class="panel">
<div class="page-heading">
<h1>Blueprint: {{ blueprint.name }}</h1>
<button type="button" class="danger" data-modal-open="delete-blueprint-modal">Delete</button>
</div>
<form method="post" action="/blueprints/{{ blueprint.id }}" class="stack">
<input type="hidden" name="csrf_token" value="{{ session.get('csrf_token', '') }}">
<label>Name <input name="name" value="{{ blueprint.name }}" required></label>
<p class="muted">Overlay order matters: the first overlay has highest precedence.</p>
<div class="overlay-picker">
<ol class="overlay-picker-list" data-overlay-list>
{% for overlay in selected_overlays %}
<li class="overlay-picker-row" draggable="true" data-overlay-id="{{ overlay.id }}" data-overlay-name="{{ overlay.name }}">
<span class="overlay-picker-handle" aria-hidden="true">⋮⋮</span>
<span class="overlay-picker-name">{{ overlay.name }}</span>
<button type="button" class="overlay-picker-remove" data-action="remove" aria-label="Remove {{ overlay.name }}">×</button>
<input type="hidden" name="overlay_ids" value="{{ overlay.id }}">
</li>
{% endfor %}
</ol>
<p class="overlay-picker-empty muted" data-overlay-empty {% if selected_overlays %}hidden{% endif %}>No overlays selected. Pick one below to add.</p>
<label class="overlay-picker-add">
<span>Add overlay</span>
<select data-overlay-add>
<option value="">Pick a name…</option>
{% for overlay in available_overlays %}
<option value="{{ overlay.id }}" data-overlay-name="{{ overlay.name }}">{{ overlay.name }}</option>
{% endfor %}
</select>
</label>
</div>
<label>Arguments <textarea name="arguments" rows="8" spellcheck="false">{{ arguments | join('\n') }}</textarea></label>
<label>Config <textarea name="config" rows="8" spellcheck="false">{{ config_lines | join('\n') }}</textarea></label>
<button type="submit">Save blueprint</button>
</form>
</section>
<dialog id="delete-blueprint-modal" class="modal" aria-labelledby="delete-blueprint-title">
<div class="modal-header">
<h2 id="delete-blueprint-title">Delete blueprint "{{ blueprint.name }}"?</h2>
<button type="button" class="modal-close" data-modal-close aria-label="Close">&times;</button>
</div>
<div class="modal-body">
<p>This cannot be undone. Blueprints in use by a server cannot be deleted.</p>
</div>
<div class="modal-footer">
<button type="button" class="button-secondary" data-modal-close>Cancel</button>
<form method="post" action="/blueprints/{{ blueprint.id }}/delete" class="inline-form">
<input type="hidden" name="csrf_token" value="{{ session.get('csrf_token', '') }}">
<button class="danger" type="submit">Delete</button>
</form>
</div>
</dialog>
<script src="{{ url_for('static', filename='js/blueprint-overlay-picker.js') }}" defer></script>
{% endblock %}