feat(curriculum): add blog post card lab (#56165)

Co-authored-by: Jessica Wilkins <67210629+jdwilkin4@users.noreply.github.com>
Co-authored-by: Ilenia <26656284+ilenia-magoni@users.noreply.github.com>
This commit is contained in:
Ihechikara Vincent Abba
2024-12-06 10:28:30 +01:00
committed by GitHub
parent 9d4f63920b
commit 245b486f63
5 changed files with 417 additions and 1 deletions
+6 -1
View File
@@ -2026,7 +2026,12 @@
"In these lecture videos, you will learn about working with backgrounds and borders."
]
},
"pahx": { "title": "45", "intro": [] },
"lab-blog-post-card": {
"title": "Design a Blog Post Card",
"intro": [
"In this lab, you'll design a blog post card using HTML and CSS"
]
},
"review-css-backgrounds-and-borders": {
"title": "CSS Backgrounds and Borders Review",
"intro": [
@@ -0,0 +1,9 @@
---
title: Introduction to the Design a Blog Post Card
block: lab-blog-post-card
superBlock: full-stack-developer
---
## Introduction to the Design a Blog Post Card
In this lab, you'll design a blog post card using HTML and CSS
@@ -0,0 +1,11 @@
{
"name": "Design a Blog Post Card",
"isUpcomingChange": true,
"usesMultifileEditor": true,
"dashedName": "lab-blog-post-card",
"superBlock": "full-stack-developer",
"challengeOrder": [{ "id": "66eaddd04a9e533fba689001", "title": "Design a Blog Post Card" }],
"helpCategory": "HTML-CSS",
"blockType": "lab",
"blockLayout": "link"
}
@@ -0,0 +1,390 @@
---
id: 66eaddd04a9e533fba689001
title: Design a Blog Post Card
challengeType: 14
dashedName: lab-blog-post-card
demoType: onClick
---
# --description--
In this lab, you'll practice how to style backgrounds and borders by creating a blog post card.
**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` element with a class of `blog-post-card` to hold all of your card elements.
2. Within the `.blog-post-card` `div` element, you should have an image element with a valid `alt` attribute and text, and a class of `post-img`. You can use `https://cdn.freecodecamp.org/curriculum/labs/cover-photo.jpg` for the `src` attribute of the image.
3. You should have a `div` with a class of `post-content` within the `.blog-post-card` `div` element with the following:
- An `h2` element with a class of `post-title` and text for the title of your blog post.
- A `p` element with a class of `post-excerpt` and text to summarize your blog post.
- An `a` element with a class of `read-more` with the text `Read More`.
4. You should apply the following styles to the `.blog-post-card` element:
- A white background.
- Rounded corners.
- A width of your choice.
- The text alignment of your choice.
5. The `.post-img` element should be styled so that the image fills the card's entire width and has a bottom border.
6. The `.post-content` element should be styled so that there is padding inside the card.
7. The `.post-title` and `.post-excerpt` elements should have a text color other than the default and margins on all sides.
8. The `.read-more` element should be styled like a button and have:
- A text color other than the default.
- A background color.
- Margins on all sides.
- Padding on all sides.
- Rounded corners.
- A `display` property set to `inline-block`.
- A hover effect that changes its background color.
**Note:** Be sure to link your stylesheet in your HTML and apply your CSS.
# --hints--
You should have a `div` with a class of `blog-post-card`.
```js
assert.exists(document.querySelector("div.blog-post-card"));
```
You should have an `img` element with a `class` of `post-img`. Make sure your image has an `alt` attribute with text and a `src` attribute with a value.
```js
const card = document.querySelector("div.blog-post-card");
assert.exists(card);
const img = card.querySelector("img.post-img");
assert.exists(img);
assert.isString(img.alt);
assert.isNotEmpty(img.alt);
assert.isTrue(img.hasAttribute("src"));
assert.isNotEmpty(img.getAttribute("src"));
```
You should have a `div` with class of `post-content`.
```js
const card = document.querySelector("div.blog-post-card");
assert.exists(card);
const content = card.querySelector("div.post-content");
assert.exists(content);
```
You should have an `h2` element with a class of `post-title`. Make sure it has some text content for the title of your blog post.
```js
const card = document.querySelector("div.blog-post-card");
assert.exists(card);
const content = card.querySelector("div.post-content");
assert.exists(content);
const postTitle = content.querySelector("h2.post-title");
assert.exists(postTitle);
assert.isString(postTitle.textContent);
assert.isNotEmpty(postTitle.textContent);
```
You should have a `p` with a class of `post-excerpt`. Make sure it has some text content to summarize your blog post.
```js
const card = document.querySelector("div.blog-post-card");
assert.exists(card);
const content = card.querySelector("div.post-content");
assert.exists(content);
const postExcerpt = content.querySelector("p.post-excerpt");
assert.exists(postExcerpt);
```
You should have an `a` element with a `class` of `read-more`.
```js
const card = document.querySelector("div.blog-post-card");
assert.exists(card);
const content = card.querySelector("div.post-content");
assert.exists(content);
const readMore = content.querySelector("a.read-more");
assert.exists(readMore);
```
Your `.read-more` element should have the text `Read More`.
```js
const el = document.querySelector("div.post-content a.read-more");
assert.exists(el);
assert.strictEqual(el.textContent, "Read More");
```
Your `.blog-post-card` element should have a `border-radius` property with a value (should not be `0` or a negative value).
```js
const card = document.querySelector('.blog-post-card');
assert.exists(card);
const borderRadius = getComputedStyle(card).borderRadius;
assert.isAbove(parseInt(borderRadius), 0);
```
Your `.blog-post-card` element should have a white background.
```js
const card = document.querySelector('.blog-post-card');
assert.exists(card);
const backgroundColor = getComputedStyle(card).backgroundColor;
const whiteColors = ['rgb(255, 255, 255)', 'rgba(255, 255, 255, 1)', '#ffffff', '#fff', 'white'];
assert.oneOf(backgroundColor.toLowerCase(), whiteColors);
```
You should target `.blog-post-card` and set its `width` property.
```js
assert.isNotEmpty(new __helpers.CSSHelp(document).getStyle(".blog-post-card")?.getPropertyValue("width"));
```
You should target `.blog-post-card` and set its `text-align` property.
```js
assert.isNotEmpty(new __helpers.CSSHelp(document).getStyle(".blog-post-card")?.getPropertyValue("text-align"));
```
You should target `.post-content` and set its `padding` property.
```js
assert.isNotEmpty(new __helpers.CSSHelp(document).getStyle(".post-content")?.getPropertyValue("padding"));
```
Your `.read-more` element should have a hover effect.
```js
const link = document.querySelector('.read-more');
assert.exists(link);
const stylesheet = [...document.styleSheets].find(sheet => [...sheet.rules].some(rule => rule.selectorText === '.read-more:hover'));
assert.exists(stylesheet);
const hoverRule = [...stylesheet.rules].find(rule => rule.selectorText === '.read-more:hover');
const hoverBackgroundColor = hoverRule.style.backgroundColor;
assert.isNotEmpty(hoverBackgroundColor);
```
You should target `.read-more` and set its `color` property.
```js
const readMore = document.querySelector('.read-more');
assert.exists(readMore);
const readMoreTextColor = getComputedStyle(readMore).color;
assert.notStrictEqual(readMoreTextColor, 'rgba(0, 0, 0, 0)');
```
You should target `.read-more` and set its `background-color` property.
```js
const readMore = document.querySelector('.read-more');
assert.exists(readMore);
const readMoreBackgroundColor = getComputedStyle(readMore).backgroundColor;
assert.notStrictEqual(readMoreBackgroundColor, 'rgba(0, 0, 0, 0)');
```
You should target `.read-more` and set its `margin` property.
```js
const readMore = document.querySelector('.read-more');
assert.exists(readMore);
const readMoreMargin = getComputedStyle(readMore).marginTop;
assert.notStrictEqual(readMoreMargin, '0px');
```
You should target `.read-more` and set its `display` property.
```js
const readMore = document.querySelector('.read-more');
assert.exists(readMore);
const readMoreDisplay = getComputedStyle(readMore).display;
assert.strictEqual(readMoreDisplay, 'inline-block');
```
You should target `.read-more` and set its `border-radius` property.
```js
const readMore = document.querySelector('.read-more');
assert.exists(readMore);
const readMoreBorderRadius = getComputedStyle(readMore).borderRadius;
assert.notStrictEqual(readMoreBorderRadius, '0px');
```
You should target `.read-more` and set its `padding` property.
```js
const readMore = document.querySelector('.read-more');
assert.exists(readMore);
const readMorePadding = getComputedStyle(readMore).padding;
assert.notStrictEqual(readMorePadding, '0px');
```
Your `.post-img` element should fill the card's `width` and have a `border-bottom` value.
```js
const postImg = document.querySelector('.post-img');
assert.exists(postImg);
const imgWidth = getComputedStyle(postImg).width;
const cardWidth = getComputedStyle(postImg.parentElement).width;
assert.strictEqual(imgWidth, cardWidth);
const imgBorderBottom = getComputedStyle(postImg).borderBottomWidth;
assert.notStrictEqual(imgBorderBottom, '0px');
```
Your `.post-title` and `.post-excerpt` elements should have margins and non-default text colors.
```js
const title = document.querySelector('.post-title');
const excerpt = document.querySelector('.post-excerpt');
function isColorApplied(element) {
const color = getComputedStyle(element).getPropertyValue('color');
return color && color !== 'rgba(0, 0, 0, 0)' && color !== 'transparent';
}
function isMarginApplied(element) {
const margin = getComputedStyle(element).getPropertyValue('margin');
return margin && margin !== '0px';
}
assert.isTrue(isColorApplied(title));
assert.isTrue(isMarginApplied(title));
assert.isTrue(isColorApplied(excerpt));
assert.isTrue(isMarginApplied(excerpt));
const styleSheets = [...document.styleSheets];
function hasSelectorWithColor(selector) {
return styleSheets.some(sheet => {
try {
return [...sheet.cssRules].some(rule => {
return rule.selectorText?.split(',').map(s => s.trim()).includes(selector) && rule.style.color;
});
} catch (e) {
return false;
}
});
}
assert.isTrue(hasSelectorWithColor('.post-title'));
assert.isTrue(hasSelectorWithColor('.post-excerpt'));
```
# --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>Blog Post Card</title>
</head>
<body>
</body>
</html>
```
```css
```
# --solutions--
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blog Post Card</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="blog-post-card">
<img src="https://cdn.freecodecamp.org/curriculum/labs/cover-photo.jpg" alt="Blog Post Image" class="post-img">
<div class="post-content">
<h2 class="post-title">Learn Web Development in 2024</h2>
<p class="post-excerpt">Stay ahead of the curve with the latest trends in web development. Discover what's new and exciting in 2024</p>
<a href="#" class="read-more">Read More</a>
</div>
</div>
</body>
</html>
```
```css
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f0f0f0;
font-family: Arial, sans-serif;
}
.blog-post-card {
background-color: white;
border-radius: 15px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
width: 350px;
margin: 20px;
text-align: center;
}
.post-img {
width: 100%;
height: auto;
border-bottom: 5px solid #333;
}
.post-content {
padding: 20px;
}
.post-title {
color: #333;
margin: 0 0 10px;
}
.post-excerpt {
color: #667;
margin: 10px 0;
}
.read-more {
display: inline-block;
margin-top: 10px;
padding: 10px 15px;
background-color: #333;
color: white;
text-decoration: none;
border-radius: 5px;
}
.read-more:hover {
background-color: #555;
}
```
@@ -98,6 +98,7 @@
{ "dashedName": "lecture-styling-lists-and-links" },
{ "dashedName": "lab-stylized-to-do-list" },
{ "dashedName": "lecture-working-with-backgrounds-and-borders" },
{ "dashedName": "lab-blog-post-card" },
{ "dashedName": "review-css-backgrounds-and-borders" },
{ "dashedName": "quiz-css-backgrounds-and-borders" }
]