Portfolio
Explore our creative projects and artwork
Loading...
Loading portfolio projects...
No portfolio projects available at the moment.
id="modalContent"
overflow-y: auto;
overflow-x: hidden;
flex: 1;
scroll-behavior: smooth;
let portfolioProjects = [];
// Open project modal
function openProjectModal(projectId) {
try {
const project = portfolioProjects.find((p) => p.id === projectId);
if (!project) {
console.error('[Portfolio] Project not found:', projectId);
return;
}
// Validate project data
if (!project.title) {
console.error('[Portfolio] Invalid project data - missing title:', project);
return;
}
const modal = document.getElementById("projectModal");
const modalContent = document.getElementById("modalContent");
// Safe template with validated data
modalContent.innerHTML = `
${
project.category
? `
${project.category}`
: ""
}
${
project.title
}
${project.description || "No description available."}
${
project.createdat
? `
Created on ${new Date(
project.createdat
).toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
})}
`
: ""
}
`;
modal.style.display = "block";
modalContent.scrollTop = 0;
document.body.style.overflow = "hidden";
} catch (error) {
console.error('[Portfolio] Error opening modal:', error);
alert('Unable to open project details. Please try again.');
}
}
// Close project modal
function closeProjectModal() {
document.getElementById("projectModal").style.display = "none";
document.body.style.overflow = "auto";
}
// Close modal on outside click
document.addEventListener("click", (e) => {
if (e.target === modal) {
closeProjectModal();
}
});
// Close modal on Escape key
document.addEventListener("keydown", (e) => {
if (e.key === "Escape") {
closeProjectModal();
}
});
// Load portfolio projects from API
async function loadPortfolio() {
try {
const response = await fetch("/api/portfolio/projects");
if (response.ok) {
const data = await response.json();
portfolioProjects = data.projects || [];
document.getElementById("loadingMessage").style.display = "none";
if (portfolioProjects.length === 0) {
document.getElementById("noProjects").style.display = "block";
return;
}
// Validate and filter projects
const validProjects = portfolioProjects.filter(project => {
if (!project || !project.id || !project.title) {
console.warn('[Portfolio] Skipping invalid project:', project);
return false;
}
return true;
});
if (validProjects.length === 0) {
document.getElementById("noProjects").style.display = "block";
return;
}
const grid = document.getElementById("portfolioGrid");
grid.innerHTML = validProjects
.map(
(project) => `

${
project.category
? `
${project.category}`
: ""
}
${
project.title
}
${
project.description && project.description.replace(/<[^>]*>/g, '').trim()
? `
${project.description.replace(/<[^>]*>/g, '').substring(0, 80)}${project.description.length > 80 ? '...' : ''}
`
: ""
}
`
)
.join("");
} else {
document.getElementById("noProjects").style.display = "block";
}
} catch (error) {
console.error("Error loading portfolio:", error);
document.getElementById("loadingMessage").innerHTML =
'
Error loading portfolio projects. Please try again later.
';
// Initialize
loadPortfolio();