converting some things to choo/component
This commit is contained in:
parent
a576d54d64
commit
037c79730d
16 changed files with 270 additions and 381 deletions
|
@ -1,5 +1,7 @@
|
|||
import 'fast-text-encoding'; // MS Edge support
|
||||
import 'fluent-intl-polyfill';
|
||||
import choo from 'choo';
|
||||
import nanotiming from 'nanotiming';
|
||||
import routes from './routes';
|
||||
import capabilities from './capabilities';
|
||||
import locale from '../common/locales';
|
||||
|
@ -14,7 +16,10 @@ import './main.css';
|
|||
import User from './user';
|
||||
|
||||
(async function start() {
|
||||
const app = routes();
|
||||
const app = routes(choo());
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
nanotiming.disabled = true;
|
||||
}
|
||||
if (navigator.doNotTrack !== '1' && window.RAVEN_CONFIG) {
|
||||
Raven.config(window.SENTRY_ID, window.RAVEN_CONFIG).install();
|
||||
}
|
||||
|
|
|
@ -1,37 +1,8 @@
|
|||
const choo = require('choo');
|
||||
const html = require('choo/html');
|
||||
const nanotiming = require('nanotiming');
|
||||
const download = require('./ui/download');
|
||||
const footer = require('./ui/footer');
|
||||
const fxPromo = require('./ui/fxPromo');
|
||||
const header = require('./ui/header');
|
||||
const body = require('./ui/body');
|
||||
|
||||
nanotiming.disabled = true;
|
||||
|
||||
function banner(state, emit) {
|
||||
if (state.promo && !state.route.startsWith('/unsupported/')) {
|
||||
return fxPromo(state, emit);
|
||||
}
|
||||
}
|
||||
|
||||
function body(main) {
|
||||
return function(state, emit) {
|
||||
const b = html`<body class="flex flex-col items-center font-sans bg-blue-lightest md:h-screen md:bg-grey-lightest">
|
||||
${banner(state, emit)}
|
||||
${header(state, emit)}
|
||||
${main(state, emit)}
|
||||
${footer(state)}
|
||||
</body>`;
|
||||
if (state.layout) {
|
||||
// server side only
|
||||
return state.layout(state, b);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = function() {
|
||||
const app = choo();
|
||||
module.exports = function(app = choo()) {
|
||||
app.route('/', body(require('./ui/home')));
|
||||
app.route('/download/:id', body(download));
|
||||
app.route('/download/:id/:key', body(download));
|
||||
|
|
|
@ -1,58 +1,101 @@
|
|||
const html = require('choo/html');
|
||||
const Component = require('choo/component');
|
||||
|
||||
module.exports = function(state, emit) {
|
||||
if (!state.capabilities.account) {
|
||||
return null;
|
||||
class Account extends Component {
|
||||
constructor(name, state, emit) {
|
||||
super(name);
|
||||
this.state = state;
|
||||
this.emit = emit;
|
||||
this.enabled = state.capabilities.account;
|
||||
this.local = state.components[name] = {};
|
||||
this.setState();
|
||||
}
|
||||
const user = state.user;
|
||||
if (!user.loggedIn) {
|
||||
return html`<button
|
||||
class="p-2 border rounded border-white text-white hover:bg-white hover:text-blue md:text-blue md:border-blue md:hover:text-white md:hover:bg-blue"
|
||||
onclick=${login}>
|
||||
${state.translate('signInMenuOption')}
|
||||
</button>`;
|
||||
}
|
||||
return html`<div class="relative h-8">
|
||||
<input
|
||||
type="image"
|
||||
alt="${user.email}"
|
||||
class="w-8 h-8 rounded-full text-white"
|
||||
src="${user.avatar}"
|
||||
onclick=${avatarClick}/>
|
||||
<ul
|
||||
id="accountMenu"
|
||||
class="invisible list-reset absolute pin-t pin-r mt-10 pt-2 pb-2 bg-white shadow-md whitespace-no-wrap outline-none z-50"
|
||||
onblur="${hideMenu}"
|
||||
tabindex="-1">
|
||||
<li class="p-2 text-grey-dark">${user.email}</li>
|
||||
<li>
|
||||
<a class="block px-4 py-2 text-grey-darkest hover:bg-blue hover:text-white cursor-pointer" onclick=${logout}>
|
||||
${state.translate('logOut')}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>`;
|
||||
|
||||
function avatarClick(event) {
|
||||
avatarClick(event) {
|
||||
event.preventDefault();
|
||||
const menu = document.getElementById('accountMenu');
|
||||
menu.classList.toggle('invisible');
|
||||
menu.focus();
|
||||
}
|
||||
|
||||
function hideMenu(event) {
|
||||
hideMenu(event) {
|
||||
event.stopPropagation();
|
||||
const menu = document.getElementById('accountMenu');
|
||||
menu.classList.add('invisible');
|
||||
}
|
||||
|
||||
function login(event) {
|
||||
login(event) {
|
||||
event.preventDefault();
|
||||
emit('login');
|
||||
this.emit('login');
|
||||
}
|
||||
|
||||
function logout(event) {
|
||||
logout(event) {
|
||||
event.preventDefault();
|
||||
emit('logout');
|
||||
this.emit('logout');
|
||||
}
|
||||
};
|
||||
|
||||
changed() {
|
||||
return this.local.loggedIn !== this.state.user.loggedIn;
|
||||
}
|
||||
|
||||
setState() {
|
||||
const changed = this.changed();
|
||||
if (changed) {
|
||||
this.local.loggedIn = this.state.user.loggedIn;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
update() {
|
||||
return this.setState();
|
||||
}
|
||||
|
||||
createElement() {
|
||||
if (!this.enabled) {
|
||||
return null;
|
||||
}
|
||||
const user = this.state.user;
|
||||
const translate = this.state.translate;
|
||||
if (!this.local.loggedIn) {
|
||||
return html`
|
||||
<div>
|
||||
<button
|
||||
class="p-2 border rounded border-white text-white hover:bg-white hover:text-blue md:text-blue md:border-blue md:hover:text-white md:hover:bg-blue"
|
||||
onclick="${e => this.login(e)}"
|
||||
>
|
||||
${translate('signInMenuOption')}
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
return html`
|
||||
<div class="relative h-8">
|
||||
<input
|
||||
type="image"
|
||||
alt="${user.email}"
|
||||
class="w-8 h-8 rounded-full text-white"
|
||||
src="${user.avatar}"
|
||||
onclick="${e => this.avatarClick(e)}"
|
||||
/>
|
||||
<ul
|
||||
id="accountMenu"
|
||||
class="invisible list-reset absolute pin-t pin-r mt-10 pt-2 pb-2 bg-white shadow-md whitespace-no-wrap outline-none z-50"
|
||||
onblur="${e => this.hideMenu(e)}"
|
||||
tabindex="-1"
|
||||
>
|
||||
<li class="p-2 text-grey-dark">${user.email}</li>
|
||||
<li>
|
||||
<a
|
||||
class="block px-4 py-2 text-grey-darkest hover:bg-blue hover:text-white cursor-pointer"
|
||||
onclick="${e => this.logout(e)}"
|
||||
>
|
||||
${translate('logOut')}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Account;
|
||||
|
|
28
app/ui/body.js
Normal file
28
app/ui/body.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
const html = require('choo/html');
|
||||
const Promo = require('./promo');
|
||||
const Header = require('./header');
|
||||
const Footer = require('./footer');
|
||||
|
||||
function banner(state) {
|
||||
if (state.promo && !state.route.startsWith('/unsupported/')) {
|
||||
return state.cache(Promo, 'promo').render();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function body(main) {
|
||||
return function(state, emit) {
|
||||
const b = html`
|
||||
<body
|
||||
class="flex flex-col items-center font-sans bg-blue-lightest md:h-screen md:bg-grey-lightest"
|
||||
>
|
||||
${banner(state, emit)} ${state.cache(Header, 'header').render()}
|
||||
${main(state, emit)} ${state.cache(Footer, 'footer').render()}
|
||||
</body>
|
||||
`;
|
||||
if (state.layout) {
|
||||
// server side only
|
||||
return state.layout(state, b);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
};
|
118
app/ui/footer.js
118
app/ui/footer.js
|
@ -1,52 +1,74 @@
|
|||
const html = require('choo/html');
|
||||
const Component = require('choo/component');
|
||||
const version = require('../../package.json').version;
|
||||
const { browserName } = require('../utils');
|
||||
|
||||
module.exports = function(state) {
|
||||
const browser = browserName();
|
||||
const feedbackUrl = `https://qsurvey.mozilla.com/s3/txp-firefox-send?ver=${version}&browser=${browser}`;
|
||||
const footer = html`<footer class="flex flex-col md:flex-row items-start w-full flex-none self-start p-6 font-medium text-xs text-grey-dark md:items-center justify-between bg-grey-lightest">
|
||||
<a class="mozilla-logo pb-10 md:pb-0 m-2"
|
||||
href="https://www.mozilla.org/">
|
||||
Mozilla
|
||||
</a>
|
||||
<ul class="list-reset flex flex-col md:flex-row items-start md:items-center md:justify-end">
|
||||
<li class="m-2"><a
|
||||
href="https://www.mozilla.org/about/legal">
|
||||
${state.translate('footerLinkLegal')}
|
||||
</a></li>
|
||||
<li class="m-2"><a
|
||||
href="/legal">
|
||||
${state.translate('footerLinkTerms')}
|
||||
</a></li>
|
||||
<li class="m-2"><a
|
||||
href="https://www.mozilla.org/privacy/websites/#cookies">
|
||||
${state.translate('footerLinkCookies')}
|
||||
</a></li>
|
||||
<li class="m-2"><a
|
||||
href="https://www.mozilla.org/about/legal/report-infringement/">
|
||||
${state.translate('reportIPInfringement')}
|
||||
</a></li>
|
||||
<li class="m-2"><a
|
||||
href="https://github.com/mozilla/send">GitHub
|
||||
</a></li>
|
||||
<li class="m-2"><a
|
||||
href="https://twitter.com/FxTestPilot">Twitter
|
||||
</a></li>
|
||||
<li class="m-2"><a href="${feedbackUrl}"
|
||||
rel="noreferrer noopener"
|
||||
class="feedback-link"
|
||||
alt="Feedback"
|
||||
target="_blank">
|
||||
${state.translate('siteFeedback')}
|
||||
</a></li>
|
||||
</ul>
|
||||
</footer>`;
|
||||
// HACK
|
||||
// We only want to render this once because we
|
||||
// toggle the targets of the links with utils/openLinksInNewTab
|
||||
footer.isSameNode = function(target) {
|
||||
return target && target.nodeName && target.nodeName === 'FOOTER';
|
||||
};
|
||||
return footer;
|
||||
};
|
||||
class Footer extends Component {
|
||||
constructor(name, state) {
|
||||
super(name);
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
update() {
|
||||
return false;
|
||||
}
|
||||
|
||||
createElement() {
|
||||
const translate = this.state.translate;
|
||||
const browser = browserName();
|
||||
const feedbackUrl = `https://qsurvey.mozilla.com/s3/txp-firefox-send?ver=${version}&browser=${browser}`;
|
||||
return html`
|
||||
<footer
|
||||
class="flex flex-col md:flex-row items-start w-full flex-none self-start p-6 font-medium text-xs text-grey-dark md:items-center justify-between bg-grey-lightest"
|
||||
>
|
||||
<a
|
||||
class="mozilla-logo pb-10 md:pb-0 m-2"
|
||||
href="https://www.mozilla.org/"
|
||||
>
|
||||
Mozilla
|
||||
</a>
|
||||
<ul
|
||||
class="list-reset flex flex-col md:flex-row items-start md:items-center md:justify-end"
|
||||
>
|
||||
<li class="m-2">
|
||||
<a href="https://www.mozilla.org/about/legal">
|
||||
${translate('footerLinkLegal')}
|
||||
</a>
|
||||
</li>
|
||||
<li class="m-2">
|
||||
<a href="/legal"> ${translate('footerLinkTerms')} </a>
|
||||
</li>
|
||||
<li class="m-2">
|
||||
<a href="https://www.mozilla.org/privacy/websites/#cookies">
|
||||
${translate('footerLinkCookies')}
|
||||
</a>
|
||||
</li>
|
||||
<li class="m-2">
|
||||
<a href="https://www.mozilla.org/about/legal/report-infringement/">
|
||||
${translate('reportIPInfringement')}
|
||||
</a>
|
||||
</li>
|
||||
<li class="m-2">
|
||||
<a href="https://github.com/mozilla/send">GitHub </a>
|
||||
</li>
|
||||
<li class="m-2">
|
||||
<a href="https://twitter.com/FxTestPilot">Twitter </a>
|
||||
</li>
|
||||
<li class="m-2">
|
||||
<a
|
||||
href="${feedbackUrl}"
|
||||
rel="noreferrer noopener"
|
||||
class="feedback-link"
|
||||
alt="Feedback"
|
||||
target="_blank"
|
||||
>
|
||||
${translate('siteFeedback')}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Footer;
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
const html = require('choo/html');
|
||||
const assets = require('../../common/assets');
|
||||
|
||||
module.exports = function() {
|
||||
return html`
|
||||
<div class="w-full flex-none flex flex-row items-center content-center justify-center text-sm bg-grey-light leading-tight text-grey-darkest px-4 py-3">
|
||||
<div class="flex items-center mx-auto">
|
||||
<img
|
||||
src="${assets.get('firefox_logo-only.svg')}"
|
||||
class="w-6"
|
||||
alt="Firefox"/>
|
||||
<span class="ml-3">Send is brought to you by the all-new Firefox.
|
||||
<a
|
||||
class="text-blue"
|
||||
href="https://www.mozilla.org/firefox/new/?utm_campaign=send-acquisition&utm_medium=referral&utm_source=send.firefox.com">Download Firefox now ≫</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>`;
|
||||
};
|
|
@ -1,25 +1,34 @@
|
|||
const html = require('choo/html');
|
||||
const account = require('./account');
|
||||
const Component = require('choo/component');
|
||||
const Account = require('./account');
|
||||
|
||||
module.exports = function(state, emit) {
|
||||
const header = html`
|
||||
<header class="relative flex-none flex flex-row items-center justify-between bg-blue md:bg-white w-full px-6 h-16 md:shadow z-20">
|
||||
<a
|
||||
class="header-logo"
|
||||
href="/">
|
||||
<h1 class="text-white md:text-black font-normal">Firefox <b>Send</b></h1>
|
||||
</a>
|
||||
${account(state, emit)}
|
||||
<div class="invisible absolute pin-t pin-l mt-12 w-full flex flex-col items-center pointer-events-none">
|
||||
<div class="border rounded bg-grey-darkest text-white mt-2 p-2">Your upload has finished.<button class="border border-blue rounded-sm bg-blue text-white inline-block p-1 ml-2">Copy Link</button><button class="text-white inline-block p-1 ml-2">ⓧ</button></div>
|
||||
${state.toast ? state.toast() : ''}
|
||||
</div>
|
||||
</header>`;
|
||||
// HACK
|
||||
// We only want to render this once because we
|
||||
// toggle the targets of the links with utils/openLinksInNewTab
|
||||
// header.isSameNode = function(target) {
|
||||
// return target && target.nodeName && target.nodeName === 'HEADER';
|
||||
// };
|
||||
return header;
|
||||
};
|
||||
class Header extends Component {
|
||||
constructor(name, state, emit) {
|
||||
super(name);
|
||||
this.state = state;
|
||||
this.emit = emit;
|
||||
this.account = state.cache(Account, 'account');
|
||||
}
|
||||
|
||||
update() {
|
||||
this.account.render();
|
||||
return false;
|
||||
}
|
||||
|
||||
createElement() {
|
||||
return html`
|
||||
<header
|
||||
class="relative flex-none flex flex-row items-center justify-between bg-blue md:bg-white w-full px-6 h-16 md:shadow z-20"
|
||||
>
|
||||
<a class="header-logo" href="/">
|
||||
<h1 class="text-white md:text-black font-normal">
|
||||
Firefox <b>Send</b>
|
||||
</h1>
|
||||
</a>
|
||||
${this.account.render()}
|
||||
</header>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Header;
|
||||
|
|
39
app/ui/promo.js
Normal file
39
app/ui/promo.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
const html = require('choo/html');
|
||||
const Component = require('choo/component');
|
||||
const assets = require('../../common/assets');
|
||||
|
||||
class Promo extends Component {
|
||||
constructor(name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
update() {
|
||||
return false;
|
||||
}
|
||||
|
||||
createElement() {
|
||||
return html`
|
||||
<div
|
||||
class="w-full flex-none flex flex-row items-center content-center justify-center text-sm bg-grey-light leading-tight text-grey-darkest px-4 py-3"
|
||||
>
|
||||
<div class="flex items-center mx-auto">
|
||||
<img
|
||||
src="${assets.get('firefox_logo-only.svg')}"
|
||||
class="w-6"
|
||||
alt="Firefox"
|
||||
/>
|
||||
<span class="ml-3"
|
||||
>Send is brought to you by the all-new Firefox.
|
||||
<a
|
||||
class="text-blue"
|
||||
href="https://www.mozilla.org/firefox/new/?utm_campaign=send-acquisition&utm_medium=referral&utm_source=send.firefox.com"
|
||||
>Download Firefox now ≫</a
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Promo;
|
Loading…
Add table
Add a link
Reference in a new issue