You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
502 lines
8.0 KiB
502 lines
8.0 KiB
<!doctype html> |
|
<html lang="fr"> |
|
<head> |
|
<meta charset="utf-8" /> |
|
<meta name="viewport" content="width=device-width, initial-scale=1" /> |
|
<title>pySonnerie - Interface de controle</title> |
|
<style> |
|
:root { |
|
--bg: #f8f6ef; |
|
--ink: #1f1c1a; |
|
--panel: #fffef9; |
|
--brand: #0f6f63; |
|
--brand-strong: #0b544b; |
|
--accent: #d66d2d; |
|
--danger: #b13a2e; |
|
--line: #d8d2c3; |
|
--muted: #665e57; |
|
--shadow: 0 12px 40px rgba(45, 37, 23, 0.12); |
|
} |
|
|
|
* { |
|
box-sizing: border-box; |
|
} |
|
|
|
html, |
|
body { |
|
margin: 0; |
|
padding: 0; |
|
min-height: 100%; |
|
} |
|
|
|
body { |
|
font-family: "Noto Sans", "DejaVu Sans", "Segoe UI", "Helvetica Neue", Arial, sans-serif; |
|
color: var(--ink); |
|
background: |
|
radial-gradient(circle at 15% -5%, #ffe8cc 0%, transparent 40%), |
|
radial-gradient(circle at 100% 100%, #d5efe6 0%, transparent 40%), |
|
var(--bg); |
|
overflow-x: hidden; |
|
} |
|
|
|
h1, |
|
h2, |
|
h3 { |
|
font-family: "Noto Sans", "DejaVu Sans", "Segoe UI", "Helvetica Neue", Arial, sans-serif; |
|
margin: 0 0 0.4rem; |
|
} |
|
|
|
.muted { |
|
color: var(--muted); |
|
} |
|
|
|
.bg-orb { |
|
position: fixed; |
|
border-radius: 999px; |
|
pointer-events: none; |
|
filter: blur(4px); |
|
z-index: -1; |
|
} |
|
|
|
.bg-orb-one { |
|
width: 260px; |
|
height: 260px; |
|
background: rgba(214, 109, 45, 0.25); |
|
top: -60px; |
|
right: -40px; |
|
} |
|
|
|
.bg-orb-two { |
|
width: 220px; |
|
height: 220px; |
|
background: rgba(15, 111, 99, 0.18); |
|
bottom: -70px; |
|
left: -40px; |
|
} |
|
|
|
.reveal { |
|
animation: reveal-up 0.45s ease both; |
|
} |
|
|
|
.delay-1 { |
|
animation-delay: 0.05s; |
|
} |
|
|
|
.delay-2 { |
|
animation-delay: 0.11s; |
|
} |
|
|
|
.delay-3 { |
|
animation-delay: 0.16s; |
|
} |
|
|
|
@keyframes reveal-up { |
|
from { |
|
opacity: 0; |
|
transform: translateY(8px); |
|
} |
|
to { |
|
opacity: 1; |
|
transform: translateY(0); |
|
} |
|
} |
|
|
|
.flash-stack { |
|
position: fixed; |
|
top: 1rem; |
|
right: 1rem; |
|
display: grid; |
|
gap: 0.5rem; |
|
z-index: 50; |
|
} |
|
|
|
.flash { |
|
padding: 0.7rem 0.95rem; |
|
border-radius: 12px; |
|
box-shadow: var(--shadow); |
|
font-size: 0.9rem; |
|
max-width: min(82vw, 420px); |
|
opacity: 1; |
|
transform: translateY(0); |
|
transition: opacity 0.35s ease, transform 0.35s ease; |
|
} |
|
|
|
.flash.is-hiding { |
|
opacity: 0; |
|
transform: translateY(-6px); |
|
} |
|
|
|
.flash-success { |
|
background: #e3f7ef; |
|
border: 1px solid #9cdcbc; |
|
} |
|
|
|
.flash-error { |
|
background: #fdeceb; |
|
border: 1px solid #f2b2ad; |
|
} |
|
|
|
.flash-info { |
|
background: #edf4ff; |
|
border: 1px solid #bed4f9; |
|
} |
|
|
|
.auth-wrap { |
|
min-height: 100vh; |
|
display: grid; |
|
place-items: center; |
|
padding: 1rem; |
|
} |
|
|
|
.auth-card { |
|
width: min(560px, 100%); |
|
background: var(--panel); |
|
border: 1px solid var(--line); |
|
box-shadow: var(--shadow); |
|
border-radius: 22px; |
|
padding: 2rem; |
|
} |
|
|
|
.auth-card h1 { |
|
margin-bottom: 2rem; |
|
} |
|
|
|
.auth-inline-error { |
|
margin: -1rem 0 1rem; |
|
padding: 0.65rem 0.75rem; |
|
border-radius: 10px; |
|
border: 1px solid #f2b2ad; |
|
background: #fdeceb; |
|
color: #7a1f16; |
|
font-size: 0.9rem; |
|
} |
|
|
|
.form-grid { |
|
display: grid; |
|
gap: 0.9rem; |
|
} |
|
|
|
.form-grid > * { |
|
min-width: 0; |
|
} |
|
|
|
label { |
|
display: grid; |
|
gap: 0.4rem; |
|
font-size: 0.9rem; |
|
} |
|
|
|
input, |
|
button { |
|
border-radius: 12px; |
|
border: 1px solid var(--line); |
|
font: inherit; |
|
max-width: 100%; |
|
} |
|
|
|
input { |
|
display: block; |
|
width: 100%; |
|
background: #fff; |
|
padding: 0.65rem 0.75rem; |
|
} |
|
|
|
input[type="file"] { |
|
min-width: 0; |
|
} |
|
|
|
button, |
|
.small-button, |
|
.ghost-link { |
|
text-decoration: none; |
|
display: inline-flex; |
|
align-items: center; |
|
justify-content: center; |
|
cursor: pointer; |
|
transition: transform 0.08s ease, background-color 0.2s ease; |
|
} |
|
|
|
button { |
|
background: var(--brand); |
|
color: #fff; |
|
padding: 0.65rem 0.85rem; |
|
border: 0; |
|
} |
|
|
|
button:hover, |
|
.small-button:hover, |
|
.ghost-link:hover { |
|
transform: translateY(-1px); |
|
} |
|
|
|
button.danger { |
|
background: var(--danger); |
|
} |
|
|
|
button.small { |
|
padding: 0.45rem 0.6rem; |
|
font-size: 0.82rem; |
|
} |
|
|
|
.topbar { |
|
margin: 1.2rem; |
|
padding: 1rem; |
|
background: var(--panel); |
|
border: 1px solid var(--line); |
|
border-radius: 16px; |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: center; |
|
gap: 1rem; |
|
} |
|
|
|
.topbar-actions { |
|
display: flex; |
|
align-items: center; |
|
gap: 0.65rem; |
|
} |
|
|
|
.ghost-link { |
|
padding: 0.65rem 0.85rem; |
|
border-radius: 12px; |
|
border: 1px solid var(--line); |
|
color: var(--ink); |
|
} |
|
|
|
.dashboard-grid { |
|
display: grid; |
|
gap: 1rem; |
|
grid-template-columns: repeat(12, minmax(0, 1fr)); |
|
padding: 0 1.2rem 1.2rem; |
|
} |
|
|
|
.panel { |
|
background: var(--panel); |
|
border: 1px solid var(--line); |
|
border-radius: 16px; |
|
padding: 1rem; |
|
box-shadow: var(--shadow); |
|
} |
|
|
|
.panel:nth-child(1) { |
|
grid-column: span 4; |
|
} |
|
|
|
.panel:nth-child(2) { |
|
grid-column: span 8; |
|
} |
|
|
|
.panel:nth-child(3) { |
|
grid-column: span 12; |
|
} |
|
|
|
.time-row { |
|
display: grid; |
|
grid-template-columns: 1fr 1fr; |
|
gap: 0.8rem; |
|
} |
|
|
|
.time-row > * { |
|
min-width: 0; |
|
} |
|
|
|
.volume-row { |
|
display: flex; |
|
flex-direction: column; |
|
gap: 0.3rem; |
|
} |
|
|
|
.volume-row input[type="range"] { |
|
width: 100%; |
|
accent-color: var(--brand); |
|
} |
|
|
|
.table-wrap { |
|
overflow-x: auto; |
|
} |
|
|
|
table { |
|
width: 100%; |
|
border-collapse: collapse; |
|
} |
|
|
|
th, |
|
td { |
|
border-bottom: 1px solid var(--line); |
|
text-align: left; |
|
padding: 0.45rem; |
|
font-size: 0.9rem; |
|
} |
|
|
|
.trigger-row { |
|
cursor: pointer; |
|
} |
|
|
|
.trigger-row:hover { |
|
background: #f7f2e6; |
|
} |
|
|
|
.inline-form { |
|
display: inline-block; |
|
margin-right: 0.35rem; |
|
} |
|
|
|
.upload-row { |
|
display: flex; |
|
flex-wrap: wrap; |
|
gap: 0.7rem; |
|
margin-bottom: 0.75rem; |
|
} |
|
|
|
.audio-player-card { |
|
border: 1px solid var(--line); |
|
border-radius: 12px; |
|
padding: 0.75rem; |
|
margin-bottom: 0.8rem; |
|
background: #fff; |
|
} |
|
|
|
#browser-audio-player { |
|
width: 100%; |
|
margin-top: 0.35rem; |
|
} |
|
|
|
.audio-time { |
|
margin: 0.5rem 0 0; |
|
font-size: 0.9rem; |
|
color: var(--muted); |
|
} |
|
|
|
.modal-backdrop { |
|
position: fixed; |
|
inset: 0; |
|
background: rgba(20, 18, 15, 0.45); |
|
display: none; |
|
align-items: center; |
|
justify-content: center; |
|
padding: 1rem; |
|
z-index: 120; |
|
} |
|
|
|
.modal-backdrop.is-open { |
|
display: flex; |
|
} |
|
|
|
.modal-card { |
|
width: min(460px, 100%); |
|
background: var(--panel); |
|
border: 1px solid var(--line); |
|
border-radius: 14px; |
|
box-shadow: var(--shadow); |
|
padding: 1rem; |
|
} |
|
|
|
.modal-actions { |
|
margin-top: 0.9rem; |
|
display: flex; |
|
justify-content: flex-end; |
|
gap: 0.6rem; |
|
} |
|
|
|
.audio-list { |
|
list-style: none; |
|
margin: 0; |
|
padding: 0; |
|
display: grid; |
|
gap: 0.6rem; |
|
} |
|
|
|
.audio-list li { |
|
border: 1px solid var(--line); |
|
border-radius: 12px; |
|
padding: 0.7rem; |
|
display: flex; |
|
justify-content: space-between; |
|
gap: 0.8rem; |
|
align-items: center; |
|
background: #fff; |
|
} |
|
|
|
.audio-actions { |
|
display: flex; |
|
align-items: center; |
|
gap: 0.45rem; |
|
} |
|
|
|
.small-button { |
|
border: 1px solid var(--line); |
|
border-radius: 10px; |
|
padding: 0.45rem 0.6rem; |
|
font-size: 0.82rem; |
|
color: var(--ink); |
|
background: #fff; |
|
} |
|
|
|
@media (max-width: 1080px) { |
|
.panel:nth-child(1), |
|
.panel:nth-child(2), |
|
.panel:nth-child(3) { |
|
grid-column: span 12; |
|
} |
|
} |
|
|
|
@media (max-width: 640px) { |
|
.topbar { |
|
margin: 0.8rem; |
|
flex-direction: column; |
|
align-items: flex-start; |
|
} |
|
|
|
.dashboard-grid { |
|
padding: 0 0.8rem 0.8rem; |
|
} |
|
|
|
.audio-list li { |
|
flex-direction: column; |
|
align-items: flex-start; |
|
} |
|
|
|
.time-row { |
|
grid-template-columns: 1fr; |
|
} |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div class="bg-orb bg-orb-one"></div> |
|
<div class="bg-orb bg-orb-two"></div> |
|
|
|
{% with messages = get_flashed_messages(with_categories=true) %} |
|
{% if messages %} |
|
<div class="flash-stack"> |
|
{% for category, message in messages %} |
|
<div class="flash flash-{{ category }}">{{ message }}</div> |
|
{% endfor %} |
|
</div> |
|
{% endif %} |
|
{% endwith %} |
|
|
|
{% block content %}{% endblock %} |
|
|
|
<script> |
|
(function () { |
|
const stack = document.querySelector(".flash-stack"); |
|
if (!stack) return; |
|
|
|
const flashes = Array.from(stack.querySelectorAll(".flash")); |
|
flashes.forEach((flash, index) => { |
|
const visibleDurationMs = 3600 + index * 250; |
|
window.setTimeout(() => { |
|
flash.classList.add("is-hiding"); |
|
window.setTimeout(() => { |
|
flash.remove(); |
|
if (!stack.querySelector(".flash")) { |
|
stack.remove(); |
|
} |
|
}, 360); |
|
}, visibleDurationMs); |
|
}); |
|
})(); |
|
</script> |
|
</body> |
|
</html>
|
|
|