diff --git a/.stylelintrc b/.stylelintrc
index 9ade6144..0af67b03 100644
--- a/.stylelintrc
+++ b/.stylelintrc
@@ -10,3 +10,4 @@ rules:
declaration-colon-newline-after: null
selector-list-comma-newline-after: null
value-list-comma-newline-after: null
+ at-rule-no-unknown: null
diff --git a/app/archive.js b/app/archive.js
index 6cdce5f4..dea25cd1 100644
--- a/app/archive.js
+++ b/app/archive.js
@@ -62,7 +62,10 @@ export default class Archive {
return true;
}
- remove(index) {
- this.files.splice(index, 1);
+ remove(file) {
+ const index = this.files.indexOf(file);
+ if (index > -1) {
+ this.files.splice(index, 1);
+ }
}
}
diff --git a/app/base.css b/app/base.css
deleted file mode 100644
index 27707143..00000000
--- a/app/base.css
+++ /dev/null
@@ -1,305 +0,0 @@
-:root {
- --pageBGColor: #fff;
- --lightControlBGColor: #e6e6e6;
- --primaryControlBGColor: #0a84ff;
- --primaryControlFGColor: #fff;
- --primaryControlHoverColor: #0473e2;
- --inputTextColor: #737373;
- --errorColor: #d70022;
- --linkColor: #0094fb;
- --textColor: #0c0c0d;
- --lightBorderColor: rgba(12, 12, 12, 0.2);
- --lightTextColor: #737373;
- --successControlBGColor: #12bc00;
- --successControlFGColor: #fff;
-}
-
-html {
- font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'segoe ui',
- 'helvetica neue', helvetica, ubuntu, roboto, noto, arial, sans-serif;
- font-weight: 200;
-}
-
-body {
- font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'segoe ui',
- 'helvetica neue', helvetica, ubuntu, roboto, noto, arial, sans-serif;
- display: flex;
- flex-direction: column;
- margin: 0;
- height: 100vh;
-}
-
-input,
-select,
-textarea,
-button {
- font-family: inherit;
- margin: 0;
-}
-
-a {
- text-decoration: none;
-}
-
-.main {
- display: flex;
- flex: auto;
- padding: 0 25px;
- box-sizing: border-box;
- min-height: 500px;
- max-height: 800px;
- height: 100%;
-}
-
-.stripedBox {
- flex: none;
- position: relative;
- width: 400px;
- margin-top: 32px;
- background-color: white;
- border-radius: 6px;
- border: 3px solid rgba(12, 12, 12, 0.2);
- background-clip: padding-box;
- background-image: repeating-linear-gradient(
- 45deg,
- white,
- white 5px,
- #ea000e 5px,
- #ea000e 25px,
- white 25px,
- white 30px,
- #0083ff 30px,
- #0083ff 50px
- );
-}
-
-.mainContent {
- height: 100%;
- background-color: white;
- box-sizing: border-box;
- margin: 0 10px;
- padding: 10px 10px 28px;
- display: flex;
- flex-direction: column;
-}
-
-.spacer {
- flex: auto;
-}
-
-.uploads {
- flex: 0 0 262px;
- box-sizing: border-box;
- padding-top: 180px;
- display: flex;
-}
-
-.noscript {
- text-align: center;
- border: 3px solid var(--errorColor);
- border-radius: 6px;
-}
-
-.btn {
- display: flex;
- width: 100%;
- height: 70px;
- line-height: 1.2;
- align-items: center;
- justify-content: center;
- padding: 0 10px;
- box-sizing: border-box;
- font-size: 17px;
- font-weight: 500;
- text-transform: uppercase;
- text-align: center;
- letter-spacing: 0.56px;
- color: var(--primaryControlFGColor);
- background: var(--primaryControlBGColor);
- cursor: pointer;
- border: 0;
- border-radius: 5px;
-}
-
-.btn:hover {
- background-color: var(--primaryControlHoverColor);
-}
-
-.btn--stripes {
- background: repeating-linear-gradient(
- -65deg,
- #7c7c7c 0,
- #7c7c7c 17px,
- #737373 17px,
- #737373 30px
- );
- background-size: 300% 300%;
- animation: barberpole 12s linear infinite;
-}
-
-@keyframes barberpole {
- 0% {
- background-position: 100% 0%;
- }
-
- 100% {
- background-position: 0% 0%;
- }
-}
-
-.btn--cancel {
- font-size: 13px;
- font-weight: 700;
- background: none;
- color: var(--errorColor);
- border: none;
-}
-
-.input {
- border: 1px solid var(--lightBorderColor);
- font-size: 20px;
- color: var(--inputTextColor);
- font-family: 'SF Pro Text', sans-serif;
- font-weight: 300;
- padding-left: 10px;
- padding-right: 10px;
-}
-
-.input--error {
- border-color: var(--errorColor);
-}
-
-.link {
- color: var(--linkColor);
- text-decoration: none;
-}
-
-.link:focus,
-.link:active,
-.link:hover {
- color: var(--primaryControlHoverColor);
-}
-
-.link--action {
- font-weight: 500;
- font-size: 14px;
- text-align: center;
-}
-
-.page {
- height: 100%;
- margin: 0;
- display: flex;
- flex-direction: column;
- text-align: center;
-}
-
-.effect--fadeOut {
- opacity: 0;
- animation: fadeout 200ms linear;
-}
-
-@keyframes fadeout {
- 0% {
- opacity: 1;
- }
-
- 100% {
- opacity: 0;
- }
-}
-
-.effect--fadeIn {
- opacity: 1;
- animation: fadein 200ms linear;
-}
-
-@keyframes fadein {
- 0% {
- opacity: 0;
- }
-
- 100% {
- opacity: 1;
- }
-}
-
-.goBackButton {
- position: absolute;
- top: 0;
- left: 0;
- margin: 18px;
-}
-
-.error {
- color: var(--errorColor);
- font-weight: 600;
-}
-
-.title {
- color: var(--lightTextColor);
- font-size: 18px;
- line-height: 40px;
- margin: 20px auto;
- max-width: 520px;
- font-family: 'SF Pro Text', sans-serif;
- font-weight: 700;
- word-wrap: break-word;
-}
-
-.description {
- font-size: 13px;
- text-align: left;
- margin: 14px auto;
- color: var(--lightTextColor);
- width: 95%;
-}
-
-.visible {
- visibility: visible !important;
-}
-
-.noDisplay {
- display: none !important;
-}
-
-.flexible {
- flex: 1;
-}
-
-@media (max-device-width: 750px), (max-width: 750px) {
- .description {
- margin: 0 auto 25px;
- }
-
- .main {
- flex-direction: column;
- height: 100%;
- }
-
- .spacer {
- flex: none;
- height: 0;
- }
-
- .stripedBox {
- margin-top: 72px;
- min-height: 400px;
- flex: 1;
- }
-
- .uploads {
- flex: none;
- padding-top: 6px;
- }
-
- .footer {
- margin: 15px;
- }
-}
-
-@media (max-device-width: 700px), (max-width: 700px) {
- .stripedBox {
- margin-top: 72px;
- }
-}
diff --git a/app/dragManager.js b/app/dragManager.js
index 3002e9c1..f5133a0a 100644
--- a/app/dragManager.js
+++ b/app/dragManager.js
@@ -3,20 +3,14 @@ export default function(state, emitter) {
document.body.addEventListener('dragover', event => {
if (state.route === '/') {
event.preventDefault();
- const files = document.querySelector('.uploadedFilesWrapper');
- files.classList.add('uploadArea--noEvents');
}
});
document.body.addEventListener('drop', event => {
if (state.route === '/' && !state.uploading) {
event.preventDefault();
- document
- .querySelector('.uploadArea')
- .classList.remove('uploadArea--dragging');
-
- const files = Array.from(event.dataTransfer.files);
-
- emitter.emit('addFiles', { files });
+ emitter.emit('addFiles', {
+ files: Array.from(event.dataTransfer.files)
+ });
}
});
});
diff --git a/app/fileManager.js b/app/fileManager.js
index bd45b252..b43a91ca 100644
--- a/app/fileManager.js
+++ b/app/fileManager.js
@@ -5,7 +5,8 @@ import { copyToClipboard, delay, openLinksInNewTab, percent } from './utils';
import * as metrics from './metrics';
import Archive from './archive';
import { bytes } from './utils';
-import okDialog from './templates/okDialog';
+import okDialog from './ui/okDialog';
+import copyDialog from './ui/copyDialog';
export default function(state, emitter) {
let lastRender = 0;
@@ -66,8 +67,11 @@ export default function(state, emitter) {
metrics.changedDownloadLimit(file);
});
- emitter.on('removeUpload', async ({ index }) => {
- state.archive.remove(index);
+ emitter.on('removeUpload', file => {
+ state.archive.remove(file);
+ if (state.archive.numFiles === 0) {
+ state.archive = null;
+ }
render();
});
@@ -86,6 +90,7 @@ export default function(state, emitter) {
} catch (e) {
state.raven.captureException(e);
}
+ render();
});
emitter.on('cancel', () => {
@@ -104,6 +109,9 @@ export default function(state, emitter) {
count: LIMITS.MAX_FILES_PER_ARCHIVE
})
);
+ if (state.archive.numFiles === 0) {
+ state.archive = null;
+ }
}
render();
});
@@ -149,15 +157,7 @@ export default function(state, emitter) {
if (password) {
emitter.emit('password', { password, file: ownedFile });
}
-
- const cancelBtn = document.getElementById('cancel-upload');
- if (cancelBtn) {
- cancelBtn.hidden = 'hidden';
- }
- if (document.querySelector('.page')) {
- await delay(1000);
- }
- emitter.emit('pushState', `/share/${ownedFile.id}`);
+ state.modal = copyDialog(ownedFile.name, ownedFile.url);
} catch (err) {
if (err.message === '0') {
//cancelled. do nothing
@@ -176,6 +176,7 @@ export default function(state, emitter) {
state.password = '';
state.uploading = false;
state.transfer = null;
+ render();
}
});
@@ -232,11 +233,7 @@ export default function(state, emitter) {
await dl;
const time = Date.now() - start;
const speed = size / (time / 1000);
- if (document.querySelector('.page')) {
- await delay(1000);
- }
state.storage.totalDownloads += 1;
- state.transfer.reset();
metrics.completedDownload({ size, time, speed });
} catch (err) {
if (err.message === '0') {
diff --git a/app/main.css b/app/main.css
index 3a98d958..95ca22ad 100644
--- a/app/main.css
+++ b/app/main.css
@@ -1,25 +1,158 @@
-@import './base.css';
-@import './pages/share/share.css';
-@import './pages/signin/signin.css';
-@import './pages/unsupported/unsupported.css';
-@import './pages/welcome/welcome.css';
-@import './templates/downloadButton/downloadButton.css';
-@import './templates/downloadPassword/downloadPassword.css';
-@import './templates/file/file.css';
-@import './templates/fileIcon/fileIcon.css';
-@import './templates/fileList/fileList.css';
-@import './templates/footer/footer.css';
-@import './templates/fxPromo/fxPromo.css';
-@import './templates/header/header.css';
-@import './templates/modal/modal.css';
-@import './templates/okDialog/okDialog.css';
-@import './templates/passwordInput/passwordInput.css';
-@import './templates/popup/popup.css';
-@import './templates/selectbox/selectbox.css';
-@import './templates/setPasswordSection/setPasswordSection.css';
-@import './templates/signupDialog/signupDialog.css';
-@import './templates/signupPromo/signupPromo.css';
-@import './templates/title/title.css';
-@import './templates/uploadedFile/uploadedFile.css';
-@import './templates/uploadedFileList/uploadedFileList.css';
-@import './templates/userAccount/userAccount.css';
+@tailwind preflight;
+@tailwind components;
+@tailwind utilities;
+
+a {
+ color: inherit;
+ text-decoration: none;
+}
+
+progress {
+ @apply bg-grey-light;
+ @apply rounded-sm;
+ @apply w-full;
+ @apply h-1;
+}
+
+progress::-moz-progress-bar {
+ @apply bg-blue;
+ @apply rounded-sm;
+}
+
+progress::-webkit-progress-bar {
+ @apply bg-grey-light;
+ @apply rounded-sm;
+ @apply w-full;
+ @apply h-1;
+}
+
+progress::-webkit-progress-value {
+ @apply bg-blue;
+ @apply rounded-sm;
+}
+
+.main {
+ display: flex;
+ max-width: 64rem;
+ width: 100%;
+}
+
+.main > section {
+ @apply bg-white;
+ @apply shadow;
+}
+
+.header-logo {
+ background-image: url('../assets/send_logo.svg');
+ background-position: left;
+ background-repeat: no-repeat;
+ background-size: 1.8rem;
+ padding-left: 2.4rem;
+ text-decoration: none;
+}
+
+.header-logo h1 {
+ font-size: 1.5rem;
+}
+
+.mozilla-logo {
+ background-image: url('../assets/mozilla-logo.svg');
+ background-repeat: no-repeat;
+ background-size: 100px, 32px;
+ overflow: hidden;
+ text-indent: 120%;
+ white-space: nowrap;
+ display: inline-block;
+ height: 32px;
+ width: 100px;
+ flex-shrink: 0;
+}
+
+.feedback-link {
+ background-color: #000;
+ background-image: url('../assets/feedback.svg');
+ background-position: 0.125rem 0.25rem;
+ background-repeat: no-repeat;
+ background-size: 1.125rem;
+ color: #fff;
+ display: block;
+ font-size: 0.75rem;
+ line-height: 0.75rem;
+ padding: 0.375rem 0.375rem 0.375rem 1.25rem;
+ text-indent: 0.125rem;
+ white-space: nowrap;
+}
+
+.checkbox {
+ @apply leading-normal;
+ @apply select-none;
+}
+
+.checkbox > input[type='checkbox'] {
+ @apply absolute;
+ @apply opacity-0;
+}
+
+.checkbox > label {
+ @apply cursor-pointer;
+}
+
+.checkbox > label::before {
+ @apply bg-blue-lightest;
+ @apply border;
+ @apply rounded-sm;
+
+ content: '';
+ height: 1.5rem;
+ width: 1.5rem;
+ margin-right: 0.5rem;
+ float: left;
+}
+
+.checkbox > label:hover::before {
+ @apply border-blue;
+}
+
+.checkbox > input:focus + label::before {
+ @apply border-blue;
+}
+
+.checkbox > input:checked + label::before {
+ background-image: url('../assets/lock.svg');
+ background-position: center;
+ background-size: 1.25rem;
+ background-repeat: no-repeat;
+}
+
+.checkbox > input:disabled + label {
+ cursor: auto;
+}
+
+.checkbox > input:disabled + label::before {
+ background-image: url('../assets/lock.svg');
+ background-position: center;
+ background-size: 1.25rem;
+ background-repeat: no-repeat;
+ cursor: auto;
+}
+
+#password-msg::after {
+ content: '\200b';
+}
+
+@screen md {
+ .main {
+ @apply flex-1;
+ @apply self-center;
+ @apply items-center;
+ @apply my-10;
+
+ width: calc(100% - 3rem);
+ min-height: 30rem;
+ max-height: 40rem;
+ }
+
+ .main > section {
+ @apply shadow-md;
+ }
+}
diff --git a/app/main.js b/app/main.js
index 8febde65..d16c4f07 100644
--- a/app/main.js
+++ b/app/main.js
@@ -34,6 +34,7 @@ import User from './user';
window.appState = state;
window.appEmit = emitter.emit.bind(emitter);
let unsupportedReason = null;
+
if (
// Firefox < 50
/firefox/i.test(navigator.userAgent) &&
diff --git a/app/pages/error/index.js b/app/pages/error/index.js
deleted file mode 100644
index 5b6167f5..00000000
--- a/app/pages/error/index.js
+++ /dev/null
@@ -1,22 +0,0 @@
-const html = require('choo/html');
-const assets = require('../../../common/assets');
-const title = require('../../templates/title');
-
-module.exports = function(state) {
- return html`
-
-
- ${title(state)}
-
-
${state.translate('errorPageHeader')}
-
})
-
-
- ${state.translate('uploadPageExplainer')}
-
-
- ${state.translate('sendYourFilesLink')}
-
-
-
`;
-};
diff --git a/app/pages/legal.js b/app/pages/legal.js
deleted file mode 100644
index f18a926a..00000000
--- a/app/pages/legal.js
+++ /dev/null
@@ -1,38 +0,0 @@
-const html = require('choo/html');
-const raw = require('choo/html/raw');
-const assets = require('../../common/assets');
-const title = require('../templates/title');
-
-module.exports = function(state) {
- return html`
-
-
-
-
- ${title(state)}
-
${state.translate('legalHeader')}
- ${raw(
- replaceLinks(state.translate('legalNoticeTestPilot'), [
- 'https://testpilot.firefox.com/terms',
- 'https://testpilot.firefox.com/privacy',
- 'https://testpilot.firefox.com/experiments/send'
- ])
- )}
- ${raw(
- replaceLinks(state.translate('legalNoticeMozilla'), [
- 'https://www.mozilla.org/privacy/websites/',
- 'https://www.mozilla.org/about/legal/terms/mozilla/'
- ])
- )}
-
- `;
-};
-
-function replaceLinks(str, urls) {
- let i = 0;
- const s = str.replace(
- /([^<]+)<\/a>/g,
- (m, v) => `${v}`
- );
- return `${s}
`;
-}
diff --git a/app/pages/notFound/index.js b/app/pages/notFound/index.js
deleted file mode 100644
index 46ab6753..00000000
--- a/app/pages/notFound/index.js
+++ /dev/null
@@ -1,22 +0,0 @@
-const html = require('choo/html');
-const assets = require('../../../common/assets');
-const title = require('../../templates/title');
-
-module.exports = function(state) {
- return html`
-
-
- ${title(state)}
-
-
${state.translate('expiredPageHeader')}
-
})
-
- ${state.translate('uploadPageExplainer')}
-
-
- ${state.translate('sendYourFilesLink')}
-
-
`;
-};
diff --git a/app/pages/password/index.js b/app/pages/password/index.js
deleted file mode 100644
index e4c06949..00000000
--- a/app/pages/password/index.js
+++ /dev/null
@@ -1,19 +0,0 @@
-const html = require('choo/html');
-const titleSection = require('../../templates/title');
-const downloadPassword = require('../../templates/downloadPassword');
-
-module.exports = function(state, emit) {
- return html`
-
- ${titleSection(state)}
-
-
${state.translate('downloadMessage2')}
- ${downloadPassword(state, emit)}
-
-
- ${state.translate('sendYourFilesLink')}
-
-
-
- `;
-};
diff --git a/app/pages/preview/index.js b/app/pages/preview/index.js
deleted file mode 100644
index 076d26c8..00000000
--- a/app/pages/preview/index.js
+++ /dev/null
@@ -1,42 +0,0 @@
-const html = require('choo/html');
-const titleSection = require('../../templates/title');
-const downloadButton = require('../../templates/downloadButton');
-const downloadedFiles = require('../../templates/uploadedFileList');
-
-module.exports = function(state, emit) {
- const fileInfo = state.fileInfo;
-
- const trySendLink = html`
-
- ${state.translate('sendYourFilesLink')}
- `;
- const cancelButton = html`
-
- `;
-
- const bottomLink =
- state.transfer.state === 'downloading' ? cancelButton : trySendLink;
-
- return html`
-
- ${titleSection(state)}
-
- ${downloadedFiles(fileInfo, state, emit)}
-
${state.translate('downloadMessage2')}
- ${downloadButton(state, emit)}
-
- ${bottomLink}
-
-
- `;
-
- function cancel() {
- if (state.transfer.state === 'downloading') {
- emit('cancel');
- }
- }
-};
diff --git a/app/pages/share/index.js b/app/pages/share/index.js
deleted file mode 100644
index 153c3a98..00000000
--- a/app/pages/share/index.js
+++ /dev/null
@@ -1,110 +0,0 @@
-const html = require('choo/html');
-const raw = require('choo/html/raw');
-const assets = require('../../../common/assets');
-const notFound = require('../notFound');
-const deletePopup = require('../../templates/popup');
-const uploadedFileList = require('../../templates/uploadedFileList');
-const timeLimitText = require('../../templates/timeLimitText');
-const { allowedCopy, delay, fadeOut } = require('../../utils');
-
-module.exports = function(state, emit) {
- const file = state.storage.getFileById(state.params.id);
- if (!file) {
- return notFound(state);
- }
-
- const passwordReminderClass = file._hasPassword
- ? ''
- : 'passwordReminder--hidden';
-
- return html`
-
-
-
-
- ${expireInfo(file, state.translate)}
-
- ${uploadedFileList(file, state, emit)}
-
-
- ${state.translate('copyUrlLabel')}
-
(don't forget the password too)
-
-
-
-
-
-
-
-
-
-
-
-
- `;
-
- function showDeletePopup() {
- const popup = document.querySelector('.popup');
- popup.classList.add('popup--show');
- popup.focus();
- }
-
- async function copyLink() {
- if (allowedCopy()) {
- emit('copy', { url: file.url, location: 'success-screen' });
- const input = document.getElementById('fileUrl');
- input.disabled = true;
- const copyBtn = document.getElementById('copyBtn');
- copyBtn.disabled = true;
- copyBtn.classList.add('copyBtn--copied');
- copyBtn.replaceChild(
- html``,
- copyBtn.firstChild
- );
- await delay(2000);
- input.disabled = false;
- copyBtn.disabled = false;
- copyBtn.classList.remove('copyBtn--copied');
- copyBtn.textContent = state.translate('copyUrlFormButton');
- }
- }
-
- async function deleteFile() {
- emit('delete', { file, location: 'success-screen' });
- await fadeOut('#shareWrapper');
- emit('pushState', '/');
- }
-};
-
-function expireInfo(file, translate) {
- const el = html`
- ${raw(
- translate('expireInfo', {
- downloadCount: translate('downloadCount', { num: file.dlimit }),
- timespan: timeLimitText(translate, file.timeLimit)
- })
- )}
-
`;
-
- return el;
-}
diff --git a/app/pages/share/share.css b/app/pages/share/share.css
deleted file mode 100644
index 2ad3f468..00000000
--- a/app/pages/share/share.css
+++ /dev/null
@@ -1,81 +0,0 @@
-.sharePage__copyText {
- margin: 8px 0 8px;
- word-wrap: break-word;
- font-size: 15px;
- color: var(--lightTextColor);
- text-align: center;
-}
-
-.sharePage__passwordReminder {
- font-size: 11px;
- font-style: italic;
-}
-
-.passwordReminder--hidden {
- display: none;
-}
-
-.sharePage__deletePopup {
- position: relative;
- margin-top: -70px;
- pointer-events: none;
-}
-
-.shareTitle {
- color: var(--textColor);
- margin: 8px auto 15px;
- text-align: center;
- font-family: 'SF Pro Text', sans-serif;
- font-size: 12px;
- font-style: italic;
- width: 280px;
-}
-
-.copySection {
- width: 100%;
-}
-
-.copySection__url {
- box-sizing: border-box;
- height: 30px;
- border: 1px solid var(--lightBorderColor);
- border-radius: 4px;
- font-size: 15px;
- color: var(--primaryControlBGColor);
- margin: 0 0 6px;
- padding: 6px;
- font-family: 'SF Pro Text', sans-serif;
- letter-spacing: 0;
- line-height: 18px;
- font-weight: 500;
-}
-
-.copySection__url:disabled {
- background: var(--successControlFGColor);
-}
-
-.input--copied {
- border-color: var(--successControlBGColor);
-}
-
-.copyBtn--copied,
-.copyBtn--copied:hover {
- background: var(--successControlBGColor);
- color: var(--successControlFGColor);
-}
-
-.btn--delete {
- border: none;
- align-self: center;
- width: 176px;
- background: #fff;
- margin: 10px 0 0;
- font-size: 14px;
- line-height: 16px;
- color: var(--errorColor);
- cursor: pointer;
-}
-
-.btn--delete:hover {
- text-decoration: underline;
-}
diff --git a/app/pages/signin/index.js b/app/pages/signin/index.js
deleted file mode 100644
index 75588071..00000000
--- a/app/pages/signin/index.js
+++ /dev/null
@@ -1,66 +0,0 @@
-/* globals LIMITS */
-const html = require('choo/html');
-const assets = require('../../../common/assets');
-const title = require('../../templates/title');
-const bytes = require('../../utils').bytes;
-
-module.exports = function(state, emit) {
- return html`
-
-
-
-
- ${title(state)}
-
- ${state.translate('accountBenefitTitle')}
-
- - ${state.translate('accountBenefitLargeFiles', {
- size: bytes(LIMITS.MAX_FILE_SIZE)
- })}
- - ${state.translate('accountBenefitExpiry')}
- - ${state.translate('accountBenefitSync')}
-
-
-
-
-
- `;
-
- function submitEmail(event) {
- event.preventDefault();
- const el = document.getElementById('email-input');
- const email = el.value;
- if (email) {
- // just check if it's the right shape
- const a = email.split('@');
- if (a.length === 2 && a.every(s => s.length > 0)) {
- return emit('login', email);
- }
- }
- el.value = '';
- }
-};
diff --git a/app/pages/signin/signin.css b/app/pages/signin/signin.css
deleted file mode 100644
index 85745267..00000000
--- a/app/pages/signin/signin.css
+++ /dev/null
@@ -1,33 +0,0 @@
-.signInPage {
- font-size: 13px;
- line-height: 18px;
- color: var(--lightTextColor);
-}
-
-.signIn__info {
- width: 308px;
- margin: 12px auto 0;
- text-align: left;
-}
-
-.signIn__firefoxLogo {
- display: block;
- margin: 0 auto;
-}
-
-.signIn__emailLabel {
- font-size: 22px;
- margin: 8px 0;
-}
-
-.signIn__emailInput {
- box-sizing: border-box;
- width: 310px;
- height: 40px;
- border: 1px solid rgba(0, 0, 0, 0.2);
- border-radius: 4px;
- margin: 8px 0;
- padding: 0 8px;
- font-size: 18px;
- color: var(--lightTextColor);
-}
diff --git a/app/pages/unsupported/index.js b/app/pages/unsupported/index.js
deleted file mode 100644
index 61c724f5..00000000
--- a/app/pages/unsupported/index.js
+++ /dev/null
@@ -1,75 +0,0 @@
-const html = require('choo/html');
-const assets = require('../../../common/assets');
-const title = require('../../templates/title');
-
-module.exports = function(state) {
- let strings = {};
- let why = '';
- let url = '';
- let buttonAction = '';
-
- if (state.params.reason !== 'outdated') {
- strings = unsupportedStrings(state);
- why = html`
- `;
- url =
- 'https://www.mozilla.org/firefox/new/?utm_campaign=send-acquisition&utm_medium=referral&utm_source=send.firefox.com';
- buttonAction = html`
-
- Firefox
${strings.button}
-
`;
- } else {
- strings = outdatedStrings(state);
- url = 'https://support.mozilla.org/kb/update-firefox-latest-version';
- buttonAction = html`
-
- ${strings.button}
-
`;
- }
-
- return html`
-
- ${title(state)}
-
${strings.header}
-
- ${strings.description}
- ${why}
-
-
-
-
-
- ${strings.explainer}
-
-
`;
-};
-
-function outdatedStrings(state) {
- return {
- header: state.translate('notSupportedHeader'),
- description: state.translate('notSupportedOutdatedDetail'),
- button: state.translate('updateFirefox'),
- explainer: state.translate('uploadPageExplainer')
- };
-}
-
-function unsupportedStrings(state) {
- return {
- header: state.translate('notSupportedHeader'),
- description: state.translate('notSupportedDetail'),
- button: state.translate('downloadFirefoxButtonSub'),
- explainer: state.translate('uploadPageExplainer')
- };
-}
diff --git a/app/pages/unsupported/unsupported.css b/app/pages/unsupported/unsupported.css
deleted file mode 100644
index b34adcae..00000000
--- a/app/pages/unsupported/unsupported.css
+++ /dev/null
@@ -1,54 +0,0 @@
-.unsupportedPage {
- justify-content: center;
- align-items: center;
-}
-
-.unsupportedPage__error {
- margin: 10px 0 20px;
-}
-
-.unsupportedPage__info {
- font-size: 13px;
- color: var(--lightTextColor);
- margin: 0 auto 10px;
-}
-
-.firefoxDownload {
- flex: 2;
-}
-
-.firefoxDownload__button {
- margin: 0 auto 20px;
- height: 70px;
- width: 250px;
- background: #12bc00;
- border-radius: 3px;
- cursor: pointer;
- border: 0;
- font-family: 'Fira Sans', 'segoe ui', sans-serif;
- font-weight: 500;
- color: var(--primaryControlFGColor);
- font-size: 26px;
- display: flex;
- justify-content: center;
- align-items: center;
- line-height: 1;
- padding: 8px;
-}
-
-.firefoxDownload__logo {
- width: 55px;
-}
-
-.firefoxDownload__action {
- text-align: left;
- text-transform: uppercase;
- margin-left: 20px;
-}
-
-.firefoxDownload__text {
- text-transform: none;
- font-family: 'Fira Sans', 'segoe ui', sans-serif;
- font-weight: 300;
- font-size: 17px;
-}
diff --git a/app/pages/welcome/index.js b/app/pages/welcome/index.js
deleted file mode 100644
index ffe60ba1..00000000
--- a/app/pages/welcome/index.js
+++ /dev/null
@@ -1,140 +0,0 @@
-const html = require('choo/html');
-const assets = require('../../../common/assets');
-const title = require('../../templates/title');
-const setPasswordSection = require('../../templates/setPasswordSection');
-const uploadBox = require('../../templates/uploadedFileList');
-const expireInfo = require('../../templates/expireInfo');
-
-module.exports = function(state, emit) {
- // the page flickers if both the server and browser set 'effect--fadeIn'
- const fade = state.layout ? '' : 'effect--fadeIn';
-
- const hasAnUpload = state.archive && state.archive.numFiles > 0;
-
- const optionClass = state.uploading ? 'uploadOptions--faded' : '';
- const btnUploading = state.uploading ? 'btn--stripes' : '';
- const cancelVisible = state.uploading ? '' : 'noDisplay';
- const faded = hasAnUpload ? 'uploadArea--faded' : '';
- const selectFileClass = hasAnUpload > 0 ? 'btn--hidden' : '';
- const sendFileClass = hasAnUpload > 0 ? '' : 'btn--hidden';
-
- let btnText = '';
-
- if (state.encrypting) {
- btnText = state.translate('encryptingFile');
- } else if (state.uploading) {
- btnText = `sending... ${Math.floor(state.transfer.progressRatio * 100)}%`;
- } else {
- //default pre-upload text
- btnText = state.translate('uploadSuccessConfirmHeader');
- }
-
- return html`
-
- ${title(state)}
-
-
-
-
- ${expireInfo(state, emit)}
- ${setPasswordSection(state)}
-
-
-
-
-
-
-
-
-
- `;
-
- function noop() {}
-
- function dragover(event) {
- const div = document.querySelector('.uploadArea');
- div.classList.add('uploadArea--dragging');
- }
-
- function dragleave(event) {
- const div = document.querySelector('.uploadArea');
- div.classList.remove('uploadArea--dragging');
- }
-
- function onfocus(event) {
- event.target.classList.add('inputFile--focused');
- }
-
- function onblur(event) {
- event.target.classList.remove('inputFile--focused');
- }
-
- function cancel(event) {
- if (state.uploading) {
- emit('cancel');
- const cancelBtn = document.querySelector('.uploadCancel');
- cancelBtn.innerHTML = state.translate('uploadCancelNotification');
- }
- }
-
- function addFiles(event) {
- event.preventDefault();
- const newFiles = Array.from(event.target.files);
-
- emit('addFiles', { files: newFiles });
- }
-
- function upload(event) {
- event.preventDefault();
- event.target.disabled = true;
- if (!state.uploading) {
- emit('upload', {
- type: 'click',
- dlimit: state.downloadCount || 1,
- password: state.password
- });
- }
- }
-};
diff --git a/app/pages/welcome/welcome.css b/app/pages/welcome/welcome.css
deleted file mode 100644
index defa299b..00000000
--- a/app/pages/welcome/welcome.css
+++ /dev/null
@@ -1,96 +0,0 @@
-.uploadArea {
- position: relative;
- display: flex;
- flex-direction: column;
- justify-content: center;
- text-align: center;
- border: 1px dashed rgba(12, 12, 13, 0.2);
- margin: 0 0 10px;
- height: 400px;
- border-radius: 4px;
- overflow: scroll;
- transition: transform 150ms;
- flex: 1;
-}
-
-.uploadArea__msg {
- font-size: 15px;
- color: var(--lightTextColor);
- margin: 12px 0 0;
- font-family: 'SF Pro Text', sans-serif;
- text-transform: uppercase;
- font-weight: bold;
-}
-
-.uploadArea__clickMsg {
- font-style: italic;
- font-size: 12px;
- line-height: 12px;
- color: var(--lightTextColor);
- margin: 5px;
-}
-
-.uploadArea--dragging {
- border: 1px dashed rgba(12, 12, 13, 0.4);
- transform: scale(1.04);
-}
-
-.uploadArea--faded * {
- opacity: 0.5;
-}
-
-.uploadArea--noEvents,
-.uploadArea--noEvents * {
- pointer-events: none;
-}
-
-.btn--file {
- background-color: #737373;
-}
-
-.btn--file:hover {
- background-color: #636363;
-}
-
-.btn--hidden {
- display: none;
-}
-
-.inputFile {
- display: none;
-}
-
-.inputFile--focused + .btn--file {
- background-color: var(--primaryControlHoverColor);
- outline: 1px dotted #000;
- outline: -webkit-focus-ring-color auto 5px;
-}
-
-.uploadArea > .uploadedFiles {
- position: absolute;
- top: 0;
- left: 0;
- flex: none;
- width: 100%;
- border: none;
- z-index: 1;
-}
-
-.uploadOptions {
- text-align: left;
- font-size: 13px;
- color: var(--lightTextColor);
-}
-
-.uploadOptions--faded {
- opacity: 0.5;
- pointer-events: none;
-}
-
-.uploadCancel {
- margin: 6px 0 0;
-}
-
-.uploadCancel:hover {
- text-decoration: underline;
-}
diff --git a/app/pasteManager.js b/app/pasteManager.js
index 33b180b4..cdde7a81 100644
--- a/app/pasteManager.js
+++ b/app/pasteManager.js
@@ -7,6 +7,7 @@ function getString(item) {
export default function(state, emitter) {
window.addEventListener('paste', async event => {
if (state.route !== '/' || state.uploading) return;
+ if (event.target.type === 'password') return;
const items = Array.from(event.clipboardData.items);
const transferFiles = items.filter(item => item.kind === 'file');
diff --git a/app/routes.js b/app/routes.js
new file mode 100644
index 00000000..b2619599
--- /dev/null
+++ b/app/routes.js
@@ -0,0 +1,53 @@
+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');
+
+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`
+ ${banner(state, emit)}
+ ${header(state, emit)}
+ ${main(state, emit)}
+ ${footer(state)}
+ `;
+ if (state.layout) {
+ // server side only
+ return state.layout(state, b);
+ }
+ return b;
+ };
+}
+
+module.exports = function() {
+ const app = choo();
+ app.route('/', body(require('./ui/home')));
+ app.route('/download/:id', body(download));
+ app.route('/download/:id/:key', body(download));
+ app.route('/unsupported/:reason', body(require('./ui/unsupported')));
+ app.route('/legal', body(require('./ui/legal')));
+ app.route('/error', body(require('./ui/error')));
+ app.route('/blank', body(require('./ui/blank')));
+ app.route('/oauth', async function(state, emit) {
+ try {
+ await state.user.finishLogin(state.query.code, state.query.state);
+ emit('replaceState', '/');
+ } catch (e) {
+ emit('replaceState', '/error');
+ setTimeout(() => emit('render'));
+ }
+ });
+ app.route('*', body(require('./ui/notFound')));
+ return app;
+};
diff --git a/app/routes/download.js b/app/routes/download.js
deleted file mode 100644
index 722a6b45..00000000
--- a/app/routes/download.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/* global downloadMetadata */
-const preview = require('../pages/preview');
-const password = require('../pages/password');
-
-function createFileInfo(state) {
- return {
- id: state.params.id,
- secretKey: state.params.key,
- nonce: downloadMetadata.nonce,
- requiresPassword: downloadMetadata.pwd
- };
-}
-
-module.exports = function(state, emit) {
- if (!state.fileInfo) {
- state.fileInfo = createFileInfo(state);
- }
-
- if (!state.transfer && !state.fileInfo.requiresPassword) {
- emit('getMetadata');
- }
-
- if (state.transfer) {
- return preview(state, emit);
- }
-
- if (state.fileInfo.requiresPassword && !state.fileInfo.password) {
- return password(state, emit);
- }
-};
diff --git a/app/routes/index.js b/app/routes/index.js
deleted file mode 100644
index 180f8ca3..00000000
--- a/app/routes/index.js
+++ /dev/null
@@ -1,91 +0,0 @@
-const choo = require('choo');
-const html = require('choo/html');
-const nanotiming = require('nanotiming');
-const download = require('./download');
-const footer = require('../templates/footer');
-const fxPromo = require('../templates/fxPromo');
-const signupPromo = require('../templates/signupPromo');
-const fileList = require('../templates/fileList');
-const profile = require('../templates/userAccount');
-const modal = require('../templates/modal');
-
-nanotiming.disabled = true;
-
-module.exports = function() {
- const app = choo();
-
- function banner(state, emit) {
- if (state.promo && !state.route.startsWith('/unsupported/')) {
- return fxPromo(state, emit);
- }
- }
-
- function modalDialog(state, emit) {
- if (state.modal) {
- return modal(state, emit);
- }
- }
-
- function body(template) {
- return function(state, emit) {
- const b = html`
- ${modalDialog(state, emit)}
- ${banner(state, emit)}
-
-
- ${signupPromo(state)}
-
-
-
- ${profile(state, emit)}
-
- ${template(state, emit)}
-
-
-
-
-
- ${fileList(state)}
-
-
- ${footer(state)}
- `;
- if (state.layout) {
- // server side only
- return state.layout(state, b);
- }
- return b;
- };
- }
-
- app.route('/', body(require('../pages/welcome')));
- app.route('/share/:id', body(require('../pages/share')));
- app.route('/download/:id', body(download));
- app.route('/download/:id/:key', body(download));
- app.route('/unsupported/:reason', body(require('../pages/unsupported')));
- app.route('/legal', body(require('../pages/legal')));
- app.route('/error', body(require('../pages/error')));
- app.route('/blank', body(require('../pages/blank')));
- app.route('/signin', body(require('../pages/signin')));
- app.route('/oauth', async function(state, emit) {
- try {
- await state.user.finishLogin(state.query.code, state.query.state);
- emit('replaceState', '/');
- } catch (e) {
- emit('replaceState', '/error');
- setTimeout(() => emit('render'));
- }
- });
- app.route('*', body(require('../pages/notFound')));
- return app;
-};
diff --git a/app/templates/downloadButton/downloadButton.css b/app/templates/downloadButton/downloadButton.css
deleted file mode 100644
index 821bcf18..00000000
--- a/app/templates/downloadButton/downloadButton.css
+++ /dev/null
@@ -1,20 +0,0 @@
-.btn--download {
- margin: 0 0 13px;
-}
-
-.btn--complete,
-.btn--complete:hover {
- background-color: var(--successControlBGColor);
-}
-
-.btn--blueStripes {
- background: repeating-linear-gradient(
- -65deg,
- #3282f2 0,
- #3282f2 17px,
- #3c87eb 17px,
- #3c87eb 30px
- );
- background-size: 300% 300%;
- animation: barberpole 12s linear infinite;
-}
diff --git a/app/templates/downloadButton/index.js b/app/templates/downloadButton/index.js
deleted file mode 100644
index fd020cb6..00000000
--- a/app/templates/downloadButton/index.js
+++ /dev/null
@@ -1,37 +0,0 @@
-const html = require('choo/html');
-const percent = require('../../utils').percent;
-
-module.exports = function(state, emit) {
- const downloadState = state.transfer.state;
- const progress = percent(state.transfer.progressRatio);
-
- let btnText = '';
- let btnClass = '';
-
- if (downloadState === 'complete') {
- btnText = state.translate('downloadFinish');
- btnClass = 'btn--complete';
- } else if (downloadState === 'decrypting') {
- btnText = state.translate('decryptingFile');
- btnClass = 'btn--blueStripes';
- } else if (downloadState === 'downloading') {
- btnText = state.translate('downloadProgressButton', { progress });
- btnClass = 'btn--blueStripes';
- } else {
- btnText = state.translate('downloadButtonLabel');
- }
-
- return html`
- `;
-
- function download(event) {
- event.preventDefault();
- event.target.disabled = true;
- if (downloadState === 'ready') {
- emit('download', state.fileInfo);
- }
- }
-};
diff --git a/app/templates/downloadPassword/downloadPassword.css b/app/templates/downloadPassword/downloadPassword.css
deleted file mode 100644
index fd07616d..00000000
--- a/app/templates/downloadPassword/downloadPassword.css
+++ /dev/null
@@ -1,31 +0,0 @@
-.passwordSection {
- margin: auto;
- text-align: center;
- padding: 40px 0;
- width: 80%;
-}
-
-.passwordForm {
- margin: 13px;
-}
-
-.passwordForm__input {
- width: 100%;
- height: 40px;
- box-sizing: border-box;
-}
-
-.unlockBtn {
- margin-top: 48px;
-}
-
-.unlockBtn--error,
-.unlockBtn--error:hover {
- background-color: var(--errorColor);
-}
-
-.passwordForm__error {
- font-size: 13px;
- font-weight: 600;
- visibility: hidden;
-}
diff --git a/app/templates/downloadPassword/index.js b/app/templates/downloadPassword/index.js
deleted file mode 100644
index a4f74002..00000000
--- a/app/templates/downloadPassword/index.js
+++ /dev/null
@@ -1,60 +0,0 @@
-const html = require('choo/html');
-
-module.exports = function(state, emit) {
- const fileInfo = state.fileInfo;
- const invalid = fileInfo.password === null;
-
- const visible = invalid ? 'visible' : '';
- const invalidBtn = invalid ? 'unlockBtn--error' : '';
-
- const div = html`
-
-
-
-
-
-
`;
-
- if (!(div instanceof String)) {
- setTimeout(() => document.getElementById('password-input').focus());
- }
-
- function inputChanged() {
- const input = document.querySelector('.passwordForm__error');
- input.classList.remove('visible');
- const btn = document.getElementById('password-btn');
- btn.classList.remove('unlockBtn--error');
- }
-
- function checkPassword(event) {
- event.preventDefault();
- const password = document.getElementById('password-input').value;
- if (password.length > 0) {
- document.getElementById('password-btn').disabled = true;
- state.fileInfo.url = window.location.href;
- state.fileInfo.password = password;
- emit('getMetadata');
- }
- return false;
- }
-
- return div;
-};
diff --git a/app/templates/file/file.css b/app/templates/file/file.css
deleted file mode 100644
index 67e436a0..00000000
--- a/app/templates/file/file.css
+++ /dev/null
@@ -1,100 +0,0 @@
-.fileToast {
- flex: none;
- display: block;
- margin: 6px 0 0;
- overflow: hidden;
- font-size: 11px;
- line-height: 18px;
- color: var(--lightTextColor);
- background-color: var(--pageBGColor);
- position: relative;
- border: 3px solid rgba(12, 12, 12, 0.2);
- background-clip: padding-box;
- box-sizing: border-box;
- height: 53px;
- border-radius: 4px;
-}
-
-.fileToast__content {
- height: 100%;
- position: relative;
- z-index: 2;
-}
-
-.fileToast::after {
- position: absolute;
- z-index: 1;
- content: '';
- transition: all 0.25s;
- top: 0;
- left: 50%;
- width: 0;
- height: 100%;
- background-color: var(--primaryControlBGColor);
-}
-
-.fileToast:hover {
- background-color: #eee;
-}
-
-.fileToast--active {
- color: var(--primaryControlFGColor);
-}
-
-.fileToast--active::after {
- left: 0%;
- width: 100%;
-}
-
-.fileData {
- margin: 8px 16px 8px 44px;
- overflow: hidden;
-}
-
-.fileName {
- margin: 0;
- font-size: 13px;
- font-weight: 500;
- white-space: nowrap;
- text-overflow: ellipsis;
- overflow: hidden;
-}
-
-.fileInfo {
- margin: 0;
-}
-
-.fileToast .fileIcon {
- margin: 0 8px;
-}
-
-@media (max-device-width: 750px), (max-width: 750px) {
- .fileToast {
- height: 32px;
- }
-
- .fileToast__content {
- display: flex;
- line-height: 13px;
- margin: 0;
- align-items: center;
- }
-
- .fileData {
- flex: auto;
- display: flex;
- flex-wrap: nowrap;
- margin: 0 6px 0 0;
- }
-
- .fileInfo {
- flex: none;
- margin-left: auto;
- }
-
- .fileToast .fileIcon {
- flex: none;
- transform: scale(0.5);
- color: transparent;
- }
-}
diff --git a/app/templates/file/index.js b/app/templates/file/index.js
deleted file mode 100644
index b0221a42..00000000
--- a/app/templates/file/index.js
+++ /dev/null
@@ -1,74 +0,0 @@
-const html = require('choo/html');
-const number = require('../../utils').number;
-const bytes = require('../../utils').bytes;
-const fileIcon = require('../fileIcon');
-
-module.exports = function(file, state) {
- const ttl = file.expiresAt - Date.now();
- const remainingTime =
- timeLeft(ttl, state) || state.translate('linkExpiredAlt');
- const downloadLimit = file.dlimit || 1;
- const totalDownloads = file.dtotal || 0;
-
- const multiFiles = file.manifest.files;
- const fileName =
- multiFiles.length > 1
- ? `${multiFiles[0].name} + ${state.translate('fileCount', {
- num: multiFiles.length - 1
- })}`
- : file.name;
-
- const activeClass = isOnSharePage() ? 'fileToast--active' : '';
- return html`
-
-
-
- ${fileIcon(file.name, file._hasPassword)}
-
-
${fileName}
-
- ${bytes(file.size)} ·
- ${state.translate('downloadCount', {
- num: `${number(totalDownloads)} / ${number(downloadLimit)}`
- })}
- ${remainingTime}
-
-
-
-
-
- `;
-
- function toastClick() {
- return isOnSharePage() ? '/' : `/share/${file.id}`;
- }
-
- function isOnSharePage() {
- return state.href.includes('/share/') && state.params.id === file.id;
- }
-};
-
-function timeLeft(milliseconds, state) {
- const minutes = Math.floor(milliseconds / 1000 / 60);
- const hours = Math.floor(minutes / 60);
- const days = Math.floor(hours / 24);
- if (days >= 1) {
- return state.translate('expiresDaysHoursMinutes', {
- days,
- hours: hours % 24,
- minutes: minutes % 60
- });
- }
- if (hours >= 1) {
- return state.translate('expiresHoursMinutes', {
- hours,
- minutes: minutes % 60
- });
- } else if (hours === 0) {
- if (minutes === 0) {
- return state.translate('expiresMinutes', { minutes: '< 1' });
- }
- return state.translate('expiresMinutes', { minutes });
- }
- return null;
-}
diff --git a/app/templates/fileIcon/fileIcon.css b/app/templates/fileIcon/fileIcon.css
deleted file mode 100644
index ac87674d..00000000
--- a/app/templates/fileIcon/fileIcon.css
+++ /dev/null
@@ -1,30 +0,0 @@
-.fileIcon {
- position: relative;
- float: left;
- pointer-events: none;
- margin: 8px;
- color: #fff;
- background-image: url('../assets/red_file.svg');
- width: 22px;
- height: 32px;
- overflow: hidden;
- user-select: none;
-}
-
-.fileIcon__lock {
- margin: 7px 0 0 5px;
- visibility: hidden;
-}
-
-.fileIcon__lock--visible {
- visibility: visible;
-}
-
-.fileIcon__fileType {
- position: absolute;
- margin: 16px 0 0 2px;
- font-size: 7px;
- font-weight: 600;
- text-transform: uppercase;
- user-select: none;
-}
diff --git a/app/templates/fileIcon/index.js b/app/templates/fileIcon/index.js
deleted file mode 100644
index 2ce9e110..00000000
--- a/app/templates/fileIcon/index.js
+++ /dev/null
@@ -1,17 +0,0 @@
-const html = require('choo/html');
-const assets = require('../../../common/assets');
-
-module.exports = function(name, hasPassword) {
- let type = '';
- if (name) {
- type = name.split('.').pop();
- }
- const lockClass = hasPassword ? 'fileIcon__lock--visible' : '';
- return html`
-
-
${type}
-
})
-
`;
-};
diff --git a/app/templates/fileList/fileList.css b/app/templates/fileList/fileList.css
deleted file mode 100644
index 787f9c31..00000000
--- a/app/templates/fileList/fileList.css
+++ /dev/null
@@ -1,28 +0,0 @@
-.fileList {
- margin: 0;
- padding: 0;
- width: 262px;
- min-height: 100%;
- height: 100%;
- flex-grow: 1;
- display: flex;
- flex-direction: column;
- list-style-type: none;
- overflow: scroll;
- font-family: 'Segoe UI', 'SF Pro Text', sans-serif;
-}
-
-/* hack because justify-content:flex-end and overflow:scroll doesn't work together */
-.fileList > :first-child {
- margin-top: auto;
-}
-
-@media (max-device-width: 750px), (max-width: 750px) {
- .fileList {
- flex: none;
- position: static;
- width: 406px;
- max-height: 160px;
- margin: 0;
- }
-}
diff --git a/app/templates/fileList/index.js b/app/templates/fileList/index.js
deleted file mode 100644
index 55229f5f..00000000
--- a/app/templates/fileList/index.js
+++ /dev/null
@@ -1,12 +0,0 @@
-const html = require('choo/html');
-const file = require('../file');
-
-module.exports = function(state) {
- if (state.storage.files.length) {
- return html`
-
- ${state.storage.files.map(f => file(f, state))}
-
- `;
- }
-};
diff --git a/app/templates/footer/footer.css b/app/templates/footer/footer.css
deleted file mode 100644
index 9a0262a7..00000000
--- a/app/templates/footer/footer.css
+++ /dev/null
@@ -1,134 +0,0 @@
-.footer {
- bottom: 0;
- left: 0;
- font-size: 13px;
- font-weight: 600;
- display: flex;
- flex-direction: row;
- padding: 50px 31px 41px;
- width: 100%;
- box-sizing: border-box;
- justify-content: flex-end;
- align-items: flex-end;
-}
-
-.legalSection {
- display: flex;
- align-items: center;
- flex-direction: row;
-}
-
-.legalSection__link {
- color: var(--lightTextColor);
- white-space: nowrap;
- margin-right: 2vw;
-}
-
-.legalSection__link:hover {
- color: var(--textColor);
-}
-
-.footer__mozLogo {
- width: 112px;
- height: 32px;
- margin-bottom: -5px;
-}
-
-.socialSection__icon {
- width: 32px;
- height: 32px;
- margin: 0 0 -5px 4px;
-}
-
-.feedback {
- background-color: #000;
- background-image: url('../assets/feedback.svg');
- background-position: 2px 4px;
- background-repeat: no-repeat;
- background-size: 18px;
- border-radius: 3px;
- border: 1px solid #000;
- color: var(--primaryControlFGColor);
- cursor: pointer;
- display: block;
- font-size: 12px;
- line-height: 12px;
- padding: 5px 5px 5px 20px;
- overflow: hidden;
- min-width: 30px;
- max-width: 300px;
- text-indent: 2px;
- transition: all 250ms ease-in-out;
- white-space: nowrap;
-}
-
-.feedback:active {
- background-color: var(--primaryControlHoverColor);
-}
-
-.dropDownArrow {
- display: none;
-}
-
-.dropdown__only {
- display: none;
-}
-
-@media (max-device-width: 750px), (max-width: 750px) {
- .footer {
- align-items: flex-end;
- padding: 20px 25px;
- margin: 0;
- min-width: 455px;
- }
-
- .footer_hiddenIcon {
- display: none;
- }
-
- .dropdown__only {
- display: block;
- }
-
- .dropDownArrow {
- display: initial;
- float: right;
- }
-
- .legalSection {
- flex: 0;
- background-color: #fff;
- display: block;
- border-radius: 4px;
- border: 1px solid rgba(12, 12, 13, 0.1);
- box-sizing: border-box;
- text-align: left;
- margin-right: auto;
- }
-
- .legalSection__link {
- flex: none;
- display: block;
- box-sizing: border-box;
- height: 24px;
- width: 176px;
- margin: 0;
- padding: 4px 20px 0 8px;
- text-shadow: none;
- font-weight: 400;
- color: var(--lightTextColor);
- }
-
- .legalSection__link:visited {
- color: var(--lightTextColor);
- }
-
- .legalSection__link:hover {
- color: var(--primaryControlFGColor);
- background-color: var(--primaryControlBGColor);
- }
-
- .footer__noDisplay {
- display: none;
- }
-}
diff --git a/app/templates/footer/index.js b/app/templates/footer/index.js
deleted file mode 100644
index 281010f4..00000000
--- a/app/templates/footer/index.js
+++ /dev/null
@@ -1,109 +0,0 @@
-const html = require('choo/html');
-const version = require('../../../package.json').version;
-const assets = require('../../../common/assets');
-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``;
- // 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;
-
- function showDropDown() {
- const menus = document.querySelectorAll('.footer__dropdown');
- menus.forEach(element => {
- element.classList.remove('footer__noDisplay');
- });
- }
-
- function hideDropDown() {
- const menus = document.querySelectorAll('.footer__dropdown');
- menus.forEach(element => {
- element.classList.add('footer__noDisplay');
- });
- }
-};
diff --git a/app/templates/fxPromo/fxPromo.css b/app/templates/fxPromo/fxPromo.css
deleted file mode 100644
index c1582fcc..00000000
--- a/app/templates/fxPromo/fxPromo.css
+++ /dev/null
@@ -1,57 +0,0 @@
-.fxPromo {
- flex: none;
- padding: 0 15px;
- height: 48px;
- background-color: #efeff1;
- color: #4a4a4f;
- font-size: 13px;
- display: flex;
- flex-direction: row;
- align-content: center;
- align-items: center;
- justify-content: center;
-}
-
-.fxPromo > div {
- display: flex;
- align-items: center;
- margin: 0 auto;
-}
-
-.fxPromo > div > span {
- margin-left: 10px;
-}
-
-.fxPromo__logo {
- width: 24px;
-}
-
-.fxPromo--blue {
- background: linear-gradient(-180deg, #45a1ff 0%, #00feff 94%);
- color: #fff;
-}
-
-.fxPromo--pink {
- background: linear-gradient(-180deg, #ff9400 0%, #ff1ad9 94%);
- color: #fff;
-}
-
-.fxPromo--blue a {
- color: #fff;
- font-weight: bold;
-}
-
-.fxPromo--pink a {
- color: #fff;
- font-weight: bold;
-}
-
-.fxPromo--blue a:hover {
- color: #eee;
- font-weight: bold;
-}
-
-.fxPromo--pink a:hover {
- color: #eee;
- font-weight: bold;
-}
diff --git a/app/templates/fxPromo/index.js b/app/templates/fxPromo/index.js
deleted file mode 100644
index 1b0532d5..00000000
--- a/app/templates/fxPromo/index.js
+++ /dev/null
@@ -1,34 +0,0 @@
-const html = require('choo/html');
-const assets = require('../../../common/assets');
-
-module.exports = function(state, emit) {
- let classes = 'fxPromo';
- switch (state.promo) {
- case 'blue':
- classes = 'fxPromo fxPromo--blue';
- break;
- case 'pink':
- classes = 'fxPromo fxPromo--pink';
- break;
- }
-
- return html`
- `;
-
- function clicked() {
- emit('experiment', { cd3: 'promo' });
- }
-};
diff --git a/app/templates/header/header.css b/app/templates/header/header.css
deleted file mode 100644
index 7b7db949..00000000
--- a/app/templates/header/header.css
+++ /dev/null
@@ -1,9 +0,0 @@
-.header {
- align-items: flex-start;
- box-sizing: border-box;
- display: flex;
- justify-content: space-between;
- height: 32px;
- padding: 10px;
- width: 100%;
-}
diff --git a/app/templates/header/index.js b/app/templates/header/index.js
deleted file mode 100644
index be296ffe..00000000
--- a/app/templates/header/index.js
+++ /dev/null
@@ -1,14 +0,0 @@
-const html = require('choo/html');
-
-module.exports = function() {
- const header = html`
- `;
- // 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;
-};
diff --git a/app/templates/modal/index.js b/app/templates/modal/index.js
deleted file mode 100644
index 005824bc..00000000
--- a/app/templates/modal/index.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const html = require('choo/html');
-
-module.exports = function(state, emit) {
- return html`
-
-
e.stopPropagation()}>
- ${state.modal(state, emit, close)}
-
-
`;
-
- function close(event) {
- state.modal = null;
- emit('render');
- }
-};
diff --git a/app/templates/modal/modal.css b/app/templates/modal/modal.css
deleted file mode 100644
index ae1608a1..00000000
--- a/app/templates/modal/modal.css
+++ /dev/null
@@ -1,21 +0,0 @@
-.modal {
- display: flex;
- justify-content: center;
- align-items: center;
- position: fixed;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- overflow: hidden;
- z-index: 100;
- background: rgba(0, 0, 0, 0.7);
- animation: fade-in 0.5s forwards;
-}
-
-.modal__box {
- max-width: 480px;
- background: var(--pageBGColor);
- border-radius: 4px;
- color: var(--textColor);
-}
diff --git a/app/templates/okDialog/index.js b/app/templates/okDialog/index.js
deleted file mode 100644
index 4986c1b9..00000000
--- a/app/templates/okDialog/index.js
+++ /dev/null
@@ -1,13 +0,0 @@
-const html = require('choo/html');
-
-module.exports = function(message) {
- return function(state, emit, close) {
- return html`
-
-
${message}
-
-
`;
- };
-};
diff --git a/app/templates/okDialog/okDialog.css b/app/templates/okDialog/okDialog.css
deleted file mode 100644
index 5b04d83b..00000000
--- a/app/templates/okDialog/okDialog.css
+++ /dev/null
@@ -1,11 +0,0 @@
-.okDialog {
- display: flex;
- flex-direction: column;
- max-width: 400px;
- padding: 16px;
-}
-
-.okDialog__message {
- margin: 32px;
- text-align: center;
-}
diff --git a/app/templates/passwordInput/index.js b/app/templates/passwordInput/index.js
deleted file mode 100644
index a1b9c01c..00000000
--- a/app/templates/passwordInput/index.js
+++ /dev/null
@@ -1,50 +0,0 @@
-const html = require('choo/html');
-
-module.exports = function(state) {
- const placeholder =
- state.route === '/' ? '' : state.translate('unlockInputPlaceholder');
- const hasPassword = !!state.password;
- const sectionClass = hasPassword
- ? 'passwordInput'
- : 'passwordInput passwordInput--hidden';
-
- return html`
-
-
-
`;
-
- function onSubmit() {
- event.preventDefault();
- }
-
- function inputChanged() {
- const password = document.getElementById('password-input').value;
- state.password = password;
- }
-
- function focused(event) {
- event.preventDefault();
- const el = document.getElementById('password-input');
- if (el.placeholder !== state.translate('unlockInputPlaceholder')) {
- el.placeholder = '';
- }
- }
-};
-
-function passwordPlaceholder(password) {
- return password ? password.replace(/./g, '•') : '••••••••••••';
-}
diff --git a/app/templates/passwordInput/passwordInput.css b/app/templates/passwordInput/passwordInput.css
deleted file mode 100644
index ccfab210..00000000
--- a/app/templates/passwordInput/passwordInput.css
+++ /dev/null
@@ -1,31 +0,0 @@
-.passwordInput {
- display: inline;
-}
-
-.passwordInput--hidden {
- visibility: hidden;
-}
-
-.passwordInput__fill {
- height: 24px;
- box-sizing: border-box;
- padding: 4px;
- font-size: 18px;
- border: none;
- background-color: var(--lightControlBGColor);
- outline: none;
-}
-
-.passwordInput__fill:focus {
- border: 1px solid rgba(12, 12, 13, 0.2);
- background-color: var(--pageBGColor);
-}
-
-.passwordInput__msg {
- font-size: 12px;
- color: var(--lightTextColor);
-}
-
-.passwordInput__msg--error {
- color: var(--errorColor);
-}
diff --git a/app/templates/popup/index.js b/app/templates/popup/index.js
deleted file mode 100644
index cdf65a89..00000000
--- a/app/templates/popup/index.js
+++ /dev/null
@@ -1,24 +0,0 @@
-const html = require('choo/html');
-
-module.exports = function(msg, confirmText, cancelText, confirmCallback) {
- return html`
- `;
-
- function hide(e) {
- e.stopPropagation();
- const popup = document.querySelector('.popup.popup--show');
- if (popup) {
- popup.classList.remove('popup--show');
- }
- }
-};
diff --git a/app/templates/popup/popup.css b/app/templates/popup/popup.css
deleted file mode 100644
index 548aedb6..00000000
--- a/app/templates/popup/popup.css
+++ /dev/null
@@ -1,79 +0,0 @@
-.popup {
- display: block;
- width: 100%;
- height: 70px;
- background-color: var(--errorColor);
- color: var(--textColor);
- padding: 0;
- box-sizing: border-box;
- text-align: center;
- border-radius: 4px;
- transition: opacity 0.5s;
- outline: 0;
- opacity: 0;
- visibility: hidden;
-}
-
-.popup::after {
- content: '';
- position: absolute;
- top: 100%;
- left: 50%;
- width: 0;
- height: 0;
- border: 8px solid;
- border-color: var(--errorColor) transparent transparent;
- margin-left: -8px;
- pointer-events: none;
-}
-
-.popup__message {
- height: 40px;
- padding: 10px;
- box-sizing: border-box;
- text-align: center;
- color: var(--primaryControlFGColor);
- font-size: 15px;
- font-style: italic;
- white-space: nowrap;
-}
-
-.popup__action {
- display: flex;
- flex-direction: row;
- text-transform: uppercase;
-}
-
-.popup__action > div {
- flex: auto;
-}
-
-.popup__no {
- color: var(--primaryControlFGColor);
- padding: 5px;
- font-weight: bold;
- cursor: pointer;
- white-space: nowrap;
-}
-
-.popup__no:hover {
- text-decoration: underline;
-}
-
-.popup__yes {
- color: var(--primaryControlFGColor);
- padding: 5px;
- font-weight: normal;
- cursor: pointer;
- white-space: nowrap;
-}
-
-.popup__yes:hover {
- text-decoration: underline;
-}
-
-.popup--show {
- visibility: visible;
- opacity: 1;
- pointer-events: auto;
-}
diff --git a/app/templates/selectbox/selectbox.css b/app/templates/selectbox/selectbox.css
deleted file mode 100644
index fcbb196b..00000000
--- a/app/templates/selectbox/selectbox.css
+++ /dev/null
@@ -1,22 +0,0 @@
-option {
- padding: 0;
-}
-
-.selectBox {
- appearance: none;
- outline: 0;
- box-shadow: none;
- border: none;
- border-radius: 0;
- background-color: #e6e6e6;
- font-size: 1em;
- font-weight: 200;
- margin: 0;
- padding: 4px 2px 4px 2px;
- cursor: pointer;
-}
-
-select:active {
- background-color: var(--pageBGColor);
- border: 0;
-}
diff --git a/app/templates/setPasswordSection/index.js b/app/templates/setPasswordSection/index.js
deleted file mode 100644
index 8fad4337..00000000
--- a/app/templates/setPasswordSection/index.js
+++ /dev/null
@@ -1,42 +0,0 @@
-const html = require('choo/html');
-const passwordInput = require('../passwordInput');
-
-module.exports = function(state) {
- const checked = state.password ? 'checked' : '';
- const label = state.password ? 'addPasswordLabel' : 'addPasswordMessage';
-
- return html`
-
-
-
-
-
-
- ${passwordInput(state)}
-
-
`;
-
- function togglePasswordInput(e) {
- const unlockInput = document.getElementById('password-input');
- const boxChecked = e.target.checked;
- document
- .querySelector('.passwordInput')
- .classList.toggle('passwordInput--hidden', !boxChecked);
-
- const label = document.querySelector('.checkbox__label');
- if (boxChecked) {
- label.innerHTML = state.translate('addPasswordLabel');
- unlockInput.focus();
- } else {
- label.innerHTML = state.translate('addPasswordMessage');
- unlockInput.value = '';
- }
- }
-};
diff --git a/app/templates/setPasswordSection/setPasswordSection.css b/app/templates/setPasswordSection/setPasswordSection.css
deleted file mode 100644
index 28233cfe..00000000
--- a/app/templates/setPasswordSection/setPasswordSection.css
+++ /dev/null
@@ -1,58 +0,0 @@
-.setPasswordSection {
- display: flex;
- padding: 10px 0;
- max-width: 100%;
-}
-
-.checkbox {
- flex: auto;
- height: 24px;
-}
-
-.checkbox__input {
- position: absolute;
- opacity: 0;
-}
-
-.checkbox__label {
- font-size: 13px;
- line-height: 20px;
- cursor: pointer;
- color: var(--lightTextColor);
- user-select: none;
-}
-
-.checkbox__label::before {
- content: '';
- height: 24px;
- width: 24px;
- margin-right: 10px;
- float: left;
- background-color: #e6e6e6;
-}
-
-.checkbox__label:hover::before {
- background-color: #d6d6d6;
-}
-
-.checkbox__input:checked + .checkbox__label::before {
- background-image: url('../assets/lock.svg');
- background-position: 2px 2px;
- background-repeat: no-repeat;
-}
-
-.checkbox__input:disabled + .checkbox__label {
- cursor: auto;
-}
-
-.checkbox__input:disabled + .checkbox__label::before {
- background-image: url('../assets/lock.svg');
- background-repeat: no-repeat;
- background-size: 26px 26px;
- border: none;
- cursor: auto;
-}
-
-.setPasswordSection > .passwordInput--hidden {
- display: none;
-}
diff --git a/app/templates/signupDialog/signupDialog.css b/app/templates/signupDialog/signupDialog.css
deleted file mode 100644
index 018dbcad..00000000
--- a/app/templates/signupDialog/signupDialog.css
+++ /dev/null
@@ -1,22 +0,0 @@
-.signupDialog {
- display: flex;
- flex-direction: column;
- max-width: 400px;
- padding: 16px;
-}
-
-.signupDialog__message {
- margin: 32px 32px 0 32px;
-}
-
-.signupDialog__emailInput {
- box-sizing: border-box;
- height: 40px;
- width: 100%;
- border: 1px solid rgba(0, 0, 0, 0.2);
- border-radius: 4px;
- margin: 16px 0;
- padding: 0 8px;
- font-size: 18px;
- color: var(--lightTextColor);
-}
diff --git a/app/templates/signupPromo/index.js b/app/templates/signupPromo/index.js
deleted file mode 100644
index 20122946..00000000
--- a/app/templates/signupPromo/index.js
+++ /dev/null
@@ -1,16 +0,0 @@
-const html = require('choo/html');
-
-module.exports = function(state) {
- if (state.user.loggedIn || !state.capabilities.account) {
- return null;
- }
- return html`
-
- ${state.translate('signInPromoText')}
- ${state.translate('signInExplanation')}
- ${state.translate(
- 'signInLearnMore'
- )}
-
- `;
-};
diff --git a/app/templates/signupPromo/signupPromo.css b/app/templates/signupPromo/signupPromo.css
deleted file mode 100644
index 231736db..00000000
--- a/app/templates/signupPromo/signupPromo.css
+++ /dev/null
@@ -1,85 +0,0 @@
-.signupPromo {
- display: flex;
- flex-direction: column;
- position: absolute;
- right: 0;
- height: 140px;
- width: 150px;
- background: #ffe900;
- font-size: 13px;
- font-weight: 500;
- text-align: center;
- justify-content: center;
-}
-
-.signupPromo::before {
- content: '';
- width: 0;
- height: 0;
- border-style: solid;
- border-width: 0 35px 140px 0;
- border-color: transparent #ffe900 transparent;
- position: absolute;
- right: 100%;
-}
-
-.signupPromo::after {
- content: '';
- width: 0;
- height: 0;
- border-style: solid;
- border-width: 0 150px 35px 0;
- border-color: transparent #ffe900 transparent;
- position: absolute;
- top: 100%;
- left: 0%;
-}
-
-.signupPromo__title {
- color: #0a84ff;
- font-size: 22px;
- font-style: italic;
- font-weight: 600;
- padding: 6px;
-}
-
-.signupPromo__info {
- color: var(--lightTextColor);
- padding: 6px;
-}
-
-.signupPromo__link {
- z-index: 5;
-}
-
-.signupPromo__link:hover {
- text-decoration: underline;
-}
-
-@media (max-device-width: 700px), (max-width: 700px) {
- .signupPromo {
- flex-direction: row;
- align-items: center;
- height: 40px;
- width: 100%;
- }
-
- .signupPromo::before {
- visibility: hidden;
- }
-
- .signupPromo::after {
- border-width: 15px 50vw 0 50vw;
- border-color: #ffe900 transparent transparent;
- }
-}
-
-@media (max-device-width: 500px), (max-width: 500px) {
- .signupPromo__link {
- display: none;
- }
-
- .signupPromo {
- overflow: hidden;
- }
-}
diff --git a/app/templates/timeLimitText/index.js b/app/templates/timeLimitText/index.js
deleted file mode 100644
index 3de88db5..00000000
--- a/app/templates/timeLimitText/index.js
+++ /dev/null
@@ -1,14 +0,0 @@
-module.exports = function(translate, seconds) {
- const displayText = {
- 300: translate('timespanMinutes', { num: 5 }),
- 3600: translate('timespanHours', { num: 1 }),
- 86400: translate('timespanHours', { num: 24 }),
- 604800: translate('timespanWeeks', { num: 1 }),
- 1209600: translate('timespanWeeks', { num: 2 })
- };
-
- if (displayText[seconds]) {
- return displayText[seconds];
- }
- return seconds;
-};
diff --git a/app/templates/title/index.js b/app/templates/title/index.js
deleted file mode 100644
index 6e0b0e01..00000000
--- a/app/templates/title/index.js
+++ /dev/null
@@ -1,11 +0,0 @@
-const html = require('choo/html');
-
-module.exports = function(state) {
- return html`
-
- ${state.translate('uploadPageHeader')}
-
- ${state.translate('pageHeaderCredits')}
-
-
`;
-};
diff --git a/app/templates/title/title.css b/app/templates/title/title.css
deleted file mode 100644
index 8b0c90a7..00000000
--- a/app/templates/title/title.css
+++ /dev/null
@@ -1,14 +0,0 @@
-.boxTitle {
- font-size: 15px;
- text-align: center;
- font-weight: 500;
- margin: 9px 0 19px 0;
- padding: 0 42px;
- color: var(--lightTextColor);
-}
-
-.boxSubtitle {
- font-size: 12px;
- font-weight: 300;
- font-style: italic;
-}
diff --git a/app/templates/uploadedFile/index.js b/app/templates/uploadedFile/index.js
deleted file mode 100644
index 40c8345d..00000000
--- a/app/templates/uploadedFile/index.js
+++ /dev/null
@@ -1,51 +0,0 @@
-const html = require('choo/html');
-const assets = require('../../../common/assets');
-const bytes = require('../../utils').bytes;
-const fileIcon = require('../fileIcon');
-
-module.exports = function(file, index, state, emit, hasPassword) {
- const transfer = state.transfer;
- const transferState = transfer ? transfer.state : null;
- const share = state.route.includes('share/');
- const complete = share ? 'uploadedFile--completed' : '';
-
- const cancelVisible =
- state.route === '/' && !state.uploading
- ? 'uploadedFile__cancel--visible'
- : '';
-
- const stampClass =
- share || transferState === 'complete' ? 'uploadedFile__stamp--visible' : '';
-
- function cancel(event) {
- event.preventDefault();
- if (state.route === '/') {
- emit('removeUpload', { index });
- }
- }
-
- return html`
-
-
- ${fileIcon(file.name, hasPassword)}
-
-
-
})
-
-
-
-
${file.name}
-
- ${bytes(file.size)}
-
-
-
-
-
- `;
-};
diff --git a/app/templates/uploadedFile/uploadedFile.css b/app/templates/uploadedFile/uploadedFile.css
deleted file mode 100644
index f3fe4dcb..00000000
--- a/app/templates/uploadedFile/uploadedFile.css
+++ /dev/null
@@ -1,70 +0,0 @@
-.uploadedFile {
- margin: 11px;
- list-style-type: none;
- font-size: 11px;
- line-height: 18px;
- text-align: initial;
- color: var(--lightTextColor);
- background-color: var(--pageBGColor);
- border: 1px solid #cececf;
- box-sizing: border-box;
- height: 53px;
- border-radius: 4px;
- position: relative;
-}
-
-.uploadedFile--completed {
- background-color: #e8f2fe;
-}
-
-.uploadedFile__fileData {
- margin: 8px 16px 8px 44px;
-}
-
-.uploadedFile__fileName {
- margin: 0;
- font-size: 13px;
- font-weight: 500;
- white-space: nowrap;
- text-overflow: ellipsis;
- overflow: hidden;
-}
-
-.uploadedFile__fileInfo {
- margin: 0;
-}
-
-.uploadedFile__cancel {
- float: right;
- margin: 6px;
- visibility: hidden;
-}
-
-.uploadedFile:hover .uploadedFile__cancel--visible {
- visibility: visible;
-}
-
-.uploadedFile__stamp {
- position: absolute;
- top: -4px;
- right: -8px;
- visibility: hidden;
- opacity: 0;
-}
-
-.uploadedFile__stamp--visible {
- visibility: visible;
- opacity: 1;
- animation: stampDown 0.2s linear;
-}
-
-@keyframes stampDown {
- 0% {
- opacity: 0;
- transform: scale(1.5);
- }
-
- 100% {
- opacity: 1;
- }
-}
diff --git a/app/templates/uploadedFileList/index.js b/app/templates/uploadedFileList/index.js
deleted file mode 100644
index 1175af02..00000000
--- a/app/templates/uploadedFileList/index.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const html = require('choo/html');
-const file = require('../uploadedFile');
-
-module.exports = function(archive, state, emit) {
- let files = [];
- if (archive) {
- files = Array.from(archive.manifest.files);
- }
-
- return html`
-
- ${files.map((f, i) => file(f, i, state, emit, archive._hasPassword))}
-
- `;
-};
diff --git a/app/templates/uploadedFileList/uploadedFileList.css b/app/templates/uploadedFileList/uploadedFileList.css
deleted file mode 100644
index 2784a3c7..00000000
--- a/app/templates/uploadedFileList/uploadedFileList.css
+++ /dev/null
@@ -1,11 +0,0 @@
-.uploadedFiles {
- border: 1px solid rgba(12, 12, 13, 0.1);
- border-radius: 4px;
- box-sizing: border-box;
- margin: 0;
- padding: 0;
- align-content: center;
- flex: 1;
- overflow-y: scroll;
- overflow-x: hidden;
-}
diff --git a/app/templates/userAccount/index.js b/app/templates/userAccount/index.js
deleted file mode 100644
index f852bdec..00000000
--- a/app/templates/userAccount/index.js
+++ /dev/null
@@ -1,70 +0,0 @@
-const html = require('choo/html');
-
-module.exports = function(state, emit) {
- if (!state.capabilities.account) {
- return null;
- }
- const user = state.user;
- const menu = user.loggedIn
- ? html`
- `
- : html`
-
- `;
-
- return html`
-
-
-

-
- ${menu}
-
`;
-
- function avatarClick(event) {
- event.preventDefault();
- const dropdown = document.querySelector('.account_dropdown');
- dropdown.classList.toggle('visible');
- dropdown.focus();
- }
-
- function login(event) {
- event.preventDefault();
- emit('login');
- }
-
- function logout(event) {
- event.preventDefault();
- emit('logout');
- }
-
- function hideMenu(event) {
- event.stopPropagation();
- const dropdown = document.querySelector('.account_dropdown');
- dropdown.classList.remove('visible');
- }
-};
diff --git a/app/templates/userAccount/userAccount.css b/app/templates/userAccount/userAccount.css
deleted file mode 100644
index 44ae4feb..00000000
--- a/app/templates/userAccount/userAccount.css
+++ /dev/null
@@ -1,78 +0,0 @@
-.account {
- position: absolute;
- right: 0;
- margin: 0 21px;
- padding: 0;
-}
-
-.account__avatar {
- height: 32px;
- width: 32px;
- border-radius: 50%;
-}
-
-.account_dropdown {
- z-index: 2;
- position: absolute;
- top: 30px;
- left: -15px;
- min-width: 150px;
- list-style-type: none;
- border: 1px solid #ccc;
- border-radius: 4px;
- background-color: var(--pageBGColor);
- box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.2);
- padding: 11px 0;
- visibility: hidden;
- outline: 0;
-}
-
-.account_dropdown::after,
-.account_dropdown::before {
- position: absolute;
- bottom: 100%;
- left: 18px;
- height: 0;
- width: 0;
- border: 1px solid transparent;
- content: '';
- pointer-events: none;
-}
-
-.account_dropdown::after {
- border-bottom-color: var(--pageBGColor);
- border-width: 12px;
-}
-
-.account_dropdown::before {
- border-bottom-color: #ccc;
- border-width: 13px;
- margin-left: -1px;
-}
-
-.account_dropdown__link {
- display: block;
- padding: 0 14px;
- font-size: 13px;
- line-height: 24px;
- color: var(--lightTextColor);
- position: relative;
- z-index: 999;
-}
-
-.account_dropdown__link:visited {
- color: var(--lightTextColor);
-}
-
-.account_dropdown__link:hover {
- background-color: var(--primaryControlBGColor);
- color: var(--primaryControlFGColor);
-}
-
-.account_dropdown__text {
- display: block;
- padding: 0 14px;
- font-size: 13px;
- color: var(--lightTextColor);
- line-height: 24px;
-}
diff --git a/app/ui/account.js b/app/ui/account.js
new file mode 100644
index 00000000..d9f92ff6
--- /dev/null
+++ b/app/ui/account.js
@@ -0,0 +1,63 @@
+const html = require('choo/html');
+const itemClass =
+ 'block px-4 py-2 text-grey-darkest hover:bg-blue hover:text-white cursor-pointer';
+
+module.exports = function(state, emit) {
+ if (!state.capabilities.account) {
+ return null;
+ }
+ const user = state.user;
+ const menuItems = [];
+ if (user.loggedIn) {
+ menuItems.push(html`${user.email}`);
+ menuItems.push(
+ html`${state.translate(
+ 'logOut'
+ )}`
+ );
+ } else {
+ menuItems.push(
+ html`${state.translate(
+ 'signInMenuOption'
+ )}`
+ );
+ }
+ return html``;
+
+ function avatarClick(event) {
+ event.preventDefault();
+ const menu = document.getElementById('accountMenu');
+ menu.classList.toggle('invisible');
+ menu.focus();
+ }
+
+ function hideMenu(event) {
+ event.stopPropagation();
+ const menu = document.getElementById('accountMenu');
+ menu.classList.add('invisible');
+ }
+
+ function login(event) {
+ event.preventDefault();
+ emit('login');
+ }
+
+ function logout(event) {
+ event.preventDefault();
+ emit('logout');
+ }
+};
diff --git a/app/ui/archiveTile.js b/app/ui/archiveTile.js
new file mode 100644
index 00000000..4b401a39
--- /dev/null
+++ b/app/ui/archiveTile.js
@@ -0,0 +1,372 @@
+const html = require('choo/html');
+const raw = require('choo/html/raw');
+const assets = require('../../common/assets');
+const { bytes, copyToClipboard, list, percent, timeLeft } = require('../utils');
+const expiryOptions = require('./expiryOptions');
+
+function expiryInfo(translate, archive) {
+ const l10n = timeLeft(archive.expiresAt - Date.now());
+ return raw(
+ translate('frontPageExpireInfo', {
+ downloadCount: translate('downloadCount', {
+ num: archive.dlimit - archive.dtotal
+ }),
+ timespan: translate(l10n.id, l10n)
+ })
+ );
+}
+
+function password(state) {
+ const MAX_LENGTH = 32;
+
+ return html`
+ `;
+
+ function togglePasswordInput(event) {
+ event.stopPropagation();
+ const checked = event.target.checked;
+ const input = document.getElementById('password-input');
+ if (checked) {
+ input.classList.remove('invisible');
+ input.focus();
+ } else {
+ input.classList.add('invisible');
+ input.value = '';
+ document.getElementById('password-msg').textContent = '';
+ state.password = null;
+ }
+ }
+
+ function inputChanged() {
+ const passwordInput = document.getElementById('password-input');
+ const pwdmsg = document.getElementById('password-msg');
+ const password = passwordInput.value;
+ const length = password.length;
+
+ if (length === MAX_LENGTH) {
+ pwdmsg.textContent = state.translate('maxPasswordLength', {
+ length: MAX_LENGTH
+ });
+ } else {
+ pwdmsg.textContent = '';
+ }
+ state.password = password;
+ }
+
+ function focused(event) {
+ event.preventDefault();
+ const el = document.getElementById('password-input');
+ if (el.placeholder !== state.translate('unlockInputPlaceholder')) {
+ el.placeholder = '';
+ }
+ }
+}
+
+function fileInfo(file, action) {
+ return html`
+
+
+
+
${file.name}
+ ${bytes(
+ file.size
+ )}
+ ${file.type}
+
+ ${action}
+ `;
+}
+
+function archiveDetails(translate, archive) {
+ if (archive.manifest.files.length > 1) {
+ return html`
+
+ ${translate('fileCount', {
+ num: archive.manifest.files.length
+ })}
+ ${list(archive.manifest.files.map(f => fileInfo(f)), 'list-reset h-full')}
+ `;
+ }
+ function toggled(event) {
+ event.stopPropagation();
+ archive.open = event.target.open;
+ }
+}
+
+module.exports = function(state, emit, archive) {
+ return html`
+
+
+
+
+
${archive.name}
+ ${bytes(
+ archive.size
+ )}
+
+
+ ${expiryInfo(state.translate, archive)}
+
+ ${archiveDetails(state.translate, archive)}
+
+
+ `;
+
+ function copy(event) {
+ event.stopPropagation();
+ copyToClipboard(archive.url);
+ const text = event.target.lastChild;
+ text.textContent = state.translate('copiedUrl');
+ setTimeout(
+ () => (text.textContent = state.translate('copyUrlHover')),
+ 1000
+ );
+ }
+
+ function del(event) {
+ event.stopPropagation();
+ emit('delete', { file: archive, location: 'success-screen' });
+ }
+};
+
+module.exports.wip = function(state, emit) {
+ return html`
+
+ ${list(
+ state.archive.files.map(f => fileInfo(f, remove(f))),
+ 'list-reset h-full overflow-y-scroll p-4 bg-blue-lightest md:max-h-half-screen',
+ 'bg-white px-2 mb-3 border border-grey-light rounded'
+ )}
+
+
+
+
+ ${expiryOptions(state, emit)}
+ ${password(state, emit)}
+
+ `;
+
+ function upload(event) {
+ event.preventDefault();
+ event.target.disabled = true;
+ if (!state.uploading) {
+ emit('upload', {
+ type: 'click',
+ dlimit: state.downloadCount || 1,
+ password: state.password
+ });
+ }
+ }
+
+ function add(event) {
+ event.preventDefault();
+ const newFiles = Array.from(event.target.files);
+
+ emit('addFiles', { files: newFiles });
+ }
+
+ function remove(file) {
+ return html`
+ `;
+ function del(event) {
+ event.stopPropagation();
+ emit('removeUpload', file);
+ }
+ }
+};
+
+module.exports.uploading = function(state, emit) {
+ const progress = state.transfer.progressRatio;
+ const progressPercent = percent(progress);
+ const archive = state.archive;
+ return html`
+
+
+
+
${archive.name}
+ ${bytes(
+ archive.size
+ )}
+
+
+ ${expiryInfo(state.translate, {
+ dlimit: state.downloadCount || 1,
+ dtotal: 0,
+ expiresAt: Date.now() + 500 + state.timeLimit * 1000
+ })}
+
+ ${progressPercent}
+
+
+ `;
+
+ function cancel(event) {
+ event.stopPropagation();
+ event.target.disabled = true;
+ emit('cancel');
+ }
+};
+
+module.exports.empty = function(state, emit) {
+ return html`
+
+
+ ${state.translate(
+ 'uploadDropDragMessage'
+ )}
+ ${state.translate(
+ 'uploadDropClickMessage'
+ )}
+
+
+ `;
+
+ function add(event) {
+ event.preventDefault();
+ const newFiles = Array.from(event.target.files);
+
+ emit('addFiles', { files: newFiles });
+ }
+};
+
+module.exports.preview = function(state, emit) {
+ const archive = state.fileInfo;
+ if (archive.open === undefined) {
+ archive.open = true;
+ }
+ return html`
+
+
+
+
${archive.name}
+ ${bytes(
+ archive.size
+ )}
+
+ ${archiveDetails(state.translate, archive)}
+
+ `;
+
+ function download(event) {
+ event.preventDefault();
+ event.target.disabled = true;
+ emit('download', archive);
+ }
+};
+
+module.exports.downloading = function(state, emit) {
+ const archive = state.fileInfo;
+ const progress = state.transfer.progressRatio;
+ const progressPercent = percent(progress);
+ return html`
+
+
+
+
${archive.name}
+ ${bytes(
+ archive.size
+ )}
+
+ ${progressPercent}
+
+
+ `;
+
+ function cancel(event) {
+ event.preventDefault();
+ event.target.disabled = true;
+ emit('download', archive);
+ }
+};
diff --git a/app/pages/blank.js b/app/ui/blank.js
similarity index 56%
rename from app/pages/blank.js
rename to app/ui/blank.js
index edaadcac..f6411022 100644
--- a/app/pages/blank.js
+++ b/app/ui/blank.js
@@ -1,5 +1,5 @@
const html = require('choo/html');
module.exports = function() {
- return html``;
+ return html``;
};
diff --git a/app/ui/copyDialog.js b/app/ui/copyDialog.js
new file mode 100644
index 00000000..87f1456b
--- /dev/null
+++ b/app/ui/copyDialog.js
@@ -0,0 +1,29 @@
+const html = require('choo/html');
+const { copyToClipboard } = require('../utils');
+
+module.exports = function(name, url) {
+ return function(state, emit, close) {
+ return html`
+
+
${state.translate('notifyUploadDone')}
+
${state.translate(
+ 'copyUrlFormLabelWithName',
+ { filename: name }
+ )}
+
+
+
${state.translate(
+ 'okButton'
+ )}
+
`;
+
+ function copy(event) {
+ event.stopPropagation();
+ copyToClipboard(url);
+ event.target.textContent = state.translate('copiedUrl');
+ setTimeout(close, 1000);
+ }
+ };
+};
diff --git a/app/ui/download.js b/app/ui/download.js
new file mode 100644
index 00000000..a4d89639
--- /dev/null
+++ b/app/ui/download.js
@@ -0,0 +1,114 @@
+/* global downloadMetadata */
+const html = require('choo/html');
+const archiveTile = require('./archiveTile');
+const intro = require('./intro');
+
+function password(state, emit) {
+ const fileInfo = state.fileInfo;
+ const invalid = fileInfo.password === null;
+
+ const div = html`
+
+
+
+
+
`;
+
+ if (!(div instanceof String)) {
+ setTimeout(() => document.getElementById('password-input').focus());
+ }
+
+ function inputChanged() {
+ const label = document.getElementById('password-error');
+ const input = document.getElementById('password-input');
+ label.classList.add('invisible');
+ input.classList.remove('border-red');
+ }
+
+ function checkPassword(event) {
+ event.preventDefault();
+ const password = document.getElementById('password-input').value;
+ if (password.length > 0) {
+ document.getElementById('password-btn').disabled = true;
+ state.fileInfo.url = window.location.href;
+ state.fileInfo.password = password;
+ emit('getMetadata');
+ }
+ return false;
+ }
+
+ return div;
+}
+
+function createFileInfo(state) {
+ return {
+ id: state.params.id,
+ secretKey: state.params.key,
+ nonce: downloadMetadata.nonce,
+ requiresPassword: downloadMetadata.pwd
+ };
+}
+
+module.exports = function(state, emit) {
+ let content = '';
+ if (!state.fileInfo) {
+ state.fileInfo = createFileInfo(state);
+ }
+
+ if (!state.transfer && !state.fileInfo.requiresPassword) {
+ emit('getMetadata');
+ }
+
+ if (state.transfer) {
+ switch (state.transfer.state) {
+ case 'downloading':
+ case 'decrypting':
+ content = archiveTile.downloading(state, emit);
+ break;
+ case 'complete':
+ content = html`
+ `;
+ break;
+ default:
+ content = archiveTile.preview(state, emit);
+ }
+ } else if (state.fileInfo.requiresPassword && !state.fileInfo.password) {
+ content = password(state, emit);
+ }
+ return html`
+
+
+ ${content}
+ ${intro(state)}
+
+ `;
+};
diff --git a/app/ui/error.js b/app/ui/error.js
new file mode 100644
index 00000000..c0189d9c
--- /dev/null
+++ b/app/ui/error.js
@@ -0,0 +1,18 @@
+const html = require('choo/html');
+const assets = require('../../common/assets');
+
+module.exports = function(state) {
+ return html`
+
+
+ `;
+};
diff --git a/app/templates/expireInfo/index.js b/app/ui/expiryOptions.js
similarity index 74%
rename from app/templates/expireInfo/index.js
rename to app/ui/expiryOptions.js
index d0aa7ac7..b94ffe7b 100644
--- a/app/templates/expireInfo/index.js
+++ b/app/ui/expiryOptions.js
@@ -1,17 +1,19 @@
/* globals DEFAULTS */
const html = require('choo/html');
const raw = require('choo/html/raw');
-const selectbox = require('../selectbox');
-const timeLimitText = require('../timeLimitText');
-const signupDialog = require('../signupDialog');
+const { secondsToL10nId } = require('../utils');
+const selectbox = require('./selectbox');
+const signupDialog = require('./signupDialog');
module.exports = function(state, emit) {
- const el = html` ${raw(
- state.translate('frontPageExpireInfo', {
- downloadCount: '
',
- timespan: '
'
- })
- )}
+ const el = html`
+
+ ${raw(
+ state.translate('frontPageExpireInfo', {
+ downloadCount: '',
+ timespan: ''
+ })
+ )}
`;
if (el.__encoded) {
// we're rendering on the server
@@ -50,7 +52,10 @@ module.exports = function(state, emit) {
selectbox(
state.timeLimit || 86400,
expires,
- num => timeLimitText(state.translate, num),
+ num => {
+ const l10n = secondsToL10nId(num);
+ return state.translate(l10n.id, l10n);
+ },
value => {
const max = state.user.maxExpireSeconds;
if (value > max) {
diff --git a/app/ui/footer.js b/app/ui/footer.js
new file mode 100644
index 00000000..b1023718
--- /dev/null
+++ b/app/ui/footer.js
@@ -0,0 +1,56 @@
+const html = require('choo/html');
+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`
`;
+ // 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;
+};
diff --git a/app/ui/fxPromo.js b/app/ui/fxPromo.js
new file mode 100644
index 00000000..cd472e17
--- /dev/null
+++ b/app/ui/fxPromo.js
@@ -0,0 +1,19 @@
+const html = require('choo/html');
+const assets = require('../../common/assets');
+
+module.exports = function() {
+ return html`
+
`;
+};
diff --git a/app/ui/header.js b/app/ui/header.js
new file mode 100644
index 00000000..6f25fa41
--- /dev/null
+++ b/app/ui/header.js
@@ -0,0 +1,25 @@
+const html = require('choo/html');
+const account = require('./account');
+
+module.exports = function(state, emit) {
+ const header = html`
+
`;
+ // 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;
+};
diff --git a/app/ui/home.js b/app/ui/home.js
new file mode 100644
index 00000000..864887bb
--- /dev/null
+++ b/app/ui/home.js
@@ -0,0 +1,33 @@
+const html = require('choo/html');
+const { list } = require('../utils');
+const archiveTile = require('./archiveTile');
+const modal = require('./modal');
+const intro = require('./intro');
+
+module.exports = function(state, emit) {
+ const archives = state.storage.files.map(archive =>
+ archiveTile(state, emit, archive)
+ );
+ let left = '';
+ if (state.uploading) {
+ left = archiveTile.uploading(state, emit);
+ } else if (state.archive) {
+ left = archiveTile.wip(state, emit);
+ } else {
+ left = archiveTile.empty(state, emit);
+ }
+ archives.reverse();
+ const right =
+ archives.length < 1
+ ? intro(state)
+ : list(archives, 'list-reset h-full overflow-y-scroll', 'mb-3');
+
+ return html`
+
+ ${state.modal && modal(state, emit)}
+
+ `;
+};
diff --git a/app/ui/intro.js b/app/ui/intro.js
new file mode 100644
index 00000000..d1bba348
--- /dev/null
+++ b/app/ui/intro.js
@@ -0,0 +1,20 @@
+const html = require('choo/html');
+const assets = require('../../common/assets');
+
+module.exports = function intro(state) {
+ return html`
+
+
+
${state.translate(
+ 'uploadPageHeader'
+ )}
+ ${state.translate(
+ 'pageHeaderCredits'
+ )}
+
+
+ ${state.translate(
+ 'uploadPageExplainer'
+ )}
+ `;
+};
diff --git a/app/ui/legal.js b/app/ui/legal.js
new file mode 100644
index 00000000..f00d74d7
--- /dev/null
+++ b/app/ui/legal.js
@@ -0,0 +1,33 @@
+const html = require('choo/html');
+const raw = require('choo/html/raw');
+
+module.exports = function(state) {
+ return html`
+
+
+
${state.translate('legalHeader')}
+ ${raw(
+ replaceLinks(state.translate('legalNoticeTestPilot'), [
+ 'https://testpilot.firefox.com/terms',
+ 'https://testpilot.firefox.com/privacy',
+ 'https://testpilot.firefox.com/experiments/send'
+ ])
+ )}
+ ${raw(
+ replaceLinks(state.translate('legalNoticeMozilla'), [
+ 'https://www.mozilla.org/privacy/websites/',
+ 'https://www.mozilla.org/about/legal/terms/mozilla/'
+ ])
+ )}
+
+ `;
+};
+
+function replaceLinks(str, urls) {
+ let i = 0;
+ const s = str.replace(
+ /
([^<]+)<\/a>/g,
+ (m, v) => `${v}`
+ );
+ return `
${s}
`;
+}
diff --git a/app/ui/modal.js b/app/ui/modal.js
new file mode 100644
index 00000000..94416666
--- /dev/null
+++ b/app/ui/modal.js
@@ -0,0 +1,21 @@
+const html = require('choo/html');
+
+module.exports = function(state, emit) {
+ return html`
+
+
+
e.stopPropagation()}>
+ ${state.modal(state, emit, close)}
+
+
+
`;
+
+ function close(event) {
+ if (event) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ state.modal = null;
+ emit('render');
+ }
+};
diff --git a/app/ui/notFound.js b/app/ui/notFound.js
new file mode 100644
index 00000000..78a63361
--- /dev/null
+++ b/app/ui/notFound.js
@@ -0,0 +1,22 @@
+const html = require('choo/html');
+const assets = require('../../common/assets');
+
+module.exports = function(state) {
+ return html`
+
+
+ `;
+};
diff --git a/app/ui/okDialog.js b/app/ui/okDialog.js
new file mode 100644
index 00000000..0bca4442
--- /dev/null
+++ b/app/ui/okDialog.js
@@ -0,0 +1,13 @@
+const html = require('choo/html');
+
+module.exports = function(message) {
+ return function(state, emit, close) {
+ return html`
+
+
${message}
+
+
`;
+ };
+};
diff --git a/app/templates/selectbox/index.js b/app/ui/selectbox.js
similarity index 75%
rename from app/templates/selectbox/index.js
rename to app/ui/selectbox.js
index 43d2d666..9f529708 100644
--- a/app/templates/selectbox/index.js
+++ b/app/ui/selectbox.js
@@ -1,11 +1,10 @@
const html = require('choo/html');
module.exports = function(selected, options, translate, changed) {
- const id = `select-${Math.random()}`;
let x = selected;
return html`
-