Files
signage/templates/priority.html

387 lines
13 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.
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>CANCOM Simple Signage Priority Playlist</title>
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
<script>
(() => {
const stored = window.localStorage.getItem("signage-theme");
const theme = stored === "dark" || stored === "light" ? stored : "light";
document.documentElement.setAttribute("data-bs-theme", theme);
})();
</script>
<link rel="stylesheet"
href="https://unpkg.com/@tabler/core@1.0.0-beta20/dist/css/tabler.min.css">
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css">
<script defer
src="https://unpkg.com/@tabler/core@1.0.0-beta20/dist/js/tabler.min.js"></script>
<script defer
src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>
{% include "_styles.html" %}
<style>
.playlist-row {
display: grid;
grid-template-columns:
28px 1fr 90px 80px 50px 40px 32px;
align-items: center;
gap: 0.75rem;
}
.playlist-name {
font-weight: 600;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.playlist-size {
color: #6c757d;
font-size: 0.9em;
}
.drag-handle {
cursor: grab;
font-size: 1.2em;
text-align: center;
user-select: none;
}
.drag-handle:active {
cursor: grabbing;
}
.card-body .nav-tabs {
margin-left: -1rem;
margin-right: -1rem;
padding: 0 1rem;
border-bottom-color: var(--ccm-border);
}
.card-body .nav-tabs .nav-link {
background: transparent;
color: var(--ccm-muted);
}
.card-body .nav-tabs .nav-link.active {
background: var(--ccm-surface);
border-color: var(--ccm-border) var(--ccm-border) var(--ccm-surface);
color: var(--ccm-text);
}
.card-body .tab-content {
background: var(--ccm-surface);
padding: 1rem;
}
</style>
</head>
<body>
<div class="page">
{% set brand_subtitle = "Priority Playlist" %}
{% set site_dropdown_url_prefix = "/admin/" %}
{% include "_header.html" %}
<!-- Second Nav -->
<div class="navbar-expand-md">
<div class="collapse navbar-collapse show">
<div class="navbar navbar-dark nav-surface">
<div class="container-xl">
<div class="d-flex flex-wrap gap-2 py-2">
<a class="btn btn-white" href="/admin/{{ current_site }}"><i class="ti ti-layout-dashboard me-1"></i>Übersicht</a>
<a class="btn btn-white active" href="/admin/{{ current_site }}/priority"><i class="ti ti-alert-triangle me-1"></i>Priority Playlist</a>
<a class="btn btn-white" href="/willkommen?site={{ current_site }}"><i class="ti ti-file-plus me-1"></i>Willkommensseite</a>
</div>
</div>
</div>
</div>
</div>
<!-- Content -->
<div class="page-wrapper">
<div class="container-xl mt-4">
<!-- ========================= -->
<!-- PRIORITY / GLOBAL PLAYLIST -->
<!-- ========================= -->
<div class="card mb-6">
<div class="card-header d-flex justify-content-between align-items-center">
<span>
<div class="page-title" style="color:#DA002D;">⚠ PRIORITY Playlist</div>
<div class="page-subtitle">wirkt auf alle Player</div>
</span>
</div>
<div class="card-body">
<ul class="nav nav-tabs" data-bs-toggle="tabs" role="tablist">
<li class="nav-item" role="presentation">
<a href="#tab-prio-playlist" class="nav-link active" data-bs-toggle="tab" role="tab">
<i class="ti ti-list me-1"></i>Playlist
</a>
</li>
<li class="nav-item" role="presentation">
<a href="#tab-prio-media" class="nav-link" data-bs-toggle="tab" role="tab">
<i class="ti ti-upload me-1"></i>Medien
</a>
</li>
</ul>
<div class="tab-content">
<!-- Tab: Playlist -->
<div class="tab-pane active" id="tab-prio-playlist" role="tabpanel">
<ul class="list-group mb-3" id="playlist-priority">
{% for file in priority_files %}
<li class="list-group-item playlist-row"
data-file="{{ file.name }}">
<input class="form-check-input playlist-enabled"
type="checkbox"
{% if file.enabled %}checked{% endif %}
title="Element aktivieren">
<span class="playlist-name"
{% if file.type == "image" %}
data-bs-toggle="tooltip"
data-bs-html="true"
title="<img src='/media/priority/{{ file.name }}' style='max-width: 200px; max-height: 150px; border: none; background: white; padding: 2px;' alt='Vorschau'>"
{% elif file.type == "url" %}
data-bs-toggle="tooltip"
title="URL: {{ file.name }}{% if file.zoom %} (Zoom: {{ file.zoom }}x){% endif %}"
{% endif %}>
{{ file.name }}{% if file.type == "url" and file.zoom != 1.0 %} <strong style="color: #DA002D;">[{{ file.zoom }}x]</strong>{% endif %}
</span>
{% if file.type == "image" %}
<span class="badge bg-purple text-purple-fg">Bild</span>
{% elif file.type == "url" or file.type == "html" %}
<span class="badge bg-blue text-blue-fg">URL</span>
{% else %}
<span class="badge bg-orange text-orange-fg">Video</span>
{% endif %}
<span class="playlist-size">
{% if file.type == "url" %}
{{ file.size }}
{% else %}
{{ file.size }} KB
{% endif %}
</span>
<!-- Delete -->
<form action="{{ url_for('delete_file', site=current_site, screen='priority', filename=file.name) }}"
method="post"
class="d-inline"
onmousedown="event.stopPropagation()">
<button type="submit"
class="btn btn-outline-danger btn-sm"
onclick="return confirm('Datei wirklich löschen?')">
Löschen
</button>
</form>
<!-- Bearbeiten (nur URLs) -->
{% if file.type == "url" %}
<button type="button"
class="btn btn-outline-secondary btn-sm edit-url-btn"
title="URL bearbeiten"
data-name="{{ file.name | e }}"
data-zoom="{{ file.zoom | default(1.0) }}"
data-site="{{ current_site }}"
data-screen="priority"
data-oldname="{{ file.name | e }}">
Edit
</button>
{% endif %}
<!-- Drag -->
<span class="drag-handle" title="Reihenfolge ändern"></span>
</li>
{% endfor %}
</ul>
<button class="btn btn-primary"
onclick="savePlaylist('{{ current_site }}', 'priority')">
Priority-Playlist speichern
</button>
</div>
<!-- Tab: Medien -->
<div class="tab-pane" id="tab-prio-media" role="tabpanel">
<h3>Medien hochladen</h3>
<form action="/admin/{{ current_site }}/upload/priority"
method="post" enctype="multipart/form-data">
<div class="input-group mb-3">
<input type="file" name="file" class="form-control" required>
<button class="btn btn-primary" type="submit">Upload</button>
</div>
</form>
<hr>
<h3>URL hinzufügen</h3>
<form action="/admin/{{ current_site }}/add-url/priority" method="post" class="mb-3">
<div class="mb-2">
<label class="form-label">URL</label>
<input type="url" name="url" class="form-control"
placeholder="https://example.com" required>
</div>
<div class="mb-2">
<label class="form-label">Zoom Faktor (z.B. 1.0, 1.5, 2.0)</label>
<input type="number" name="zoom" class="form-control" step="0.1" value="1.0" min="0.1">
</div>
<button class="btn btn-primary" type="submit">URL hinzufügen</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Footer -->
{% include "_footer.html" %}
</div>
<script>
/* ─── Global: editState ─── */
var editState = { site: "", screen: "", oldName: "" };
/* Event-Delegation für Edit-Buttons (global, sofort aktiv) */
document.addEventListener("click", function (e) {
var btn = e.target.closest(".edit-url-btn");
if (!btn) return;
e.preventDefault();
editState.site = btn.dataset.site;
editState.screen = btn.dataset.screen;
editState.oldName = btn.dataset.oldname;
document.getElementById("edit-url-input").value = btn.dataset.oldname;
document.getElementById("edit-zoom-input").value = btn.dataset.zoom;
document.getElementById("edit-url-error").style.display = "none";
new bootstrap.Modal(document.getElementById("edit-url-modal")).show();
});
document.addEventListener("DOMContentLoaded", function () {
function initSortable(name) {
const el = document.getElementById("playlist-" + name);
if (!el || typeof Sortable === "undefined") return;
new Sortable(el, {
animation: 150,
handle: ".drag-handle",
ghostClass: "bg-light",
chosenClass: "bg-light"
});
}
initSortable("priority");
function savePlaylist(site, screen) {
const items = document.querySelectorAll(
"#playlist-" + screen + " li"
);
const playlist = [];
const enabled = {};
items.forEach((item) => {
const checkbox = item.querySelector(".playlist-enabled");
const fileName = item.dataset.file;
enabled[fileName] = !!(checkbox && checkbox.checked);
playlist.push(fileName);
});
fetch("/admin/" + site + "/playlist/" + screen, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
playlist: playlist,
enabled: enabled
})
}).then(() => location.reload());
}
window.savePlaylist = savePlaylist;
/* ─── Bootstrap Tooltips ─── */
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
/* ─── Edit-URL-Modal: Speichern-Button ─── */
document.getElementById("edit-url-save").addEventListener("click", function () {
const newUrl = document.getElementById("edit-url-input").value.trim();
const zoom = parseFloat(document.getElementById("edit-zoom-input").value) || 1.0;
const errorEl = document.getElementById("edit-url-error");
if (!newUrl.startsWith("http://") && !newUrl.startsWith("https://")) {
errorEl.textContent = "Ungültige URL (muss mit http:// oder https:// beginnen)";
errorEl.style.display = "block";
return;
}
errorEl.style.display = "none";
fetch("/admin/" + editState.site + "/update-playlist-item/" + editState.screen, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
old_name: editState.oldName,
new_url: newUrl,
zoom: zoom
})
}).then(function (r) {
if (r.ok) {
location.reload();
} else {
return r.json().then(function (d) {
errorEl.textContent = d.error || "Fehler beim Speichern";
errorEl.style.display = "block";
});
}
}).catch(function () {
errorEl.textContent = "Netzwerkfehler";
errorEl.style.display = "block";
});
});
});
</script>
<!-- Modal: URL bearbeiten -->
<div class="modal fade" id="edit-url-modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">URL bearbeiten</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label class="form-label">URL</label>
<input type="url" class="form-control" id="edit-url-input">
</div>
<div class="mb-3">
<label class="form-label">Zoom Faktor (z.B. 1.0, 1.5, 2.0)</label>
<input type="number" class="form-control" id="edit-zoom-input" step="0.1" min="0.1" value="1.0">
</div>
<div class="alert alert-danger py-2" id="edit-url-error" style="display:none"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
<button type="button" class="btn btn-primary" id="edit-url-save">Speichern</button>
</div>
</div>
</div>
</div>
</body>
</html>