Implement Webmaker App installation landing page

This commit is contained in:
Christopher De Cairos 2015-02-19 16:28:57 -05:00
Родитель 3d048d34bb
Коммит 2b2e58b831
19 изменённых файлов: 590 добавлений и 1 удалений

3
app.js
Просмотреть файл

@ -454,6 +454,9 @@ app.get("/terms", routes.angular);
app.get("/privacy", routes.angular);
app.get("/languages", routes.page("languages"));
app.get("/app", routes.app);
app.post("/app/send-download-link", routes.api.sendSMS);
// goggles onboard, with special image routing for lowest-threshold onboarding
app.get("/goggles", routes.angular);
app.get("/goggles/install", routes.angular);

Просмотреть файл

@ -9,6 +9,7 @@
"angular-sanitize": "1.2.14",
"cookie-js": "0.0.1",
"font-awesome": "3.2.1",
"intl-tel-input": "^5.1.7",
"jquery": "2.0.3",
"jquery-ui": "1.10.3",
"makeapi-client": "0.5.28",

193
less/app-install.less Normal file
Просмотреть файл

@ -0,0 +1,193 @@
@app-install-header-size-mobile: 24px;
@app-install-header-size-desktop: 52px;
@app-install-text-size-mobile: 16px;
@app-install-text-size-desktop: 20px;
@app-install-spacing-mobile: 32px;
@app-install-spacing-desktop: 46px;
@btn-height: 49px;
.install-webmaker-app {
.navbar-header,
.row {
margin-right: 0;
margin-left: 0;
}
.create-something,
.build-something,
.share-something,
.download-app {
@media (max-width: @screen-md-max) {
padding-top: @app-install-spacing-mobile;
padding-bottom: @app-install-spacing-mobile;
}
@media (min-width: @screen-lg-min) {
padding-top: @app-install-spacing-desktop;
padding-bottom: @app-install-spacing-desktop;
}
.section-content {
@media (min-width: @screen-lg-min) {
&.push-down {
top: 100px;
}
}
.desktop-install-app {
@media (max-width: @screen-md-max) {
display: none;
}
}
}
.section-header,
.section-text {
color: @white;
line-height: 24px;
.text-center();
@media (min-width: @screen-lg-min) {
.text-left();
}
}
.section-header {
font-size: @app-install-header-size-mobile;
margin-bottom: 12px;
@media (min-width: @screen-lg-min) {
font-size: @app-install-header-size-desktop;
margin-top: 140px;
margin-bottom: @app-install-spacing-desktop;
}
font-family: "Fira Sans";
font-weight: 500;
}
.section-text {
font-size: @app-install-text-size-mobile;
&.add-margin {
margin-bottom: @app-install-spacing-mobile;
}
@media (min-width: @screen-lg-min) {
font-size: @app-install-text-size-desktop;
}
font-family: "Fira Sans";
font-weight: normal;
}
.cellphone {
@media (max-width: @screen-md-max) {
margin-top: @app-install-spacing-mobile;
}
img {
@media (min-width: @screen-lg-min) {
height: 600px;
width: auto;
}
.center-block();
}
}
}
.app-download-button {
height: @btn-height;
>button {
height: 100%;
width: 100%;
background-color: #FACD34;
color: #4B5B62;
font-family: "Open Sans";
font-weight: bold;
font-size: 12px;
}
@media (min-width: @screen-lg-min) {
display: none;
}
}
.pull-left {
margin-left: 0;
padding-left: 0;
}
.desktop-install-app-btn-wrapper {
height: @btn-height;
.desktop-install-app-btn {
height: 100%;
width: 100%;
background-color: #FACD34;
color: #4B5B62;
font-family: "Fira Sans";
font-size: 18px;
font-weight: 500;
text-transform: uppercase;
}
&.hidden {
display: none;
}
}
.send-install-link-container {
.phone-number-label {
font-family: "Fira Sans";
font-size: 14px;
color: @white;
text-overflow: nowrap;
}
.phone-num-input {
height: 50px;
width: 100%;
font-family: "Fira Sans";
font-style: italic;
font-size: 14px;
}
.send-sms-btn {
height: 50px;
width: 100%;
background-color: #FACD34;
color: #4B5B62;
font-family: "Fira Sans";
font-size: 18px;
font-weight: 500;
text-transform: uppercase;
}
.message-sent-container,
.message-sent-error-container {
color: @white;
font-family: "Fira Sans";
font-weight: normal;
font-size: @app-install-text-size-mobile;
}
&.hidden {
display: none;
}
}
.create-something {
background-color: #64A8EE;
}
.build-something {
background-color: #EE8950;
}
.share-something {
background-color: #F0C233;
}
.download-app {
background-color: #8796ED;
@media (min-width: @screen-lg-min) {
display: none;
}
}
.install-footer {
margin-top: 0;
}
}

