/* Portfolio Components — Phan Phuoc Thinh */
/* ─── Doodle SVG Decorations ─── */
function DoodleBrackets({ style, color = 'currentColor' }) {
return (
);
}
function DoodleArrow({ style, color = 'currentColor' }) {
return (
);
}
function DoodleCircle({ style, color = 'currentColor', size = 40 }) {
return (
);
}
function DoodleCode({ style, color = 'currentColor' }) {
return (
);
}
function DoodleChart({ style, color = 'currentColor' }) {
return (
);
}
function DoodleStar({ style, color = 'currentColor', size = 24 }) {
return (
);
}
/* ─── Navigation ─── */
function Nav({ activeSection, onNavigate, tweaks }) {
const navItems = [
{ id: 'home', label: 'Home', icon: 'M3 12l9-9 9 9M5 10v10a1 1 0 001 1h3a1 1 0 001-1v-4h4v4a1 1 0 001 1h3a1 1 0 001-1V10' },
{ id: 'about', label: 'About', icon: 'M12 11a4 4 0 100-8 4 4 0 000 8zM4 21v-1a6 6 0 0112 0v1M16 21v-1a6 6 0 016 0v1' },
{ id: 'experience', label: 'Experience', icon: 'M20 7H4a2 2 0 00-2 2v10a2 2 0 002 2h16a2 2 0 002-2V9a2 2 0 00-2-2zM16 7V5a2 2 0 00-2-2h-4a2 2 0 00-2 2v2' },
{ id: 'projects', label: 'Projects', icon: 'M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z' },
{ id: 'contact', label: 'Contact', icon: 'M3 5h18a2 2 0 012 2v10a2 2 0 01-2 2H3a2 2 0 01-2-2V7a2 2 0 012-2zm0 0l9 6 9-6' }];
const primary = tweaks.primaryColor;
return (
);
}
/* ─── Project Card ─── */
function ProjectCard({ project, index, onClick, tweaks }) {
const [hovered, setHovered] = React.useState(false);
const primary = tweaks.primaryColor;
return (
onClick(project)}
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
style={{
position: 'relative', width: '100%', aspectRatio: '368/280',
borderRadius: 16, overflow: 'hidden', cursor: 'pointer',
background: 'rgba(57,62,70,0.5)', backdropFilter: 'blur(4px)',
transform: hovered ? 'translateY(-8px) scale(1.02)' : 'translateY(0)',
boxShadow: hovered ? `0 20px 40px rgba(0,0,0,0.4), 0 0 0 1px ${primary}33` : '0 4px 20px rgba(0,0,0,0.2)',
transition: 'all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94)'
}}>
{project.category}
{project.title}
);
}
/* ─── Skill Badge ─── */
function SkillBadge({ label, tweaks }) {
const [hovered, setHovered] = React.useState(false);
return (
setHovered(true)}
onMouseLeave={() => setHovered(false)}
style={{
display: 'inline-block', padding: '8px 20px', borderRadius: 24,
background: hovered ? tweaks.primaryColor : 'rgba(57,62,70,0.6)',
color: hovered ? '#0D1B2A' : '#EEE',
fontFamily: 'Poppins, sans-serif', fontWeight: 600, fontSize: 14,
transition: 'all 0.3s ease', cursor: 'default',
border: `1px solid ${hovered ? tweaks.primaryColor : 'rgba(238,238,238,0.15)'}`
}}>
{label});
}
/* ─── Footer ─── */
function Footer({ onNavigate, tweaks }) {
const primary = tweaks.primaryColor;
const links = [
{ id: 'home', label: 'Home' },
{ id: 'about', label: 'About' },
{ id: 'experience', label: 'Experience' },
{ id: 'projects', label: 'Projects' },
{ id: 'contact', label: 'Contact' }];
const socials = [
{ label: 'GitHub', icon: 'M12 2C6.477 2 2 6.477 2 12c0 4.42 2.865 8.166 6.839 9.489.5.092.682-.217.682-.482 0-.237-.009-.866-.013-1.7-2.782.604-3.369-1.34-3.369-1.34-.454-1.156-1.11-1.463-1.11-1.463-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.087 2.91.831.092-.646.35-1.086.636-1.336-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.268 2.75 1.026A9.578 9.578 0 0112 6.836a9.59 9.59 0 012.504.337c1.909-1.294 2.747-1.026 2.747-1.026.546 1.377.203 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.743 0 .267.18.579.688.481C19.137 20.164 22 16.418 22 12c0-5.523-4.477-10-10-10z' },
{ label: 'LinkedIn', icon: 'M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z' },
{ label: 'Email', icon: 'M3 5h18a2 2 0 012 2v10a2 2 0 01-2 2H3a2 2 0 01-2-2V7a2 2 0 012-2zm0 0l9 6 9-6' }];
return (
);
}
/* ─── Scroll Reveal ─── */
function Reveal({ children, delay = 0 }) {
const ref = React.useRef(null);
const [visible, setVisible] = React.useState(false);
React.useEffect(() => {
const el = ref.current;
if (!el) return;
const obs = new IntersectionObserver(([e]) => {
if (e.isIntersecting) {setVisible(true);obs.disconnect();}
}, { threshold: 0.15 });
obs.observe(el);
return () => obs.disconnect();
}, []);
return (
{children}
);
}
Object.assign(window, {
DoodleBrackets, DoodleArrow, DoodleCircle, DoodleCode, DoodleChart, DoodleStar,
Nav, ProjectCard, SkillBadge, Footer, Reveal
});