mirror of
https://github.com/soconnor0919/beenvoice.git
synced 2025-12-13 01:24:44 -05:00
Add flashy UI animations and enhance PDF invoice layout
- Adds CSS animations for buttons, cards, icons, and text - Improves homepage with animated elements and interactive effects - Refines PDF export: better notes/totals layout, colors, and spacing - Updates styles for more engaging user experience
This commit is contained in:
121
src/app/page.tsx
121
src/app/page.tsx
@@ -9,13 +9,13 @@ import {
|
||||
Check,
|
||||
Zap,
|
||||
Shield,
|
||||
Globe,
|
||||
Sparkles,
|
||||
BarChart3,
|
||||
Clock,
|
||||
Rocket,
|
||||
Heart,
|
||||
ChevronRight,
|
||||
Stars,
|
||||
} from "lucide-react";
|
||||
|
||||
export default function HomePage() {
|
||||
@@ -62,57 +62,93 @@ export default function HomePage() {
|
||||
<section className="bg-hero-gradient relative overflow-hidden px-4 pt-12 pb-16 sm:pt-20">
|
||||
{/* Background decoration */}
|
||||
<div className="hero-overlay"></div>
|
||||
<div className="hero-orb-1"></div>
|
||||
<div className="hero-orb-2"></div>
|
||||
<div className="hero-orb-3"></div>
|
||||
<div className="hero-orb-1 animate-glow-pulse animate-pulse"></div>
|
||||
<div className="hero-orb-2 animate-rainbow animate-bounce"></div>
|
||||
<div className="hero-orb-3 animate-glow-pulse animate-pulse"></div>
|
||||
|
||||
{/* Particle Effects */}
|
||||
<div className="particles-container">
|
||||
<div className="particle"></div>
|
||||
<div className="particle"></div>
|
||||
<div className="particle"></div>
|
||||
<div className="particle"></div>
|
||||
<div className="particle"></div>
|
||||
<div className="particle"></div>
|
||||
<div className="particle"></div>
|
||||
<div className="particle"></div>
|
||||
<div className="particle"></div>
|
||||
</div>
|
||||
|
||||
{/* Floating icons */}
|
||||
<div className="animate-float-slow hover:animate-wiggle absolute top-20 left-10">
|
||||
<Stars className="h-6 w-6 cursor-pointer text-white/20 transition-colors hover:text-white/40" />
|
||||
</div>
|
||||
<div className="animate-float-delayed hover:animate-wiggle absolute top-32 right-16">
|
||||
<Zap className="h-8 w-8 cursor-pointer text-emerald-300/30 transition-colors hover:text-emerald-300/60" />
|
||||
</div>
|
||||
<div className="animate-float hover:animate-wiggle absolute bottom-32 left-20">
|
||||
<Heart className="h-5 w-5 cursor-pointer text-pink-300/25 transition-colors hover:text-pink-300/50" />
|
||||
</div>
|
||||
<div className="relative container mx-auto text-center">
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<Badge className="badge-brand mb-4 sm:mb-6">
|
||||
<Sparkles className="mr-1 h-3 w-3" />
|
||||
<Badge className="badge-brand hover:animate-wiggle mb-4 animate-pulse cursor-pointer sm:mb-6">
|
||||
<Sparkles className="hover:animate-rainbow mr-1 h-3 w-3 animate-spin" />
|
||||
Free Forever
|
||||
</Badge>
|
||||
|
||||
<h1 className="mb-4 text-4xl font-bold tracking-tight text-white sm:mb-6 sm:text-6xl lg:text-7xl">
|
||||
<h1 className="animate-fade-in-up animate-glitch mb-4 text-4xl font-bold tracking-tight text-white sm:mb-6 sm:text-6xl lg:text-7xl">
|
||||
Simple Invoicing for
|
||||
<span className="block text-emerald-50">Freelancers</span>
|
||||
<span className="animate-text-shimmer neon-glow block bg-gradient-to-r from-emerald-50 via-white to-emerald-50 bg-[length:200%_100%] bg-clip-text text-transparent">
|
||||
Freelancers
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<p className="mx-auto mb-6 max-w-2xl text-lg leading-relaxed text-emerald-50/90 sm:mb-8 sm:text-xl">
|
||||
<p className="animate-fade-in-up animation-delay-300 mx-auto mb-6 max-w-2xl text-lg leading-relaxed text-emerald-50/90 sm:mb-8 sm:text-xl">
|
||||
Create professional invoices, manage clients, and track payments.
|
||||
Built for freelancers and small businesses—
|
||||
<span className="font-semibold text-white">completely free</span>.
|
||||
<span className="animate-pulse font-semibold text-white">
|
||||
completely free
|
||||
</span>
|
||||
.
|
||||
</p>
|
||||
|
||||
<div className="btn-group">
|
||||
<div className="btn-group animate-fade-in-up animation-delay-500">
|
||||
<Link href="/auth/register">
|
||||
<Button
|
||||
size="lg"
|
||||
className="btn-brand-secondary group w-full px-6 py-3 text-base font-semibold shadow-xl transition-colors duration-300 sm:w-auto sm:px-8 sm:py-4 sm:text-lg"
|
||||
className="btn-brand-secondary btn-flashy group w-full transform px-6 py-3 text-base font-semibold shadow-xl transition-all duration-300 hover:scale-105 hover:shadow-2xl sm:w-auto sm:px-8 sm:py-4 sm:text-lg"
|
||||
>
|
||||
Get Started
|
||||
<ArrowRight className="ml-2 h-4 w-4 transition-transform group-hover:translate-x-1 sm:h-5 sm:w-5" />
|
||||
<ArrowRight className="ml-2 h-4 w-4 transition-all group-hover:translate-x-1 group-hover:scale-110 group-hover:rotate-12 sm:h-5 sm:w-5" />
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="#features">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="lg"
|
||||
className="group w-full border-white/30 px-6 py-3 text-base text-white hover:bg-white/10 sm:w-auto sm:px-8 sm:py-4 sm:text-lg"
|
||||
className="btn-flashy group w-full transform border-white/30 px-6 py-3 text-base text-white transition-all duration-300 hover:scale-105 hover:bg-white/10 hover:shadow-xl sm:w-auto sm:px-8 sm:py-4 sm:text-lg"
|
||||
>
|
||||
Learn More
|
||||
<ChevronRight className="ml-2 h-4 w-4 transition-transform group-hover:translate-x-1 sm:h-5 sm:w-5" />
|
||||
<ChevronRight className="ml-2 h-4 w-4 transition-all group-hover:translate-x-1 group-hover:scale-110 group-hover:rotate-12 sm:h-5 sm:w-5" />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="mt-8 flex flex-col items-center justify-center gap-2 text-sm text-emerald-50/80 sm:mt-12 sm:flex-row sm:gap-6">
|
||||
<div className="animate-fade-in-up animation-delay-700 mt-8 flex flex-col items-center justify-center gap-2 text-sm text-emerald-50/80 sm:mt-12 sm:flex-row sm:gap-6">
|
||||
{[
|
||||
"No credit card required",
|
||||
"Setup in 2 minutes",
|
||||
"Free forever",
|
||||
].map((text, i) => (
|
||||
<div key={i} className="flex items-center gap-2">
|
||||
<Check className="h-4 w-4 text-emerald-100" />
|
||||
<div
|
||||
key={i}
|
||||
className="animate-fade-in-up flex items-center gap-2"
|
||||
style={{ animationDelay: `${800 + i * 100}ms` }}
|
||||
>
|
||||
<Check
|
||||
className="h-4 w-4 animate-bounce text-emerald-100"
|
||||
style={{ animationDelay: `${1000 + i * 150}ms` }}
|
||||
/>
|
||||
<span className="text-center">{text}</span>
|
||||
</div>
|
||||
))}
|
||||
@@ -146,10 +182,10 @@ export default function HomePage() {
|
||||
|
||||
<div className="grid gap-6 sm:gap-8 md:grid-cols-2 lg:grid-cols-3">
|
||||
{/* Feature 1 */}
|
||||
<Card className="card-floating group">
|
||||
<Card className="card-floating interactive-card group animate-fade-in-up animate-glow-pulse transform transition-all duration-500 hover:scale-105 hover:shadow-2xl">
|
||||
<CardContent className="p-6 sm:p-8">
|
||||
<div className="icon-bg-brand mb-4">
|
||||
<Rocket className="h-6 w-6" />
|
||||
<div className="icon-bg-brand hover:animate-wiggle mb-4 animate-bounce">
|
||||
<Rocket className="h-6 w-6 transition-all group-hover:scale-125 group-hover:rotate-12" />
|
||||
</div>
|
||||
<h3 className="mb-3 text-xl font-bold text-slate-900 dark:text-slate-100">
|
||||
Quick Setup
|
||||
@@ -176,10 +212,10 @@ export default function HomePage() {
|
||||
</Card>
|
||||
|
||||
{/* Feature 2 */}
|
||||
<Card className="card-floating group">
|
||||
<Card className="card-floating interactive-card group animate-fade-in-up animation-delay-300 transform transition-all duration-500 hover:scale-105 hover:shadow-2xl">
|
||||
<CardContent className="p-6 sm:p-8">
|
||||
<div className="icon-bg-blue mb-4">
|
||||
<BarChart3 className="h-6 w-6" />
|
||||
<div className="icon-bg-blue mb-4 animate-pulse">
|
||||
<BarChart3 className="h-6 w-6 transition-transform group-hover:scale-110" />
|
||||
</div>
|
||||
<h3 className="mb-3 text-xl font-bold text-slate-900 dark:text-slate-100">
|
||||
Payment Tracking
|
||||
@@ -205,10 +241,10 @@ export default function HomePage() {
|
||||
</Card>
|
||||
|
||||
{/* Feature 3 */}
|
||||
<Card className="card-floating group">
|
||||
<Card className="card-floating interactive-card group animate-fade-in-up animation-delay-500 transform transition-all duration-500 hover:scale-105 hover:shadow-2xl">
|
||||
<CardContent className="p-6 sm:p-8">
|
||||
<div className="icon-bg-purple mb-4">
|
||||
<Globe className="h-6 w-6" />
|
||||
<div className="icon-bg-purple animate-float mb-4">
|
||||
<Shield className="h-6 w-6 transition-all group-hover:scale-110 group-hover:rotate-12" />
|
||||
</div>
|
||||
<h3 className="mb-3 text-xl font-bold text-slate-900 dark:text-slate-100">
|
||||
Professional Features
|
||||
@@ -255,13 +291,15 @@ export default function HomePage() {
|
||||
</div>
|
||||
|
||||
<div className="mx-auto max-w-md">
|
||||
<Card className="relative border-2 border-emerald-500 bg-white/90 shadow-2xl backdrop-blur-sm dark:border-emerald-400 dark:bg-slate-800/90">
|
||||
<Card className="animate-fade-in-up animate-glow-pulse interactive-card hover:shadow-3xl relative transform border-2 border-emerald-500 bg-white/90 shadow-2xl backdrop-blur-sm transition-all duration-500 hover:scale-105 dark:border-emerald-400 dark:bg-slate-800/90">
|
||||
<div className="absolute -top-4 left-1/2 -translate-x-1/2">
|
||||
<Badge className="badge-success px-6 py-1">Forever Free</Badge>
|
||||
<Badge className="badge-success animate-pulse px-6 py-1">
|
||||
Forever Free
|
||||
</Badge>
|
||||
</div>
|
||||
<CardContent className="p-6 text-center sm:p-8">
|
||||
<div className="mb-6">
|
||||
<div className="text-brand-gradient mb-2 text-5xl font-bold sm:text-6xl">
|
||||
<div className="animate-text-shimmer mb-2 bg-gradient-to-r from-emerald-500 via-teal-500 to-emerald-500 bg-[length:200%_100%] bg-clip-text text-5xl font-bold text-transparent sm:text-6xl">
|
||||
$0
|
||||
</div>
|
||||
<div className="text-slate-600 dark:text-slate-400">
|
||||
@@ -280,8 +318,15 @@ export default function HomePage() {
|
||||
"Line item details",
|
||||
"Free forever",
|
||||
].map((feature, i) => (
|
||||
<div key={i} className="flex items-center gap-3">
|
||||
<Check className="h-5 w-5 flex-shrink-0 text-emerald-500" />
|
||||
<div
|
||||
key={i}
|
||||
className="animate-fade-in-up flex items-center gap-3"
|
||||
style={{ animationDelay: `${i * 100}ms` }}
|
||||
>
|
||||
<Check
|
||||
className="h-5 w-5 flex-shrink-0 animate-bounce text-emerald-500"
|
||||
style={{ animationDelay: `${200 + i * 100}ms` }}
|
||||
/>
|
||||
<span className="text-slate-700 dark:text-slate-300">
|
||||
{feature}
|
||||
</span>
|
||||
@@ -292,9 +337,9 @@ export default function HomePage() {
|
||||
<Link href="/auth/register">
|
||||
<Button
|
||||
variant="brand"
|
||||
className="w-full py-3 text-base font-semibold sm:text-lg"
|
||||
className="btn-flashy animate-magnetic w-full transform py-3 text-base font-semibold transition-all duration-300 hover:scale-105 hover:shadow-lg sm:text-lg"
|
||||
>
|
||||
Get Started
|
||||
Get Started ✨
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
@@ -316,7 +361,9 @@ export default function HomePage() {
|
||||
<div className="mb-12 text-center sm:mb-16">
|
||||
<h2 className="mb-4 text-3xl font-bold tracking-tight text-slate-900 sm:text-4xl lg:text-5xl dark:text-slate-100">
|
||||
Why choose
|
||||
<span className="text-brand-gradient block">BeenVoice</span>
|
||||
<span className="animate-text-shimmer neon-glow animate-glitch block bg-gradient-to-r from-teal-500 via-emerald-600 to-teal-500 bg-[length:200%_100%] bg-clip-text text-transparent">
|
||||
BeenVoice
|
||||
</span>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
@@ -381,10 +428,10 @@ export default function HomePage() {
|
||||
<Button
|
||||
size="lg"
|
||||
variant="secondary"
|
||||
className="btn-brand-secondary group w-full px-6 py-3 text-base font-semibold shadow-xl transition-colors duration-300 sm:w-auto sm:px-8 sm:py-4 sm:text-lg"
|
||||
className="btn-brand-secondary btn-flashy group animate-glow-pulse w-full transform px-6 py-3 text-base font-semibold shadow-xl transition-all duration-300 hover:scale-105 hover:shadow-2xl sm:w-auto sm:px-8 sm:py-4 sm:text-lg"
|
||||
>
|
||||
Start Free Today
|
||||
<Rocket className="ml-2 h-4 w-4 transition-transform group-hover:translate-x-1 sm:h-5 sm:w-5" />
|
||||
<Rocket className="ml-2 h-4 w-4 animate-bounce transition-all group-hover:translate-x-1 group-hover:scale-125 group-hover:rotate-45 sm:h-5 sm:w-5" />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -267,8 +267,8 @@ const styles = StyleSheet.create({
|
||||
|
||||
// Notes section (first page only)
|
||||
notesSection: {
|
||||
marginTop: 20,
|
||||
marginBottom: 20,
|
||||
marginTop: 0,
|
||||
marginBottom: 0,
|
||||
padding: 15,
|
||||
backgroundColor: "#f9fafb",
|
||||
borderRadius: 4,
|
||||
@@ -285,7 +285,7 @@ const styles = StyleSheet.create({
|
||||
notesContent: {
|
||||
fontSize: 10,
|
||||
fontFamily: "Helvetica",
|
||||
color: "#6b7280",
|
||||
color: "#374151",
|
||||
lineHeight: 1.4,
|
||||
},
|
||||
|
||||
@@ -436,16 +436,25 @@ const styles = StyleSheet.create({
|
||||
alignSelf: "flex-start",
|
||||
},
|
||||
|
||||
// Totals section
|
||||
totalsSection: {
|
||||
// Bottom section with notes and totals
|
||||
bottomSection: {
|
||||
marginTop: 20,
|
||||
flexDirection: "row",
|
||||
justifyContent: "flex-end",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "flex-start",
|
||||
},
|
||||
|
||||
notesContainer: {
|
||||
width: 240,
|
||||
},
|
||||
|
||||
totalsContainer: {
|
||||
width: 240,
|
||||
},
|
||||
|
||||
totalsBox: {
|
||||
width: 250,
|
||||
padding: 15,
|
||||
width: "100%",
|
||||
padding: 10,
|
||||
backgroundColor: "#f9fafb",
|
||||
border: "1px solid #e5e7eb",
|
||||
borderRadius: 4,
|
||||
@@ -454,26 +463,27 @@ const styles = StyleSheet.create({
|
||||
totalRow: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
marginBottom: 6,
|
||||
marginBottom: 4,
|
||||
paddingVertical: 1,
|
||||
},
|
||||
|
||||
totalLabel: {
|
||||
fontSize: 11,
|
||||
color: "#6b7280",
|
||||
fontSize: 12,
|
||||
color: "#475569",
|
||||
fontFamily: "Helvetica",
|
||||
},
|
||||
|
||||
totalAmount: {
|
||||
fontSize: 10,
|
||||
fontSize: 12,
|
||||
fontFamily: "Courier-Bold",
|
||||
color: "#111827",
|
||||
color: "#1e293b",
|
||||
},
|
||||
|
||||
finalTotalRow: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
marginTop: 8,
|
||||
paddingTop: 8,
|
||||
borderTop: "2px solid #10b981",
|
||||
marginTop: 6,
|
||||
paddingTop: 6,
|
||||
},
|
||||
|
||||
finalTotalLabel: {
|
||||
@@ -491,7 +501,7 @@ const styles = StyleSheet.create({
|
||||
itemCount: {
|
||||
fontSize: 9,
|
||||
fontFamily: "Helvetica",
|
||||
color: "#6b7280",
|
||||
color: "#64748b",
|
||||
textAlign: "center",
|
||||
marginTop: 6,
|
||||
fontStyle: "italic",
|
||||
@@ -631,10 +641,10 @@ function calculateItemsForPage(
|
||||
|
||||
if (hasNotes) {
|
||||
// Last page needs space for totals and notes
|
||||
availableHeight -= 120; // Totals + notes space
|
||||
availableHeight -= 100; // Totals + notes space (reduced)
|
||||
} else {
|
||||
// Regular page just needs totals space
|
||||
availableHeight -= 80; // Totals space only
|
||||
availableHeight -= 65; // Totals space only (reduced)
|
||||
}
|
||||
|
||||
// Table header takes space
|
||||
@@ -683,10 +693,10 @@ function calculateItemsPerPage(
|
||||
|
||||
if (hasNotes) {
|
||||
// Last page needs space for totals and notes
|
||||
availableHeight -= 120; // Totals + notes space
|
||||
availableHeight -= 100; // Totals + notes space (reduced)
|
||||
} else {
|
||||
// Regular page just needs totals space
|
||||
availableHeight -= 80; // Totals space only
|
||||
availableHeight -= 65; // Totals space only (reduced)
|
||||
}
|
||||
|
||||
// Table header takes space
|
||||
@@ -892,9 +902,11 @@ const NotesSection: React.FC<{ invoice: InvoiceData }> = ({ invoice }) => {
|
||||
if (!invoice.notes) return null;
|
||||
|
||||
return (
|
||||
<View style={styles.notesSection}>
|
||||
<Text style={styles.notesTitle}>Notes:</Text>
|
||||
<Text style={styles.notesContent}>{invoice.notes}</Text>
|
||||
<View style={styles.notesContainer}>
|
||||
<View style={styles.notesSection}>
|
||||
<Text style={styles.notesTitle}>NOTES</Text>
|
||||
<Text style={styles.notesContent}>{invoice.notes}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
@@ -919,7 +931,7 @@ const Footer: React.FC = () => (
|
||||
</View>
|
||||
);
|
||||
|
||||
// Totals section component
|
||||
// Enhanced totals section component
|
||||
const TotalsSection: React.FC<{
|
||||
invoice: InvoiceData;
|
||||
items: Array<NonNullable<InvoiceData["items"]>[0]>;
|
||||
@@ -928,8 +940,22 @@ const TotalsSection: React.FC<{
|
||||
const taxAmount = (subtotal * invoice.taxRate) / 100;
|
||||
|
||||
return (
|
||||
<View style={styles.totalsSection}>
|
||||
<View style={styles.totalsContainer}>
|
||||
<View style={styles.totalsBox}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 12,
|
||||
fontFamily: "Helvetica-Bold",
|
||||
color: "#334155",
|
||||
textAlign: "center",
|
||||
marginBottom: 6,
|
||||
paddingBottom: 4,
|
||||
borderBottom: "1px solid #e2e8f0",
|
||||
}}
|
||||
>
|
||||
INVOICE SUMMARY
|
||||
</Text>
|
||||
|
||||
<View style={styles.totalRow}>
|
||||
<Text style={styles.totalLabel}>Subtotal:</Text>
|
||||
<Text style={styles.totalAmount}>{formatCurrency(subtotal)}</Text>
|
||||
@@ -943,14 +969,14 @@ const TotalsSection: React.FC<{
|
||||
)}
|
||||
|
||||
<View style={styles.finalTotalRow}>
|
||||
<Text style={styles.finalTotalLabel}>Total:</Text>
|
||||
<Text style={styles.finalTotalLabel}>TOTAL:</Text>
|
||||
<Text style={styles.finalTotalAmount}>
|
||||
{formatCurrency(invoice.totalAmount)}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<Text style={styles.itemCount}>
|
||||
{items.length} item{items.length !== 1 ? "s" : ""}
|
||||
{items.length} line item{items.length !== 1 ? "s" : ""}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
@@ -1020,11 +1046,13 @@ const InvoicePDF: React.FC<{ invoice: InvoiceData }> = ({ invoice }) => {
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* Totals (only on last page) */}
|
||||
{isLastPage && <TotalsSection invoice={invoice} items={items} />}
|
||||
|
||||
{/* Notes (only on last page) */}
|
||||
{isLastPage && <NotesSection invoice={invoice} />}
|
||||
{/* Bottom section with notes and totals (only on last page) */}
|
||||
{isLastPage && (
|
||||
<View style={styles.bottomSection}>
|
||||
{invoice.notes && <NotesSection invoice={invoice} />}
|
||||
<TotalsSection invoice={invoice} items={items} />
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* Footer */}
|
||||
<Footer />
|
||||
|
||||
@@ -49,6 +49,383 @@
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
}
|
||||
|
||||
/* Flashy Animations */
|
||||
@keyframes fade-in-up {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes text-shimmer {
|
||||
0% {
|
||||
background-position: -200% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: 200% 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes float-slow {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0px) rotate(0deg);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-15px) rotate(5deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes float-delayed {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0px) scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-10px) scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-fade-in-up {
|
||||
animation: fade-in-up 0.8s ease-out forwards;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.animate-text-shimmer {
|
||||
animation: text-shimmer 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.animate-float {
|
||||
animation: float 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.animate-float-slow {
|
||||
animation: float-slow 4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.animate-float-delayed {
|
||||
animation: float-delayed 5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.animation-delay-300 {
|
||||
animation-delay: 300ms;
|
||||
}
|
||||
|
||||
.animation-delay-500 {
|
||||
animation-delay: 500ms;
|
||||
}
|
||||
|
||||
.animation-delay-700 {
|
||||
animation-delay: 700ms;
|
||||
}
|
||||
|
||||
/* Particle Effects */
|
||||
@keyframes particles {
|
||||
0% {
|
||||
transform: translateY(0) rotate(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(-100vh) rotate(360deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes glow-pulse {
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: 0 0 20px rgba(16, 185, 129, 0.3);
|
||||
}
|
||||
50% {
|
||||
box-shadow:
|
||||
0 0 40px rgba(16, 185, 129, 0.6),
|
||||
0 0 60px rgba(16, 185, 129, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rainbow {
|
||||
0% {
|
||||
filter: hue-rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
filter: hue-rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes wiggle {
|
||||
0%,
|
||||
7%,
|
||||
14%,
|
||||
21%,
|
||||
28%,
|
||||
35%,
|
||||
42%,
|
||||
49%,
|
||||
56%,
|
||||
63%,
|
||||
70%,
|
||||
77%,
|
||||
84%,
|
||||
91%,
|
||||
98%,
|
||||
100% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
3.5%,
|
||||
10.5%,
|
||||
17.5%,
|
||||
24.5%,
|
||||
31.5%,
|
||||
38.5%,
|
||||
45.5%,
|
||||
52.5%,
|
||||
59.5%,
|
||||
66.5%,
|
||||
73.5%,
|
||||
80.5%,
|
||||
87.5%,
|
||||
94.5% {
|
||||
transform: rotate(2deg);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-particles {
|
||||
animation: particles 4s linear infinite;
|
||||
}
|
||||
|
||||
.animate-glow-pulse {
|
||||
animation: glow-pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.animate-rainbow {
|
||||
animation: rainbow 3s linear infinite;
|
||||
}
|
||||
|
||||
.animate-wiggle {
|
||||
animation: wiggle 1s ease-in-out;
|
||||
}
|
||||
|
||||
/* Particle Container */
|
||||
.particles-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.particle {
|
||||
position: absolute;
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
border-radius: 50%;
|
||||
animation: particles 4s linear infinite;
|
||||
}
|
||||
|
||||
.particle:nth-child(1) {
|
||||
left: 10%;
|
||||
animation-delay: 0s;
|
||||
}
|
||||
.particle:nth-child(2) {
|
||||
left: 20%;
|
||||
animation-delay: 0.5s;
|
||||
}
|
||||
.particle:nth-child(3) {
|
||||
left: 30%;
|
||||
animation-delay: 1s;
|
||||
}
|
||||
.particle:nth-child(4) {
|
||||
left: 40%;
|
||||
animation-delay: 1.5s;
|
||||
}
|
||||
.particle:nth-child(5) {
|
||||
left: 50%;
|
||||
animation-delay: 2s;
|
||||
}
|
||||
.particle:nth-child(6) {
|
||||
left: 60%;
|
||||
animation-delay: 2.5s;
|
||||
}
|
||||
.particle:nth-child(7) {
|
||||
left: 70%;
|
||||
animation-delay: 3s;
|
||||
}
|
||||
.particle:nth-child(8) {
|
||||
left: 80%;
|
||||
animation-delay: 3.5s;
|
||||
}
|
||||
.particle:nth-child(9) {
|
||||
left: 90%;
|
||||
animation-delay: 4s;
|
||||
}
|
||||
|
||||
/* Enhanced Button Effects */
|
||||
.btn-flashy {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-flashy:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.btn-flashy::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
rgba(255, 255, 255, 0.3),
|
||||
transparent
|
||||
);
|
||||
transition: left 0.5s;
|
||||
}
|
||||
|
||||
.btn-flashy:hover::before {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
/* Mouse Interaction Effects */
|
||||
@keyframes confetti {
|
||||
0% {
|
||||
transform: translateY(0) rotate(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(-200px) rotate(720deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sparkle {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(0) rotate(0deg);
|
||||
opacity: 0;
|
||||
}
|
||||
50% {
|
||||
transform: scale(1) rotate(180deg);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes magnetic-pull {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-confetti {
|
||||
animation: confetti 1s ease-out forwards;
|
||||
}
|
||||
|
||||
.animate-sparkle {
|
||||
animation: sparkle 0.8s ease-in-out;
|
||||
}
|
||||
|
||||
.animate-magnetic {
|
||||
animation: magnetic-pull 0.3s ease-out;
|
||||
}
|
||||
|
||||
/* Cursor Trail Effect */
|
||||
.cursor-trail {
|
||||
position: fixed;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: radial-gradient(
|
||||
circle,
|
||||
rgba(16, 185, 129, 0.8) 0%,
|
||||
transparent 70%
|
||||
);
|
||||
border-radius: 50%;
|
||||
pointer-events: none;
|
||||
z-index: 9999;
|
||||
animation: sparkle 0.6s ease-out forwards;
|
||||
}
|
||||
|
||||
/* Interactive Card Effects */
|
||||
.interactive-card {
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.interactive-card:hover {
|
||||
transform: translateY(-8px) rotateX(5deg);
|
||||
box-shadow:
|
||||
0 20px 40px rgba(0, 0, 0, 0.1),
|
||||
0 0 20px rgba(16, 185, 129, 0.2);
|
||||
}
|
||||
|
||||
/* Glitch Effect */
|
||||
@keyframes glitch {
|
||||
0%,
|
||||
100% {
|
||||
transform: translate(0);
|
||||
}
|
||||
20% {
|
||||
transform: translate(-2px, 2px);
|
||||
}
|
||||
40% {
|
||||
transform: translate(-2px, -2px);
|
||||
}
|
||||
60% {
|
||||
transform: translate(2px, 2px);
|
||||
}
|
||||
80% {
|
||||
transform: translate(2px, -2px);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-glitch:hover {
|
||||
animation: glitch 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
/* Neon Glow Effect */
|
||||
.neon-glow {
|
||||
text-shadow:
|
||||
0 0 5px currentColor,
|
||||
0 0 10px currentColor,
|
||||
0 0 15px currentColor,
|
||||
0 0 20px currentColor;
|
||||
}
|
||||
|
||||
.neon-glow:hover {
|
||||
text-shadow:
|
||||
0 0 10px currentColor,
|
||||
0 0 20px currentColor,
|
||||
0 0 30px currentColor,
|
||||
0 0 40px currentColor;
|
||||
}
|
||||
|
||||
:root {
|
||||
--radius: 0.625rem;
|
||||
--background: oklch(0.99 0.003 164.25);
|
||||
|
||||
Reference in New Issue
Block a user