Просмотреть файл

@ -14,6 +14,9 @@ body {
@makerstrap-bower-path: "../bower_components";
@import "../bower_components/makerstrap/less/makerstrap";
// intl-tel-input css
@import "../bower_components/intl-tel-input/build/css/intlTelInput.css";
@import "breakpoints";
@import "mixins";
@import "webfonts";
@ -22,6 +25,7 @@ body {
@import "search";
@import "me";
@import "badges";
@import "app-install";
@import "components/chevron-list";
@import "components/powertip";

Просмотреть файл

@ -41,3 +41,29 @@
font-weight: normal;
font-style: normal;
}
// Fira Sans
@font-face {
font-family: 'Fira Sans';
src: url('@{fontpath}/FiraSans-Regular.woff') format('woff'),
url('@{fontpath}/FiraSans-Regular.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Fira Sans';
src: url('@{fontpath}/FiraSans-Medium.woff') format('woff'),
url('@{fontpath}/FiraSans-Medium.ttf') format('truetype');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'Fira Sans';
src: url('@{fontpath}/FiraSans-Italic.woff') format('woff'),
url('@{fontpath}/FiraSans-Italic.ttf') format('truetype');
font-weight: normal;
font-style: italic;
}

54
locale/en_US/app.json Normal file
Просмотреть файл

@ -0,0 +1,54 @@
{
"Become a Maker": {
"message": "Become a Maker",
"description": "Call to action to become a Maker using Webmaker's app"
},
"Strips away complexity": {
"message": "Webmaker takes the best part of the web — creating — and strips away the complexity.",
"description": "Explanation about how Webmaker makes creating on the we less complex for Makers"
},
"Build the Perfect App": {
"message": "Build the Perfect App",
"description": "Header describing what Webmaker's app can be used for - building your own apps"
},
"Exactly what you need": {
"message": "Create exactly what you need: A website for your business, a chat app for your friends, a lesson plan for your students.",
"description": "A description about what kind of apps you can make"
},
"Share It with the World": {
"message": "Share It with the World",
"description": "Header describing how apps can be shared"
},
"Meant to be seen": {
"message": "Webmaker creations are meant to be seen, heard and used. Share your project with friends and colleagues",
"description": "A description about the sharing capabilities of Webmaker"
},
"Download Webmaker": {
"message": "Download Webmaker",
"description": "Action text for Downloading the Webmaker app"
},
"Get App": {
"message": "Get App >",
"description": "Action text for triggering the SMS backed get download link tool"
},
"Enter your phone number": {
"message": "Enter your phone number:",
"description": "Label text for the phone number input"
},
"Send Text": {
"message": "Send Text >",
"description": "Label text for the phone number input"
},
"install webmaker sms text": {
"message": "Install the Mozilla Webmaker app by following this link: http://mzl.la/installwm",
"description": "Text message text used when requesting a Mozilla Webmaker app installation link"
},
"message sent" : {
"message": "Sweet! A text message has been sent to your phone.",
"description": "Success text displayed after submitting a phone number"
},
"message sent error" : {
"message": "Uh oh! We're having trouble sending you the install link, try reloading the page and submitting your number again.",
"description": "Error text displayed if submitting a phone number fails"
}
}

Просмотреть файл

@ -67,5 +67,8 @@
"grunt-jsbeautifier": "0.2.2",
"grunt-jsonlint": "^1.0.4",
"grunt-shell": "0.6.1"
},
"engines": {
"node": "0.10.x"
}
}

