feat: Maestro loading animation - bouncing music note on staff

Replaced generic spinning character with a custom SVG eighth note
bouncing against four staff lines. Added note-bounce keyframe to
Tailwind config (0.6s ease-in-out infinite). More on-brand for a
music tool than a generic spinner.
This commit is contained in:
rin.kagamine committed 2026-05-31 10:32:39 -04:00
1 parent b08d0b6782
commit 9df8a4f865
2 files changed
+33 -4

No files matched your search

+28 -4
View File
@@ -19,6 +19,30 @@ interface Props {
onStructuredResult?: (fields: PromptStructure, mode: 'generate' | 'complete') => void onStructuredResult?: (fields: PromptStructure, mode: 'generate' | 'complete') => void
} }
function BouncingNote() {
return (
<svg
width="18"
height="18"
viewBox="0 0 18 18"
className="animate-note-bounce"
aria-hidden="true"
>
{/* Staff lines */}
<line x1="2" y1="5" x2="16" y2="5" stroke="currentColor" strokeWidth="0.7" opacity="0.4" />
<line x1="2" y1="8" x2="16" y2="8" stroke="currentColor" strokeWidth="0.7" opacity="0.4" />
<line x1="2" y1="11" x2="16" y2="11" stroke="currentColor" strokeWidth="0.7" opacity="0.4" />
<line x1="2" y1="14" x2="16" y2="14" stroke="currentColor" strokeWidth="0.7" opacity="0.4" />
{/* Note head */}
<ellipse cx="5.5" cy="13" rx="2.5" ry="2" fill="currentColor" transform="rotate(-15 5.5 13)" />
{/* Stem */}
<line x1="7.8" y1="12.5" x2="7.8" y2="4" stroke="currentColor" strokeWidth="1.2" />
{/* Flag */}
<path d="M7.8 4 C10 5.5, 9.5 7.5, 7.8 8" fill="none" stroke="currentColor" strokeWidth="1" />
</svg>
)
}
export default function MaestroButton({ export default function MaestroButton({
prompt, prompt,
onResult, onResult,
@@ -75,10 +99,10 @@ export default function MaestroButton({
type="button" type="button"
onClick={handleMaestro} onClick={handleMaestro}
disabled={isMaestroing} disabled={isMaestroing}
className={`${className} flex items-center justify-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md min-w-[140px] border transition-colors duration-200 ${ className={`${className} flex items-center justify-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md min-w-[140px] border border-kithara-accent/30 transition-colors duration-200 ${
isMaestroing isMaestroing
? 'bg-kithara-accent/20 border-kithara-accent/30 text-kithara-accent animate-pulse' ? 'bg-kithara-accent/20 text-kithara-accent'
: 'bg-kithara-accent/10 border-kithara-accent/30 hover:bg-kithara-accent/25 hover:border-kithara-accent/50 text-kithara-accent' : 'bg-kithara-accent/10 text-kithara-accent hover:bg-kithara-accent/25 hover:border-kithara-accent/50'
}`} }`}
title={mode === 'generate' title={mode === 'generate'
? "Let Maestro write a creative prompt for you" ? "Let Maestro write a creative prompt for you"
@@ -87,7 +111,7 @@ export default function MaestroButton({
> >
{isMaestroing ? ( {isMaestroing ? (
<> <>
<span className="inline-block animate-spin">♩</span> <BouncingNote />
<span className="truncate"> <span className="truncate">
{mode === 'generate' ? 'Dreaming...' : 'Composing...'} {mode === 'generate' ? 'Dreaming...' : 'Composing...'}
</span> </span>
+5
View File
@@ -19,9 +19,14 @@ export default {
'0%': { transform: 'translateX(0)' }, '0%': { transform: 'translateX(0)' },
'100%': { transform: 'translateX(-50%)' }, '100%': { transform: 'translateX(-50%)' },
}, },
'note-bounce': {
'0%, 100%': { transform: 'translateY(0)' },
'50%': { transform: 'translateY(-3px)' },
},
}, },
animation: { animation: {
'marquee': 'marquee-scroll linear infinite', 'marquee': 'marquee-scroll linear infinite',
'note-bounce': 'note-bounce 0.6s ease-in-out infinite',
}, },
}, },
}, },