Progress bar and song reference/cover metadata

This commit is contained in:
riversedge
2026-02-04 20:40:38 -05:00
parent 16f5af6435
commit b75bea3860
8 changed files with 167 additions and 24 deletions
+14 -15
View File
@@ -445,11 +445,7 @@ export const CreatePanel: React.FC<CreatePanelProps> = ({ onGenerate, isGenerati
// Also set as current reference/source
const selectedTarget = target ?? audioModalTarget;
if (selectedTarget === 'reference') {
setReferenceAudioUrl(data.track.audio_url);
} else {
setSourceAudioUrl(data.track.audio_url);
}
applyAudioTargetUrl(selectedTarget, data.track.audio_url);
setShowAudioModal(false);
} catch (err) {
const message = err instanceof Error ? err.message : 'Upload failed';
@@ -481,11 +477,7 @@ export const CreatePanel: React.FC<CreatePanelProps> = ({ onGenerate, isGenerati
};
const useReferenceTrack = (track: ReferenceTrack) => {
if (audioModalTarget === 'reference') {
setReferenceAudioUrl(track.audio_url);
} else {
setSourceAudioUrl(track.audio_url);
}
applyAudioTargetUrl(audioModalTarget, track.audio_url);
setShowAudioModal(false);
setPlayingTrackId(null);
};
@@ -507,17 +499,24 @@ export const CreatePanel: React.FC<CreatePanelProps> = ({ onGenerate, isGenerati
const applyAudioUrl = () => {
if (!tempAudioUrl.trim()) return;
if (audioModalTarget === 'reference') {
setReferenceAudioUrl(tempAudioUrl.trim());
applyAudioTargetUrl(audioModalTarget, tempAudioUrl.trim());
setShowAudioModal(false);
setTempAudioUrl('');
};
const applyAudioTargetUrl = (target: 'reference' | 'source', url: string) => {
if (target === 'reference') {
setReferenceAudioUrl(url);
setReferenceTime(0);
setReferenceDuration(0);
} else {
setSourceAudioUrl(tempAudioUrl.trim());
setSourceAudioUrl(url);
setSourceTime(0);
setSourceDuration(0);
if (taskType === 'text2music') {
setTaskType('cover');
}
}
setShowAudioModal(false);
setTempAudioUrl('');
};
const formatTime = (time: number) => {
+68 -1
View File
@@ -39,6 +39,24 @@ export const RightSidebar: React.FC<RightSidebarProps> = ({ song, onClose, onOpe
}
}, [song, user]);
const getSourceLabel = (url?: string) => {
if (!url) return 'None';
try {
const parsed = new URL(url, window.location.origin);
const name = parsed.pathname.split('/').pop();
return decodeURIComponent(name || url);
} catch {
const parts = url.split('/');
return decodeURIComponent(parts[parts.length - 1] || url);
}
};
const openSource = (url?: string) => {
if (!url) return;
const resolved = url.startsWith('http') ? url : `${window.location.origin}${url}`;
window.open(resolved, '_blank');
};
if (!song) return (
<div className="w-full h-full bg-zinc-50 dark:bg-suno-panel border-l border-zinc-200 dark:border-white/5 flex items-center justify-center text-zinc-400 dark:text-zinc-500 text-sm transition-colors duration-300">
@@ -239,6 +257,55 @@ export const RightSidebar: React.FC<RightSidebarProps> = ({ song, onClose, onOpe
</div>
</div>
{(song.generationParams?.referenceAudioUrl || song.generationParams?.sourceAudioUrl) && (
<div className="space-y-3">
<div className="flex items-center gap-2 text-xs font-bold text-zinc-500 dark:text-zinc-400 uppercase tracking-wide">
<LinkIcon size={14} />
Sources
</div>
<div className="space-y-2">
<div className="flex items-center justify-between gap-3 rounded-lg border border-zinc-200 dark:border-white/10 bg-white dark:bg-zinc-900/40 px-3 py-2">
<div className="flex items-center gap-2 min-w-0">
<Music size={14} className="text-zinc-400" />
<div className="min-w-0">
<div className="text-xs text-zinc-500">Reference</div>
<div className="text-sm font-medium text-zinc-900 dark:text-white truncate">
{getSourceLabel(song.generationParams?.referenceAudioUrl)}
</div>
</div>
</div>
{song.generationParams?.referenceAudioUrl && (
<button
className="text-xs px-2 py-1 rounded-full border border-zinc-200 dark:border-white/10 text-zinc-600 dark:text-zinc-300 hover:bg-zinc-100 dark:hover:bg-white/10 transition-colors"
onClick={() => openSource(song.generationParams?.referenceAudioUrl)}
>
Open
</button>
)}
</div>
<div className="flex items-center justify-between gap-3 rounded-lg border border-zinc-200 dark:border-white/10 bg-white dark:bg-zinc-900/40 px-3 py-2">
<div className="flex items-center gap-2 min-w-0">
<Layers size={14} className="text-zinc-400" />
<div className="min-w-0">
<div className="text-xs text-zinc-500">Cover</div>
<div className="text-sm font-medium text-zinc-900 dark:text-white truncate">
{getSourceLabel(song.generationParams?.sourceAudioUrl)}
</div>
</div>
</div>
{song.generationParams?.sourceAudioUrl && (
<button
className="text-xs px-2 py-1 rounded-full border border-zinc-200 dark:border-white/10 text-zinc-600 dark:text-zinc-300 hover:bg-zinc-100 dark:hover:bg-white/10 transition-colors"
onClick={() => openSource(song.generationParams?.sourceAudioUrl)}
>
Open
</button>
)}
</div>
</div>
</div>
)}
<div className="h-px bg-zinc-200 dark:bg-white/5 w-full"></div>
{/* Tags / Style */}
@@ -332,4 +399,4 @@ const ActionButton: React.FC<{ icon: React.ReactNode; label?: string; active?: b
{icon}
{label && <span className="text-xs font-semibold">{label}</span>}
</button>
);
);
+15 -1
View File
@@ -355,6 +355,20 @@ const SongItem: React.FC<SongItemProps> = ({
<p className="text-xs text-zinc-500 dark:text-zinc-500 line-clamp-2 pt-1 font-medium max-w-2xl">
{song.style}
</p>
{song.isGenerating && (
<div className="pt-2">
<div className="h-1 rounded-full bg-zinc-200/70 dark:bg-white/10 overflow-hidden">
{song.progress !== undefined ? (
<div
className="h-full bg-gradient-to-r from-pink-500 to-purple-600 transition-all"
style={{ width: `${Math.min(100, Math.max(0, song.progress * 100))}%` }}
/>
) : (
<div className="h-full w-1/3 bg-gradient-to-r from-pink-500 to-purple-600 animate-pulse" />
)}
</div>
</div>
)}
</div>
{/* Actions Row - Hidden while generating */}
@@ -453,4 +467,4 @@ const SongItem: React.FC<SongItemProps> = ({
/>
</>
);
};
};