Web changes: Split shared helpers, bootstrap logic, route groups, and upload-sync behavior out of web.js. Kept web.js focused on wiring and server startup. Fixed screen playlist reassignment so changing a screen’s playlist now triggers a refresh. Fixed single-slide playlist refresh behavior so updates do not get stuck behind the current slide. Player changes: Split websocket/runtime handling into runtime.js. Split playlist assembly and revision hashing into playlist.js. Split onboarding and player HTTP routes into dedicated modules. Split render utilities and template loading into render-helpers.js. Kept player.js mostly as startup/orchestration. Validation: Rebuilt both services with Docker Compose. Smoke-checked web and player routes after the refactor. Verified get_errors was clean on the touched modules.
76 lines
3.5 KiB
Handlebars
76 lines
3.5 KiB
Handlebars
<div class="page-header">
|
|
<div>
|
|
<h2>{{#if isEdit}}Edit slide - {{slide.title}}{{else}}Create slide{{/if}}</h2>
|
|
<p>Build slide content and preview it against the selected template.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="slide-editor-shell">
|
|
<form method="post" action="{{action}}" enctype="multipart/form-data" id="slide-form" class="slide-form-stack" data-async-save-close-url="/admin/slides" data-async-save-new-url="/admin/slides/new">
|
|
<div class="card card-outline card-primary admin-form-card slide-template-card">
|
|
<div class="card-header">
|
|
<h3 class="card-title">Slide details</h3>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row g-3">
|
|
<div class="col-6">
|
|
<label for="slide-title" class="form-label">Title</label>
|
|
<input id="slide-title" name="title" class="form-control" value="{{slide.title}}" required />
|
|
</div>
|
|
<div class="col-6">
|
|
<label for="template-select" class="form-label">Template</label>
|
|
<select name="template_id" id="template-select" class="form-select">
|
|
<option value="">-- none --</option>
|
|
{{#each templates}}
|
|
<option value="{{id}}" {{#if (eq ../slide.template_id id)}}selected{{/if}}>{{name}}</option>
|
|
{{/each}}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="template-fields"></div>
|
|
</form>
|
|
|
|
<div class="slide-editor-sidebar">
|
|
<div class="card card-outline card-primary admin-form-card mb-3">
|
|
<div class="card-body d-grid gap-2">
|
|
<div class="btn-group template-actions-group slide-actions-group" role="group" aria-label="Slide actions">
|
|
{{{saveActionButtons formId="slide-form" saveLabel=saveLabel saveAndCloseLabel="Save and Close" saveAndNewLabel="Save and New" saveAndCloseValue="close" saveAndNewValue="new"}}}
|
|
<a class="btn btn-warning" href="/admin/slides" data-confirm-unsaved="You have unsaved changes. Leave this page?">Cancel</a>
|
|
{{#if isEdit}}
|
|
<button type="submit" class="btn btn-danger" form="delete-slide-form">Delete</button>
|
|
{{/if}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<aside class="card card-outline card-secondary admin-form-card slide-preview-card">
|
|
<div class="card-header d-flex align-items-center justify-content-between gap-2">
|
|
<div class="slide-preview-header">
|
|
<h3>Preview</h3>
|
|
</div>
|
|
<span class="chip slide-preview-dimensions-chip" id="slide-preview-meta">--</span>
|
|
</div>
|
|
<div class="card-body slide-preview-scroll">
|
|
<div class="slide-preview-stage" id="slide-preview-stage">
|
|
<div class="slide-preview-canvas" id="slide-preview-canvas">
|
|
<img id="slide-preview-background" class="slide-preview-background" alt="" style="display:none;" />
|
|
<div class="slide-preview-empty" id="slide-preview-empty">Select a template to preview the slide.</div>
|
|
<div class="slide-preview-overlay" id="slide-preview-overlay"></div>
|
|
</div>
|
|
</div>
|
|
<button type="button" class="btn btn-outline-secondary w-100 mt-3" id="open-preview-popup">Open popup preview</button>
|
|
</div>
|
|
</aside>
|
|
</div>
|
|
</div>
|
|
|
|
{{#if isEdit}}
|
|
<form id="delete-slide-form" method="post" action="/admin/slides/{{slide.id}}/delete" data-confirm-message="Delete this slide?"></form>
|
|
{{/if}}
|
|
|
|
<textarea id="slide-editor-data" hidden>{{json slideEditorData}}</textarea>
|
|
<script type="module" src="/assets/js/slides/slide-form.js"></script>
|