feat(curriculum): add availability table lab (#55802)
Some checks are pending
i18n - Build Validation / Validate i18n Builds (20.x) (push) Waiting to run
CI - Node.js / Lint (20.x) (push) Waiting to run
CI - Node.js / Build (20.x) (push) Blocked by required conditions
CI - Node.js / Test (20.x) (push) Blocked by required conditions
CI - Node.js / Test - Upcoming Changes (20.x) (push) Blocked by required conditions
CI - Node.js / Test - i18n (italian, 20.x) (push) Blocked by required conditions
CI - Node.js / Test - i18n (portuguese, 20.x) (push) Blocked by required conditions

Co-authored-by: moT01 <20648924+moT01@users.noreply.github.com>
Co-authored-by: Sem Bauke <sem@freecodecamp.org>
This commit is contained in:
Dario-DC 2024-08-27 16:40:29 +02:00 committed by GitHub
parent c35dc47df6
commit 4957cd47f6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 627 additions and 1 deletions

View File

@ -1857,7 +1857,10 @@
"scec": { "title": "107", "intro": [] },
"mtbl": { "title": "108", "intro": [] },
"vlov": { "title": "109", "intro": [] },
"njkq": { "title": "110", "intro": [] },
"lab-availability-table": {
"title": "Build an Availability Table",
"intro": ["For this lab, you will create an availability table."]
},
"sget": { "title": "111", "intro": [] },
"huge": { "title": "112", "intro": [] },
"agbl": { "title": "113", "intro": [] },

View File

@ -0,0 +1,9 @@
---
title: Introduction to the Build an Availability Table
block: lab-availability-table
superBlock: front-end-development
---
## Introduction to the Build an Availability Table
For this lab, you will create an availability table.

View File

@ -0,0 +1,11 @@
{
"name": "Build an Availability Table",
"blockType": "lab",
"isUpcomingChange": true,
"usesMultifileEditor": true,
"dashedName": "lab-availability-table",
"order": 110,
"superBlock": "front-end-development",
"challengeOrder": [{ "id": "66b36358ed4f261d64840c24", "title": "Build an Availability Table" }],
"helpCategory": "HTML-CSS"
}

View File

@ -0,0 +1,603 @@
---
id: 66b36358ed4f261d64840c24
title: Build an Availability Table
challengeType: 14
dashedName: build-an-availability-table
demoType: onClick
---
# --description--
**Objective:** Fulfill the user stories below and get all the tests to pass to complete the lab.
**User Stories:**
1. You should have a table with at least three columns and five rows, headers included.
1. Cells in the first row should be table headers containing days of the week.
1. Cells in the first column should be table headers with a `class` of `time` and should contain time values as their text.
1. All data cells should have the `class` of `available-#`, where `#` is a number from `0` to `5` that specifies the number of available people at that time.
1. In your `:root` selector, you should define six CSS variables named `--color#`, where `#` is a number from `0` to `5`, and assign them each a color value. Use these variables to set the background color of the corresponding `.available-#` elements.
1. In your `:root` selector, you should define CSS variables named `--solid-border` and `--dashed-border`. Use these variables to style the bottom borders of your data cells, alternating between solid and dashed borders depending on the row. Give the rows either the class of `sharp` or `half` to style them.
1. You should have a `div` element with the `id` of `legend`. It should contain a `span` element with the text `Availability` and a `div` element with the `id` of `legend-gradient`.
1. You should give the `#legend-gradient` element a linear gradient that transitions between all the colors from `--color0` to `--color5`. Each color value should have two color stops (expressed as percentages) to make the transition between colors a hard line.
**Note:** Be sure to link your stylesheet in your HTML to apply your CSS.
# --hints--
You should have a `table` element.
```js
assert(!!document.querySelectorAll('table').length);
```
You should have only one `table` element.
```js
assert(document.querySelectorAll('table').length === 1);
```
Your table should have at least `5` rows.
```js
assert.isAtLeast(document.querySelectorAll('tr')?.length, 5);
```
Your table should have at least `3` columns.
```js
const rows = [...document.querySelectorAll('tr')];
assert(!!rows.length);
rows.forEach((row) => {
assert.isAtLeast(row.children.length, 3);
})
```
The first row in your table should contain at least three `th` elements.
```js
assert.isAtLeast(document.querySelectorAll('tr:first-child>th').length, 3)
```
The first row in your table should not contain `td` elements.
```js
assert(document.querySelector('tr:first-child'));
assert.lengthOf(document.querySelectorAll('tr:first-child>td'), 0)
```
You should have at least two rows with the class of `sharp`.
```js
assert.isAtLeast(document.querySelectorAll('tr[class~="sharp"]').length, 2);
```
You should have at least two rows with the class of `half`.
```js
assert.isAtLeast(document.querySelectorAll('tr[class~="half"]').length, 2);
```
`th` elements in the first column should have the `class` of `time` and the contain time values.
```js
const firstColumnData = [...document.querySelectorAll('tr th:first-child')];
assert(!!firstColumnData.length);
for (let cell of firstColumnData) {
if (cell.innerText.match(/\d/)?.length) {
assert(cell.classList.contains('time'));
}
}
```
You should have at least four `th` elements with the class of `time` that contain time values.
```js
const timeClass = document.querySelectorAll('.time');
assert.isAtLeast(timeClass.length, 4);
for (let cell of timeClass) {
assert(cell.innerText.match(/\d/)?.length)
}
```
All your `td` elements should have the `class` of `available-#`, where `#` is a number from `0` to `5`.
```js
const cells = [...document.querySelectorAll('tr[class="sharp"]>td, tr[class="half"]>td')];
assert(!!cells.length);
for (let cell of cells) {
const classString = [...cell.classList].join(' ');
assert.lengthOf(classString.match(/(?<=\s|^)available-[0-5](?=\s|$)/gm), 1);
}
```
You should have at least eight `.available-#` elements, where `#` is a number between `0` and `5`.
```js
assert.isAtLeast(document.querySelectorAll('td[class*="available-"]').length, 8);
```
You should define a `--color0` variable in your root selector.
```js
const root = new __helpers.CSSHelp(document).getStyle(':root');
assert(!!root && root.getPropVal('--color0'));
```
You should define a `--color1` variable in your root selector.
```js
const root = new __helpers.CSSHelp(document).getStyle(':root');
assert(!!root && root.getPropVal('--color1'));
```
You should define a `--color2` variable in your root selector.
```js
const root = new __helpers.CSSHelp(document).getStyle(':root');
assert(!!root && root.getPropVal('--color2'));
```
You should define a `--color3` variable in your root selector.
```js
const root = new __helpers.CSSHelp(document).getStyle(':root');
assert(!!root && root.getPropVal('--color3'));
```
You should define a `--color4` variable in your root selector.
```js
const root = new __helpers.CSSHelp(document).getStyle(':root');
assert(!!root && root.getPropVal('--color4'));
```
You should define a `--color5` variable in your root selector.
```js
const root = new __helpers.CSSHelp(document).getStyle(':root');
assert(!!root && root.getPropVal('--color5'));
```
You should use `--color0` to set the background color of `.available-0` elements.
```js
const a = new __helpers.CSSHelp(document).getStyle('.available-0');
assert(!!a && a.backgroundColor === 'var(--color0)');
```
You should use `--color1` to set the background color of `.available-1` elements.
```js
const a = new __helpers.CSSHelp(document).getStyle('.available-1');
assert(!!a && a.backgroundColor === 'var(--color1)');
```
You should use `--color2` to set the background color of `.available-2` elements.
```js
const a = new __helpers.CSSHelp(document).getStyle('.available-2');
assert(!!a && a.backgroundColor === 'var(--color2)');
```
You should use `--color3` to set the background color of `.available-3` elements.
```js
const a = new __helpers.CSSHelp(document).getStyle('.available-3');
assert(!!a && a.backgroundColor === 'var(--color3)');
```
You should use `--color4` to set the background color of `.available-4` elements.
```js
const a = new __helpers.CSSHelp(document).getStyle('.available-4');
assert(!!a && a.backgroundColor === 'var(--color4)');
```
You should use `--color5` to set the background color of `.available-5` elements.
```js
const a = new __helpers.CSSHelp(document).getStyle('.available-5');
assert(!!a && a.backgroundColor === 'var(--color5)');
```
You should define a `--solid-border` variable in your root selector.
```js
const root = new __helpers.CSSHelp(document).getStyle(':root');
assert(!!root && root.getPropVal('--solid-border'));
```
You should define a `--dashed-border` variable in your root selector.
```js
const root = new __helpers.CSSHelp(document).getStyle(':root');
assert(!!root && root.getPropVal('--dashed-border'));
```
You should target `td` elements that are children of `.sharp` elements.
```js
const tds = new __helpers.CSSHelp(document).getStyle('.sharp td') || new __helpers.CSSHelp(document).getStyle('.sharp>td');
assert(tds);
```
You should use `--solid-border` to set the `bottom-border` of `td` elements that are children of `.sharp` elements.
```js
const tds = new __helpers.CSSHelp(document).getStyle('.sharp td') || new __helpers.CSSHelp(document).getStyle('.sharp>td');
assert(tds && tds.borderBottom === 'var(--solid-border)');
```
You should target `td` elements that are children of `.half` elements.
```js
const tds = new __helpers.CSSHelp(document).getStyle('.half td') || new __helpers.CSSHelp(document).getStyle('.half>td');
assert(tds);
```
You should use `--dashed-border` to set the `bottom-border` of `td` elements of `.half` elements.
```js
const tds = new __helpers.CSSHelp(document).getStyle('.half td') || new __helpers.CSSHelp(document).getStyle('.half>td');
assert(tds && tds.borderBottom === 'var(--dashed-border)');
```
You should have a `div` element with the `id` of `legend`.
```js
assert.equal(document.querySelector('#legend')?.tagName, 'DIV');
```
You should have a `span` element with the text `Availability` inside your `#legend`.
```js
assert.equal(document.querySelector('#legend span')?.innerText, 'Availability');
```
You should have a `div` element with the `id` of `legend-gradient` inside your `#legend`.
```js
assert.equal(document.querySelector('#legend #legend-gradient')?.tagName, 'DIV');
```
You should set the background image of `#legend-gradient` to a linear gradient.
```js
const legendGradient = new __helpers.CSSHelp(document).getStyle('#legend-gradient');
assert(!!legendGradient && legendGradient.backgroundImage.includes('linear-gradient('))
```
You should use two color-stops (expressed in percentage) to make the transition from one color to the following color a hard line for your `#legend-gradient`. Remember to use your `--color#` variables.
```js
const legendGradient = new __helpers.CSSHelp(document).getStyle('#legend-gradient');
assert(!!legendGradient && legendGradient.backgroundImage.match(/var\(\s*--color[0-5]\s*\)\s+\d+%\s+\d+%/g).length === 6)
```
# --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>Availability Table</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>Availability Table</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<main>
<table>
<tbody>
<tr class="sharp">
<th rowspan="2" class="time">9 AM</th>
<th>Monday</th>
<th>Tuesday</th>
<th>Wednesday</th>
<th>Thursday</th>
<th>Friday</th>
</tr>
<tr class="half">
<td class="available-0"></td>
<td class="available-1"></td>
<td class="available-2"></td>
<td class="available-2"></td>
<td class="available-5"></td>
</tr>
<tr class="sharp">
<th rowspan="2" class="time">10 AM</th>
<td class="available-3"></td>
<td class="available-4"></td>
<td class="available-4"></td>
<td class="available-5"></td>
<td class="available-5"></td>
</tr>
<tr class="half">
<td class="available-3"></td>
<td class="available-4"></td>
<td class="available-5"></td>
<td class="available-5"></td>
<td class="available-5"></td>
</tr>
<tr class="sharp">
<th rowspan="2" class="time">11 AM</th>
<td class="available-0"></td>
<td class="available-2"></td>
<td class="available-4"></td>
<td class="available-4"></td>
<td class="available-0"></td>
</tr>
<tr class="half">
<td class="available-3"></td>
<td class="available-4"></td>
<td class="available-1"></td>
<td class="available-5"></td>
<td class="available-5"></td>
</tr>
<tr class="sharp">
<th rowspan="2" class="time">12 PM</th>
<td class="available-5"></td>
<td class="available-5"></td>
<td class="available-3"></td>
<td class="available-2"></td>
<td class="available-0"></td>
</tr>
<tr class="half">
<td class="available-3"></td>
<td class="available-0"></td>
<td class="available-4"></td>
<td class="available-5"></td>
<td class="available-5"></td>
</tr>
<tr class="sharp">
<th rowspan="2" class="time">1 PM</th>
<td class="available-2"></td>
<td class="available-3"></td>
<td class="available-3"></td>
<td class="available-2"></td>
<td class="available-0"></td>
</tr>
<tr class="half">
<td class="available-3"></td>
<td class="available-4"></td>
<td class="available-4"></td>
<td class="available-5"></td>
<td class="available-5"></td>
</tr>
<tr class="sharp">
<th rowspan="2" class="time">2 PM</th>
<td class="available-0"></td>
<td class="available-3"></td>
<td class="available-4"></td>
<td class="available-4"></td>
<td class="available-4"></td>
</tr>
<tr class="half">
<td class="available-3"></td>
<td class="available-4"></td>
<td class="available-4"></td>
<td class="available-5"></td>
<td class="available-5"></td>
</tr>
<tr class="sharp">
<th rowspan="2" class="time">3 PM</th>
<td class="available-3"></td>
<td class="available-3"></td>
<td class="available-4"></td>
<td class="available-5"></td>
<td class="available-4"></td>
</tr>
<tr class="half">
<td class="available-3"></td>
<td class="available-4"></td>
<td class="available-4"></td>
<td class="available-5"></td>
<td class="available-5"></td>
</tr>
<tr class="sharp">
<th rowspan="2" class="time">4 PM</th>
<td class="available-5"></td>
<td class="available-5"></td>
<td class="available-5"></td>
<td class="available-4"></td>
<td class="available-4"></td>
</tr>
<tr class="half">
<td class="available-3"></td>
<td class="available-0"></td>
<td class="available-4"></td>
<td class="available-2"></td>
<td class="available-5"></td>
</tr>
<tr class="sharp">
<th rowspan="2" class="time">5 PM</th>
<td class="available-5"></td>
<td class="available-5"></td>
<td class="available-5"></td>
<td class="available-3"></td>
<td class="available-4"></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<div id="legend">
<span id="legend-title">Availability</span>
<div id="legend-line"><span>0</span>
<div id="legend-gradient"></div><span>5+</span>
</div>
</div>
</main>
</body>
</html>
```
```css
:root {
font-size: 16px;
font-family: Arial, Helvetica, sans-serif;
--color0: hsl(0, 0%, 100%);
--color1: hsl(120, 95%, 90%);
--color2: hsl(120, 95%, 80%);
--color3: hsl(120, 95%, 65%);
--color4: hsl(120, 95%, 40%);
--color5: hsl(120, 95%, 25%);
--solid-border: 0.1rem solid black;
--dashed-border: 0.09rem dashed black;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: hsl(150, 30%, 75%);
width: 100vw;
height: 100vh;
}
main {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-evenly;
}
table {
border-collapse: collapse;
table-layout: fixed;
width: 32rem;
}
tr {
height: 1.1rem;
}
tr :first-child {
width: 4rem;
}
td {
border-right: var(--solid-border);
border-left: var(--solid-border);
}
.sharp td {
border-bottom: var(--solid-border);
}
.sharp th:not([class*="time"]) {
border-bottom: var(--solid-border);
}
.half td {
border-bottom: var(--dashed-border);
}
tbody :last-child td {
border: 0;
}
.time {
text-align: right;
border: 0;
padding: 0.4rem;
}
.available-0 {
background-color: var(--color0);
}
.available-1 {
background-color: var(--color1);
}
.available-2 {
background-color: var(--color2);
}
.available-3 {
background-color: var(--color3);
}
.available-4 {
background-color: var(--color4);
}
.available-5 {
background-color: var(--color5);
}
#legend {
display: flex;
flex-direction: column;
align-items: center;
width: 18rem;
height: 3.5rem;
text-align: center;
}
#legend span {
display: inline-block;
width: 5rem;
height: 2rem;
}
#legend-gradient {
width: 100%;
height: 60%;
border: var(--solid-border);
background-image: linear-gradient(90deg,
var(--color0) 0% 17%,
var(--color1) 17% 34%,
var(--color2) 34% 50%,
var(--color3) 50% 67%,
var(--color4) 67% 83%,
var(--color5) 83% 100%);
}
#legend-line {
width: 60%;
height: 100%;
display: flex;
}
```