Compare commits

..

2 Commits

  1. BIN
      backend/data/musiques/SONNERIE_P.mp3
  2. 31
      frontend/app/templates/base.html
  3. 88
      frontend/app/templates/dashboard.html

BIN
backend/data/musiques/SONNERIE_P.mp3

Binary file not shown.

31
frontend/app/templates/base.html

@ -187,6 +187,7 @@ label {
} }
input, input,
select,
button { button {
border-radius: 12px; border-radius: 12px;
border: 1px solid var(--line); border: 1px solid var(--line);
@ -194,13 +195,23 @@ button {
max-width: 100%; max-width: 100%;
} }
input { input,
select {
display: block; display: block;
width: 100%; width: 100%;
background: #fff; background: #fff;
padding: 0.65rem 0.75rem; padding: 0.65rem 0.75rem;
} }
select {
cursor: pointer;
appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%23665e57' d='M1 1l5 5 5-5'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 0.75rem center;
padding-right: 2rem;
}
input[type="file"] { input[type="file"] {
min-width: 0; min-width: 0;
} }
@ -348,6 +359,24 @@ td {
margin-bottom: 0.75rem; margin-bottom: 0.75rem;
} }
.audio-select-row {
display: flex;
gap: 0.5rem;
align-items: stretch;
}
.audio-select-row select {
flex: 1;
min-width: 0;
}
.audio-select-row .btn-preview {
flex-shrink: 0;
padding: 0.65rem 0.75rem;
font-size: 1rem;
line-height: 1;
}
.audio-player-card { .audio-player-card {
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 12px; border-radius: 12px;

88
frontend/app/templates/dashboard.html

@ -4,11 +4,10 @@
<header class="topbar reveal"> <header class="topbar reveal">
<div> <div>
<h1>Tableau de bord</h1> <h1>Tableau de bord</h1>
<p class="muted">Backend: {{ backend_url }} | Utilisateur: {{ username }}</p>
</div> </div>
<div class="topbar-actions"> <div class="topbar-actions">
<button type="button" class="danger" id="btn-stop-audio">Arreter l'audio</button> <button type="button" class="danger" id="btn-stop-audio">Arrêter l'audio</button>
<a href="{{ url_for('ui.logout') }}" class="ghost-link">Deconnexion</a> <a href="{{ url_for('ui.logout') }}" class="ghost-link">Déconnexion</a>
</div> </div>
</header> </header>
@ -26,20 +25,28 @@
</label> </label>
<label> <label>
Nom Nom
<input type="text" name="name" id="trigger_name" placeholder="Bouton entree" required /> <input type="text" name="name" id="trigger_name" placeholder="Bouton entrée" required />
</label> </label>
<label> <label>
Fichier audio Fichier audio
<input list="audio-files" name="music_file" id="music_file" placeholder="bell.mp3" required /> <div class="audio-select-row">
<datalist id="audio-files"> <select name="music_file" id="music_file" required
{% for f in audio_files %} data-stream-url="{{ url_for('ui.stream_audio', filename='__FILE__') }}">
<option value="{{ f }}"></option> <option value="" disabled {% if not audio_files %}selected{% endif %}>
{% endfor %} {% if audio_files %}Choisir un fichier…{% else %}Aucun fichier disponible{% endif %}
</datalist> </option>
{% for f in audio_files %}
<option value="{{ f }}">{{ f }}</option>
{% endfor %}
</select>
<button type="button" class="small btn-preview" id="btn-preview-trigger-audio"
title="Prévisualiser le fichier sélectionné"
{% if not audio_files %}disabled{% endif %}>&#9654;</button>
</div>
</label> </label>
<div class="time-row"> <div class="time-row">
<label> <label>
Debut (s) Début (s)
<input type="number" step="0.1" min="0" name="start_seconds" id="start_seconds" value="0" /> <input type="number" step="0.1" min="0" name="start_seconds" id="start_seconds" value="0" />
</label> </label>
<label> <label>
@ -57,7 +64,7 @@
<section class="panel reveal delay-2"> <section class="panel reveal delay-2">
<h2>Liste des triggers</h2> <h2>Liste des triggers</h2>
<p class="muted" id="no-triggers-msg"{% if triggers %} hidden{% endif %}>Aucun trigger configure.</p> <p class="muted" id="no-triggers-msg"{% if triggers %} hidden{% endif %}>Aucun trigger configuré.</p>
<div class="table-wrap"{% if not triggers %} hidden{% endif %} id="triggers-table-wrap"> <div class="table-wrap"{% if not triggers %} hidden{% endif %} id="triggers-table-wrap">
<table <table
id="triggers-table" id="triggers-table"
@ -70,7 +77,7 @@
<th>Nom</th> <th>Nom</th>
<th>Type</th> <th>Type</th>
<th>Audio</th> <th>Audio</th>
<th>Debut</th> <th>Début</th>
<th>Fin</th> <th>Fin</th>
<th>Volume</th> <th>Volume</th>
<th>Actions</th> <th>Actions</th>
@ -126,7 +133,7 @@
<form method="post" action="{{ url_for('ui.upload_audio') }}" enctype="multipart/form-data" class="upload-row" id="upload-audio-form"> <form method="post" action="{{ url_for('ui.upload_audio') }}" enctype="multipart/form-data" class="upload-row" id="upload-audio-form">
<input type="file" name="audio_file" id="audio_file_input" accept=".mp3,.wav,.ogg,.flac,.aac,.m4a" required /> <input type="file" name="audio_file" id="audio_file_input" accept=".mp3,.wav,.ogg,.flac,.aac,.m4a" required />
<button type="submit">Televerser</button> <button type="submit">Téléverser</button>
</form> </form>
{% if audio_files %} {% if audio_files %}
@ -143,7 +150,7 @@
> >
Lire Lire
</button> </button>
<a href="{{ url_for('ui.download_audio', filename=filename) }}" class="small-button">Telecharger</a> <a href="{{ url_for('ui.download_audio', filename=filename) }}" class="small-button">Télécharger</a>
<form method="post" action="{{ url_for('ui.delete_audio') }}" class="inline-form js-delete-audio-form" data-filename="{{ filename }}"> <form method="post" action="{{ url_for('ui.delete_audio') }}" class="inline-form js-delete-audio-form" data-filename="{{ filename }}">
<input type="hidden" name="filename" value="{{ filename }}" /> <input type="hidden" name="filename" value="{{ filename }}" />
<button type="submit" class="small danger">Supprimer</button> <button type="submit" class="small danger">Supprimer</button>
@ -182,8 +189,8 @@
<div class="modal-backdrop" id="duplicate-name-modal" aria-hidden="true"> <div class="modal-backdrop" id="duplicate-name-modal" aria-hidden="true">
<div class="modal-card" role="dialog" aria-modal="true" aria-labelledby="duplicate-name-title"> <div class="modal-card" role="dialog" aria-modal="true" aria-labelledby="duplicate-name-title">
<h3 id="duplicate-name-title">Nom deja utilise</h3> <h3 id="duplicate-name-title">Nom déjà utilisé</h3>
<p id="duplicate-name-message">Ce nom existe deja dans les fichiers enregistres.</p> <p id="duplicate-name-message">Ce nom existe déjà dans les fichiers enregistrés.</p>
<div class="modal-actions"> <div class="modal-actions">
<button type="button" class="ghost-link" id="duplicate-name-close">Fermer</button> <button type="button" class="ghost-link" id="duplicate-name-close">Fermer</button>
</div> </div>
@ -295,8 +302,8 @@
body: body.toString(), body: body.toString(),
}) })
.then((res) => res.json()) .then((res) => res.json())
.then((d) => { showFlash(d.ok ? (d.message || "Trigger demarre.") : (d.error || "Echec."), d.ok ? "success" : "error"); }) .then((d) => { showFlash(d.ok ? (d.message || "Trigger démarré.") : (d.error || "Échec."), d.ok ? "success" : "error"); })
.catch(() => { showFlash("Erreur reseau lors du lancement.", "error"); }) .catch(() => { showFlash("Erreur réseau lors du lancement.", "error"); })
.finally(() => { playBtn.disabled = false; }); .finally(() => { playBtn.disabled = false; });
}); });
} }
@ -319,13 +326,13 @@
.then((res) => res.json()) .then((res) => res.json())
.then((data) => { .then((data) => {
if (data.ok) { if (data.ok) {
showFlash(data.message || "Audio arrete.", "info"); showFlash(data.message || "Audio arrêté.", "info");
} else { } else {
showFlash(data.error || "Echec de l'arret audio.", "error"); showFlash(data.error || "Échec de l'arrêt audio.", "error");
} }
}) })
.catch(() => { .catch(() => {
showFlash("Erreur reseau lors de l'arret audio.", "error"); showFlash("Erreur réseau lors de l'arrêt audio.", "error");
}) })
.finally(() => { .finally(() => {
btn.disabled = false; btn.disabled = false;
@ -350,13 +357,13 @@
.then((res) => res.json()) .then((res) => res.json())
.then((data) => { .then((data) => {
if (data.ok) { if (data.ok) {
showFlash(data.message || "Trigger demarre.", "success"); showFlash(data.message || "Trigger démarré.", "success");
} else { } else {
showFlash(data.error || "Echec du lancement.", "error"); showFlash(data.error || "Échec du lancement.", "error");
} }
}) })
.catch(() => { .catch(() => {
showFlash("Erreur reseau lors du lancement.", "error"); showFlash("Erreur réseau lors du lancement.", "error");
}) })
.finally(() => { .finally(() => {
btn.disabled = false; btn.disabled = false;
@ -395,14 +402,14 @@
.then((res) => res.json()) .then((res) => res.json())
.then((data) => { .then((data) => {
if (data.ok) { if (data.ok) {
showFlash(data.message || "Trigger enregistre.", "success"); showFlash(data.message || "Trigger enregistré.", "success");
upsertTriggerRow(data); upsertTriggerRow(data);
} else { } else {
showFlash(data.error || "Echec de l'enregistrement.", "error"); showFlash(data.error || "Échec de l'enregistrement.", "error");
} }
}) })
.catch(() => { .catch(() => {
showFlash("Erreur reseau lors de l'enregistrement.", "error"); showFlash("Erreur réseau lors de l'enregistrement.", "error");
}) })
.finally(() => { .finally(() => {
if (submitBtn) submitBtn.disabled = false; if (submitBtn) submitBtn.disabled = false;
@ -635,18 +642,37 @@
if (tableWrap) tableWrap.hidden = true; if (tableWrap) tableWrap.hidden = true;
if (noMsg) noMsg.hidden = false; if (noMsg) noMsg.hidden = false;
} }
showFlash(data.message || "Trigger supprime.", "success"); showFlash(data.message || "Trigger supprimé.", "success");
} else { } else {
showFlash(data.error || "Echec de la suppression.", "error"); showFlash(data.error || "Échec de la suppression.", "error");
} }
}) })
.catch(() => { .catch(() => {
showFlash("Erreur reseau lors de la suppression.", "error"); showFlash("Erreur réseau lors de la suppression.", "error");
}) })
.finally(() => { .finally(() => {
confirmBtn.disabled = false; confirmBtn.disabled = false;
}); });
}); });
})(); })();
(function () {
const select = document.getElementById("music_file");
const btn = document.getElementById("btn-preview-trigger-audio");
if (!select || !btn) return;
btn.addEventListener("click", () => {
const filename = select.value;
if (!filename) return;
const streamBase = select.dataset.streamUrl || "";
const url = streamBase.replace("__FILE__", encodeURIComponent(filename));
const player = document.getElementById("browser-audio-player");
const nowPlaying = document.getElementById("audio-now-playing");
if (!player) return;
player.src = url;
player.play().catch(() => {});
if (nowPlaying) nowPlaying.textContent = "Lecture: " + filename;
player.closest("section")?.scrollIntoView({ behavior: "smooth", block: "nearest" });
});
})();
</script> </script>
{% endblock %} {% endblock %}

Loading…
Cancel
Save