+
+ ${title(state)}
+
${strings.header}
+
${strings.description}
+ ${why}
- ${why}
-
-
- ${buttonAction}
-
+
+
+
${strings.explainer}
@@ -50,7 +58,7 @@ module.exports = function(state) {
function outdatedStrings(state) {
return {
- title: state.translate('notSupportedHeader'),
+ header: state.translate('notSupportedHeader'),
description: state.translate('notSupportedOutdatedDetail'),
button: state.translate('updateFirefox'),
explainer: state.translate('uploadPageExplainer')
@@ -59,7 +67,7 @@ function outdatedStrings(state) {
function unsupportedStrings(state) {
return {
- title: state.translate('notSupportedHeader'),
+ 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
index 8f22443a..b34adcae 100644
--- a/app/pages/unsupported/unsupported.css
+++ b/app/pages/unsupported/unsupported.css
@@ -1,26 +1,30 @@
.unsupportedPage {
- display: flex;
justify-content: center;
align-items: center;
- flex-direction: column;
+}
+
+.unsupportedPage__error {
+ margin: 10px 0 20px;
}
.unsupportedPage__info {
font-size: 13px;
- line-height: 23px;
- text-align: center;
color: var(--lightTextColor);
- margin: 0 auto 23px;
+ margin: 0 auto 10px;
}
.firefoxDownload {
- margin-bottom: 181px;
- height: 80px;
- background: #98e02b;
+ flex: 2;
+}
+
+.firefoxDownload__button {
+ margin: 0 auto 20px;
+ height: 70px;
+ width: 250px;
+ background: #12bc00;
border-radius: 3px;
cursor: pointer;
border: 0;
- box-shadow: 0 5px 3px rgb(234, 234, 234);
font-family: 'Fira Sans', 'segoe ui', sans-serif;
font-weight: 500;
color: var(--primaryControlFGColor);
@@ -29,21 +33,22 @@
justify-content: center;
align-items: center;
line-height: 1;
- padding: 0 25px;
+ padding: 8px;
}
.firefoxDownload__logo {
- width: 70px;
+ width: 55px;
}
.firefoxDownload__action {
text-align: left;
- margin-left: 20.4px;
+ text-transform: uppercase;
+ margin-left: 20px;
}
.firefoxDownload__text {
+ text-transform: none;
font-family: 'Fira Sans', 'segoe ui', sans-serif;
font-weight: 300;
- font-size: 18px;
- letter-spacing: -0.69px;
+ font-size: 17px;
}
diff --git a/app/pages/upload/index.js b/app/pages/upload/index.js
deleted file mode 100644
index 81353e0f..00000000
--- a/app/pages/upload/index.js
+++ /dev/null
@@ -1,39 +0,0 @@
-const html = require('choo/html');
-const progress = require('../../templates/progress');
-const { bytes } = require('../../utils');
-
-module.exports = function(state, emit) {
- const transfer = state.transfer;
-
- return html`
-
-
- ${state.translate('uploadingPageProgress', {
- filename: transfer.file.name,
- size: bytes(transfer.file.size)
- })}
-
-
- ${progress(transfer.progressRatio, transfer.progressIndefinite)}
-
-
- ${state.translate(transfer.msg, transfer.sizes)}
-
-
-
-
- `;
-
- function cancel() {
- const btn = document.getElementById('cancel-upload');
- btn.disabled = true;
- btn.textContent = state.translate('uploadCancelNotification');
- emit('cancel');
- }
-};
diff --git a/app/pages/welcome/index.js b/app/pages/welcome/index.js
index d7a63f12..3f143ba5 100644
--- a/app/pages/welcome/index.js
+++ b/app/pages/welcome/index.js
@@ -1,50 +1,86 @@
-/* global MAXFILESIZE */
const html = require('choo/html');
const assets = require('../../../common/assets');
-const fileList = require('../../templates/fileList');
-const { bytes, fadeOut } = require('../../utils');
+const { checkSize } = require('../../utils');
+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 files = state.files ? state.files : [];
+
+ const optionClass = state.uploading ? 'uploadOptions--faded' : '';
+ const btnUploading = state.uploading ? 'btn--stripes' : '';
+ const faded = files.length > 0 ? 'uploadArea--faded' : '';
+ const selectFileClass = files.length > 0 ? 'btn--hidden' : '';
+ const sendFileClass = files.length > 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`
-
-
${state.translate('uploadPageHeader')}
-
-
+ ${title(state)}
+
+
-
`;
diff --git a/app/templates/header/header.css b/app/templates/header/header.css
index 91b6ad04..fa345dc8 100644
--- a/app/templates/header/header.css
+++ b/app/templates/header/header.css
@@ -3,7 +3,7 @@
box-sizing: border-box;
display: flex;
justify-content: space-between;
- padding: 31px;
+ padding: 20px;
width: 100%;
}
@@ -62,7 +62,7 @@
color: var(--primaryControlFGColor);
cursor: pointer;
display: block;
- float: right;
+ float: left;
font-size: 12px;
line-height: 12px;
opacity: 0.9;
@@ -88,17 +88,10 @@
background-color: var(--primaryControlHoverColor);
}
-@media (max-device-width: 520px), (max-width: 520px) {
+@media (max-device-width: 750px), (max-width: 750px) {
.header {
+ padding-top: 60px;
flex-direction: column;
justify-content: flex-start;
}
-
- .feedback {
- margin-top: 10px;
- min-width: 30px;
- max-width: 300px;
- text-indent: 2px;
- padding: 5px 5px 5px 20px;
- }
}
diff --git a/app/templates/header/index.js b/app/templates/header/index.js
index b5fbf882..4f4b9151 100644
--- a/app/templates/header/index.js
+++ b/app/templates/header/index.js
@@ -6,8 +6,6 @@ module.exports = function(state) {
const feedbackUrl = `https://qsurvey.mozilla.com/s3/txp-firefox-send?ver=${version}&browser=${browser}`;
const header = html`
`;
- function inputChanged() {
- state.passwordSetError = null;
- const resetInput = document.getElementById('password-input');
- const resetBtn = document.getElementById('password-btn');
- const pwdmsg = document.querySelector('.passwordInput__msg');
- const length = resetInput.value.length;
+ function onSubmit() {
+ event.preventDefault();
+ }
- if (length === MAX_LENGTH) {
- pwdmsg.textContent = state.translate('maxPasswordLength', {
- length: MAX_LENGTH
- });
- } else {
- pwdmsg.textContent = '';
- }
- if (length > 0) {
- resetBtn.classList.remove('inputBtn--hidden');
- resetInput.classList.remove('input--noBtn');
- } else {
- resetBtn.classList.add('inputBtn--hidden');
- resetInput.classList.add('input--noBtn');
- }
+ function inputChanged() {
+ const password = document.getElementById('password-input').value;
+ state.password = password;
}
function focused(event) {
@@ -80,30 +43,8 @@ module.exports = function(file, state, emit) {
el.placeholder = '';
}
}
-
- function setPassword(event) {
- event.preventDefault();
- const el = document.getElementById('password-input');
- const password = el.value;
- if (password.length > 0) {
- emit('password', { password, file });
- } else {
- el.focus();
- }
- return false;
- }
};
function passwordPlaceholder(password) {
- return password ? password.replace(/./g, '●') : '●●●●●●●●●●●●';
-}
-
-function message(state, pwd) {
- if (state.passwordSetError) {
- return state.translate('passwordSetError');
- }
- if (state.settingPassword || !pwd) {
- return '';
- }
- return state.translate('passwordIsSet');
+ return password ? password.replace(/./g, '•') : '••••••••••••';
}
diff --git a/app/templates/passwordInput/passwordInput.css b/app/templates/passwordInput/passwordInput.css
index b67885d9..ccfab210 100644
--- a/app/templates/passwordInput/passwordInput.css
+++ b/app/templates/passwordInput/passwordInput.css
@@ -1,41 +1,31 @@
.passwordInput {
- width: 90%;
- height: 100px;
- padding: 10px 5px 5px;
+ display: inline;
}
.passwordInput--hidden {
visibility: hidden;
}
-.passwordInput__form {
- display: flex;
- flex-wrap: nowrap;
- padding-bottom: 5px;
+.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: 15px;
+ font-size: 12px;
color: var(--lightTextColor);
}
.passwordInput__msg--error {
color: var(--errorColor);
}
-
-.inputBtn--loading {
- background-image: url('../assets/spinner.svg');
- background-position: center;
- background-size: 30px 30px;
- background-repeat: no-repeat;
-}
-
-.inputBtn--password {
- flex: 0 0 200px;
-}
-
-@media (max-device-width: 520px), (max-width: 520px) {
- .passwordInput__form {
- flex-direction: column;
- }
-}
diff --git a/app/templates/popup/index.js b/app/templates/popup/index.js
index 969115f4..cdf65a89 100644
--- a/app/templates/popup/index.js
+++ b/app/templates/popup/index.js
@@ -2,19 +2,17 @@ const html = require('choo/html');
module.exports = function(msg, confirmText, cancelText, confirmCallback) {
return html`
- `;
+
`;
function hide(e) {
e.stopPropagation();
diff --git a/app/templates/popup/popup.css b/app/templates/popup/popup.css
index 3ced13ef..548aedb6 100644
--- a/app/templates/popup/popup.css
+++ b/app/templates/popup/popup.css
@@ -1,122 +1,79 @@
.popup {
- visibility: hidden;
- min-width: 204px;
- min-height: 105px;
- background-color: var(--pageBGColor);
+ display: block;
+ width: 100%;
+ height: 70px;
+ background-color: var(--errorColor);
color: var(--textColor);
- border: 1px solid #d7d7db;
- padding: 15px 24px;
- box-sizing: content-box;
+ padding: 0;
+ box-sizing: border-box;
text-align: center;
- border-radius: 5px;
- position: absolute;
- z-index: 1;
- bottom: 20px;
- left: -40px;
+ border-radius: 4px;
transition: opacity 0.5s;
- opacity: 0;
outline: 0;
- box-shadow: 3px 3px 7px rgba(136, 136, 136, 0.3);
+ opacity: 0;
+ visibility: hidden;
}
.popup::after {
content: '';
position: absolute;
- bottom: -11px;
- left: 20px;
- background-color: #fff;
- display: block;
- width: 20px;
- height: 20px;
- transform: rotate(45deg);
- border-radius: 0 0 5px;
- border-right: 1px solid #d7d7db;
- border-bottom: 1px solid #d7d7db;
- border-left: 1px solid #fff;
- border-top: 1px solid #fff;
-}
-
-.popup__wrapper {
- position: absolute;
- display: inline-block;
+ 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;
- display: flex;
- justify-content: center;
- align-items: center;
- border-bottom: 1px #ebebeb solid;
- color: var(--textColor);
+ padding: 10px;
+ box-sizing: border-box;
+ text-align: center;
+ color: var(--primaryControlFGColor);
font-size: 15px;
- font-weight: normal;
- padding-bottom: 15px;
+ font-style: italic;
white-space: nowrap;
- width: calc(100% + 48px);
- margin-left: -24px;
}
.popup__action {
- margin-top: 15px;
display: flex;
flex-direction: row;
- align-items: center;
- justify-content: space-between;
+ text-transform: uppercase;
+}
+
+.popup__action > div {
+ flex: auto;
}
.popup__no {
- color: #4a4a4a;
- background-color: #fbfbfb;
- border: 1px #c1c1c1 solid;
- border-radius: 5px;
- padding: 5px 25px;
- font-weight: normal;
- min-width: 94px;
- box-sizing: border-box;
+ color: var(--primaryControlFGColor);
+ padding: 5px;
+ font-weight: bold;
cursor: pointer;
white-space: nowrap;
}
.popup__no:hover {
- background-color: #efeff1;
+ text-decoration: underline;
}
.popup__yes {
color: var(--primaryControlFGColor);
- background-color: var(--primaryControlBGColor);
- border-radius: 5px;
- padding: 5px 25px;
+ padding: 5px;
font-weight: normal;
cursor: pointer;
- min-width: 94px;
- box-sizing: border-box;
white-space: nowrap;
- margin-left: 12px;
}
.popup__yes:hover {
- background-color: var(--primaryControlHoverColor);
+ text-decoration: underline;
}
.popup--show {
visibility: visible;
opacity: 1;
-}
-
-@media (max-device-width: 992px), (max-width: 992px) {
- .popup {
- left: auto;
- right: -40px;
- }
-
- .popup::after {
- left: auto;
- right: 36px;
- }
-}
-
-@media (max-device-width: 520px), (max-width: 520px) {
- .popup::after {
- left: 125px;
- }
+ pointer-events: auto;
}
diff --git a/app/templates/progress/index.js b/app/templates/progress/index.js
deleted file mode 100644
index 4ab9a1d3..00000000
--- a/app/templates/progress/index.js
+++ /dev/null
@@ -1,56 +0,0 @@
-const html = require('choo/html');
-const percent = require('../../utils').percent;
-
-const radius = 73;
-const oRadius = radius + 10;
-const oDiameter = oRadius * 2;
-const circumference = 2 * Math.PI * radius;
-
-module.exports = function(progressRatio, indefinite = false) {
- // HACK - never indefinite for MS Edge
- if (/edge/i.test(navigator.userAgent)) {
- indefinite = false;
- }
- const p = indefinite ? 0.2 : progressRatio;
- const dashOffset = (1 - p) * circumference;
- const progressPercent = html`
-
- ${percent(progressRatio)}
- `;
-
- return html`
-
-
-
- `;
-};
diff --git a/app/templates/progress/progress.css b/app/templates/progress/progress.css
deleted file mode 100644
index 410b0be0..00000000
--- a/app/templates/progress/progress.css
+++ /dev/null
@@ -1,43 +0,0 @@
-.progress {
- margin-top: 3px;
-}
-
-.progress__bg {
- stroke: #eee;
- stroke-width: 0.75em;
-}
-
-.progress__bar {
- stroke: #3b9dff;
- stroke-width: 0.75em;
- transition: stroke-dashoffset 300ms linear;
-}
-
-.progress__indefinite {
- stroke: #3b9dff;
- stroke-width: 0.75em;
- animation: 1s linear infinite spin;
- transform-origin: center;
-}
-
-@keyframes spin {
- from {
- transform: rotate(0deg);
- }
-
- to {
- transform: rotate(360deg);
- }
-}
-
-.progress__percent {
- font-family: 'Segoe UI', 'SF Pro Text', sans-serif;
- font-size: 43.2px;
- letter-spacing: -0.78px;
- line-height: 58px;
- user-select: none;
-}
-
-.progress--invisible {
- display: none;
-}
diff --git a/app/templates/selectbox/index.js b/app/templates/selectbox/index.js
index 52ed93b9..43d2d666 100644
--- a/app/templates/selectbox/index.js
+++ b/app/templates/selectbox/index.js
@@ -5,16 +5,14 @@ module.exports = function(selected, options, translate, changed) {
let x = selected;
return html`
-
-
`;
+ `;
function choose(event) {
const target = event.target;
diff --git a/app/templates/selectbox/selectbox.css b/app/templates/selectbox/selectbox.css
index 49664978..fcbb196b 100644
--- a/app/templates/selectbox/selectbox.css
+++ b/app/templates/selectbox/selectbox.css
@@ -1,46 +1,22 @@
-.select {
- background-color: var(--pageBGColor);
- overflow: hidden;
- padding: 4px 2px 4px 2px;
- border: 1px dotted #0094fb88;
- border-radius: 4px;
- display: inline;
- position: relative;
-}
-
-.select::after {
- color: #0094fb;
- content: '\25BC';
- pointer-events: none;
- font-size: 20px;
- margin-left: -30px;
- padding-right: 10px;
-}
-
option {
padding: 0;
}
-select {
+.selectBox {
appearance: none;
outline: 0;
box-shadow: none;
- border: 0;
- background: #fff;
- background-image: none;
+ border: none;
+ border-radius: 0;
+ background-color: #e6e6e6;
font-size: 1em;
font-weight: 200;
margin: 0;
- color: #0094fb;
+ padding: 4px 2px 4px 2px;
cursor: pointer;
- padding-right: 40px;
}
select:active {
background-color: var(--pageBGColor);
border: 0;
}
-
-#arrow {
- position: relative;
-}
diff --git a/app/templates/setPasswordSection/index.js b/app/templates/setPasswordSection/index.js
index 16130712..8fad4337 100644
--- a/app/templates/setPasswordSection/index.js
+++ b/app/templates/setPasswordSection/index.js
@@ -1,25 +1,26 @@
const html = require('choo/html');
const passwordInput = require('../passwordInput');
-module.exports = function(state, emit) {
- const file = state.storage.getFileById(state.params.id);
+module.exports = function(state) {
+ const checked = state.password ? 'checked' : '';
+ const label = state.password ? 'addPasswordLabel' : 'addPasswordMessage';
return html`
`;
function togglePasswordInput(e) {
@@ -28,9 +29,13 @@ module.exports = function(state, emit) {
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
index bf3adb75..28233cfe 100644
--- a/app/templates/setPasswordSection/setPasswordSection.css
+++ b/app/templates/setPasswordSection/setPasswordSection.css
@@ -1,11 +1,12 @@
.setPasswordSection {
+ display: flex;
padding: 10px 0;
max-width: 100%;
- overflow-wrap: break-word;
}
.checkbox {
- min-height: 24px;
+ flex: auto;
+ height: 24px;
}
.checkbox__input {
@@ -14,7 +15,8 @@
}
.checkbox__label {
- line-height: 23px;
+ font-size: 13px;
+ line-height: 20px;
cursor: pointer;
color: var(--lightTextColor);
user-select: none;
@@ -22,27 +24,21 @@
.checkbox__label::before {
content: '';
- height: 20px;
- width: 20px;
+ height: 24px;
+ width: 24px;
margin-right: 10px;
- margin-left: 5px;
float: left;
- border: 1px solid rgba(12, 12, 13, 0.3);
- border-radius: 2px;
+ background-color: #e6e6e6;
}
-.checkbox__input:focus + .checkbox__label::before,
-.checkbox:hover .checkbox__label::before {
- border: 1px solid var(--primaryControlBGColor);
-}
-
-.checkbox__input:checked + .checkbox__label {
- color: var(--textColor);
+.checkbox__label:hover::before {
+ background-color: #d6d6d6;
}
.checkbox__input:checked + .checkbox__label::before {
- background-image: url('../assets/check-16-blue.svg');
- background-position: 2px 1px;
+ background-image: url('../assets/lock.svg');
+ background-position: 2px 2px;
+ background-repeat: no-repeat;
}
.checkbox__input:disabled + .checkbox__label {
@@ -50,20 +46,13 @@
}
.checkbox__input:disabled + .checkbox__label::before {
- background-image: url('../assets/check-16-blue.svg');
+ background-image: url('../assets/lock.svg');
background-repeat: no-repeat;
background-size: 26px 26px;
border: none;
cursor: auto;
}
-@media (max-device-width: 520px), (max-width: 520px) {
- .setPasswordSection {
- align-self: center;
- min-width: 95%;
- }
-
- .checkbox__label::before {
- margin-left: 0;
- }
+.setPasswordSection > .passwordInput--hidden {
+ display: none;
}
diff --git a/app/templates/signupPromo/index.js b/app/templates/signupPromo/index.js
new file mode 100644
index 00000000..376b5ba0
--- /dev/null
+++ b/app/templates/signupPromo/index.js
@@ -0,0 +1,15 @@
+const html = require('choo/html');
+
+module.exports = function(state) {
+ return html`
+
+ `;
+};
diff --git a/app/templates/signupPromo/signupPromo.css b/app/templates/signupPromo/signupPromo.css
new file mode 100644
index 00000000..ce372c38
--- /dev/null
+++ b/app/templates/signupPromo/signupPromo.css
@@ -0,0 +1,85 @@
+.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: 750px), (max-width: 750px) {
+ .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/title/index.js b/app/templates/title/index.js
new file mode 100644
index 00000000..6e0b0e01
--- /dev/null
+++ b/app/templates/title/index.js
@@ -0,0 +1,11 @@
+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
new file mode 100644
index 00000000..1f45a798
--- /dev/null
+++ b/app/templates/title/title.css
@@ -0,0 +1,13 @@
+.boxTitle {
+ font-size: 15px;
+ text-align: center;
+ font-weight: 500;
+ margin: 9px 0 19px 0;
+ 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
new file mode 100644
index 00000000..7fc65ccf
--- /dev/null
+++ b/app/templates/uploadedFile/index.js
@@ -0,0 +1,64 @@
+const html = require('choo/html');
+const assets = require('../../../common/assets');
+const bytes = require('../../utils').bytes;
+const fileIcon = require('../fileIcon');
+
+module.exports = function(file, state, emit) {
+ const transfer = state.transfer;
+ const transferState = transfer ? transfer.state : null;
+ const transferring = state.uploading || state.downloading;
+ const share = state.route.includes('share/');
+ const complete = share ? 'uploadedFile--completed' : '';
+
+ const cancelVisible =
+ transferring || state.route === '/' ? 'uploadedFile__cancel--visible' : '';
+
+ const stampClass =
+ share || transferState === 'complete' ? 'uploadedFile__stamp--visible' : '';
+
+ function cancel(event) {
+ event.preventDefault();
+ const btn = document.querySelector('.uploadedFile__cancel');
+ btn.disabled = true;
+ if (transferring) {
+ emit('cancel');
+ } else if (state.route === '/') {
+ emit('removeUpload', { file });
+ }
+ }
+
+ //const percent = share ? 100 : Math.floor(progressRatio * 100);
+ /*
+ style="
+ background: linear-gradient(to right,
+ #e8f2fe 0%,
+ #e8f2fe ${percent}%,
+ #fff ${percent}%,
+ #fff 100%);"
+ */
+
+ return html`
+
+
+ ${fileIcon(file.name, file._hasPassword)}
+
+
+
+
+
+
+
${file.name}
+
+ ${bytes(file.size)}
+
+
+
+
+
+ `;
+};
diff --git a/app/templates/uploadedFile/uploadedFile.css b/app/templates/uploadedFile/uploadedFile.css
new file mode 100644
index 00000000..f3fe4dcb
--- /dev/null
+++ b/app/templates/uploadedFile/uploadedFile.css
@@ -0,0 +1,70 @@
+.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
new file mode 100644
index 00000000..c10c4ce7
--- /dev/null
+++ b/app/templates/uploadedFileList/index.js
@@ -0,0 +1,12 @@
+const html = require('choo/html');
+const file = require('../uploadedFile');
+
+module.exports = function(files, state, emit) {
+ //const progressRatio = state.transfer ? state.transfer.progressRatio : 0;
+
+ return html`
+
+ ${files.map(f => file(f, state, emit))}
+
+ `;
+};
diff --git a/app/templates/uploadedFileList/uploadedFileList.css b/app/templates/uploadedFileList/uploadedFileList.css
new file mode 100644
index 00000000..378faf5e
--- /dev/null
+++ b/app/templates/uploadedFileList/uploadedFileList.css
@@ -0,0 +1,10 @@
+.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;
+}
diff --git a/app/templates/userAccount/index.js b/app/templates/userAccount/index.js
new file mode 100644
index 00000000..76b28a2a
--- /dev/null
+++ b/app/templates/userAccount/index.js
@@ -0,0 +1,24 @@
+const html = require('choo/html');
+const assets = require('../../../common/assets');
+
+// eslint-disable-next-line no-unused-vars
+module.exports = function(state) {
+ return html`
+
+
+
+
+ - Placeholder
+ - Placeholder
+
+
`;
+
+ function onclick(event) {
+ event.preventDefault();
+ const dropdown = document.querySelector('.account_dropdown');
+ dropdown.classList.toggle('visible');
+ }
+};
diff --git a/app/templates/userAccount/userAccount.css b/app/templates/userAccount/userAccount.css
new file mode 100644
index 00000000..b92d54e4
--- /dev/null
+++ b/app/templates/userAccount/userAccount.css
@@ -0,0 +1,33 @@
+.account {
+ position: absolute;
+ right: 0;
+ margin: 0 21px;
+ padding: 0;
+}
+
+.account_dropdown {
+ z-index: 1;
+ position: absolute;
+ top: 25px;
+ left: -10px;
+ width: 150px;
+ list-style-type: none;
+ border: 1px solid rgba(0, 0, 0, 0.2);
+ border-radius: 4px;
+ background-color: var(--pageBGColor);
+ box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.2);
+ padding: 11px 0;
+ visibility: hidden;
+}
+
+.account_dropdown__item {
+ padding: 0 14px;
+ color: var(--lightTextColor);
+ font-size: 13px;
+ line-height: 24px;
+}
+
+.account_dropdown__item:hover {
+ background-color: var(--primaryControlBGColor);
+ color: var(--primaryControlFGColor);
+}
diff --git a/app/utils.js b/app/utils.js
index 8baa6617..2ec84e23 100644
--- a/app/utils.js
+++ b/app/utils.js
@@ -1,3 +1,4 @@
+/* global MAXFILESIZE */
const b64 = require('base64-js');
function arrayToB64(array) {
@@ -128,6 +129,27 @@ function openLinksInNewTab(links, should = true) {
return links;
}
+function checkSize(files, oldfiles, translate) {
+ function size(arr) {
+ let total = 0;
+ for (let i = 0; i < arr.length; i++) {
+ total += arr[i].size;
+ }
+ return total;
+ }
+
+ const addSize = size(files);
+ if (addSize === 0) {
+ return;
+ }
+ const totalSize = addSize + size(oldfiles);
+ if (totalSize > MAXFILESIZE) {
+ // eslint-disable-next-line no-alert
+ alert(translate('fileTooBig', { size: bytes(MAXFILESIZE) }));
+ return;
+ }
+}
+
module.exports = {
fadeOut,
delay,
@@ -140,5 +162,6 @@ module.exports = {
b64ToArray,
loadShim,
isFile,
- openLinksInNewTab
+ openLinksInNewTab,
+ checkSize
};
diff --git a/assets/addfile.svg b/assets/addfile.svg
new file mode 100644
index 00000000..c55f170e
--- /dev/null
+++ b/assets/addfile.svg
@@ -0,0 +1,10 @@
+
+
\ No newline at end of file
diff --git a/assets/back-arrow.svg b/assets/back-arrow.svg
new file mode 100644
index 00000000..ee746536
--- /dev/null
+++ b/assets/back-arrow.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/assets/blue_file.svg b/assets/blue_file.svg
new file mode 100644
index 00000000..c06eefd8
--- /dev/null
+++ b/assets/blue_file.svg
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/assets/lock-white.svg b/assets/lock-white.svg
new file mode 100644
index 00000000..429a8dec
--- /dev/null
+++ b/assets/lock-white.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/assets/lock.svg b/assets/lock.svg
new file mode 100644
index 00000000..bf4b6249
--- /dev/null
+++ b/assets/lock.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/assets/red_file.svg b/assets/red_file.svg
new file mode 100644
index 00000000..d52e51b1
--- /dev/null
+++ b/assets/red_file.svg
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/assets/sent-done.svg b/assets/sent-done.svg
new file mode 100644
index 00000000..8c1dfe4f
--- /dev/null
+++ b/assets/sent-done.svg
@@ -0,0 +1,19 @@
+
+
\ No newline at end of file
diff --git a/assets/upload.svg b/assets/upload.svg
deleted file mode 100644
index f98e6b2e..00000000
--- a/assets/upload.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/assets/user.svg b/assets/user.svg
new file mode 100644
index 00000000..3d052d07
--- /dev/null
+++ b/assets/user.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/locales/en-US/send.ftl b/public/locales/en-US/send.ftl
index 60bd9e8c..43d017cd 100644
--- a/public/locales/en-US/send.ftl
+++ b/public/locales/en-US/send.ftl
@@ -26,6 +26,7 @@ uploadSuccessConfirmHeader = Ready to Send
uploadSvgAlt = Upload
uploadSuccessTimingHeader = The link to your file will expire after 1 download or in 24 hours.
expireInfo = The link to your file will expire after { $downloadCount } or { $timespan }.
+frontPageExpireInfo = Expires after { $downloadCount } or { $timespan }
downloadCount = { $num ->
[one] 1 download
*[other] { $num } downloads
@@ -34,6 +35,14 @@ timespanHours = { $num ->
[one] 1 hour
*[other] { $num } hours
}
+timespanMinutes = { $num ->
+ [one] 1 minute
+ *[other] { $num } minutes
+ }
+timespanWeeks = { $num ->
+ [one] 1 week
+ *[other] { $num } weeks
+ }
copyUrlFormLabelWithName = Copy and share the link to send your file: { $filename }
copyUrlFormButton = Copy to clipboard
copiedUrl = Copied!
@@ -117,3 +126,30 @@ passwordIsSet = Password set
maxPasswordLength = Maximum password length: { $length }
# A short status message shown when there was an error setting the password
passwordSetError = This password could not be set
+pageHeaderCredits = from the makers of Firefox
+addFilesButton = Add file(s)
+uploadFilesButton = Send
+uploadFileProgress = Sending
+uploadDropDragMessage = Drop files here
+uploadDropClickMessage = or click to select a file
+addPasswordMessage = Protect with password
+addPasswordLabel = Password:
+copyUrlLabel = Copy and share this link:
+passwordReminder = don't forget the password too
+signInPromoText = Sign In/Up!
+signInExplanation = It's free and gives you many more Send options
+signInLearnMore = Learn more!
+downloadProgressButton = Downloading... { $progress }
+downloadMessage2 = Firefox Send lets you share files with a safe, private, and encrypted link that automatically expires to ensure your stuff does not remain online forever.
+signInEmailEnter = Enter your Email
+emailEntryPlaceholder = Email
+signInContinueMessage = to continue to Firefox Send
+signInContinueButton = Continue
+accountBenefitTitle = With a free Firefox Account with Send you can:
+accountBenefitMultiFile = Send multiple files at once
+accountBenefitLargeFiles = Upload larger files (up to { $size } GB)
+accountBenefitExpiry = Have more expiry options
+accountBenefitSync = Manage your uploads across devices
+accountBenefitNotify = Be notified when your files are downloaded
+accountBenefitMore = Do a lot more!
+
diff --git a/server/routes/exists.js b/server/routes/exists.js
index badb32c3..da49c019 100644
--- a/server/routes/exists.js
+++ b/server/routes/exists.js
@@ -5,7 +5,7 @@ module.exports = async (req, res) => {
const meta = await storage.metadata(req.params.id);
res.set('WWW-Authenticate', `send-v1 ${meta.nonce}`);
res.send({
- password: meta.pwd
+ requiresPassword: meta.pwd
});
} catch (e) {
res.sendStatus(404);
diff --git a/server/routes/index.js b/server/routes/index.js
index d258c662..33091402 100644
--- a/server/routes/index.js
+++ b/server/routes/index.js
@@ -49,7 +49,7 @@ module.exports = function(app) {
next();
});
app.use(express.json());
- app.get('/', language, pages.index);
+ app.get('/', language, pages.blank);
app.get('/legal', language, pages.legal);
app.get('/jsconfig.js', require('./jsconfig'));
app.get(`/share/:id${ID_REGEX}`, language, pages.blank);
diff --git a/server/routes/pages.js b/server/routes/pages.js
index 74f633f1..4b8128cf 100644
--- a/server/routes/pages.js
+++ b/server/routes/pages.js
@@ -19,16 +19,15 @@ module.exports = {
download: async function(req, res, next) {
const id = req.params.id;
-
try {
const { nonce, pwd } = await storage.metadata(id);
res.set('WWW-Authenticate', `send-v1 ${nonce}`);
res.send(
stripEvents(
routes.toString(
- `/download/${req.params.id}`,
+ `/download/${id}`,
Object.assign(state(req), {
- fileInfo: { nonce, requiresPassword: +pwd }
+ fileInfo: { nonce, requiresPassword: pwd }
})
)
)