Files
csgowtf/src/lib/components/landing/AnimatedCounter.svelte
vikingowl 1ddda81d93 feat: Add neon esports landing page with WCAG accessibility
- Create HeroSection with animated search bar and stat counters
- Add LiveMatchTicker with auto-scrolling recent matches
- Build FlashLeaderboard "Wall of Shame" with podium display
- Implement FeatureShowcase with scroll-triggered animations
- Add NeonCTA call-to-action section with trust badges
- Create reusable NeonButton component with glow effects

Accessibility improvements:
- Add aria-labels, aria-hidden for decorative elements
- Implement focus-visible ring styles for keyboard navigation
- Support prefers-reduced-motion across all animations
- Use semantic HTML (article, nav, dl) for screen readers
- Improve color contrast ratios for WCAG compliance

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 16:10:13 +01:00

64 lines
1.2 KiB
Svelte

<script lang="ts">
import { tweened } from 'svelte/motion';
import { cubicOut } from 'svelte/easing';
import { onMount } from 'svelte';
interface Props {
value: number;
duration?: number;
prefix?: string;
suffix?: string;
format?: (value: number) => string;
}
let {
value,
duration = 2000,
prefix = '',
suffix = '',
format = (val: number) => Math.floor(val).toLocaleString()
}: Props = $props();
const displayValue = tweened(0, {
duration,
easing: cubicOut
});
let hasAnimated = false;
let containerElement: HTMLElement;
onMount(() => {
// Use Intersection Observer to start animation when visible
const observer = new IntersectionObserver(
(entries) => {
for (const entry of entries) {
if (entry.isIntersecting && !hasAnimated) {
hasAnimated = true;
displayValue.set(value);
}
}
},
{ threshold: 0.1 }
);
if (containerElement) {
observer.observe(containerElement);
}
return () => {
observer.disconnect();
};
});
// Update the target value if it changes after initial animation
$effect(() => {
if (hasAnimated) {
displayValue.set(value);
}
});
</script>
<span bind:this={containerElement} class="tabular-nums">
{prefix}{format($displayValue)}{suffix}
</span>