-
Notifications
You must be signed in to change notification settings - Fork 223
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3050 from mozilla/nextjs-landing-page
Port over the existing landing page
- Loading branch information
Showing
5 changed files
with
263 additions
and
333 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
/** @type {HTMLDivElement} */ | ||
// @ts-ignore: We guard against a null value by not calling init(): | ||
const landingPartial = document.querySelector("[data-partial='landing']") | ||
|
||
if (landingPartial) { | ||
init() | ||
} | ||
|
||
async function init () { | ||
const landingForm = landingPartial.querySelector('form.exposure-scan') | ||
if (!(landingForm instanceof HTMLFormElement)) { | ||
return | ||
} | ||
landingForm.addEventListener('submit', (e) => { | ||
e.preventDefault() | ||
const emailField = landingForm.elements.namedItem('email') | ||
const newLocation = new URL(document.location) | ||
newLocation.pathname = '/scan/' | ||
newLocation.hash = `#email=${encodeURIComponent(emailField.value)}` | ||
document.location = newLocation.href | ||
}) | ||
landingForm.hidden = false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
// percentage a section that has to be in view in order to appear | ||
const sectionThreshold = 0.1 | ||
const queueIntervalDuration = 150 | ||
|
||
let observers | ||
let queueInterval | ||
// holds the sections so they can appear one after another | ||
const entryQueue = [] | ||
|
||
function handleShowSection () { | ||
if (!entryQueue.length && queueInterval) { | ||
clearInterval(queueInterval) | ||
queueInterval = null | ||
return | ||
} | ||
|
||
const nextEntry = entryQueue.shift() | ||
nextEntry.target.dataset.enterTransition = 'visible' | ||
} | ||
|
||
function setQueueInterval () { | ||
queueInterval = setInterval(handleShowSection, queueIntervalDuration) | ||
} | ||
|
||
function handleScroll (entries) { | ||
entries.forEach(entry => { | ||
const sectionElement = entry.target | ||
const hasEntered = sectionElement.getAttribute('data-enter-transition') === 'visible' | ||
|
||
if (hasEntered) { | ||
return | ||
} | ||
|
||
const isInViewport = entry.isIntersecting | ||
if (isInViewport) { | ||
entryQueue.push(entry) | ||
} | ||
|
||
if (!queueInterval) { | ||
setQueueInterval() | ||
} | ||
}) | ||
} | ||
|
||
function init (sections) { | ||
const observer = new IntersectionObserver(handleScroll, { | ||
threshold: sectionThreshold | ||
}) | ||
|
||
observers = [...sections].map(section => { | ||
section.dataset.enterTransition = 'entering' | ||
|
||
observer.observe(section) | ||
return observer | ||
}) | ||
|
||
setQueueInterval() | ||
} | ||
|
||
if (!observers) { | ||
const mediaQuery = window.matchMedia('(prefers-reduced-motion: no-preference)') | ||
const allowMotion = mediaQuery && mediaQuery.matches | ||
|
||
const sections = document.querySelectorAll('[data-enter-transition]') | ||
|
||
// Don’t hide elements that are marked for entering transitions | ||
// while users set their motion preferences. | ||
mediaQuery.addEventListener('change', () => { | ||
const documentStyle = document.documentElement.style | ||
documentStyle.setProperty('--enter-transition-opacity', '1') | ||
documentStyle.setProperty('--enter-transition-y', '0') | ||
}) | ||
|
||
if (allowMotion) { | ||
init(sections) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
import Image from "next/image"; | ||
import Script from "next/script"; | ||
import "../../../client/css/partials/landing.css"; | ||
|
||
import { getL10n } from "../../functions/server/l10n"; | ||
|
||
import HeroImage from "../../../client/images/landing-hero@2x.webp"; | ||
import LaptopImage from "../../../client/images/landing-laptop@2x.webp"; | ||
import LockImage from "../../../client/images/landing-lock@2x.webp"; | ||
import MailImage from "../../../client/images/landing-mail@2x.webp"; | ||
import NaturePhoneImage from "../../../client/images/landing-nature-phone@2x.webp"; | ||
|
||
export default function Home() { | ||
const l10n = getL10n(); | ||
|
||
return ( | ||
<div data-partial="landing"> | ||
<Script src="/nextjs_migration/client/js/transitionObserver.js" /> | ||
<Script src="/nextjs_migration/client/js/landing.js" /> | ||
<section className="hero"> | ||
<div> | ||
<h1>{l10n.getString("exposure-landing-hero-heading")}</h1> | ||
<p>{l10n.getString("exposure-landing-hero-lead")}</p> | ||
<form hidden className="exposure-scan"> | ||
<label htmlFor="scan-email-adddress" className="visually-hidden"> | ||
{l10n.getString("exposure-landing-hero-email-label")} | ||
</label> | ||
<input | ||
id="scan-email-address" | ||
name="email" | ||
type="email" | ||
placeholder={l10n.getString( | ||
"exposure-landing-hero-email-placeholder" | ||
)} | ||
required | ||
/> | ||
<button | ||
type="submit" | ||
className="button primary" | ||
data-cta-id="exposure-landing-1" | ||
> | ||
{l10n.getString("exposure-landing-hero-cta-label")} | ||
</button> | ||
</form> | ||
</div> | ||
<figure> | ||
<Image alt="" src={HeroImage} /> | ||
</figure> | ||
</section> | ||
|
||
<section className="why-use-monitor" data-enter-transition> | ||
<h2>{l10n.getString("why-use-monitor")}</h2> | ||
<p>{l10n.getString("identifying-breaches")}</p> | ||
<ul> | ||
<li> | ||
<h3>{l10n.getString("protect-account")}</h3> | ||
<p>{l10n.getString("protect-account-prevent-hackers")}</p> | ||
</li> | ||
<li> | ||
<h3>{l10n.getString("prevent-fraud")}</h3> | ||
<p>{l10n.getString("prevent-fraud-keep-info")}</p> | ||
</li> | ||
<li> | ||
<h3>{l10n.getString("get-alerts")}</h3> | ||
<p>{l10n.getString("get-alerts-find-out")}</p> | ||
</li> | ||
</ul> | ||
</section> | ||
|
||
<section className="how-it-works" data-enter-transition> | ||
<h2>{l10n.getString("how-it-works")}</h2> | ||
<ol> | ||
<li> | ||
<Image alt="" src={LaptopImage} /> | ||
<h3>{l10n.getString("check-for-breaches")}</h3> | ||
<p>{l10n.getString("check-for-breaches-we-search")}</p> | ||
</li> | ||
<li> | ||
<Image alt="" src={LockImage} /> | ||
<h3>{l10n.getString("protect-accounts")}</h3> | ||
<p>{l10n.getString("protect-accounts-clear-steps")}</p> | ||
</li> | ||
<li> | ||
<Image alt="" src={MailImage} /> | ||
<h3>{l10n.getString("alerts-for-breaches")}</h3> | ||
<p>{l10n.getString("alerts-for-breaches-monitor-new")}</p> | ||
</li> | ||
</ol> | ||
</section> | ||
|
||
<section className="safe-with-us" data-enter-transition> | ||
<div> | ||
<h2>{l10n.getString("safe-with-us")}</h2> | ||
<p>{l10n.getString("parent-company")}</p> | ||
<p>{l10n.getString("our-mission")}</p> | ||
<p> | ||
<a href="https://www.mozilla.org/mission/" target="_blank"> | ||
{l10n.getString("learn-more-mission")} | ||
</a> | ||
</p> | ||
</div> | ||
<figure> | ||
<Image alt="" src={NaturePhoneImage} /> | ||
</figure> | ||
</section> | ||
|
||
<section className="top-questions-about-monitor" data-enter-transition> | ||
<div> | ||
<h2>{l10n.getString("top-questions-about-monitor")}</h2> | ||
<a | ||
href="https://support.mozilla.org/kb/firefox-monitor-faq" | ||
target="_blank" | ||
> | ||
{l10n.getString("see-all-faq")} | ||
</a> | ||
</div> | ||
<div> | ||
<details> | ||
<summary>{l10n.getString("what-is-breach")}</summary> | ||
<p>{l10n.getString("when-info-exposed")}</p> | ||
</details> | ||
<details> | ||
<summary>{l10n.getString("what-do-i-do")}</summary> | ||
<p>{l10n.getString("visit-monitor-to-learn")}</p> | ||
</details> | ||
<details> | ||
<summary>{l10n.getString("what-gets-exposed")}</summary> | ||
<p>{l10n.getString("depends-on-hackers")}</p> | ||
</details> | ||
</div> | ||
</section> | ||
|
||
<section className="see-if-data-breach" data-enter-transition> | ||
<h2>{l10n.getString("see-if-data-breach")}</h2> | ||
<a | ||
className="button primary" | ||
data-cta-id="landing-2" | ||
href="/user/breaches" | ||
> | ||
{l10n.getString("get-started")} | ||
</a> | ||
<p | ||
className="hibp-attribution" | ||
dangerouslySetInnerHTML={{ | ||
__html: l10n.getString("hibp-footer-attribution"), | ||
}} | ||
/> | ||
</section> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.