Skip to content

Commit ba644c3

Browse files
committed
training fixed
1 parent 18ba519 commit ba644c3

8 files changed

Lines changed: 307 additions & 415 deletions

File tree

components/Credentials.jsx

Lines changed: 53 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,67 @@
11
"use client";
22
import { useState, useEffect } from "react";
33
import { motion, AnimatePresence } from "framer-motion";
4-
import { FiX, FiExternalLink, FiEye, FiCheckCircle } from "react-icons/fi";
4+
import { FiX, FiExternalLink, FiEye } from "react-icons/fi";
55
import { certifications, education } from "@/data/portfolio";
66
import { getIcon } from "./icons";
77

8+
/* compact card — smaller padding, smaller icon, single-line title, no hover-expand */
89
function Card({ item, i, onOpen }) {
910
const Icon = getIcon(item.icon);
1011
const hasProof = Boolean(item.image || item.verifyUrl);
1112
return (
12-
<motion.div
13+
<motion.button
14+
type="button"
1315
data-hover
14-
initial={{ opacity: 0, y: 20 }}
16+
initial={{ opacity: 0, y: 12 }}
1517
whileInView={{ opacity: 1, y: 0 }}
1618
viewport={{ once: true }}
17-
transition={{ duration: 0.45, delay: (i % 4) * 0.06 }}
18-
whileHover={{ y: -6 }}
19+
transition={{ duration: 0.35, delay: (i % 6) * 0.04 }}
20+
whileHover={{ y: -3 }}
1921
onClick={() => hasProof && onOpen(item)}
20-
className={`group relative glass rounded-2xl p-5 overflow-hidden transition-colors ${
21-
hasProof ? "cursor-pointer hover:border-accent/60" : "hover:border-accent/40"
22-
}`}
22+
className={`glass rounded-xl p-3 flex items-center gap-3 text-left transition-colors ${hasProof ? "cursor-pointer hover:border-accent/60" : ""}`}
2323
>
24-
<div className="flex items-center gap-3">
25-
<span className="w-11 h-11 shrink-0 rounded-xl bg-gradient-to-br from-accent to-accent2 flex items-center justify-center text-bg">
26-
<Icon size={20} />
24+
<span className="w-9 h-9 shrink-0 rounded-lg bg-gradient-to-br from-accent to-accent2 flex items-center justify-center text-bg">
25+
<Icon size={16} />
26+
</span>
27+
<span className="min-w-0 flex-1">
28+
<span className="block text-[13px] font-semibold leading-tight truncate">{item.title}</span>
29+
<span className="block text-[11px] text-muted truncate">
30+
{item.issuer}{item.year ? ` · ${item.year}` : ""}
2731
</span>
28-
<div className="min-w-0">
29-
<h4 className="font-semibold leading-tight">{item.title}</h4>
30-
<p className="text-xs text-muted truncate">
31-
{item.issuer}{item.year ? ` · ${item.year}` : ""}
32-
</p>
33-
</div>
34-
</div>
35-
<div className="grid grid-rows-[0fr] group-hover:grid-rows-[1fr] transition-all duration-300 ease-out">
36-
<div className="overflow-hidden">
37-
<p className="text-muted text-sm mt-3 leading-relaxed">{item.detail}</p>
38-
</div>
39-
</div>
40-
{hasProof && (
41-
<span className="mt-3 inline-flex items-center gap-1.5 text-xs font-medium text-accent">
42-
<FiEye size={13} /> View certificate
43-
</span>
44-
)}
45-
</motion.div>
32+
</span>
33+
{hasProof && <FiEye size={13} className="text-accent shrink-0" />}
34+
</motion.button>
4635
);
4736
}
4837

