Skip to content

Commit 6a27251

Browse files
committed
update
1 parent 15f83e6 commit 6a27251

15 files changed

+965
-1283
lines changed

.vscode/.server-controller-port.log

Lines changed: 0 additions & 5 deletions
This file was deleted.

Certificates.js

Lines changed: 113 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,140 +1,128 @@
1-
// Modern Certificate Gallery with Tailwind CSS and shadcn/ui theming
21
document.addEventListener("DOMContentLoaded", function() {
3-
// Certificate data with more metadata for better display
4-
const certificates = [
5-
{ path: 'data/UdacityCertificate.pdf', title: 'Udacity Certificate', category: 'education' },
6-
{ path: 'data/Coursera E4WZRUCIBAMB.pdf', title: 'Coursera Certificate', category: 'education' },
7-
{ path: 'data/CertificateOfCompletion_Master JavaScript.pdf', title: 'Master JavaScript', category: 'javascript' },
8-
{ path: 'data/CertificateOfCompletion_Career Essentials in Generative AI by Microsoft and LinkedIn.pdf', title: 'Generative AI Essentials', category: 'ai' },
9-
{ path: 'data/CertificateOfCompletion_Advanced Node.js.pdf', title: 'Advanced Node.js', category: 'node' },
10-
{ path: 'data/CertificateOfCompletion_CSS Essential Training.pdf', title: 'CSS Essential Training', category: 'css' },
11-
{ path: 'data/CertificateOfCompletion_EndtoEnd JavaScript Testing with Cypress.io.pdf', title: 'Cypress.io Testing', category: 'javascript' },
12-
{ path: 'data/CertificateOfCompletion_Ethical Hacking with JavaScript.pdf', title: 'Ethical Hacking', category: 'javascript' },
13-
{ path: 'data/CertificateOfCompletion_JavaScript Best Practices for Code Formatting.pdf', title: 'JS Code Formatting', category: 'javascript' },
14-
{ path: 'data/CertificateOfCompletion_JavaScript Best Practices for Data.pdf', title: 'JS Data Practices', category: 'javascript' },
15-
{ path: 'data/CertificateOfCompletion_JavaScript Security Essentials.pdf', title: 'JS Security', category: 'javascript' },
16-
{ path: 'data/CertificateOfCompletion_JavaScript TestDriven Development ES6.pdf', title: 'Test-Driven Development', category: 'javascript' },
17-
{ path: 'data/CertificateOfCompletion_Learning MongoDB.pdf', title: 'MongoDB', category: 'database' },
18-
{ path: 'data/CertificateOfCompletion_Node.js Design Patterns.pdf', title: 'Node.js Design Patterns', category: 'node' },
19-
{ path: 'data/CertificateOfCompletion_Responsive Layout.pdf', title: 'Responsive Layout', category: 'css' },
20-
{ path: 'data/Gabrielius Pocevicius_JavaScript.pdf', title: 'JavaScript Certificate', category: 'javascript' },
21-
{ path: 'data/Gabrielius Pocevicius_Python.pdf', title: 'Python Certificate', category: 'python' },
22-
{ path: 'data/CertificateOfCompletion_Search Techniques for Web Developers.pdf', title: 'Search Techniques', category: 'development' },
23-
{ path: 'data/CertificateOfCompletion_Essential New Skills in Software Engineering.pdf', title: 'Software Engineering Skills', category: 'development' },
24-
];
2+
// Check if we've already loaded certificates to prevent duplicates
3+
if (window.certificatesLoaded) return;
4+
window.certificatesLoaded = true;
255

26-
let loadedCount = 0;
27-
const totalCerts = certificates.length;
28-
const certContainer = document.getElementById('cert-container');
29-
const loadingIndicator = document.getElementById('loading-indicator');
6+
// Certificate data with more metadata for better display
7+
const certificates = [
8+
{ path: 'data/UdacityCertificate.pdf', title: 'Udacity Certificate', category: 'education' },
9+
{ path: 'data/Coursera E4WZRUCIBAMB.pdf', title: 'Coursera Certificate', category: 'education' },
10+
{ path: 'data/CertificateOfCompletion_Master JavaScript.pdf', title: 'Master JavaScript', category: 'javascript' },
11+
{ path: 'data/CertificateOfCompletion_Career Essentials in Generative AI by Microsoft and LinkedIn.pdf', title: 'Generative AI Essentials', category: 'ai' },
12+
{ path: 'data/CertificateOfCompletion_Advanced Node.js.pdf', title: 'Advanced Node.js', category: 'node' },
13+
{ path: 'data/CertificateOfCompletion_CSS Essential Training.pdf', title: 'CSS Essential Training', category: 'css' },
14+
{ path: 'data/CertificateOfCompletion_EndtoEnd JavaScript Testing with Cypress.io.pdf', title: 'Cypress.io Testing', category: 'javascript' },
15+
{ path: 'data/CertificateOfCompletion_Ethical Hacking with JavaScript.pdf', title: 'Ethical Hacking', category: 'javascript' },
16+
{ path: 'data/CertificateOfCompletion_JavaScript Best Practices for Code Formatting.pdf', title: 'JS Code Formatting', category: 'javascript' },
17+
{ path: 'data/CertificateOfCompletion_JavaScript Best Practices for Data.pdf', title: 'JS Data Practices', category: 'javascript' },
18+
{ path: 'data/CertificateOfCompletion_JavaScript Security Essentials.pdf', title: 'JS Security', category: 'javascript' },
19+
{ path: 'data/CertificateOfCompletion_JavaScript TestDriven Development ES6.pdf', title: 'Test-Driven Development', category: 'javascript' },
20+
{ path: 'data/CertificateOfCompletion_Learning MongoDB.pdf', title: 'MongoDB', category: 'database' },
21+
{ path: 'data/CertificateOfCompletion_Node.js Design Patterns.pdf', title: 'Node.js Design Patterns', category: 'node' },
22+
{ path: 'data/CertificateOfCompletion_Responsive Layout.pdf', title: 'Responsive Layout', category: 'css' },
23+
{ path: 'data/Gabrielius Pocevicius_JavaScript.pdf', title: 'JavaScript Certificate', category: 'javascript' },
24+
{ path: 'data/Gabrielius Pocevicius_Python.pdf', title: 'Python Certificate', category: 'python' },
25+
{ path: 'data/CertificateOfCompletion_Search Techniques for Web Developers.pdf', title: 'Search Techniques', category: 'development' },
26+
{ path: 'data/CertificateOfCompletion_Essential New Skills in Software Engineering.pdf', title: 'Software Engineering Skills', category: 'development' },
27+
];
28+
29+
let loadedCount = 0;
30+
const totalCerts = certificates.length;
31+
const certContainer = document.getElementById('cert-container');
32+
const loadingIndicator = document.getElementById('loading-indicator');
33+
34+
// Clear existing certificates to prevent duplicates
35+
if (certContainer) {
36+
certContainer.innerHTML = '';
37+
}
38+
39+
// Update loading progress
40+
function updateProgress() {
41+
loadedCount++;
42+
const progress = Math.round((loadedCount / totalCerts) * 100);
3043

31-
// Update loading progress
32-
function updateProgress() {
33-
loadedCount++;
34-
const progress = Math.round((loadedCount / totalCerts) * 100);
35-
36-
if (loadingIndicator) {
37-
loadingIndicator.style.width = `${progress}%`;
38-
loadingIndicator.setAttribute('aria-valuenow', progress);
39-
loadingIndicator.textContent = `${progress}%`;
40-
}
41-
42-
if (loadedCount === totalCerts) {
43-
// Hide loading bar when complete
44-
setTimeout(() => {
45-
document.getElementById('loading-wrapper').classList.add('opacity-0', 'h-0', 'mb-0');
46-
}, 500);
47-
}
44+
if (loadingIndicator) {
45+
loadingIndicator.style.width = `${progress}%`;
46+
loadingIndicator.setAttribute('aria-valuenow', progress);
47+
loadingIndicator.textContent = `${progress}%`;
4848
}
49-
50-
// Create certificate card with Tailwind classes
51-
function createCertificateCard(cert) {
52-
return new Promise((resolve) => {
53-
const uuid = crypto.randomUUID();
54-
const card = document.createElement('div');
55-
card.className = 'cert-card opacity-0 transform translate-y-4 transition-all duration-300 ease-in-out data-category-' + cert.category;
56-
card.dataset.categories = cert.category;
57-
card.id = uuid;
58-
59-
// Add a staggered animation effect
60-
setTimeout(() => {
61-
card.classList.remove('opacity-0', 'translate-y-4');
62-
}, loadedCount * 100);
63-
64-
card.innerHTML = `
65-
<div class="bg-card text-card-foreground rounded-lg shadow-sm overflow-hidden">
66-
<div class="relative h-64 border overflow-hidden">
67-
<iframe class="relative h-full overflow-hidden pointer-events-none border-0" src="${cert.path}"></iframe>
49+
50+
if (loadedCount === totalCerts) {
51+
// Hide loading bar when complete
52+
setTimeout(() => {
53+
const loadingWrapper = document.getElementById('loading-wrapper');
54+
if (loadingWrapper) {
55+
loadingWrapper.classList.add('opacity-0', 'h-0', 'mb-0');
56+
}
57+
}, 500);
58+
}
59+
}
6860

61+
// Create certificate card with Tailwind classes
62+
function createCertificateCard(cert) {
63+
return new Promise((resolve) => {
64+
const uuid = crypto.randomUUID();
65+
const card = document.createElement('div');
66+
card.className = 'cert-card opacity-0 transform translate-y-4 transition-all duration-300 ease-in-out data-category-' + cert.category;
67+
card.dataset.categories = cert.category;
68+
card.id = uuid;
69+
70+
// Add a staggered animation effect
71+
setTimeout(() => {
72+
card.classList.remove('opacity-0', 'translate-y-4');
73+
}, loadedCount * 100);
74+
75+
card.innerHTML = `
76+
<div class="bg-card text-card-foreground rounded-lg shadow-sm overflow-hidden">
77+
<div class="relative h-64 border overflow-hidden">
78+
<iframe class="relative h-full overflow-hidden pointer-events-none border-0" src="${cert.path}"></iframe>
6979
70-
<div class="absolute inset-0 bg-gradient-to-t from-black/70 via-black/0 to-transparent transform translate-y-full transition-transform duration-300 p-4 flex flex-col justify-end">
71-
<div class="text-white font-medium text-sm">${cert.title}</div>
72-
</div>
80+
<div class="absolute inset-0 bg-gradient-to-t from-black/70 via-black/0 to-transparent transform translate-y-full transition-transform duration-300 p-4 flex flex-col justify-end">
81+
<div class="text-white font-medium text-sm">${cert.title}</div>
7382
</div>
74-
<div class="p-4 bg-card">
75-
<div class="flex justify-between items-center m-2">
76-
<span class="text-xs text-muted-foreground">${cert.category}</span>
77-
<a href="${cert.path}" target="_blank" class="badge border px-2 py-1 rounded-0 inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 text-primary-foreground hover:bg-secondary/90 h-8 px-4 py-2">
78-
View Full
79-
</a>
80-
</div>
83+
</div>
84+
<div class="p-4 bg-card">
85+
<div class="flex justify-between items-center m-2">
86+
<span class="text-xs text-muted-foreground">${cert.category}</span>
87+
<a href="${cert.path}" target="_blank" class="badge border px-2 py-1 rounded-0 inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 text-primary-foreground hover:bg-secondary/90 h-8 px-4 py-2">
88+
View Full
89+
</a>
8190
</div>
8291
</div>
83-
`;
84-
92+
</div>
93+
`;
8594

95+
if (certContainer) {
8696
certContainer.appendChild(card);
87-
88-
// Simulate loading time
89-
setTimeout(() => {
90-
updateProgress();
91-
resolve();
92-
}, 100);
93-
94-
// Add hover effect
95-
card.addEventListener('mouseenter', function() {
96-
const overlay = this.querySelector('.bg-gradient-to-t');
97-
overlay.classList.remove('translate-y-full');
98-
});
99-
100-
card.addEventListener('mouseleave', function() {
101-
const overlay = this.querySelector('.bg-gradient-to-t');
102-
overlay.classList.add('translate-y-full');
103-
});
97+
}
98+
99+
// Simulate loading time
100+
setTimeout(() => {
101+
updateProgress();
102+
resolve();
103+
}, 100);
104+
105+
// Add hover effect
106+
card.addEventListener('mouseenter', function() {
107+
const overlay = this.querySelector('.bg-gradient-to-t');
108+
if (overlay) overlay.classList.remove('translate-y-full');
104109
});
105-
}
106-
107-
// Load all certificates
108-
async function loadAllCertificates() {
109-
const loadPromises = certificates.map(cert => createCertificateCard(cert));
110-
await Promise.all(loadPromises);
111-
}
112-
113-
// Add filter capabilities
114-
function setupFilters() {
115-
const filterButtons = document.querySelectorAll('.filter-btn');
116110

117-
filterButtons.forEach(btn => {
118-
btn.addEventListener('click', function() {
119-
const filter = this.getAttribute('data-filter');
120-
121-
// Filter cards
122-
const cards = document.querySelectorAll('.cert-card');
123-
cards.forEach(card => {
124-
const categories = card.dataset.categories;
125-
126-
if (filter === 'all' || categories.includes(filter)) {
127-
card.classList.remove('hidden');
128-
} else {
129-
card.classList.add('hidden');
130-
}
131-
});
132-
});
111+
card.addEventListener('mouseleave', function() {
112+
const overlay = this.querySelector('.bg-gradient-to-t');
113+
if (overlay) overlay.classList.add('translate-y-full');
133114
});
134-
}
135-
136-
// Initialize
137-
loadAllCertificates().then(() => {
138-
setupFilters();
139115
});
140-
});
116+
}
117+
118+
// Load all certificates
119+
async function loadAllCertificates() {
120+
if (!certContainer) return;
121+
122+
const loadPromises = certificates.map(cert => createCertificateCard(cert));
123+
await Promise.all(loadPromises);
124+
}
125+
126+
// Initialize
127+
loadAllCertificates();
128+
});

0 commit comments

Comments
 (0)