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 { @@ -187,6 +187,7 @@ label {
}
input,
select,
button {
border-radius: 12px;
border: 1px solid var(--line);
@ -194,13 +195,23 @@ button { @@ -194,13 +195,23 @@ button {
max-width: 100%;
}
input {
input,
select {
display: block;
width: 100%;
background: #fff;
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"] {
min-width: 0;
}
@ -348,6 +359,24 @@ td { @@ -348,6 +359,24 @@ td {
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 {
border: 1px solid var(--line);
border-radius: 12px;

88
frontend/app/templates/dashboard.html

@ -4,11 +4,10 @@ @@ -4,11 +4,10 @@
<header class="topbar reveal">
<div>
<h1>Tableau de bord</h1>
<p class="muted">Backend: {{ backend_url }} | Utilisateur: {{ username }}</p>
</div>
<div class="topbar-actions">
<button type="button" class="danger" id="btn-stop-audio">Arreter l'audio</button>
<a href="{{ url_for('ui.logout') }}" class="ghost-link">Deconnexion</a>
<button type="button" class="danger" id="btn-stop-audio">Arrêter l'audio</button>
<a href="{{ url_for('ui.logout') }}" class="ghost-link">Déconnexion</a>
</div>
</header>
@ -26,20 +25,28 @@ @@ -26,20 +25,28 @@
</label>
<label>
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>
Fichier audio
<input list="audio-files" name="music_file" id="music_file" placeholder="bell.mp3" required />
<datalist id="audio-files">
{% for f in audio_files %}
<option value="{{ f }}"></option>
{% endfor %}
</datalist>
<div class="audio-select-row">
<select name="music_file" id="music_file" required
data-stream-url="{{ url_for('ui.stream_audio', filename='__FILE__') }}">
<option value="" disabled {% if not audio_files %}selected{% endif %}>
{% if audio_files %}Choisir un fichier…{% else %}Aucun fichier disponible{% endif %}
</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>
<div class="time-row">
<label>
Debut (s)
Début (s)
<input type="number" step="0.1" min="0" name="start_seconds" id="start_seconds" value="0" />
</label>
<label>
@ -57,7 +64,7 @@ @@ -57,7 +64,7 @@
<section class="panel reveal delay-2">
<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">
<table
id="triggers-table"
@ -70,7 +77,7 @@ @@ -70,7 +77,7 @@
<th>Nom</th>
<th>Type</th>
<th>Audio</th>
<th>Debut</th>
<th>Début</th>
<th>Fin</th>
<th>Volume</th>
<th>Actions</th>
@ -126,7 +133,7 @@ @@ -126,7 +133,7 @@
<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 />
<button type="submit">Televerser</button>
<button type="submit">Téléverser</button>
</form>
{% if audio_files %}
@ -143,7 +150,7 @@ @@ -143,7 +150,7 @@
>
Lire
</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 }}">
<input type="hidden" name="filename" value="{{ filename }}" />
<button type="submit" class="small danger">Supprimer</button>
@ -182,8 +189,8 @@ @@ -182,8 +189,8 @@
<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">
<h3 id="duplicate-name-title">Nom deja utilise</h3>
<p id="duplicate-name-message">Ce nom existe deja dans les fichiers enregistres.</p>
<h3 id="duplicate-name-title">Nom déjà utilisé</h3>
<p id="duplicate-name-message">Ce nom existe déjà dans les fichiers enregistrés.</p>
<div class="modal-actions">
<button type="button" class="ghost-link" id="duplicate-name-close">Fermer</button>
</div>
@ -295,8 +302,8 @@ @@ -295,8 +302,8 @@
body: body.toString(),
})
.then((res) => res.json())
.then((d) => { showFlash(d.ok ? (d.message || "Trigger demarre.") : (d.error || "Echec."), d.ok ? "success" : "error"); })
.catch(() => { showFlash("Erreur reseau lors du lancement.", "error"); })
.then((d) => { showFlash(d.ok ? (d.message || "Trigger démarré.") : (d.error || "Échec."), d.ok ? "success" : "error"); })
.catch(() => { showFlash("Erreur réseau lors du lancement.", "error"); })
.finally(() => { playBtn.disabled = false; });
});
}
@ -319,13 +326,13 @@ @@ -319,13 +326,13 @@
.then((res) => res.json())
.then((data) => {
if (data.ok) {
showFlash(data.message || "Audio arrete.", "info");
showFlash(data.message || "Audio arrêté.", "info");
} else {
showFlash(data.error || "Echec de l'arret audio.", "error");
showFlash(data.error || "Échec de l'arrêt audio.", "error");
}
})
.catch(() => {
showFlash("Erreur reseau lors de l'arret audio.", "error");
showFlash("Erreur réseau lors de l'arrêt audio.", "error");
})
.finally(() => {
btn.disabled = false;
@ -350,13 +357,13 @@ @@ -350,13 +357,13 @@
.then((res) => res.json())
.then((data) => {
if (data.ok) {
showFlash(data.message || "Trigger demarre.", "success");
showFlash(data.message || "Trigger démarré.", "success");
} else {
showFlash(data.error || "Echec du lancement.", "error");
showFlash(data.error || "Échec du lancement.", "error");
}
})
.catch(() => {
showFlash("Erreur reseau lors du lancement.", "error");
showFlash("Erreur réseau lors du lancement.", "error");
})
.finally(() => {
btn.disabled = false;
@ -395,14 +402,14 @@ @@ -395,14 +402,14 @@
.then((res) => res.json())
.then((data) => {
if (data.ok) {
showFlash(data.message || "Trigger enregistre.", "success");
showFlash(data.message || "Trigger enregistré.", "success");
upsertTriggerRow(data);
} else {
showFlash(data.error || "Echec de l'enregistrement.", "error");
showFlash(data.error || "Échec de l'enregistrement.", "error");
}
})
.catch(() => {
showFlash("Erreur reseau lors de l'enregistrement.", "error");
showFlash("Erreur réseau lors de l'enregistrement.", "error");
})
.finally(() => {
if (submitBtn) submitBtn.disabled = false;
@ -635,18 +642,37 @@ @@ -635,18 +642,37 @@
if (tableWrap) tableWrap.hidden = true;
if (noMsg) noMsg.hidden = false;
}
showFlash(data.message || "Trigger supprime.", "success");
showFlash(data.message || "Trigger supprimé.", "success");
} else {
showFlash(data.error || "Echec de la suppression.", "error");
showFlash(data.error || "Échec de la suppression.", "error");
}
})
.catch(() => {
showFlash("Erreur reseau lors de la suppression.", "error");
showFlash("Erreur réseau lors de la suppression.", "error");
})
.finally(() => {
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>
{% endblock %}

Loading…
Cancel
Save