Audiofy – Musikwünsche für Partys

Server (Website, Admin-Bereich, Player-API) und Player (raspotify +
Controller) mit Install-Skripten für Debian-Systeme.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-17 19:16:39 +01:00
co-authored by Claude Opus 5.5
commit 3610de7bae
45 changed files with 5666 additions and 0 deletions
+127
View File
@@ -0,0 +1,127 @@
/* Audiofy – Admin-Bereich (ergänzt app.css) */
.kopf { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 4px 0 12px; }
.kopf h1 { font-size: 1.4rem; }
.pillen { display: flex; flex-wrap: wrap; gap: 6px; }
.pille { font-size: .78rem; font-weight: 700; padding: 3px 10px; border-radius: 999px; background: #333; color: var(--leise); }
.pille.gut { background: #12391f; color: var(--akzent); }
.pille.schlecht { background: #3d1717; color: var(--fehler); }
.reiter {
position: sticky;
top: 0;
z-index: 5;
display: flex;
gap: 4px;
overflow-x: auto;
background: var(--bg);
padding: 8px 0;
margin-bottom: 8px;
scrollbar-width: none;
}
.reiter button {
flex: 1 0 auto;
font: inherit;
font-weight: 600;
font-size: .95rem;
min-height: 44px;
padding: 0 14px;
border: 0;
border-radius: 999px;
background: var(--karte);
color: var(--leise);
cursor: pointer;
}
.reiter button[aria-selected="true"] { background: var(--text); color: #111; }
.zahl { display: inline-block; min-width: 20px; margin-left: 4px; padding: 0 6px; border-radius: 999px; background: var(--warnung); color: #111; font-size: .78rem; }
button.gross, a.gross {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
font: inherit;
font-weight: 700;
font-size: 1.05rem;
min-height: 52px;
padding: 0 18px;
border: 0;
border-radius: 14px;
background: #2f2f2f;
color: var(--text);
cursor: pointer;
text-decoration: none;
}
button.akzent { background: var(--akzent); color: var(--akzent-text); }
/* Symbol über dem Text */
.gross.mit-symbol { flex-direction: column; gap: 4px; min-height: 72px; padding: 8px 12px; }
.gross.mit-symbol .symbol { font-size: 1.6rem; line-height: 1; }
button.gefahr { background: #b3261e; color: #fff; }
button:disabled { opacity: .5; cursor: default; }
form#login button { width: 100%; margin-top: 14px; }
.knopfreihe { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 12px; }
.knopfreihe.zwei { grid-template-columns: repeat(2, 1fr); }
.voll { width: 100%; margin-top: 12px; }
button.klein {
font: inherit;
font-size: .85rem;
font-weight: 600;
min-height: 40px;
min-width: 40px;
padding: 0 10px;
border: 0;
border-radius: 10px;
background: #2f2f2f;
color: var(--text);
cursor: pointer;
flex: 0 0 auto;
}
button.klein.akzent { background: var(--akzent); color: var(--akzent-text); }
button.klein.gefahr { background: #4a1c1c; color: var(--fehler); }
.aktionen { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.schalter-zeile { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 0; border-top: 1px solid var(--linie); }
.schalter-zeile:first-of-type { border-top: 0; }
.schalter-zeile .text .m { white-space: normal; }
.schalter { position: relative; width: 58px; height: 34px; flex: 0 0 auto; }
.schalter input { opacity: 0; width: 100%; height: 100%; margin: 0; position: absolute; cursor: pointer; z-index: 1; }
.schalter span { position: absolute; inset: 0; border-radius: 999px; background: #444; transition: background .15s; }
.schalter span::after { content: ""; position: absolute; top: 4px; left: 4px; width: 26px; height: 26px; border-radius: 50%; background: #fff; transition: transform .15s; }
.schalter input:checked + span { background: var(--akzent); }
.schalter input:checked + span::after { transform: translateX(24px); }
.schalter input:focus-visible + span { outline: 2px solid var(--text); outline-offset: 2px; }
.feld-zeile { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 0; }
.feld-zeile input[type="number"] {
width: 96px;
font: inherit;
font-size: 1.05rem;
color: var(--text);
background: #2a2a2a;
border: 2px solid transparent;
border-radius: 10px;
padding: 8px 10px;
text-align: right;
}
input[type="range"] { width: 100%; height: 36px; accent-color: var(--akzent); }
.lautstaerke { display: flex; align-items: center; gap: 12px; margin-top: 14px; }
.lautstaerke output { min-width: 3ch; text-align: right; font-weight: 700; }
.notaus-aktiv { background: #3d1717; color: var(--fehler); border-radius: var(--radius); padding: 12px 16px; margin-bottom: 16px; font-weight: 700; }
.qr { display: block; width: 100%; max-width: 280px; margin: 12px auto; background: #fff; border-radius: 12px; padding: 8px; }
.link-feld { width: 100%; font: inherit; font-size: .9rem; color: var(--text); background: #2a2a2a; border: 0; border-radius: 10px; padding: 10px 12px; }
.fehlertext { color: var(--fehler); }
/* Legende zu den Symbol-Knöpfen – nur auf Touch-Geräten (dort gibt es keine Hover-Beschriftung) */
.legende { display: none; flex-wrap: wrap; justify-content: center; text-align: center; gap: 4px 14px; margin: 12px 0 0; padding-top: 10px; border-top: 1px solid var(--linie); color: var(--leise); font-size: .82rem; }
@media (hover: none) { .legende { display: flex; } }
.zeit { color: var(--leise); font-size: .8rem; white-space: nowrap; }
.marke.besitzer { background: #6a4cff; color: #fff; }
.marke.quelle { background: #333; color: var(--leise); }
.abstand { margin-top: 18px; }