full upgrade
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { Globe, Server, Wrench, Shield, Gamepad2, Code } from "lucide-react";
|
||||
import { Globe, Server, Wrench, Shield, Gamepad2, Code, Activity, Lightbulb } from "lucide-react";
|
||||
|
||||
// Smooth animation configuration
|
||||
const smoothTransition = {
|
||||
@@ -60,10 +60,11 @@ const About = () => {
|
||||
},
|
||||
];
|
||||
|
||||
const hobbies = [
|
||||
const hobbies: Array<{ icon: typeof Code; text: string }> = [
|
||||
{ icon: Code, text: "Self-Hosting & DevOps" },
|
||||
{ icon: Gamepad2, text: "Gaming" },
|
||||
{ icon: Server, text: "Setting up Game Servers" },
|
||||
{ icon: Activity, text: "Jogging to clear my mind and stay active" },
|
||||
];
|
||||
|
||||
if (!mounted) return null;
|
||||
@@ -113,11 +114,24 @@ const About = () => {
|
||||
experimenting with new tech like game servers or automation
|
||||
workflows with <strong>n8n</strong>.
|
||||
</p>
|
||||
<p className="text-sm italic text-stone-500 bg-stone-50 p-4 rounded-lg border-l-4 border-liquid-mint">
|
||||
💡 Fun fact: Even though I automate a lot, I still use pen and
|
||||
paper for my calendar and notes – it helps me clear my head and
|
||||
stay focused.
|
||||
</p>
|
||||
<motion.div
|
||||
variants={fadeInUp}
|
||||
className="relative overflow-hidden bg-gradient-to-br from-liquid-mint/15 via-liquid-sky/10 to-liquid-lavender/15 border-2 border-liquid-mint/30 rounded-xl p-5 backdrop-blur-sm"
|
||||
>
|
||||
<div className="flex items-start gap-3">
|
||||
<Lightbulb size={20} className="text-stone-600 flex-shrink-0 mt-0.5" />
|
||||
<div>
|
||||
<p className="text-sm font-semibold text-stone-800 mb-1">
|
||||
Fun Fact
|
||||
</p>
|
||||
<p className="text-sm text-stone-700 leading-relaxed">
|
||||
Even though I automate a lot, I still use pen and paper
|
||||
for my calendar and notes – it helps me clear my head and
|
||||
stay focused.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
@@ -209,7 +223,9 @@ const About = () => {
|
||||
? "bg-gradient-to-r from-liquid-mint/10 to-liquid-sky/10 border-liquid-mint/30 hover:border-liquid-mint/50 hover:from-liquid-mint/15 hover:to-liquid-sky/15"
|
||||
: idx === 1
|
||||
? "bg-gradient-to-r from-liquid-coral/10 to-liquid-peach/10 border-liquid-coral/30 hover:border-liquid-coral/50 hover:from-liquid-coral/15 hover:to-liquid-peach/15"
|
||||
: "bg-gradient-to-r from-liquid-lavender/10 to-liquid-pink/10 border-liquid-lavender/30 hover:border-liquid-lavender/50 hover:from-liquid-lavender/15 hover:to-liquid-pink/15"
|
||||
: idx === 2
|
||||
? "bg-gradient-to-r from-liquid-lavender/10 to-liquid-pink/10 border-liquid-lavender/30 hover:border-liquid-lavender/50 hover:from-liquid-lavender/15 hover:to-liquid-pink/15"
|
||||
: "bg-gradient-to-r from-liquid-lime/10 to-liquid-teal/10 border-liquid-lime/30 hover:border-liquid-lime/50 hover:from-liquid-lime/15 hover:to-liquid-teal/15"
|
||||
}`}
|
||||
>
|
||||
<hobby.icon size={20} className="text-stone-600" />
|
||||
@@ -218,19 +234,6 @@ const About = () => {
|
||||
</span>
|
||||
</motion.div>
|
||||
))}
|
||||
<motion.div
|
||||
variants={fadeInUp}
|
||||
whileHover={{
|
||||
x: 8,
|
||||
scale: 1.02,
|
||||
transition: { duration: 0.4, ease: "easeOut" },
|
||||
}}
|
||||
className="p-4 rounded-xl bg-gradient-to-r from-liquid-lime/15 to-liquid-teal/15 border-2 border-liquid-lime/40 hover:border-liquid-lime/60 hover:from-liquid-lime/20 hover:to-liquid-teal/20 transition-all duration-500 ease-out"
|
||||
>
|
||||
<p className="text-sm text-stone-600">
|
||||
🏃 Jogging to clear my mind and stay active
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
@@ -119,7 +119,7 @@ const SoundWaves = () => {
|
||||
);
|
||||
};
|
||||
|
||||
// Running animation
|
||||
// Running animation with smooth wavy motion
|
||||
const RunningAnimation = () => {
|
||||
return (
|
||||
<div className="absolute inset-0 overflow-hidden pointer-events-none">
|
||||
@@ -127,16 +127,34 @@ const RunningAnimation = () => {
|
||||
className="absolute bottom-2 text-4xl"
|
||||
animate={{
|
||||
x: ["-10%", "110%"],
|
||||
y: [0, -10, -5, -12, -3, -10, 0, -8, -2, -10, 0],
|
||||
}}
|
||||
transition={{
|
||||
duration: 3,
|
||||
repeat: Infinity,
|
||||
ease: "linear",
|
||||
x: {
|
||||
duration: 1.2,
|
||||
repeat: Infinity,
|
||||
ease: "linear",
|
||||
},
|
||||
y: {
|
||||
duration: 0.4,
|
||||
repeat: Infinity,
|
||||
ease: [0.25, 0.1, 0.25, 1], // Smooth cubic bezier for wavy effect
|
||||
},
|
||||
}}
|
||||
>
|
||||
🏃
|
||||
</motion.div>
|
||||
<div className="absolute bottom-2 left-0 right-0 h-0.5 bg-liquid-lime/30" />
|
||||
<motion.div
|
||||
className="absolute bottom-2 left-0 right-0 h-0.5 bg-liquid-lime/30"
|
||||
animate={{
|
||||
opacity: [0.3, 0.6, 0.3],
|
||||
}}
|
||||
transition={{
|
||||
duration: 0.4,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -264,7 +282,9 @@ export const ActivityFeed = () => {
|
||||
setData(json);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch activity", e);
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.error("Failed to fetch activity", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
fetchData();
|
||||
@@ -301,7 +321,9 @@ export const ActivityFeed = () => {
|
||||
throw new Error("Chat API failed");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Chat error:", error);
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.error("Chat error:", error);
|
||||
}
|
||||
setChatHistory((prev) => [
|
||||
...prev,
|
||||
{
|
||||
@@ -527,7 +549,7 @@ export const ActivityFeed = () => {
|
||||
<div
|
||||
className={`max-w-[85%] p-3 rounded-2xl text-sm ${
|
||||
msg.role === "user"
|
||||
? "bg-gradient-to-br from-stone-800 to-stone-900 text-white rounded-tr-none shadow-md"
|
||||
? "bg-gradient-to-br from-stone-700 to-stone-600 text-white rounded-tr-none shadow-md"
|
||||
: "bg-gradient-to-br from-white to-stone-50 text-stone-900 shadow-md rounded-tl-none border-2 border-stone-100"
|
||||
}`}
|
||||
>
|
||||
@@ -561,14 +583,14 @@ export const ActivityFeed = () => {
|
||||
onChange={(e) => setChatMessage(e.target.value)}
|
||||
placeholder="Ask me anything..."
|
||||
disabled={isLoading}
|
||||
className="flex-1 bg-white border-2 border-stone-200 rounded-xl px-4 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-liquid-mint focus:border-transparent disabled:opacity-50 transition-all duration-300"
|
||||
className="flex-1 bg-white border-2 border-stone-200 rounded-xl px-4 py-3 text-sm text-stone-900 placeholder:text-stone-400 focus:outline-none focus:ring-2 focus:ring-liquid-mint focus:border-transparent disabled:opacity-50 transition-all duration-300"
|
||||
/>
|
||||
<motion.button
|
||||
type="submit"
|
||||
disabled={isLoading || !chatMessage.trim()}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
className="p-3 bg-gradient-to-br from-stone-900 to-stone-800 text-white rounded-xl hover:from-black hover:to-stone-900 transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed shadow-lg"
|
||||
className="p-3 bg-gradient-to-br from-stone-700 to-stone-600 text-white rounded-xl hover:from-stone-600 hover:to-stone-500 transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed shadow-lg"
|
||||
>
|
||||
<Send size={18} />
|
||||
</motion.button>
|
||||
|
||||
@@ -90,7 +90,9 @@ const Contact = () => {
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error sending email:", error);
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.error("Error sending email:", error);
|
||||
}
|
||||
showEmailError(
|
||||
"Network error. Please check your connection and try again.",
|
||||
);
|
||||
@@ -230,7 +232,7 @@ const Contact = () => {
|
||||
transition={{ duration: 1, ease: [0.25, 0.1, 0.25, 1] }}
|
||||
className="glass-card p-8 rounded-3xl bg-white/50 border border-white/70"
|
||||
>
|
||||
<h3 className="text-2xl font-bold text-stone-800 mb-6">
|
||||
<h3 className="text-2xl font-bold text-gray-800 mb-6">
|
||||
Send Message
|
||||
</h3>
|
||||
|
||||
@@ -404,7 +406,7 @@ const Contact = () => {
|
||||
) : (
|
||||
<>
|
||||
<Send size={20} />
|
||||
<span>Send Message</span>
|
||||
<span className="text-cream">Send Message</span>
|
||||
</>
|
||||
)}
|
||||
</motion.button>
|
||||
|
||||
@@ -58,13 +58,16 @@ const Header = () => {
|
||||
scrolled ? "w-full max-w-5xl" : "w-full max-w-7xl"
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: -20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.2, ease: "easeOut" }}
|
||||
className={`
|
||||
backdrop-blur-xl transition-all duration-500
|
||||
${
|
||||
scrolled
|
||||
? "bg-white/95 border border-stone-300 shadow-[0_8px_30px_rgba(0,0,0,0.12)] rounded-full px-6 py-3"
|
||||
: "bg-white/85 border border-stone-200 shadow-[0_4px_24px_rgba(0,0,0,0.08)] px-4 py-4 rounded-full"
|
||||
? "bg-white/95 border border-stone-200/50 shadow-[0_8px_30px_rgba(0,0,0,0.12)] rounded-full px-6 py-3"
|
||||
: "bg-white/85 border border-stone-200/30 shadow-[0_4px_24px_rgba(0,0,0,0.08)] px-4 py-4 rounded-full"
|
||||
}
|
||||
flex justify-between items-center
|
||||
`}
|
||||
@@ -105,7 +108,16 @@ const Header = () => {
|
||||
}}
|
||||
>
|
||||
{item.name}
|
||||
<span className="absolute -bottom-1 left-0 right-0 h-0.5 bg-gradient-to-r from-liquid-mint to-liquid-lavender transform scale-x-0 group-hover:scale-x-100 transition-transform duration-300 origin-center rounded-full"></span>
|
||||
<motion.span
|
||||
className="absolute -bottom-1 left-0 right-0 h-0.5 bg-gradient-to-r from-liquid-mint to-liquid-lavender rounded-full"
|
||||
initial={{ scaleX: 0, opacity: 0 }}
|
||||
whileHover={{ scaleX: 1, opacity: 1 }}
|
||||
transition={{
|
||||
duration: 0.4,
|
||||
ease: [0.25, 0.1, 0.25, 1],
|
||||
}}
|
||||
style={{ transformOrigin: "left center" }}
|
||||
/>
|
||||
</Link>
|
||||
</motion.div>
|
||||
))}
|
||||
@@ -134,7 +146,7 @@ const Header = () => {
|
||||
>
|
||||
{isOpen ? <X size={24} /> : <Menu size={24} />}
|
||||
</motion.button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<AnimatePresence>
|
||||
|
||||
@@ -226,9 +226,9 @@ const Hero = () => {
|
||||
whileHover={{ scale: 1.03, y: -2 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
transition={{ duration: 0.3, ease: "easeOut" }}
|
||||
className="px-8 py-4 bg-stone-900 text-cream rounded-full font-medium shadow-lg hover:shadow-xl hover:bg-stone-950 transition-all duration-500 flex items-center gap-2"
|
||||
className="px-8 py-4 bg-stone-900 text-cream rounded-full shadow-lg hover:shadow-xl hover:bg-stone-950 transition-all duration-500 flex items-center gap-2"
|
||||
>
|
||||
<span>View My Work</span>
|
||||
<span className="text-cream">View My Work</span>
|
||||
<ArrowDown size={18} />
|
||||
</motion.a>
|
||||
|
||||
|
||||
@@ -68,7 +68,9 @@ const Projects = () => {
|
||||
setProjects(data.projects || []);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading projects:", error);
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.error("Error loading projects:", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
loadProjects();
|
||||
|
||||
Reference in New Issue
Block a user