Bug fix
- EqualizerIcon: the SVG was rendering at the wrong size (filling
its parent) because it had no explicit width/height attributes.
Now it accepts a size prop with a 24px default and the SVG element
carries the size as width/height attributes, with the className
on top. Can't accidentally balloon.
Design
- Stripped the light-mode CSS — the app is dark-only now, and the
theme toggle was a no-op (clicking it just toggled a class that
had no matching rules). ThemeToggle.tsx and lib/theme.ts are
gone; initTheme() call removed from main.tsx.
- Reworked the input form:
• brand row is now small + refined (icon + wordmark, no huge
gradient title)
• Options is a single subtle collapsible card with a chevron and
a count badge showing how many options are non-default
• Vocals is now a segmented pill (single rounded container, two
flat segments) instead of two full-width grid buttons
• Generate button is slightly smaller (py-3.5, text-sm) and
uses a softer shadow (shadow-violet-900/20)
- Empty state in the results panel: dashed-border card, soft
gradient blur behind the music icon, cleaner copy.
- Results header: smaller heading, the 'Regenerate All' and
'Cancel' buttons are now tiny ghost-style pills in the top-right.
- Sticky ZIP bar: softer shadow, more refined copy.
- Result cards: smaller icon, single-line title, the Regenerate
button is now an inline pill that fits next to Revert + Copy.
- Home page header now has a tiny equalizer icon + 'MelodyMuse'
wordmark on the left (was just text). Settings page header has
the back arrow on the left and the title, no theme toggle.
- Global CSS: added modern focus-visible ring, custom selection
color, subtle scrollbar thumb, slightly tweaked the gradient
text to a softer violet-300 → cyan-300 instead of the loud
violet-400 → fuchsia-400 → cyan-400.
95 lines
2.4 KiB
TypeScript
95 lines
2.4 KiB
TypeScript
// Equalizer/waveform mark for the MelodyMuse header. The SVG has explicit
|
|
// width/height attributes (in addition to the Tailwind class) so it can't
|
|
// accidentally balloon to fill its parent if the CSS fails to load.
|
|
|
|
interface EqualizerIconProps {
|
|
className?: string;
|
|
size?: number;
|
|
}
|
|
|
|
export function EqualizerIcon({ className, size = 24 }: EqualizerIconProps) {
|
|
return (
|
|
<svg
|
|
width={size}
|
|
height={size}
|
|
viewBox="0 0 32 32"
|
|
fill="none"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
aria-hidden="true"
|
|
className={className}
|
|
>
|
|
<defs>
|
|
<linearGradient
|
|
id="eq-grad"
|
|
x1="0"
|
|
y1="0"
|
|
x2="32"
|
|
y2="32"
|
|
gradientUnits="userSpaceOnUse"
|
|
>
|
|
<stop offset="0" stopColor="#a78bfa" />
|
|
<stop offset="1" stopColor="#22d3ee" />
|
|
</linearGradient>
|
|
</defs>
|
|
<g stroke="url(#eq-grad)" strokeWidth="2.4" strokeLinecap="round">
|
|
<line x1="5" y1="13" x2="5" y2="19">
|
|
<animate
|
|
attributeName="y1"
|
|
values="13;8;13"
|
|
dur="1.2s"
|
|
repeatCount="indefinite"
|
|
/>
|
|
<animate
|
|
attributeName="y2"
|
|
values="19;24;19"
|
|
dur="1.2s"
|
|
repeatCount="indefinite"
|
|
/>
|
|
</line>
|
|
<line x1="11" y1="9" x2="11" y2="23">
|
|
<animate
|
|
attributeName="y1"
|
|
values="9;14;9"
|
|
dur="1.4s"
|
|
repeatCount="indefinite"
|
|
/>
|
|
<animate
|
|
attributeName="y2"
|
|
values="23;18;23"
|
|
dur="1.4s"
|
|
repeatCount="indefinite"
|
|
/>
|
|
</line>
|
|
<line x1="17" y1="11" x2="17" y2="21">
|
|
<animate
|
|
attributeName="y1"
|
|
values="11;6;11"
|
|
dur="1.0s"
|
|
repeatCount="indefinite"
|
|
/>
|
|
<animate
|
|
attributeName="y2"
|
|
values="21;26;21"
|
|
dur="1.0s"
|
|
repeatCount="indefinite"
|
|
/>
|
|
</line>
|
|
<line x1="23" y1="8" x2="23" y2="24">
|
|
<animate
|
|
attributeName="y1"
|
|
values="8;13;8"
|
|
dur="1.6s"
|
|
repeatCount="indefinite"
|
|
/>
|
|
<animate
|
|
attributeName="y2"
|
|
values="24;19;24"
|
|
dur="1.6s"
|
|
repeatCount="indefinite"
|
|
/>
|
|
</line>
|
|
</g>
|
|
</svg>
|
|
);
|
|
}
|