diff --git a/curriculum/challenges/english/25-front-end-development/lab-lightbox-viewer/66db57ad34c7089b9b41bfd6.md b/curriculum/challenges/english/25-front-end-development/lab-lightbox-viewer/66db57ad34c7089b9b41bfd6.md index 365086b3606..a60c71c12fe 100644 --- a/curriculum/challenges/english/25-front-end-development/lab-lightbox-viewer/66db57ad34c7089b9b41bfd6.md +++ b/curriculum/challenges/english/25-front-end-development/lab-lightbox-viewer/66db57ad34c7089b9b41bfd6.md @@ -8,7 +8,9 @@ demoType: onClick # --description-- -A lightbox displays a larger version of an image when clicked and shadows the rest of the page. This project will create a lightbox gallery that displays full-size images when a thumbnail is clicked. For each image, two versions are provided: a thumbnail and a full-size image. The full-size image is the same as the thumbnail, but without the `-thumbnail` suffix. +A lightbox is used on websites to showcase multimedia content in a more engaging way through use of a popup or modal window over the page's main content. + +In this lab, you will create a lightbox gallery that displays full-size images when a thumbnail is clicked. For each image, two versions are provided: a thumbnail and a full-size image. The full-size image is the same as the thumbnail, but without the `-thumbnail` suffix. Fulfill the user stories below and get all the tests to pass to complete the lab. @@ -22,19 +24,19 @@ Fulfill the user stories below and get all the tests to pass to complete the lab - `https://cdn.freecodecamp.org/curriculum/labs/trees-thumbnail.jpg` 1. You should have a `div` with a class of `lightbox` within your `body`. -1. You should have a `span` with an `id` of `close` within your `.lightbox` element. You can use `×` as its text if you want. +1. You should have a `button` with an `id` of `close-btn` within your `.lightbox` element. You can use `×` as its text if you want. 1. You should have a `img` with an `id` of `lightbox-image` within your `.lightbox` element. 1. Your `.lightbox` element should have a fixed position so that the preview opens on top of the current images. -1. Your `.lightbox` element should cover the entire viewport by setting the height and width to 100% of the container. You should ensure that the lightbox element starts at the top left corner of the container. +1. Your `.lightbox` element should cover the entire viewport by setting the height and width to 100% of the container. You should ensure that the `.lightbox` element starts at the top left corner of the container. 1. `.lightbox` should have a background color. Initially, its `display` property should be set to `none` to hide it. -1. When you click one of your `.gallery-item` elements, the `.lightbox` element's `display` property should be set to `flex` to make `.lightbox` and the two elements within it visible. +1. When you click one of your `.gallery-item` elements, the `.lightbox` element's `display` property should be set to `flex` to make the `.lightbox` element and the two elements within it visible. 1. When you click one of your `.gallery-item` elements, the `#lightbox-image` element's `src` should be set to a full-size version of the image clicked by removing `-thumbnail` from the image's `src` attribute. The full-size images are located at the following links: - `https://cdn.freecodecamp.org/curriculum/labs/stonehenge.jpg` - `https://cdn.freecodecamp.org/curriculum/labs/storm.jpg` - `https://cdn.freecodecamp.org/curriculum/labs/trees.jpg` -1. When your `.lightbox` element is visible and you click the `#close` button or the `.lightbox` element, the `.lightbox` elements `display` should be set back to `none`. +1. When your `.lightbox` element is visible and you click the `#close-btn` or the `.lightbox` element, the `.lightbox` element's `display` should be set back to `none`. **Note:** Be sure to link your stylesheet and the JavaScript file in your HTML. @@ -43,58 +45,58 @@ Fulfill the user stories below and get all the tests to pass to complete the lab You should have a `div` with the class of `gallery` inside your `body` element. ```js -assert.equal(document.querySelector('body .gallery')?.tagName, 'DIV'); +assert.equal(document.querySelector("body .gallery")?.tagName, "DIV"); ``` -Within the `.gallery` `div`, you should have three image elements with the class of `gallery-item`. +Within the `.gallery` element, you should have three `img` elements with the class of `gallery-item`. ```js -assert.equal(document.querySelectorAll('.gallery .gallery-item').length, 3); +assert.lengthOf(document.querySelectorAll(".gallery .gallery-item"), 3) ``` -Within the `.gallery` `div`, you should an image element with the `src` set to `https://cdn.freecodecamp.org/curriculum/labs/stonehenge-thumbnail.jpg`. +Within the `.gallery` element, you should have an `img` element with the `src` set to `https://cdn.freecodecamp.org/curriculum/labs/stonehenge-thumbnail.jpg`. ```js -const images = document.querySelectorAll('.gallery .gallery-item'); +const images = document.querySelectorAll(".gallery .gallery-item"); let srcCount = 0; -const targetSrc = 'https://cdn.freecodecamp.org/curriculum/labs/stonehenge-thumbnail.jpg'; +const targetSrc = "https://cdn.freecodecamp.org/curriculum/labs/stonehenge-thumbnail.jpg"; for (let image of images) { - if (image.src === targetSrc) { - srcCount++; - } + if (image.src === targetSrc) { + srcCount++; + } } assert.strictEqual(srcCount, 1); ``` -Within the `.gallery` `div`, you should an image element with the `src` set to `https://cdn.freecodecamp.org/curriculum/labs/storm-thumbnail.jpg`. +Within the `.gallery` element, you should an `img` element with the `src` set to `https://cdn.freecodecamp.org/curriculum/labs/storm-thumbnail.jpg`. ```js -const images = document.querySelectorAll('.gallery .gallery-item'); +const images = document.querySelectorAll(".gallery .gallery-item"); let srcCount = 0; -const targetSrc = 'https://cdn.freecodecamp.org/curriculum/labs/storm-thumbnail.jpg'; +const targetSrc = "https://cdn.freecodecamp.org/curriculum/labs/storm-thumbnail.jpg"; for (let image of images) { - if (image.src === targetSrc) { - srcCount++; - } + if (image.src === targetSrc) { + srcCount++; + } } assert.strictEqual(srcCount, 1); ``` -Within the `.gallery` `div`, you should an image element with the `src` set to `https://cdn.freecodecamp.org/curriculum/labs/trees-thumbnail.jpg`. +Within the `.gallery` element, you should an `img` element with the `src` set to `https://cdn.freecodecamp.org/curriculum/labs/trees-thumbnail.jpg`. ```js -const images = document.querySelectorAll('.gallery .gallery-item'); +const images = document.querySelectorAll(".gallery .gallery-item"); let srcCount = 0; -const targetSrc = 'https://cdn.freecodecamp.org/curriculum/labs/trees-thumbnail.jpg'; +const targetSrc = "https://cdn.freecodecamp.org/curriculum/labs/trees-thumbnail.jpg"; for (let image of images) { - if (image.src === targetSrc) { - srcCount++; - } + if (image.src === targetSrc) { + srcCount++; + } } assert.strictEqual(srcCount, 1); @@ -103,159 +105,125 @@ assert.strictEqual(srcCount, 1); You should have a `div` element with the class of `lightbox` inside your `body` element. ```js -// assert either div or span -assert.exists(document.querySelector('body .lightbox')); +const lightboxEl = document.querySelector("body .lightbox"); +assert.exists(lightboxEl); +assert.equal(lightboxEl?.tagName, "DIV"); ``` -Within your `.lightbox` `div`, you should have a `span` element with the `id` set to `close`. +Within your `.lightbox` element, you should have a `button` element with the `id` set to `close-btn`. ```js -assert.equal(document.querySelector('.lightbox #close').tagName, 'SPAN'); +assert.equal(document.querySelector(".lightbox #close-btn")?.tagName, "BUTTON"); ``` -Within your `.lightbox` `div`, you should have an `img` element with the `id` set to `lightbox-image`. +Within your `.lightbox` element, you should have an `img` element with the `id` set to `lightbox-image`. ```js -assert.equal(document.querySelector('.lightbox #lightbox-image').tagName, 'IMG'); +assert.equal(document.querySelector(".lightbox #lightbox-image")?.tagName, "IMG"); ``` Your `.lightbox` element should have fixed positioning. ```js -assert.equal(new __helpers.CSSHelp(document).getStyle('.lightbox')?.position, 'fixed'); +assert.equal(new __helpers.CSSHelp(document).getStyle(".lightbox")?.position, "fixed"); ``` Your `.lightbox` element should cover the entire viewport. ```js -assert.equal(new __helpers.CSSHelp(document).getStyle('.lightbox')?.width, '100%'); -assert.equal(new __helpers.CSSHelp(document).getStyle('.lightbox')?.height, '100%'); +assert.equal(new __helpers.CSSHelp(document).getStyle(".lightbox")?.width, "100%"); +assert.equal(new __helpers.CSSHelp(document).getStyle(".lightbox")?.height, "100%"); ``` Your `.lightbox` element should be aligned with top left corner of the container. ```js -assert.equal(new __helpers.CSSHelp(document).getStyle('.lightbox')?.top, '0px'); -assert.equal(new __helpers.CSSHelp(document).getStyle('.lightbox')?.left, '0px'); +assert.equal(new __helpers.CSSHelp(document).getStyle(".lightbox")?.top, "0px"); +assert.equal(new __helpers.CSSHelp(document).getStyle(".lightbox")?.left, "0px"); ``` Your `.lightbox` element should have a background color. ```js -assert.isNotEmpty(new __helpers.CSSHelp(document).getStyle('.lightbox')?.backgroundColor); +assert.isNotEmpty(new __helpers.CSSHelp(document).getStyle(".lightbox")?.backgroundColor); ``` Your `.lightbox` element should be hidden initially. ```js -assert.equal(new __helpers.CSSHelp(document).getStyle('.lightbox')?.display, 'none'); +assert.equal(new __helpers.CSSHelp(document).getStyle(".lightbox")?.display, "none"); ``` When you click one of your `.gallery-item` elements, the `.lightbox` element's `display` property should be set to `flex` to make `.lightbox` and the two elements within it visible. ```js -// Get the lightbox element const lightbox = document.querySelector(".lightbox"); -// Function to get the computed style function getComputedDisplay(element) { return window.getComputedStyle(element).display; } -// Initial assertion: check if lightbox is hidden -assert.strictEqual(getComputedDisplay(lightbox), 'none'); +assert.strictEqual(getComputedDisplay(lightbox), "none"); -// Simulate a click event on a gallery item (ensure you have a reference to one) -// Here, assuming there's an element with class '.gallery-item' that triggers the display change -const galleryItem = document.querySelector('.gallery-item'); -galleryItem.dispatchEvent(new Event('click')); +const galleryItem = document.querySelector(".gallery-item"); +galleryItem.dispatchEvent(new Event("click")); -// Wait for any potential async operations to complete (if necessary) -// This might be needed if you have asynchronous operations triggered by the click event -// await new Promise(resolve => setTimeout(resolve, 100)); // Adjust timeout as needed - -// Assertion: check if lightbox is visible -assert.strictEqual(getComputedDisplay(lightbox), 'flex'); +assert.strictEqual(getComputedDisplay(lightbox), "flex"); ``` When you click one of your `.gallery-item` elements, the `#lightbox-image` element's `src` should be set to a full-size version of the image clicked by removing `-thumbnail` from the image's `src` attribute. ```js -// Select gallery items and lightbox image element const galleryItems = document.querySelectorAll(".gallery-item"); const lightboxImage = document.getElementById("lightbox-image"); assert.isAbove(galleryItems.length, 0); -// Function to extract the full-size image URL from a thumbnail URL function getFullSizeImageUrl(thumbnailUrl) { - return thumbnailUrl.replace('-thumbnail', ''); + return thumbnailUrl.replace("-thumbnail", ""); } -// Simulate a click event on each gallery item and check the lightbox image source galleryItems.forEach((item) => { - const thumbnailUrl = item.src; // The src of the clicked image + const thumbnailUrl = item.src; const expectedFullSizeUrl = getFullSizeImageUrl(thumbnailUrl); - // Simulate click event - item.dispatchEvent(new MouseEvent('click', { bubbles: true })); + item.dispatchEvent(new MouseEvent("click", { bubbles: true })); - // Wait for any async operations if needed - // await new Promise(resolve => setTimeout(resolve, 100)); // Adjust timeout as needed - - // Assert that the lightbox image src is updated correctly assert.strictEqual(lightboxImage.src, expectedFullSizeUrl); }); - ``` -When your `.lightbox` element is visible and you click the `#close` button, the `.lightbox` elements `display` should be set back to `none`. +When your `.lightbox` element is visible and you click the `#close-btn` button, the `.lightbox` element's `display` should be set back to `none`. ```js -// Get the lightbox and a background element (or the document) for simulating clicks outside const lightbox = document.querySelector(".lightbox"); -const background = document.getElementById("close"); // Assume you have an element representing the outside area +const background = document.getElementById("close-btn"); -// Function to get the computed display property function getComputedDisplay(element) { return window.getComputedStyle(element).display; } -// Make sure the lightbox is visible initially lightbox.style.display = "flex"; -// Simulate a click outside the lightbox -background.dispatchEvent(new Event('click')); +background.dispatchEvent(new Event("click")); -// Wait for any async operations if needed -// await new Promise(resolve => setTimeout(resolve, 100)); // Adjust timeout as needed - -// Assert that the lightbox is hidden after clicking outside -assert.strictEqual(getComputedDisplay(lightbox), 'none'); +assert.strictEqual(getComputedDisplay(lightbox), "none"); ``` -When your `.lightbox` element is visible and you click the `.lightbox` element, the `.lightbox` elements `display` should be set back to `none`. +When your `.lightbox` element is visible and you click the `.lightbox` element, the `.lightbox` element's `display` should be set back to `none`. ```js -// Get the lightbox element for simulating clicks outside const lightbox = document.querySelector(".lightbox"); -// Function to get the computed display property function getComputedDisplay(element) { return window.getComputedStyle(element).display; } -// Make sure the lightbox is visible initially lightbox.style.display = "flex"; -// Simulate a click inside the lightbox -lightbox.dispatchEvent(new Event('click')); +lightbox.dispatchEvent(new Event("click")); -// Wait for any async operations if needed -// await new Promise(resolve => setTimeout(resolve, 100)); // Adjust timeout as needed - -// Assert that the lightbox is hidden after clicking outside -assert.strictEqual(getComputedDisplay(lightbox), 'none'); +assert.strictEqual(getComputedDisplay(lightbox), "none"); ``` # --seed-- @@ -266,14 +234,15 @@ assert.strictEqual(getComputedDisplay(lightbox), 'none'); - + + Lightbox Viewer - + - + - + ``` @@ -291,132 +260,122 @@ assert.strictEqual(getComputedDisplay(lightbox), 'none'); ```html - - + - Image Gallery with Lightbox + Lightbox Viewer - + - -

