<div class="projects-grid">
	<div class="project-card" data-project-id="project1">
		<img src="https://picsum.photos/800/400" alt="Project 1" />
	</div>
	<div class="project-card" data-project-id="project2">
		<img src="https://picsum.photos/800/500" alt="Project 2" />
	</div>
</div>
.projects-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
	gap: 20px;
	padding: 20px;
}

.project-card {
	position: relative;
	cursor: pointer;
}

.project-card img {
	width: 100%;
	height: 200px;
	object-fit: cover;
}

.modal-overlay {
	position: fixed;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	background: rgba(0, 0, 0, 0.75);
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.4s cubic-bezier(0.4, 0, 0.2, 1);
	z-index: 1000;
}

.modal-overlay.active {
	opacity: 1;
	pointer-events: auto;
}

.modal-content {
	position: fixed;
	bottom: 0;
	left: 0;
	right: 0;
	margin: 0 auto;
	width: 90%;
	height: 80vh;
	background: white;
	transform: translateY(100%);
	transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
	z-index: 1001;
	display: flex;
	flex-direction: row;
	overflow: hidden;
	border-radius: 20px 20px 0 0;
}

.modal-content.active {
	transform: translateY(0);
}

.modal-content.expanded {
	width: 100%;
	height: 100vh;
	border-radius: 0;
}

.modal-sidebar {
	width: 250px;
	padding: 20px;
	border-right: 1px solid #eee;
	background: white;
	height: 100%;
	overflow-y: auto;
	flex-shrink: 0;
	display: block; /* Make sidebar always visible */
}

.modal-main {
	position: relative;
	flex: 1;
	display: flex;
	flex-direction: column;
	min-width: 0;
	height: 100%;
	overflow: hidden; /* Prevent double scroll */
	margin: 0 auto;
	max-width: 1200px;
	transition: inherit;
}

.modal-content.expanded .modal-main {
	max-width: none;
}

.modal-header {
	height: 70px;
	padding: 20px;
	background: white;
	border-bottom: 1px solid #eee;
	z-index: 2;
	flex-shrink: 0;
}

.modal-body {
	flex: 1;
	overflow-y: scroll;
	padding: 20px;
	height: calc(100% - 70px); /* Account for header height */
	scroll-behavior: smooth;
}

.sidebar-section {
	margin-bottom: 20px;
}

.sidebar-section h3 {
	margin-bottom: 10px;
}

.modal-image {
	width: 100%;
	height: auto;
	margin: 20px 0;
	border-radius: 8px;
}

.modal-text {
	font-size: 16px;
	line-height: 1.6;
	margin: 20px 0;
}

.modal-close {
	position: absolute;
	top: 20px;
	right: 20px;
	cursor: pointer;
	font-size: 24px;
	background: white;
	border-radius: 50%;
	width: 40px;
	height: 40px;
	display: flex;
	align-items: center;
	justify-content: center;
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
// State variables
const originalURL = window.location.pathname;

// Create modal DOM element
function createModal(projectId) {
	const modal = document.createElement("div");
	// CMS DATA- Simulated content with text
	modal.innerHTML = `
        <div class="modal-overlay">
          <div class="modal-content">
            <div class="modal-sidebar">
              <div class="sidebar-section">
                <h3>Project Info</h3>
                <p>Created: Jan 1, 2024</p>
                <p>Category: Design</p>
                <p>Status: Active</p>
              </div>
              <div class="sidebar-section">
                <h3>Technologies</h3>
                <ul>
                  <li>HTML/CSS</li>
                  <li>JavaScript</li>
                  <li>React</li>
                </ul>
              </div>
              <div class="sidebar-section">
                <h3>Team</h3>
                <ul>
                  <li>John Doe - Lead</li>
                  <li>Jane Smith - Design</li>
                </ul>
              </div>
            </div>
            <div class="modal-main">
              <div class="modal-header">
                <span class="modal-close">&times;</span>
                <h2>${projectId}</h2>
              </div>
              <div class="modal-body">
                <div class="loading">Loading project details...</div>
              </div>
            </div>
          </div>
        </div>
      `;

	document.body.appendChild(modal);

	// Improved scroll handler
	const content = modal.querySelector(".modal-content");
	const modalOverlay = modal.querySelector(".modal-overlay");
	let lastScrollY = window.scrollY;
	let scrollTimer = null;

	// Handle scroll events on both window and modal content
	const handleScroll = (e) => {
		if (scrollTimer !== null) {
			clearTimeout(scrollTimer);
		}

		const delta = e.deltaY || window.scrollY - lastScrollY;
		lastScrollY = window.scrollY;

		scrollTimer = setTimeout(() => {
			if (delta > 0 && !content.classList.contains("expanded")) {
				content.classList.add("expanded");
			} else if (
				delta < 0 &&
				content.classList.contains("expanded") &&
				window.scrollY <= 0
			) {
				content.classList.remove("expanded");
			}
		}, 20);
	};

	// Add wheel event listener to the entire modal
	modalOverlay.addEventListener("wheel", handleScroll, { passive: true });

	// Initialize modal
	requestAnimationFrame(() => {
		modalOverlay.classList.add("active");
		content.classList.add("active");
	});

	return modal;
}

// Load project content
async function loadProjectContent(projectId) {
	try {
		const response = await fetch(`/api/projects/${projectId}`);
		const data = await response.json();
		return data;
	} catch (error) {
		// CMS CONTENT - Simulated content with images and text
		return {
			title: "Project Title",
			description: "Project description...",
			content: `
            <img class="modal-image" src="https://picsum.photos/800/400" alt="Project image 1">
            <p class="modal-text">Detailed project description paragraph 1...</p>
            <img class="modal-image" src="https://picsum.photos/800/600" alt="Project image 2">
            <p class="modal-text">Detailed project description paragraph 2...</p>
            <img class="modal-image" src="https://picsum.photos/800/500" alt="Project image 3">
            <p class="modal-text">Detailed project description paragraph 3...</p>
          `
		};
	}
}

// Close modal
function closeModal(modal) {
	const overlay = modal.querySelector(".modal-overlay");
	const content = modal.querySelector(".modal-content");

	content.style.transform = "translateY(100%)";
	overlay.style.opacity = "0";

	setTimeout(() => {
		modal.remove();
		history.pushState(null, "", originalURL);
	}, 300);
}

// Initialize event listeners
function initializeModalHandlers() {
	// Handle project clicks
	document.querySelectorAll(".project-card").forEach((card) => {
		card.addEventListener("click", async (e) => {
			e.preventDefault();
			const projectId = card.dataset.projectId;
			// display changeg URL
			history.pushState({ modal: true, projectId }, "", `/projects/${projectId}`);

			const modal = createModal(projectId);
			const content = await loadProjectContent(projectId);
			modal.querySelector(".modal-body").innerHTML = `
            <h3>${content.title}</h3>
            <p>${content.description}</p>
            ${content.content}
          `;

			modal
				.querySelector(".modal-close")
				.addEventListener("click", () => closeModal(modal));
		});
	});

	// Handle browser back/forward
	window.addEventListener("popstate", (event) => {
		const modal = document.querySelector(".modal-overlay")?.parentElement;
		if (!event.state?.modal && modal) {
			closeModal(modal);
		}
	});
}

// Initialize
initializeModalHandlers();
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.