mirror of
https://github.com/R0m1k3/podcastic.git
synced 2026-10-11 17:26:20 +02:00
fix: equalizer plus proche du design Stitch + couleurs plus profondes
Barres plus pleines et arrondies, halo lumineux sur pics audio, palette dark plus riche (indigo vibrant, cyan éclatant, bleu profond), ombres et bordures plus marquées, gradients de fond plus immersifs. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
1 parent
5c2a6438cd
commit
66d61595bd
2 files changed
+47
-46
No files matched your search
@@ -8,12 +8,12 @@ interface AudioVisualizerProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function AudioVisualizer({
|
export default function AudioVisualizer({
|
||||||
barCount = 28,
|
barCount = 40,
|
||||||
height = 80,
|
height = 96,
|
||||||
gap = 3,
|
gap = 2,
|
||||||
}: AudioVisualizerProps) {
|
}: AudioVisualizerProps) {
|
||||||
const { isPlaying, getFrequencyData } = useAudio();
|
const { isPlaying, getFrequencyData } = useAudio();
|
||||||
const [heights, setHeights] = useState<number[]>(() => Array(barCount).fill(4));
|
const [heights, setHeights] = useState<number[]>(() => Array(barCount).fill(3));
|
||||||
const rafRef = useRef<number>(0);
|
const rafRef = useRef<number>(0);
|
||||||
const playingRef = useRef(isPlaying);
|
const playingRef = useRef(isPlaying);
|
||||||
const getDataRef = useRef(getFrequencyData);
|
const getDataRef = useRef(getFrequencyData);
|
||||||
@@ -27,33 +27,30 @@ export default function AudioVisualizer({
|
|||||||
const animate = () => {
|
const animate = () => {
|
||||||
const rawData = getDataRef.current?.();
|
const rawData = getDataRef.current?.();
|
||||||
if (rawData && playingRef.current) {
|
if (rawData && playingRef.current) {
|
||||||
// Build symmetric mirrored heights
|
|
||||||
const newHeights: number[] = [];
|
const newHeights: number[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < barCount; i++) {
|
for (let i = 0; i < barCount; i++) {
|
||||||
// Mirror index: distance from center
|
|
||||||
const distFromCenter = Math.abs(i - (barCount - 1) / 2);
|
const distFromCenter = Math.abs(i - (barCount - 1) / 2);
|
||||||
const halfIdx = Math.floor(distFromCenter);
|
const halfIdx = Math.floor(distFromCenter);
|
||||||
const dataIndex = Math.min(halfIdx, rawData.length - 1);
|
const dataIndex = Math.min(halfIdx, rawData.length - 1);
|
||||||
|
|
||||||
const value = rawData[dataIndex] ?? 0;
|
const value = rawData[dataIndex] ?? 0;
|
||||||
|
|
||||||
// Smooth falloff curve toward edges for aesthetic hill shape
|
// Smoother edge fade — keep center bars taller
|
||||||
const edgeFade = 1 - (distFromCenter / half) * 0.35;
|
const edgeFade = 1 - (distFromCenter / half) * 0.2;
|
||||||
|
|
||||||
// Boost mid frequencies for speech
|
// Mid boost for vocals/speech
|
||||||
const midBoost = distFromCenter < half * 0.5 ? 1.1 : 1;
|
const midBoost = distFromCenter < half * 0.6 ? 1.15 : 1;
|
||||||
|
|
||||||
const h = Math.max(4, Math.min(100, (value / 255) * 100 * edgeFade * midBoost));
|
// More dynamic range — minimum height of 6%
|
||||||
|
const h = Math.max(6, Math.min(100, (value / 255) * 100 * edgeFade * midBoost));
|
||||||
newHeights.push(h);
|
newHeights.push(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
setHeights(newHeights);
|
setHeights(newHeights);
|
||||||
} else {
|
} else {
|
||||||
|
// Gentle decay when paused — slower falloff for smoother look
|
||||||
setHeights(prev =>
|
setHeights(prev =>
|
||||||
prev.map(h => {
|
prev.map(h => {
|
||||||
const next = h * 0.88;
|
const next = h * 0.92;
|
||||||
return next < 4.5 ? 4 : next;
|
return next < 3.5 ? 3 : next;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -64,21 +61,25 @@ export default function AudioVisualizer({
|
|||||||
return () => cancelAnimationFrame(rafRef.current);
|
return () => cancelAnimationFrame(rafRef.current);
|
||||||
}, [barCount]);
|
}, [barCount]);
|
||||||
|
|
||||||
|
const barWidth = Math.max(2, (100 - gap * (barCount - 1)) / barCount);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="flex items-end justify-center"
|
className="flex items-end justify-center w-full"
|
||||||
style={{ height, gap }}
|
style={{ height, gap: `${gap}%` }}
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
>
|
>
|
||||||
{heights.map((h, i) => (
|
{heights.map((h, i) => (
|
||||||
<div
|
<div
|
||||||
key={i}
|
key={i}
|
||||||
className="rounded-full bg-gradient-to-t from-[var(--accent-primary)] to-[var(--accent-secondary)]"
|
className="rounded-full"
|
||||||
style={{
|
style={{
|
||||||
width: 3,
|
width: `${barWidth}%`,
|
||||||
height: `${h}%`,
|
height: `${h}%`,
|
||||||
transition: playingRef.current ? 'height 60ms linear' : 'height 220ms ease-out',
|
background: `linear-gradient(to top, var(--accent-primary), var(--accent-secondary))`,
|
||||||
opacity: 0.45 + (h / 180),
|
transition: playingRef.current ? 'height 80ms linear' : 'height 300ms ease-out',
|
||||||
|
opacity: 0.55 + (h / 200),
|
||||||
|
boxShadow: h > 40 ? `0 0 ${Math.floor(h / 6)}px rgba(99, 102, 241, ${Math.min(0.5, h / 200)})` : 'none',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -8,30 +8,30 @@
|
|||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
:root {
|
:root {
|
||||||
/* Dark theme (default) */
|
/* Dark theme (default) — calibrated to Stitch designs */
|
||||||
--bg-base: #020617;
|
--bg-base: #010615;
|
||||||
--bg-surface: #0f1222;
|
--bg-surface: #0b0f20;
|
||||||
--bg-elevated: #161a2e;
|
--bg-elevated: #11162c;
|
||||||
--bg-glass: rgba(15, 18, 34, 0.7);
|
--bg-glass: rgba(11, 15, 32, 0.75);
|
||||||
--text-primary: #f1f5f9;
|
--text-primary: #f0f4ff;
|
||||||
--text-secondary: #94a3b8;
|
--text-secondary: #8892b0;
|
||||||
--text-muted: #64748b;
|
--text-muted: #566080;
|
||||||
--accent-primary: #6366f1;
|
--accent-primary: #6c6ff7;
|
||||||
--accent-secondary: #06b6d4;
|
--accent-secondary: #0dc5e0;
|
||||||
--accent-rose: #f43f5e;
|
--accent-rose: #f84b6b;
|
||||||
--accent-gold: #f59e0b;
|
--accent-gold: #f7b80a;
|
||||||
--accent-emerald: #10b981;
|
--accent-emerald: #12c278;
|
||||||
--accent-glow: rgba(99, 102, 241, 0.25);
|
--accent-glow: rgba(108, 111, 247, 0.28);
|
||||||
--border-color: rgba(255, 255, 255, 0.06);
|
--border-color: rgba(255, 255, 255, 0.07);
|
||||||
--border-hover: rgba(255, 255, 255, 0.12);
|
--border-hover: rgba(255, 255, 255, 0.14);
|
||||||
--radius-sm: 0.625rem;
|
--radius-sm: 0.625rem;
|
||||||
--radius-md: 0.875rem;
|
--radius-md: 0.875rem;
|
||||||
--radius-lg: 1.125rem;
|
--radius-lg: 1.125rem;
|
||||||
--radius-xl: 1.375rem;
|
--radius-xl: 1.5rem;
|
||||||
--glass-blur: blur(24px) saturate(180%);
|
--glass-blur: blur(28px) saturate(180%);
|
||||||
--shadow-card: 0 2px 12px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.03);
|
--shadow-card: 0 2px 16px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.04);
|
||||||
--shadow-card-hover: 0 8px 30px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.06);
|
--shadow-card-hover: 0 10px 36px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.08);
|
||||||
--shadow-glow: 0 0 24px var(--accent-glow);
|
--shadow-glow: 0 0 28px var(--accent-glow);
|
||||||
--font-display: 'Montserrat', ui-sans-serif, system-ui, sans-serif;
|
--font-display: 'Montserrat', ui-sans-serif, system-ui, sans-serif;
|
||||||
--font-body: 'Outfit', ui-sans-serif, system-ui, sans-serif;
|
--font-body: 'Outfit', ui-sans-serif, system-ui, sans-serif;
|
||||||
--transition-base: 200ms cubic-bezier(0.4, 0, 0.2, 1);
|
--transition-base: 200ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
@@ -97,9 +97,9 @@ body::before {
|
|||||||
z-index: -1;
|
z-index: -1;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
background:
|
background:
|
||||||
radial-gradient(ellipse 80% 35% at 10% 5%, rgba(99, 102, 241, 0.08) 0%, transparent 55%),
|
radial-gradient(ellipse 80% 30% at 5% 0%, rgba(108, 111, 247, 0.10) 0%, transparent 50%),
|
||||||
radial-gradient(ellipse 60% 40% at 90% 95%, rgba(6, 182, 212, 0.06) 0%, transparent 55%),
|
radial-gradient(ellipse 55% 35% at 95% 100%, rgba(13, 197, 224, 0.07) 0%, transparent 50%),
|
||||||
radial-gradient(ellipse 50% 30% at 50% 50%, rgba(99, 102, 241, 0.03) 0%, transparent 50%);
|
radial-gradient(ellipse 40% 25% at 50% 50%, rgba(108, 111, 247, 0.04) 0%, transparent 50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
body.light-theme::before {
|
body.light-theme::before {
|
||||||
|
|||||||
Reference in new issue
Block a user