Museum Gallery

+ +

Museum Gallery

- - - - + ``` ```css body { - margin: 0; - padding: 0; - background-color: #f0f0f0; - color: #333; + margin: 0; + padding: 0; + background-color: #f0f0f0; + color: #333; } .title { - margin-top: 100px; - display: flex; - flex-wrap: wrap; - justify-content: center; - background-color: rgb(211, 221, 224); - + margin-top: 100px; + text-align: center; + background-color: rgb(211, 221, 224); } .gallery { - display: flex; - flex-wrap: wrap; - gap: 10px; - justify-content: center; - padding: 20px; - + display: flex; + flex-wrap: wrap; + gap: 10px; + justify-content: center; + padding: 20px; } .gallery-item { - width: 250px; - height: 300px; - object-fit: cover; - cursor: pointer; - transition: transform 0.2s; + width: 250px; + height: 300px; + object-fit: cover; + cursor: pointer; + transition: transform 0.2s; } .gallery-item:hover { - transform: scale(1.05); + transform: scale(1.05); } .lightbox { - display: none; - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: rgba(0, 0, 0, 0.8); - justify-content: center; - align-items: center; - z-index: 1000; + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.8); + justify-content: center; + align-items: center; + z-index: 1000; } .lightbox img { - max-width: 90%; - max-height: 90%; + max-width: 90%; + max-height: 90%; } -.close { - position: absolute; - top: 20px; - right: 20px; - font-size: 2em; - color: white; - cursor: pointer; +.close-btn { + position: absolute; + top: 20px; + right: 10px; + font-size: 2em; + color: white; + cursor: pointer; + border: none; + background-color: transparent; } ``` ```js -// Get references to the elements -const galleryItems = document.querySelectorAll(".gallery-item"); const lightbox = document.getElementById("lightbox"); const lightboxImage = document.getElementById("lightbox-image"); -const closeButton = document.getElementById("close"); -// Function to open the lightbox function openLightbox(src) { lightboxImage.src = src; - lightbox.style.display = "flex"; // Show the lightbox + lightbox.style.display = "flex"; } -// Function to close the lightbox function closeLightbox() { - lightbox.style.display = "none"; // Hide the lightbox + lightbox.style.display = "none"; } -// Add event listener to the close button +const closeButton = document.getElementById("close-btn"); + closeButton.addEventListener("click", closeLightbox); -// Add event listener to the lightbox background - lightbox.addEventListener("click", (e) => { +lightbox.addEventListener("click", (e) => { if (e.target === lightbox) { - closeLightbox(); // Close lightbox if clicking outside the image + closeLightbox(); } }); -// Add event listeners to gallery items +const galleryItems = document.querySelectorAll(".gallery-item"); + galleryItems.forEach((item) => { item.addEventListener("click", () => { - openLightbox(item.src.replace("-thumbnail", "")); // Open lightbox with the full image + openLightbox(item.src.replace("-thumbnail", "")); }); }); ```