Added SpeedCalc and MelodyBuilder. Evaluation Pending

This commit is contained in:
2026-02-22 13:17:54 +02:00
parent 8a8c665dfd
commit 8703c4fe26
27 changed files with 4075 additions and 3 deletions

View File

@@ -3,6 +3,7 @@ import { useParams, useNavigate } from "react-router-dom";
import api from "../api/client";
import { useAuth } from "../auth/AuthContext";
import ConfirmDialog from "../components/ConfirmDialog";
import SpeedCalculatorModal from "./SpeedCalculatorModal";
import {
getLocalizedValue,
getLanguageName,
@@ -36,6 +37,9 @@ export default function MelodyDetail() {
const [actionLoading, setActionLoading] = useState(false);
const [displayLang, setDisplayLang] = useState("en");
const [melodySettings, setMelodySettings] = useState(null);
const [builtMelody, setBuiltMelody] = useState(null);
const [codeCopied, setCodeCopied] = useState(false);
const [showSpeedCalc, setShowSpeedCalc] = useState(false);
useEffect(() => {
api.get("/settings/melody").then((ms) => {
@@ -57,6 +61,13 @@ export default function MelodyDetail() {
]);
setMelody(m);
setFiles(f);
// Load built melody assignment (non-fatal if it fails)
try {
const bm = await api.get(`/builder/melodies/for-melody/${id}`);
setBuiltMelody(bm || null);
} catch {
setBuiltMelody(null);
}
} catch (err) {
setError(err.message);
} finally {
@@ -189,6 +200,13 @@ export default function MelodyDetail() {
Unpublish
</button>
)}
<button
onClick={() => setShowSpeedCalc(true)}
className="px-4 py-2 text-sm rounded-md transition-colors"
style={{ backgroundColor: "var(--bg-card-hover)", color: "var(--text-primary)", border: "1px solid var(--border-primary)" }}
>
Speed Calculator
</button>
<button
onClick={() => navigate(`/melodies/${id}/edit`)}
className="px-4 py-2 text-sm rounded-md transition-colors"
@@ -375,6 +393,63 @@ export default function MelodyDetail() {
</div>
</div>
{/* Firmware Code section — only shown if a built melody with PROGMEM code is assigned */}
{builtMelody?.progmem_code && (
<section
className="rounded-lg p-6 border mt-6"
style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}
>
<div className="flex items-center justify-between mb-3">
<div>
<h2 className="text-lg font-semibold" style={{ color: "var(--text-heading)" }}>Firmware Code</h2>
<p className="text-xs mt-0.5" style={{ color: "var(--text-muted)" }}>
PROGMEM code for built-in firmware playback &nbsp;·&nbsp; PID: <span className="font-mono">{builtMelody.pid}</span>
</p>
</div>
<button
onClick={() => {
navigator.clipboard.writeText(builtMelody.progmem_code).then(() => {
setCodeCopied(true);
setTimeout(() => setCodeCopied(false), 2000);
});
}}
className="px-3 py-1.5 text-xs rounded transition-colors"
style={{
backgroundColor: codeCopied ? "var(--success-bg)" : "var(--bg-card-hover)",
color: codeCopied ? "var(--success-text)" : "var(--text-secondary)",
border: "1px solid var(--border-primary)",
}}
>
{codeCopied ? "Copied!" : "Copy Code"}
</button>
</div>
<pre
className="p-4 text-xs overflow-x-auto rounded-lg"
style={{
backgroundColor: "var(--bg-primary)",
color: "var(--text-primary)",
fontFamily: "monospace",
whiteSpace: "pre",
maxHeight: "360px",
overflowY: "auto",
border: "1px solid var(--border-primary)",
}}
>
{builtMelody.progmem_code}
</pre>
</section>
)}
<SpeedCalculatorModal
open={showSpeedCalc}
melody={melody}
onClose={() => setShowSpeedCalc(false)}
onSaved={() => {
setShowSpeedCalc(false);
loadData();
}}
/>
<ConfirmDialog
open={showDelete}
title="Delete Melody"