Back to Freecodecamp

Design a Photography Exhibit

curriculum/challenges/english/blocks/lab-photography-exhibit/686e64be3cd9db25282a956d.md

latest12.0 KB
Original Source

--description--

In this lab, you'll create a photography exhibit layout using Tailwind CSS utility classes.

For the images, you can use the following URLs if you like:

Objective: Fulfill the user stories below and get all the tests to pass to complete the lab.

User Stories:

  1. You should have an element with a class called main-container.
  2. Your .main-container element should also have the following Tailwind CSS utility classes:
    • the correct utility class for creating a CSS Grid container.
    • a utility class for defining the number of columns within the grid. You should use the utility class that utilizes the fixed number of columns. Ex. grid-cols-<number>.
    • a utility class for setting the row and column gap for the grid items.
  3. Inside your .main-container element, there should be at least three elements each with a class called card.
  4. Each of your .card elements should also have the following Tailwind CSS utility classes:
    • a utility class for setting a rounded border of your choice.
    • a utility class for setting padding of your choice. You should use this format p-<number>.
  5. Inside each of your .card elements, you should have the following elements:
    • an image element with src and alt attributes.
    • an element with the class called subheading.
    • an element with the class called description.
  6. Each of your image elements should have a utility class for setting a rounded border of your choice.
  7. Each of your .subheading elements should use utility classes to set the font weight and size of your choosing.
  8. Each of your .description elements should use a utility class to set the font size of your choosing.

--hints--

You should have an element with a class called main-container.

js
assert.exists(document.querySelector(".main-container"));

Your .main-container element should use the correct Tailwind CSS utility class for creating a CSS Grid container.

js
const mainContainer = document.querySelector(".main-container");
assert.isTrue(mainContainer.classList.contains("grid"));

Your .main-container element should use a utility class for defining the number of columns within the grid.

js
const mainContainer = document.querySelector(".main-container");
// Grid classes can vary, so this check is for the presence of any grid-cols class
const hasGridCols = [...mainContainer.classList].some(className => className.startsWith("grid-cols-"));
assert.isTrue(hasGridCols);

Your .main-container element should use a utility class for setting the row and column gap for the grid items.

js
const mainContainer = document.querySelector(".main-container");
// Check for any gap class including gap-x and gap-y

const hasGap = [...mainContainer.classList].some(c => c.startsWith("gap-")) ||
  (classList.some(c => c.startsWith("gap-x-")) &&
   classList.some(c => c.startsWith("gap-y-")));

assert.isTrue(hasGap);

Your .main-container element should contain at least three elements each with a class called card.

js
const cards = document.querySelectorAll(".main-container .card");
assert.isAtLeast(cards.length, 3);

Each of your .card elements should have a utility class for setting a rounded border.

js
const cards = document.querySelectorAll(".main-container .card");
assert.isNotEmpty(cards);

const predefinedRoundedCorners = [
  "rounded-none",
  "rounded-sm",
  "rounded",
  "rounded-md",
  "rounded-lg",
  "rounded-xl",
  "rounded-2xl",
  "rounded-3xl",
  "rounded-full"
];

cards.forEach(card => {
  const hasRoundedCorners = predefinedRoundedCorners.some(corner => card.classList.contains(corner));
  assert.isTrue(hasRoundedCorners);
})

Each of your .card elements should have a utility class for setting padding.

js
const cards = document.querySelectorAll(".main-container .card");
assert.isNotEmpty(cards);
const hasPadding = [...cards].every(card => {
  return [...card.classList].some(c => c.startsWith("p-"));
});
assert.isTrue(hasPadding);

Each of your .card elements should contain an image element.

js
const images = document.querySelectorAll(".main-container .card img");
assert.isAtLeast(images.length, 3);

Each of your img elements should have a src attribute.

js
const images = document.querySelectorAll(".main-container .card img");
assert.isAtLeast(images.length, 3);
images.forEach(img => assert.isTrue(img.hasAttribute("src")));
images.forEach(img => assert.isTrue(img.getAttribute("src").length > 0));

Each of your img elements should have an alt attribute.

js
const images = document.querySelectorAll(".main-container .card img");
assert.isAtLeast(images.length, 3);
images.forEach(img => assert.isTrue(img.hasAttribute("alt")));
images.forEach(img => assert.isTrue(img.getAttribute("alt").length > 0));

Each of your .card elements should contain an element with the class called subheading.

js
const subheadings = document.querySelectorAll(".main-container .card .subheading");
assert.isAtLeast(subheadings.length, 3);

Each of your .subheading elements should have some text content.

js
const subheadings = document.querySelectorAll(".main-container .card .subheading");
// Ensure we are not dealing with an empty NodeList
assert.isNotEmpty(subheadings);

subheadings.forEach(subheading => {
  assert.isNotEmpty(subheading.textContent.trim());
});

Each of your .card elements should contain an element with the class called description.

js
const descriptions = document.querySelectorAll(".main-container .card .description");
assert.isAtLeast(descriptions.length, 3);

Each of your .description elements should have some text content.

js
const descriptions = document.querySelectorAll(".main-container .card .description");
// Ensure we are not dealing with an empty NodeList
assert.isNotEmpty(descriptions);

descriptions.forEach(description => {
  assert.isNotEmpty(description.textContent.trim());
});

Each of your img elements should have a utility class for setting a rounded border.

