Merge PR #24: Various UI improvements from riversedge

Includes progress bar, drag and drop, gender buttons, upload
improvements, and dynamic duration limits.
This commit is contained in:
fspecii
2026-02-05 22:34:01 +02:00
19 changed files with 1892 additions and 285 deletions
+102
View File
@@ -95,6 +95,25 @@ export const RightSidebar: React.FC<RightSidebarProps> = ({ song, onClose, onOpe
}
};
const getSourceLabel = (url?: string) => {
if (!url) return 'None';
try {
const parsed = new URL(url, window.location.origin);
const name = decodeURIComponent(parsed.pathname.split('/').pop() || url);
return name.replace(/\.[^/.]+$/, '') || name;
} catch {
const parts = url.split('/');
const name = decodeURIComponent(parts[parts.length - 1] || url);
return name.replace(/\.[^/.]+$/, '') || name;
}
};
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">
<div className="flex flex-col items-center gap-2">
@@ -347,6 +366,89 @@ 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">
{song.generationParams?.referenceAudioUrl && (
<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">
{song.generationParams?.referenceAudioTitle || getSourceLabel(song.generationParams?.referenceAudioUrl)}
</div>
</div>
</div>
<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={() => {
if (!song.generationParams?.referenceAudioUrl || !onPlay) return;
const previewSong = {
id: `ref_${song.id}`,
title: song.generationParams?.referenceAudioTitle || getSourceLabel(song.generationParams?.referenceAudioUrl),
lyrics: '',
style: 'Reference',
coverUrl: song.coverUrl,
duration: '0:00',
createdAt: new Date(),
tags: [],
audioUrl: song.generationParams?.referenceAudioUrl,
isPublic: false,
userId: song.userId,
creator: song.creator,
};
onPlay(previewSong);
}}
>
Play
</button>
</div>
)}
{song.generationParams?.sourceAudioUrl && (
<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">
{song.generationParams?.sourceAudioTitle || getSourceLabel(song.generationParams?.sourceAudioUrl)}
</div>
</div>
</div>
<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={() => {
if (!song.generationParams?.sourceAudioUrl || !onPlay) return;
const previewSong = {
id: `cover_${song.id}`,
title: song.generationParams?.sourceAudioTitle || getSourceLabel(song.generationParams?.sourceAudioUrl),
lyrics: '',
style: 'Cover',
coverUrl: song.coverUrl,
duration: '0:00',
createdAt: new Date(),
tags: [],
audioUrl: song.generationParams?.sourceAudioUrl,
isPublic: false,
userId: song.userId,
creator: song.creator,
};
onPlay(previewSong);
}}
>
Play
</button>
</div>
)}
</div>
</div>
)}
<div className="h-px bg-zinc-200 dark:bg-white/5 w-full"></div>
{/* Tags / Style */}