From ab5837c844a336bae3bd0677047f7cf77347dc7c Mon Sep 17 00:00:00 2001 From: Zaira <33151350+zairahira@users.noreply.github.com> Date: Tue, 17 Sep 2024 00:48:41 +0500 Subject: [PATCH] feat(curriculum): add lightbox lab (#56056) Co-authored-by: Dario-DC <105294544+Dario-DC@users.noreply.github.com> --- client/i18n/locales/english/intro.json | 7 +- .../lab-lightbox-viewer/index.md | 9 + .../_meta/lab-lightbox-viewer/meta.json | 11 + .../66db57ad34c7089b9b41bfd6.md | 398 ++++++++++++++++++ 4 files changed, 424 insertions(+), 1 deletion(-) create mode 100644 client/src/pages/learn/front-end-development/lab-lightbox-viewer/index.md create mode 100644 curriculum/challenges/_meta/lab-lightbox-viewer/meta.json create mode 100644 curriculum/challenges/english/25-front-end-development/lab-lightbox-viewer/66db57ad34c7089b9b41bfd6.md diff --git a/client/i18n/locales/english/intro.json b/client/i18n/locales/english/intro.json index 4bcdd2c027d..a20bd91842f 100644 --- a/client/i18n/locales/english/intro.json +++ b/client/i18n/locales/english/intro.json @@ -2032,7 +2032,12 @@ "intro": ["In this lab, you will build a real-time character counter"] }, "fmbk": { "title": "196", "intro": [] }, - "nlbo": { "title": "197", "intro": [] }, + "lab-lightbox-viewer": { + "title": "Build a Lightbox Viewer", + "intro": [ + "In this lab, you will build a lighbox viewer for viewing images in a focused mode." + ] + }, "workshop-rps-game": { "title": "Build a Rock, Paper, Scissors Game", "intro": [ diff --git a/client/src/pages/learn/front-end-development/lab-lightbox-viewer/index.md b/client/src/pages/learn/front-end-development/lab-lightbox-viewer/index.md new file mode 100644 index 00000000000..a6245fc8ad5 --- /dev/null +++ b/client/src/pages/learn/front-end-development/lab-lightbox-viewer/index.md @@ -0,0 +1,9 @@ +--- +title: Introduction to the Build a Lightbox Viewer +block: lab-lightbox-viewer +superBlock: front-end-development +--- + +## Introduction to the Build a Lightbox Viewer + +In this lab, you will build a lighbox viewer for viewing images in a focused mode. diff --git a/curriculum/challenges/_meta/lab-lightbox-viewer/meta.json b/curriculum/challenges/_meta/lab-lightbox-viewer/meta.json new file mode 100644 index 00000000000..5cc0b165b5d --- /dev/null +++ b/curriculum/challenges/_meta/lab-lightbox-viewer/meta.json @@ -0,0 +1,11 @@ +{ + "name": "Build a Lightbox Viewer", + "isUpcomingChange": true, + "usesMultifileEditor": true, + "dashedName": "lab-lightbox-viewer", + "order": 197, + "superBlock": "front-end-development", + "challengeOrder": [{ "id": "66db57ad34c7089b9b41bfd6", "title": "Build a Lightbox Viewer" }], + "helpCategory": "HTML-CSS", + "blockType": "lab" +} 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 new file mode 100644 index 00000000000..ae061014619 --- /dev/null +++ b/curriculum/challenges/english/25-front-end-development/lab-lightbox-viewer/66db57ad34c7089b9b41bfd6.md @@ -0,0 +1,398 @@ +--- +id: 66db57ad34c7089b9b41bfd6 +title: Build a Lightbox Viewer +challengeType: 14 +dashedName: build-a-lightbox-viewer +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. + +**Objective:** Fulfill the user stories below and get all the tests to pass to complete the lab. + +**User Stories:** + +1. You should have a `div` with a class of `gallery` within your `body`. +1. Within the `.gallery` element, you should have three image thumbnails, each with a class of `gallery-item`. You should use the following links for thumbnail images: + + - `https://cdn.freecodecamp.org/curriculum/labs/stonehenge-thumbnail.jpg` + - `https://cdn.freecodecamp.org/curriculum/labs/storm-thumbnail.jpg` + - `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 `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. `.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-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`. + +**Note:** Be sure to link your stylesheet and the JavaScript file in your HTML. + +# --hints-- + +You should have a `div` with the class of `gallery` inside your `body` element. + +```js +assert.equal(document.querySelector('body .gallery')?.tagName, 'DIV'); +``` + +Within the `.gallery` `div`, you should have three image elements with the class of `gallery-item`. + +```js +assert.equal(document.querySelectorAll('.gallery .gallery-item').length, 3); +``` + +Within the `.gallery` `div`, you should an image element with the `src` set to `https://cdn.freecodecamp.org/curriculum/labs/stonehenge-thumbnail.jpg`. + +```js +const images = document.querySelectorAll('.gallery .gallery-item'); +let srcCount = 0; +const targetSrc = 'https://cdn.freecodecamp.org/curriculum/labs/stonehenge-thumbnail.jpg'; + +for (let image of images) { + if (image.src === targetSrc) { + srcCount++; + } +} + +assert(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`. + +```js +const images = document.querySelectorAll('.gallery .gallery-item'); +let srcCount = 0; +const targetSrc = 'https://cdn.freecodecamp.org/curriculum/labs/storm-thumbnail.jpg'; + +for (let image of images) { + if (image.src === targetSrc) { + srcCount++; + } +} + +assert(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`. + +```js +const images = document.querySelectorAll('.gallery .gallery-item'); +let srcCount = 0; +const targetSrc = 'https://cdn.freecodecamp.org/curriculum/labs/trees-thumbnail.jpg'; + +for (let image of images) { + if (image.src === targetSrc) { + srcCount++; + } +} + +assert(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')); +``` + +Within your `.lightbox` `div`, you should have a `span` element with the `id` set to `close`. + +```js +assert.equal(document.querySelector('.lightbox #close').tagName, 'SPAN'); +``` + +Within your `.lightbox` `div`, you should have an `img` element with the `id` set to `lightbox-image`. + +```js +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'); +``` + +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%'); +``` + +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'); +``` + +Your `.lightbox` element should have a background color. + +```js +assert(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'); +``` + +When you click one of your `.gallery-item` elements, the `.lightbox` element’s `display` property should be set to `flex` to make 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'); + +// 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')); + +// 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'); +``` + +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', ''); +} + +// 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 expectedFullSizeUrl = getFullSizeImageUrl(thumbnailUrl); + + // Simulate click event + 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 anywhere outside the image, the `.lightbox` elements `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 + +// Function to get the computed display property +function getComputedDisplay(element) { + return window.getComputedStyle(element).display; +} + +// Make sure the lightbox is visible initially +assert.strictEqual(getComputedDisplay(lightbox), 'flex'); + +// Simulate a click outside the lightbox +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'); +``` + +# --seed-- + +## --seed-contents-- + +```html + + + +
+ +