removed old ui
This commit is contained in:
parent
f0cfc19f8c
commit
7838ad586d
309
app/base.css
309
app/base.css
|
@ -1,309 +0,0 @@
|
||||||
:root {
|
|
||||||
--pageBGColor: #fff;
|
|
||||||
--lightControlBGColor: #e6e6e6;
|
|
||||||
--primaryControlBGColor: #0a84ff;
|
|
||||||
--primaryControlFGColor: #fff;
|
|
||||||
--primaryControlHoverColor: #0473e2;
|
|
||||||
--inputTextColor: #000;
|
|
||||||
--errorColor: #d70022;
|
|
||||||
--linkColor: #0094fb;
|
|
||||||
--textColor: #0c0c0d;
|
|
||||||
--lightBorderColor: rgba(12, 12, 12, 0.2);
|
|
||||||
--lightTextColor: #737373;
|
|
||||||
--successControlBGColor: #12bc00;
|
|
||||||
--successControlFGColor: #fff;
|
|
||||||
--large-box-shadow: 0 4px 16px rgba(12, 12, 13, 0.1);
|
|
||||||
--edge-size: 96px;
|
|
||||||
--grid-basis: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
*,
|
|
||||||
*::before,
|
|
||||||
*::after {
|
|
||||||
box-sizing: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
font-family: Futura, -apple-system, BlinkMacSystemFont, 'SF Pro Text',
|
|
||||||
'segoe ui', 'helvetica neue', helvetica, ubuntu, roboto, noto, arial,
|
|
||||||
sans-serif;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'segoe ui',
|
|
||||||
'helvetica neue', helvetica, ubuntu, roboto, noto, arial, sans-serif;
|
|
||||||
height: 100vh;
|
|
||||||
margin: 0;
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
}
|
|
||||||
|
|
||||||
input,
|
|
||||||
select,
|
|
||||||
textarea,
|
|
||||||
button {
|
|
||||||
font-family: inherit;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
background: var(--pageBGColor);
|
|
||||||
box-shadow: var(--large-box-shadow);
|
|
||||||
width: 90%;
|
|
||||||
max-width: 960px;
|
|
||||||
min-height: 550px;
|
|
||||||
max-height: 600px;
|
|
||||||
align-self: center;
|
|
||||||
margin: auto 0;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 70px 360px 1fr;
|
|
||||||
grid-template-areas: 'nav files content';
|
|
||||||
}
|
|
||||||
|
|
||||||
.split {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.split__left {
|
|
||||||
height: 100%;
|
|
||||||
border-right: 1px solid #d7d7db;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
text-align: center;
|
|
||||||
grid-area: files;
|
|
||||||
}
|
|
||||||
|
|
||||||
.split__right {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-end;
|
|
||||||
justify-content: center;
|
|
||||||
position: relative;
|
|
||||||
grid-area: content;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wide {
|
|
||||||
grid-area: files-start / files-start / content-end / content-end;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
margin-left: 12px;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.noscript {
|
|
||||||
text-align: center;
|
|
||||||
border: 3px solid var(--errorColor);
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer__mozLogo {
|
|
||||||
width: 112px;
|
|
||||||
height: 32px;
|
|
||||||
margin-bottom: -5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
line-height: 1.2;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 16px;
|
|
||||||
font-size: 17px;
|
|
||||||
font-weight: 500;
|
|
||||||
text-transform: uppercase;
|
|
||||||
text-align: center;
|
|
||||||
letter-spacing: 0.56px;
|
|
||||||
color: white;
|
|
||||||
background: black;
|
|
||||||
cursor: pointer;
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.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%;
|
|
||||||
padding: 24px;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
.invisible {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.noDisplay {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flexible {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-device-width: 720px), (max-width: 720px) {
|
|
||||||
body {
|
|
||||||
height: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main {
|
|
||||||
box-shadow: none;
|
|
||||||
align-items: center;
|
|
||||||
max-height: none;
|
|
||||||
width: 100%;
|
|
||||||
grid-template-columns: none;
|
|
||||||
grid-template-rows: 90px minmax(160px, 30vh) minmax(240px, 30vh) 70px;
|
|
||||||
grid-template-areas:
|
|
||||||
'promo'
|
|
||||||
'files'
|
|
||||||
'content'
|
|
||||||
'nav';
|
|
||||||
}
|
|
||||||
|
|
||||||
.split__left {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.description {
|
|
||||||
margin: 0 auto 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.uploads {
|
|
||||||
flex: none;
|
|
||||||
padding-top: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,7 +5,7 @@ import { copyToClipboard, delay, openLinksInNewTab, percent } from './utils';
|
||||||
import * as metrics from './metrics';
|
import * as metrics from './metrics';
|
||||||
import Archive from './archive';
|
import Archive from './archive';
|
||||||
import { bytes } from './utils';
|
import { bytes } from './utils';
|
||||||
import okDialog from './templates/okDialog';
|
import okDialog from './ui/okDialog';
|
||||||
|
|
||||||
export default function(state, emitter) {
|
export default function(state, emitter) {
|
||||||
let lastRender = 0;
|
let lastRender = 0;
|
||||||
|
@ -108,6 +108,9 @@ export default function(state, emitter) {
|
||||||
count: LIMITS.MAX_FILES_PER_ARCHIVE
|
count: LIMITS.MAX_FILES_PER_ARCHIVE
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
if (state.archive.numFiles === 0) {
|
||||||
|
state.archive = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
render();
|
render();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
|
|
||||||
module.exports = function() {
|
|
||||||
return html`<main class="main"></main>`;
|
|
||||||
};
|
|
|
@ -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`
|
|
||||||
<div class="page">
|
|
||||||
|
|
||||||
${title(state)}
|
|
||||||
|
|
||||||
<div class="error">${state.translate('errorPageHeader')}</div>
|
|
||||||
<img class="flexible" src="${assets.get('illustration_error.svg')}"/>
|
|
||||||
|
|
||||||
<div class="description">
|
|
||||||
${state.translate('uploadPageExplainer')}
|
|
||||||
</div>
|
|
||||||
<a class="link link--action" href="/">
|
|
||||||
${state.translate('sendYourFilesLink')}
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>`;
|
|
||||||
};
|
|
|
@ -1,34 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
const raw = require('choo/html/raw');
|
|
||||||
const title = require('../templates/title');
|
|
||||||
|
|
||||||
module.exports = function(state) {
|
|
||||||
return html`
|
|
||||||
<main class="main page">
|
|
||||||
${title(state)}
|
|
||||||
<div class="title">${state.translate('legalHeader')}</div>
|
|
||||||
${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/'
|
|
||||||
])
|
|
||||||
)}
|
|
||||||
</main>
|
|
||||||
`;
|
|
||||||
};
|
|
||||||
|
|
||||||
function replaceLinks(str, urls) {
|
|
||||||
let i = 0;
|
|
||||||
const s = str.replace(
|
|
||||||
/<a>([^<]+)<\/a>/g,
|
|
||||||
(m, v) => `<a href="${urls[i++]}">${v}</a>`
|
|
||||||
);
|
|
||||||
return `<div class="description">${s}</div>`;
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
const assets = require('../../../common/assets');
|
|
||||||
const title = require('../../templates/title');
|
|
||||||
|
|
||||||
module.exports = function(state) {
|
|
||||||
return html`
|
|
||||||
<main class="main page">
|
|
||||||
${title(state)}
|
|
||||||
<div class="error">${state.translate('expiredPageHeader')}</div>
|
|
||||||
<img src="${assets.get('illustration_expired.svg')}" id="expired-img">
|
|
||||||
<div class="description">
|
|
||||||
${state.translate('uploadPageExplainer')}
|
|
||||||
</div>
|
|
||||||
<a class="link link--action" href="/">
|
|
||||||
${state.translate('sendYourFilesLink')}
|
|
||||||
</a>
|
|
||||||
</main>`;
|
|
||||||
};
|
|
|
@ -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`
|
|
||||||
<main class="main page">
|
|
||||||
${titleSection(state)}
|
|
||||||
|
|
||||||
<div class="description">${state.translate('downloadMessage2')}</div>
|
|
||||||
${downloadPassword(state, emit)}
|
|
||||||
|
|
||||||
<a class="link link--action" href="/">
|
|
||||||
${state.translate('sendYourFilesLink')}
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
`;
|
|
||||||
};
|
|
|
@ -1,41 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
const downloadButton = require('../../templates/downloadButton');
|
|
||||||
const downloadedFiles = require('../../templates/uploadedFileList');
|
|
||||||
const split = require('../split');
|
|
||||||
|
|
||||||
module.exports = function(state, emit) {
|
|
||||||
const fileInfo = state.fileInfo;
|
|
||||||
|
|
||||||
const trySendLink = html`
|
|
||||||
<a class="link link--action" href="/">
|
|
||||||
${state.translate('sendYourFilesLink')}
|
|
||||||
</a>`;
|
|
||||||
const cancelButton = html`
|
|
||||||
<button class="btn--cancel"
|
|
||||||
onclick=${cancel}
|
|
||||||
>
|
|
||||||
${state.translate('downloadCancel')}
|
|
||||||
</button>
|
|
||||||
`;
|
|
||||||
|
|
||||||
const bottomLink =
|
|
||||||
state.transfer.state === 'downloading' ? cancelButton : trySendLink;
|
|
||||||
|
|
||||||
return split(
|
|
||||||
state,
|
|
||||||
emit,
|
|
||||||
downloadedFiles(fileInfo, state, emit),
|
|
||||||
html`
|
|
||||||
<div class="copySection">
|
|
||||||
<div class="description">${state.translate('downloadMessage2')}</div>
|
|
||||||
${downloadButton(state, emit)}
|
|
||||||
${bottomLink}
|
|
||||||
</div>`
|
|
||||||
);
|
|
||||||
|
|
||||||
function cancel() {
|
|
||||||
if (state.transfer.state === 'downloading') {
|
|
||||||
emit('cancel');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,105 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
const raw = require('choo/html/raw');
|
|
||||||
const notFound = require('../notFound');
|
|
||||||
const deletePopup = require('../../templates/popup');
|
|
||||||
const uploadedFileList = require('../../templates/uploadedFileList');
|
|
||||||
const timeLimitText = require('../../templates/timeLimitText');
|
|
||||||
const { allowedCopy, delay } = require('../../utils');
|
|
||||||
const split = require('../split');
|
|
||||||
|
|
||||||
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 split(
|
|
||||||
state,
|
|
||||||
emit,
|
|
||||||
uploadedFileList(file, state, emit),
|
|
||||||
html`
|
|
||||||
<div class="copySection">
|
|
||||||
<div class="sharePage__copyText">
|
|
||||||
${expireInfo(file, state.translate)}
|
|
||||||
${state.translate('copyUrlLabel')}
|
|
||||||
<div class="sharePage__passwordReminder ${passwordReminderClass}">(don't forget the password too)</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<input
|
|
||||||
id="fileUrl"
|
|
||||||
class="copySection__url"
|
|
||||||
type="url"
|
|
||||||
value="${file.url}"
|
|
||||||
readonly="true"/>
|
|
||||||
|
|
||||||
<button id="copyBtn"
|
|
||||||
class="btn copyBtn"
|
|
||||||
title="${state.translate('copyUrlFormButton')}"
|
|
||||||
onclick=${copyLink}>${state.translate('copyUrlFormButton')}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div class="sharePage__deletePopup">
|
|
||||||
${deletePopup(
|
|
||||||
state.translate('deletePopupText'),
|
|
||||||
state.translate('deletePopupYes'),
|
|
||||||
state.translate('deletePopupCancel'),
|
|
||||||
deleteFile
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="btn--cancel btn--delete"
|
|
||||||
title="${state.translate('deleteFileButton')}"
|
|
||||||
onclick=${showDeletePopup}>${state.translate('deleteFileButton')}
|
|
||||||
</button>
|
|
||||||
</div>`
|
|
||||||
);
|
|
||||||
|
|
||||||
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`<label>${state.translate('copiedUrl')}</label>`,
|
|
||||||
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' });
|
|
||||||
emit('pushState', '/');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function expireInfo(file, translate) {
|
|
||||||
const el = html`<div class="shareTitle">
|
|
||||||
${raw(
|
|
||||||
translate('expireInfo', {
|
|
||||||
downloadCount: translate('downloadCount', { num: file.dlimit }),
|
|
||||||
timespan: timeLimitText(translate, file.timeLimit)
|
|
||||||
})
|
|
||||||
)}
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
return el;
|
|
||||||
}
|
|
|
@ -1,80 +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 {
|
|
||||||
margin: 8px auto 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.copySection {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
margin: 24px auto;
|
|
||||||
width: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.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;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.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;
|
|
||||||
}
|
|
|
@ -1,63 +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`
|
|
||||||
<main class="main page signInPage">
|
|
||||||
${title(state)}
|
|
||||||
<div class="signIn__info flexible">
|
|
||||||
${state.translate('accountBenefitTitle')}
|
|
||||||
<ul>
|
|
||||||
<li>${state.translate('accountBenefitLargeFiles', {
|
|
||||||
size: bytes(LIMITS.MAX_FILE_SIZE)
|
|
||||||
})}</li>
|
|
||||||
<li>${state.translate('accountBenefitExpiry')}</li>
|
|
||||||
<li>${state.translate('accountBenefitSync')}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="signIn__form flexible">
|
|
||||||
<img class="signIn__firefoxLogo"
|
|
||||||
src="${assets.get('firefox_logo-only.svg')}"
|
|
||||||
width=56 height=56
|
|
||||||
alt="Firefox logo"/>
|
|
||||||
<div class="signIn__emailLabel">
|
|
||||||
${state.translate('signInEmailEnter')}
|
|
||||||
</div>
|
|
||||||
${state.translate('signInContinueMessage')}
|
|
||||||
<form
|
|
||||||
onsubmit=${submitEmail}
|
|
||||||
data-no-csrf>
|
|
||||||
<input
|
|
||||||
id="email-input"
|
|
||||||
type="text"
|
|
||||||
class="signIn__emailInput"
|
|
||||||
placeholder=${state.translate('emailEntryPlaceholder')}/>
|
|
||||||
<input
|
|
||||||
class='noDisplay'
|
|
||||||
id="email-submit"
|
|
||||||
type="submit"/>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<label class="btn" for="email-submit">
|
|
||||||
${state.translate('signInContinueButton')}
|
|
||||||
</label>
|
|
||||||
</main>
|
|
||||||
`;
|
|
||||||
|
|
||||||
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 = '';
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
const title = require('../templates/title');
|
|
||||||
const signupPromo = require('../templates/signupPromo');
|
|
||||||
const controlArea = require('../templates/controlArea');
|
|
||||||
|
|
||||||
module.exports = function(state, emit, a, b) {
|
|
||||||
return html`
|
|
||||||
<main class="main">
|
|
||||||
${controlArea(state, emit)}
|
|
||||||
<div class="split__left">
|
|
||||||
${title(state)}
|
|
||||||
${a}
|
|
||||||
</div>
|
|
||||||
<div class="split__right">
|
|
||||||
${b}
|
|
||||||
</div>
|
|
||||||
${signupPromo(state)}
|
|
||||||
</main>
|
|
||||||
`;
|
|
||||||
};
|
|
|
@ -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`
|
|
||||||
<div class="description">
|
|
||||||
<a href="https://github.com/mozilla/send/blob/master/docs/faq.md#why-is-my-browser-not-supported">
|
|
||||||
${state.translate('notSupportedLink')}
|
|
||||||
</a>
|
|
||||||
</div>`;
|
|
||||||
url =
|
|
||||||
'https://www.mozilla.org/firefox/new/?utm_campaign=send-acquisition&utm_medium=referral&utm_source=send.firefox.com';
|
|
||||||
buttonAction = html`
|
|
||||||
<div class="firefoxDownload__action">
|
|
||||||
Firefox<br><span class="firefoxDownload__text">${strings.button}</span>
|
|
||||||
</div>`;
|
|
||||||
} else {
|
|
||||||
strings = outdatedStrings(state);
|
|
||||||
url = 'https://support.mozilla.org/kb/update-firefox-latest-version';
|
|
||||||
buttonAction = html`
|
|
||||||
<div class="firefoxDownload__action">
|
|
||||||
${strings.button}
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<main class="main page unsupportedPage">
|
|
||||||
${title(state)}
|
|
||||||
<div class="error unsupportedPage__error">${strings.header}</div>
|
|
||||||
<div class="description flexible">
|
|
||||||
${strings.description}
|
|
||||||
${why}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flexible firefoxDownload">
|
|
||||||
<a href="${url}" class="firefoxDownload__button">
|
|
||||||
<img
|
|
||||||
src="${assets.get('firefox_logo-only.svg')}"
|
|
||||||
class="firefoxDownload__logo"
|
|
||||||
alt="Firefox"/>
|
|
||||||
${buttonAction}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="unsupportedPage__info">
|
|
||||||
${strings.explainer}
|
|
||||||
</div>
|
|
||||||
</main>`;
|
|
||||||
};
|
|
||||||
|
|
||||||
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')
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
const controlArea = require('../../templates/controlArea');
|
|
||||||
const archiveTile = require('../../templates/archiveTile');
|
|
||||||
|
|
||||||
module.exports = function(state, emit) {
|
|
||||||
const fileArea = state.storage.files.length
|
|
||||||
? html`<ul class="myUploads">
|
|
||||||
${state.storage.files.map(f => archiveTile(f, state))}
|
|
||||||
</ul>`
|
|
||||||
: html`<div>nothing to see here</div>`;
|
|
||||||
return html`<main class="main">
|
|
||||||
${controlArea(state, emit)}
|
|
||||||
<div class="wide">
|
|
||||||
<h1>${state.translate('myUploads')}</h1>
|
|
||||||
${fileArea}
|
|
||||||
</div>
|
|
||||||
</main>`;
|
|
||||||
};
|
|
|
@ -1,11 +0,0 @@
|
||||||
.myUploads {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
display: grid;
|
|
||||||
grid-gap: 12px;
|
|
||||||
grid-template-columns: repeat(auto-fit, 150px);
|
|
||||||
grid-auto-columns: 150px;
|
|
||||||
grid-auto-rows: 160px;
|
|
||||||
list-style-type: none;
|
|
||||||
overflow: scroll;
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
const fileManager = require('../../templates/fileManager');
|
|
||||||
const split = require('../split');
|
|
||||||
|
|
||||||
module.exports = function(state, emit) {
|
|
||||||
return split(state, emit, fileManager(state, emit));
|
|
||||||
};
|
|
|
@ -1,10 +0,0 @@
|
||||||
.archiveTile {
|
|
||||||
border: 1px solid #d7d7db;
|
|
||||||
border-radius: 4px;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.archiveTile:hover {
|
|
||||||
border: 1px solid lightblue;
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
|
|
||||||
module.exports = function(archive) {
|
|
||||||
return html`
|
|
||||||
<li id="${archive.id}" class="archiveTile">
|
|
||||||
<a href="/share/${archive.id}">${archive.name}</a>
|
|
||||||
</li>`;
|
|
||||||
};
|
|
|
@ -1,22 +0,0 @@
|
||||||
.controlArea {
|
|
||||||
border-right: 1px solid #d7d7db;
|
|
||||||
}
|
|
||||||
|
|
||||||
.controlArea > ul {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style-type: none;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.controlArea > ul > li {
|
|
||||||
margin: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-device-width: 720px), (max-width: 720px) {
|
|
||||||
.controlArea > ul {
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
const assets = require('../../../common/assets');
|
|
||||||
const userAccount = require('../userAccount');
|
|
||||||
|
|
||||||
module.exports = function(state, emit) {
|
|
||||||
const account = state.capabilities.account
|
|
||||||
? html`<li>
|
|
||||||
${userAccount(state, emit)}
|
|
||||||
</li>`
|
|
||||||
: null;
|
|
||||||
return html`
|
|
||||||
<nav class="controlArea">
|
|
||||||
<ul>
|
|
||||||
${account}
|
|
||||||
<li>
|
|
||||||
<a href="/">
|
|
||||||
<img src="${assets.get('addfile.svg')}"/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/uploads">
|
|
||||||
<img src="${assets.get('blue_file.svg')}"/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
`;
|
|
||||||
};
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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`
|
|
||||||
<button class="btn btn--download ${btnClass}"
|
|
||||||
onclick=${download}>
|
|
||||||
${btnText}
|
|
||||||
</button>`;
|
|
||||||
|
|
||||||
function download(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
event.target.disabled = true;
|
|
||||||
if (downloadState === 'ready') {
|
|
||||||
emit('download', state.fileInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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`
|
|
||||||
<div class="passwordSection">
|
|
||||||
|
|
||||||
<label
|
|
||||||
class="error passwordForm__error ${visible}"
|
|
||||||
for="password-input">
|
|
||||||
${state.translate('passwordTryAgain')}
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<form class="passwordForm" onsubmit=${checkPassword} data-no-csrf>
|
|
||||||
<input id="password-input"
|
|
||||||
class="input passwordForm__input"
|
|
||||||
maxlength="64"
|
|
||||||
autocomplete="off"
|
|
||||||
placeholder="${state.translate('unlockInputPlaceholder')}"
|
|
||||||
oninput=${inputChanged}
|
|
||||||
type="password" />
|
|
||||||
|
|
||||||
<input type="submit"
|
|
||||||
id="password-btn"
|
|
||||||
class="btn unlockBtn ${invalidBtn}"
|
|
||||||
value="${state.translate('unlockInputLabel')}"/>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
|
@ -1,68 +0,0 @@
|
||||||
/* 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');
|
|
||||||
|
|
||||||
module.exports = function(state, emit) {
|
|
||||||
const el = html`<div> ${raw(
|
|
||||||
state.translate('frontPageExpireInfo', {
|
|
||||||
downloadCount: '<select id=dlCount></select>',
|
|
||||||
timespan: '<select id=timespan></select>'
|
|
||||||
})
|
|
||||||
)}
|
|
||||||
</div>`;
|
|
||||||
if (el.__encoded) {
|
|
||||||
// we're rendering on the server
|
|
||||||
return el;
|
|
||||||
}
|
|
||||||
|
|
||||||
const counts = DEFAULTS.DOWNLOAD_COUNTS.filter(
|
|
||||||
i => state.capabilities.account || i <= state.user.maxDownloads
|
|
||||||
);
|
|
||||||
|
|
||||||
const dlCountSelect = el.querySelector('#dlCount');
|
|
||||||
el.replaceChild(
|
|
||||||
selectbox(
|
|
||||||
state.downloadCount || 1,
|
|
||||||
counts,
|
|
||||||
num => state.translate('downloadCount', { num }),
|
|
||||||
value => {
|
|
||||||
const max = state.user.maxDownloads;
|
|
||||||
if (value > max) {
|
|
||||||
state.modal = signupDialog();
|
|
||||||
value = max;
|
|
||||||
}
|
|
||||||
state.downloadCount = value;
|
|
||||||
emit('render');
|
|
||||||
}
|
|
||||||
),
|
|
||||||
dlCountSelect
|
|
||||||
);
|
|
||||||
|
|
||||||
const expires = DEFAULTS.EXPIRE_TIMES_SECONDS.filter(
|
|
||||||
i => state.capabilities.account || i <= state.user.maxExpireSeconds
|
|
||||||
);
|
|
||||||
|
|
||||||
const timeSelect = el.querySelector('#timespan');
|
|
||||||
el.replaceChild(
|
|
||||||
selectbox(
|
|
||||||
state.timeLimit || 86400,
|
|
||||||
expires,
|
|
||||||
num => timeLimitText(state.translate, num),
|
|
||||||
value => {
|
|
||||||
const max = state.user.maxExpireSeconds;
|
|
||||||
if (value > max) {
|
|
||||||
state.modal = signupDialog();
|
|
||||||
value = max;
|
|
||||||
}
|
|
||||||
state.timeLimit = value;
|
|
||||||
emit('render');
|
|
||||||
}
|
|
||||||
),
|
|
||||||
timeSelect
|
|
||||||
);
|
|
||||||
|
|
||||||
return el;
|
|
||||||
};
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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`
|
|
||||||
<li id="${file.id}">
|
|
||||||
<a class="fileToast ${activeClass}" href=${toastClick()}>
|
|
||||||
<div class="fileToast__content">
|
|
||||||
${fileIcon(file.name, file._hasPassword)}
|
|
||||||
<div class="fileData">
|
|
||||||
<p class="fileName">${fileName}</p>
|
|
||||||
<p class="fileInfo">
|
|
||||||
<span>${bytes(file.size)}</span> ·
|
|
||||||
<span>${state.translate('downloadCount', {
|
|
||||||
num: `${number(totalDownloads)} / ${number(downloadLimit)}`
|
|
||||||
})}</span>
|
|
||||||
<span>${remainingTime}</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
`;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
.fileIcon {
|
|
||||||
position: relative;
|
|
||||||
float: left;
|
|
||||||
pointer-events: none;
|
|
||||||
margin: 8px;
|
|
||||||
color: #fff;
|
|
||||||
background-image: url('../assets/blue_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;
|
|
||||||
}
|
|
|
@ -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`
|
|
||||||
<div class="fileIcon">
|
|
||||||
<div class="fileIcon__fileType">${type}</div>
|
|
||||||
<img class="fileIcon__lock ${lockClass}"src="${assets.get(
|
|
||||||
'lock-white.svg'
|
|
||||||
)}"/>
|
|
||||||
</div>`;
|
|
||||||
};
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
const file = require('../file');
|
|
||||||
|
|
||||||
module.exports = function(state) {
|
|
||||||
if (state.storage.files.length) {
|
|
||||||
return html`
|
|
||||||
<ul class="fileList">
|
|
||||||
${state.storage.files.map(f => file(f, state))}
|
|
||||||
</ul>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,101 +0,0 @@
|
||||||
.fileManager {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.uploadArea {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
text-align: center;
|
|
||||||
overflow: scroll;
|
|
||||||
transition: transform 150ms;
|
|
||||||
flex: 1;
|
|
||||||
min-height: 90px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.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;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
border: none;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.uploadOptions {
|
|
||||||
text-align: left;
|
|
||||||
font-size: 13px;
|
|
||||||
color: var(--lightTextColor);
|
|
||||||
margin: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.uploadOptions--faded {
|
|
||||||
opacity: 0.5;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.uploadCancel {
|
|
||||||
margin: 6px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.uploadCancel:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
|
@ -1,129 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
const assets = require('../../../common/assets');
|
|
||||||
const setPasswordSection = require('../setPasswordSection');
|
|
||||||
const uploadBox = require('../uploadedFileList');
|
|
||||||
const expireInfo = require('../expireInfo');
|
|
||||||
|
|
||||||
module.exports = function(state, emit) {
|
|
||||||
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 ? 'noDisplay' : '';
|
|
||||||
const selectFileClass = hasAnUpload > 0 ? 'btn--hidden' : '';
|
|
||||||
const sendFileClass = hasAnUpload > 0 ? 'btn--file' : '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`<div class="fileManager">
|
|
||||||
<label class="uploadArea"
|
|
||||||
ondragover=${dragover}
|
|
||||||
ondragleave=${dragleave}>
|
|
||||||
|
|
||||||
${uploadBox(state.archive, state, emit)}
|
|
||||||
|
|
||||||
<div class="uploadedFilesWrapper ${faded}">
|
|
||||||
<img
|
|
||||||
src="${assets.get('addfile.svg')}"
|
|
||||||
title="${state.translate('uploadSvgAlt')}"/>
|
|
||||||
<div class="uploadArea__msg">
|
|
||||||
${state.translate('uploadDropDragMessage')}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span class="uploadArea__clickMsg">
|
|
||||||
${state.translate('uploadDropClickMessage')}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<input id="file-upload"
|
|
||||||
class="inputFile fileBox"
|
|
||||||
type="file"
|
|
||||||
multiple
|
|
||||||
name="fileUploaded"
|
|
||||||
onfocus=${onfocus}
|
|
||||||
onblur=${onblur}
|
|
||||||
onchange=${addFiles} />
|
|
||||||
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<div class="uploadOptions ${optionClass}">
|
|
||||||
${expireInfo(state, emit)}
|
|
||||||
${setPasswordSection(state)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<label for="file-upload"
|
|
||||||
class="btn btn--file ${selectFileClass}"
|
|
||||||
title="${state.translate('uploadPageBrowseButton1')}">
|
|
||||||
${state.translate('uploadPageBrowseButton1')}
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="btn ${btnUploading} ${sendFileClass}"
|
|
||||||
onclick=${state.uploading ? noop : upload}
|
|
||||||
title="${btnText}">
|
|
||||||
${btnText}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button class="btn--cancel uploadCancel ${cancelVisible}"
|
|
||||||
onclick=${cancel}>
|
|
||||||
${state.translate('uploadingPageCancel')}
|
|
||||||
</button>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
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
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,95 +0,0 @@
|
||||||
.footer {
|
|
||||||
flex: none;
|
|
||||||
margin: 24px;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 600;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legalSection {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legalSection__link {
|
|
||||||
color: var(--lightTextColor);
|
|
||||||
white-space: nowrap;
|
|
||||||
margin-left: calc(var(--grid-basis) * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.legalSection__link:hover {
|
|
||||||
color: var(--textColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
.socialSection__icon {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
margin: 0 0 -5px calc(var(--grid-basis) * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown__only {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.feedback {
|
|
||||||
background-color: #000;
|
|
||||||
background-image: url('../assets/feedback.svg');
|
|
||||||
background-position: 2px 4px;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: 18px;
|
|
||||||
color: var(--primaryControlFGColor);
|
|
||||||
cursor: pointer;
|
|
||||||
display: block;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 12px;
|
|
||||||
padding: 5px 5px 5px 20px;
|
|
||||||
text-indent: 2px;
|
|
||||||
transition: all 250ms ease-in-out;
|
|
||||||
white-space: nowrap;
|
|
||||||
margin-left: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-device-width: 720px), (max-width: 720px) {
|
|
||||||
.footer {
|
|
||||||
justify-content: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer_hiddenIcon {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown__only {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.legalSection {
|
|
||||||
flex-direction: column;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
const assets = require('../../../common/assets');
|
|
||||||
const version = require('../../../package.json').version;
|
|
||||||
const { browserName } = require('../../utils');
|
|
||||||
|
|
||||||
module.exports = function(state) {
|
|
||||||
const browser = browserName();
|
|
||||||
const feedbackUrl = `https://qsurvey.mozilla.com/s3/txp-firefox-send?ver=${version}&browser=${browser}`;
|
|
||||||
const footer = html`<footer class="footer">
|
|
||||||
<div class="legalSection">
|
|
||||||
<a class="legalSection__link"
|
|
||||||
href="https://www.mozilla.org/about/legal">
|
|
||||||
${state.translate('footerLinkLegal')}
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="https://testpilot.firefox.com/about"
|
|
||||||
class="legalSection__link footer__dropdown footer__noDisplay">
|
|
||||||
${state.translate('footerLinkAbout')}
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="/legal"
|
|
||||||
class="legalSection__link footer__dropdown footer__noDisplay">
|
|
||||||
${state.translate('footerLinkTerms')}
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="https://www.mozilla.org/privacy/websites/#cookies"
|
|
||||||
class="legalSection__link footer__dropdown footer__noDisplay">
|
|
||||||
${state.translate('footerLinkCookies')}
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="https://www.mozilla.org/about/legal/report-infringement/"
|
|
||||||
class="legalSection__link footer__dropdown footer__noDisplay">
|
|
||||||
${state.translate('reportIPInfringement')}
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="https://github.com/mozilla/send"
|
|
||||||
class="legalSection__link footer__dropdown dropdown__only footer__noDisplay">
|
|
||||||
Github
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="https://twitter.com/FxTestPilot"
|
|
||||||
class="legalSection__link footer__dropdown dropdown__only footer__noDisplay">
|
|
||||||
Twitter
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<a href="${feedbackUrl}"
|
|
||||||
rel="noreferrer noopener"
|
|
||||||
class="feedback"
|
|
||||||
alt="Feedback"
|
|
||||||
target="_blank">${state.translate('siteFeedback')}
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="https://github.com/mozilla/send"
|
|
||||||
class="socialSection__link footer_hiddenIcon">
|
|
||||||
<img
|
|
||||||
class="socialSection__icon"
|
|
||||||
src="${assets.get('github-icon.svg')}"
|
|
||||||
alt="Github"/>
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="https://twitter.com/FxTestPilot"
|
|
||||||
class="socialSection__link footer_hiddenIcon">
|
|
||||||
<img
|
|
||||||
class="socialSection__icon"
|
|
||||||
src="${assets.get('twitter-icon.svg')}"
|
|
||||||
alt="Twitter"/>
|
|
||||||
</a>
|
|
||||||
</footer>`;
|
|
||||||
// HACK
|
|
||||||
// We only want to render this once because we
|
|
||||||
// toggle the targets of the links with utils/openLinksInNewTab
|
|
||||||
footer.isSameNode = function(target) {
|
|
||||||
return target && target.nodeName && target.nodeName === 'FOOTER';
|
|
||||||
};
|
|
||||||
return footer;
|
|
||||||
};
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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`
|
|
||||||
<div class="${classes}">
|
|
||||||
<div>
|
|
||||||
<img
|
|
||||||
src="${assets.get('firefox_logo-only.svg')}"
|
|
||||||
class="fxPromo__logo"
|
|
||||||
alt="Firefox"/>
|
|
||||||
<span>Send is brought to you by the all-new Firefox.
|
|
||||||
<a
|
|
||||||
class="link"
|
|
||||||
href="https://www.mozilla.org/firefox/new/?utm_campaign=send-acquisition&utm_medium=referral&utm_source=send.firefox.com"
|
|
||||||
onclick=${clicked}
|
|
||||||
>Download Firefox now ≫</a></span>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
function clicked() {
|
|
||||||
emit('experiment', { cd3: 'promo' });
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,15 +0,0 @@
|
||||||
.header {
|
|
||||||
flex: none;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
height: 64px;
|
|
||||||
background-color: white;
|
|
||||||
box-shadow: 0 -1px 0 0 #d7d7db7f, 0 2px 6px 0 #0000001e;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header h1 {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
const assets = require('../../../common/assets');
|
|
||||||
|
|
||||||
module.exports = function() {
|
|
||||||
const header = html`
|
|
||||||
<header class="header">
|
|
||||||
<a href="/"><img src="${assets.get('send_logo.svg')}"/></a>
|
|
||||||
<a href="/"><h1>Firefox Send</h1></a>
|
|
||||||
</header>`;
|
|
||||||
// HACK
|
|
||||||
// We only want to render this once because we
|
|
||||||
// toggle the targets of the links with utils/openLinksInNewTab
|
|
||||||
header.isSameNode = function(target) {
|
|
||||||
return target && target.nodeName && target.nodeName === 'HEADER';
|
|
||||||
};
|
|
||||||
return header;
|
|
||||||
};
|
|
|
@ -1,15 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
|
|
||||||
module.exports = function(state, emit) {
|
|
||||||
return html`
|
|
||||||
<div class="modal" onclick=${close}>
|
|
||||||
<div class="modal__box" onclick=${e => e.stopPropagation()}>
|
|
||||||
${state.modal(state, emit, close)}
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
function close(event) {
|
|
||||||
state.modal = null;
|
|
||||||
emit('render');
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
|
|
||||||
module.exports = function(message) {
|
|
||||||
return function(state, emit, close) {
|
|
||||||
return html`
|
|
||||||
<div class="okDialog">
|
|
||||||
<div class="okDialog__message">${message}</div>
|
|
||||||
<button class="btn" onclick=${close}>${state.translate(
|
|
||||||
'okButton'
|
|
||||||
)}</button>
|
|
||||||
</div>`;
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,11 +0,0 @@
|
||||||
.okDialog {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
max-width: 400px;
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.okDialog__message {
|
|
||||||
margin: 32px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
|
@ -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`
|
|
||||||
<div class="${sectionClass}">
|
|
||||||
<form
|
|
||||||
onsubmit=${onSubmit}
|
|
||||||
data-no-csrf>
|
|
||||||
|
|
||||||
<input id="password-input"
|
|
||||||
class="input passwordInput__fill"
|
|
||||||
autocomplete="off"
|
|
||||||
type="password"
|
|
||||||
oninput=${inputChanged}
|
|
||||||
onfocus=${focused}
|
|
||||||
placeholder="${
|
|
||||||
hasPassword ? passwordPlaceholder(state.password) : placeholder
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
</form>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
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, '•') : '••••••••••••';
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
|
|
||||||
module.exports = function(msg, confirmText, cancelText, confirmCallback) {
|
|
||||||
return html`
|
|
||||||
<div class="popup" onblur=${hide} tabindex="-1">
|
|
||||||
<div class="popup__message">${msg}</div>
|
|
||||||
<div class="popup__action">
|
|
||||||
<div>
|
|
||||||
<span class="popup__no" onclick=${hide}>${cancelText}</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="popup__yes" onclick=${confirmCallback}>${confirmText}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
function hide(e) {
|
|
||||||
e.stopPropagation();
|
|
||||||
const popup = document.querySelector('.popup.popup--show');
|
|
||||||
if (popup) {
|
|
||||||
popup.classList.remove('popup--show');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
|
|
||||||
module.exports = function(selected, options, translate, changed) {
|
|
||||||
const id = `select-${Math.random()}`;
|
|
||||||
let x = selected;
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<select class="selectBox" id="${id}" onchange=${choose}>
|
|
||||||
${options.map(
|
|
||||||
i =>
|
|
||||||
html`<option value="${i}" ${
|
|
||||||
i === selected ? 'selected' : ''
|
|
||||||
}>${translate(i)}</option>`
|
|
||||||
)}
|
|
||||||
</select>`;
|
|
||||||
|
|
||||||
function choose(event) {
|
|
||||||
const target = event.target;
|
|
||||||
const value = +target.value;
|
|
||||||
|
|
||||||
if (x !== value) {
|
|
||||||
x = value;
|
|
||||||
changed(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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 ? '' : 'addPasswordMessage';
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<div class="setPasswordSection">
|
|
||||||
<div class="checkbox">
|
|
||||||
<input
|
|
||||||
class="checkbox__input" id="add-password"
|
|
||||||
type="checkbox"
|
|
||||||
${checked}
|
|
||||||
autocomplete="off"
|
|
||||||
onchange=${togglePasswordInput}/>
|
|
||||||
<label class="checkbox__label" for="add-password">
|
|
||||||
${label && state.translate(label)}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
${passwordInput(state)}
|
|
||||||
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
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 = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,57 +0,0 @@
|
||||||
.setPasswordSection {
|
|
||||||
display: flex;
|
|
||||||
padding: 10px 0;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.checkbox {
|
|
||||||
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;
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
/* globals LIMITS */
|
|
||||||
const html = require('choo/html');
|
|
||||||
const bytes = require('../../utils').bytes;
|
|
||||||
|
|
||||||
// TODO: there's some duplication here with the signin page
|
|
||||||
module.exports = function() {
|
|
||||||
return function(state, emit, close) {
|
|
||||||
return html`
|
|
||||||
<div class="signupDialog">
|
|
||||||
<div class="signupDialog__message">
|
|
||||||
${state.translate('accountBenefitTitle')}
|
|
||||||
<ul>
|
|
||||||
<li>${state.translate('accountBenefitLargeFiles', {
|
|
||||||
size: bytes(LIMITS.MAX_FILE_SIZE)
|
|
||||||
})}</li>
|
|
||||||
<li>${state.translate('accountBenefitExpiry')}</li>
|
|
||||||
<li>${state.translate('accountBenefitSync')}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<form
|
|
||||||
onsubmit=${submitEmail}
|
|
||||||
data-no-csrf>
|
|
||||||
<input
|
|
||||||
id="email-input"
|
|
||||||
type="text"
|
|
||||||
class="signupDialog__emailInput"
|
|
||||||
placeholder=${state.translate('emailEntryPlaceholder')}/>
|
|
||||||
<input
|
|
||||||
class='noDisplay'
|
|
||||||
id="email-submit"
|
|
||||||
type="submit"/>
|
|
||||||
</form>
|
|
||||||
<label class="btn" for="email-submit">
|
|
||||||
${state.translate('signInMenuOption')}
|
|
||||||
</label>
|
|
||||||
<button
|
|
||||||
class="btn--cancel"
|
|
||||||
title="${state.translate('deletePopupCancel')}"
|
|
||||||
onclick=${close}>${state.translate('deletePopupCancel')}
|
|
||||||
</button>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
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 = '';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
|
|
||||||
module.exports = function(state) {
|
|
||||||
if (state.user.loggedIn || !state.capabilities.account) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<a href="/signin" class="signupPromo">
|
|
||||||
<div class="signupPromo__title">${state.translate('signInPromoText')}</div>
|
|
||||||
<div class="signupPromo__info">${state.translate('signInExplanation')}</div>
|
|
||||||
</a>
|
|
||||||
`;
|
|
||||||
};
|
|
|
@ -1,42 +0,0 @@
|
||||||
.signupPromo {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: calc(var(--grid-basis) * 12.5);
|
|
||||||
width: calc(var(--grid-basis) * 12.5);
|
|
||||||
border: 3px solid black;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
text-align: center;
|
|
||||||
justify-content: center;
|
|
||||||
transition: background 100ms;
|
|
||||||
margin: 24px;
|
|
||||||
grid-area: content;
|
|
||||||
justify-self: right;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signupPromo:hover {
|
|
||||||
background: #ff1ad9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signupPromo__title {
|
|
||||||
color: black;
|
|
||||||
font-size: 22px;
|
|
||||||
font-weight: 900;
|
|
||||||
padding: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signupPromo__info {
|
|
||||||
padding: 6px;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-device-width: 720px), (max-width: 720px) {
|
|
||||||
.signupPromo {
|
|
||||||
grid-area: promo;
|
|
||||||
margin: 0;
|
|
||||||
justify-self: auto;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -1,11 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
|
|
||||||
module.exports = function(state) {
|
|
||||||
return html`
|
|
||||||
<div class="boxTitle">
|
|
||||||
${state.translate('uploadPageHeader')}
|
|
||||||
<div class="boxSubtitle">
|
|
||||||
${state.translate('pageHeaderCredits')}
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
};
|
|
|
@ -1,9 +0,0 @@
|
||||||
.boxTitle {
|
|
||||||
margin: 24px;
|
|
||||||
text-align: center;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.boxSubtitle {
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
|
@ -1,39 +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 cancelVisible =
|
|
||||||
state.route === '/' && !state.uploading
|
|
||||||
? 'uploadedFile__cancel--visible'
|
|
||||||
: '';
|
|
||||||
|
|
||||||
function cancel(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
if (state.route === '/') {
|
|
||||||
emit('removeUpload', { index });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<li class="uploadedFile" id="${file.id}">
|
|
||||||
|
|
||||||
${fileIcon(file.name, hasPassword)}
|
|
||||||
|
|
||||||
<div class="uploadedFile__cancel ${cancelVisible}"
|
|
||||||
onclick=${cancel}>
|
|
||||||
<img
|
|
||||||
src="${assets.get('close-16.svg')}"
|
|
||||||
alt="cancel"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="uploadedFile__fileData">
|
|
||||||
<p class="uploadedFile__fileName">${file.name}</p>
|
|
||||||
<p class="uploadedFile__fileInfo">
|
|
||||||
<span>${bytes(file.size)}</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
`;
|
|
||||||
};
|
|
|
@ -1,66 +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__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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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`
|
|
||||||
<ul class="uploadedFiles">
|
|
||||||
${files.map((f, i) => file(f, i, state, emit, archive._hasPassword))}
|
|
||||||
</ul>
|
|
||||||
`;
|
|
||||||
};
|
|
|
@ -1,9 +0,0 @@
|
||||||
.uploadedFiles {
|
|
||||||
background: rgba(132, 193, 255, 0.1);
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
align-content: center;
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: scroll;
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
|
@ -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`
|
|
||||||
<ul
|
|
||||||
class="account_dropdown"
|
|
||||||
onblur=${hideMenu}
|
|
||||||
tabindex="-1">
|
|
||||||
<li class="account_dropdown__text">
|
|
||||||
${user.email}
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a class="account_dropdown__link" onclick=${logout}>${state.translate(
|
|
||||||
'logOut'
|
|
||||||
)}</a>
|
|
||||||
</li>
|
|
||||||
</ul>`
|
|
||||||
: html`
|
|
||||||
<ul
|
|
||||||
class="account_dropdown"
|
|
||||||
onblur=${hideMenu}
|
|
||||||
tabindex="-1">
|
|
||||||
<li>
|
|
||||||
<a class="account_dropdown__link" onclick=${login}>${state.translate(
|
|
||||||
'signInMenuOption'
|
|
||||||
)}</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
`;
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<div class="account">
|
|
||||||
<div class="account__avatar">
|
|
||||||
<img
|
|
||||||
class="account__avatar"
|
|
||||||
src="${user.avatar}"
|
|
||||||
onclick=${avatarClick}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
${menu}
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
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');
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,74 +0,0 @@
|
||||||
.account {
|
|
||||||
/* padding: 12px; */
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account__avatar {
|
|
||||||
height: 32px;
|
|
||||||
width: 32px;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account_dropdown {
|
|
||||||
z-index: 2;
|
|
||||||
position: absolute;
|
|
||||||
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;
|
|
||||||
white-space: nowrap;
|
|
||||||
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;
|
|
||||||
}
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
const html = require('choo/html');
|
||||||
|
|
||||||
|
module.exports = function(message) {
|
||||||
|
return function(state, emit, close) {
|
||||||
|
return html`
|
||||||
|
<div class="flex flex-col max-w-xs p-4">
|
||||||
|
<div class="text-center m-8">${message}</div>
|
||||||
|
<button class="border rounded bg-blue text-white leading-loose w-full" onclick=${close}>${state.translate(
|
||||||
|
'okButton'
|
||||||
|
)}</button>
|
||||||
|
</div>`;
|
||||||
|
};
|
||||||
|
};
|
Loading…
Reference in New Issue