mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-04-13 22:00:19 -04:00
feat(curriculum): add bug emoji picker workshop (#63673)
Co-authored-by: Kolade <chrisjay967@gmail.com> Co-authored-by: Kolade Chris <65571316+Ksound22@users.noreply.github.com> Co-authored-by: Dario <105294544+Dario-DC@users.noreply.github.com>
This commit is contained in:
@@ -6205,6 +6205,12 @@
|
||||
"In these lessons, you will learn about generics and type narrowing in TypeScript."
|
||||
]
|
||||
},
|
||||
"workshop-bug-emoji-picker": {
|
||||
"title": "Build a Bug Emoji Picker",
|
||||
"intro": [
|
||||
"In this workshop, you will learn about TypeScript abstract classes and generics by building a bug species selector that displays different bug emojis."
|
||||
]
|
||||
},
|
||||
"lecture-working-with-typescript-configuration-files": {
|
||||
"title": "Working with TypeScript Configuration Files",
|
||||
"intro": [
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
---
|
||||
id: 690fe8b8e39ebd4a4d217d6b
|
||||
title: Step 1
|
||||
challengeType: 0
|
||||
dashedName: step-1
|
||||
demoType: onLoad
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In this workshop, you'll learn about TypeScript abstract classes and generics by building a bug species selector that displays different bug emojis.
|
||||
|
||||
The HTML and CSS for the project have been provided for you so you can focus on the TypeScript. You can check the files to learn about the elements you will select later.
|
||||
|
||||
To start, you'll need an abstract base class for all bugs. Abstract classes cannot be instantiated directly and are meant to be extended by other classes.
|
||||
|
||||
Create an abstract class named `Bug` with a generic type parameter `T`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have an abstract class named `Bug`.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /abstract\s+class\s+Bug/);
|
||||
```
|
||||
|
||||
Your `Bug` class should have a generic type parameter `T`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.isTrue(explorer.classes.Bug.typeParameters[0].matches("T"));
|
||||
```
|
||||
|
||||
# --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>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,138 @@
|
||||
---
|
||||
id: 690ffbe80b0429c0d448050c
|
||||
title: Step 2
|
||||
challengeType: 0
|
||||
dashedName: step-2
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now you need to define the properties that all bugs will have.
|
||||
|
||||
Inside the `Bug` class, declare a property named `emoji` with the type `T` using the definite assignment assertion operator (`!`). This tells TypeScript that the property will be assigned later.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `Bug` class should have a property named `emoji`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.exists(explorer.classes.Bug.classProps.emoji);
|
||||
```
|
||||
|
||||
Your `emoji` property should have the type `T`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.isTrue(explorer.classes.Bug.classProps.emoji.annotation.matches("T"));
|
||||
```
|
||||
|
||||
Your `emoji` property should use the definite assignment assertion operator (`!`).
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /emoji\s*!/);
|
||||
```
|
||||
|
||||
# --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>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
abstract class Bug<T> {
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,137 @@
|
||||
---
|
||||
id: 6927b1bf0ec0410912d6f738
|
||||
title: Step 3
|
||||
challengeType: 0
|
||||
dashedName: step-3
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Still inside the `Bug` class, declare a property named `emojiElement` with the type `HTMLParagraphElement`. This property will hold a reference to the HTML paragraph element where the bug emoji will be displayed.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `Bug` class should have a property named `emojiElement`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.exists(explorer.classes.Bug.classProps.emojiElement);
|
||||
```
|
||||
|
||||
Your `emojiElement` property should have the type `HTMLParagraphElement`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.isTrue(explorer.classes.Bug.classProps.emojiElement.annotation.matches("HTMLParagraphElement"));
|
||||
```
|
||||
|
||||
Your `emojiElement` property should use the definite assignment assertion operator (`!`).
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /emojiElement\s*!/);
|
||||
```
|
||||
|
||||
# --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>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
abstract class Bug<T> {
|
||||
emoji!: T;
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,138 @@
|
||||
---
|
||||
id: 692fb0d9ee52ab2403d8bfe7
|
||||
title: Step 4
|
||||
challengeType: 0
|
||||
dashedName: step-4
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Next, create a constructor for the `Bug` class that takes a single parameter named `emojiElement` of type `HTMLParagraphElement`. Inside the constructor, assign the `emojiElement` parameter to the `emojiElement` property of the class.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `Bug` class should have a constructor.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.exists(explorer.classes.Bug.classConstructor);
|
||||
```
|
||||
|
||||
Your `Bug` constructor should have a parameter named `emojiElement` of type `HTMLParagraphElement`.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /constructor\s*\(\s*emojiElement\s*:\s*HTMLParagraphElement\s*\)/);
|
||||
```
|
||||
|
||||
Your `Bug` constructor should assign `emojiElement` to `this.emojiElement`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.exists(explorer.classes.Bug.constructorProps.emojiElement);
|
||||
```
|
||||
|
||||
# --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>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
abstract class Bug<T> {
|
||||
emoji!: T;
|
||||
emojiElement!: HTMLParagraphElement;
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,135 @@
|
||||
---
|
||||
id: 692fb24a233fc22e2923e3f2
|
||||
title: Step 5
|
||||
challengeType: 0
|
||||
dashedName: step-5
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
After the constructor, create an abstract `render` method that has a return type of `void`. You'll use this in subclasses to update the displayed emoji.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `Bug` class should have an abstract `render` method.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /abstract\s+render\s*\(\s*\)/);
|
||||
```
|
||||
|
||||
Your `render` method should have a return type of `void`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.isTrue(explorer.classes.Bug.methods.render.hasReturnAnnotation("void"));
|
||||
```
|
||||
|
||||
# --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>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
abstract class Bug<T> {
|
||||
emoji!: T;
|
||||
emojiElement!: HTMLParagraphElement;
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
this.emojiElement = emojiElement;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,144 @@
|
||||
---
|
||||
id: 692fb38f7a5889378e93655f
|
||||
title: Step 6
|
||||
challengeType: 0
|
||||
dashedName: step-6
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Next, create a subclass named `Bee` that extends the `Bug` class with the generic type parameter set to `string`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a class named `Bee`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.exists(explorer.classes.Bee);
|
||||
```
|
||||
|
||||
Your `Bee` class should extend `Bug`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.isTrue(explorer.classes.Bee.doesExtend("Bug"));
|
||||
```
|
||||
|
||||
Your `Bee` class should extend `Bug` with a type argument of `string`.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /class\s+Bee\s+extends\s+Bug\s*<\s*string\s*>/);
|
||||
```
|
||||
|
||||
# --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>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
abstract class Bug<T> {
|
||||
emoji!: T;
|
||||
emojiElement!: HTMLParagraphElement;
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
this.emojiElement = emojiElement;
|
||||
}
|
||||
|
||||
abstract render(): void;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,153 @@
|
||||
---
|
||||
id: 692fb4da06eeff4114b47433
|
||||
title: Step 7
|
||||
challengeType: 0
|
||||
dashedName: step-7
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Inside the `Bee` class, create a constructor that takes a single parameter `emojiElement` of type `HTMLParagraphElement`.
|
||||
|
||||
Inside the constructor, call the `super` function with the `emojiElement` parameter to invoke the constructor of the parent `Bug` class. Then, set the `emoji` property to the string value `"🐝"`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `Bee` class should have a constructor.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.exists(explorer.classes.Bee.classConstructor);
|
||||
```
|
||||
|
||||
Your `Bee` constructor should have a parameter named `emojiElement` of type `HTMLParagraphElement`.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /class\s+Bee[\s\S]*?constructor\s*\(\s*emojiElement\s*:\s*HTMLParagraphElement\s*\)/);
|
||||
```
|
||||
|
||||
Your `Bee` constructor should call `super` with the `emojiElement` parameter.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /super\s*\(\s*emojiElement\s*\)/);
|
||||
```
|
||||
|
||||
Your `Bee` constructor should set `this.emoji` to `"🐝"`.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /this\.emoji\s*=\s*["']🐝["']/);
|
||||
```
|
||||
|
||||
# --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>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
abstract class Bug<T> {
|
||||
emoji!: T;
|
||||
emojiElement!: HTMLParagraphElement;
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
this.emojiElement = emojiElement;
|
||||
}
|
||||
|
||||
abstract render(): void;
|
||||
}
|
||||
|
||||
class Bee extends Bug<string> {
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,144 @@
|
||||
---
|
||||
id: 692fb5ed756efe49f8531441
|
||||
title: Step 8
|
||||
challengeType: 0
|
||||
dashedName: step-8
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Inside the `Bee` class, implement the `render` method, prefixed by the `override` keyword, to update the `innerText` property of the `emojiElement` with the value of the `emoji` property.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `Bee` class should have a `render` method using the `override` keyword.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /override\s+render/);
|
||||
```
|
||||
|
||||
You should set `this.emojiElement.innerText` to `this.emoji` inside the `render` method of `Bee`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.isTrue(explorer.classes.Bee.methods.render.matches("override render() { this.emojiElement.innerText = this.emoji; }"));
|
||||
```
|
||||
|
||||
# --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>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
abstract class Bug<T> {
|
||||
emoji!: T;
|
||||
emojiElement!: HTMLParagraphElement;
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
this.emojiElement = emojiElement;
|
||||
}
|
||||
|
||||
abstract render(): void;
|
||||
}
|
||||
|
||||
class Bee extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🐝";
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,155 @@
|
||||
---
|
||||
id: 692fb7ad64801c563e8391b7
|
||||
title: Step 9
|
||||
challengeType: 0
|
||||
dashedName: step-9
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Create a subclass `Spider` that extends the `Bug` class with the generic type parameter set to `string`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a class named `Spider`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.exists(explorer.classes.Spider);
|
||||
```
|
||||
|
||||
Your `Spider` class should extend `Bug`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.isTrue(explorer.classes.Spider.doesExtend("Bug"));
|
||||
```
|
||||
|
||||
Your `Spider` class should extend `Bug` with a type argument of `string`.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /class\s+Spider\s+extends\s+Bug\s*<\s*string\s*>/);
|
||||
```
|
||||
|
||||
# --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>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
abstract class Bug<T> {
|
||||
emoji!: T;
|
||||
emojiElement!: HTMLParagraphElement;
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
this.emojiElement = emojiElement;
|
||||
}
|
||||
|
||||
abstract render(): void;
|
||||
}
|
||||
|
||||
class Bee extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🐝";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,164 @@
|
||||
---
|
||||
id: 692fb81e768aab5a1a6a0381
|
||||
title: Step 10
|
||||
challengeType: 0
|
||||
dashedName: step-10
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Inside the `Spider` class, create a constructor that takes a single parameter `emojiElement` of type `HTMLParagraphElement`.
|
||||
|
||||
Inside the constructor, call the `super` function with the `emojiElement` parameter to invoke the constructor of the parent `Bug` class. Then, set the `emoji` property to the string value `"🕷️"`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `Spider` class should have a constructor.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.exists(explorer.classes.Spider.classConstructor);
|
||||
```
|
||||
|
||||
Your `Spider` constructor should have a parameter named `emojiElement` of type `HTMLParagraphElement`.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /class\s+Spider[\s\S]*?constructor\s*\(\s*emojiElement\s*:\s*HTMLParagraphElement\s*\)/);
|
||||
```
|
||||
|
||||
Your `Spider` constructor should call `super` with the `emojiElement` parameter.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /class\s+Spider[\s\S]*?super\s*\(\s*emojiElement\s*\)/);
|
||||
```
|
||||
|
||||
Your `Spider` constructor should set `this.emoji` to `"🕷️"`.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /this\.emoji\s*=\s*["']🕷️["']/);
|
||||
```
|
||||
|
||||
# --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>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
abstract class Bug<T> {
|
||||
emoji!: T;
|
||||
emojiElement!: HTMLParagraphElement;
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
this.emojiElement = emojiElement;
|
||||
}
|
||||
|
||||
abstract render(): void;
|
||||
}
|
||||
|
||||
class Bee extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🐝";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
class Spider extends Bug<string> {
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,162 @@
|
||||
---
|
||||
id: 692fb94bf8221362ce6f54c5
|
||||
title: Step 11
|
||||
challengeType: 0
|
||||
dashedName: step-11
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Inside the `Spider` class, implement the `render` method, prefixed by the `override` keyword, to update the `innerText` property of the `emojiElement` with the value of the `emoji` property.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `Spider` class should have a `render` method.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.exists(explorer.classes.Spider.methods.render);
|
||||
```
|
||||
|
||||
Your `Spider` `render` method should use the `override` keyword.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /class\s+Spider[\s\S]*?override\s+render/);
|
||||
```
|
||||
|
||||
Your `Spider` `render` method should set `this.emojiElement.innerText` to `this.emoji`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.isTrue(explorer.classes.Spider.methods.render.matches("override render() { this.emojiElement.innerText = this.emoji; }"));
|
||||
```
|
||||
|
||||
# --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>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
abstract class Bug<T> {
|
||||
emoji!: T;
|
||||
emojiElement!: HTMLParagraphElement;
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
this.emojiElement = emojiElement;
|
||||
}
|
||||
|
||||
abstract render(): void;
|
||||
}
|
||||
|
||||
class Bee extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🐝";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
class Spider extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🕷️";
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,166 @@
|
||||
---
|
||||
id: 692fb9f4046f1d677f1f6e4e
|
||||
title: Step 12
|
||||
challengeType: 0
|
||||
dashedName: step-12
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Create a function named `isSelect` that takes a single parameter `element` of type `EventTarget | null`. This function will check if the selected element is a `<select>` HTML element.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a function named `isSelect`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.exists(explorer.allFunctions.isSelect);
|
||||
```
|
||||
|
||||
Your `isSelect` function should have a parameter named `element` of type `EventTarget | null`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.isTrue(explorer.allFunctions.isSelect.parameters[0].matches("element: EventTarget | null"));
|
||||
```
|
||||
|
||||
Your `isSelect` function should have a return type of `element is HTMLSelectElement`.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /:\s*element\s+is\s+HTMLSelectElement/);
|
||||
```
|
||||
|
||||
# --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>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
abstract class Bug<T> {
|
||||
emoji!: T;
|
||||
emojiElement!: HTMLParagraphElement;
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
this.emojiElement = emojiElement;
|
||||
}
|
||||
|
||||
abstract render(): void;
|
||||
}
|
||||
|
||||
class Bee extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🐝";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
class Spider extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🕷️";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,155 @@
|
||||
---
|
||||
id: 692fbce895711f7c574c1e81
|
||||
title: Step 13
|
||||
challengeType: 0
|
||||
dashedName: step-13
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now inside the `isSelect` function, return a boolean indicating whether the `element` is an instance of `HTMLSelectElement`. Use the `instanceof` operator to perform this check.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `isSelect` function should return `element instanceof HTMLSelectElement`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.isTrue(explorer.allFunctions.isSelect.hasReturn("element instanceof HTMLSelectElement"));
|
||||
```
|
||||
|
||||
# --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>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
abstract class Bug<T> {
|
||||
emoji!: T;
|
||||
emojiElement!: HTMLParagraphElement;
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
this.emojiElement = emojiElement;
|
||||
}
|
||||
|
||||
abstract render(): void;
|
||||
}
|
||||
|
||||
class Bee extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🐝";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
class Spider extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🕷️";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
function isSelect(element: EventTarget | null): element is HTMLSelectElement {
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,172 @@
|
||||
---
|
||||
id: 692fbdf423ea7685453dbbf9
|
||||
title: Step 14
|
||||
challengeType: 0
|
||||
dashedName: step-14
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You will now start referencing the needed DOM elements.
|
||||
|
||||
Get the paragraph element with the ID of `bug-emoji` and store it in a constant named `bugEmojiElement`. Use the `!` non-null assertion operator to assert that the element is not `null`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a constant named `bugEmojiElement`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.exists(explorer.variables.bugEmojiElement);
|
||||
```
|
||||
|
||||
Your `bugEmojiElement` should query the element with the ID `bug-emoji` using `document.querySelector` with a type argument of `HTMLParagraphElement`.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /querySelector\s*<\s*HTMLParagraphElement\s*>\s*\(\s*['"]#bug-emoji['"]\s*\)/);
|
||||
```
|
||||
|
||||
Your `bugEmojiElement` should use the non-null assertion operator (`!`).
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.isTrue(explorer.variables.bugEmojiElement.value.hasNonNullAssertion());
|
||||
```
|
||||
|
||||
# --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>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
abstract class Bug<T> {
|
||||
emoji!: T;
|
||||
emojiElement!: HTMLParagraphElement;
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
this.emojiElement = emojiElement;
|
||||
}
|
||||
|
||||
abstract render(): void;
|
||||
}
|
||||
|
||||
class Bee extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🐝";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
class Spider extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🕷️";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
function isSelect(element: EventTarget | null): element is HTMLSelectElement {
|
||||
return element instanceof HTMLSelectElement;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,172 @@
|
||||
---
|
||||
id: 692fbf63c8fe56907977f450
|
||||
title: Step 15
|
||||
challengeType: 0
|
||||
dashedName: step-15
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Next, define an object named `bugMap` with the type `Record<string, Bug<string>>` and assign it an empty object for now.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a constant named `bugMap`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.exists(explorer.variables.bugMap);
|
||||
```
|
||||
|
||||
Your `bugMap` should have a type annotation of `Record<string, Bug<string>>`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.isTrue(explorer.variables.bugMap.hasAnnotation("Record<string, Bug<string>>"));
|
||||
```
|
||||
|
||||
Your `bugMap` should be initialized to an empty object.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.isTrue(explorer.variables.bugMap.value.matches("{}"));
|
||||
```
|
||||
|
||||
# --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>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
abstract class Bug<T> {
|
||||
emoji!: T;
|
||||
emojiElement!: HTMLParagraphElement;
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
this.emojiElement = emojiElement;
|
||||
}
|
||||
|
||||
abstract render(): void;
|
||||
}
|
||||
|
||||
class Bee extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🐝";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
class Spider extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🕷️";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
function isSelect(element: EventTarget | null): element is HTMLSelectElement {
|
||||
return element instanceof HTMLSelectElement;
|
||||
}
|
||||
|
||||
const bugEmojiElement = document.querySelector<HTMLParagraphElement>('#bug-emoji')!;
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,176 @@
|
||||
---
|
||||
id: 69386f3bce81c60f2b3feeb8
|
||||
title: Step 17
|
||||
challengeType: 0
|
||||
dashedName: step-17
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Get the `select` element with ID `species` from the DOM and store it in a constant named `selectElement`. Use the `!` non-null assertion operator to assert that the element is not `null`
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a constant named `selectElement`.
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.exists(explorer.variables.selectElement);
|
||||
```
|
||||
|
||||
Your `selectElement` should query the element with the ID `species` using `document.querySelector` with a type argument of `HTMLSelectElement`.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /querySelector\s*<\s*HTMLSelectElement\s*>\s*\(\s*['"]#species['"]\s*\)/);
|
||||
```
|
||||
|
||||
Your `selectElement` should use the non-null assertion operator (`!`).
|
||||
|
||||
```js
|
||||
const explorer = await __helpers.Explorer(code);
|
||||
assert.isTrue(explorer.variables.selectElement.value.hasNonNullAssertion());
|
||||
```
|
||||
|
||||
# --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>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
abstract class Bug<T> {
|
||||
emoji!: T;
|
||||
emojiElement!: HTMLParagraphElement;
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
this.emojiElement = emojiElement;
|
||||
}
|
||||
|
||||
abstract render(): void;
|
||||
}
|
||||
|
||||
class Bee extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🐝";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
class Spider extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🕷️";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
function isSelect(element: EventTarget | null): element is HTMLSelectElement {
|
||||
return element instanceof HTMLSelectElement;
|
||||
}
|
||||
|
||||
const bugEmojiElement = document.querySelector<HTMLParagraphElement>('#bug-emoji')!;
|
||||
const bugMap: Record<string, Bug<string>> = {
|
||||
"bee": new Bee(bugEmojiElement),
|
||||
"spider": new Spider(bugEmojiElement),
|
||||
};
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,171 @@
|
||||
---
|
||||
id: 693874cf5bf4aa32aded7ce5
|
||||
title: Step 18
|
||||
challengeType: 0
|
||||
dashedName: step-18
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Up until now, nothing changes when you select a different bug.
|
||||
|
||||
Add a `change` event listener to `selectElement`. In the callback, use `isSelect` to check if `e.target` is an `HTMLSelectElement`. You don't need to do anything inside the `if` block yet.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `selectElement` should have a `change` event listener with a callback that takes an event parameter.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /selectElement\s*\.\s*addEventListener\s*\(\s*["']change["']\s*,\s*(?:function\s*\(\s*\w+\s*\)|\w+\s*=>|\(\s*\w+\s*\)\s*=>)/);
|
||||
```
|
||||
|
||||
Your event listener callback should have an `if` statement with the condition `isSelect(e.target)`.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /addEventListener\s*\(\s*["']change["'][\s\S]*?if\s*\(\s*isSelect\s*\(\s*e\.target\s*\)\s*\)/);
|
||||
```
|
||||
|
||||
# --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>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
abstract class Bug<T> {
|
||||
emoji!: T;
|
||||
emojiElement!: HTMLParagraphElement;
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
this.emojiElement = emojiElement;
|
||||
}
|
||||
|
||||
abstract render(): void;
|
||||
}
|
||||
|
||||
class Bee extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🐝";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
class Spider extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🕷️";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
function isSelect(element: EventTarget | null): element is HTMLSelectElement {
|
||||
return element instanceof HTMLSelectElement;
|
||||
}
|
||||
|
||||
const bugEmojiElement = document.querySelector<HTMLParagraphElement>('#bug-emoji')!;
|
||||
const bugMap: Record<string, Bug<string>> = {
|
||||
"bee": new Bee(bugEmojiElement),
|
||||
"spider": new Spider(bugEmojiElement),
|
||||
};
|
||||
|
||||
const selectElement = document.querySelector<HTMLSelectElement>('#species')!;
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,165 @@
|
||||
---
|
||||
id: 69d902c4f58b8a0d48d19c67
|
||||
title: Step 16
|
||||
challengeType: 0
|
||||
dashedName: step-16
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now populate `bugMap` with two entries. Add `"bee"` as a key mapped to a new `Bee` instance, and `"spider"` as a key mapped to a new `Spider` instance. Pass in `bugEmojiElement` as the argument of both.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `bugMap` should have a `"bee"` entry set to `new Bee(bugEmojiElement)`.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /bugMap\s*[^=]*=\s*\{[^}]*["']bee["']\s*:\s*new\s+Bee\s*\(\s*bugEmojiElement\s*\)/s);
|
||||
```
|
||||
|
||||
Your `bugMap` should have a `"spider"` entry set to `new Spider(bugEmojiElement)`.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /bugMap\s*[^=]*=\s*\{[^}]*["']spider["']\s*:\s*new\s+Spider\s*\(\s*bugEmojiElement\s*\)/s);
|
||||
```
|
||||
|
||||
# --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>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
abstract class Bug<T> {
|
||||
emoji!: T;
|
||||
emojiElement!: HTMLParagraphElement;
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
this.emojiElement = emojiElement;
|
||||
}
|
||||
|
||||
abstract render(): void;
|
||||
}
|
||||
|
||||
class Bee extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🐝";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
class Spider extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🕷️";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
function isSelect(element: EventTarget | null): element is HTMLSelectElement {
|
||||
return element instanceof HTMLSelectElement;
|
||||
}
|
||||
|
||||
const bugEmojiElement = document.querySelector<HTMLParagraphElement>('#bug-emoji')!;
|
||||
const bugMap: Record<string, Bug<string>> = {
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,314 @@
|
||||
---
|
||||
id: 69d909f2946a3fcabed720c6
|
||||
title: Step 19
|
||||
challengeType: 0
|
||||
dashedName: step-19
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now that the `if` check is in place, use `e.target.value` to look up the corresponding bug in `bugMap` and call its `render` method. After that, you should be able to select the bugs and see the result right away.
|
||||
|
||||
With that, your Bug Emoji Picker workshop is complete!
|
||||
|
||||
# --hints--
|
||||
|
||||
You should call the `render` method on the corresponding bug from `bugMap`.
|
||||
|
||||
```js
|
||||
assert.match(__helpers.removeJSComments(code), /bugMap\s*\[\s*e\.target\.value\s*\]\s*\.\s*render\s*\(\s*\)/);
|
||||
```
|
||||
|
||||
# --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>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
abstract class Bug<T> {
|
||||
emoji!: T;
|
||||
emojiElement!: HTMLParagraphElement;
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
this.emojiElement = emojiElement;
|
||||
}
|
||||
|
||||
abstract render(): void;
|
||||
}
|
||||
|
||||
class Bee extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🐝";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
class Spider extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🕷️";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
function isSelect(element: EventTarget | null): element is HTMLSelectElement {
|
||||
return element instanceof HTMLSelectElement;
|
||||
}
|
||||
|
||||
const bugEmojiElement = document.querySelector<HTMLParagraphElement>('#bug-emoji')!;
|
||||
const bugMap: Record<string, Bug<string>> = {
|
||||
"bee": new Bee(bugEmojiElement),
|
||||
"spider": new Spider(bugEmojiElement),
|
||||
};
|
||||
|
||||
const selectElement = document.querySelector<HTMLSelectElement>('#species')!;
|
||||
selectElement.addEventListener("change", e => {
|
||||
if (isSelect(e.target)) {
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Bug Emoji Picker</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form id="bug-form">
|
||||
<label for="species">Species:</Label>
|
||||
<select id="species">
|
||||
<option value="bee" selected>🐝 Bee</option>
|
||||
<option value="spider">🕷️ Spider</option>
|
||||
</select>
|
||||
</form>
|
||||
<div>
|
||||
<p id="bug-emoji">🐝</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<script src="index.ts"></script>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--gradient-back: #987284;
|
||||
--gradient-left: #F9B5AC;
|
||||
--gradient-right: #AA7674;
|
||||
--card: #FFFFFF;
|
||||
--card-shadow: 0 10px 30px rgba(30, 41, 59, 0.12);
|
||||
--font: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background: radial-gradient(100% 100% at 10% 10%, var(--gradient-left), transparent 60%),
|
||||
radial-gradient(90% 85% at 90% 0%, var(--gradient-right), transparent 55%),
|
||||
linear-gradient(180deg, var(--gradient-back), #ffffff);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 5rem auto;
|
||||
padding: 2rem 3rem;
|
||||
width: fit-content;
|
||||
min-width: 15%;
|
||||
color: var(--font);
|
||||
font: 500 16px/1.4 system-ui;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 15%;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
backdrop-filter: blue(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
select, input {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 12px;
|
||||
padding: 0.1rem 2rem 0.1rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#bug-emoji {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
#bug-name {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
font-size: 24;
|
||||
font-weight: 700;
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
abstract class Bug<T> {
|
||||
emoji!: T;
|
||||
emojiElement!: HTMLParagraphElement;
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
this.emojiElement = emojiElement;
|
||||
}
|
||||
|
||||
abstract render(): void;
|
||||
}
|
||||
|
||||
class Bee extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🐝";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
class Spider extends Bug<string> {
|
||||
constructor(emojiElement: HTMLParagraphElement) {
|
||||
super(emojiElement);
|
||||
this.emoji = "🕷️";
|
||||
}
|
||||
|
||||
override render() {
|
||||
this.emojiElement.innerText = this.emoji;
|
||||
}
|
||||
}
|
||||
|
||||
function isSelect(element: EventTarget | null): element is HTMLSelectElement {
|
||||
return element instanceof HTMLSelectElement;
|
||||
}
|
||||
|
||||
const bugEmojiElement = document.querySelector<HTMLParagraphElement>('#bug-emoji')!;
|
||||
const bugMap: Record<string, Bug<string>> = {
|
||||
"bee": new Bee(bugEmojiElement),
|
||||
"spider": new Spider(bugEmojiElement),
|
||||
};
|
||||
|
||||
const selectElement = document.querySelector<HTMLSelectElement>('#species')!;
|
||||
selectElement.addEventListener("change", e => {
|
||||
if (isSelect(e.target)) {
|
||||
bugMap[e.target.value].render();
|
||||
}
|
||||
});
|
||||
```
|
||||
30
curriculum/structure/blocks/workshop-bug-emoji-picker.json
Normal file
30
curriculum/structure/blocks/workshop-bug-emoji-picker.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"isUpcomingChange": true,
|
||||
"dashedName": "workshop-bug-emoji-picker",
|
||||
"helpCategory": "JavaScript",
|
||||
"blockLayout": "challenge-grid",
|
||||
"challengeOrder": [
|
||||
{ "id": "690fe8b8e39ebd4a4d217d6b", "title": "Step 1" },
|
||||
{ "id": "690ffbe80b0429c0d448050c", "title": "Step 2" },
|
||||
{ "id": "6927b1bf0ec0410912d6f738", "title": "Step 3" },
|
||||
{ "id": "692fb0d9ee52ab2403d8bfe7", "title": "Step 4" },
|
||||
{ "id": "692fb24a233fc22e2923e3f2", "title": "Step 5" },
|
||||
{ "id": "692fb38f7a5889378e93655f", "title": "Step 6" },
|
||||
{ "id": "692fb4da06eeff4114b47433", "title": "Step 7" },
|
||||
{ "id": "692fb5ed756efe49f8531441", "title": "Step 8" },
|
||||
{ "id": "692fb7ad64801c563e8391b7", "title": "Step 9" },
|
||||
{ "id": "692fb81e768aab5a1a6a0381", "title": "Step 10" },
|
||||
{ "id": "692fb94bf8221362ce6f54c5", "title": "Step 11" },
|
||||
{ "id": "692fb9f4046f1d677f1f6e4e", "title": "Step 12" },
|
||||
{ "id": "692fbce895711f7c574c1e81", "title": "Step 13" },
|
||||
{ "id": "692fbdf423ea7685453dbbf9", "title": "Step 14" },
|
||||
{ "id": "692fbf63c8fe56907977f450", "title": "Step 15" },
|
||||
{ "id": "69d902c4f58b8a0d48d19c67", "title": "Step 16" },
|
||||
{ "id": "69386f3bce81c60f2b3feeb8", "title": "Step 17" },
|
||||
{ "id": "693874cf5bf4aa32aded7ce5", "title": "Step 18" },
|
||||
{ "id": "69d909f2946a3fcabed720c6", "title": "Step 19" }
|
||||
],
|
||||
"blockLabel": "workshop",
|
||||
"usesMultifileEditor": true,
|
||||
"hasEditableBoundaries": true
|
||||
}
|
||||
@@ -95,6 +95,7 @@
|
||||
"workshop-type-safe-math-toolkit",
|
||||
"lecture-understanding-type-composition",
|
||||
"lecture-working-with-generics-and-type-narrowing",
|
||||
"workshop-bug-emoji-picker",
|
||||
"lecture-working-with-typescript-configuration-files",
|
||||
"review-typescript",
|
||||
"quiz-typescript"
|
||||
|
||||
Reference in New Issue
Block a user