OpenClaw + ClawTeam + Superpowers Git Initialization
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
'use client';
|
||||
|
||||
import { GraduationCapIcon, AwardIcon, LanguagesIcon, MapPinIcon, MailIcon, PhoneIcon } from '@/components/icons/TetIcons';
|
||||
import ScrollReveal from '@/components/animations/ScrollReveal';
|
||||
|
||||
export default function AboutPage() {
|
||||
return (
|
||||
<main className="min-h-screen py-20 px-4 sm:px-6 lg:px-8 bg-[var(--tet-cream)]">
|
||||
<div className="max-w-6xl mx-auto">
|
||||
{/* Page Header */}
|
||||
<ScrollReveal variant="fadeInUp">
|
||||
<div className="text-center mb-16">
|
||||
<h1 className="text-5xl font-bold text-[var(--tet-red)] mb-4">About Me</h1>
|
||||
<div className="h-1 w-32 bg-[var(--tet-gold)] mx-auto rounded-full" />
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-12 items-start">
|
||||
{/* Avatar Section */}
|
||||
<ScrollReveal variant="fadeInUp" delay={0.1}>
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="relative w-80 h-80 rounded-full overflow-hidden border-8 border-[var(--tet-gold)] shadow-2xl mb-6 bg-gradient-to-br from-[var(--tet-red)] to-[var(--tet-gold)] flex items-center justify-center">
|
||||
<span className="text-6xl font-bold text-white">TV</span>
|
||||
</div>
|
||||
|
||||
{/* Quick contact */}
|
||||
<div className="space-y-3 w-full max-w-md">
|
||||
<div className="flex items-center space-x-3 text-gray-700">
|
||||
<MapPinIcon className="w-5 h-5 text-[var(--tet-red)]" />
|
||||
<span>Ho Chi Minh City, Vietnam</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-3 text-gray-700">
|
||||
<MailIcon className="w-5 h-5 text-[var(--tet-red)]" />
|
||||
<a href="mailto:nntrivi2001@gmail.com" className="hover:text-[var(--tet-red)] transition">
|
||||
nntrivi2001@gmail.com
|
||||
</a>
|
||||
</div>
|
||||
<div className="flex items-center space-x-3 text-gray-700">
|
||||
<PhoneIcon className="w-5 h-5 text-[var(--tet-red)]" />
|
||||
<span>090 321 5095</span>
|
||||
</div>
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
|
||||
{/* Bio Content */}
|
||||
<ScrollReveal variant="fadeInUp" delay={0.2}>
|
||||
<div className="space-y-8">
|
||||
{/* Introduction */}
|
||||
<section className="bg-white p-8 rounded-2xl border-2 border-[var(--tet-red)]/20 shadow-lg">
|
||||
<h2 className="text-2xl font-bold text-[var(--tet-red)] mb-4">Who I Am</h2>
|
||||
<p className="text-gray-700 leading-relaxed mb-4">
|
||||
I'm <strong>Nguyễn Ngọc Trí Vĩ</strong> (Thomas), an AI Engineer with a passion for building intelligent systems
|
||||
that solve real-world problems. I graduated as <span className="text-[var(--tet-gold)] font-semibold">Valedictorian</span> with a GPA of 3.74/4.0
|
||||
from Ho Chi Minh City University of Industry and Trade, majoring in Data Analytics & AI.
|
||||
</p>
|
||||
<p className="text-gray-700 leading-relaxed">
|
||||
My journey spans from computer vision in manufacturing to applied AI research and workflow automation.
|
||||
I believe in the power of AI to transform businesses and improve lives, and I'm committed to pushing
|
||||
the boundaries of what's possible with technology.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Education */}
|
||||
<section className="bg-white p-8 rounded-2xl border-2 border-[var(--tet-red)]/20 shadow-lg">
|
||||
<div className="flex items-center space-x-3 mb-4">
|
||||
<GraduationCapIcon className="w-8 h-8 text-[var(--tet-red)]" />
|
||||
<h2 className="text-2xl font-bold text-[var(--tet-red)]">Education</h2>
|
||||
</div>
|
||||
|
||||
<div className="border-l-4 border-[var(--tet-gold)] pl-6 py-2">
|
||||
<h3 className="text-xl font-semibold text-gray-800">
|
||||
Engineer in Data Analytics & AI
|
||||
</h3>
|
||||
<p className="text-[var(--tet-red)] font-medium">Ho Chi Minh City University of Industry and Trade</p>
|
||||
<p className="text-gray-600">Oct 2020 – Oct 2024</p>
|
||||
<div className="mt-3 flex flex-wrap gap-2">
|
||||
<span className="px-3 py-1 bg-[var(--tet-red)]/10 text-[var(--tet-red)] rounded-full text-sm font-medium">
|
||||
Valedictorian 🎓
|
||||
</span>
|
||||
<span className="px-3 py-1 bg-[var(--tet-gold)]/20 text-amber-700 rounded-full text-sm font-medium">
|
||||
GPA: 3.74 / 4.0
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Awards */}
|
||||
<div className="mt-6">
|
||||
<h4 className="font-semibold text-gray-800 mb-3">Awards & Achievements</h4>
|
||||
<ul className="space-y-2">
|
||||
{[
|
||||
"🥈 2nd Place – Essential IT Products Competition (2024)",
|
||||
"🥉 Consolation Prize – TOFAS (2023)",
|
||||
"🏆 Clean Code Award – Finding Talents & Innovative IT (2022)",
|
||||
"📜 Multiple scholarships (2020–2024)",
|
||||
].map((award, idx) => (
|
||||
<li key={idx} className="flex items-start space-x-2 text-gray-700">
|
||||
<span className="text-[var(--tet-gold)]">{award}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Skills & Languages */}
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
<section className="bg-white p-6 rounded-2xl border-2 border-[var(--tet-red)]/20 shadow-lg">
|
||||
<h3 className="text-xl font-bold text-[var(--tet-red)] mb-4">Skills</h3>
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
<p className="font-semibold text-gray-800 mb-2">Programming & Tools</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{['Python', 'C++', 'HTML/CSS', 'JavaScript', 'PineScript', 'n8n', 'Telegram Bots'].map(skill => (
|
||||
<span key={skill} className="px-3 py-1 bg-gray-100 text-gray-700 rounded-full text-sm">
|
||||
{skill}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-semibold text-gray-800 mb-2">AI / ML</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{['TensorFlow', 'PyTorch', 'Scikit-learn', 'OpenCV'].map(skill => (
|
||||
<span key={skill} className="px-3 py-1 bg-gray-100 text-gray-700 rounded-full text-sm">
|
||||
{skill}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-semibold text-gray-800 mb-2">Data & Cloud</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{['SQL Server', 'Supabase', 'Firebase', 'MongoDB'].map(skill => (
|
||||
<span key={skill} className="px-3 py-1 bg-gray-100 text-gray-700 rounded-full text-sm">
|
||||
{skill}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="bg-white p-6 rounded-2xl border-2 border-[var(--tet-red)]/20 shadow-lg">
|
||||
<div className="flex items-center space-x-3 mb-4">
|
||||
<LanguagesIcon className="w-6 h-6 text-[var(--tet-red)]" />
|
||||
<h3 className="text-xl font-bold text-[var(--tet-red)]">Languages</h3>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<div className="flex justify-between mb-1">
|
||||
<span className="font-medium text-gray-800">Vietnamese</span>
|
||||
<span className="text-sm text-gray-600">Native</span>
|
||||
</div>
|
||||
<div className="h-2 bg-gray-200 rounded-full">
|
||||
<div className="h-2 bg-[var(--tet-red)] rounded-full" style={{ width: '100%' }} />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex justify-between mb-1">
|
||||
<span className="font-medium text-gray-800">English</span>
|
||||
<span className="text-sm text-gray-600">Professional</span>
|
||||
</div>
|
||||
<div className="h-2 bg-gray-200 rounded-full">
|
||||
<div className="h-2 bg-[var(--tet-gold)] rounded-full" style={{ width: '85%' }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
'use client';
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
import { MailIcon, PhoneIcon, MapPinIcon, SendIcon, LinkedInIcon, GithubIcon, ArrowRightIcon } from '@/components/icons/TetIcons';
|
||||
import { useState } from 'react';
|
||||
import ScrollReveal from '@/components/animations/ScrollReveal';
|
||||
|
||||
export default function ContactPage() {
|
||||
const [formData, setFormData] = useState({
|
||||
name: '',
|
||||
email: '',
|
||||
subject: '',
|
||||
message: '',
|
||||
});
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [submitStatus, setSubmitStatus] = useState<'idle' | 'success' | 'error'>('idle');
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setIsSubmitting(true);
|
||||
|
||||
// Simulate form submission (in production, connect to backend)
|
||||
await new Promise(resolve => setTimeout(resolve, 1500));
|
||||
|
||||
setSubmitStatus('success');
|
||||
setIsSubmitting(false);
|
||||
setFormData({ name: '', email: '', subject: '', message: '' });
|
||||
|
||||
setTimeout(() => setSubmitStatus('idle'), 5000);
|
||||
};
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
[e.target.name]: e.target.value
|
||||
}));
|
||||
};
|
||||
|
||||
return (
|
||||
<main className="min-h-screen py-20 px-4 sm:px-6 lg:px-8 bg-[var(--tet-cream)]">
|
||||
<div className="max-w-6xl mx-auto">
|
||||
{/* Page Header */}
|
||||
<ScrollReveal variant="fadeInUp">
|
||||
<div className="text-center mb-16">
|
||||
<h1 className="text-5xl font-bold text-[var(--tet-red)] mb-4">Get in Touch</h1>
|
||||
<div className="h-1 w-32 bg-[var(--tet-gold)] mx-auto rounded-full mb-4" />
|
||||
<p className="text-lg text-gray-600 max-w-2xl mx-auto">
|
||||
Have a project in mind or want to collaborate? I'd love to hear from you.
|
||||
Don't hesitate to reach out!
|
||||
</p>
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
|
||||
<div className="grid lg:grid-cols-3 gap-12">
|
||||
{/* Contact Information */}
|
||||
<ScrollReveal variant="fadeInUp" delay={0.1} className="lg:col-span-1 space-y-6">
|
||||
<div className="bg-white p-8 rounded-2xl border-2 border-[var(--tet-red)]/20 shadow-lg">
|
||||
<h2 className="text-2xl font-bold text-[var(--tet-red)] mb-6">Contact Info</h2>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-start space-x-4">
|
||||
<div className="p-3 bg-[var(--tet-red)]/10 rounded-xl">
|
||||
<MailIcon className="w-6 h-6 text-[var(--tet-red)]" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-semibold text-gray-800">Email</p>
|
||||
<a
|
||||
href="mailto:nntrivi2001@gmail.com"
|
||||
className="text-gray-600 hover:text-[var(--tet-red)] transition-colors"
|
||||
>
|
||||
nntrivi2001@gmail.com
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start space-x-4">
|
||||
<div className="p-3 bg-[var(--tet-red)]/10 rounded-xl">
|
||||
<PhoneIcon className="w-6 h-6 text-[var(--tet-red)]" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-semibold text-gray-800">Phone</p>
|
||||
<a
|
||||
href="tel:+84903215095"
|
||||
className="text-gray-600 hover:text-[var(--tet-red)] transition-colors"
|
||||
>
|
||||
090 321 5095
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start space-x-4">
|
||||
<div className="p-3 bg-[var(--tet-red)]/10 rounded-xl">
|
||||
<MapPinIcon className="w-6 h-6 text-[var(--tet-red)]" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-semibold text-gray-800">Location</p>
|
||||
<p className="text-gray-600">Ho Chi Minh City, Vietnam</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Social Links */}
|
||||
<div className="mt-8 pt-8 border-t border-gray-200">
|
||||
<h3 className="font-semibold text-gray-800 mb-4">Connect with me</h3>
|
||||
<div className="flex space-x-4">
|
||||
<a
|
||||
href="https://linkedin.com/in/nguyen-ngoc-tri-vi"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="p-3 bg-[var(--tet-red)]/10 rounded-xl hover:bg-[var(--tet-red)]/20 transition-colors group"
|
||||
aria-label="LinkedIn"
|
||||
>
|
||||
<LinkedInIcon className="w-6 h-6 text-[var(--tet-red)] group-hover:scale-110 transition-transform" />
|
||||
</a>
|
||||
<a
|
||||
href="https://nguyenngoctrivi.vercel.app/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="p-3 bg-[var(--tet-gold)]/20 rounded-xl hover:bg-[var(--tet-gold)]/30 transition-colors group"
|
||||
aria-label="Portfolio"
|
||||
>
|
||||
<ArrowRightIcon className="w-6 h-6 text-amber-600 group-hover:scale-110 transition-transform" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Decorative element */}
|
||||
<div className="text-center text-6xl hidden lg:block">🧧</div>
|
||||
</ScrollReveal>
|
||||
|
||||
{/* Contact Form */}
|
||||
<ScrollReveal variant="fadeInUp" delay={0.2} className="lg:col-span-2">
|
||||
<div className="bg-white p-8 rounded-2xl border-2 border-[var(--tet-red)]/20 shadow-lg">
|
||||
<h2 className="text-2xl font-bold text-[var(--tet-red)] mb-6">Send a Message</h2>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<label htmlFor="name" className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Your Name *
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
name="name"
|
||||
required
|
||||
value={formData.name}
|
||||
onChange={handleChange}
|
||||
className="w-full px-4 py-3 rounded-xl border-2 border-gray-200 focus:border-[var(--tet-red)] focus:outline-none transition-colors"
|
||||
placeholder="Nguyễn Văn A"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="email" className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Email Address *
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
name="email"
|
||||
required
|
||||
value={formData.email}
|
||||
onChange={handleChange}
|
||||
className="w-full px-4 py-3 rounded-xl border-2 border-gray-200 focus:border-[var(--tet-red)] focus:outline-none transition-colors"
|
||||
placeholder="example@email.com"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="subject" className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Subject
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="subject"
|
||||
name="subject"
|
||||
value={formData.subject}
|
||||
onChange={handleChange}
|
||||
className="w-full px-4 py-3 rounded-xl border-2 border-gray-200 focus:border-[var(--tet-red)] focus:outline-none transition-colors"
|
||||
placeholder="What's this about?"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="message" className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Message *
|
||||
</label>
|
||||
<textarea
|
||||
id="message"
|
||||
name="message"
|
||||
required
|
||||
rows={6}
|
||||
value={formData.message}
|
||||
onChange={handleChange}
|
||||
className="w-full px-4 py-3 rounded-xl border-2 border-gray-200 focus:border-[var(--tet-red)] focus:outline-none transition-colors resize-none"
|
||||
placeholder="Tell me about your project or opportunity..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-sm text-gray-500">
|
||||
* Required fields
|
||||
</p>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
className="inline-flex items-center gap-2 px-8 py-4 bg-[var(--tet-red)] text-white rounded-full font-semibold hover:bg-[var(--tet-red-dark)] transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed shadow-lg hover:shadow-xl"
|
||||
>
|
||||
{isSubmitting ? (
|
||||
'Sending...'
|
||||
) : (
|
||||
<>
|
||||
Send Message
|
||||
<SendIcon className="w-5 h-5" />
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Success/Error messages */}
|
||||
{submitStatus === 'success' && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="p-4 bg-green-50 border-2 border-green-200 rounded-xl text-green-800"
|
||||
>
|
||||
✅ Your message has been sent successfully! I'll get back to you soon.
|
||||
</motion.div>
|
||||
)}
|
||||
{submitStatus === 'error' && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="p-4 bg-red-50 border-2 border-red-200 rounded-xl text-red-800"
|
||||
>
|
||||
❌ Something went wrong. Please try again or email me directly.
|
||||
</motion.div>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
'use client';
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
import { BriefcaseIcon, CalendarIcon, MapPinIcon } from '@/components/icons/TetIcons';
|
||||
import ScrollReveal from '@/components/animations/ScrollReveal';
|
||||
|
||||
const experiences = [
|
||||
{
|
||||
company: 'SmartGift Solution',
|
||||
role: 'AI Engineer',
|
||||
period: 'Mar 2026 – Present',
|
||||
location: 'Ho Chi Minh City, Vietnam',
|
||||
description: [
|
||||
'Researched and implemented AI-assisted solutions to improve developer team performance',
|
||||
'Explored technologies for business use cases, built POCs, and documented recommendations',
|
||||
],
|
||||
color: 'tet-red',
|
||||
},
|
||||
{
|
||||
company: 'Learning Chain Vietnam',
|
||||
role: 'Applied AI Researcher & Operations Associate',
|
||||
period: 'Jul 2025 – Mar 2026',
|
||||
location: 'Ho Chi Minh City, Vietnam',
|
||||
description: [
|
||||
'Built AI-assisted trading and operations automation systems',
|
||||
'Developed POCs and recommended technologies for business use',
|
||||
'Designed applied AI curricula, workshops, and n8n learning assets',
|
||||
'Supported COO in workflow optimization and process standardization',
|
||||
],
|
||||
color: 'tet-gold',
|
||||
},
|
||||
{
|
||||
company: 'Vườn Đậu – Herbal Soy Milk Brand',
|
||||
role: 'Founder',
|
||||
period: 'Oct 2024 – Apr 2025',
|
||||
location: 'Ho Chi Minh City, Vietnam',
|
||||
description: [
|
||||
'Managed full production and business operations',
|
||||
'Optimized sourcing, production, and inventory systems',
|
||||
'Built pricing strategy and launched direct sales channels',
|
||||
'Achieved strong customer retention (2.51 repeat purchases/customer)',
|
||||
],
|
||||
color: 'tet-red',
|
||||
},
|
||||
{
|
||||
company: 'VSTECH Company Limited',
|
||||
role: 'Computer Vision Engineer',
|
||||
period: 'Aug 2023 – Feb 2025',
|
||||
location: 'Ho Chi Minh City, Vietnam',
|
||||
description: [
|
||||
'Developed nozzle quality inspection system for Japanese factory',
|
||||
'Integrated 3D vision system for Samsung LED measurement (±7% accuracy)',
|
||||
'Built OCR system for package code recognition in industrial environments',
|
||||
],
|
||||
color: 'tet-gold',
|
||||
},
|
||||
];
|
||||
|
||||
export default function ExperiencePage() {
|
||||
return (
|
||||
<main className="min-h-screen py-20 px-4 sm:px-6 lg:px-8 bg-[var(--tet-cream)]">
|
||||
<div className="max-w-5xl mx-auto">
|
||||
{/* Page Header */}
|
||||
<ScrollReveal variant="fadeInUp">
|
||||
<div className="text-center mb-16">
|
||||
<h1 className="text-5xl font-bold text-[var(--tet-red)] mb-4">Experience</h1>
|
||||
<div className="h-1 w-32 bg-[var(--tet-gold)] mx-auto rounded-full" />
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
|
||||
{/* Timeline */}
|
||||
<div className="relative">
|
||||
{/* Central line */}
|
||||
<div className="absolute left-8 md:left-1/2 top-0 bottom-0 w-0.5 bg-gradient-to-b from-[var(--tet-red)] to-[var(--tet-gold)] transform md:-translate-x-1/2" />
|
||||
|
||||
{experiences.map((exp, index) => {
|
||||
const isEven = index % 2 === 0;
|
||||
const Icon = BriefcaseIcon;
|
||||
|
||||
return (
|
||||
<ScrollReveal key={index} variant={isEven ? "slideInLeft" : "slideInRight"} delay={index * 0.15}>
|
||||
<div className={`relative flex items-center mb-16 ${isEven ? 'md:flex-row' : 'md:flex-row-reverse'}`}>
|
||||
{/* Content Card */}
|
||||
<div className={`ml-20 md:ml-0 md:w-5/12 ${isEven ? 'md:pr-12 md:text-right' : 'md:pl-12'} z-10`}>
|
||||
<div className="bg-white p-6 rounded-2xl border-2 border-[var(--tet-red)]/20 shadow-lg hover:shadow-xl transition-shadow duration-300 card-hover">
|
||||
<div className="flex items-center gap-2 mb-2 justify-center md:justify-start">
|
||||
<CalendarIcon className="w-4 h-4 text-[var(--tet-red)]" />
|
||||
<span className="text-sm font-medium text-[var(--tet-red)]">{exp.period}</span>
|
||||
</div>
|
||||
|
||||
<h3 className="text-2xl font-bold text-gray-800 mb-1">{exp.role}</h3>
|
||||
<div className="flex items-center gap-2 mb-3 justify-center md:justify-start">
|
||||
<span className="text-lg font-semibold text-[var(--tet-red)]">{exp.company}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2 mb-4 text-gray-600 text-sm justify-center md:justify-start">
|
||||
<MapPinIcon className="w-4 h-4" />
|
||||
<span>{exp.location}</span>
|
||||
</div>
|
||||
|
||||
<ul className="space-y-2 mb-4">
|
||||
{exp.description.map((item, idx) => (
|
||||
<li key={idx} className={`text-gray-700 ${isEven ? 'md:text-right' : 'md:text-left'}`}>
|
||||
• {item}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<div className="flex justify-center md:justify-start">
|
||||
<span className={`px-3 py-1 rounded-full text-xs font-medium bg-${exp.color === 'tet-red' ? '[var(--tet-red)]/10' : '[var(--tet-gold)]/20'} text-${exp.color === 'tet-red' ? '[var(--tet-red)]' : 'amber-700'}`}>
|
||||
{exp.color === 'tet-red' ? '🔴' : '🟡'} {exp.period.split(' – ')[0]}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Timeline dot */}
|
||||
<div className="absolute left-8 md:left-1/2 transform -translate-x-1/2">
|
||||
<motion.div
|
||||
whileHover={{ scale: 1.3 }}
|
||||
className="w-8 h-8 rounded-full bg-[var(--tet-gold)] border-4 border-[var(--tet-cream)] shadow-lg flex items-center justify-center z-20"
|
||||
>
|
||||
<Icon className="w-4 h-4 text-[var(--tet-dark)]" />
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/* Empty spacer for opposite side */}
|
||||
<div className="hidden md:block md:w-5/12" />
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
@@ -0,0 +1,66 @@
|
||||
:root {
|
||||
/* Tet Theme Colors */
|
||||
--tet-red: #C41E3A;
|
||||
--tet-red-dark: #8B0000;
|
||||
--tet-gold: #FFD700;
|
||||
--tet-gold-light: #FFC107;
|
||||
--tet-cream: #FFF8E7;
|
||||
--tet-dark: #1A1A1A;
|
||||
--tet-red-gradient: linear-gradient(135deg, #C41E3A 0%, #8B0000 100%);
|
||||
--tet-gold-gradient: linear-gradient(135deg, #FFD700 0%, #FFA500 100%);
|
||||
|
||||
--background: var(--tet-cream);
|
||||
--foreground: var(--tet-dark);
|
||||
}
|
||||
|
||||
/* Custom utility classes */
|
||||
.bg-tet-red { background-color: var(--tet-red); }
|
||||
.bg-tet-gold { background-color: var(--tet-gold); }
|
||||
.text-tet-red { color: var(--tet-red); }
|
||||
.text-tet-gold { color: var(--tet-gold); }
|
||||
.border-tet-red { border-color: var(--tet-red); }
|
||||
|
||||
body {
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* Smooth scrolling */
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
/* Custom scrollbar with Tet colors */
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--tet-cream);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--tet-red);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--tet-red-dark);
|
||||
}
|
||||
|
||||
/* Golden glow effect */
|
||||
.text-glow {
|
||||
text-shadow: 0 0 20px rgba(255, 215, 0, 0.5);
|
||||
}
|
||||
|
||||
/* Red card hover effect */
|
||||
.card-hover {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.card-hover:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 30px rgba(196, 30, 58, 0.2);
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
'use client';
|
||||
|
||||
import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import Navigation from "@/components/layout/Navigation";
|
||||
import Footer from "@/components/layout/Footer";
|
||||
import Script from "next/script";
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import FallingPetals from '@/components/animations/FallingPetals';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: "--font-geist-mono",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Trí Vĩ - AI Engineer Portfolio",
|
||||
description: "Portfolio of Nguyễn Ngọc Trí Vĩ - AI Engineer specializing in Computer Vision, Machine Learning, and Applied AI solutions",
|
||||
keywords: ["AI Engineer", "Machine Learning", "Computer Vision", "Portfolio", "Vietnam"],
|
||||
authors: [{ name: "Nguyễn Ngọc Trí Vĩ" }],
|
||||
openGraph: {
|
||||
title: "Trí Vĩ - AI Engineer",
|
||||
description: "Portfolio of an AI Engineer building intelligent systems",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
// Page transition variants
|
||||
const pageVariants = {
|
||||
hidden: { opacity: 0, x: 20 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: {
|
||||
duration: 0.4,
|
||||
ease: [0.25, 0.1, 0.25, 1]
|
||||
}
|
||||
},
|
||||
exit: {
|
||||
opacity: 0,
|
||||
x: -20,
|
||||
transition: {
|
||||
duration: 0.3,
|
||||
ease: [0.25, 0.1, 0.25, 1]
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
const pathname = usePathname();
|
||||
const [isClient, setIsClient] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setIsClient(true);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<html lang="en" className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}>
|
||||
<body className="min-h-full flex flex-col">
|
||||
{/* Tailwind CSS CDN */}
|
||||
<Script
|
||||
src="https://cdn.tailwindcss.com"
|
||||
strategy="beforeInteractive"
|
||||
/>
|
||||
|
||||
<Navigation />
|
||||
<div className="flex-1 pt-16 relative"> {/* Added relative for positioning */}
|
||||
<AnimatePresence mode="wait" initial={false}>
|
||||
{isClient && (
|
||||
<motion.div
|
||||
key={pathname}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
exit="exit"
|
||||
variants={pageVariants}
|
||||
className="min-h-screen"
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
{/* Falling petals overlay - appears on all pages */}
|
||||
<FallingPetals count={40} />
|
||||
</div>
|
||||
<Footer />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
'use client';
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
import { ArrowRightIcon, SparklesIcon, Code2Icon, BrainIcon } from '@/components/icons/TetIcons';
|
||||
import Link from 'next/link';
|
||||
import ScrollReveal from '@/components/animations/ScrollReveal';
|
||||
|
||||
const containerVariants = {
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
staggerChildren: 0.2,
|
||||
delayChildren: 0.3,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const itemVariants = {
|
||||
hidden: { opacity: 0, y: 30 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: { duration: 0.6 },
|
||||
},
|
||||
};
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<main className="relative min-h-screen flex items-center justify-center overflow-hidden">
|
||||
{/* Decorative border patterns */}
|
||||
<div className="absolute inset-0 pointer-events-none">
|
||||
{/* Top border - traditional cloud pattern */}
|
||||
<div className="absolute top-0 left-0 right-0 h-4 bg-gradient-to-r from-[var(--tet-red)] via-[var(--tet-gold)] to-[var(--tet-red)]" />
|
||||
|
||||
{/* Corner decorations */}
|
||||
<div className="absolute top-4 left-4 w-16 h-16 border-t-4 border-l-4 border-[var(--tet-red)]" />
|
||||
<div className="absolute top-4 right-4 w-16 h-16 border-t-4 border-r-4 border-[var(--tet-red)]" />
|
||||
<div className="absolute bottom-4 left-4 w-16 h-16 border-b-4 border-l-4 border-[var(--tet-red)]" />
|
||||
<div className="absolute bottom-4 right-4 w-16 h-16 border-b-4 border-r-4 border-[var(--tet-red)]" />
|
||||
</div>
|
||||
|
||||
{/* Main content */}
|
||||
<motion.div
|
||||
variants={containerVariants}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
className="relative z-10 max-w-6xl mx-auto px-6 py-24 text-center"
|
||||
>
|
||||
{/* Greeting in Traditional Vietnamese style */}
|
||||
<motion.div variants={itemVariants} className="mb-6">
|
||||
<span className="inline-block px-6 py-2 bg-[var(--tet-red)] text-white rounded-full text-sm font-semibold tracking-wider uppercase">
|
||||
🎊 Chúc Mừng Năm Mới 🎊
|
||||
</span>
|
||||
</motion.div>
|
||||
|
||||
{/* Test agent completion badge */}
|
||||
<motion.div variants={itemVariants} className="mb-4">
|
||||
<span className="inline-flex items-center gap-2 px-4 py-1.5 bg-green-100 text-green-800 rounded-full text-xs font-medium border border-green-200">
|
||||
<svg className="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
|
||||
</svg>
|
||||
Test Agent Task Completed
|
||||
</span>
|
||||
</motion.div>
|
||||
|
||||
{/* Name with golden glow */}
|
||||
<motion.h1
|
||||
variants={itemVariants}
|
||||
className="text-5xl md:text-8xl font-bold mb-4 bg-[var(--tet-gold-gradient)] bg-clip-text text-transparent text-glow"
|
||||
>
|
||||
Nguyễn Ngọc Trí Vĩ
|
||||
</motion.h1>
|
||||
|
||||
{/* Role with red accent */}
|
||||
<motion.h2
|
||||
variants={itemVariants}
|
||||
className="text-2xl md:text-4xl font-semibold mb-8 text-[var(--tet-red)]"
|
||||
>
|
||||
AI Engineer
|
||||
</motion.h2>
|
||||
|
||||
{/* Bio */}
|
||||
<motion.p
|
||||
variants={itemVariants}
|
||||
className="text-lg md:text-xl max-w-3xl mx-auto mb-12 leading-relaxed text-gray-700"
|
||||
>
|
||||
Passionate about building intelligent systems that bridge the gap between AI and real-world business problems.
|
||||
Currently researching AI-assisted solutions at <span className="font-bold text-[var(--tet-red)]">SmartGift Solution</span>.
|
||||
</motion.p>
|
||||
|
||||
{/* Quick stats */}
|
||||
<motion.div
|
||||
variants={itemVariants}
|
||||
className="grid grid-cols-2 md:grid-cols-4 gap-6 mb-12 max-w-4xl mx-auto"
|
||||
>
|
||||
{[
|
||||
{ icon: BrainIcon, label: 'AI/ML', value: 'Expert' },
|
||||
{ icon: Code2Icon, label: 'Experience', value: '3+ Years' },
|
||||
{ icon: SparklesIcon, label: 'Projects', value: '20+' },
|
||||
{ icon: () => (
|
||||
<span className="text-2xl">🎓</span>
|
||||
), label: 'Education', value: 'Valedictorian' },
|
||||
].map((stat, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
className="flex flex-col items-center p-6 bg-white/80 backdrop-blur-sm rounded-2xl border-2 border-[var(--tet-red)]/20 shadow-lg card-hover"
|
||||
>
|
||||
<stat.icon className="w-8 h-8 text-[var(--tet-red)] mb-2" />
|
||||
<span className="text-3xl font-bold text-[var(--tet-gold)]">{stat.value}</span>
|
||||
<span className="text-sm text-gray-600 mt-1">{stat.label}</span>
|
||||
</motion.div>
|
||||
))}
|
||||
</motion.div>
|
||||
|
||||
{/* CTA buttons */}
|
||||
<motion.div
|
||||
variants={itemVariants}
|
||||
className="flex flex-col sm:flex-row gap-4 justify-center"
|
||||
>
|
||||
<Link
|
||||
href="/about"
|
||||
className="group inline-flex items-center justify-center px-8 py-4 bg-[var(--tet-red)] text-white rounded-full font-semibold text-lg hover:bg-[var(--tet-red-dark)] transition-all duration-300 shadow-lg hover:shadow-xl hover:scale-105"
|
||||
>
|
||||
Learn More
|
||||
<ArrowRightIcon className="ml-2 w-5 h-5 group-hover:translate-x-1 transition-transform" />
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
href="/projects"
|
||||
className="inline-flex items-center justify-center px-8 py-4 border-2 border-[var(--tet-red)] text-[var(--tet-red)] rounded-full font-semibold text-lg hover:bg-[var(--tet-red)] hover:text-white transition-all duration-300"
|
||||
>
|
||||
View Projects
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
href="/contact"
|
||||
className="inline-flex items-center justify-center px-8 py-4 bg-[var(--tet-gold)] text-[var(--tet-dark)] rounded-full font-semibold text-lg hover:bg-[var(--tet-gold-light)] transition-all duration-300"
|
||||
>
|
||||
Get in Touch
|
||||
</Link>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
{/* Floating lantern decoration */}
|
||||
<motion.div
|
||||
animate={{ y: [0, -20, 0] }}
|
||||
transition={{ duration: 3, repeat: Infinity, ease: 'easeInOut' }}
|
||||
className="absolute bottom-10 left-10 text-4xl hidden lg:block"
|
||||
>
|
||||
🏮
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
animate={{ y: [0, -15, 0] }}
|
||||
transition={{ duration: 2.5, repeat: Infinity, ease: 'easeInOut', delay: 0.5 }}
|
||||
className="absolute bottom-10 right-10 text-4xl hidden lg:block"
|
||||
>
|
||||
🧧
|
||||
</motion.div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
'use client';
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
import { ExternalLinkIcon, GithubIcon, FolderOpenIcon, TagIcon } from '@/components/icons/TetIcons';
|
||||
import ScrollReveal from '@/components/animations/ScrollReveal';
|
||||
|
||||
const projects = [
|
||||
return (
|
||||
<main className="min-h-screen py-20 px-4 sm:px-6 lg:px-8 bg-[var(--tet-cream)]">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
{/* Page Header */}
|
||||
<ScrollReveal variant="fadeInUp">
|
||||
<div className="text-center mb-16">
|
||||
<h1 className="text-5xl font-bold text-[var(--tet-red)] mb-4">Projects</h1>
|
||||
<div className="h-1 w-32 bg-[var(--tet-gold)] mx-auto rounded-full mb-4" />
|
||||
<p className="text-lg text-gray-600 max-w-2xl mx-auto">
|
||||
A showcase of AI, computer vision, and automation projects that demonstrate my expertise in applied AI and full-stack development.
|
||||
</p>
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
|
||||
{/* Projects Grid */}
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
{projects.map((project, index) => (
|
||||
<ScrollReveal key={project.id} variant="fadeInUp" delay={index * 0.1}>
|
||||
<motion.div
|
||||
whileHover={{ y: -8 }}
|
||||
className="bg-white rounded-2xl border-2 border-[var(--tet-red)]/20 shadow-lg overflow-hidden card-hover group"
|
||||
>
|
||||
{/* Card Header with decorative pattern */}
|
||||
<div className={`h-3 bg-gradient-to-r from-${project.color === 'tet-red' ? '[var(--tet-red)]' : '[var(--tet-gold)]'} to-${project.color === 'tet-red' ? '[var(--tet-red-dark)]' : '[#FFA500]'}`} />
|
||||
|
||||
<div className="p-6">
|
||||
{/* Icon and year */}
|
||||
<div className="flex justify-between items-start mb-4">
|
||||
<div className={`p-3 rounded-xl bg-${project.color}/10`}>
|
||||
<FolderOpenIcon className={`w-8 h-8 text-${project.color === 'tet-red' ? '[var(--tet-red)]' : '[var(--tet-gold)]'}`} />
|
||||
</div>
|
||||
<span className="text-sm font-medium text-gray-500">{project.year}</span>
|
||||
</div>
|
||||
|
||||
{/* Title */}
|
||||
<h3 className="text-xl font-bold text-gray-800 mb-3 line-clamp-2 min-h-[3.5rem]">
|
||||
{project.title}
|
||||
</h3>
|
||||
|
||||
{/* Description */}
|
||||
<p className="text-gray-600 mb-6 text-sm leading-relaxed line-clamp-3">
|
||||
{project.description}
|
||||
</p>
|
||||
|
||||
{/* Tags */}
|
||||
<div className="flex flex-wrap gap-2 mb-6">
|
||||
{project.tags.map(tag => (
|
||||
<span
|
||||
key={tag}
|
||||
className="inline-flex items-center gap-1 px-3 py-1 bg-gray-100 text-gray-700 rounded-full text-xs"
|
||||
>
|
||||
<TagIcon className="w-3 h-3" />
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Links */}
|
||||
<div className="flex gap-3">
|
||||
<a
|
||||
href={project.link}
|
||||
className="flex-1 inline-flex items-center justify-center gap-2 px-4 py-2 bg-[var(--tet-red)] text-white rounded-lg text-sm font-medium hover:bg-[var(--tet-red-dark)] transition-colors"
|
||||
>
|
||||
<ExternalLinkIcon className="w-4 h-4" />
|
||||
View
|
||||
</a>
|
||||
<a
|
||||
href={project.github}
|
||||
className="inline-flex items-center justify-center gap-2 px-4 py-2 border border-gray-300 text-gray-700 rounded-lg text-sm hover:bg-gray-50 transition-colors"
|
||||
>
|
||||
<GithubIcon className="w-4 h-4" />
|
||||
Code
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</ScrollReveal>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* More projects placeholder */}
|
||||
<ScrollReveal variant="fadeInUp" delay={0.6}>
|
||||
<div className="mt-16 text-center">
|
||||
<p className="text-gray-600 mb-4">
|
||||
Want to see more of my work or discuss a collaboration?
|
||||
</p>
|
||||
<a
|
||||
href="/contact"
|
||||
className="inline-flex items-center gap-2 px-8 py-4 bg-[var(--tet-gold)] text-[var(--tet-dark)] rounded-full font-semibold hover:bg-[var(--tet-gold-light)] transition-all duration-300"
|
||||
>
|
||||
Get in Touch
|
||||
</a>
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user