More Archetype Fixes
This commit is contained in:
@@ -42,6 +42,44 @@ function Field({ label, children }) {
|
||||
);
|
||||
}
|
||||
|
||||
function UrlField({ label, value }) {
|
||||
const [copied, setCopied] = useState(false);
|
||||
return (
|
||||
<div>
|
||||
<dt className="text-xs font-medium uppercase tracking-wide mb-1" style={{ color: "var(--text-muted)" }}>
|
||||
{label}
|
||||
</dt>
|
||||
<dd className="flex items-center gap-2">
|
||||
<span
|
||||
className="text-sm font-mono flex-1 min-w-0"
|
||||
style={{
|
||||
color: "var(--text-primary)",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
display: "block",
|
||||
userSelect: "text",
|
||||
}}
|
||||
title={value}
|
||||
>
|
||||
{value}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => copyText(value, () => { setCopied(true); setTimeout(() => setCopied(false), 2000); })}
|
||||
className="flex-shrink-0 px-2 py-0.5 text-xs rounded transition-colors"
|
||||
style={{
|
||||
backgroundColor: copied ? "var(--success-bg)" : "var(--bg-card-hover)",
|
||||
color: copied ? "var(--success-text)" : "var(--text-muted)",
|
||||
border: "1px solid var(--border-primary)",
|
||||
}}
|
||||
>
|
||||
{copied ? "Copied!" : "Copy"}
|
||||
</button>
|
||||
</dd>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function MelodyDetail() {
|
||||
const { id } = useParams();
|
||||
const navigate = useNavigate();
|
||||
@@ -333,9 +371,11 @@ export default function MelodyDetail() {
|
||||
<dl className="grid grid-cols-2 md:grid-cols-3 gap-4">
|
||||
<Field label="Document ID">{melody.id}</Field>
|
||||
<Field label="PID (Playback ID)">{melody.pid}</Field>
|
||||
<div className="col-span-2 md:col-span-3">
|
||||
<Field label="URL">{melody.url}</Field>
|
||||
</div>
|
||||
{melody.url && (
|
||||
<div className="col-span-2 md:col-span-3">
|
||||
<UrlField label="URL" value={melody.url} />
|
||||
</div>
|
||||
)}
|
||||
</dl>
|
||||
</section>
|
||||
</div>
|
||||
@@ -384,7 +424,7 @@ export default function MelodyDetail() {
|
||||
}}
|
||||
>
|
||||
<span className="text-xs font-bold leading-tight" style={{ color: "var(--text-secondary)" }}>
|
||||
{noteIdx + 1}
|
||||
{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: "var(--text-muted)" }}>
|
||||
@@ -396,7 +436,7 @@ export default function MelodyDetail() {
|
||||
) : (
|
||||
<span style={{ color: "var(--text-muted)" }}>-</span>
|
||||
)}
|
||||
<p className="text-xs mt-1" style={{ color: "var(--text-muted)" }}>Top = Note #, Bottom = Assigned Bell</p>
|
||||
<p className="text-xs mt-1" style={{ color: "var(--text-muted)" }}>Top = Note, Bottom = Assigned Bell</p>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
@@ -432,9 +472,13 @@ export default function MelodyDetail() {
|
||||
e.preventDefault();
|
||||
try {
|
||||
const token = localStorage.getItem("access_token");
|
||||
const res = await fetch(binaryUrl, {
|
||||
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")) {
|
||||
res = await fetch(binaryUrl);
|
||||
}
|
||||
if (!res.ok) throw new Error(`Download failed: ${res.statusText}`);
|
||||
const blob = await res.blob();
|
||||
const objectUrl = URL.createObjectURL(blob);
|
||||
|
||||
Reference in New Issue
Block a user