curriculum/challenges/english/blocks/lab-photography-exhibit/686e64be3cd9db25282a956d.md
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:
main-container..main-container element should also have the following Tailwind CSS utility classes:
grid-cols-<number>..main-container element, there should be at least three elements each with a class called card..card elements should also have the following Tailwind CSS utility classes:
p-<number>..card elements, you should have the following elements:
src and alt attributes.subheading.description..subheading elements should use utility classes to set the font weight and size of your choosing..description elements should use a utility class to set the font size of your choosing.You should have an element with a class called main-container.
assert.exists(document.querySelector(".main-container"));
Your .main-container element should use the correct Tailwind CSS utility class for creating a CSS Grid container.
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.
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.
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.
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.
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.
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.
const images = document.querySelectorAll(".main-container .card img");
assert.isAtLeast(images.length, 3);
Each of your img elements should have a src attribute.
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.
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.
const subheadings = document.querySelectorAll(".main-container .card .subheading");
assert.isAtLeast(subheadings.length, 3);
Each of your .subheading elements should have some text content.
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.
const descriptions = document.querySelectorAll(".main-container .card .description");
assert.isAtLeast(descriptions.length, 3);
Each of your .description elements should have some text content.
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.
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.
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.
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.
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);
});
<!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>
<!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>