js
const images = document.querySelectorAll(".main-container .card img");
assert.isNotEmpty(images);
const predefinedRoundedCorners = [
  "rounded-none",
  "rounded-sm",
  "rounded",
  "rounded-md",
  "rounded-lg",
  "rounded-xl",
  "rounded-2xl",
  "rounded-3xl",
  "rounded-full"
];

images.forEach(img => {
  const hasRoundedCorners = predefinedRoundedCorners.some(corner => img.classList.contains(corner));
  assert.isTrue(hasRoundedCorners);
});

Each of your .subheading elements should use utility classes to set the font weight.

js
const subheadings = document.querySelectorAll(".main-container .card .subheading");
assert.isNotEmpty(subheadings);
const predefinedFontWeights = [
  "font-thin",
  "font-extralight",
  "font-light",
  "font-normal",
  "font-medium",
  "font-semibold",
  "font-bold",
  "font-extrabold",
  "font-black"
];

subheadings.forEach(subheading => {
  const hasFontWeight = predefinedFontWeights.some(weight => subheading.classList.contains(weight));
  assert.isTrue(hasFontWeight);
});

Each of your .subheading elements should use utility classes to set the font size.

js
const subheadings = document.querySelectorAll(".main-container .card .subheading");
assert.isNotEmpty(subheadings);
const predefinedSizes = [
  "text-xs",
  "text-sm",
  "text-base",
  "text-lg",
  "text-xl",
  "text-2xl",
  "text-3xl",
  "text-4xl",
  "text-5xl",
  "text-6xl",
  "text-7xl",
  "text-8xl",
  "text-9xl"
];

subheadings.forEach(subheading => {
  const hasFontSize = predefinedSizes.some(size => subheading.classList.contains(size));
  assert.isTrue(hasFontSize);
});

Each of your .description elements should use a utility class to set the font size.

js
const descriptions = document.querySelectorAll(".description");
assert.isNotEmpty(descriptions);
const predefinedSizes = [
  "text-xs",
  "text-sm",
  "text-base",
  "text-lg",
  "text-xl",
  "text-2xl",
  "text-3xl",
  "text-4xl",
  "text-5xl",
  "text-6xl",
  "text-7xl",
  "text-8xl",
  "text-9xl"
];

descriptions.forEach(description => {
  const hasFontSize = predefinedSizes.some(size => description.classList.contains(size));
  assert.isTrue(hasFontSize);
});

--seed--

--seed-contents--

html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Photography Exhibit</title>
    <script src="https://cdn.tailwindcss.com"></script>
  </head>
  <body>
 
  </body>
</html>

--solutions--

html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Photography Exhibit</title>
    <script src="https://cdn.tailwindcss.com"></script>
  </head>
  <body class="bg-purple-800 text-yellow-400 min-h-screen">
    <h1 class="text-center text-4xl font-bold my-12">Photography Exhibit</h1>

    <main class="main-container grid grid-cols-1 md:grid-cols-3 gap-8 px-4">
      <figure
        class="card bg-purple-900 border border-yellow-400 rounded-lg p-4"
      >
        
        <figcaption>
          <h2 class="subheading text-lg font-semibold mb-2">Colosseum, Rome</h2>
          <p class="description text-sm mb-4">
            There is so much history and beauty. The light hits it just right.
          </p>
          <div class="grid grid-cols-2 gap-4">
            <button
              class="bg-purple-800 hover:bg-purple-700 border border-yellow-400 py-1 px-2 rounded-md"
            >
              Like
            </button>
            <a
              href="#"
              class="bg-yellow-400 hover:bg-yellow-300 text-purple-900 font-semibold py-1 px-2 rounded-md text-center"
            >
              View Details
            </a>
          </div>
        </figcaption>
      </figure>

      <figure
        class="card bg-purple-900 border border-yellow-400 rounded-lg p-4"
      >
        
        <figcaption>
          <h2 class="subheading text-lg font-semibold mb-2">The Alps</h2>
          <p class="description text-sm mb-4">
            The mountains go on forever and the view is breathtaking.
          </p>
          <div class="grid grid-cols-2 gap-4">
            <button
              class="bg-purple-800 hover:bg-purple-700 border border-yellow-400 py-1 px-2 rounded-md"
            >
              Like
            </button>
            <a
              href="#"
              class="bg-yellow-400 hover:bg-yellow-300 text-purple-900 font-semibold py-1 px-2 rounded-md text-center"
            >
              View Details
            </a>
          </div>
        </figcaption>
      </figure>

      <figure
        class="card bg-purple-900 border border-yellow-400 rounded-lg p-4"
      >
        
        <figcaption>
          <h2 class="subheading text-lg font-semibold mb-2">Seascape</h2>
          <p class="description text-sm mb-4">
            The water was still, the air was cool and the feeling is pure peace.
          </p>
          <div class="grid grid-cols-2 gap-4">
            <button
              class="bg-purple-800 hover:bg-purple-700 border border-yellow-400 py-1 px-2 rounded-md"
            >
              Like
            </button>
            <a
              href="#"
              class="bg-yellow-400 hover:bg-yellow-300 text-purple-900 font-semibold py-1 px-2 rounded-md text-center"
            >
              View Details
            </a>
          </div>
        </figcaption>
      </figure>
    </main>
  </body>
</html>