28
public/img/cellphone.svg Normal file
Просмотреть файл

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="211px" height="415px" viewBox="0 0 211 415" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
<title>mobile 3</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="Mobile" sketch:type="MSArtboardGroup" transform="translate(-53.000000, -1477.000000)">
<g id="mobile-3" sketch:type="MSLayerGroup" transform="translate(53.000000, 1477.000000)">
<g id="Page-1" sketch:type="MSShapeGroup">
<g id="Landing-Page-Bright-Pattern-Iteration-3">
<g id="iMac-+-Browser-3-+-Group-3-+-iPad-+-Group-2">
<g id="mobile">
<g id="google-nexus-4-2">
<g id="Page-1">
<path d="M210.526509,29.9411076 L210.52651,380.188321 C210.52651,380.188321 210.460883,399.509272 180.584974,409.798138 C164.369838,415.382417 123.82921,414.991926 105.323683,414.991926 C86.81816,414.991926 44.8377672,415.382417 28.622634,409.798138 C-1.25327108,399.509276 0.120874769,380.188321 0.120874769,380.188321 L0.120874768,29.9411076 C0.120874768,29.9411076 -1.33241113,13.8442759 28.6226346,4.99119085 C44.8003585,0.209931993 86.8775678,0.00219949748 105.3237,0.00219400397 C123.769829,0.00219400397 164.407255,0.209931958 180.584977,4.99119085 C210.536046,13.8431062 210.526511,29.9368393 210.526509,29.9411076 Z M9.34230642,48.5753602 L9.34230642,372.135846 L200.620155,372.135846 L200.620155,48.5753602 L9.34230642,48.5753602 L9.34230642,48.5753602 Z" id="Google-Nexus-4" fill="#FFFFFF"></path>
<path d="M180.429716,25.0045147 C182.972897,25.0045147 185.034553,22.9258883 185.034553,20.3617724 C185.034553,17.7976565 182.972897,15.7190301 180.429716,15.7190301 C177.886534,15.7190301 175.824878,17.7976565 175.824878,20.3617724 C175.824878,22.9258883 177.886534,25.0045147 180.429716,25.0045147 L180.429716,25.0045147 L180.429716,25.0045147 Z" id="Google-Nexus-4-path" fill="#ECF1F7"></path>
<path d="M82.7653748,11.8976196 C81.988023,11.9421728 81.7293118,12.4924823 82.1883965,13.1279734 L84.6314927,16.5098441 C85.0901884,17.1447965 86.1012627,17.6595271 86.8739981,17.6595271 L123.722515,17.6595271 C124.50232,17.6595271 125.507997,17.1352333 125.963306,16.4961348 L128.3531,13.1416827 C128.81085,12.4991588 128.543244,11.9402106 127.766425,11.8961922 C127.766425,11.8961922 117.246492,11.2311147 105.352088,11.2311147 C93.4576834,11.231115 82.7653748,11.8976196 82.7653748,11.8976196 Z" id="Google-Nexus-4-path" fill="#ECF1F7"></path>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 3.1 KiB

Просмотреть файл

@ -0,0 +1,82 @@
requirejs.config({
baseDir: "/js",
paths: {
"analytics": "/bower_components/webmaker-analytics/analytics",
"jquery": "/bower_components/jquery/jquery.min",
"intl-tel-input": "/bower_components/intl-tel-input/build/js/intlTelInput.min"
}
});
require(["jquery", "analytics", "intl-tel-input"], function ($, analytics) {
"use strict";
var downloadButtons = $(".download-app-btn"),
sendInstallAppButtonContainer = $(".desktop-install-app-btn-wrapper"),
sendInstallLinkContainer = $(".send-install-link-container"),
phoneNumberLabel = $(".phone-number-label"),
getAppBtn = $(".desktop-install-app-btn"),
phoneNumberInput = $(".phone-num-input"),
sendSmsButton = $(".send-sms-btn"),
messageSent = $(".message-sent-container"),
messageSentError = $(".message-sent-error-container"),
csrfToken = $("meta[name='csrf-token']").attr("content");
function sendSMS() {
sendSmsButton.attr("disabled", true);
analytics.event("Send SMS Link for Beta App");
var phoneNumber = phoneNumberInput.intlTelInput("getNumber", window.intlTelInputUtils.numberFormat.INTERNATIONAL);
$.ajax({
type: "POST",
url: "/app/send-download-link",
dataType: "json",
data: {
to: phoneNumber
},
headers: {
"X-CSRF-Token": csrfToken
},
error: function () {
phoneNumberLabel.addClass("hidden");
phoneNumberInput.addClass("hidden");
sendSmsButton.addClass("hidden");
$(".intl-tel-input").addClass("hidden");
messageSentError.removeClass("hidden");
},
success: function () {
phoneNumberLabel.addClass("hidden");
phoneNumberInput.addClass("hidden");
sendSmsButton.addClass("hidden");
$(".intl-tel-input").addClass("hidden");
messageSent.removeClass("hidden");
}
});
}
sendSmsButton.attr("disabled", true);
downloadButtons.click(function () {
analytics.event("Download Beta App");
window.open("http://mzl.la/installwm", "_blank");
});
getAppBtn.click(function () {
analytics.event("Click Get App Button");
sendInstallAppButtonContainer.addClass("hidden");
sendInstallLinkContainer.removeClass("hidden");
});
phoneNumberInput.intlTelInput();
phoneNumberInput.intlTelInput("loadUtils", "/bower_components/intl-tel-input/lib/libphonenumber/build/utils.js");
phoneNumberInput.keyup(function () {
sendSmsButton.attr("disabled", !phoneNumberInput.intlTelInput("isValidNumber"));
});
sendSmsButton.click(sendSMS);
sendSmsButton.keypress(function (evt) {
if (evt.keycode === 13 && phoneNumberInput.intlTelInput("isValidNumber")) {
sendSMS();
}
});
});

