Files
signage/templates/admin.html
2026-04-17 14:06:24 +02:00

266 lines
6.7 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">
<title>CANCOM Simple Signage Admin</title>
<!-- Tabler CSS -->
<link rel="stylesheet"
href="https://unpkg.com/@tabler/core@1.0.0-beta20/dist/css/tabler.min.css">
<!-- Tabler JS -->
<script defer
src="https://unpkg.com/@tabler/core@1.0.0-beta20/dist/js/tabler.min.js"></script>
<!-- SortableJS -->
<script defer
src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>
<style>
body {
background-color: #F4F6F8;
color: #212121;
}
/* Top Navigation */
.navbar {
background-color: #DA002D;
}
.navbar-brand {
color: #ffffff !important;
font-weight: 600;
letter-spacing: 0.3px;
}
/* CANCOM CI Variante 1 */
.card-header {
background-color: #ffffff;
border-left: 6px solid #DA002D;
padding-left: 1rem;
font-weight: 600;
}
.btn-primary {
background-color: #DA002D;
border-color: #DA002D;
}
.btn-primary:hover {
background-color: #B00024;
border-color: #B00024;
}
.form-check-input:checked {
background-color: #DA002D;
border-color: #DA002D;
}
.form-check-input:focus {
box-shadow: 0 0 0 0.2rem rgba(218, 0, 45, 0.25);
}
/* Playlist als Grid (eine Zeile, tabellarisch) */
.playlist-row {
display: grid;
grid-template-columns:
1fr /* Name */
90px /* Typ */
80px /* Größe */
90px /* Delete */
32px; /* Drag */
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;
}
</style>
</head>
<body>
<div class="page">
<!-- Header -->
<header class="navbar navbar-expand-md">
<div class="container-xl">
<span class="navbar-brand">CANCOM Simple Signage Admin</span>
<div class="navbar-nav ms-auto">
<a href="/logout" class="nav-link text-white">Logout</a>
</div>
</div>
</header>
<!-- Content -->
<div class="page-wrapper">
<div class="container-xl mt-4">
{% for screen, cfg in screens.items() %}
<div class="card mb-4">
<!-- Card Header -->
<div class="card-header d-flex justify-content-between align-items-center">
<span>Screen: {{ screen }}</span>
{% if screen_status[screen] == "active" %}
<span class="badge bg-success">Aktiv</span>
{% else %}
<span class="badge bg-warning text-dark">Leer</span>
{% endif %}
</div>
<div class="card-body">
<!-- Einstellungen -->
<form action="/admin/update/{{ screen }}" method="post">
<div class="mb-3">
<label class="form-label">Intervall (Sekunden)</label>
<input type="number" class="form-control"
name="interval" min="1" value="{{ cfg.interval }}">
</div>
<div class="form-check form-switch mb-2">
<input class="form-check-input" type="checkbox"
name="show_images"
{% if cfg.show_images %}checked{% endif %}>
<label class="form-check-label">Bilder anzeigen</label>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox"
name="show_videos"
{% if cfg.show_videos %}checked{% endif %}>
<label class="form-check-label">Videos anzeigen</label>
</div>
<button type="submit" class="btn btn-primary">
Einstellungen speichern
</button>
</form>
<hr>
<!-- Upload -->
<h5>Medien hochladen</h5>
<form action="/admin/upload/{{ screen }}"
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>
<!-- Playlist -->
<h5>Playlist Reihenfolge</h5>
<ul class="list-group mb-3" id="playlist-{{ screen }}">
{% for file in media_files[screen] %}
<li class="list-group-item playlist-row"
data-file="{{ file.name }}">
<span class="playlist-name">{{ file.name }}</span>
{% if file.type == "image" %}
<span class="badge bg-blue-lt">Bild</span>
{% else %}
<span class="badge bg-orange-lt">Video</span>
{% endif %}
<span class="playlist-size">{{ file.size }} KB</span>
<!-- Delete -->
<form action="/admin/delete/{{ screen }}/{{ file.name }}"
method="post">
<button type="submit"
class="btn btn-outline-danger btn-sm"
onclick="return confirm('Datei wirklich löschen?')">
Löschen
</button>
</form>
<!-- Drag -->
<span class="drag-handle" title="Reihenfolge ändern"></span>
</li>
{% endfor %}
</ul>
<button class="btn btn-primary"
onclick="savePlaylist('{{ screen }}')">
Reihenfolge speichern
</button>
</div>
</div>
{% endfor %}
</div>
</div>
<!-- Footer -->
<footer class="footer footer-transparent mt-4">
<div class="container-xl text-muted">
© {{ year }} CANCOM · Version {{ version }} · {{ hostname }}
</div>
</footer>
</div>
<script>
document.addEventListener("DOMContentLoaded", function () {
function initSortable(screen) {
const el = document.getElementById("playlist-" + screen);
if (!el || typeof Sortable === "undefined") return;
new Sortable(el, {
animation: 150,
handle: ".drag-handle",
ghostClass: "bg-light",
chosenClass: "bg-light"
});
}
function savePlaylist(screen) {
const items = document.querySelectorAll(
"#playlist-" + screen + " li"
);
fetch("/admin/playlist/" + screen, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
playlist: Array.from(items).map(i => i.dataset.file)
})
}).then(() => location.reload());
}
window.savePlaylist = savePlaylist;
{% for screen in screens.keys() %}
initSortable("{{ screen }}");
{% endfor %}
});
</script>
</body>
</html>