mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
feat(curriculum): add mood board lab for React props (#57205)
Co-authored-by: moT01 <20648924+moT01@users.noreply.github.com> Co-authored-by: Kolade Chris <65571316+Ksound22@users.noreply.github.com>
This commit is contained in:
@@ -3324,7 +3324,12 @@
|
||||
]
|
||||
},
|
||||
"cdfr": { "title": "263", "intro": [] },
|
||||
"bgtd": { "title": "264", "intro": [] },
|
||||
"lab-mood-board": {
|
||||
"title": "Build a Mood Board",
|
||||
"intro": [
|
||||
"In this lab, you will create a mood board using a React with props."
|
||||
]
|
||||
},
|
||||
"review-react-basics": {
|
||||
"title": "React Basics Review",
|
||||
"intro": [
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
title: Introduction to the Build a Mood Board
|
||||
block: lab-mood-board
|
||||
superBlock: full-stack-developer
|
||||
---
|
||||
|
||||
## Introduction to the Build a Mood Board
|
||||
|
||||
In this lab, you will create a mood board using a React with props.
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "Build a Mood Board",
|
||||
"isUpcomingChange": true,
|
||||
"usesMultifileEditor": true,
|
||||
"dashedName": "lab-mood-board",
|
||||
"superBlock": "full-stack-developer",
|
||||
"challengeOrder": [{ "id": "673b3d6b7ef7318eef926d5a", "title": "Build a Mood Board" }],
|
||||
"helpCategory": "HTML-CSS",
|
||||
"blockLayout": "link",
|
||||
"blockType": "lab"
|
||||
}
|
||||
+354
@@ -0,0 +1,354 @@
|
||||
---
|
||||
id: 673b3d6b7ef7318eef926d5a
|
||||
title: Build a Mood Board
|
||||
challengeType: 14
|
||||
dashedName: build-a-mood-board
|
||||
demoType: onClick
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
A mood board is a collage of images and text that conveys a general idea, goal, or feeling about a particular topic.
|
||||
|
||||
In this lab, you will create a mood board using reusable React components. The CSS has already been provided for you.
|
||||
|
||||
Fulfil the user stories below and get all the tests to pass to complete the lab.
|
||||
|
||||
**User Stories:**
|
||||
|
||||
1. You should create and export a `MoodBoardItem` component that accepts three props: `color`, `image`, and `description`.
|
||||
2. Your `MoodBoardItem` component should return a `div` with the class `mood-board-item` as its top-level element.
|
||||
3. You should set the background color of the `.mood-board-item` element to the value of the `color` prop using inline styles.
|
||||
4. You should render an `img` element, with a class of `mood-board-image` and its `src` attribute set to the value of the `image` prop, within the `.mood-board-item` element.
|
||||
5. You should render an `h3` element, with a class of `mood-board-text` and its text the value of the `description` prop, within the `.mood-board-item` element.
|
||||
6. You should create and export a `MoodBoard`.
|
||||
7. Your `MoodBoard` component should return a `div` as its top-level element.
|
||||
8. Your `MoodBoard` component should render an `h1` element with a class of `mood-board-heading` and the text `Destination Mood Board`.
|
||||
9. Your `MoodBoard` component should render a `div` with a class of `mood-board`.
|
||||
10. Your `MoodBoard` component should render at least three `MoodBoardItem` components within the `.mood-board` element, each should pass `color`, `image`, and `description` props with valid values.
|
||||
|
||||
You can use the following images in your Mood Board if you would like:
|
||||
|
||||
- `https://cdn.freecodecamp.org/curriculum/labs/pathway.jpg`
|
||||
- `https://cdn.freecodecamp.org/curriculum/labs/shore.jpg`
|
||||
- `https://cdn.freecodecamp.org/curriculum/labs/grass.jpg`
|
||||
- `https://cdn.freecodecamp.org/curriculum/labs/ship.jpg`
|
||||
- `https://cdn.freecodecamp.org/curriculum/labs/santorini.jpg`
|
||||
- `https://cdn.freecodecamp.org/curriculum/labs/pigeon.jpg`
|
||||
|
||||
|
||||
# --hints--
|
||||
|
||||
You should export a `MoodBoardItem` component.
|
||||
|
||||
```js
|
||||
const mockedComponent = Enzyme.mount(React.createElement(window.index.MoodBoardItem));
|
||||
assert.lengthOf(mockedComponent.find('MoodBoardItem'), 1);
|
||||
```
|
||||
|
||||
Your `MoodBoardItem` component should return a `div` with a class of `mood-board-item` at its top-level element.
|
||||
|
||||
```js
|
||||
const mockedComponent = Enzyme.mount(React.createElement(window.index.MoodBoardItem));
|
||||
assert.equal(mockedComponent.childAt(0).type(), 'div');
|
||||
assert.isTrue(mockedComponent.childAt(0).hasClass('mood-board-item'));
|
||||
```
|
||||
|
||||
The background color of the `.mood-board-item` element should be set to the value of `color` prop using inline styles.
|
||||
|
||||
```js
|
||||
const mockedComponent = Enzyme.mount(React.createElement(window.index.MoodBoardItem));
|
||||
mockedComponent.setProps({ color: "colorValue" });
|
||||
assert.equal(mockedComponent.find('.mood-board-item').prop('style').backgroundColor, 'colorValue');
|
||||
```
|
||||
|
||||
Your `MoodBoardItem` component should render an `img` element with a class of `mood-board-image` and its `src` set to the value of the `image` prop.
|
||||
|
||||
```js
|
||||
const mockedComponent = Enzyme.mount(React.createElement(window.index.MoodBoardItem));
|
||||
mockedComponent.setProps({ image: "imageValue" });
|
||||
const img = mockedComponent.find('img.mood-board-image');
|
||||
assert.lengthOf(img, 1);
|
||||
assert.equal(img.prop('src'), 'imageValue');
|
||||
```
|
||||
|
||||
Your `MoodBoardItem` component should render an `h3` element with a class of `mood-board-text` and its text set to the value of the `description` prop.
|
||||
|
||||
```js
|
||||
const mockedComponent = Enzyme.mount(React.createElement(window.index.MoodBoardItem));
|
||||
mockedComponent.setProps({ description: "descriptionValue" });
|
||||
const h3 = mockedComponent.find('h3.mood-board-text');
|
||||
assert.lengthOf(h3, 1);
|
||||
assert.equal(h3.text(), 'descriptionValue');
|
||||
```
|
||||
|
||||
You should export a `MoodBoard` component.
|
||||
|
||||
```js
|
||||
const mockedComponent = Enzyme.mount(React.createElement(window.index.MoodBoard));
|
||||
assert.lengthOf(mockedComponent.find('MoodBoard'), 1);
|
||||
```
|
||||
|
||||
Your `MoodBoard` component should return a `div` as its top-level element.
|
||||
|
||||
```js
|
||||
const mockedComponent = Enzyme.mount(React.createElement(window.index.MoodBoard));
|
||||
assert.equal(mockedComponent.childAt(0).type(), 'div');
|
||||
```
|
||||
|
||||
Your `MoodBoard` component should render an `h1` element with a class of `mood-board-heading` and the text `Destination Mood Board`.
|
||||
|
||||
```js
|
||||
const mockedComponent = Enzyme.mount(React.createElement(window.index.MoodBoard));
|
||||
const h1 = mockedComponent.find('h1.mood-board-heading');
|
||||
assert.lengthOf(h1, 1);
|
||||
assert.equal(h1.text(), 'Destination Mood Board');
|
||||
```
|
||||
|
||||
Your `MoodBoard` component should render at least three `MoodBoardItem` components, each should pass `color`, `image`, and `description` props with valid values.
|
||||
|
||||
```js
|
||||
const mockedComponent = Enzyme.mount(React.createElement(window.index.MoodBoard));
|
||||
const mbItems = mockedComponent.find(window.index.MoodBoardItem);
|
||||
assert.isAtLeast(mbItems.length, 3)
|
||||
const propsList = mbItems.map(item => item.props());
|
||||
propsList.forEach(({ color, image, description }) => {
|
||||
assert.isAtLeast(color.length, 1);
|
||||
assert.isAtLeast(image.length, 1);
|
||||
assert.isAtLeast(description.length, 1);
|
||||
});
|
||||
```
|
||||
|
||||
Your `MoodBoard` component should be rendered to the page's `#root` element.
|
||||
|
||||
```js
|
||||
const mockedComponent = Enzyme.mount(React.createElement(window.index.MoodBoard));
|
||||
assert.equal(mockedComponent.html(), document.getElementById('root').innerHTML);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Mood Board</title>
|
||||
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
|
||||
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
|
||||
<script
|
||||
data-plugins="transform-modules-umd"
|
||||
type="text/babel"
|
||||
src="index.jsx"
|
||||
></script>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script
|
||||
data-plugins="transform-modules-umd"
|
||||
type="text/babel"
|
||||
data-presets="react"
|
||||
data-type="module"
|
||||
>
|
||||
import { MoodBoard } from './index.jsx';
|
||||
ReactDOM.createRoot(document.getElementById('root')).render(
|
||||
<MoodBoard />
|
||||
);
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
body {
|
||||
background-color: #ffffcc;
|
||||
}
|
||||
|
||||
.mood-board-heading {
|
||||
text-align: center;
|
||||
font-size: 2.5em;
|
||||
color: #333;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.mood-board {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 20px;
|
||||
padding: 20px;
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.mood-board-item {
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
text-align: center;
|
||||
height: 250px;
|
||||
}
|
||||
|
||||
.mood-board-image {
|
||||
border-radius: 5px;
|
||||
width: 180px;
|
||||
height:150px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.mood-board-text {
|
||||
margin-top: 20px;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
```
|
||||
|
||||
```jsx
|
||||
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Mood Board</title>
|
||||
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
|
||||
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
|
||||
<script
|
||||
data-plugins="transform-modules-umd"
|
||||
type="text/babel"
|
||||
src="index.jsx"
|
||||
></script>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script
|
||||
data-plugins="transform-modules-umd"
|
||||
type="text/babel"
|
||||
data-presets="react"
|
||||
data-type="module"
|
||||
>
|
||||
import { MoodBoard } from './index.jsx';
|
||||
ReactDOM.createRoot(document.getElementById('root')).render(
|
||||
<MoodBoard />
|
||||
);
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
body {
|
||||
background-color: #ffffcc;
|
||||
}
|
||||
|
||||
.mood-board-heading {
|
||||
text-align: center;
|
||||
font-size: 2.5em;
|
||||
color: #333;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.mood-board {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 20px;
|
||||
padding: 20px;
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.mood-board-item {
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
text-align: center;
|
||||
height: 250px;
|
||||
}
|
||||
|
||||
.mood-board-image {
|
||||
border-radius: 5px;
|
||||
width: 180px;
|
||||
height:150px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.mood-board-text {
|
||||
margin-top: 20px;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
```
|
||||
|
||||
```jsx
|
||||
export function MoodBoardItem(props) {
|
||||
return (
|
||||
<div className="mood-board-item" style={{ backgroundColor: props.color }}>
|
||||
<img src={props.image} alt="Mood" className="mood-board-image" />
|
||||
<h3 className="mood-board-text">{props.description}</h3>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function MoodBoard() {
|
||||
return (
|
||||
<div>
|
||||
<h1 className="mood-board-heading">Destination Mood Board</h1>
|
||||
<div className="mood-board">
|
||||
<MoodBoardItem
|
||||
color="#2da64f"
|
||||
image="https://cdn.freecodecamp.org/curriculum/labs/pathway.jpg"
|
||||
description="Carribean"
|
||||
/>
|
||||
<MoodBoardItem
|
||||
color="#8e44ad"
|
||||
image="https://cdn.freecodecamp.org/curriculum/labs/shore.jpg"
|
||||
description="Gawadar Beach"
|
||||
/>
|
||||
<MoodBoardItem
|
||||
color="#3498db"
|
||||
image="https://cdn.freecodecamp.org/curriculum/labs/grass.jpg"
|
||||
description="Cape Town"
|
||||
/>
|
||||
<MoodBoardItem
|
||||
color="#bf3d7e"
|
||||
image="https://cdn.freecodecamp.org/curriculum/labs/ship.jpg"
|
||||
description="Suez Canal"
|
||||
/>
|
||||
<MoodBoardItem
|
||||
color="#e74c3c"
|
||||
image="https://cdn.freecodecamp.org/curriculum/labs/santorini.jpg"
|
||||
description="Santorini"
|
||||
/>
|
||||
<MoodBoardItem
|
||||
color="#95a5a6"
|
||||
image="https://cdn.freecodecamp.org/curriculum/labs/pigeon.jpg"
|
||||
description="Istanbul"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
@@ -551,6 +551,7 @@
|
||||
{ "dashedName": "lab-reusable-footer" },
|
||||
{ "dashedName": "lecture-working-with-data-in-react" },
|
||||
{ "dashedName": "workshop-reusable-mega-navbar" },
|
||||
{ "dashedName": "lab-mood-board" },
|
||||
{ "dashedName": "review-react-basics" },
|
||||
{ "dashedName": "quiz-react-basics" }
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user