Двоичные данные
public/resources/fonts/FiraSans-Italic.ttf Normal file

Двоичный файл не отображается.

Двоичные данные
public/resources/fonts/FiraSans-Italic.woff Normal file

Двоичный файл не отображается.

Двоичные данные
public/resources/fonts/FiraSans-Medium.ttf Normal file

Двоичный файл не отображается.

Двоичные данные
public/resources/fonts/FiraSans-Medium.woff Normal file

Двоичный файл не отображается.

Двоичные данные
public/resources/fonts/FiraSans-Regular.ttf Normal file

Двоичный файл не отображается.

Двоичные данные
public/resources/fonts/FiraSans-Regular.woff Normal file

Двоичный файл не отображается.

17
routes/api/sendSMS.js Normal file
Просмотреть файл

@ -0,0 +1,17 @@
var hatchet = require('hatchet');
module.exports = function (req, res) {
var body = req.body;
if (!body.to) {
return res.json(400, {
error: "Missing to parameter"
});
}
hatchet.send('send_sms', {
to: body.to,
body: req.gettext("install webmaker sms text")
});
res.json(200);
};

3
routes/app.js Normal file
Просмотреть файл

@ -0,0 +1,3 @@
module.exports = function (req, res) {
res.render("app.html");
};

Просмотреть файл

