mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
feat(curriculum): add html music player workshop (#65825)
Co-authored-by: Jeevankumar S <110320697+Jeevankumar-s@users.noreply.github.com> Co-authored-by: Dario <105294544+Dario-DC@users.noreply.github.com> Co-authored-by: Sem Bauke <sem@freecodecamp.org>
This commit is contained in:
@@ -5221,6 +5221,13 @@
|
||||
"In these lectures, you will learn how to work with the <code>audio</code> and <code>video</code> elements."
|
||||
]
|
||||
},
|
||||
"workshop-html-music-player": {
|
||||
"title": "Build an HTML Music Player",
|
||||
"intro": [
|
||||
"In this workshop, you'll use HTML to create a basic music player.",
|
||||
"This project will cover the <code>audio</code> element, the audio player setup, and more."
|
||||
]
|
||||
},
|
||||
"workshop-html-video-player": {
|
||||
"title": "Build an HTML Video Player",
|
||||
"intro": [
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
---
|
||||
id: 698c4e69abe14a9746c72312
|
||||
title: Step 1
|
||||
challengeType: 0
|
||||
dashedName: step-1
|
||||
demoType: onLoad
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In this workshop, you will build an HTML music player. The HTML boilerplate has been provided for you.
|
||||
|
||||
Create an `h1` element and give it the text `freeCodeCamp Tunes`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have an `h1` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('h1'));
|
||||
```
|
||||
|
||||
Your `h1` element should contain the text `freeCodeCamp Tunes`.
|
||||
|
||||
```js
|
||||
const h1 = document.querySelector('h1');
|
||||
assert.strictEqual(h1?.textContent.trim(), 'freeCodeCamp Tunes');
|
||||
```
|
||||
|
||||
# --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>Working with the HTML Audio Element</title>
|
||||
</head>
|
||||
<body>
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
---
|
||||
id: 698c4f4e965bd853ad5084e1
|
||||
title: Step 2
|
||||
challengeType: 0
|
||||
dashedName: step-2
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Below the `h1`, add an `h2` element with the text `Can't Stay Down`, this is the title of the first song.
|
||||
|
||||
Below the `h2` element add a `p` element with the text `Artist: Quincy Larson`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have an `h2` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('h2'));
|
||||
```
|
||||
|
||||
Your `h2` element should be below the `h1` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('h1 + h2'));
|
||||
```
|
||||
|
||||
Your `h2` element should contain the text `Can't Stay Down`.
|
||||
|
||||
```js
|
||||
const h2 = document.querySelector('h2');
|
||||
assert.strictEqual(h2?.textContent.trim(), "Can't Stay Down");
|
||||
```
|
||||
|
||||
You should have a `p` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('p'));
|
||||
```
|
||||
|
||||
Your `p` element should contain the text `Artist: Quincy Larson`.
|
||||
|
||||
```js
|
||||
const p = document.querySelector('p');
|
||||
assert.strictEqual(p?.textContent.trim(), 'Artist: Quincy Larson');
|
||||
```
|
||||
|
||||
# --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>Working with the HTML Audio Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>freeCodeCamp Tunes</h1>
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
---
|
||||
id: 698c4fe24f1f1a17be74a23e
|
||||
title: Step 3
|
||||
challengeType: 0
|
||||
dashedName: step-3
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Next, create an `audio` element below the `p` element. Over the next few steps, you will add the necessary attributes to make the audio element play music.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have an `audio` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('audio'));
|
||||
```
|
||||
|
||||
The new `audio` element should be below the `p` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('p + audio'));
|
||||
```
|
||||
|
||||
# --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>Working with the HTML Audio Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>freeCodeCamp Tunes</h1>
|
||||
|
||||
<h2>Can't Stay Down</h2>
|
||||
<p>Artist: Quincy Larson</p>
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
---
|
||||
id: 698c50535b54b2d75fa985fb
|
||||
title: Step 5
|
||||
challengeType: 0
|
||||
dashedName: step-5
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The `loop` attribute will restart the audio once playback is completed. Think of an internet meme that repeats playback. Omitting the `loop` attribute will make the audio play once.
|
||||
|
||||
The `loop` attribute is a boolean attribute and does not need a value.
|
||||
|
||||
Add the `loop` attribute to the `audio` element.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `audio` element should have the `loop` attribute.
|
||||
|
||||
```js
|
||||
const audio = document.querySelector('audio');
|
||||
assert.isTrue(audio?.hasAttribute('loop'));
|
||||
```
|
||||
|
||||
# --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>Working with the HTML Audio Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>freeCodeCamp Tunes</h1>
|
||||
|
||||
<h2>Can't Stay Down</h2>
|
||||
<p>Artist: Quincy Larson</p>
|
||||
|
||||
--fcc-editable-region--
|
||||
<audio src="https://cdn.freecodecamp.org/curriculum/js-music-player/can't-stay-down.mp3"></audio>
|
||||
--fcc-editable-region--
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
---
|
||||
id: 698c513508507ec8bb820227
|
||||
title: Step 4
|
||||
challengeType: 0
|
||||
dashedName: step-4
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
To specify the media resource for the audio, you will need to add the `src` attribute to the `audio` element.
|
||||
|
||||
Add the `src` attribute with the value `https://cdn.freecodecamp.org/curriculum/js-music-player/can't-stay-down.mp3`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `audio` element should have a `src` attribute.
|
||||
|
||||
```js
|
||||
const audio = document.querySelector('audio');
|
||||
assert.isTrue(audio?.hasAttribute('src'));
|
||||
```
|
||||
|
||||
Your `audio` element should have a `src` attribute with the value `https://cdn.freecodecamp.org/curriculum/js-music-player/can't-stay-down.mp3`.
|
||||
|
||||
```js
|
||||
const audio = document.querySelector('audio');
|
||||
assert.strictEqual(audio?.getAttribute('src'),
|
||||
"https://cdn.freecodecamp.org/curriculum/js-music-player/can't-stay-down.mp3");
|
||||
```
|
||||
|
||||
# --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>Working with the HTML Audio Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>freeCodeCamp Tunes</h1>
|
||||
|
||||
<h2>Can't Stay Down</h2>
|
||||
<p>Artist: Quincy Larson</p>
|
||||
|
||||
--fcc-editable-region--
|
||||
<audio></audio>
|
||||
--fcc-editable-region--
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
---
|
||||
id: 698c5229e47d57c6dfaa91bd
|
||||
title: Step 6
|
||||
challengeType: 0
|
||||
dashedName: step-6
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The `controls` attribute provides playback controls including pause/resume playback, seeking, and volume control for the `audio` element.
|
||||
|
||||
The `controls` attribute is a boolean attribute and does not need a value.
|
||||
|
||||
Add the `controls` attribute to the `audio` element.
|
||||
|
||||
Now you should see the `audio` element displayed on the page.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `audio` element should have the `controls` attribute.
|
||||
|
||||
```js
|
||||
const audio = document.querySelector('audio');
|
||||
assert.isTrue(audio?.hasAttribute('controls'));
|
||||
```
|
||||
|
||||
# --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>Working with the HTML Audio Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>freeCodeCamp Tunes</h1>
|
||||
|
||||
<h2>Can't Stay Down</h2>
|
||||
<p>Artist: Quincy Larson</p>
|
||||
|
||||
--fcc-editable-region--
|
||||
<audio src="https://cdn.freecodecamp.org/curriculum/js-music-player/can't-stay-down.mp3" loop></audio>
|
||||
--fcc-editable-region--
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
---
|
||||
id: 698c55e7aaacfae48a227459
|
||||
title: Step 7
|
||||
challengeType: 0
|
||||
dashedName: step-7
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Add a new `h2` element below the `audio` element with the text `Cruising for a Musing`.
|
||||
|
||||
Below the `h2`, add a `p` element with the text `Artist: Quincy Larson`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a second `h2` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('h2:nth-of-type(2)'));
|
||||
```
|
||||
|
||||
Your second `h2` element should contain the text `Cruising for a Musing`.
|
||||
|
||||
```js
|
||||
const h2 = document.querySelector('h2:nth-of-type(2)');
|
||||
assert.strictEqual(h2?.textContent.trim(), 'Cruising for a Musing');
|
||||
```
|
||||
|
||||
You should have a second `p` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('p:nth-of-type(2)'));
|
||||
```
|
||||
|
||||
Your second `p` element should contain the text `Artist: Quincy Larson`.
|
||||
|
||||
```js
|
||||
const p = document.querySelector('p:nth-of-type(2)');
|
||||
assert.strictEqual(p?.textContent.trim(), 'Artist: Quincy Larson');
|
||||
```
|
||||
|
||||
# --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>Working with the HTML Audio Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>freeCodeCamp Tunes</h1>
|
||||
|
||||
<h2>Can't Stay Down</h2>
|
||||
<p>Artist: Quincy Larson</p>
|
||||
|
||||
<audio src="https://cdn.freecodecamp.org/curriculum/js-music-player/can't-stay-down.mp3" loop controls></audio>
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
---
|
||||
id: 698c5710136539797f296098
|
||||
title: Step 8
|
||||
challengeType: 0
|
||||
dashedName: step-8
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Below the `p` element, add an `audio` element, give it an `src` attribute with a value of `https://cdn.freecodecamp.org/curriculum/js-music-player/cruising-for-a-musing.mp3`, and the `loop` and `controls` attributes.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a second `audio` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('audio:nth-of-type(2)'));
|
||||
```
|
||||
|
||||
The new `audio` element should be below the `p` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('p:nth-of-type(2) + audio:nth-of-type(2)'));
|
||||
```
|
||||
|
||||
Your `audio` element should have a `src` attribute.
|
||||
|
||||
```js
|
||||
const audio = document.querySelector('audio:nth-of-type(2)');
|
||||
assert.isTrue(audio?.hasAttribute('src'));
|
||||
```
|
||||
|
||||
Your `audio` element should have a `src` attribute with the value `https://cdn.freecodecamp.org/curriculum/js-music-player/cruising-for-a-musing.mp3`.
|
||||
|
||||
```js
|
||||
const audio = document.querySelector('audio:nth-of-type(2)');
|
||||
assert.strictEqual(audio?.getAttribute('src'),
|
||||
"https://cdn.freecodecamp.org/curriculum/js-music-player/cruising-for-a-musing.mp3");
|
||||
```
|
||||
|
||||
Your `audio` element should have the `loop` attribute.
|
||||
|
||||
```js
|
||||
const audio = document.querySelector('audio:nth-of-type(2)');
|
||||
assert.isTrue(audio?.hasAttribute('loop'));
|
||||
```
|
||||
|
||||
Your `audio` element should have the `controls` attribute.
|
||||
|
||||
```js
|
||||
const audio = document.querySelector('audio:nth-of-type(2)');
|
||||
assert.isTrue(audio?.hasAttribute('controls'));
|
||||
```
|
||||
|
||||
# --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>Working with the HTML Audio Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>freeCodeCamp Tunes</h1>
|
||||
|
||||
<h2>Can't Stay Down</h2>
|
||||
<p>Artist: Quincy Larson</p>
|
||||
|
||||
<audio src="https://cdn.freecodecamp.org/curriculum/js-music-player/can't-stay-down.mp3" loop controls></audio>
|
||||
|
||||
<h2>Cruising for a Musing</h2>
|
||||
<p>Artist: Quincy Larson</p>
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
---
|
||||
id: 698c58745b73289bb6c89ece
|
||||
title: Step 9
|
||||
challengeType: 0
|
||||
dashedName: step-9
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The last song is titled `Scratching the Surface`, the artist is Quincy Larson, and the file to use is `https://cdn.freecodecamp.org/curriculum/js-music-player/scratching-the-surface.mp3`.
|
||||
|
||||
Add the last song to complete the music player following the same pattern you used for the first two songs.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a third `h2` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('h2:nth-of-type(3)'));
|
||||
```
|
||||
|
||||
Your third `h2` element should contain the text `Scratching the Surface`.
|
||||
|
||||
```js
|
||||
const h2 = document.querySelector('h2:nth-of-type(3)');
|
||||
assert.strictEqual(h2?.textContent.trim(), 'Scratching the Surface');
|
||||
```
|
||||
|
||||
You should have a `p` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('p:nth-of-type(3)'));
|
||||
```
|
||||
|
||||
Your `p` element should contain the text `Artist: Quincy Larson`.
|
||||
|
||||
```js
|
||||
const p = document.querySelector('p:nth-of-type(3)');
|
||||
assert.strictEqual(p?.textContent.trim(), 'Artist: Quincy Larson');
|
||||
```
|
||||
|
||||
You should have a third `audio` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('audio:nth-of-type(3)'));
|
||||
```
|
||||
|
||||
The new `audio` element should be below the `p` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('p:nth-of-type(3) + audio:nth-of-type(3)'));
|
||||
```
|
||||
|
||||
Your `audio` element should have a `src` attribute.
|
||||
|
||||
```js
|
||||
const audio = document.querySelector('audio:nth-of-type(3)');
|
||||
assert.isTrue(audio?.hasAttribute('src'));
|
||||
```
|
||||
|
||||
Your `audio` element should have a `src` attribute with the value `https://cdn.freecodecamp.org/curriculum/js-music-player/scratching-the-surface.mp3`.
|
||||
|
||||
```js
|
||||
const audio = document.querySelector('audio:nth-of-type(3)');
|
||||
assert.strictEqual(audio?.getAttribute('src'),
|
||||
"https://cdn.freecodecamp.org/curriculum/js-music-player/scratching-the-surface.mp3");
|
||||
```
|
||||
|
||||
Your `audio` element should have the `loop` attribute.
|
||||
|
||||
```js
|
||||
const audio = document.querySelector('audio:nth-of-type(3)');
|
||||
assert.isTrue(audio?.hasAttribute('loop'));
|
||||
```
|
||||
|
||||
Your `audio` element should have the `controls` attribute.
|
||||
|
||||
```js
|
||||
const audio = document.querySelector('audio:nth-of-type(3)');
|
||||
assert.isTrue(audio?.hasAttribute('controls'));
|
||||
```
|
||||
|
||||
# --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>Working with the HTML Audio Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>freeCodeCamp Tunes</h1>
|
||||
|
||||
<h2>Can't Stay Down</h2>
|
||||
<p>Artist: Quincy Larson</p>
|
||||
|
||||
<audio src="https://cdn.freecodecamp.org/curriculum/js-music-player/can't-stay-down.mp3" loop controls></audio>
|
||||
|
||||
<h2>Cruising for a Musing</h2>
|
||||
<p>Artist: Quincy Larson</p>
|
||||
|
||||
<audio src="https://cdn.freecodecamp.org/curriculum/js-music-player/cruising-for-a-musing.mp3" loop controls></audio>
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
</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>Working with the HTML Audio Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>freeCodeCamp Tunes</h1>
|
||||
|
||||
<h2>Can't Stay Down</h2>
|
||||
<p>Artist: Quincy Larson</p>
|
||||
|
||||
<audio src="https://cdn.freecodecamp.org/curriculum/js-music-player/can't-stay-down.mp3" loop controls></audio>
|
||||
|
||||
<h2>Cruising for a Musing</h2>
|
||||
<p>Artist: Quincy Larson</p>
|
||||
|
||||
<audio src="https://cdn.freecodecamp.org/curriculum/js-music-player/cruising-for-a-musing.mp3" loop controls></audio>
|
||||
|
||||
<h2>Scratching the Surface</h2>
|
||||
<p>Artist: Quincy Larson</p>
|
||||
|
||||
<audio src="https://cdn.freecodecamp.org/curriculum/js-music-player/scratching-the-surface.mp3" loop controls></audio>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "Build an HTML Music Player",
|
||||
"isUpcomingChange": false,
|
||||
"dashedName": "workshop-html-music-player",
|
||||
"helpCategory": "HTML-CSS",
|
||||
"blockLayout": "challenge-grid",
|
||||
"challengeOrder": [
|
||||
{ "id": "698c4e69abe14a9746c72312", "title": "Step 1" },
|
||||
{ "id": "698c4f4e965bd853ad5084e1", "title": "Step 2" },
|
||||
{ "id": "698c4fe24f1f1a17be74a23e", "title": "Step 3" },
|
||||
{ "id": "698c513508507ec8bb820227", "title": "Step 4" },
|
||||
{ "id": "698c50535b54b2d75fa985fb", "title": "Step 5" },
|
||||
{ "id": "698c5229e47d57c6dfaa91bd", "title": "Step 6" },
|
||||
{ "id": "698c55e7aaacfae48a227459", "title": "Step 7" },
|
||||
{ "id": "698c5710136539797f296098", "title": "Step 8" },
|
||||
{ "id": "698c58745b73289bb6c89ece", "title": "Step 9" }
|
||||
],
|
||||
"blockLabel": "workshop",
|
||||
"usesMultifileEditor": true,
|
||||
"hasEditableBoundaries": true
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
"lecture-understanding-how-html-affects-seo",
|
||||
"lab-travel-agency-page",
|
||||
"lecture-working-with-audio-and-video-elements",
|
||||
"workshop-html-music-player",
|
||||
"workshop-html-video-player",
|
||||
"lab-html-audio-and-video-player",
|
||||
"lecture-working-with-images-and-svgs",
|
||||
|
||||
Reference in New Issue
Block a user