Files
pulse-signage/src/web/views/signage/templates/form.hbs
T
lzstealth c4ae69d25f
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile, web, pulse-signage-web) (push) Successful in 2m0s
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile.player, player, pulse-signage-player) (push) Successful in 31s
release: v2.11.2
2026-09-05 18:14:38 +01:00

227 lines
14 KiB
Handlebars

<div class="page-header">
<div>
<h2>{{#if isEdit}}Edit template - {{template.name}}{{else}}Create template{{/if}}</h2>
<p>{{#if isEdit}}Adjust the canvas and region layout for this template.{{else}}Define a canvas, upload a background, and place content regions.{{/if}}</p>
</div>
</div>
<form method="post" action="{{formAction}}" enctype="multipart/form-data" id="template-form" {{{formAttrs}}}>
<input type="hidden" name="canvas_size_id" id="canvas-size-id" value="{{template.canvas_size_id}}" />
<input type="hidden" name="canvas_width" id="canvas-width" value="{{template.canvas_size_width}}" />
<input type="hidden" name="canvas_height" id="canvas-height" value="{{template.canvas_size_height}}" />
<input type="hidden" id="canvas-size-summary" />
<input type="hidden" name="existing_background_image_path" value="{{template.background_image_path}}" />
<input type="hidden" name="regions_json" id="regions-json" value="" />
<textarea id="template-region-usage" hidden>{{json template.region_usage}}</textarea>
<div class="template-designer-layout">
<div class="card card-outline card-secondary admin-form-card mb-3">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Designer</h3>
</div>
<div class="card-body">
<div class="template-designer-main">
<div class="designer-stage" id="designer-stage" style="aspect-ratio: {{template.canvas_size_width}} / {{template.canvas_size_height}};">
<img id="background-preview" src="{{template.background_image_path}}" alt="" style="{{#if template.background_image_path}}{{else}}display:none;{{/if}}" />
<div class="empty-bg" id="background-empty" style="opacity:0.4;{{#if template.background_image_path}}display:none;{{/if}}">No background image selected</div>
<div class="designer-overlay" id="designer-overlay"></div>
</div>
</div>
</div>
</div>
<div class="template-designer-sidebar">
<div class="card card-outline card-primary admin-form-card">
<div class="card-body d-grid gap-3 pb-0">
<div class="btn-group" role="group" aria-label="Template actions">
{{{saveActionButtons formId="template-form" saveUrl=formAction cancelUrl=cancelUrl cancelConfirmMessage=cancelConfirmMessage deleteUrl=deleteUrl deleteDisabled=deleteDisabled deleteConfirmMessage=deleteConfirmMessage showSaveAndClose=showSaveSecondaryActions showSaveAndNew=showSaveSecondaryActions}}}
</div>
<div class="d-grid gap-2 template-preview-card" id="template-preview-card" hidden>
<div class="btn-group flex-wrap gap-0" role="group" aria-label="Template animation preview controls">
<button type="button" class="btn btn-outline-secondary" id="template-preview-intro" data-preview-control data-preview-action="intro" aria-pressed="false"><i class="bi bi-play-fill me-1" aria-hidden="true" data-preview-icon></i><span>Intro</span></button>
<button type="button" class="btn btn-outline-secondary" id="template-preview-out" data-preview-control data-preview-action="out" aria-pressed="false"><i class="bi bi-play-fill me-1" aria-hidden="true" data-preview-icon></i><span>Outro</span></button>
<button type="button" class="btn btn-outline-secondary" id="template-preview-continuous" data-preview-control data-preview-action="continuous" aria-pressed="false"><i class="bi bi-play-fill me-1" aria-hidden="true" data-preview-icon></i><span>Attention</span></button>
</div>
</div>
</div>
</div>
<div class="card card-outline card-info admin-form-card region-info-card mb-3">
<div class="card-header bg-body-tertiary">
<div>
<h3 class="card-title">Region information</h3>
</div>
</div>
<div class="card-body">
<button type="button" class="btn btn-info w-100" id="add-region-button" data-bs-toggle="modal" data-bs-target="#region-add-modal">Add region</button>
<div class="region-selector-block mt-3">
<label for="region-select" class="form-label">Select region</label>
<select id="region-select" class="form-select region-select"></select>
</div>
<div id="region-list" class="region-list mt-3"></div>
</div>
</div>
</div>
</div>
<div class="row g-4 mb-4 align-items-stretch">
<div class="col-12 col-xl-4">
<div class="card card-outline card-primary admin-form-card h-100 template-details-card">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Template details</h3>
</div>
<div class="card-body">
<div class="row g-3 template-meta-row">
<div class="col-12">
<label for="template-name" class="form-label">Name</label>
<input name="name" id="template-name" class="form-control" value="{{template.name}}" maxlength="128" data-limit-text-length required />
</div>
<div class="col-12">
<label for="canvas-size-select" class="form-label">Canvas size</label>
<select id="canvas-size-select" class="form-select" data-lock-on-existing-template="{{#if isEdit}}true{{else}}false{{/if}}">
{{#unless template.canvas_size_id}}
<option value="" data-width="{{template.canvas_size_width}}" data-height="{{template.canvas_size_height}}" selected>{{template.canvas_size_label}}</option>
{{/unless}}
{{#if canvasSizes.length}}
{{#each canvasSizes}}
<option value="{{id}}" data-width="{{width}}" data-height="{{height}}" {{#if (eq ../template.canvas_size_id id)}}selected{{/if}}>{{name}} ({{width}}x{{height}})</option>
{{/each}}
{{/if}}
</select>
</div>
</div>
</div>
</div>
</div>
<div class="col-12 col-xl-8">
<div class="card card-outline card-primary admin-form-card h-100 template-options-card">
<div class="card-header bg-body-tertiary">
<h3 class="card-title">Options</h3>
</div>
<div class="card-body">
<div class="row g-3">
<div class="col-12 col-md-6">
<label for="background-image" class="form-label">Background image</label>
<div class="template-background-row d-flex gap-2">
<input type="file" name="background_image" id="background-image" class="form-control" accept="image/*" />
<button type="button" class="btn btn-outline-secondary" id="remove-background-image">Remove</button>
</div>
<input type="checkbox" name="remove_background_image" id="remove-background-image-flag" value="1" hidden />
</div>
<div class="col-12 col-md-6">
<label for="background-color" class="form-label">Background colour</label>
<input type="color" name="background_color" id="background-color" class="form-control form-control-color w-100" value="{{#if template.background_color}}{{template.background_color}}{{else}}#111111{{/if}}" title="Choose a background colour" />
</div>
<div class="col-12">
<input type="hidden" name="background_gradient" id="background-gradient" value="{{template.background_gradient}}" />
<button type="button" class="btn btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#background-advanced-modal"><i class="bi bi-sliders me-1" aria-hidden="true"></i>Advanced background</button>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
{{#> modal-shell modalId="background-advanced-modal" modalLabelId="background-advanced-modal-label" modalDialogClass="modal-dialog-centered"}}
<div class="modal-header">
<h2 class="modal-title fs-5" id="background-advanced-modal-label">Advanced background</h2>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="background-gradient-enabled" {{#if template.background_gradient}}checked{{/if}} />
<label class="form-check-label" for="background-gradient-enabled">Use linear gradient</label>
</div>
<div class="row g-3" id="background-gradient-options" {{#if template.background_gradient}}{{else}}hidden{{/if}}>
<div class="col-12"><label for="background-gradient-angle" class="form-label">Gradient angle <output id="background-gradient-angle-output">90</output>&deg;</label><input type="range" id="background-gradient-angle" class="form-range" min="0" max="360" value="90" /></div>
<div class="col-12"><div class="gradient-stop-bar mb-3" id="background-gradient-bar" role="slider" aria-label="Gradient colour stops" aria-valuemin="0" aria-valuemax="100"><div class="gradient-stop-bar-track"></div><div class="gradient-stop-bar-handles" id="background-gradient-bar-handles"></div></div><div class="d-flex justify-content-between align-items-center mb-2"><strong>Colour stops</strong><button type="button" class="btn btn-sm btn-outline-secondary" id="background-gradient-add-stop"><i class="bi bi-plus-lg me-1" aria-hidden="true"></i>Add stop</button></div><div class="d-grid gap-2" id="background-gradient-stops"></div></div>
</div>
</div>
{{/modal-shell}}
<script src="/assets/js/shared/qr-code-svg.js?v={{appVersion}}"></script>
<script src="/assets/vendor/qr-code-styling/qr-code-styling-loader.js?v={{appVersion}}"></script>
{{#> modal-shell modalId="region-add-modal" modalLabelId="region-add-modal-label" modalDialogClass="modal-dialog-centered"}}
<div class="modal-header">
<h2 class="modal-title fs-5" id="region-add-modal-label">Add region</h2>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p class="text-body-secondary mb-3">Choose the type of region you want to add to this template.</p>
<div class="d-grid gap-2" id="region-add-options"></div>
</div>
{{/modal-shell}}
<template id="region-card-template">
<div class="card card-outline card-secondary admin-form-card region-item">
<div class="card-header bg-body-tertiary template-field-head d-flex align-items-center flex-nowrap gap-2"><strong class="flex-grow-1 text-truncate" data-region-title>Region</strong><span class="chip ms-auto" data-region-chip>Text</span></div>
<div class="card-body p-3 d-grid gap-3 pb-0">
<div class="region-field-grid region-field-grid--identity">
<label>Region name<input class="form-control" name="region_name[]" value="" maxlength="64" data-limit-text-length placeholder="type_1" required /></label>
</div>
<input type="hidden" name="region_type[]" value="text" />
<input type="hidden" name="region_key[]" value="" />
<input type="hidden" name="region_label[]" value="" />
<div class="region-field-grid region-field-grid--position">
<label>X<input class="form-control" type="number" name="region_x[]" value="80" required /></label>
<label>Y<input class="form-control" type="number" name="region_y[]" value="80" required /></label>
<label>Z-Index<input class="form-control" type="number" name="region_z[]" value="1" required /></label>
</div>
<div class="region-field-grid region-field-grid--size">
<label>Width<input class="form-control" type="number" name="region_width[]" value="300" required /></label>
<label>Height<input class="form-control" type="number" name="region_height[]" value="120" required /></label>
<label>Lock ratio<input class="form-control" type="text" name="region_lock_ratio[]" value="" maxlength="20" data-limit-text-length placeholder="Ratio, e.g. 16:9" /></label>
<label>Remove<button type="button" class="btn btn-outline-danger w-100" data-region-remove-button{{#if isEdit}} disabled{{/if}}>Remove</button></label>
</div>
<div class="region-field-grid region-field-grid--animation">
<div class="d-grid gap-1">
<label>
Intro
<select class="form-select" data-animation-preset="intro">
{{#each animationPresets.basic.intro}}
<option value="{{value}}">{{label}}</option>
{{/each}}
</select>
</label>
<button type="button" class="btn btn-outline-secondary w-100" data-animation-reset-button="intro" hidden>Reset to basic</button>
</div>
<div class="d-grid gap-1">
<label>
Outro
<select class="form-select" data-animation-preset="outro">
{{#each animationPresets.basic.outro}}
<option value="{{value}}">{{label}}</option>
{{/each}}
</select>
</label>
<button type="button" class="btn btn-outline-secondary w-100" data-animation-reset-button="outro" hidden>Reset to basic</button>
</div>
</div>
<div class="region-field-grid region-field-grid--animation">
<div class="d-grid gap-1">
<label>
Attention seekers
<select class="form-select" data-animation-preset="loop">
{{#each animationPresets.basic.attentionSeekers}}
<option value="{{value}}">{{label}}</option>
{{/each}}
</select>
</label>
<button type="button" class="btn btn-outline-secondary w-100" data-animation-reset-button="loop" hidden>Reset to basic</button>
</div>
<div class="d-grid gap-1">
<label>
Advanced
<button type="button" class="btn btn-outline-secondary w-100" data-animation-advanced-button>Advanced</button>
</label>
</div>
</div>
<textarea class="visually-hidden" name="region_animation_json[]" data-animation-json-input rows="1"></textarea>
</div>
</div>
</div>
</template>
{{> signage/templates/animation-advanced-modal}}
<textarea id="template-editor-data" hidden>{{json template.regions}}</textarea>