feat: premium polish pass — typing effect, animated counters, ambient orbs, input glow, show/hide password, redesigned settings, Reveal animations
Deploy / release (push) Skipped
Deploy / deploy (push) Successful in 1m53s

- Add TypewriterText component for hero heading animation
- Add AnimatedCounter with scroll-triggered count-up
- Add AmbientOrbs with floating gradient orbs in hero
- Add input-glow focus effect, btn-shine hover effect CSS
- Add show/hide password toggle on login, register, and home login forms
- Redesign settings page with premium gradient cards and icon headers
- Polish /me dashboard with Reveal animations, btn-shine, input-glow
- Add animate-count CSS keyframe
This commit is contained in:
openhands committed 2026-07-24 13:34:46 +02:00
1 parent 5fa342018d
commit b37b6bc2b9
10 files changed
+569 -150

No files matched your search

+66
View File
@@ -0,0 +1,66 @@
"use client";
import { useEffect, useState } from "react";
interface Orb {
id: number;
x: number;
y: number;
size: number;
delay: number;
duration: number;
color: string;
}
export function AmbientOrbs() {
const [orbs, setOrbs] = useState<Orb[]>([]);
useEffect(() => {
const colors = [
"var(--color-primary)",
"var(--color-accent)",
"color-mix(in srgb, var(--color-primary) 60%, var(--color-accent))",
];
const items: Orb[] = Array.from({ length: 3 }, (_, i) => ({
id: i,
x: 15 + Math.random() * 70,
y: 10 + Math.random() * 70,
size: 120 + Math.random() * 180,
delay: Math.random() * 3,
duration: 8 + Math.random() * 6,
color: colors[i],
}));
setOrbs(items);
}, []);
if (orbs.length === 0) return null;
return (
<div className="absolute inset-0 overflow-hidden pointer-events-none" style={{ zIndex: 1 }}>
{orbs.map((orb) => (
<div
key={orb.id}
className="absolute rounded-full"
style={{
left: `${orb.x}%`,
top: `${orb.y}%`,
width: orb.size,
height: orb.size,
background: `radial-gradient(circle, ${orb.color} 0%, transparent 70%)`,
opacity: 0.12,
animation: `ambient-drift-${orb.id} ${orb.duration}s ease-in-out ${orb.delay}s infinite alternate`,
}}
/>
))}
<style>{`
${orbs.map((orb) => `
@keyframes ambient-drift-${orb.id} {
0% { transform: translate(0, 0) scale(1); }
33% { transform: translate(${(Math.random() > 0.5 ? "" : "-") + (20 + Math.random() * 30)}px, ${(Math.random() > 0.5 ? "" : "-") + (20 + Math.random() * 30)}px) scale(${0.8 + Math.random() * 0.4}); }
66% { transform: translate(${(Math.random() > 0.5 ? "" : "-") + (10 + Math.random() * 40)}px, ${(Math.random() > 0.5 ? "" : "-") + (15 + Math.random() * 35)}px) scale(${0.9 + Math.random() * 0.3}); }
100% { transform: translate(0, 0) scale(1); }
}`).join("\n")}
`}</style>
</div>
);
}