49-
function CertModal({ item, onClose }) {
38+
function Modal({ item, onClose }) {
5039
const isPdf = item?.image?.toLowerCase().endsWith(".pdf");
5140
useEffect(() => {
5241
const onKey = (e) => e.key === "Escape" && onClose();
53-
document.addEventListener("keydown", onKey);
54-
document.body.style.overflow = "hidden";
55-
return () => {
56-
document.removeEventListener("keydown", onKey);
57-
document.body.style.overflow = "";
58-
};
42+
document.addEventListener("keydown", onKey); document.body.style.overflow = "hidden";
43+
return () => { document.removeEventListener("keydown", onKey); document.body.style.overflow = ""; };
5944
}, [onClose]);
60-
6145
return (
62-
<motion.div
63-
initial={{ opacity: 0 }}
64-
animate={{ opacity: 1 }}
65-
exit={{ opacity: 0 }}
66-
onClick={onClose}
67-
className="fixed inset-0 z-[100] flex items-center justify-center p-4 bg-black/70 backdrop-blur-sm"
68-
>
69-
<motion.div
70-
initial={{ scale: 0.94, y: 12, opacity: 0 }}
71-
animate={{ scale: 1, y: 0, opacity: 1 }}
72-
exit={{ scale: 0.94, y: 12, opacity: 0 }}
73-
transition={{ type: "spring", stiffness: 260, damping: 24 }}
74-
onClick={(e) => e.stopPropagation()}
75-
className="relative w-full max-w-2xl glass rounded-2xl border border-line overflow-hidden"
76-
>
46+
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} onClick={onClose}
47+
className="fixed inset-0 z-[100] flex items-center justify-center p-4 bg-black/70 backdrop-blur-sm">
48+
<motion.div initial={{ scale: 0.95, y: 10, opacity: 0 }} animate={{ scale: 1, y: 0, opacity: 1 }} exit={{ scale: 0.95, y: 10, opacity: 0 }}
49+
onClick={(e) => e.stopPropagation()} className="relative w-full max-w-2xl glass rounded-2xl border border-line overflow-hidden">
7750
<div className="flex items-start justify-between gap-4 p-5 border-b border-line">
78-
<div className="min-w-0">
79-
<h3 className="font-bold truncate">{item.title}</h3>
80-
<p className="text-xs text-muted truncate">{item.issuer}{item.year ? ` · ${item.year}` : ""}</p>
81-
</div>
82-
<button data-hover onClick={onClose} aria-label="Close"
83-
className="w-9 h-9 shrink-0 rounded-full border border-line flex items-center justify-center hover:border-accent hover:text-accent transition-colors">
84-
<FiX size={18} />
85-
</button>
51+
<div className="min-w-0"><h3 className="font-bold truncate">{item.title}</h3>
52+
<p className="text-xs text-muted truncate">{item.issuer}{item.year ? ` · ${item.year}` : ""}</p></div>
53+
<button data-hover onClick={onClose} className="w-9 h-9 shrink-0 rounded-full border border-line flex items-center justify-center hover:border-accent hover:text-accent transition-colors"><FiX size={18} /></button>
8654
</div>
8755
<div className="p-5">
88-
{item.image ? (
89-
isPdf ? (
90-
<object data={item.image} type="application/pdf" className="w-full h-[60vh] rounded-lg bg-white">
91-
<p className="text-muted text-sm">Preview unavailable.{" "}
92-
<a href={item.image} target="_blank" rel="noopener noreferrer" className="text-accent hover:underline">Open PDF ↗</a>
93-
</p>
94-
</object>
95-
) : (
96-
/* eslint-disable-next-line @next/next/no-img-element */
97-
<img src={item.image} alt={item.title} className="w-full max-h-[60vh] object-contain rounded-lg bg-white" />
98-
)
99-
) : (
100-
<div className="text-center py-10">
101-
<FiCheckCircle className="mx-auto text-accent mb-3" size={40} />
102-
<p className="text-muted text-sm">{item.detail}</p>
103-
</div>
104-
)}
56+
{item.image
57+
? (isPdf
58+
? <object data={item.image} type="application/pdf" className="w-full h-[60vh] rounded-lg bg-white"><p className="text-muted text-sm">Preview unavailable. <a href={item.image} target="_blank" rel="noopener noreferrer" className="text-accent hover:underline">Open ↗</a></p></object>
59+
: /* eslint-disable-next-line @next/next/no-img-element */ <img src={item.image} alt={item.title} className="w-full max-h-[60vh] object-contain rounded-lg bg-white" />)
60+
: <p className="text-muted text-sm text-center py-8">{item.detail}</p>}
10561
</div>
106-
<div className="flex flex-wrap items-center justify-end gap-3 p-5 border-t border-line">
107-
{item.image && (
108-
<a href={item.image} target="_blank" rel="noopener noreferrer" data-hover
109-
className="text-sm px-4 py-2 rounded-full border border-line hover:border-accent hover:text-accent transition-colors flex items-center gap-2">
110-
<FiEye size={15} /> Open full
111-
</a>
112-
)}
113-
{item.verifyUrl && (
114-
<a href={item.verifyUrl} target="_blank" rel="noopener noreferrer" data-hover
115-
className="text-sm px-4 py-2 rounded-full bg-accent text-bg font-semibold hover:opacity-90 transition flex items-center gap-2">
116-
<FiExternalLink size={15} /> Verify credential
117-
</a>
118-
)}
62+
<div className="flex items-center justify-end gap-3 p-5 border-t border-line">
63+
{item.image && <a href={item.image} target="_blank" rel="noopener noreferrer" data-hover className="text-sm px-4 py-2 rounded-full border border-line hover:border-accent hover:text-accent transition-colors flex items-center gap-2"><FiEye size={15} /> Open full</a>}
64+
{item.verifyUrl && <a href={item.verifyUrl} target="_blank" rel="noopener noreferrer" data-hover className="text-sm px-4 py-2 rounded-full bg-accent text-bg font-semibold hover:opacity-90 transition flex items-center gap-2"><FiExternalLink size={15} /> Verify</a>}
11965
</div>
12066
</motion.div>
12167
</motion.div>
@@ -124,46 +70,43 @@ function CertModal({ item, onClose }) {
12470

12571
export default function Credentials() {
12672
const [active, setActive] = useState(null);
73+
74+
// group by category
12775
const groups = [];
12876
const seen = {};
12977
(certifications || []).forEach((c) => {
130-
const key = c.category || "Certifications";
131-
if (!(key in seen)) { seen[key] = groups.length; groups.push({ category: key, items: [] }); }
132-
groups[seen[key]].items.push(c);
78+
const k = c.category || "Certifications";
79+
if (!(k in seen)) { seen[k] = groups.length; groups.push({ category: k, items: [] }); }
80+
groups[seen[k]].items.push(c);
13381
});
13482

13583
return (
136-
<section id="credentials" className="py-24 border-t border-line">
84+
<section id="credentials" className="py-20 border-t border-line">
13785
<div className="container">
138-
<h2 className="text-3xl sm:text-4xl font-bold mb-3">Certifications &amp; Education</h2>
139-
<p className="text-muted mb-12">Click a certificate to preview or verify it.</p>
86+
<h2 className="text-3xl sm:text-4xl font-bold mb-1">Certifications &amp; Education</h2>
87+
<p className="text-muted mb-8 text-sm">Click any certificate to preview or verify it.</p>
14088

89+
{/* compact: 2 → 3 columns, small gaps, tight category spacing */}
14190
{groups.map((g) => (
142-
<div key={g.category} className="mb-12">
143-
<h3 className="text-sm font-mono text-accent mb-4">{g.category.toUpperCase()}</h3>
144-
<div className="grid sm:grid-cols-2 lg:grid-cols-4 gap-5">
145-
{g.items.map((c, i) => (
146-
<Card key={c.title} item={c} i={i} onOpen={setActive} />
147-
))}
91+
<div key={g.category} className="mb-7">
92+
<h3 className="text-xs font-mono text-accent mb-3">{g.category.toUpperCase()}</h3>
93+
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-3">
94+
{g.items.map((c, i) => <Card key={c.title} item={c} i={i} onOpen={setActive} />)}
14895
</div>
14996
</div>
15097
))}
15198

15299
{education?.length > 0 && (
153100
<>
154-
<h3 className="text-sm font-mono text-accent mb-4">🎓 EDUCATION</h3>
155-
<div className="grid sm:grid-cols-2 lg:grid-cols-4 gap-5">
156-
{education.map((e, i) => (
157-
<Card key={e.title} item={e} i={i} onOpen={setActive} />
158-
))}
101+
<h3 className="text-xs font-mono text-accent mb-3">🎓 EDUCATION</h3>
102+
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-3">
103+
{education.map((e, i) => <Card key={e.title} item={e} i={i} onOpen={setActive} />)}
159104
</div>
160105
</>
161106
)}
162107
</div>
163108

164-
<AnimatePresence>
165-
{active && <CertModal item={active} onClose={() => setActive(null)} />}
166-
</AnimatePresence>
109+
<AnimatePresence>{active && <Modal item={active} onClose={() => setActive(null)} />}</AnimatePresence>
167110
</section>
168111
);
169112
}

components/Navbar.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const links = [
88
{ label: "Experience", href: "#experience" },
99
{ label: "Projects", href: "#projects" },
1010
{ label: "Training", href: "#training" },
11-
{ label: "Verify", href: "/migration/" },
11+
{ label: "Transformation", href: "/transformation/" },
1212
{ label: "Verify", href: "/verify/" },
1313
{ label: "Contact", href: "#contact" },
1414
];

0 commit comments

Comments
 (0)