mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-01-10 09:05:55 -05:00
feat: remove legacy RWD projects (#50960)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"responsive-web-design": {
|
||||
"title": "Legacy Responsive Web Design",
|
||||
"title": "Legacy Responsive Web Design Challenges",
|
||||
"intro": [
|
||||
"In this Responsive Web Design Certification, you'll learn the languages that developers use to build webpages: HTML (Hypertext Markup Language) for content, and CSS (Cascading Style Sheets) for design.",
|
||||
"First, you'll build a cat photo app to learn the basics of HTML and CSS. Later, you'll learn modern techniques like CSS variables by building a penguin, and best practices for accessibility by building a web form.",
|
||||
@@ -56,13 +56,6 @@
|
||||
"The CSS grid is a newer standard that makes it easy to build complex responsive layouts. It works by turning an HTML element into a grid, and lets you place child elements anywhere within.",
|
||||
"In this course, you'll learn the fundamentals of CSS grid by building different complex layouts, including a blog."
|
||||
]
|
||||
},
|
||||
"responsive-web-design-projects": {
|
||||
"title": "Responsive Web Design Projects",
|
||||
"intro": [
|
||||
"Time to put your newly learnt skills to work. By working on these projects, you will get a chance to apply all of the skills, principles, and concepts you have learned so far: HTML, CSS, Visual Design, Accessibility, and more.",
|
||||
"Complete the five web programming projects below to earn your Responsive Web Design certification."
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -458,7 +451,10 @@
|
||||
"In these projects, you'll need to fetch data and parse a dataset, then use D3 to create different data visualizations. Finish them all to earn your Data Visualization certification."
|
||||
]
|
||||
},
|
||||
"d3-dashboard": { "title": "D3 Dashboard", "intro": ["", ""] }
|
||||
"d3-dashboard": {
|
||||
"title": "D3 Dashboard",
|
||||
"intro": ["", ""]
|
||||
}
|
||||
}
|
||||
},
|
||||
"relational-database": {
|
||||
|
||||
@@ -181,6 +181,7 @@ const SuperBlockIntroductionPage = (props: SuperBlockProp) => {
|
||||
const defaultCurriculumNames = blockDashedNames;
|
||||
|
||||
const superblockWithoutCert = [
|
||||
SuperBlocks.RespWebDesign,
|
||||
SuperBlocks.CodingInterviewPrep,
|
||||
SuperBlocks.TheOdinProject,
|
||||
SuperBlocks.ProjectEuler
|
||||
|
||||
@@ -10,6 +10,7 @@ enum SuperBlockI18nKeys {
|
||||
// the map and window. e.g. 'Certification' in Responsive Web Design
|
||||
// Certification
|
||||
const superBlocksWithoutLastWord = [
|
||||
SuperBlocks.RespWebDesign,
|
||||
SuperBlocks.CodingInterviewPrep,
|
||||
SuperBlocks.TheOdinProject,
|
||||
SuperBlocks.ProjectEuler
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"name": "Responsive Web Design Projects",
|
||||
"isUpcomingChange": false,
|
||||
"usesMultifileEditor": true,
|
||||
"dashedName": "responsive-web-design-projects",
|
||||
"helpCategory": "HTML-CSS",
|
||||
"order": 7,
|
||||
"time": "150 hours",
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "responsive-web-design",
|
||||
"challengeOrder": [
|
||||
{
|
||||
"id": "bd7158d8c442eddfaeb5bd18",
|
||||
"title": "Build a Tribute Page"
|
||||
},
|
||||
{
|
||||
"id": "587d78af367417b2b2512b03",
|
||||
"title": "Build a Survey Form"
|
||||
},
|
||||
{
|
||||
"id": "587d78af367417b2b2512b04",
|
||||
"title": "Build a Product Landing Page"
|
||||
},
|
||||
{
|
||||
"id": "587d78b0367417b2b2512b05",
|
||||
"title": "Build a Technical Documentation Page"
|
||||
},
|
||||
{
|
||||
"id": "bd7158d8c242eddfaeb5bd13",
|
||||
"title": "Build a Personal Portfolio Webpage"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,281 +0,0 @@
|
||||
---
|
||||
id: bd7158d8c242eddfaeb5bd13
|
||||
title: Build a Personal Portfolio Webpage
|
||||
challengeType: 14
|
||||
forumTopicId: 301143
|
||||
dashedName: build-a-personal-portfolio-webpage
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
**Objective:** Build an app that is functionally similar to <a href="https://personal-portfolio.freecodecamp.rocks" target="_blank" rel="noopener noreferrer nofollow">https://personal-portfolio.freecodecamp.rocks</a>
|
||||
|
||||
**User Stories:**
|
||||
|
||||
1. Your portfolio should have a welcome section with an `id` of `welcome-section`
|
||||
1. The welcome section should have an `h1` element that contains text
|
||||
1. Your portfolio should have a projects section with an `id` of `projects`
|
||||
1. The projects section should contain at least one element with a `class` of `project-tile` to hold a project
|
||||
1. The projects section should contain at least one link to a project
|
||||
1. Your portfolio should have a navbar with an id of `navbar`
|
||||
1. The navbar should contain at least one link that you can click on to navigate to different sections of the page
|
||||
1. Your portfolio should have a link with an id of `profile-link`, which opens your GitHub or freeCodeCamp profile in a new tab
|
||||
1. Your portfolio should have at least one media query
|
||||
1. The height of the welcome section should be equal to the height of the viewport
|
||||
1. The navbar should always be at the top of the viewport
|
||||
|
||||
Fulfill the user stories and pass all the tests below to complete this project. Give it your own personal style. Happy Coding!
|
||||
|
||||
**Note:** Be sure to add `<link rel="stylesheet" href="styles.css">` in your HTML to link your stylesheet and apply your CSS
|
||||
|
||||
# --hints--
|
||||
|
||||
Your portfolio should have a "Welcome" section with an `id` of `welcome-section`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('welcome-section')
|
||||
assert(!!el);
|
||||
```
|
||||
|
||||
Your `#welcome-section` element should contain an `h1` element.
|
||||
|
||||
```js
|
||||
assert.isAbove(
|
||||
document.querySelectorAll('#welcome-section h1').length,
|
||||
0,
|
||||
'Welcome section should contain an h1 element '
|
||||
);
|
||||
```
|
||||
|
||||
You should not have any empty `h1` elements within `#welcome-section` element.
|
||||
|
||||
```js
|
||||
assert.isAbove(
|
||||
document.querySelectorAll('#welcome-section h1')?.[0]?.innerText?.length,
|
||||
0,
|
||||
'h1 element in welcome section should contain your name or camper ' +
|
||||
'name '
|
||||
);
|
||||
```
|
||||
|
||||
You should have a "Projects" section with an `id` of `projects`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('projects')
|
||||
assert(!!el);
|
||||
```
|
||||
|
||||
Your portfolio should contain at least one element with a class of `project-tile`.
|
||||
|
||||
```js
|
||||
assert.isAbove(
|
||||
document.querySelectorAll('#projects .project-tile').length,
|
||||
0
|
||||
);
|
||||
```
|
||||
|
||||
Your `#projects` element should contain at least one `a` element.
|
||||
|
||||
```js
|
||||
assert.isAbove(document.querySelectorAll('#projects a').length, 0);
|
||||
```
|
||||
|
||||
Your portfolio should have a navbar with an `id` of `navbar`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('navbar');
|
||||
assert(!!el);
|
||||
```
|
||||
|
||||
Your `#navbar` element should contain at least one `a` element whose `href` attribute starts with `#`.
|
||||
|
||||
```js
|
||||
const links = [...document.querySelectorAll('#navbar a')].filter(
|
||||
(nav) => (nav?.getAttribute('href') || '').substring(0, 1) === '#'
|
||||
);
|
||||
|
||||
assert.isAbove(
|
||||
links.length,
|
||||
0,
|
||||
'Navbar should contain an anchor link '
|
||||
);
|
||||
```
|
||||
|
||||
Your portfolio should have an `a` element with an `id` of `profile-link`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('profile-link');
|
||||
assert(!!el && el.tagName === 'A')
|
||||
```
|
||||
|
||||
Your `#profile-link` element should have a `target` attribute of `_blank`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('profile-link');
|
||||
assert(!!el && el.target === '_blank')
|
||||
```
|
||||
|
||||
Your portfolio should use at least one media query.
|
||||
|
||||
```js
|
||||
const htmlSourceAttr = Array.from(document.querySelectorAll('source')).map(el => el.getAttribute('media'))
|
||||
const cssCheck = new __helpers.CSSHelp(document).getCSSRules('media')
|
||||
assert(cssCheck.length > 0 || htmlSourceAttr.length > 0);
|
||||
```
|
||||
|
||||
Your `#navbar` element should always be at the top of the viewport.
|
||||
|
||||
```js
|
||||
(async () => {
|
||||
const timeout = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
|
||||
|
||||
const navbar = document.getElementById('navbar');
|
||||
assert.approximately(
|
||||
navbar?.getBoundingClientRect().top,
|
||||
0,
|
||||
15,
|
||||
"Navbar's parent should be body and it should be at the top of " +
|
||||
'the viewport '
|
||||
);
|
||||
|
||||
window.scroll(0, 500);
|
||||
|
||||
await timeout(1);
|
||||
|
||||
assert.approximately(
|
||||
navbar?.getBoundingClientRect().top,
|
||||
0,
|
||||
15,
|
||||
'Navbar should be at the top of the viewport even after ' +
|
||||
'scrolling '
|
||||
);
|
||||
window.scroll(0, 0);
|
||||
})();
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
|
||||
```
|
||||
|
||||
```css
|
||||
|
||||
```
|
||||
|
||||
## --solutions--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<title>Personal Portfolio</title>
|
||||
</head>
|
||||
<body>
|
||||
<link href="https://fonts.googleapis.com/css?family=Pacifico" rel="stylesheet">
|
||||
<!--Font Reference-->
|
||||
<nav id="navbar">
|
||||
<a href="#projects">Projects</a> |
|
||||
<a href="#contact">Contact me</a>
|
||||
</nav>
|
||||
<main>
|
||||
<section id="welcome-section">
|
||||
<br>
|
||||
<h1>It's me!</h1>
|
||||
<img src="https://s.cdpn.io/profiles/user/4369153/512.jpg?1587151780" height=100px>
|
||||
<h2>Naomi Carrigan</h2>
|
||||
<p>Welcome to my portfolio page!</p>
|
||||
</section><hr>
|
||||
<section id="projects">
|
||||
<h1>Projects</h1>
|
||||
<h2><a href="https://codepen.io/nhcarrigan">Here's what I've worked on!</a></h2>
|
||||
<p class="project-tile">
|
||||
<iframe height="265" style="width: 25;" scrolling="no" title="Algebraic Concepts" src="https://codepen.io/nhcarrigan/embed/preview/NWGrWBR?height=265&theme-id=dark&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true" loading="lazy">
|
||||
See the Pen <a href='https://codepen.io/nhcarrigan/pen/NWGrWBR'>Algebraic Concepts</a> by Naomi Carrigan
|
||||
(<a href='https://codepen.io/nhcarrigan'>@nhcarrigan</a>) on <a href='https://codepen.io'>CodePen</a>.
|
||||
</iframe>
|
||||
<iframe height="265" style="width: 25;" scrolling="no" title="Pokemon Daycare Service" src="https://codepen.io/nhcarrigan/embed/preview/mdeEbeq?height=265&theme-id=dark&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true" loading="lazy">
|
||||
See the Pen <a href='https://codepen.io/nhcarrigan/pen/mdeEbeq'>Pokemon Daycare Service</a> by Naomi Carrigan
|
||||
(<a href='https://codepen.io/nhcarrigan'>@nhcarrigan</a>) on <a href='https://codepen.io'>CodePen</a>.
|
||||
</iframe>
|
||||
<iframe height="265" style="width: 25;" scrolling="no" title="Togepi Fan Club" src="https://codepen.io/nhcarrigan/embed/preview/vYNGoBE?height=265&theme-id=dark&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true" loading="lazy">
|
||||
See the Pen <a href='https://codepen.io/nhcarrigan/pen/vYNGoBE'>Togepi Fan Club</a> by Naomi Carrigan
|
||||
(<a href='https://codepen.io/nhcarrigan'>@nhcarrigan</a>) on <a href='https://codepen.io'>CodePen</a>.
|
||||
</iframe>
|
||||
<iframe height="265" style="width: 25;" scrolling="no" title="Togepi" src="https://codepen.io/nhcarrigan/embed/preview/yLYOWEN?height=265&theme-id=dark&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true" loading="lazy">
|
||||
See the Pen <a href='https://codepen.io/nhcarrigan/pen/yLYOWEN'>Togepi</a> by Naomi Carrigan
|
||||
(<a href='https://codepen.io/nhcarrigan'>@nhcarrigan</a>) on <a href='https://codepen.io'>CodePen</a>.
|
||||
</iframe>
|
||||
</p></section><hr>
|
||||
<section id="contact">
|
||||
<h1>Contact me!</h1>
|
||||
<h2>Use the links below to get in touch.</h2>
|
||||
<p><a href="https://www.freecodecamp.org/nhcarrigan" id="profile-link" target="_blank" rel="noopener noreferrer">FreeCodeCamp.org</a> | <a href="https://github.com/nhcarrigan" id="github-link" target="_blank" rel="noopener noreferrer">GitHub</a> | <a href="https://www.facebook.com/nhcarrigan" id="facebook-link" target="_blank" rel="noopener noreferrer">Facebook</a> | <a href="https://www.linkedin.com/in/Naomi-l-carrigan/" id="linkedin-link" target="_blank" rel="noopener noreferrer">LinkedIn</a>
|
||||
</section>
|
||||
<footer><a href="../">Return to Project List</a> | <a href="https://www.nhcarrigan.com">Return to HomePage</a></footer>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
nav{
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
font-size: 24pt;
|
||||
top: 0%;
|
||||
right: 5px;
|
||||
background-color: #000000;
|
||||
color: #ffffff;
|
||||
}
|
||||
@media (max-width: 500px){
|
||||
nav{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
a{
|
||||
color: #ffffff;
|
||||
}
|
||||
main{
|
||||
text-align: center;
|
||||
background-color: black;
|
||||
font-family:Pacifico
|
||||
}
|
||||
h1{
|
||||
font-size: 48pt;
|
||||
}
|
||||
h2{
|
||||
font-size: 24pt;
|
||||
}
|
||||
p{
|
||||
font-size: 12pt;
|
||||
}
|
||||
#welcome-section{
|
||||
background-color:#251a4a;
|
||||
color: #FFFFFF;
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
#projects{
|
||||
background-color: #060a9c;
|
||||
color: #ffffff;
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
#contact{
|
||||
background-color: #03300b;
|
||||
color: #ffffff;
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
```
|
||||
@@ -1,470 +0,0 @@
|
||||
---
|
||||
id: 587d78af367417b2b2512b04
|
||||
title: Build a Product Landing Page
|
||||
challengeType: 14
|
||||
forumTopicId: 301144
|
||||
dashedName: build-a-product-landing-page
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
**Objective:** Build an app that is functionally similar to <a href="https://product-landing-page.freecodecamp.rocks" target="_blank" rel="noopener noreferrer nofollow">https://product-landing-page.freecodecamp.rocks</a>
|
||||
|
||||
**User Stories:**
|
||||
|
||||
1. Your product landing page should have a `header` element with a corresponding `id="header"`
|
||||
1. You can see an image within the `header` element with a corresponding `id="header-img"` (A logo would make a good image here)
|
||||
1. Within the `#header` element, you can see a `nav` element with a corresponding `id="nav-bar"`
|
||||
1. You can see at least three clickable elements inside the `nav` element, each with the class `nav-link`
|
||||
1. When you click a `.nav-link` button in the `nav` element, you are taken to the corresponding section of the landing page
|
||||
1. You can watch an embedded product video with `id="video"`
|
||||
1. Your landing page has a `form` element with a corresponding `id="form"`
|
||||
1. Within the form, there is an `input` field with `id="email"` where you can enter an email address
|
||||
1. The `#email` input field should have placeholder text to let users know what the field is for
|
||||
1. The `#email` input field uses HTML5 validation to confirm that the entered text is an email address
|
||||
1. Within the form, there is a submit `input` with a corresponding `id="submit"`
|
||||
1. When you click the `#submit` element, the email is submitted to a static page (use this mock URL: `https://www.freecodecamp.com/email-submit`)
|
||||
1. The navbar should always be at the top of the viewport
|
||||
1. Your product landing page should have at least one media query
|
||||
1. Your product landing page should utilize CSS flexbox at least once
|
||||
|
||||
Fulfill the user stories and pass all the tests below to complete this project. Give it your own personal style. Happy Coding!
|
||||
|
||||
**Note:** Be sure to add `<link rel="stylesheet" href="styles.css">` in your HTML to link your stylesheet and apply your CSS
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a `header` element with an `id` of `header`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('header')
|
||||
assert(!!el && el.tagName === 'HEADER')
|
||||
```
|
||||
|
||||
You should have an `img` element with an `id` of `header-img`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('header-img')
|
||||
assert(!!el && el.tagName === 'IMG')
|
||||
```
|
||||
|
||||
Your `#header-img` should be a descendant of the `#header`.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('#header #header-img')
|
||||
assert(els.length > 0)
|
||||
```
|
||||
|
||||
Your `#header-img` should have a `src` attribute.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('header-img')
|
||||
assert(!!el && !!el.src)
|
||||
```
|
||||
|
||||
Your `#header-img`’s `src` value should be a valid URL (starts with `http`).
|
||||
|
||||
```js
|
||||
const el = document.getElementById('header-img')
|
||||
assert(!!el && /^http/.test(el.src))
|
||||
```
|
||||
|
||||
You should have a `nav` element with an `id` of `nav-bar`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('nav-bar')
|
||||
assert(!!el && el.tagName === 'NAV')
|
||||
```
|
||||
|
||||
Your `#nav-bar` should be a descendant of the `#header`.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('#header #nav-bar')
|
||||
assert(els.length > 0)
|
||||
```
|
||||
|
||||
You should have at least 3 `.nav-link` elements within the `#nav-bar`.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('#nav-bar .nav-link')
|
||||
assert(els.length >= 3)
|
||||
```
|
||||
|
||||
Each `.nav-link` element should have an `href` attribute.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('.nav-link')
|
||||
els.forEach(el => {
|
||||
if (!el.href) assert(false)
|
||||
})
|
||||
assert(els.length > 0)
|
||||
```
|
||||
|
||||
Each `.nav-link` element should link to a corresponding element on the landing page (has an `href` with a value of another element's id. e.g. `#footer`).
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('.nav-link')
|
||||
els.forEach(el => {
|
||||
const linkDestination = el.getAttribute('href').slice(1)
|
||||
if (!document.getElementById(linkDestination)) assert(false)
|
||||
})
|
||||
assert(els.length > 0)
|
||||
```
|
||||
|
||||
You should have a `video` or `iframe` element with an `id` of `video`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('video')
|
||||
assert(!!el && (el.tagName === 'VIDEO' || el.tagName === 'IFRAME'))
|
||||
```
|
||||
|
||||
Your `#video` should have a `src` attribute.
|
||||
|
||||
```js
|
||||
let el = document.getElementById('video')
|
||||
const sourceNode = el.children;
|
||||
let sourceElement = null;
|
||||
if (sourceNode.length) {
|
||||
sourceElement = [...video.children].filter(el => el.localName === 'source')[0];
|
||||
}
|
||||
if (sourceElement) {
|
||||
el = sourceElement;
|
||||
}
|
||||
assert(el.hasAttribute('src'));
|
||||
```
|
||||
|
||||
You should have a `form` element with an `id` of `form`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('form')
|
||||
assert(!!el && el.tagName === 'FORM')
|
||||
```
|
||||
|
||||
You should have an `input` element with an `id` of `email`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('email')
|
||||
assert(!!el && el.tagName === 'INPUT')
|
||||
```
|
||||
|
||||
Your `#email` should be a descendant of the `#form`.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('#form #email')
|
||||
assert(els.length > 0)
|
||||
```
|
||||
|
||||
Your `#email` should have the `placeholder` attribute with placeholder text.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('email')
|
||||
assert(!!el && !!el.placeholder && el.placeholder.length > 0)
|
||||
```
|
||||
|
||||
Your `#email` should use HTML5 validation by setting its `type` to `email`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('email')
|
||||
assert(!!el && el.type === 'email')
|
||||
```
|
||||
|
||||
You should have an `input` element with an `id` of `submit`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('submit')
|
||||
assert(!!el && el.tagName === 'INPUT')
|
||||
```
|
||||
|
||||
Your `#submit` should be a descendant of the `#form`.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('#form #submit')
|
||||
assert(els.length > 0)
|
||||
```
|
||||
|
||||
Your `#submit` should have a `type` of `submit`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('submit')
|
||||
assert(!!el && el.type === 'submit')
|
||||
```
|
||||
|
||||
Your `#form` should have an `action` attribute of `https://www.freecodecamp.com/email-submit`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('form')
|
||||
assert(!!el && el.action === 'https://www.freecodecamp.com/email-submit')
|
||||
```
|
||||
|
||||
Your `#email` should have a `name` attribute of `email`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('email')
|
||||
assert(!!el && el.name === 'email')
|
||||
```
|
||||
|
||||
Your `#nav-bar` should always be at the top of the viewport.
|
||||
|
||||
```js
|
||||
(async () => {
|
||||
const timeout = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
|
||||
|
||||
const header = document.getElementById('header');
|
||||
const headerChildren = header.children;
|
||||
const navbarCandidates = [header, ...headerChildren];
|
||||
|
||||
// Return smallest top position of all navbar candidates
|
||||
const getNavbarPosition = (candidates = []) => {
|
||||
return candidates.reduce(
|
||||
(min, candidate) =>
|
||||
Math.min(min, Math.abs(candidate?.getBoundingClientRect().top)),
|
||||
Infinity
|
||||
);
|
||||
};
|
||||
assert.approximately(
|
||||
getNavbarPosition(navbarCandidates),
|
||||
0,
|
||||
15,
|
||||
'#header or one of its children should be at the top of the viewport '
|
||||
);
|
||||
|
||||
window.scroll(0, 500);
|
||||
await timeout(1);
|
||||
|
||||
assert.approximately(
|
||||
getNavbarPosition(navbarCandidates),
|
||||
0,
|
||||
15,
|
||||
'#header or one of its children should be at the top of the ' +
|
||||
'viewport even after scrolling '
|
||||
);
|
||||
|
||||
window.scroll(0, 0);
|
||||
})();
|
||||
```
|
||||
|
||||
Your Product Landing Page should use at least one media query.
|
||||
|
||||
```js
|
||||
const htmlSourceAttr = Array.from(document.querySelectorAll('source')).map(el => el.getAttribute('media'))
|
||||
const cssCheck = new __helpers.CSSHelp(document).getCSSRules('media')
|
||||
assert(cssCheck.length > 0 || htmlSourceAttr.length > 0);
|
||||
```
|
||||
|
||||
Your Product Landing Page should use CSS Flexbox at least once.
|
||||
|
||||
```js
|
||||
const hasFlex = (rule) => ["flex", "inline-flex"].includes(rule.style?.display)
|
||||
const stylesheet = new __helpers.CSSHelp(document).getStyleSheet()
|
||||
const cssRules = new __helpers.CSSHelp(document).styleSheetToCssRulesArray(stylesheet)
|
||||
const mediaRules = new __helpers.CSSHelp(document).getCSSRules('media')
|
||||
const usesFlex = cssRules.find(rule => hasFlex(rule))
|
||||
const usesFlexMedia = mediaRules.find(mediaRule => {
|
||||
return [...mediaRule.cssRules].find(rule => hasFlex(rule))
|
||||
})
|
||||
assert(usesFlex || usesFlexMedia)
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
|
||||
```
|
||||
|
||||
```css
|
||||
|
||||
```
|
||||
|
||||
## --solutions--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
<title>Product Landing Page</title>
|
||||
</head>
|
||||
<body>
|
||||
<header id="header">
|
||||
<nav id="nav-bar">
|
||||
<img
|
||||
id="header-img"
|
||||
src="https://upload.wikimedia.org/wikipedia/commons/3/39/Pokeball.PNG"
|
||||
max-height="50px"
|
||||
/>
|
||||
<a href="#Features" class="nav-link">Features</a> |
|
||||
<a href="#Video" class="nav-link">See our facility!</a> |
|
||||
<a href="#Pricing" class="nav-link">Purchase</a>
|
||||
<hr />
|
||||
</nav>
|
||||
</header>
|
||||
<main>
|
||||
<h1>
|
||||
Pokemon Daycare Service
|
||||
</h1>
|
||||
<section id="Features">
|
||||
<h2>What we offer</h2>
|
||||
<div class="flex-here">
|
||||
<div class="flex-left">
|
||||
<img
|
||||
id="bullet"
|
||||
src="https://upload.wikimedia.org/wikipedia/commons/3/39/Pokeball.PNG"
|
||||
max-height="25px"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex-right">Guaranteed friendly and loving staff!</div>
|
||||
</div>
|
||||
<div class="flex-here">
|
||||
<div class="flex-left">
|
||||
<img
|
||||
id="bullet"
|
||||
src="https://upload.wikimedia.org/wikipedia/commons/3/39/Pokeball.PNG"
|
||||
max-height="25px"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex-right">
|
||||
Comfortable environment for Pokemon to explore and play!
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-here">
|
||||
<div class="flex-left">
|
||||
<img
|
||||
id="bullet"
|
||||
src="https://upload.wikimedia.org/wikipedia/commons/3/39/Pokeball.PNG"
|
||||
max-height="25px"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex-right">
|
||||
Multiple membership plans to fit your lifestyle!
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="Video">
|
||||
<h2>Check us out!</h2>
|
||||
A sneak peek into our facility:
|
||||
<br />
|
||||
<iframe
|
||||
id="video"
|
||||
width="520"
|
||||
height="347"
|
||||
src="https://www.youtube.com/embed/Nw-ksH2r6AQ"
|
||||
frameborder="0"
|
||||
allowfullscreen
|
||||
alt="A video tour of our facility"
|
||||
>
|
||||
</iframe>
|
||||
</section>
|
||||
<section id="Pricing">
|
||||
<h2>Membership Plans</h2>
|
||||
<div class="flex-mem">
|
||||
<div class="flex-mem-box">
|
||||
<font size="+2">Basic Membership</font><br />
|
||||
<ul>
|
||||
<li>One Pokemon</li>
|
||||
<li>Food and berries provided</li>
|
||||
</ul>
|
||||
<em>$9.99/month</em>
|
||||
</div>
|
||||
<div class="flex-mem-box">
|
||||
<font size="+2">Silver Membership</font><br />
|
||||
<ul>
|
||||
<li>Up to Three Pokemon</li>
|
||||
<li>Food and berries provided</li>
|
||||
<li>Grooming and accessories included</li>
|
||||
</ul>
|
||||
<em>$19.99/month</em>
|
||||
</div>
|
||||
<div class="flex-mem-box">
|
||||
<font size="+2">Gold Membership</font><br />
|
||||
<ul>
|
||||
<li>Up to six Pokemon!</li>
|
||||
<li>Food and berries provided</li>
|
||||
<li>Grooming and accessories included</li>
|
||||
<li>Personal training for each Pokemon</li>
|
||||
<li>Breeding and egg hatching</li>
|
||||
</ul>
|
||||
<em>$29.99/month</em>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<form id="form" action="https://www.freecodecamp.com/email-submit">
|
||||
<p>Sign up for our newsletter!</p>
|
||||
<label for="email"><p>Email:</p><input name="email" id="email" type="email" placeholder="johnsmith@email.com" required></label>
|
||||
<input type="submit" id="submit">
|
||||
</form>
|
||||
<footer>
|
||||
<a href="../">Return to Project List</a> |
|
||||
<a href="https://www.nhcarrigan.com">Return to HomePage</a>
|
||||
</footer>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
body {
|
||||
background-color: #3a3240;
|
||||
color: white;
|
||||
}
|
||||
main {
|
||||
max-width: 750px;
|
||||
margin: 50px auto;
|
||||
}
|
||||
input {
|
||||
background-color: #92869c;
|
||||
}
|
||||
a:not(.nav-link) {
|
||||
color: white;
|
||||
}
|
||||
#header-img {
|
||||
max-height: 25px;
|
||||
}
|
||||
#nav-bar {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
top: 0%;
|
||||
background-color: #92869c;
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
body {
|
||||
text-align: center;
|
||||
}
|
||||
footer {
|
||||
text-align: center;
|
||||
}
|
||||
#bullet {
|
||||
max-height: 25px;
|
||||
}
|
||||
.flex-here {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.flex-left {
|
||||
height: 25px;
|
||||
}
|
||||
.flex-mem {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.flex-mem-box {
|
||||
background-color: #92869c;
|
||||
border-color: black;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
margin: 10px;
|
||||
padding: 10px;
|
||||
color: black;
|
||||
}
|
||||
@media (max-width: 350px) {
|
||||
#video {
|
||||
width: 300;
|
||||
height: 200;
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,518 +0,0 @@
|
||||
---
|
||||
id: 587d78af367417b2b2512b03
|
||||
title: Build a Survey Form
|
||||
challengeType: 14
|
||||
forumTopicId: 301145
|
||||
dashedName: build-a-survey-form
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
**Objective:** Build an app that is functionally similar to <a href="https://survey-form.freecodecamp.rocks" target="_blank" rel="noopener noreferrer nofollow">https://survey-form.freecodecamp.rocks</a>
|
||||
|
||||
**User Stories:**
|
||||
|
||||
1. You should have a page title in an `h1` element with an `id` of `title`
|
||||
1. You should have a short explanation in a `p` element with an `id` of `description`
|
||||
1. You should have a `form` element with an `id` of `survey-form`
|
||||
1. Inside the form element, you are **required** to enter your name in an `input` field that has an `id` of `name` and a `type` of `text`
|
||||
1. Inside the form element, you are **required** to enter your email in an `input` field that has an `id` of `email`
|
||||
1. If you enter an email that is not formatted correctly, you will see an HTML5 validation error
|
||||
1. Inside the form, you can enter a number in an `input` field that has an `id` of `number`
|
||||
1. The number input should not accept non-numbers, either by preventing you from typing them or by showing an HTML5 validation error (depending on your browser).
|
||||
1. If you enter numbers outside the range of the number input, which are defined by the `min` and `max` attributes, you will see an HTML5 validation error
|
||||
1. For the name, email, and number input fields, you can see corresponding `label` elements in the form, that describe the purpose of each field with the following ids: `id="name-label"`, `id="email-label"`, and `id="number-label"`
|
||||
1. For the name, email, and number input fields, you can see placeholder text that gives a description or instructions for each field
|
||||
1. Inside the form element, you should have a `select` dropdown element with an `id` of `dropdown` and at least two options to choose from
|
||||
1. Inside the form element, you can select an option from a group of at least two radio buttons that are grouped using the `name` attribute
|
||||
1. Inside the form element, you can select several fields from a series of checkboxes, each of which must have a `value` attribute
|
||||
1. Inside the form element, you are presented with a `textarea` for additional comments
|
||||
1. Inside the form element, you are presented with a button with `id` of `submit` to submit all the inputs
|
||||
|
||||
Fulfill the user stories and pass all the tests below to complete this project. Give it your own personal style. Happy Coding!
|
||||
|
||||
**Note:** Be sure to add `<link rel="stylesheet" href="styles.css">` in your HTML to link your stylesheet and apply your CSS
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have an `h1` element with an `id` of `title`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('title')
|
||||
assert(!!el && el.tagName === 'H1')
|
||||
```
|
||||
|
||||
Your `#title` should not be empty.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('title')
|
||||
assert(!!el && el.innerText.length > 0)
|
||||
```
|
||||
|
||||
You should have a `p` element with an `id` of `description`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('description')
|
||||
assert(!!el && el.tagName === 'P')
|
||||
```
|
||||
|
||||
Your `#description` should not be empty.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('description')
|
||||
assert(!!el && el.innerText.length > 0)
|
||||
```
|
||||
|
||||
You should have a `form` element with an `id` of `survey-form`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('survey-form')
|
||||
assert(!!el && el.tagName === 'FORM')
|
||||
```
|
||||
|
||||
You should have an `input` element with an `id` of `name`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('name')
|
||||
assert(!!el && el.tagName === 'INPUT')
|
||||
```
|
||||
|
||||
Your `#name` should have a `type` of `text`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('name')
|
||||
assert(!!el && el.type === 'text')
|
||||
```
|
||||
|
||||
Your `#name` should require input.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('name')
|
||||
assert(!!el && el.required)
|
||||
```
|
||||
|
||||
Your `#name` should be a descendant of `#survey-form`.
|
||||
|
||||
```js
|
||||
const el = document.querySelector('#survey-form #name')
|
||||
assert(!!el)
|
||||
```
|
||||
|
||||
You should have an `input` element with an `id` of `email`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('email')
|
||||
assert(!!el && el.tagName === 'INPUT')
|
||||
```
|
||||
|
||||
Your `#email` should have a `type` of `email`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('email')
|
||||
assert(!!el && el.type === 'email')
|
||||
```
|
||||
|
||||
Your `#email` should require input.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('email')
|
||||
assert(!!el && el.required)
|
||||
```
|
||||
|
||||
Your `#email` should be a descendant of `#survey-form`.
|
||||
|
||||
```js
|
||||
const el = document.querySelector('#survey-form #email')
|
||||
assert(!!el)
|
||||
```
|
||||
|
||||
You should have an `input` element with an `id` of `number`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('number')
|
||||
assert(!!el && el.tagName === 'INPUT')
|
||||
```
|
||||
|
||||
Your `#number` should be a descendant of `#survey-form`.
|
||||
|
||||
```js
|
||||
const el = document.querySelector('#survey-form #number')
|
||||
assert(!!el)
|
||||
```
|
||||
|
||||
Your `#number` should have a `type` of `number`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('number')
|
||||
assert(!!el && el.type === 'number')
|
||||
```
|
||||
|
||||
Your `#number` should have a `min` attribute with a numeric value.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('number')
|
||||
assert(!!el && el.min && isFinite(el.min))
|
||||
```
|
||||
|
||||
Your `#number` should have a `max` attribute with a numeric value.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('number')
|
||||
assert(!!el && el.max && isFinite(el.max))
|
||||
```
|
||||
|
||||
You should have a `label` element with an `id` of `name-label`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('name-label')
|
||||
assert(!!el && el.tagName === 'LABEL')
|
||||
```
|
||||
|
||||
You should have a `label` element with an `id` of `email-label`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('email-label')
|
||||
assert(!!el && el.tagName === 'LABEL')
|
||||
```
|
||||
|
||||
You should have a `label` element with an `id` of `number-label`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('number-label')
|
||||
assert(!!el && el.tagName === 'LABEL')
|
||||
```
|
||||
|
||||
Your `#name-label` should contain text that describes the input.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('name-label')
|
||||
assert(!!el && el.innerText.length > 0)
|
||||
```
|
||||
|
||||
Your `#email-label` should contain text that describes the input.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('email-label')
|
||||
assert(!!el && el.innerText.length > 0)
|
||||
```
|
||||
|
||||
Your `#number-label` should contain text that describes the input.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('number-label')
|
||||
assert(!!el && el.innerText.length > 0)
|
||||
```
|
||||
|
||||
Your `#name-label` should be a descendant of `#survey-form`.
|
||||
|
||||
```js
|
||||
const el = document.querySelector('#survey-form #name-label')
|
||||
assert(!!el)
|
||||
```
|
||||
|
||||
Your `#email-label` should be a descendant of `#survey-form`.
|
||||
|
||||
```js
|
||||
const el = document.querySelector('#survey-form #email-label')
|
||||
assert(!!el)
|
||||
```
|
||||
|
||||
Your `#number-label` should be a descendant of `#survey-form`.
|
||||
|
||||
```js
|
||||
const el = document.querySelector('#survey-form #number-label')
|
||||
assert(!!el)
|
||||
```
|
||||
|
||||
Your `#name` should have a `placeholder` attribute and value.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('name')
|
||||
assert(!!el && !!el.placeholder && el.placeholder.length > 0)
|
||||
```
|
||||
|
||||
Your `#email` should have a `placeholder` attribute and value.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('email')
|
||||
assert(!!el && !!el.placeholder && el.placeholder.length > 0)
|
||||
```
|
||||
|
||||
Your `#number` should have a `placeholder` attribute and value.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('number')
|
||||
assert(!!el && !!el.placeholder && el.placeholder.length > 0)
|
||||
```
|
||||
|
||||
You should have a `select` field with an `id` of `dropdown`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('dropdown')
|
||||
assert(!!el && el.tagName === 'SELECT')
|
||||
```
|
||||
|
||||
Your `#dropdown` should have at least two selectable (not disabled) `option` elements.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('#dropdown option:not([disabled])')
|
||||
assert(els.length >= 2)
|
||||
```
|
||||
|
||||
Your `#dropdown` should be a descendant of `#survey-form`.
|
||||
|
||||
```js
|
||||
const el = document.querySelector('#survey-form #dropdown')
|
||||
assert(!!el)
|
||||
```
|
||||
|
||||
You should have at least two `input` elements with a `type` of `radio` (radio buttons).
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('input[type="radio"]')
|
||||
assert(els.length >= 2)
|
||||
```
|
||||
|
||||
You should have at least two radio buttons that are descendants of `#survey-form`.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('#survey-form input[type="radio"]')
|
||||
assert(els.length >= 2)
|
||||
```
|
||||
|
||||
All your radio buttons should have a `value` attribute and value.
|
||||
|
||||
```js
|
||||
const els1 = document.querySelectorAll('input[type="radio"]')
|
||||
const els2 = document.querySelectorAll('input[type="radio"][value=""], input[type="radio"]:not([value])')
|
||||
assert(els1.length > 0 && els2.length === 0)
|
||||
```
|
||||
|
||||
All your radio buttons should have a `name` attribute and value.
|
||||
|
||||
```js
|
||||
const els1 = document.querySelectorAll('input[type="radio"]')
|
||||
const els2 = document.querySelectorAll('input[type="radio"][name=""], input[type="radio"]:not([name])')
|
||||
assert(els1.length > 0 && els2.length === 0)
|
||||
```
|
||||
|
||||
Every radio button group should have at least 2 radio buttons.
|
||||
|
||||
```js
|
||||
const radioButtons = document.querySelectorAll('input[type="radio"]');
|
||||
const groups = {}
|
||||
|
||||
if (radioButtons) {
|
||||
radioButtons.forEach(el => {
|
||||
if (!groups[el.name]) groups[el.name] = []
|
||||
groups[el.name].push(el)
|
||||
})
|
||||
}
|
||||
|
||||
const groupKeys = Object.keys(groups)
|
||||
|
||||
groupKeys.forEach(key => {
|
||||
if (groups[key].length < 2) assert(false)
|
||||
})
|
||||
|
||||
assert(groupKeys.length > 0)
|
||||
```
|
||||
|
||||
You should have at least two `input` elements with a `type` of `checkbox` (checkboxes) that are descendants of `#survey-form`.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('#survey-form input[type="checkbox"]');
|
||||
assert(els.length >= 2)
|
||||
```
|
||||
|
||||
All your checkboxes inside `#survey-form` should have a `value` attribute and value.
|
||||
|
||||
```js
|
||||
const els1 = document.querySelectorAll('#survey-form input[type="checkbox"]')
|
||||
const els2 = document.querySelectorAll('#survey-form input[type="checkbox"][value=""], #survey-form input[type="checkbox"]:not([value])')
|
||||
assert(els1.length > 0 && els2.length === 0)
|
||||
```
|
||||
|
||||
You should have at least one `textarea` element that is a descendant of `#survey-form`.
|
||||
|
||||
```js
|
||||
const el = document.querySelector('#survey-form textarea')
|
||||
assert(!!el)
|
||||
```
|
||||
|
||||
You should have an `input` or `button` element with an `id` of `submit`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('submit')
|
||||
assert(!!el && (el.tagName === 'INPUT' || el.tagName === 'BUTTON'))
|
||||
```
|
||||
|
||||
Your `#submit` should have a `type` of `submit`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('submit')
|
||||
assert(!!el && el.type === 'submit')
|
||||
```
|
||||
|
||||
Your `#submit` should be a descendant of `#survey-form`.
|
||||
|
||||
```js
|
||||
const el = document.querySelector('#survey-form #submit')
|
||||
assert(!!el)
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
|
||||
```
|
||||
|
||||
```css
|
||||
|
||||
```
|
||||
|
||||
## --solutions--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
<title>Survey Form</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Survey Form</h1>
|
||||
<p>The card below was built as a sample survey form for freeCodeCamp.</p>
|
||||
<main id="main">
|
||||
<h1 id="title">Join the Togepi Fan Club!</h1>
|
||||
<p id="description">
|
||||
Enter your information here to receive updates about club activities,
|
||||
our monthly newsletter, and other email communications.
|
||||
</p>
|
||||
<form id="survey-form" action="#">
|
||||
<label for="name" id="name-label"
|
||||
><p>Name:</p>
|
||||
<input type="text" id="name" placeholder="e.g. John Smith" required />
|
||||
</label>
|
||||
<label for="email" id="email-label"
|
||||
><p>Email:</p>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
placeholder="e.g. john.smith@email.com"
|
||||
required
|
||||
/>
|
||||
</label>
|
||||
<label for="age" id="number-label"
|
||||
><p>Age<em>(optional)</em>:</p>
|
||||
<input
|
||||
type="number"
|
||||
id="number"
|
||||
placeholder="e.g. 19"
|
||||
min="18"
|
||||
max="99"
|
||||
/>
|
||||
</label>
|
||||
<label for="interest" id="interest-label"
|
||||
><p>What are you most interested in?</p>
|
||||
<select id="dropdown">
|
||||
<option selected disabled hidden></option>
|
||||
<option id="battles">Battling</option>
|
||||
<option id="breeding">Breeding</option>
|
||||
<option id="catching">Completing my Pokedex</option>
|
||||
<option id="exploring">Exploring new regions</option>
|
||||
</select>
|
||||
</label>
|
||||
<p>Who is your favourite Pokemon?</p>
|
||||
<label for="togepi">
|
||||
<input
|
||||
id="togepi"
|
||||
type="radio"
|
||||
name="favorite"
|
||||
value="togepi"
|
||||
/>Togepi!
|
||||
</label>
|
||||
<label for="pikachu">
|
||||
<input
|
||||
id="pikachu"
|
||||
type="radio"
|
||||
name="favorite"
|
||||
value="pikachu"
|
||||
/>Pikachu
|
||||
</label>
|
||||
<label for="other">
|
||||
<input id="other" type="radio" name="favorite" value="other" />Other
|
||||
</label>
|
||||
<p>Which communications do you want to receive?</p>
|
||||
<label for="newsletter">
|
||||
<input
|
||||
id="newsletter"
|
||||
type="checkbox"
|
||||
name="communications"
|
||||
value="newsletter"
|
||||
/>Newsletter
|
||||
</label>
|
||||
<label for="events">
|
||||
<input
|
||||
id="events"
|
||||
type="checkbox"
|
||||
name="communications"
|
||||
value="events"
|
||||
/>Event updates
|
||||
</label>
|
||||
<label for="updates">
|
||||
<input
|
||||
id="updates"
|
||||
type="checkbox"
|
||||
name="communications"
|
||||
value="updates"
|
||||
/>Club updates
|
||||
</label>
|
||||
<p>Any other information you would like to share?</p>
|
||||
<textarea id="additional-information" rows="4" cols="50">
|
||||
You can provide comments, suggestions, or feedback here.</textarea
|
||||
>
|
||||
<p>
|
||||
<em
|
||||
>Please note: This form is a proof of concept. Submitting the form
|
||||
will not actually transmit your data.</em
|
||||
>
|
||||
</p>
|
||||
<button type="Submit" id="submit">Submit</button>
|
||||
</form>
|
||||
</main>
|
||||
</body>
|
||||
<footer>
|
||||
<a href="../">Return to Project List</a> |
|
||||
<a href="https://www.nhcarrigan.com">Return to HomePage</a>
|
||||
</footer>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
main {
|
||||
text-align: center;
|
||||
background-color: #92869c;
|
||||
background-blend-mode: lighten;
|
||||
max-width: 500px;
|
||||
margin: 20px auto;
|
||||
border-radius: 50px;
|
||||
box-shadow: 10px 10px rgba(0, 0, 0, 0.5);
|
||||
color: black;
|
||||
}
|
||||
body {
|
||||
text-align: center;
|
||||
background: #3a3240;
|
||||
color: white;
|
||||
}
|
||||
input, textarea, select, button {
|
||||
background: #3a3240;
|
||||
color: white;
|
||||
}
|
||||
a {
|
||||
color: white;
|
||||
}
|
||||
```
|
||||
@@ -1,529 +0,0 @@
|
||||
---
|
||||
id: 587d78b0367417b2b2512b05
|
||||
title: Build a Technical Documentation Page
|
||||
challengeType: 14
|
||||
forumTopicId: 301146
|
||||
dashedName: build-a-technical-documentation-page
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
**Objective:** Build an app that is functionally similar to <a href="https://technical-documentation-page.freecodecamp.rocks" target="_blank" rel="noopener noreferrer nofollow">https://technical-documentation-page.freecodecamp.rocks</a>
|
||||
|
||||
**User Stories:**
|
||||
|
||||
1. You can see a `main` element with a corresponding `id="main-doc"`, which contains the page's main content (technical documentation)
|
||||
1. Within the `#main-doc` element, you can see several `section` elements, each with a class of `main-section`. There should be a minimum of five
|
||||
1. The first element within each `.main-section` should be a `header` element, which contains text that describes the topic of that section.
|
||||
1. Each `section` element with the class of `main-section` should also have an `id` that corresponds with the text of each `header` contained within it. Any spaces should be replaced with underscores (e.g. The section that contains the header "JavaScript and Java" should have a corresponding `id="JavaScript_and_Java"`)
|
||||
1. The `.main-section` elements should contain at least ten `p` elements total (not each)
|
||||
1. The `.main-section` elements should contain at least five `code` elements total (not each)
|
||||
1. The `.main-section` elements should contain at least five `li` items total (not each)
|
||||
1. You can see a `nav` element with a corresponding `id="navbar"`
|
||||
1. The navbar element should contain one `header` element which contains text that describes the topic of the technical documentation
|
||||
1. Additionally, the navbar should contain link (`a`) elements with the class of `nav-link`. There should be one for every element with the class `main-section`
|
||||
1. The `header` element in the `#navbar` must come before any link (`a`) elements in the navbar
|
||||
1. Each element with the class of `nav-link` should contain text that corresponds to the `header` text within each `section` (e.g. if you have a "Hello world" section/header, your navbar should have an element which contains the text "Hello world")
|
||||
1. When you click on a navbar element, the page should navigate to the corresponding section of the `#main-doc` element (e.g. If you click on a `.nav-link` element that contains the text "Hello world", the page navigates to a `section` element with that id, and contains the corresponding header)
|
||||
1. On regular sized devices (laptops, desktops), the element with `id="navbar"` should be shown on the left side of the screen and should always be visible to the user
|
||||
1. Your technical documentation should use at least one media query
|
||||
|
||||
Fulfill the user stories and pass all the tests below to complete this project. Give it your own personal style. Happy Coding!
|
||||
|
||||
**Note:** Be sure to add `<link rel="stylesheet" href="styles.css">` in your HTML to link your stylesheet and apply your CSS
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a `main` element with an `id` of `main-doc`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('main-doc')
|
||||
assert(!!el)
|
||||
```
|
||||
|
||||
You should have at least five `section` elements with a class of `main-section`.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('#main-doc section')
|
||||
assert(els.length >= 5)
|
||||
```
|
||||
|
||||
All of your `.main-section` elements should be `section` elements.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('.main-section')
|
||||
els.forEach(el => {
|
||||
if (el.tagName !== 'SECTION') assert(false)
|
||||
})
|
||||
assert(els.length > 0)
|
||||
```
|
||||
|
||||
You should have at least five `.main-section` elements that are descendants of `#main-doc`.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('#main-doc .main-section')
|
||||
assert(els.length >= 5)
|
||||
```
|
||||
|
||||
The first child of each `.main-section` should be a `header` element.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('.main-section')
|
||||
els.forEach(el => {
|
||||
if(el.firstElementChild?.tagName !== 'HEADER') assert(false)
|
||||
})
|
||||
assert(els.length > 0)
|
||||
```
|
||||
|
||||
None of your `header` elements should be empty.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('header')
|
||||
els.forEach(el => {
|
||||
if (el.innerText?.length <= 0) assert(false)
|
||||
})
|
||||
assert(els.length > 0)
|
||||
```
|
||||
|
||||
All of your `.main-section` elements should have an `id`.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('.main-section')
|
||||
els.forEach(el => {
|
||||
if (!el.id || el.id === '') assert(false)
|
||||
})
|
||||
assert(els.length > 0)
|
||||
```
|
||||
|
||||
Each `.main-section` should have an `id` that matches the text of its first child, having any spaces in the child's text replaced with underscores (`_`) for the id's.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('.main-section')
|
||||
els.forEach(el => {
|
||||
const text = el.firstElementChild?.innerText?.replaceAll(' ', '_')
|
||||
if (el.id?.toUpperCase() !== text?.toUpperCase()) assert(false)
|
||||
})
|
||||
assert(els.length > 0)
|
||||
```
|
||||
|
||||
You should have at least 10 `p` elements (total) within your `.main-section` elements.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('.main-section p')
|
||||
assert(els.length >= 10)
|
||||
```
|
||||
|
||||
You should have at least five `code` elements that are descendants of `.main-section` elements.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('.main-section code')
|
||||
assert(els.length >= 5)
|
||||
```
|
||||
|
||||
You should have at least five `li` elements that are descendants of `.main-section` elements.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('.main-section li')
|
||||
assert(els.length >= 5)
|
||||
```
|
||||
|
||||
You should have a `nav` element with an `id` of `navbar`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('navbar')
|
||||
assert(!!el && el.tagName === 'NAV')
|
||||
```
|
||||
|
||||
Your `#navbar` should have exactly one `header` element within it.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('#navbar header')
|
||||
assert(els.length === 1)
|
||||
```
|
||||
|
||||
You should have at least one `a` element with a class of `nav-link`.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('a.nav-link')
|
||||
assert(els.length >= 1)
|
||||
```
|
||||
|
||||
All of your `.nav-link` elements should be anchor (`a`) elements.
|
||||
|
||||
```js
|
||||
const els = document.querySelectorAll('.nav-link')
|
||||
els.forEach(el => {
|
||||
if (el.tagName !== 'A') assert(false)
|
||||
})
|
||||
assert(els.length > 0)
|
||||
```
|
||||
|
||||
All of your `.nav-link` elements should be in the `#navbar`.
|
||||
|
||||
```js
|
||||
const els1 = document.querySelectorAll('.nav-link')
|
||||
const els2 = document.querySelectorAll('#navbar .nav-link')
|
||||
assert(els2.length > 0 && els1.length === els2.length)
|
||||
```
|
||||
|
||||
You should have the same number of `.nav-link` and `.main-section` elements.
|
||||
|
||||
```js
|
||||
const els1 = document.querySelectorAll('.main-section')
|
||||
const els2 = document.querySelectorAll('.nav-link')
|
||||
assert(els1.length > 0 && els2.length > 0 && els1.length === els2.length)
|
||||
```
|
||||
|
||||
The `header` element in the `#navbar` should come before any link (`a`) elements also in the `#navbar`.
|
||||
|
||||
```js
|
||||
const navLinks = document.querySelectorAll('#navbar a.nav-link');
|
||||
const header = document.querySelector('#navbar header');
|
||||
navLinks.forEach((navLink) => {
|
||||
if (
|
||||
(
|
||||
header.compareDocumentPosition(navLink) &
|
||||
Node.DOCUMENT_POSITION_PRECEDING
|
||||
)
|
||||
) assert(false)
|
||||
});
|
||||
assert(!!header)
|
||||
```
|
||||
|
||||
Each `.nav-link` should have text that corresponds to the `header` text of its related `section` (e.g. if you have a "Hello world" section/header, your `#navbar` should have a `.nav-link` which has the text "Hello world").
|
||||
|
||||
```js
|
||||
const headerText = Array.from(document.querySelectorAll('.main-section')).map(el =>
|
||||
el.firstElementChild?.innerText?.trim().toUpperCase()
|
||||
)
|
||||
const linkText = Array.from(document.querySelectorAll('.nav-link')).map(el =>
|
||||
el.innerText?.trim().toUpperCase()
|
||||
)
|
||||
const remainder = headerText.filter(str => linkText.indexOf(str) === -1)
|
||||
assert(headerText.length > 0 && headerText.length > 0 && remainder.length === 0)
|
||||
```
|
||||
|
||||
Each `.nav-link` should have an `href` attribute that links to its corresponding `.main-section` (e.g. If you click on a `.nav-link` element that contains the text "Hello world", the page navigates to a `section` element with that id).
|
||||
|
||||
```js
|
||||
const hrefValues = Array.from(document.querySelectorAll('.nav-link')).map(el => el.getAttribute('href'))
|
||||
const mainSectionIDs = Array.from(document.querySelectorAll('.main-section')).map(el => el.id)
|
||||
const missingHrefValues = mainSectionIDs.filter(str => hrefValues.indexOf('#' + str) === -1)
|
||||
assert(hrefValues.length > 0 && mainSectionIDs.length > 0 && missingHrefValues.length === 0)
|
||||
```
|
||||
|
||||
Your `#navbar` should always be on the left edge of the window.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('navbar')
|
||||
const left1 = el?.offsetLeft
|
||||
const left2 = el?.offsetLeft
|
||||
assert(!!el && left1 >= -15 && left1 <= 15 && left2 >= -15 && left2 <= 15)
|
||||
```
|
||||
|
||||
Your Technical Documentation project should use at least one media query.
|
||||
|
||||
```js
|
||||
const htmlSourceAttr = Array.from(document.querySelectorAll('source')).map(el => el.getAttribute('media'))
|
||||
const cssCheck = new __helpers.CSSHelp(document).getCSSRules('media')
|
||||
assert(cssCheck.length > 0 || htmlSourceAttr.length > 0);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
|
||||
```
|
||||
|
||||
```css
|
||||
|
||||
```
|
||||
|
||||
## --solutions--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
<title>Technical Documentation Page</title>
|
||||
</head>
|
||||
<body>
|
||||
<nav id="navbar">
|
||||
<header><br />Algebraic Concepts</header>
|
||||
<hr />
|
||||
<a href="#introduction" class="nav-link">Introduction</a><br />
|
||||
<hr />
|
||||
<a href="#definitions" class="nav-link">Definitions</a><br />
|
||||
<hr />
|
||||
<a href="#examples" class="nav-link">Examples</a><br />
|
||||
<hr />
|
||||
<a href="#solving_equations" class="nav-link">Solving Equations</a><br />
|
||||
<hr />
|
||||
<a href="#solving_equations_ii" class="nav-link">Solving Equations II</a
|
||||
><br />
|
||||
<hr />
|
||||
<a href="#solving_equations_iii" class="nav-link">Solving Equations III</a
|
||||
><br />
|
||||
<hr />
|
||||
<a href="#system_of_equations" class="nav-link">System of Equations</a
|
||||
><br />
|
||||
<hr />
|
||||
<a href="#try_it_yourself!" class="nav-link">Try it Yourself!</a><br />
|
||||
<hr />
|
||||
<a href="#more_information" class="nav-link">More Information</a><br />
|
||||
</nav>
|
||||
<main id="main-doc">
|
||||
<section class="main-section" id="introduction">
|
||||
<header>Introduction</header>
|
||||
<p>
|
||||
Welcome to a basic introduction of algebra. In this tutorial, we will
|
||||
review some of the more common algebraic concepts.
|
||||
</p>
|
||||
</section>
|
||||
<section class="main-section" id="definitions">
|
||||
<header>Definitions</header>
|
||||
<p>
|
||||
To start with, let's define some of the more common terms used in
|
||||
algebra:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<b>Variable:</b> A variable is an unknown value, usually represented
|
||||
by a letter.
|
||||
</li>
|
||||
<li>
|
||||
<b>Expression:</b> Essentially a mathematical object. For the
|
||||
purpose of this tutorial, an expression is one part of an equation.
|
||||
</li>
|
||||
<li>
|
||||
<b>Equation:</b> An equation is a mathematical argument in which two
|
||||
expressions result in the same value.
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="main-section" id="examples">
|
||||
<header>Examples</header>
|
||||
<p>
|
||||
Sometimes it is easier to understand the definitions when you have a
|
||||
physical example to look at. Here is an example of the above terms.<br /><br />
|
||||
<code>x + 5 = 12 </code><br /><br />
|
||||
In this above example, we have:
|
||||
</p>
|
||||
<ul>
|
||||
<li><b>Variable:</b> The variable in the example is "x".</li>
|
||||
<li>
|
||||
<b>Expression:</b> There are two expressions in this example. They
|
||||
are "x+5" and "12".
|
||||
</li>
|
||||
<li>
|
||||
<b>Equation:</b> The entire example, "x+5=12", is an equation.
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="main-section" id="solving_equations">
|
||||
<header>Solving Equations</header>
|
||||
<p>
|
||||
The primary use for algebra is to determine an unknown value, the
|
||||
"variable", with the information provided. Continuing to use our
|
||||
example from above, we can find the value of the variable "x".<br /><br />
|
||||
<code>x + 5 = 12 </code><br /><br />
|
||||
In an equation, both sides result in the same value. So you can
|
||||
manipulate the two expressions however you need, as long as you
|
||||
perform the same operation (or change) to each side. You do this
|
||||
because the goal when solving an equation is to
|
||||
<b
|
||||
>get the variable into its own expression, or by itself on one side
|
||||
of the = sign.</b
|
||||
><br />For this example, we want to remove the "+5" so the "x" is
|
||||
alone. To do this, we can <em>subtract 5</em>, because subtraction is
|
||||
the opposite operation to addition. But remember, we have to perform
|
||||
the same operation to both sides of the equation. Now our equation
|
||||
looks like this.<br /><br />
|
||||
<code>x + 5 - 5 = 12 - 5</code><br /><br />
|
||||
The equation looks like a mess right now, because we haven't completed
|
||||
the operations. We can <b>simplify</b> this equation to make it easier
|
||||
to read by performing the operations "5-5" and "12-5". The result
|
||||
is:<br /><br />
|
||||
<code>x = 7</code><br /><br />
|
||||
We now have our solution to this equation!
|
||||
</p>
|
||||
</section>
|
||||
<section class="main-section" id="solving_equations_ii">
|
||||
<header>Solving Equations II</header>
|
||||
<p>
|
||||
Let us look at a slightly more challenging equation.<br /><br />
|
||||
<code>3x + 4 = 13</code><br /><br />
|
||||
Again we can start with subtraction. In this case, we want to subtract
|
||||
4 from each side of the equation. We will also go ahead and simplify
|
||||
with each step. So now we have:<br /><br />
|
||||
<code>3x = 9</code><br /><br />
|
||||
"3x" translates to "3*x", where the "*" symbol indicates
|
||||
multiplication. We use the "*" to avoid confusion, as the "x" is now a
|
||||
variable instead of a multiplication symbol. The opposite operation
|
||||
for multiplication is division, so we need to
|
||||
<b>divide each expression by 3</b>.<br /><br />
|
||||
<code>x = 3</code><br /><br />
|
||||
And now we have our solution!
|
||||
</p>
|
||||
</section>
|
||||
<section class="main-section" id="solving_equations_iii">
|
||||
<header>Solving Equations III</header>
|
||||
<p>
|
||||
Now we are getting in to more complex operations. Here is another
|
||||
equation for us to look at:<br /><br />
|
||||
<code>x^2 - 8 = 8</code><br /><br />
|
||||
Our very first step will be to <b>add</b> 8 to each side. This is
|
||||
different from our previous examples, where we had to subtract. But
|
||||
remember, our goal is to get the variable alone by performing opposite
|
||||
operations.<br /><br />
|
||||
<code>x^2 = 16</code><br /><br />
|
||||
But what does the "^2" mean? The "^" symbol is used to denote
|
||||
exponents in situations where superscript is not available. When
|
||||
superscript <b>is</b> available, you would see it as x<sup>2</sup>.
|
||||
For the sake of this project, however, we will use the "^" symbol.<br />
|
||||
An exponent tells you how many times the base (in our case, "x") is
|
||||
multiplied by itself. So, "x^2" would be the same as "x*x". Now the
|
||||
opposite function of multiplication is division, but we would have to
|
||||
<b>divide both sides by "x"</b>. We do not want to do this, as that
|
||||
would put an "x" on the other side of the equation. So instead, we
|
||||
need to use the root operation! For an exponent of "2", we call this
|
||||
the "square root" and denote it with "√". Our equation is now:
|
||||
<br /><br />
|
||||
<code>x = √9</code><br /><br />
|
||||
Performing a root operation by hand can be a tedious process, so we
|
||||
recommend using a calculator when necessary. However, we are lucky in
|
||||
that "9" is a
|
||||
<a href="https://en.wikipedia.org/wiki/Square_number"
|
||||
>perfect square</a
|
||||
>, so we do not need to calculate anything. Instead, we find our
|
||||
answer to be:<br /><br />
|
||||
<code>x = 3</code>
|
||||
</p>
|
||||
</section>
|
||||
<section class="main-section" id="system_of_equations">
|
||||
<header>System of Equations</header>
|
||||
<p>
|
||||
As you explore your algebra studies further, you may start to run
|
||||
across equations with more than one variable. The first such equations
|
||||
will likely look like:<br /><br />
|
||||
<code>y = 3x</code><br /><br />
|
||||
An equation like this does <b>not have one single solution</b>.
|
||||
Rather, there are a series of values for which the equation is true.
|
||||
For example, if "x=3" and "y=9", the equation is true. These equations
|
||||
are usually used to plot a graph. <br />
|
||||
Getting more complicated, though, you may be given a <b>pair</b> of
|
||||
equations. This is called a "system of equations", and CAN be solved.
|
||||
Let's look at how we do this! Consider the following system of
|
||||
equations:<br /><br />
|
||||
<code>y = 3x | y - 6 = x</code>
|
||||
A system of equations IS solvable, but it is a multi-step process. To
|
||||
get started, we need to chose a variable we are solving for. Let's
|
||||
solve for "x" first. From the second equation, we know that "x" equals
|
||||
"y - 6", but we cannot simplify that further because we do not have a
|
||||
value for "y". Except, thanks to the system of equations, we DO have a
|
||||
value for "y". We know that "y" equals "3x". So, looking at our second
|
||||
equation, we can replace "y" with "3x" because they have the same
|
||||
value. We then get:<br /><br />
|
||||
<code>3x - 6 = x</code><br /><br />
|
||||
Now we can solve for "x"! We start by adding 6 to each side.<br /><br />
|
||||
<code>3x = x + 6</code><br /><br />
|
||||
We still need to get "x" by itself, so we subtract "x" from both sides
|
||||
and get:<br /><br />
|
||||
<code>2x = 6</code><br /><br />
|
||||
If this confuses you, remember that "3x" is the same as "x+x+x".
|
||||
Subtract an "x" from that and you get "x+x", or "2x". Now we divide
|
||||
both sides by 2 and have our value for x!<br /><br />
|
||||
<code>x = 3</code><br /><br />
|
||||
However, our work is not done yet. We still need to find the value for
|
||||
"y". Let's go back to our first equation:<br /><br />
|
||||
<code>y = 3x</code><br /><br />
|
||||
We have a value for "x" now, so let's see what happens if we put that
|
||||
value in.<br /><br />
|
||||
<code>y = 3*3</code><br /><br />
|
||||
We perform the multiplication and discover that "y=9"! Our solution to
|
||||
this system of equations then is:<br /><br />
|
||||
<code>x = 3 and y = 9</code><br /><br />
|
||||
</p>
|
||||
</section>
|
||||
<section class="main-section" id="try_it_yourself!">
|
||||
<header>Try it Yourself!</header>
|
||||
<p>Coming Soon!</p>
|
||||
<p>Keep an eye out for new additions!</p>
|
||||
</section>
|
||||
<section class="main-section" id="more_information">
|
||||
<header>More Information</header>
|
||||
<p>Check out the following links for more information!</p>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://www.wolframalpha.com/examples/mathematics/algebra/"
|
||||
>Wolfram Alpha</a
|
||||
>
|
||||
is a great source for multiple mathematic fields.
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://en.wikipedia.org/wiki/Algebra"
|
||||
>Wikipedia's Algebra page</a
|
||||
>
|
||||
for more general information.
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
<footer>
|
||||
<a href="../">Return to Project List</a> |
|
||||
<a href="https://www.nhcarrigan.com">Return to HomePage</a>
|
||||
</footer>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
* {
|
||||
background-color: #3a3240;
|
||||
}
|
||||
a {
|
||||
color: #92869c;
|
||||
}
|
||||
a:hover {
|
||||
background-color: #92869c;
|
||||
color: #3a3240;
|
||||
}
|
||||
#navbar {
|
||||
border-style: solid;
|
||||
border-width: 5px;
|
||||
border-color: #92869c;
|
||||
height: 100%;
|
||||
top: -5px;
|
||||
left: -5px;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
color: #92869c
|
||||
}
|
||||
@media (min-width: 480px) {
|
||||
#navbar {
|
||||
position: fixed;
|
||||
}
|
||||
}
|
||||
main {
|
||||
margin-left: 220px;
|
||||
color: #92869c
|
||||
}
|
||||
header {
|
||||
font-size: 20pt;
|
||||
}
|
||||
code {
|
||||
background-color: #92869c;
|
||||
border-style: dashed;
|
||||
border-width: 2px;
|
||||
border-color: #92869c;
|
||||
padding: 5px;
|
||||
color: black;
|
||||
}
|
||||
footer {
|
||||
text-align: center;
|
||||
}
|
||||
```
|
||||
@@ -1,325 +0,0 @@
|
||||
---
|
||||
id: bd7158d8c442eddfaeb5bd18
|
||||
title: Build a Tribute Page
|
||||
challengeType: 14
|
||||
forumTopicId: 301147
|
||||
dashedName: build-a-tribute-page
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
**Objective:** Build an app that is functionally similar to <a href="https://tribute-page.freecodecamp.rocks" target="_blank" rel="noopener noreferrer nofollow">https://tribute-page.freecodecamp.rocks</a>
|
||||
|
||||
**User Stories:**
|
||||
|
||||
1. Your tribute page should have a `main` element with a corresponding `id` of `main`, which contains all other elements
|
||||
1. You should see an element with an `id` of `title`, which contains a string (i.e. text), that describes the subject of the tribute page (e.g. "Dr. Norman Borlaug")
|
||||
1. You should see either a `figure` or a `div` element with an `id` of `img-div`
|
||||
1. Within the `#img-div` element, you should see an `img` element with a corresponding `id="image"`
|
||||
1. Within the `#img-div` element, you should see an element with a corresponding `id="img-caption"` that contains textual content describing the image shown in `#img-div`
|
||||
1. You should see an element with a corresponding `id="tribute-info"`, which contains textual content describing the subject of the tribute page
|
||||
1. You should see an `a` element with a corresponding `id="tribute-link"`, which links to an outside site, that contains additional information about the subject of the tribute page. HINT: You must give your element an attribute of `target` and set it to `_blank` in order for your link to open in a new tab
|
||||
1. Your `#image` should use `max-width` and `height` properties to resize responsively, relative to the width of its parent element, without exceeding its original size
|
||||
1. Your `img` element should be centered within its parent element
|
||||
|
||||
Fulfill the user stories and pass all the tests below to complete this project. Give it your own personal style. Happy Coding!
|
||||
|
||||
**Note:** Be sure to add `<link rel="stylesheet" href="styles.css">` in your HTML to link your stylesheet and apply your CSS
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a `main` element with an `id` of `main`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('main')
|
||||
assert(!!el && el.tagName === 'MAIN')
|
||||
```
|
||||
|
||||
Your `#img-div`, `#image`, `#img-caption`, `#tribute-info`, and `#tribute-link` should all be descendants of `#main`.
|
||||
|
||||
```js
|
||||
const el1 = document.querySelector('#main #img-div')
|
||||
const el2 = document.querySelector('#main #image')
|
||||
const el3 = document.querySelector('#main #img-caption')
|
||||
const el4 = document.querySelector('#main #tribute-info')
|
||||
const el5 = document.querySelector('#main #tribute-link')
|
||||
assert(!!el1 & !!el2 && !!el3 && !!el4 && !!el5)
|
||||
```
|
||||
|
||||
You should have an element with an `id` of `title`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('title')
|
||||
assert(!!el)
|
||||
```
|
||||
|
||||
Your `#title` should not be empty.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('title')
|
||||
assert(!!el && el.innerText.length > 0)
|
||||
|
||||
```
|
||||
|
||||
You should have a `figure` or `div` element with an `id` of `img-div`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('img-div')
|
||||
assert(!!el && (el.tagName === 'DIV' || el.tagName === 'FIGURE'))
|
||||
```
|
||||
|
||||
You should have an `img` element with an `id` of `image`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('image')
|
||||
assert(!!el && el.tagName === 'IMG')
|
||||
```
|
||||
|
||||
Your `#image` should be a descendant of `#img-div`.
|
||||
|
||||
```js
|
||||
const el = document.querySelector('#img-div #image')
|
||||
assert(!!el)
|
||||
```
|
||||
|
||||
You should have a `figcaption` or `div` element with an `id` of `img-caption`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('img-caption')
|
||||
assert(!!el && (el.tagName === 'DIV' || el.tagName === 'FIGCAPTION'))
|
||||
```
|
||||
|
||||
Your `#img-caption` should be a descendant of `#img-div`.
|
||||
|
||||
```js
|
||||
const el = document.querySelector('#img-div #img-caption')
|
||||
assert(!!el)
|
||||
```
|
||||
|
||||
Your `#img-caption` should not be empty.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('img-caption')
|
||||
assert(!!el && el.innerText.length > 0)
|
||||
```
|
||||
|
||||
You should have an element with an `id` of `tribute-info`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('tribute-info')
|
||||
assert(!!el)
|
||||
```
|
||||
|
||||
Your `#tribute-info` should not be empty.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('tribute-info')
|
||||
assert(!!el && el.innerText.length > 0)
|
||||
```
|
||||
|
||||
You should have an `a` element with an `id` of `tribute-link`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('tribute-link')
|
||||
assert(!!el && el.tagName === 'A')
|
||||
```
|
||||
|
||||
Your `#tribute-link` should have an `href` attribute and value.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('tribute-link')
|
||||
assert(!!el && !!el.href && el.href.length > 0)
|
||||
```
|
||||
|
||||
Your `#tribute-link` should have a `target` attribute set to `_blank`.
|
||||
|
||||
```js
|
||||
const el = document.getElementById('tribute-link')
|
||||
assert(!!el && el.target === '_blank')
|
||||
```
|
||||
|
||||
Your `img` element should have a `display` of `block`.
|
||||
|
||||
```js
|
||||
const img = document.getElementById('image');
|
||||
const imgStyle = window.getComputedStyle(img);
|
||||
const style = imgStyle?.getPropertyValue('display')
|
||||
assert(style === 'block')
|
||||
```
|
||||
|
||||
Your `#image` should have a `max-width` of `100%`.
|
||||
|
||||
```js
|
||||
const img = document.getElementById('image');
|
||||
const imgStyle = window.getComputedStyle(img);
|
||||
const style = imgStyle?.getPropertyValue('max-width')
|
||||
assert(style === '100%')
|
||||
```
|
||||
|
||||
Your `#image` should have a `height` of `auto`.
|
||||
|
||||
```js
|
||||
// taken from the testable-projects repo
|
||||
const img = document.getElementById('image');
|
||||
const imgStyle = window.getComputedStyle(img);
|
||||
const oldDisplayValue = imgStyle.getPropertyValue('display');
|
||||
const oldDisplayPriority = imgStyle.getPropertyPriority('display');
|
||||
img?.style.setProperty('display', 'none', 'important');
|
||||
const heightValue = imgStyle?.getPropertyValue('height')
|
||||
img?.style.setProperty('display', oldDisplayValue, oldDisplayPriority);
|
||||
assert(heightValue === 'auto')
|
||||
```
|
||||
|
||||
Your `#image` should be centered within its parent.
|
||||
|
||||
```js
|
||||
// taken from the testable-projects repo
|
||||
const img = document.getElementById('image'),
|
||||
imgParent = img?.parentElement,
|
||||
imgLeft = img?.getBoundingClientRect().left,
|
||||
imgRight = img?.getBoundingClientRect().right,
|
||||
parentLeft = imgParent?.getBoundingClientRect().left,
|
||||
parentRight = imgParent?.getBoundingClientRect().right,
|
||||
leftMargin = imgLeft - parentLeft,
|
||||
rightMargin = parentRight - imgRight;
|
||||
assert(leftMargin - rightMargin < 6 && rightMargin - leftMargin < 6)
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
|
||||
```
|
||||
|
||||
```css
|
||||
|
||||
```
|
||||
|
||||
## --solutions--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Pacifico"
|
||||
rel="stylesheet"
|
||||
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Lobster"
|
||||
rel="stylesheet"
|
||||
|
||||
/>
|
||||
<link href="styles.css" rel="stylesheet" />
|
||||
<title>Tribute Page</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Tribute Page</h1>
|
||||
<p>The below card was designed as a tribute page for freeCodeCamp.</p>
|
||||
<main id="main">
|
||||
<div id="img-div">
|
||||
<img
|
||||
id="image"
|
||||
class="border"
|
||||
src="https://upload.wikimedia.org/wikipedia/en/5/53/Pok%C3%A9mon_Togepi_art.png"
|
||||
alt="An image of Togepi"
|
||||
/>
|
||||
<figcaption id="img-caption">Togepi, happy as always.</figcaption>
|
||||
</div>
|
||||
<h2 id="title">Togepi</h2>
|
||||
<hr />
|
||||
<div id="tribute-info">
|
||||
<p>
|
||||
Togepi was first discovered in the Johto region, when Ash Ketchum
|
||||
discovered a mysterious egg. However, when the egg hatched, Togepi saw
|
||||
Ash's friend Misty first and imprinted on her. Like many other
|
||||
creatures, this imprinting process created a bond and Togepi views
|
||||
Misty as his mother.
|
||||
</p>
|
||||
<p>
|
||||
Togepi is a very childlike Pokemon, and is very emotionally
|
||||
expressive. He demonstrates extreme levels of joy and sadness.
|
||||
</p>
|
||||
<hr />
|
||||
<p><u>Battle Information</u></p>
|
||||
<ul style="list-style-type: none">
|
||||
<li>Type: Fairy</li>
|
||||
<li>Evolutions: Togepi -> Togetic -> Togekiss</li>
|
||||
<li>Moves: Growl, Pound, Sweet Kiss, Charm</li>
|
||||
<li>Weaknesses: Poison, Steel</li>
|
||||
<li>Resistances: Dragon</li>
|
||||
</ul>
|
||||
<p>
|
||||
Check out this
|
||||
<a
|
||||
id="tribute-link"
|
||||
href="https://bulbapedia.bulbagarden.net/wiki/Togepi_(Pok%C3%A9mon)"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>Bulbapedia article on Togepi</a
|
||||
>
|
||||
for more information on this great Pokemon.
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
<footer>
|
||||
<a href="../">Return to Project List</a> |
|
||||
<a href="https://www.nhcarrigan.com">Return to HomePage</a>
|
||||
</footer>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
body {
|
||||
background-color: #3a3240;
|
||||
color: white;
|
||||
}
|
||||
main {
|
||||
background-color: #92869c;
|
||||
font-family: Lobster;
|
||||
max-width: 500px;
|
||||
margin: 20px auto;
|
||||
color: black;
|
||||
border-radius: 50px;
|
||||
box-shadow: 10px 10px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
h2 {
|
||||
text-align: center;
|
||||
font-size: 20pt;
|
||||
font-family: Pacifico;
|
||||
}
|
||||
body {
|
||||
text-align: center;
|
||||
font-size: 12pt;
|
||||
}
|
||||
footer {
|
||||
text-align: center;
|
||||
font-size: 10pt;
|
||||
}
|
||||
.border {
|
||||
border-color: black;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
}
|
||||
#image {
|
||||
height: auto;
|
||||
display: block;
|
||||
margin: auto;
|
||||
max-width: 100%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
#img-caption {
|
||||
font-size: 10pt;
|
||||
}
|
||||
a:not(#tribute-link) {
|
||||
color: white;
|
||||
}
|
||||
hr {
|
||||
border-color: black;
|
||||
}
|
||||
```
|
||||
@@ -17,7 +17,7 @@ describe('multifileCertProjects', function () {
|
||||
beforeEach(() => {
|
||||
cy.preserveSession();
|
||||
cy.visit(
|
||||
'learn/responsive-web-design/responsive-web-design-projects/build-a-tribute-page'
|
||||
'learn/2022/responsive-web-design/build-a-tribute-page-project/build-a-tribute-page'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -48,9 +48,7 @@ describe('multifileCertProjects', function () {
|
||||
cy.contains('Your code was saved to the database.');
|
||||
cy.get(editorElements.closeFlash).click();
|
||||
// load saved code when navigating site (no hard refresh)'
|
||||
cy.contains('Responsive Web Design Projects').click();
|
||||
cy.contains('In this Responsive Web Design Certification');
|
||||
cy.contains('Build a Tribute Page').click();
|
||||
cy.contains('Tribute Page').click();
|
||||
cy.get(editorElements.container)
|
||||
.find(editorElements.editor)
|
||||
.contains(save2text);
|
||||
|
||||
@@ -21,7 +21,7 @@ const superBlockNames = [
|
||||
'College Algebra with Python Certification',
|
||||
'Coding Interview Prep',
|
||||
'Project Euler',
|
||||
'Legacy Responsive Web Design Certification'
|
||||
'Legacy Responsive Web Design Challenges'
|
||||
];
|
||||
|
||||
describe('Learn Landing page (not logged in)', () => {
|
||||
|
||||
@@ -17,7 +17,7 @@ describe('challenges/superblock redirect', function () {
|
||||
|
||||
cy.title().should(
|
||||
'eq',
|
||||
'Legacy Responsive Web Design Certification | freeCodeCamp.org'
|
||||
'Legacy Responsive Web Design Challenges | freeCodeCamp.org'
|
||||
);
|
||||
cy.location().should(loc => {
|
||||
expect(loc.pathname).to.eq(testLocations.learnSuper);
|
||||
|
||||
Reference in New Issue
Block a user