From 02b12ac880d4bcb95da9fa7c21d74da1931fcd4a Mon Sep 17 00:00:00 2001 From: Ihechikara Abba Date: Mon, 13 Apr 2026 11:40:02 +0100 Subject: [PATCH] feat(curriculum): add bug emoji picker workshop (#63673) Co-authored-by: Kolade Co-authored-by: Kolade Chris <65571316+Ksound22@users.noreply.github.com> Co-authored-by: Dario <105294544+Dario-DC@users.noreply.github.com> --- client/i18n/locales/english/intro.json | 6 + .../690fe8b8e39ebd4a4d217d6b.md | 134 ++++++++ .../690ffbe80b0429c0d448050c.md | 138 ++++++++ .../6927b1bf0ec0410912d6f738.md | 137 ++++++++ .../692fb0d9ee52ab2403d8bfe7.md | 138 ++++++++ .../692fb24a233fc22e2923e3f2.md | 135 ++++++++ .../692fb38f7a5889378e93655f.md | 144 ++++++++ .../692fb4da06eeff4114b47433.md | 153 +++++++++ .../692fb5ed756efe49f8531441.md | 144 ++++++++ .../692fb7ad64801c563e8391b7.md | 155 +++++++++ .../692fb81e768aab5a1a6a0381.md | 164 +++++++++ .../692fb94bf8221362ce6f54c5.md | 162 +++++++++ .../692fb9f4046f1d677f1f6e4e.md | 166 +++++++++ .../692fbce895711f7c574c1e81.md | 155 +++++++++ .../692fbdf423ea7685453dbbf9.md | 172 ++++++++++ .../692fbf63c8fe56907977f450.md | 172 ++++++++++ .../69386f3bce81c60f2b3feeb8.md | 176 ++++++++++ .../693874cf5bf4aa32aded7ce5.md | 171 ++++++++++ .../69d902c4f58b8a0d48d19c67.md | 165 +++++++++ .../69d909f2946a3fcabed720c6.md | 314 ++++++++++++++++++ .../blocks/workshop-bug-emoji-picker.json | 30 ++ .../front-end-development-libraries-v9.json | 1 + 22 files changed, 3132 insertions(+) create mode 100644 curriculum/challenges/english/blocks/workshop-bug-emoji-picker/690fe8b8e39ebd4a4d217d6b.md create mode 100644 curriculum/challenges/english/blocks/workshop-bug-emoji-picker/690ffbe80b0429c0d448050c.md create mode 100644 curriculum/challenges/english/blocks/workshop-bug-emoji-picker/6927b1bf0ec0410912d6f738.md create mode 100644 curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb0d9ee52ab2403d8bfe7.md create mode 100644 curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb24a233fc22e2923e3f2.md create mode 100644 curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb38f7a5889378e93655f.md create mode 100644 curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb4da06eeff4114b47433.md create mode 100644 curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb5ed756efe49f8531441.md create mode 100644 curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb7ad64801c563e8391b7.md create mode 100644 curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb81e768aab5a1a6a0381.md create mode 100644 curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb94bf8221362ce6f54c5.md create mode 100644 curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb9f4046f1d677f1f6e4e.md create mode 100644 curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fbce895711f7c574c1e81.md create mode 100644 curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fbdf423ea7685453dbbf9.md create mode 100644 curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fbf63c8fe56907977f450.md create mode 100644 curriculum/challenges/english/blocks/workshop-bug-emoji-picker/69386f3bce81c60f2b3feeb8.md create mode 100644 curriculum/challenges/english/blocks/workshop-bug-emoji-picker/693874cf5bf4aa32aded7ce5.md create mode 100644 curriculum/challenges/english/blocks/workshop-bug-emoji-picker/69d902c4f58b8a0d48d19c67.md create mode 100644 curriculum/challenges/english/blocks/workshop-bug-emoji-picker/69d909f2946a3fcabed720c6.md create mode 100644 curriculum/structure/blocks/workshop-bug-emoji-picker.json diff --git a/client/i18n/locales/english/intro.json b/client/i18n/locales/english/intro.json index 54135d27993..79c92c62373 100644 --- a/client/i18n/locales/english/intro.json +++ b/client/i18n/locales/english/intro.json @@ -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": [ diff --git a/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/690fe8b8e39ebd4a4d217d6b.md b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/690fe8b8e39ebd4a4d217d6b.md new file mode 100644 index 00000000000..cf1bdc931e3 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/690fe8b8e39ebd4a4d217d6b.md @@ -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 + + + + + + Bug Emoji Picker + + + +
+
+ + +
+
+

🐝

+
+
+ + + +``` + +```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-- +``` diff --git a/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/690ffbe80b0429c0d448050c.md b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/690ffbe80b0429c0d448050c.md new file mode 100644 index 00000000000..d81867e5ce8 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/690ffbe80b0429c0d448050c.md @@ -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 + + + + + + Bug Emoji Picker + + + +
+
+ + +
+
+

🐝

+
+
+ + + +``` + +```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 { + --fcc-editable-region-- + + --fcc-editable-region-- +} +``` diff --git a/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/6927b1bf0ec0410912d6f738.md b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/6927b1bf0ec0410912d6f738.md new file mode 100644 index 00000000000..d969b8d9999 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/6927b1bf0ec0410912d6f738.md @@ -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 + + + + + + Bug Emoji Picker + + + +
+
+ + +
+
+

🐝

+
+
+ + + +``` + +```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 { + emoji!: T; +--fcc-editable-region-- + +--fcc-editable-region-- +} +``` diff --git a/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb0d9ee52ab2403d8bfe7.md b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb0d9ee52ab2403d8bfe7.md new file mode 100644 index 00000000000..cac26b5d860 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb0d9ee52ab2403d8bfe7.md @@ -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 + + + + + + Bug Emoji Picker + + + +
+
+ + +
+
+

🐝

+
+
+ + + +``` + +```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 { + emoji!: T; + emojiElement!: HTMLParagraphElement; +--fcc-editable-region-- + +--fcc-editable-region-- +} +``` diff --git a/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb24a233fc22e2923e3f2.md b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb24a233fc22e2923e3f2.md new file mode 100644 index 00000000000..67558b97283 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb24a233fc22e2923e3f2.md @@ -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 + + + + + + Bug Emoji Picker + + + +
+
+ + +
+
+

🐝

+
+
+ + + +``` + +```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 { + emoji!: T; + emojiElement!: HTMLParagraphElement; + constructor(emojiElement: HTMLParagraphElement) { + this.emojiElement = emojiElement; + } + +--fcc-editable-region-- + +--fcc-editable-region-- +} +``` diff --git a/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb38f7a5889378e93655f.md b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb38f7a5889378e93655f.md new file mode 100644 index 00000000000..200bb126d00 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb38f7a5889378e93655f.md @@ -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 + + + + + + Bug Emoji Picker + + + +
+
+ + +
+
+

🐝

+
+
+ + + +``` + +```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 { + emoji!: T; + emojiElement!: HTMLParagraphElement; + constructor(emojiElement: HTMLParagraphElement) { + this.emojiElement = emojiElement; + } + + abstract render(): void; +} + +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb4da06eeff4114b47433.md b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb4da06eeff4114b47433.md new file mode 100644 index 00000000000..983c066ad74 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb4da06eeff4114b47433.md @@ -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 + + + + + + Bug Emoji Picker + + + +
+
+ + +
+
+

🐝

+
+
+ + + +``` + +```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 { + emoji!: T; + emojiElement!: HTMLParagraphElement; + constructor(emojiElement: HTMLParagraphElement) { + this.emojiElement = emojiElement; + } + + abstract render(): void; +} + +class Bee extends Bug { +--fcc-editable-region-- + +--fcc-editable-region-- +} +``` diff --git a/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb5ed756efe49f8531441.md b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb5ed756efe49f8531441.md new file mode 100644 index 00000000000..dd87be9b6b6 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb5ed756efe49f8531441.md @@ -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 + + + + + + Bug Emoji Picker + + + +
+
+ + +
+
+

🐝

+
+
+ + + +``` + +```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 { + emoji!: T; + emojiElement!: HTMLParagraphElement; + constructor(emojiElement: HTMLParagraphElement) { + this.emojiElement = emojiElement; + } + + abstract render(): void; +} + +class Bee extends Bug { + constructor(emojiElement: HTMLParagraphElement) { + super(emojiElement); + this.emoji = "🐝"; + } + +--fcc-editable-region-- + +--fcc-editable-region-- +} +``` diff --git a/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb7ad64801c563e8391b7.md b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb7ad64801c563e8391b7.md new file mode 100644 index 00000000000..f214ca303bc --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb7ad64801c563e8391b7.md @@ -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 + + + + + + Bug Emoji Picker + + + +
+
+ + +
+
+

🐝

+
+
+ + + +``` + +```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 { + emoji!: T; + emojiElement!: HTMLParagraphElement; + constructor(emojiElement: HTMLParagraphElement) { + this.emojiElement = emojiElement; + } + + abstract render(): void; +} + +class Bee extends Bug { + constructor(emojiElement: HTMLParagraphElement) { + super(emojiElement); + this.emoji = "🐝"; + } + + override render() { + this.emojiElement.innerText = this.emoji; + } +} + +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb81e768aab5a1a6a0381.md b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb81e768aab5a1a6a0381.md new file mode 100644 index 00000000000..23a3ec42ac3 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb81e768aab5a1a6a0381.md @@ -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 + + + + + + Bug Emoji Picker + + + +
+
+ + +
+
+

🐝

+
+
+ + + +``` + +```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 { + emoji!: T; + emojiElement!: HTMLParagraphElement; + constructor(emojiElement: HTMLParagraphElement) { + this.emojiElement = emojiElement; + } + + abstract render(): void; +} + +class Bee extends Bug { + constructor(emojiElement: HTMLParagraphElement) { + super(emojiElement); + this.emoji = "🐝"; + } + + override render() { + this.emojiElement.innerText = this.emoji; + } +} + +class Spider extends Bug { +--fcc-editable-region-- + +--fcc-editable-region-- +} +``` diff --git a/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb94bf8221362ce6f54c5.md b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb94bf8221362ce6f54c5.md new file mode 100644 index 00000000000..57923030fe8 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb94bf8221362ce6f54c5.md @@ -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 + + + + + + Bug Emoji Picker + + + +
+
+ + +
+
+

🐝

+
+
+ + + +``` + +```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 { + emoji!: T; + emojiElement!: HTMLParagraphElement; + constructor(emojiElement: HTMLParagraphElement) { + this.emojiElement = emojiElement; + } + + abstract render(): void; +} + +class Bee extends Bug { + constructor(emojiElement: HTMLParagraphElement) { + super(emojiElement); + this.emoji = "🐝"; + } + + override render() { + this.emojiElement.innerText = this.emoji; + } +} + +class Spider extends Bug { + constructor(emojiElement: HTMLParagraphElement) { + super(emojiElement); + this.emoji = "🕷️"; + } + +--fcc-editable-region-- + +--fcc-editable-region-- +} +``` diff --git a/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb9f4046f1d677f1f6e4e.md b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb9f4046f1d677f1f6e4e.md new file mode 100644 index 00000000000..bba2a9a08d6 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fb9f4046f1d677f1f6e4e.md @@ -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 ` + + + + +
+

🐝

+
+ + + + +``` + +```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 { + emoji!: T; + emojiElement!: HTMLParagraphElement; + constructor(emojiElement: HTMLParagraphElement) { + this.emojiElement = emojiElement; + } + + abstract render(): void; +} + +class Bee extends Bug { + constructor(emojiElement: HTMLParagraphElement) { + super(emojiElement); + this.emoji = "🐝"; + } + + override render() { + this.emojiElement.innerText = this.emoji; + } +} + +class Spider extends Bug { + constructor(emojiElement: HTMLParagraphElement) { + super(emojiElement); + this.emoji = "🕷️"; + } + + override render() { + this.emojiElement.innerText = this.emoji; + } +} + +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fbce895711f7c574c1e81.md b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fbce895711f7c574c1e81.md new file mode 100644 index 00000000000..3214cddc197 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fbce895711f7c574c1e81.md @@ -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 + + + + + + Bug Emoji Picker + + + +
+
+ + +
+
+

🐝

+
+
+ + + +``` + +```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 { + emoji!: T; + emojiElement!: HTMLParagraphElement; + constructor(emojiElement: HTMLParagraphElement) { + this.emojiElement = emojiElement; + } + + abstract render(): void; +} + +class Bee extends Bug { + constructor(emojiElement: HTMLParagraphElement) { + super(emojiElement); + this.emoji = "🐝"; + } + + override render() { + this.emojiElement.innerText = this.emoji; + } +} + +class Spider extends Bug { + 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-- +} +``` diff --git a/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fbdf423ea7685453dbbf9.md b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fbdf423ea7685453dbbf9.md new file mode 100644 index 00000000000..e840b3bc353 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fbdf423ea7685453dbbf9.md @@ -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 + + + + + + Bug Emoji Picker + + + +
+
+ + +
+
+

🐝

+
+
+ + + +``` + +```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 { + emoji!: T; + emojiElement!: HTMLParagraphElement; + constructor(emojiElement: HTMLParagraphElement) { + this.emojiElement = emojiElement; + } + + abstract render(): void; +} + +class Bee extends Bug { + constructor(emojiElement: HTMLParagraphElement) { + super(emojiElement); + this.emoji = "🐝"; + } + + override render() { + this.emojiElement.innerText = this.emoji; + } +} + +class Spider extends Bug { + 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-- +``` diff --git a/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fbf63c8fe56907977f450.md b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fbf63c8fe56907977f450.md new file mode 100644 index 00000000000..90e30456205 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/692fbf63c8fe56907977f450.md @@ -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>` 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>`. + +```js +const explorer = await __helpers.Explorer(code); +assert.isTrue(explorer.variables.bugMap.hasAnnotation("Record>")); +``` + +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 + + + + + + Bug Emoji Picker + + + +
+
+ + +
+
+

🐝

+
+
+ + + +``` + +```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 { + emoji!: T; + emojiElement!: HTMLParagraphElement; + constructor(emojiElement: HTMLParagraphElement) { + this.emojiElement = emojiElement; + } + + abstract render(): void; +} + +class Bee extends Bug { + constructor(emojiElement: HTMLParagraphElement) { + super(emojiElement); + this.emoji = "🐝"; + } + + override render() { + this.emojiElement.innerText = this.emoji; + } +} + +class Spider extends Bug { + 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('#bug-emoji')!; +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/69386f3bce81c60f2b3feeb8.md b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/69386f3bce81c60f2b3feeb8.md new file mode 100644 index 00000000000..886ebe6dfb8 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/69386f3bce81c60f2b3feeb8.md @@ -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 + + + + + + Bug Emoji Picker + + + +
+
+ + +
+
+

🐝

+
+
+ + + +``` + +```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 { + emoji!: T; + emojiElement!: HTMLParagraphElement; + constructor(emojiElement: HTMLParagraphElement) { + this.emojiElement = emojiElement; + } + + abstract render(): void; +} + +class Bee extends Bug { + constructor(emojiElement: HTMLParagraphElement) { + super(emojiElement); + this.emoji = "🐝"; + } + + override render() { + this.emojiElement.innerText = this.emoji; + } +} + +class Spider extends Bug { + 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('#bug-emoji')!; +const bugMap: Record> = { + "bee": new Bee(bugEmojiElement), + "spider": new Spider(bugEmojiElement), +}; + +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/693874cf5bf4aa32aded7ce5.md b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/693874cf5bf4aa32aded7ce5.md new file mode 100644 index 00000000000..8eb5a605c04 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/693874cf5bf4aa32aded7ce5.md @@ -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 + + + + + + Bug Emoji Picker + + + +
+
+ + +
+
+

🐝

+
+
+ + + +``` + +```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 { + emoji!: T; + emojiElement!: HTMLParagraphElement; + constructor(emojiElement: HTMLParagraphElement) { + this.emojiElement = emojiElement; + } + + abstract render(): void; +} + +class Bee extends Bug { + constructor(emojiElement: HTMLParagraphElement) { + super(emojiElement); + this.emoji = "🐝"; + } + + override render() { + this.emojiElement.innerText = this.emoji; + } +} + +class Spider extends Bug { + 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('#bug-emoji')!; +const bugMap: Record> = { + "bee": new Bee(bugEmojiElement), + "spider": new Spider(bugEmojiElement), +}; + +const selectElement = document.querySelector('#species')!; +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/69d902c4f58b8a0d48d19c67.md b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/69d902c4f58b8a0d48d19c67.md new file mode 100644 index 00000000000..d6d0d84691c --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/69d902c4f58b8a0d48d19c67.md @@ -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 + + + + + + Bug Emoji Picker + + + +
+
+ + +
+
+

🐝

+
+
+ + + +``` + +```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 { + emoji!: T; + emojiElement!: HTMLParagraphElement; + constructor(emojiElement: HTMLParagraphElement) { + this.emojiElement = emojiElement; + } + + abstract render(): void; +} + +class Bee extends Bug { + constructor(emojiElement: HTMLParagraphElement) { + super(emojiElement); + this.emoji = "🐝"; + } + + override render() { + this.emojiElement.innerText = this.emoji; + } +} + +class Spider extends Bug { + 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('#bug-emoji')!; +const bugMap: Record> = { +--fcc-editable-region-- + +--fcc-editable-region-- +}; +``` diff --git a/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/69d909f2946a3fcabed720c6.md b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/69d909f2946a3fcabed720c6.md new file mode 100644 index 00000000000..548bde44a44 --- /dev/null +++ b/curriculum/challenges/english/blocks/workshop-bug-emoji-picker/69d909f2946a3fcabed720c6.md @@ -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 + + + + + + Bug Emoji Picker + + + +
+
+ + +
+
+

🐝

+
+
+ + + +``` + +```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 { + emoji!: T; + emojiElement!: HTMLParagraphElement; + constructor(emojiElement: HTMLParagraphElement) { + this.emojiElement = emojiElement; + } + + abstract render(): void; +} + +class Bee extends Bug { + constructor(emojiElement: HTMLParagraphElement) { + super(emojiElement); + this.emoji = "🐝"; + } + + override render() { + this.emojiElement.innerText = this.emoji; + } +} + +class Spider extends Bug { + 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('#bug-emoji')!; +const bugMap: Record> = { + "bee": new Bee(bugEmojiElement), + "spider": new Spider(bugEmojiElement), +}; + +const selectElement = document.querySelector('#species')!; +selectElement.addEventListener("change", e => { + if (isSelect(e.target)) { +--fcc-editable-region-- + +--fcc-editable-region-- + } +}); +``` + +# --solutions-- + +```html + + + + + + Bug Emoji Picker + + + +
+
+ + +
+
+

🐝

+
+
+ + + +``` + +```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 { + emoji!: T; + emojiElement!: HTMLParagraphElement; + constructor(emojiElement: HTMLParagraphElement) { + this.emojiElement = emojiElement; + } + + abstract render(): void; +} + +class Bee extends Bug { + constructor(emojiElement: HTMLParagraphElement) { + super(emojiElement); + this.emoji = "🐝"; + } + + override render() { + this.emojiElement.innerText = this.emoji; + } +} + +class Spider extends Bug { + 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('#bug-emoji')!; +const bugMap: Record> = { + "bee": new Bee(bugEmojiElement), + "spider": new Spider(bugEmojiElement), +}; + +const selectElement = document.querySelector('#species')!; +selectElement.addEventListener("change", e => { + if (isSelect(e.target)) { + bugMap[e.target.value].render(); + } +}); +``` diff --git a/curriculum/structure/blocks/workshop-bug-emoji-picker.json b/curriculum/structure/blocks/workshop-bug-emoji-picker.json new file mode 100644 index 00000000000..0508fe3d806 --- /dev/null +++ b/curriculum/structure/blocks/workshop-bug-emoji-picker.json @@ -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 +} diff --git a/curriculum/structure/superblocks/front-end-development-libraries-v9.json b/curriculum/structure/superblocks/front-end-development-libraries-v9.json index 51cee03b4db..0a4a352b334 100644 --- a/curriculum/structure/superblocks/front-end-development-libraries-v9.json +++ b/curriculum/structure/superblocks/front-end-development-libraries-v9.json @@ -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"