CODEX - Varioues Fixes, and Replaced the Playback Modal with VIEW modal
This commit is contained in:
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user