CODEX - Varioues Fixes, and Replaced the Playback Modal with VIEW modal

This commit is contained in:
2026-02-23 10:34:10 +02:00
parent 12e793aa7e
commit 3a2362b7fd
5 changed files with 484 additions and 371 deletions

View File

@@ -5,6 +5,7 @@ import { useAuth } from "../auth/AuthContext";
import ConfirmDialog from "../components/ConfirmDialog";
import SpeedCalculatorModal from "./SpeedCalculatorModal";
import PlaybackModal from "./PlaybackModal";
import BinaryTableModal from "./BinaryTableModal";
function fallbackCopy(text, onSuccess) {
const ta = document.createElement("textarea");
@@ -54,12 +55,6 @@ function normalizeFileUrl(url) {
return `/api/${url}`;
}
function hueForDepth(index, count) {
const safeCount = Math.max(1, count);
const t = Math.max(0, Math.min(1, index / safeCount));
return 190 + (15 - 190) * t;
}
function Field({ label, children }) {
return (
<div>
@@ -128,6 +123,7 @@ export default function MelodyDetail() {
const [codeCopied, setCodeCopied] = useState(false);
const [showSpeedCalc, setShowSpeedCalc] = useState(false);
const [showPlayback, setShowPlayback] = useState(false);
const [showBinaryView, setShowBinaryView] = useState(false);
const [offlineSaving, setOfflineSaving] = useState(false);
useEffect(() => {
@@ -482,9 +478,6 @@ export default function MelodyDetail() {
{settings.noteAssignments?.length > 0 ? (
<div className="flex flex-wrap gap-1.5">
{settings.noteAssignments.map((assignedBell, noteIdx) => {
const noteHue = hueForDepth(noteIdx, settings.noteAssignments.length - 1);
const bellDepthIdx = Math.max(0, Math.min(15, (assignedBell || 1) - 1));
const bellHue = hueForDepth(bellDepthIdx, 15);
return (
<div
key={noteIdx}
@@ -493,16 +486,15 @@ export default function MelodyDetail() {
minWidth: "36px",
padding: "4px 6px",
backgroundColor: "var(--bg-card-hover)",
borderColor: `hsla(${noteHue}, 65%, 55%, 0.45)`,
boxShadow: `0 0 6px hsla(${noteHue}, 75%, 55%, 0.25) inset`,
borderColor: "var(--border-primary)",
}}
>
<span className="text-xs font-bold leading-tight" style={{ color: `hsl(${noteHue}, 80%, 72%)` }}>
<span className="text-xs font-bold leading-tight" style={{ color: "var(--text-secondary)" }}>
{String.fromCharCode(65 + noteIdx)}
</span>
<div className="w-full my-0.5" style={{ height: "1px", backgroundColor: "var(--border-primary)" }} />
<span className="text-xs leading-tight" style={{ color: assignedBell > 0 ? `hsl(${bellHue}, 80%, 70%)` : "var(--text-muted)" }}>
{assignedBell > 0 ? assignedBell : ""}
<span className="text-xs leading-tight" style={{ color: "var(--text-muted)" }}>
{assignedBell > 0 ? assignedBell : "-"}
</span>
</div>
);
@@ -561,11 +553,19 @@ export default function MelodyDetail() {
e.preventDefault();
try {
const token = localStorage.getItem("access_token");
let res = await fetch(binaryUrl, {
headers: token ? { Authorization: `Bearer ${token}` } : {},
});
// For external URLs (e.g. Firebase Storage), retry without auth header
if (!res.ok && binaryUrl.startsWith("http")) {
let res = null;
try {
res = await fetch(binaryUrl, {
headers: token ? { Authorization: `Bearer ${token}` } : {},
});
} catch {
if (binaryUrl.startsWith("http")) {
res = await fetch(binaryUrl);
} else {
throw new Error("Download failed: network error");
}
}
if ((!res || !res.ok) && binaryUrl.startsWith("http")) {
res = await fetch(binaryUrl);
}
if (!res.ok) throw new Error(`Download failed: ${res.statusText}`);
@@ -577,7 +577,7 @@ export default function MelodyDetail() {
a.click();
URL.revokeObjectURL(objectUrl);
} catch (err) {
console.error(err);
setError(err.message);
}
};
@@ -601,7 +601,7 @@ export default function MelodyDetail() {
</button>
<button
type="button"
onClick={() => setShowPlayback(true)}
onClick={() => setShowBinaryView(true)}
className="px-2 py-0.5 text-xs rounded-full"
style={{ color: "var(--text-secondary)", backgroundColor: "var(--bg-card-hover)" }}
>
@@ -634,11 +634,11 @@ export default function MelodyDetail() {
})()}
</Field>
<Field label="Audio Preview">
{files.preview_url ? (
{normalizeFileUrl(files.preview_url) ? (
<div className="space-y-1">
<audio controls src={files.preview_url} className="h-8" />
<audio controls src={normalizeFileUrl(files.preview_url)} className="h-8" />
<a
href={files.preview_url}
href={normalizeFileUrl(files.preview_url)}
target="_blank"
rel="noopener noreferrer"
className="underline text-xs"
@@ -757,6 +757,14 @@ export default function MelodyDetail() {
archetypeCsv={melody?.information?.archetype_csv || null}
onClose={() => setShowPlayback(false)}
/>
<BinaryTableModal
open={showBinaryView}
melody={melody}
builtMelody={builtMelody}
files={files}
archetypeCsv={melody?.information?.archetype_csv || null}
onClose={() => setShowBinaryView(false)}
/>
<SpeedCalculatorModal
open={showSpeedCalc}