diff --git a/client/i18n/locales/english/intro.json b/client/i18n/locales/english/intro.json index 074ba6705c82e1..d9c031bde8bcb7 100644 --- a/client/i18n/locales/english/intro.json +++ b/client/i18n/locales/english/intro.json @@ -3306,7 +3306,10 @@ ] }, "oxiv": { "title": "260", "intro": [] }, - "fjvx": { "title": "261", "intro": [] }, + "lab-reusable-footer": { + "title": "Build a Reusable Footer", + "intro": ["In this lab, you will use React to build a reusable footer."] + }, "lecture-working-with-data-in-react": { "title": "Working with Data in React", "intro": [ diff --git a/client/src/pages/learn/full-stack-developer/lab-reusable-footer/index.md b/client/src/pages/learn/full-stack-developer/lab-reusable-footer/index.md new file mode 100644 index 00000000000000..ffe6459e81ee75 --- /dev/null +++ b/client/src/pages/learn/full-stack-developer/lab-reusable-footer/index.md @@ -0,0 +1,9 @@ +--- +title: Introduction to the Build a Reusable Footer +block: lab-reusable-footer +superBlock: full-stack-developer +--- + +## Introduction to the Build a Reusable Footer + +In this lab, you will use React to build a reusable footer. diff --git a/curriculum/challenges/_meta/lab-reusable-footer/meta.json b/curriculum/challenges/_meta/lab-reusable-footer/meta.json new file mode 100644 index 00000000000000..3d190d63cf1a02 --- /dev/null +++ b/curriculum/challenges/_meta/lab-reusable-footer/meta.json @@ -0,0 +1,11 @@ +{ + "name": "Build a Reusable Footer", + "isUpcomingChange": true, + "usesMultifileEditor": true, + "dashedName": "lab-reusable-footer", + "superBlock": "full-stack-developer", + "challengeOrder": [{ "id": "673b02b03134b04637bf7055", "title": "Build a Reusable Footer" }], + "helpCategory": "HTML-CSS", + "blockLayout": "link", + "blockType": "lab" +} diff --git a/curriculum/challenges/english/25-front-end-development/lab-reusable-footer/673b02b03134b04637bf7055.md b/curriculum/challenges/english/25-front-end-development/lab-reusable-footer/673b02b03134b04637bf7055.md new file mode 100644 index 00000000000000..025f562133821c --- /dev/null +++ b/curriculum/challenges/english/25-front-end-development/lab-reusable-footer/673b02b03134b04637bf7055.md @@ -0,0 +1,274 @@ +--- +id: 673b02b03134b04637bf7055 +title: Build a Reusable Footer +challengeType: 14 +dashedName: build-a-reusable-footer +demoType: onClick +--- + +# --description-- + +**Objective:** Fulfill the user stories below and get all the tests to pass to complete the lab. + +**User Stories:** + +1. You should export a `Footer` component. +2. Your `Footer` component should return a `footer` element that contains all the other elements. +3. Your `footer` element should have: + +- At least three unordered lists, each with at least two list items. +- At least one paragraph element with a copyright `©` symbol. +- At least three links with the `href` value set to `#` and the link content set to an icon or text of your choice. + +# --hints-- + +You should export a `Footer` component. + +```js +const mockedComponent = Enzyme.mount(React.createElement(window.index.Footer)); +assert.lengthOf(mockedComponent.find('Footer'), 1); +``` + +Your `Footer` component should return a `footer` element. + +```js +assert.equal(Enzyme.shallow(React.createElement(window.index.Footer)).type(), 'footer'); +``` + +Your `footer` should have at least three unordered lists. + +```js +const mockedComponent = Enzyme.shallow(React.createElement(window.index.Footer)); +assert.isAtLeast(mockedComponent.find('ul').length, 3); +``` + +Each of your unordered lists should have at least two list items. + +```js +const mockedComponent = Enzyme.shallow(React.createElement(window.index.Footer)); +const uls = mockedComponent.find('ul'); +uls.forEach(ul => { + assert.isAtLeast(ul.find('li').length, 2); +}); + +assert.isAtLeast(uls.length, 1); +``` + +Your `footer` should have at least one paragraph element. + +```js +const mockedComponent = Enzyme.shallow(React.createElement(window.index.Footer)); +assert.isAtLeast(mockedComponent.find('p').length, 1); +``` + +You should have a copyright (`©`) symbol within one of your paragraphs. + +```js +const mockedComponent = Enzyme.shallow(React.createElement(window.index.Footer)); +let hasCopyright = false; +mockedComponent.find('p').forEach(p => { + if(p.text().includes('©')) { + hasCopyright = true; + } +}); +assert.isTrue(hasCopyright); +``` + +Your `footer` should have at least three links with the `href` value set to `#`. + +```js +const mockedComponent = Enzyme.shallow(React.createElement(window.index.Footer)); +assert.isAtLeast(mockedComponent.find('a[href="#"]').length, 3); +``` + +None of your links should be empty. + +```js +const mockedComponent = Enzyme.shallow(React.createElement(window.index.Footer)); +mockedComponent.find('a').forEach(a => { + assert.isAtLeast(a.text().length, 1); +}); +assert.isAtLeast(mockedComponent.find('a').length, 1); +``` + +Your `Footer` component should be rendered to the page's `#root` element. + +```js +const mockedComponent = Enzyme.mount(React.createElement(window.index.Footer)); +assert.equal(mockedComponent.html(), document.getElementById('root').innerHTML); +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + Reusable Footer Component + + + + + + + + +
+ + + + +``` + +```css + +``` + +```jsx +export const Footer = () => { + +}; +``` + +# --solutions-- + +```html + + + + + + Reusable Footer Component + + + + + + + + +
+ + + + +``` + +```css +.footer { + background-color: #e3e1eb; + padding: 20px; + text-align: center; + border-top: 1px solid #e5e7eb; + font-family: Arial, sans-serif; +} + +.footer-section { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 20px; + justify-content: center; + margin-bottom: 20px; + align-items: center; +} + +.footer ul { + list-style: none; + padding: 0; + margin: 0; +} + +.footer li { + margin-bottom: 10px; +} + +.footer a { + text-decoration: none; + color: #1f2937; +} + +.footer a:hover { + color: #6366f1; +} + +.footer p { + color: #6b7280; + margin-top: 20px; +} + +.footer-icons { + margin-top: 20px; + display: flex; + justify-content: center; +} + +.footer-icons a { + margin: 0 10px; + font-size: 24px; + color: #6b7280; + text-decoration: none; +} + +.footer-icons a:hover { + color: #6366f1; +} +``` + +```jsx +export const Footer = () => + +``` diff --git a/curriculum/superblock-structure/full-stack.json b/curriculum/superblock-structure/full-stack.json index 253d19f33bc0fc..ec90f936c8141f 100644 --- a/curriculum/superblock-structure/full-stack.json +++ b/curriculum/superblock-structure/full-stack.json @@ -548,6 +548,7 @@ { "dashedName": "lecture-introduction-to-javascript-libraries-and-frameworks" }, + { "dashedName": "lab-reusable-footer" }, { "dashedName": "lecture-working-with-data-in-react" }, { "dashedName": "review-react-basics" }, { "dashedName": "quiz-react-basics" }