Merge pull request #1007 from mozilla/comp
converting some things to choo/component
This commit is contained in:
commit
91a8c66e0c
20 changed files with 373 additions and 396 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -6,6 +6,7 @@ dist
|
|||
.nyc_output
|
||||
.tox
|
||||
.pytest_cache
|
||||
*.iml
|
||||
android/app/src/main/assets
|
||||
ios/send-ios/assets/ios.js
|
||||
ios/send-ios/assets/vendor.js
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.id="android" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
|
@ -24,7 +24,7 @@ import html from 'choo/html';
|
|||
import Raven from 'raven-js';
|
||||
|
||||
import assets from '../common/assets';
|
||||
import header from '../app/ui/header';
|
||||
import Header from '../app/ui/header';
|
||||
import locale from '../common/locales';
|
||||
import storage from '../app/storage';
|
||||
import controller from '../app/controller';
|
||||
|
@ -59,7 +59,7 @@ function body(main) {
|
|||
>
|
||||
<img src="${assets.get('preferences.png')}" />
|
||||
</a>
|
||||
${header(state, emit)} ${main(state, emit)}
|
||||
${state.cache(Header, 'header').render()} ${main(state, emit)}
|
||||
</body>
|
||||
`;
|
||||
|
||||
|
|
|
@ -1,196 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="android-gradle" name="Android-Gradle">
|
||||
<configuration>
|
||||
<option name="GRADLE_PROJECT_PATH" value=":app" />
|
||||
</configuration>
|
||||
</facet>
|
||||
<facet type="android" name="Android">
|
||||
<configuration>
|
||||
<option name="SELECTED_BUILD_VARIANT" value="debug" />
|
||||
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
|
||||
<afterSyncTasks>
|
||||
<task>generateDebugSources</task>
|
||||
</afterSyncTasks>
|
||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
||||
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
|
||||
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
||||
</configuration>
|
||||
</facet>
|
||||
<facet type="kotlin-language" name="Kotlin">
|
||||
<configuration version="3" platform="JVM 1.8" useProjectSettings="false">
|
||||
<compilerSettings />
|
||||
<compilerArguments>
|
||||
<option name="destination" value="$MODULE_DIR$/build/tmp/kotlin-classes/debug" />
|
||||
<option name="noStdlib" value="true" />
|
||||
<option name="noReflect" value="true" />
|
||||
<option name="moduleName" value="app_debug" />
|
||||
<option name="jvmTarget" value="1.8" />
|
||||
<option name="addCompilerBuiltIns" value="true" />
|
||||
<option name="loadBuiltInsFromDependencies" value="true" />
|
||||
<option name="languageVersion" value="1.2" />
|
||||
<option name="apiVersion" value="1.2" />
|
||||
<option name="pluginOptions">
|
||||
<array>
|
||||
<option value="plugin:org.jetbrains.kotlin.android:experimental=false" />
|
||||
<option value="plugin:org.jetbrains.kotlin.android:enabled=true" />
|
||||
<option value="plugin:org.jetbrains.kotlin.android:defaultCacheImplementation=hashMap" />
|
||||
</array>
|
||||
</option>
|
||||
<option name="pluginClasspaths">
|
||||
<array>
|
||||
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.2.60/69596054ff0e04bb3f38cd906dce6854a9d3438d/kotlin-android-extensions-1.2.60.jar" />
|
||||
</array>
|
||||
</option>
|
||||
</compilerArguments>
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
|
||||
<output url="file://$MODULE_DIR$/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/build/intermediates/javac/debugUnitTest/compileDebugUnitTestJavaWithJavac/classes" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/not_namespaced_r_class_sources/debug/processDebugResources/r" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/not_namespaced_r_class_sources/debugAndroidTest/processDebugAndroidTestResources/r" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/test/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/shaders" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/annotation_processor_list" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/apk_list" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/build-info" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/builds" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/check-libraries" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/check-manifest" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/checkDebugClasspath" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/compatible_screen_manifest" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-runtime-classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-verifier" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-apk" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_main_apk_resources" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_merged_manifests" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_split_apk_resources" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javac" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifest-checker" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged_assets" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged_manifests" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/prebuild" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/processed_res" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/reload-dex" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/resources" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shader_assets" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/split-apk" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/split_list" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/kotlin" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android API 27 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Gradle: net.java.dev.jna:jna-4.5.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test:runner-1.0.2" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:common:1.1.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-annotations:27.1.1@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib:1.2.61@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:animated-vector-drawable-27.1.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-compat-27.1.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:viewmodel-1.1.0" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Gradle: com.squareup:javawriter:2.1.1@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-vector-drawable-27.1.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-core-ui-27.1.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-1.1.2" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-core-utils-27.1.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: org.jetbrains:annotations:13.0@jar" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Gradle: com.google.code.findbugs:jsr305:2.0.1@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.github.delight-im:Android-AdvancedWebView-v3.0.0" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test.espresso:espresso-core-3.0.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Gradle: javax.inject:javax.inject:1@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: org.jetbrains.kotlinx:kotlinx-coroutines-android:0.23.4@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-fragment-27.1.1" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Gradle: junit:junit:4.12@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.core:runtime-1.1.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.61@jar" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-core:1.3@jar" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test:monitor-1.0.2" level="project" />
|
||||
<orderEntry type="library" name="Gradle: org.jetbrains.kotlinx:kotlinx-coroutines-core:0.23.4@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:appcompat-v7-27.1.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: org.mozilla.components:service-firefox-accounts-0.26.0" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test.espresso:espresso-idling-resource-3.0.2" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-solver:1.1.2@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: org.mozilla.fxa_client:fxa_client-0.5.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:livedata-core-1.1.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: org.jetbrains.kotlinx:kotlinx-coroutines-core-common:0.23.4@jar" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-library:1.3@jar" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-integration:1.3@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: org.jetbrains.kotlinx:atomicfu-common:0.10.3@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.core:common:1.1.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.2.61@jar" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Gradle: net.sf.kxml:kxml2:2.3.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:runtime-1.1.0" level="project" />
|
||||
</component>
|
||||
</module>
|
|
@ -35,8 +35,7 @@ dependencies {
|
|||
}
|
||||
|
||||
task generateAndLinkBundle(type: Exec, description: 'Generate the android.js bundle and link it into the assets directory') {
|
||||
commandLine 'node'
|
||||
args '../generateAndLinkBundle.js'
|
||||
commandLine './buildAssets.sh'
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
|
|
7
android/app/buildAssets.sh
Executable file
7
android/app/buildAssets.sh
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
npm run build
|
||||
rm -rf src/main/assets
|
||||
mkdir -p src/main/assets
|
||||
cp -R ../../dist/* src/main/assets
|
||||
sed -i '' 's/url(/url(\/android_asset/g' src/main/assets/app.*.css
|
|
@ -1,10 +0,0 @@
|
|||
const child_process = require('child_process');
|
||||
const path = require('path');
|
||||
|
||||
child_process.execSync('npm run build');
|
||||
child_process.execSync(
|
||||
`cp -R ${path.resolve(__dirname, '../dist/*')} ${path.resolve(
|
||||
__dirname,
|
||||
'app/src/main/assets'
|
||||
)}`
|
||||
);
|
|
@ -18,6 +18,7 @@ module.exports = function(state, emit) {
|
|||
}
|
||||
|
||||
const archives = state.storage.files
|
||||
.filter(archive => !archive.expired)
|
||||
.map(archive => archiveTile(state, emit, archive))
|
||||
.reverse();
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import 'fast-text-encoding'; // MS Edge support
|
||||
import 'fluent-intl-polyfill';
|
||||
import choo from 'choo';
|
||||
import nanotiming from 'nanotiming';
|
||||
import routes from './routes';
|
||||
import capabilities from './capabilities';
|
||||
import locale from '../common/locales';
|
||||
|
@ -14,7 +16,10 @@ import './main.css';
|
|||
import User from './user';
|
||||
|
||||
(async function start() {
|
||||
const app = routes();
|
||||
const app = routes(choo());
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
nanotiming.disabled = true;
|
||||
}
|
||||
if (navigator.doNotTrack !== '1' && window.RAVEN_CONFIG) {
|
||||
Raven.config(window.SENTRY_ID, window.RAVEN_CONFIG).install();
|
||||
}
|
||||
|
|
|
@ -1,37 +1,8 @@
|
|||
const choo = require('choo');
|
||||
const html = require('choo/html');
|
||||
const nanotiming = require('nanotiming');
|
||||
const download = require('./ui/download');
|
||||
const footer = require('./ui/footer');
|
||||
const fxPromo = require('./ui/fxPromo');
|
||||
const header = require('./ui/header');
|
||||
const body = require('./ui/body');
|
||||
|
||||
nanotiming.disabled = true;
|
||||
|
||||
function banner(state, emit) {
|
||||
if (state.promo && !state.route.startsWith('/unsupported/')) {
|
||||
return fxPromo(state, emit);
|
||||
}
|
||||
}
|
||||
|
||||
function body(main) {
|
||||
return function(state, emit) {
|
||||
const b = html`<body class="flex flex-col items-center font-sans bg-blue-lightest md:h-screen md:bg-grey-lightest">
|
||||
${banner(state, emit)}
|
||||
${header(state, emit)}
|
||||
${main(state, emit)}
|
||||
${footer(state)}
|
||||
</body>`;
|
||||
if (state.layout) {
|
||||
// server side only
|
||||
return state.layout(state, b);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = function() {
|
||||
const app = choo();
|
||||
module.exports = function(app = choo()) {
|
||||
app.route('/', body(require('./ui/home')));
|
||||
app.route('/download/:id', body(download));
|
||||
app.route('/download/:id/:key', body(download));
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import assets from '../common/assets';
|
||||
import { version } from '../package.json';
|
||||
import Keychain from './keychain';
|
||||
import { downloadStream } from './api';
|
||||
import { transformStream } from './streams';
|
||||
|
@ -8,11 +10,11 @@ let noSave = false;
|
|||
const map = new Map();
|
||||
|
||||
self.addEventListener('install', event => {
|
||||
self.skipWaiting();
|
||||
event.waitUntil(precache());
|
||||
});
|
||||
|
||||
self.addEventListener('activate', event => {
|
||||
self.clients.claim();
|
||||
event.waitUntil(self.clients.claim());
|
||||
});
|
||||
|
||||
async function decryptStream(id) {
|
||||
|
@ -77,11 +79,32 @@ async function decryptStream(id) {
|
|||
}
|
||||
}
|
||||
|
||||
async function precache() {
|
||||
const oldCaches = await caches.keys();
|
||||
for (const c of oldCaches) {
|
||||
if (c !== version) {
|
||||
await caches.delete(c);
|
||||
}
|
||||
}
|
||||
const cache = await caches.open(version);
|
||||
const images = assets.match(/.*\.(png|svg|jpg)$/);
|
||||
await cache.addAll(images);
|
||||
return self.skipWaiting();
|
||||
}
|
||||
|
||||
async function cachedOrFetch(req) {
|
||||
const cache = await caches.open(version);
|
||||
const cached = await cache.match(req);
|
||||
return cached || fetch(req);
|
||||
}
|
||||
|
||||
self.onfetch = event => {
|
||||
const req = event.request;
|
||||
const match = /\/api\/download\/([A-Fa-f0-9]{4,})/.exec(req.url);
|
||||
if (match) {
|
||||
event.respondWith(decryptStream(match[1]));
|
||||
} else {
|
||||
event.respondWith(cachedOrFetch(req));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,58 +1,103 @@
|
|||
const html = require('choo/html');
|
||||
const Component = require('choo/component');
|
||||
|
||||
module.exports = function(state, emit) {
|
||||
if (!state.capabilities.account) {
|
||||
return null;
|
||||
class Account extends Component {
|
||||
constructor(name, state, emit) {
|
||||
super(name);
|
||||
this.state = state;
|
||||
this.emit = emit;
|
||||
this.enabled = state.capabilities.account;
|
||||
this.local = state.components[name] = {};
|
||||
this.setState();
|
||||
}
|
||||
const user = state.user;
|
||||
if (!user.loggedIn) {
|
||||
return html`<button
|
||||
class="p-2 border rounded border-white text-white hover:bg-white hover:text-blue md:text-blue md:border-blue md:hover:text-white md:hover:bg-blue"
|
||||
onclick=${login}>
|
||||
${state.translate('signInMenuOption')}
|
||||
</button>`;
|
||||
}
|
||||
return html`<div class="relative h-8">
|
||||
<input
|
||||
type="image"
|
||||
alt="${user.email}"
|
||||
class="w-8 h-8 rounded-full text-white"
|
||||
src="${user.avatar}"
|
||||
onclick=${avatarClick}/>
|
||||
<ul
|
||||
id="accountMenu"
|
||||
class="invisible list-reset absolute pin-t pin-r mt-10 pt-2 pb-2 bg-white shadow-md whitespace-no-wrap outline-none z-50"
|
||||
onblur="${hideMenu}"
|
||||
tabindex="-1">
|
||||
<li class="p-2 text-grey-dark">${user.email}</li>
|
||||
<li>
|
||||
<a class="block px-4 py-2 text-grey-darkest hover:bg-blue hover:text-white cursor-pointer" onclick=${logout}>
|
||||
${state.translate('logOut')}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>`;
|
||||
|
||||
function avatarClick(event) {
|
||||
avatarClick(event) {
|
||||
event.preventDefault();
|
||||
const menu = document.getElementById('accountMenu');
|
||||
menu.classList.toggle('invisible');
|
||||
menu.focus();
|
||||
}
|
||||
|
||||
function hideMenu(event) {
|
||||
hideMenu(event) {
|
||||
event.stopPropagation();
|
||||
const menu = document.getElementById('accountMenu');
|
||||
menu.classList.add('invisible');
|
||||
}
|
||||
|
||||
function login(event) {
|
||||
login(event) {
|
||||
event.preventDefault();
|
||||
emit('login');
|
||||
this.emit('login');
|
||||
}
|
||||
|
||||
function logout(event) {
|
||||
logout(event) {
|
||||
event.preventDefault();
|
||||
emit('logout');
|
||||
this.emit('logout');
|
||||
}
|
||||
};
|
||||
|
||||
changed() {
|
||||
return this.local.loggedIn !== this.state.user.loggedIn;
|
||||
}
|
||||
|
||||
setState() {
|
||||
const changed = this.changed();
|
||||
if (changed) {
|
||||
this.local.loggedIn = this.state.user.loggedIn;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
update() {
|
||||
return this.setState();
|
||||
}
|
||||
|
||||
createElement() {
|
||||
if (!this.enabled) {
|
||||
return html`
|
||||
<div></div>
|
||||
`;
|
||||
}
|
||||
const user = this.state.user;
|
||||
const translate = this.state.translate;
|
||||
if (!this.local.loggedIn) {
|
||||
return html`
|
||||
<div>
|
||||
<button
|
||||
class="p-2 border rounded border-white text-white hover:bg-white hover:text-blue md:text-blue md:border-blue md:hover:text-white md:hover:bg-blue"
|
||||
onclick="${e => this.login(e)}"
|
||||
>
|
||||
${translate('signInMenuOption')}
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
return html`
|
||||
<div class="relative h-8">
|
||||
<input
|
||||
type="image"
|
||||
alt="${user.email}"
|
||||
class="w-8 h-8 rounded-full text-white"
|
||||
src="${user.avatar}"
|
||||
onclick="${e => this.avatarClick(e)}"
|
||||
/>
|
||||
<ul
|
||||
id="accountMenu"
|
||||
class="invisible list-reset absolute pin-t pin-r mt-10 pt-2 pb-2 bg-white shadow-md whitespace-no-wrap outline-none z-50"
|
||||
onblur="${e => this.hideMenu(e)}"
|
||||
tabindex="-1"
|
||||
>
|
||||
<li class="p-2 text-grey-dark">${user.email}</li>
|
||||
<li>
|
||||
<a
|
||||
class="block px-4 py-2 text-grey-darkest hover:bg-blue hover:text-white cursor-pointer"
|
||||
onclick="${e => this.logout(e)}"
|
||||
>
|
||||
${translate('logOut')}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Account;
|
||||
|
|
28
app/ui/body.js
Normal file
28
app/ui/body.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
const html = require('choo/html');
|
||||
const Promo = require('./promo');
|
||||
const Header = require('./header');
|
||||
const Footer = require('./footer');
|
||||
|
||||
function banner(state) {
|
||||
if (state.promo && !state.route.startsWith('/unsupported/')) {
|
||||
return state.cache(Promo, 'promo').render();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function body(main) {
|
||||
return function(state, emit) {
|
||||
const b = html`
|
||||
<body
|
||||
class="flex flex-col items-center font-sans bg-blue-lightest md:h-screen md:bg-grey-lightest"
|
||||
>
|
||||
${banner(state, emit)} ${state.cache(Header, 'header').render()}
|
||||
${main(state, emit)} ${state.cache(Footer, 'footer').render()}
|
||||
</body>
|
||||
`;
|
||||
if (state.layout) {
|
||||
// server side only
|
||||
return state.layout(state, b);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
};
|
118
app/ui/footer.js
118
app/ui/footer.js
|
@ -1,52 +1,74 @@
|
|||
const html = require('choo/html');
|
||||
const Component = require('choo/component');
|
||||
const version = require('../../package.json').version;
|
||||
const { browserName } = require('../utils');
|
||||
|
||||
module.exports = function(state) {
|
||||
const browser = browserName();
|
||||
const feedbackUrl = `https://qsurvey.mozilla.com/s3/txp-firefox-send?ver=${version}&browser=${browser}`;
|
||||
const footer = html`<footer class="flex flex-col md:flex-row items-start w-full flex-none self-start p-6 font-medium text-xs text-grey-dark md:items-center justify-between bg-grey-lightest">
|
||||
<a class="mozilla-logo pb-10 md:pb-0 m-2"
|
||||
href="https://www.mozilla.org/">
|
||||
Mozilla
|
||||
</a>
|
||||
<ul class="list-reset flex flex-col md:flex-row items-start md:items-center md:justify-end">
|
||||
<li class="m-2"><a
|
||||
href="https://www.mozilla.org/about/legal">
|
||||
${state.translate('footerLinkLegal')}
|
||||
</a></li>
|
||||
<li class="m-2"><a
|
||||
href="/legal">
|
||||
${state.translate('footerLinkTerms')}
|
||||
</a></li>
|
||||
<li class="m-2"><a
|
||||
href="https://www.mozilla.org/privacy/websites/#cookies">
|
||||
${state.translate('footerLinkCookies')}
|
||||
</a></li>
|
||||
<li class="m-2"><a
|
||||
href="https://www.mozilla.org/about/legal/report-infringement/">
|
||||
${state.translate('reportIPInfringement')}
|
||||
</a></li>
|
||||
<li class="m-2"><a
|
||||
href="https://github.com/mozilla/send">GitHub
|
||||
</a></li>
|
||||
<li class="m-2"><a
|
||||
href="https://twitter.com/FxTestPilot">Twitter
|
||||
</a></li>
|
||||
<li class="m-2"><a href="${feedbackUrl}"
|
||||
rel="noreferrer noopener"
|
||||
class="feedback-link"
|
||||
alt="Feedback"
|
||||
target="_blank">
|
||||
${state.translate('siteFeedback')}
|
||||
</a></li>
|
||||
</ul>
|
||||
</footer>`;
|
||||
// HACK
|
||||
// We only want to render this once because we
|
||||
// toggle the targets of the links with utils/openLinksInNewTab
|
||||
footer.isSameNode = function(target) {
|
||||
return target && target.nodeName && target.nodeName === 'FOOTER';
|
||||
};
|
||||
return footer;
|
||||
};
|
||||
class Footer extends Component {
|
||||
constructor(name, state) {
|
||||
super(name);
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
update() {
|
||||
return false;
|
||||
}
|
||||
|
||||
createElement() {
|
||||
const translate = this.state.translate;
|
||||
const browser = browserName();
|
||||
const feedbackUrl = `https://qsurvey.mozilla.com/s3/txp-firefox-send?ver=${version}&browser=${browser}`;
|
||||
return html`
|
||||
<footer
|
||||
class="flex flex-col md:flex-row items-start w-full flex-none self-start p-6 font-medium text-xs text-grey-dark md:items-center justify-between bg-grey-lightest"
|
||||
>
|
||||
<a
|
||||
class="mozilla-logo pb-10 md:pb-0 m-2"
|
||||
href="https://www.mozilla.org/"
|
||||
>
|
||||
Mozilla
|
||||
</a>
|
||||
<ul
|
||||
class="list-reset flex flex-col md:flex-row items-start md:items-center md:justify-end"
|
||||
>
|
||||
<li class="m-2">
|
||||
<a href="https://www.mozilla.org/about/legal">
|
||||
${translate('footerLinkLegal')}
|
||||
</a>
|
||||
</li>
|
||||
<li class="m-2">
|
||||
<a href="/legal"> ${translate('footerLinkTerms')} </a>
|
||||
</li>
|
||||
<li class="m-2">
|
||||
<a href="https://www.mozilla.org/privacy/websites/#cookies">
|
||||
${translate('footerLinkCookies')}
|
||||
</a>
|
||||
</li>
|
||||
<li class="m-2">
|
||||
<a href="https://www.mozilla.org/about/legal/report-infringement/">
|
||||
${translate('reportIPInfringement')}
|
||||
</a>
|
||||
</li>
|
||||
<li class="m-2">
|
||||
<a href="https://github.com/mozilla/send">GitHub </a>
|
||||
</li>
|
||||
<li class="m-2">
|
||||
<a href="https://twitter.com/FxTestPilot">Twitter </a>
|
||||
</li>
|
||||
<li class="m-2">
|
||||
<a
|
||||
href="${feedbackUrl}"
|
||||
rel="noreferrer noopener"
|
||||
class="feedback-link"
|
||||
alt="Feedback"
|
||||
target="_blank"
|
||||
>
|
||||
${translate('siteFeedback')}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Footer;
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
const html = require('choo/html');
|
||||
const assets = require('../../common/assets');
|
||||
|
||||
module.exports = function() {
|
||||
return html`
|
||||
<div class="w-full flex-none flex flex-row items-center content-center justify-center text-sm bg-grey-light leading-tight text-grey-darkest px-4 py-3">
|
||||
<div class="flex items-center mx-auto">
|
||||
<img
|
||||
src="${assets.get('firefox_logo-only.svg')}"
|
||||
class="w-6"
|
||||
alt="Firefox"/>
|
||||
<span class="ml-3">Send is brought to you by the all-new Firefox.
|
||||
<a
|
||||
class="text-blue"
|
||||
href="https://www.mozilla.org/firefox/new/?utm_campaign=send-acquisition&utm_medium=referral&utm_source=send.firefox.com">Download Firefox now ≫</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>`;
|
||||
};
|
|
@ -1,25 +1,34 @@
|
|||
const html = require('choo/html');
|
||||
const account = require('./account');
|
||||
const Component = require('choo/component');
|
||||
const Account = require('./account');
|
||||
|
||||
module.exports = function(state, emit) {
|
||||
const header = html`
|
||||
<header class="relative flex-none flex flex-row items-center justify-between bg-blue md:bg-white w-full px-6 h-16 md:shadow z-20">
|
||||
<a
|
||||
class="header-logo"
|
||||
href="/">
|
||||
<h1 class="text-white md:text-black font-normal">Firefox <b>Send</b></h1>
|
||||
</a>
|
||||
${account(state, emit)}
|
||||
<div class="invisible absolute pin-t pin-l mt-12 w-full flex flex-col items-center pointer-events-none">
|
||||
<div class="border rounded bg-grey-darkest text-white mt-2 p-2">Your upload has finished.<button class="border border-blue rounded-sm bg-blue text-white inline-block p-1 ml-2">Copy Link</button><button class="text-white inline-block p-1 ml-2">ⓧ</button></div>
|
||||
${state.toast ? state.toast() : ''}
|
||||
</div>
|
||||
</header>`;
|
||||
// HACK
|
||||
// We only want to render this once because we
|
||||
// toggle the targets of the links with utils/openLinksInNewTab
|
||||
// header.isSameNode = function(target) {
|
||||
// return target && target.nodeName && target.nodeName === 'HEADER';
|
||||
// };
|
||||
return header;
|
||||
};
|
||||
class Header extends Component {
|
||||
constructor(name, state, emit) {
|
||||
super(name);
|
||||
this.state = state;
|
||||
this.emit = emit;
|
||||
this.account = state.cache(Account, 'account');
|
||||
}
|
||||
|
||||
update() {
|
||||
this.account.render();
|
||||
return false;
|
||||
}
|
||||
|
||||
createElement() {
|
||||
return html`
|
||||
<header
|
||||
class="relative flex-none flex flex-row items-center justify-between bg-blue md:bg-white w-full px-6 h-16 md:shadow z-20"
|
||||
>
|
||||
<a class="header-logo" href="/">
|
||||
<h1 class="text-white md:text-black font-normal">
|
||||
Firefox <b>Send</b>
|
||||
</h1>
|
||||
</a>
|
||||
${this.account.render()}
|
||||
</header>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Header;
|
||||
|
|
|
@ -5,9 +5,9 @@ const modal = require('./modal');
|
|||
const intro = require('./intro');
|
||||
|
||||
module.exports = function(state, emit) {
|
||||
const archives = state.storage.files.map(archive =>
|
||||
archiveTile(state, emit, archive)
|
||||
);
|
||||
const archives = state.storage.files
|
||||
.filter(archive => !archive.expired)
|
||||
.map(archive => archiveTile(state, emit, archive));
|
||||
let left = '';
|
||||
if (state.uploading) {
|
||||
left = archiveTile.uploading(state, emit);
|
||||
|
@ -23,11 +23,12 @@ module.exports = function(state, emit) {
|
|||
: list(archives, 'list-reset h-full overflow-y-scroll', 'mb-3');
|
||||
|
||||
return html`
|
||||
<main class="main relative">
|
||||
${state.modal && modal(state, emit)}
|
||||
<section class="h-full w-full p-6 md:flex md:flex-row z-10">
|
||||
<div class="md:mr-6 md:w-1/2">${left}</div>
|
||||
<div class="md:w-1/2 mt-6 md:mt-0">${right}</div>
|
||||
</section>
|
||||
</main>`;
|
||||
<main class="main relative">
|
||||
${state.modal && modal(state, emit)}
|
||||
<section class="h-full w-full p-6 md:flex md:flex-row z-10">
|
||||
<div class="md:mr-6 md:w-1/2">${left}</div>
|
||||
<div class="md:w-1/2 mt-6 md:mt-0">${right}</div>
|
||||
</section>
|
||||
</main>
|
||||
`;
|
||||
};
|
||||
|
|
39
app/ui/promo.js
Normal file
39
app/ui/promo.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
const html = require('choo/html');
|
||||
const Component = require('choo/component');
|
||||
const assets = require('../../common/assets');
|
||||
|
||||
class Promo extends Component {
|
||||
constructor(name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
update() {
|
||||
return false;
|
||||
}
|
||||
|
||||
createElement() {
|
||||
return html`
|
||||
<div
|
||||
class="w-full flex-none flex flex-row items-center content-center justify-center text-sm bg-grey-light leading-tight text-grey-darkest px-4 py-3"
|
||||
>
|
||||
<div class="flex items-center mx-auto">
|
||||
<img
|
||||
src="${assets.get('firefox_logo-only.svg')}"
|
||||
class="w-6"
|
||||
alt="Firefox"
|
||||
/>
|
||||
<span class="ml-3"
|
||||
>Send is brought to you by the all-new Firefox.
|
||||
<a
|
||||
class="text-blue"
|
||||
href="https://www.mozilla.org/firefox/new/?utm_campaign=send-acquisition&utm_medium=referral&utm_source=send.firefox.com"
|
||||
>Download Firefox now ≫</a
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Promo;
|
16
app/utils.js
16
app/utils.js
|
@ -184,8 +184,17 @@ async function streamToArrayBuffer(stream, size) {
|
|||
}
|
||||
|
||||
function list(items, ulStyle = '', liStyle = '') {
|
||||
const lis = items.map(i => html`<li class="${liStyle}">${i}</li>`);
|
||||
return html`<ul class="${ulStyle}">${lis}</ul>`;
|
||||
const lis = items.map(
|
||||
i =>
|
||||
html`
|
||||
<li class="${liStyle}">${i}</li>
|
||||
`
|
||||
);
|
||||
return html`
|
||||
<ul class="${ulStyle}">
|
||||
${lis}
|
||||
</ul>
|
||||
`;
|
||||
}
|
||||
|
||||
function secondsToL10nId(seconds) {
|
||||
|
@ -199,6 +208,9 @@ function secondsToL10nId(seconds) {
|
|||
}
|
||||
|
||||
function timeLeft(milliseconds) {
|
||||
if (milliseconds < 1) {
|
||||
return { id: 'linkExpiredAlt' };
|
||||
}
|
||||
const minutes = Math.floor(milliseconds / 1000 / 60);
|
||||
const hours = Math.floor(minutes / 60);
|
||||
const days = Math.floor(hours / 24);
|
||||
|
|
|
@ -34,7 +34,56 @@ const serviceWorker = {
|
|||
path: path.resolve(__dirname, 'dist'),
|
||||
publicPath: '/'
|
||||
},
|
||||
devtool: 'source-map'
|
||||
devtool: 'source-map',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
include: [require.resolve('./assets/cryptofill')],
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[hash:8].[ext]'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpg)$/,
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[hash:8].[ext]'
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.svg$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[hash:8].[ext]'
|
||||
}
|
||||
},
|
||||
{
|
||||
loader: 'svgo-loader',
|
||||
options: {
|
||||
plugins: [
|
||||
{ removeViewBox: false }, // true causes stretched images
|
||||
{ convertStyleToAttrs: true }, // for CSP, no unsafe-eval
|
||||
{ removeTitle: true } // for smallness
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
// loads all assets from assets/ for use by common/assets.js
|
||||
test: require.resolve('./build/generate_asset_map.js'),
|
||||
use: ['babel-loader', 'val-loader']
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [new webpack.IgnorePlugin(/\.\.\/dist/)]
|
||||
};
|
||||
|
||||
const web = {
|
||||
|
@ -185,6 +234,7 @@ const web = {
|
|||
from: '*.*'
|
||||
}
|
||||
]),
|
||||
new webpack.EnvironmentPlugin(['NODE_ENV']),
|
||||
new webpack.IgnorePlugin(/\.\.\/dist/), // used in common/*.js
|
||||
new webpack.IgnorePlugin(/require-from-string/), // used in common/locales.js
|
||||
new webpack.HashedModuleIdsPlugin(),
|
||||
|
|
Loading…
Reference in a new issue