13 KiB
id | title | challengeType | forumTopicId | dashedName |
---|---|---|---|---|
587d78af367417b2b2512b04 | Costruire la Landing Page per un prodotto | 14 | 301144 | build-a-product-landing-page |
--description--
Obiettivo: Crea un'app funzionalmente simile a https://product-landing-page.freecodecamp.rocks
User story:
- La landing page del prodotto dovrebbe avere un elemento
header
con un corrispondenteid="header"
- Dovresti avere un'immagine dentro l'elemento
header
con un attributo corrispondenteid="header-img"
(un logo sarebbe una buona scelta) - Dentro l'elemento
#header
, dovresti avere un elementonav
con un corrispondente attributoid="nav-bar"
- Dovresti avere almeno tre elementi cliccabili dentro l'elemento
nav
, ognuno con la classenav-link
- Cliccando su un pulsante
.nav-link
dentro l'elementonav
, dovresti essere portato alla sezione corrispondente nella pagina - Dovresti avere un video sul prodotto incorporato nella pagina con un
id="video"
- La landing page dovrebbe avere un elemento
form
con un corrispondente attributoid="form"
- Dentro il modulo, dovrebbe esserci un campo
input
con unid="email"
in cui inserire un indirizzo email - Il campo input
#email
dovrebbe avere del testo segnaposto per far sapere agli utenti a cosa è destinato il campo - Il campo input
#email
dovrebbe utilizzare la validazione HTML5 per confermare che il testo inserito è un indirizzo email - Dentro il modulo, dovrebbe esserci un
input
per inviare il modulo con un corrispondenteid="submit"
- Cliccando l'elemento
#submit
, l'email dovrebbe essere inviata a una pagina statica (usa l'URL non funzionante:https://www.freecodecamp.com/email-submit
) - La barra di navigazione dovrebbe essere sempre in cima al viewport
- La landing page dovrebbe avere almeno un media query
- La landing page dovrebbe utilizzare CSS flexbox almeno una volta
Soddisfa le user story e supera tutti i test qui sotto per completare questo progetto. Usa il tuo stile personale. Buon divertimento!
Nota: Assicurati di aggiungere <link rel="stylesheet" href="styles.css">
nel tuo HTML per linkare il foglio di stile e applicare il CSS
--hints--
Dovresti avere un elemento header
con un id
del valore header
.
const el = document.getElementById('header')
assert(!!el && el.tagName === 'HEADER')
Dovresti avere un elemento img
con un attributo id
del valore header-img
.
const el = document.getElementById('header-img')
assert(!!el && el.tagName === 'IMG')
L'elemento #header-img
dovrebbe essere un discendente di #header
.
const els = document.querySelectorAll('#header #header-img')
assert(els.length > 0)
L'elemento #header-img
dovrebbe avere un attributo src
.
const el = document.getElementById('header-img')
assert(!!el && !!el.src)
L'attributo src
dell'elemento #header-img
dovrebbe essere un URL valido (inizia con http
).
const el = document.getElementById('header-img')
assert(!!el && /^http/.test(el.src))
Dovresti avere un elemento nav
con un id
del valore nav-bar
.
const el = document.getElementById('nav-bar')
assert(!!el && el.tagName === 'NAV')
L'elemento #nav-bar
dovrebbe essere un discendente dell'elemento #header
.
const els = document.querySelectorAll('#header #nav-bar')
assert(els.length > 0)
Dovresti avere almeno 3 elementi .nav-link
dentro #nav-bar
.
const els = document.querySelectorAll('#nav-bar .nav-link')
assert(els.length >= 3)
Ogni elemento .nav-link
dovrebbe avere un attributo href
.
const els = document.querySelectorAll('.nav-link')
els.forEach(el => {
if (!el.href) assert(false)
})
assert(els.length > 0)
Ogni elemento .nav-link
dovrebbe linkare a un elemento corrispondente nella pagina (quindi ha un attributo href
con il valore dell'id di un altro elemento, ad esempio #footer
).
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)
Dovresti avere un elemento video
o iframe
con un id
del valore video
.
const el = document.getElementById('video')
assert(!!el && (el.tagName === 'VIDEO' || el.tagName === 'IFRAME'))
L'elemento #video
dovrebbe avere un attributo src
.
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'));
Dovresti avere un elemento form
con un attributo id
del valore form
.
const el = document.getElementById('form')
assert(!!el && el.tagName === 'FORM')
Dovresti avere un elemento input
con un id
del valore email
.
const el = document.getElementById('email')
assert(!!el && el.tagName === 'INPUT')
L'elemento #email
dovrebbe essere un discendente di #form
.
const els = document.querySelectorAll('#form #email')
assert(els.length > 0)
L'elemento #email
dovrebbe avere un attributo placeholder
con del testo segnaposto.
const el = document.getElementById('email')
assert(!!el && !!el.placeholder && el.placeholder.length > 0)
L'elemento #email
dovrebbe usare la validazione HTML5 impostando l'attributo type
su email
.
const el = document.getElementById('email')
assert(!!el && el.type === 'email')
Dovresti avere un elemento input
con un id
del valore submit
.
const el = document.getElementById('submit')
assert(!!el && el.tagName === 'INPUT')
L'elemento #submit
dovrebbe essere un discendente di #form
.
const els = document.querySelectorAll('#form #submit')
assert(els.length > 0)
L'elemento #submit
dovrebbe avere un attributo type
con il valore submit
.
const el = document.getElementById('submit')
assert(!!el && el.type === 'submit')
L'elemento #form
dovrebbe avere un attributo action
con il valore https://www.freecodecamp.com/email-submit
.
const el = document.getElementById('form')
assert(!!el && el.action === 'https://www.freecodecamp.com/email-submit')
L'elemento #email
dovrebbe avere un attributo name
con il valore email
.
const el = document.getElementById('email')
assert(!!el && el.name === 'email')
L'elemento #nav-bar
dovrebbe sempre essere in cima al viewport.
(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);
})();
La pagina dovrebbe avere almeno un media query.
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);
La tua pagina dovrebbe usare CSS Flexbox almeno una volta.
const stylesheet = new __helpers.CSSHelp(document).getStyleSheet()
const cssRules = new __helpers.CSSHelp(document).styleSheetToCssRulesArray(stylesheet)
const usesFlex = cssRules.find(rule => {
return rule.style?.display === 'flex' || rule.style?.display === 'inline-flex'
})
assert(usesFlex)
--seed--
--seed-contents--
--solutions--
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="stylesheet" type="text/css" 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>
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;
}
}