@ -1,9 +1,11 @@
module.exports = {
api: {
healthcheck: require("./api/healthcheck"),
submitResource: require("./api/submitResource")
submitResource: require("./api/submitResource"),
sendSMS: require("./api/sendSMS")
},
angular: require("./angular"),
app: require("./app"),
badges: require("./badges"),
details: require("./details"),
gallery: require("./gallery"),

173
views/app.html Normal file
Просмотреть файл

@ -0,0 +1,173 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<!-- For sharing & search engines -->
<meta property="og:type" content="website" />
<meta property="og:image" content="https://webmaker.org/img/logo-og.png" />
<meta property="og:image:width" content="1400" />
<meta property="og:image:height" content="1400" />
<meta property="og:site_name" content="Webmaker" />
<meta property="og:locale" content="{{ localeInfo.lang | replace('-', '_') }}" />
{% for language in languages %}
<meta property="og:locale:alternate" content="{{ language | replace('-', '_') }}" />{% endfor %}
<meta property="og:title" content="{{ gettext("Download Webmaker") }}" />
<meta property="og:description" content="{{ gettext("Strips away complexity") }}" />
<meta property="og:url" content="https://webmaker.org/{{ localeInfo.lang }}{{ currentPath }}" />
<link rel="canonical" href="https://webmaker.org/{{ localeInfo.lang }}{{ currentPath }}" />
<meta property="description" content="{{ gettext("Strips away complexity") }}" />
<!-- /sharing -->
<link rel="stylesheet" href="/bower_components/font-awesome/css/font-awesome.css">
<link rel="stylesheet" href="/css/style.{{ localeInfo.direction }}.css">
<meta name="csrf-token" content="{{ csrf }}">
<title>{{ gettext("Download Webmaker") }}</title>
<link rel="icon" type="image/png" href="/img/favicon.ico">
</head>
<body class="install-webmaker-app">
<div id="webmaker-nav">
<nav class="navbar navbar-webmaker">
<div class="container">
<div class="navbar-header">
<a href="/{{localeInfo.lang}}" class="logo webmaker-logo">
<img src="/img/logo.png" alt="{{ gettext("Mozilla Webmaker") }}">
</a>
</div>
</div>
</div>
</div>
<div class="content create-something">
<div class="row">
<div class="col-xs-10 col-xs-offset-1 col-lg-6 col-lg-offset-0 col-lg-push-6 section-content">
<div class="col-xs-12 section-header">{{ gettext("Become a Maker") }}</div>
<div class="col-xs-12 col-lg-8 section-text add-margin">{{ gettext("Strips away complexity") }}</div>
<div class="col-lg-12 desktop-install-app">
<div class="col-lg-3 desktop-install-app-btn-wrapper pull-left">
<button class="btn btn-block desktop-install-app-btn">{{ gettext("Get App")}}</button>
</div>
<div class="col-lg-12 send-install-link-container hidden pull-left">
<div class="col-lg-12 phone-number-label pull-left">
<div class="col-lg-4 pull-left">
<i class="fa icon-mobile-phone"></i> {{ gettext("Enter your phone number")}}
</div>
</div>
<div class="col-lg-4 pull-left">
<input class="phone-num-input" type="tel" name="" value="" placeholder="+1 (555) 555-5555">
</div>
<div class="col-lg-4">
<button class="btn btn-block send-sms-btn">{{ gettext("Send Text")}}</button>
</div>
<div class="col-lg-12 message-sent-container hidden pull-left">
<span>{{ gettext("message sent") }}</span>
</div>
<div class="col-lg-12 message-sent-error-container hidden pull-left">
<span>{{ gettext("message sent error") }}</span>
</div>
</div>
</div>
</div>
<div class="col-xs-6 col-xs-offset-3 app-download-button">
<button class="btn btn-block download-app-btn">{{ gettext("Download Webmaker")}}</button>
</div>
<div class="col-xs-8 col-xs-offset-2 col-lg-4 col-lg-pull-6 col-lg-offset-1 cellphone">
<img src="/img/cellphone.svg" alt="Cellphone">
</div>
</div>
</div>
<div class="content build-something">
<div class="row">
<div class="col-xs-8 col-xs-offset-2 col-lg-5 col-lg-offset-1 section-content push-down">
<div class="col-xs-12 section-header">{{ gettext("Build the Perfect App") }}</div>
<div class="col-xs-12 col-lg-8 section-text">{{ gettext("Exactly what you need") }}</div>
</div>
<div class="col-xs-10 col-xs-offset-1 col-lg-4 col-lg-offset-0 cellphone">
<img src="/img/cellphone.svg" alt="Cellphone">
</div>
</div>
</div>
<div class="content share-something">
<div class="row">
<div class="col-xs-10 col-xs-offset-1 col-lg-6 col-lg-offset-0 col-lg-push-6 section-content push-down">
<div class="col-xs-12 section-header">{{ gettext("Share It with the World") }}</div>
<div class="col-xs-12 col-lg-8 section-text">{{ gettext("Meant to be seen") }}</div>
</div>
<div class="col-xs-8 col-xs-offset-2 col-lg-4 col-lg-pull-6 col-lg-offset-1 cellphone">
<img src="/img/cellphone.svg" alt="Cellphone">
</div>
</div>
</div>
<div class="content download-app">
<div class="row">
<div class="col-xs-8 col-xs-offset-2 app-download-button">
<button class="btn btn-block download-app-btn">{{ gettext("Download Webmaker")}}</button>
</div>
</div>
</div>
<footer class="footer install-footer">
<div class="partnerWrapper">
<nav class="navbar-footer">
<div class="container">
<ul>
<li><a href="/{{localeInfo.lang}}/about">{{ gettext("About") }}</a></li>
<li><a href="/{{localeInfo.lang}}/mentor">{{ gettext("Teach") }}</a></li>
<li>
<a href="https://sendto.mozilla.org/page/contribute/join-mozilla?source=join_link">
{{ gettext("Donate") }}
</a>
</li>
<li><a href="mailto:help@webmaker.org">{{ gettext("Contact") }}</a></li>
<li><a href="/{{localeInfo.lang}}/privacy">{{ gettext("Privacy") }}</a></li>
<li><a href="/{{localeInfo.lang}}/terms">{{ gettext("Legal") }}</a></li>
<li>
<a href="https://support.mozilla.org/products/webmaker">
{{ gettext("Help") }}
</a>
</li>
</ul>
<ul class="secondary">
<li><span class="fa icon-twitter"></span>
<a href="https://twitter.com/webmaker">
@webmaker
</a>
</li>
<li><span class="fa icon-file-text-alt"></span>
<a href="https://blog.webmaker.org">
{{ gettext("Blog") }}
</a>
</li>
</ul>
<div class="moz-logo">
<a href="https://mozilla.org/">
<img src="/img/logo-mozilla-white.png" alt="mozilla logo" height="41" width="100"/>
</a>
</div>
</div>
</nav>
</div>
</footer>
<script id="require-js" src="/bower_components/requirejs/require.js"
data-main="/js/pages/install-app.js"
async>
</script>
{% if ga_account %}
<script id="google-analytics-js" src="/js/lib/google-analytics.js"
data-ga-account="{{ ga_account }}"
data-ga-domain="{{ ga_domain }}"
async>
</script>
{% endif %}
</body>
</html>