summaryrefslogtreecommitdiff
path: root/packages/demobank-ui
diff options
context:
space:
mode:
Diffstat (limited to 'packages/demobank-ui')
-rw-r--r--packages/demobank-ui/README.md18
-rwxr-xr-xpackages/demobank-ui/build.mjs160
-rw-r--r--packages/demobank-ui/mocks/json-server/db.json4
-rw-r--r--packages/demobank-ui/mocks/window.js27
-rw-r--r--packages/demobank-ui/package.json112
-rw-r--r--packages/demobank-ui/preact.config.js70
-rw-r--r--packages/demobank-ui/preact.mock.js55
-rw-r--r--packages/demobank-ui/preact.single-config.js60
-rwxr-xr-xpackages/demobank-ui/remove-link-stylesheet.sh8
-rw-r--r--packages/demobank-ui/src/assets/icons/auth_method/email.svg1
-rw-r--r--packages/demobank-ui/src/assets/icons/auth_method/postal.svg1
-rw-r--r--packages/demobank-ui/src/assets/icons/auth_method/question.svg1
-rw-r--r--packages/demobank-ui/src/assets/icons/auth_method/sms.svg1
-rw-r--r--packages/demobank-ui/src/assets/icons/auth_method/video.svg1
-rw-r--r--packages/demobank-ui/src/components/app.tsx7
-rw-r--r--packages/demobank-ui/src/hooks/index.ts85
-rw-r--r--packages/demobank-ui/src/index.html34
-rw-r--r--packages/demobank-ui/src/index.tsx8
-rw-r--r--packages/demobank-ui/src/pages/home/index.tsx85
-rw-r--r--packages/demobank-ui/src/scss/pure.scss1478
-rw-r--r--packages/demobank-ui/src/template.html52
-rw-r--r--packages/demobank-ui/static/index.html12
-rw-r--r--packages/demobank-ui/tests/__mocks__/browserMocks.ts21
-rw-r--r--packages/demobank-ui/tests/__mocks__/fileMocks.ts3
-rw-r--r--packages/demobank-ui/tests/__mocks__/setupTests.ts6
-rw-r--r--packages/demobank-ui/tests/__tests__/homepage.js466
-rw-r--r--packages/demobank-ui/tests/declarations.d.ts3
-rw-r--r--packages/demobank-ui/tsconfig.json28
28 files changed, 1121 insertions, 1686 deletions
diff --git a/packages/demobank-ui/README.md b/packages/demobank-ui/README.md
index c014929ce..2fc54a771 100644
--- a/packages/demobank-ui/README.md
+++ b/packages/demobank-ui/README.md
@@ -1,19 +1,11 @@
-# bank web
+# Taler Demobank UI
## CLI Commands
-- `npm install`: Installs dependencies
+- `pnpm install`: Installs dependencies
-- `npm run dev`: Run a development, HMR server
+- `pnpm run build`: Production-ready build
-- `npm run serve`: Run a production-like server
+- `pnpm run check`: Run type checker
-- `npm run build`: Production-ready build
-
-- `npm run lint`: Pass TypeScript files using ESLint
-
-- `npm run test`: Run Jest and Enzyme with
- [`enzyme-adapter-preact-pure`](https://github.com/preactjs/enzyme-adapter-preact-pure) for
- your tests
-
-For detailed explanation on how things work, checkout the [CLI Readme](https://github.com/developit/preact-cli/blob/master/README.md).
+- `pnpm run lint`: Pass TypeScript files using ESLint
diff --git a/packages/demobank-ui/build.mjs b/packages/demobank-ui/build.mjs
new file mode 100755
index 000000000..03664a7c8
--- /dev/null
+++ b/packages/demobank-ui/build.mjs
@@ -0,0 +1,160 @@
+#!/usr/bin/env node
+/*
+ This file is part of GNU Taler
+ (C) 2022 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+import esbuild from "esbuild";
+import path from "path";
+import fs from "fs";
+import crypto from "crypto";
+import { sassPlugin } from "esbuild-sass-plugin";
+
+const BASE = process.cwd();
+
+const preact = path.join(
+ BASE,
+ "node_modules",
+ "preact",
+ "compat",
+ "dist",
+ "compat.module.js",
+);
+
+const preactCompatPlugin = {
+ name: "preact-compat",
+ setup(build) {
+ build.onResolve({ filter: /^(react-dom|react)$/ }, (args) => {
+ //console.log("onresolve", JSON.stringify(args, undefined, 2));
+ return {
+ path: preact,
+ };
+ });
+ },
+};
+
+const entryPoints = ["src/index.tsx"];
+
+let GIT_ROOT = BASE;
+while (!fs.existsSync(path.join(GIT_ROOT, ".git")) && GIT_ROOT !== "/") {
+ GIT_ROOT = path.join(GIT_ROOT, "../");
+}
+if (GIT_ROOT === "/") {
+ console.log("not found");
+ process.exit(1);
+}
+const GIT_HASH = GIT_ROOT === "/" ? undefined : git_hash();
+
+let _package = JSON.parse(fs.readFileSync(path.join(BASE, "package.json")));
+
+function git_hash() {
+ const rev = fs
+ .readFileSync(path.join(GIT_ROOT, ".git", "HEAD"))
+ .toString()
+ .trim()
+ .split(/.*[: ]/)
+ .slice(-1)[0];
+ if (rev.indexOf("/") === -1) {
+ return rev;
+ } else {
+ return fs.readFileSync(path.join(GIT_ROOT, ".git", rev)).toString().trim();
+ }
+}
+
+// FIXME: Put this into some helper library.
+function copyFilesPlugin(options) {
+ const getDigest = (string) => {
+ const hash = crypto.createHash("md5");
+ const data = hash.update(string, "utf-8");
+
+ return data.digest("hex");
+ };
+
+ const getFileDigest = (path) => {
+ if (!fs.existsSync(path)) {
+ return null;
+ }
+
+ if (fs.statSync(path).isDirectory()) {
+ return null;
+ }
+
+ return getDigest(fs.readFileSync(path));
+ };
+
+ function filter(src, dest) {
+ if (!fs.existsSync(dest)) {
+ return true;
+ }
+
+ if (fs.statSync(dest).isDirectory()) {
+ return true;
+ }
+
+ return getFileDigest(src) !== getFileDigest(dest);
+ }
+
+ return {
+ name: "copy-files",
+ setup(build) {
+ let src = options.src || "./static";
+ let dest = options.dest || "./dist";
+ build.onEnd(() =>
+ fs.cpSync(src, dest, {
+ dereference: options.dereference || true,
+ errorOnExist: options.errorOnExist || false,
+ filter: options.filter || filter,
+ force: options.force || true,
+ preserveTimestamps: options.preserveTimestamps || true,
+ recursive: options.recursive || true,
+ }),
+ );
+ },
+ };
+}
+
+export const buildConfig = {
+ entryPoints: [...entryPoints],
+ bundle: true,
+ outdir: "dist",
+ minify: false,
+ loader: {
+ ".svg": "text",
+ ".png": "dataurl",
+ ".jpeg": "dataurl",
+ },
+ target: ["es6"],
+ format: "esm",
+ platform: "browser",
+ sourcemap: true,
+ jsxFactory: "h",
+ jsxFragment: "Fragment",
+ define: {
+ __VERSION__: `"${_package.version}"`,
+ __GIT_HASH__: `"${GIT_HASH}"`,
+ },
+ plugins: [
+ preactCompatPlugin,
+ sassPlugin(),
+ copyFilesPlugin({
+ src: "static/index.html",
+ dest: "dist/index.html",
+ }),
+ ],
+};
+
+esbuild.build(buildConfig).catch((e) => {
+ console.log(e);
+ process.exit(1);
+});
diff --git a/packages/demobank-ui/mocks/json-server/db.json b/packages/demobank-ui/mocks/json-server/db.json
deleted file mode 100644
index 44d3ccab2..000000000
--- a/packages/demobank-ui/mocks/json-server/db.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "register": {},
- "transactions": {}
-}
diff --git a/packages/demobank-ui/mocks/window.js b/packages/demobank-ui/mocks/window.js
deleted file mode 100644
index f396ff9e3..000000000
--- a/packages/demobank-ui/mocks/window.js
+++ /dev/null
@@ -1,27 +0,0 @@
-Object.defineProperty(window, 'requestAnimationFrame', {
- value: function(cb) {} // Silence the browser.
-})
-
-Object.defineProperty(window, 'localStorage', {
- value: {
- store: {},
- getItem: function(key) {
- return this.store[key];
- },
- setItem: function(key, value) {
- return this.store[key] = value;
- },
- clear: function() {
- this.store = {};
- }
- }
-});
-Object.defineProperty(window, 'location', {
- value: {
- origin: "http://localhost:8080", /* where taler-local rev proxy listens to */
- search: "",
- pathname: "/sandbox/demobanks/default",
- }
-})
-
-export default window;
diff --git a/packages/demobank-ui/package.json b/packages/demobank-ui/package.json
index a959ab3d3..831ec3978 100644
--- a/packages/demobank-ui/package.json
+++ b/packages/demobank-ui/package.json
@@ -4,15 +4,10 @@
"version": "0.1.0",
"license": "AGPL-3.0-OR-LATER",
"scripts": {
- "dev": "preact watch --port ${PORT:=9090} --no-sw --no-esm -c preact.mock.js",
- "build": "preact build --no-sw --no-esm -c preact.single-config.js --dest build && sh remove-link-stylesheet.sh",
- "serve": "sirv build --port ${PORT:=8080} --cors --single",
+ "build": "./build.mjs",
+ "check": "tsc",
"lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
- "test": "jest ./tests",
- "build-storybook": "build-storybook",
- "serve-single": "sirv single --port ${PORT:=8080} --cors --single",
- "pretty": "prettier --write src",
- "storybook": "start-storybook -p 6006"
+ "pretty": "prettier --write src"
},
"eslintConfig": {
"parser": "@typescript-eslint/parser",
@@ -24,77 +19,62 @@
"build/"
],
"rules": {
- "@typescript-eslint/no-explicit-any": [0],
- "@typescript-eslint/ban-ts-comment": [1],
- "quotes": [2, "single", {"allowTemplateLiterals": true,"avoidEscape": false}],
- "indent": [2,2],
- "prefer-arrow-callback": [2, {"allowNamedFunctions": false, "allowUnboundThis": true}],
- "curly": [2,"multi"],
- "prefer-template": [1]
+ "@typescript-eslint/no-explicit-any": [
+ 0
+ ],
+ "@typescript-eslint/ban-ts-comment": [
+ 1
+ ],
+ "quotes": [
+ 2,
+ "single",
+ {
+ "allowTemplateLiterals": true,
+ "avoidEscape": false
+ }
+ ],
+ "indent": [
+ 2,
+ 2
+ ],
+ "prefer-arrow-callback": [
+ 2,
+ {
+ "allowNamedFunctions": false,
+ "allowUnboundThis": true
+ }
+ ],
+ "curly": [
+ 2,
+ "multi"
+ ],
+ "prefer-template": [
+ 1
+ ]
}
},
"dependencies": {
- "base64-inline-loader": "1.1.1",
- "date-fns": "2.25.0",
+ "date-fns": "2.29.3",
"jed": "1.1.1",
- "preact": "^10.5.15",
- "preact-render-to-string": "^5.1.19",
- "preact-router": "^3.2.1",
+ "preact-render-to-string": "^5.2.6",
+ "preact-router": "^4.1.0",
"qrcode-generator": "^1.4.4",
- "swr": "1.1"
+ "swr": "~1.3.0"
},
"devDependencies": {
- "@babel/core": "7.18.9",
- "@babel/plugin-transform-modules-commonjs": "7.18.6",
- "@babel/plugin-transform-react-jsx-source": "7.18.6",
- "@babel/preset-env": "7.18.9",
"@creativebulma/bulma-tooltip": "^1.2.0",
"@gnu-taler/pogen": "^0.0.5",
- "@storybook/addon-a11y": "6.2.9",
- "@storybook/addon-actions": "6.2.9",
- "@storybook/addon-essentials": "6.2.9",
- "@storybook/addon-links": "6.2.9",
- "@storybook/preact": "6.2.9",
- "@storybook/preset-scss": "^1.0.3",
- "@testing-library/jest-dom": "^5.16.1",
- "@testing-library/preact": "^2.0.1",
- "@testing-library/preact-hooks": "^1.1.0",
- "@types/enzyme": "^3.10.10",
- "@types/jest": "^27.0.2",
- "@typescript-eslint/eslint-plugin": "^5.3.0",
- "@typescript-eslint/parser": "^5.3.0",
- "babel-loader": "^8.2.2",
- "base64-inline-loader": "^1.1.1",
- "bulma": "^0.9.3",
+ "@typescript-eslint/eslint-plugin": "^5.41.0",
+ "@typescript-eslint/parser": "^5.41.0",
+ "bulma": "^0.9.4",
"bulma-checkbox": "^1.1.1",
"bulma-radio": "^1.1.1",
- "enzyme": "^3.11.0",
- "enzyme-adapter-preact-pure": "^3.2.0",
- "eslint": "^8.1.0",
+ "esbuild": "^0.15.12",
+ "esbuild-sass-plugin": "^2.4.0",
+ "eslint": "^8.26.0",
"eslint-config-preact": "^1.2.0",
- "html-webpack-inline-chunk-plugin": "^1.1.1",
- "html-webpack-inline-source-plugin": "0.0.10",
- "html-webpack-skip-assets-plugin": "^1.0.1",
- "inline-chunk-html-plugin": "^1.1.1",
- "jest": "^27.3.1",
- "jest-fetch-mock": "^3.0.3",
- "jest-preset-preact": "^4.0.5",
- "jest-watch-typeahead": "^1.0.0",
- "jest-environment-jsdom": "^27.4.6",
- "jssha": "^3.2.0",
"po2json": "^0.4.5",
- "preact-cli": "3.0.5",
- "sass": "1.32.13",
- "sass-loader": "^10",
- "script-ext-html-webpack-plugin": "^2.1.5",
- "sirv-cli": "^1.0.14",
+ "preact": "10.11.2",
"typescript": "^4.4.4"
- },
- "jest": {
- "preset": "jest-preset-preact",
- "setupFiles": [
- "<rootDir>/tests/__mocks__/browserMocks.ts",
- "<rootDir>/tests/__mocks__/setupTests.ts"
- ]
}
}
diff --git a/packages/demobank-ui/preact.config.js b/packages/demobank-ui/preact.config.js
deleted file mode 100644
index 8e640f3ff..000000000
--- a/packages/demobank-ui/preact.config.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { DefinePlugin } from 'webpack';
-
-import pack from './package.json';
-import * as cp from 'child_process';
-
-const commitHash = cp.execSync('git rev-parse --short HEAD').toString();
-
-export default {
- webpack(config, env, helpers) {
- // ensure that process.env will not be undefined on runtime
- config.node.process = 'mock'
-
- // add __VERSION__ to be use in the html
- config.plugins.push(
- new DefinePlugin({
- 'process.env.__VERSION__': JSON.stringify(env.isProd ? pack.version : `dev-${commitHash}`) ,
- }),
- );
-
- // suddenly getting out of memory error from build process, error below [1]
- // FIXME: remove preact-cli, use rollup
- let { index } = helpers.getPluginsByName(config, 'WebpackFixStyleOnlyEntriesPlugin')[0]
- config.plugins.splice(index, 1)
- }
-}
-
-
-
-/* [1] from this error decided to remove plugin 'webpack-fix-style-only-entries
- leaving this error for future reference
-
-
-<--- Last few GCs --->
-
-[32479:0x2e01870] 19969 ms: Mark-sweep 1869.4 (1950.2) -> 1443.1 (1504.1) MB, 497.5 / 0.0 ms (average mu = 0.631, current mu = 0.455) allocation failure scavenge might not succeed
-[32479:0x2e01870] 21907 ms: Mark-sweep 2016.9 (2077.9) -> 1628.6 (1681.4) MB, 1596.0 / 0.0 ms (average mu = 0.354, current mu = 0.176) allocation failure scavenge might not succeed
-
-<--- JS stacktrace --->
-
-==== JS stack trace =========================================
-
- 0: ExitFrame [pc: 0x13cf099]
-Security context: 0x2f4ca66c08d1 <JSObject>
- 1: /* anonymous * / [0x35d05555b4b9] [...path/merchant-backoffice/node_modules/.pnpm/webpack-fix-style-only-entries@0.5.2/node_modules/webpack-fix-style-only-entries/index.js:~80] [pc=0x2145e699d1a4](this=0x1149465410e9 <GlobalObject Object map = 0xff481b5b5f9>,0x047e52e36a49 <Dependency map = 0x1ed1fe41cd19>)
- 2: arguments adaptor frame: 3...
-
-FATAL ERROR: invalid array length Allocation failed - JavaScript heap out of memory
-
-*/ \ No newline at end of file
diff --git a/packages/demobank-ui/preact.mock.js b/packages/demobank-ui/preact.mock.js
deleted file mode 100644
index dc3ceb66d..000000000
--- a/packages/demobank-ui/preact.mock.js
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { DefinePlugin, ProvidePlugin } from 'webpack';
-
-import pack from './package.json';
-import * as cp from 'child_process';
-
-const commitHash = cp.execSync('git rev-parse --short HEAD').toString();
-import path from 'path';
-
-export default {
- webpack(config, env, helpers) {
- // Ensure that process.env will not be undefined at runtime.
- config.node.process = 'mock'
- let DEMO_SITES = {
- "Blog": process.env.TALER_ENV_URL_MERCHANT_BLOG,
- "Donations": process.env.TALER_ENV_URL_MERCHANT_DONATIONS,
- "Survey": process.env.TALER_ENV_URL_MERCHANT_SURVEY,
- "Landing": process.env.TALER_ENV_URL_INTRO,
- "Bank": process.env.TALER_ENV_URL_BANK,
- }
- console.log("demo links found", DEMO_SITES);
- // Add __VERSION__ to be use in the html.
- config.plugins.push(
- new DefinePlugin({
- 'process.env.__VERSION__': JSON.stringify(env.isProd ? pack.version : `dev-${commitHash}`) ,
- }),
- // 'window' gets mocked to point at a running euFin instance.
- new ProvidePlugin({window: path.resolve("mocks/window")}),
- new DefinePlugin({"DEMO_SITES": JSON.stringify(DEMO_SITES)})
- );
-
- let { index } = helpers.getPluginsByName(config, 'WebpackFixStyleOnlyEntriesPlugin')[0]
- config.plugins.splice(index, 1)
- }
-}
diff --git a/packages/demobank-ui/preact.single-config.js b/packages/demobank-ui/preact.single-config.js
deleted file mode 100644
index 0fb6f1d0e..000000000
--- a/packages/demobank-ui/preact.single-config.js
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import defaultConfig from './preact.config'
-
-export default {
- webpack(config, env, helpers, options) {
- defaultConfig.webpack(config, env, helpers, options)
-
- //1. check no file is under /routers or /component/{routers,async} to prevent async components
- // https://github.com/preactjs/preact-cli#route-based-code-splitting
-
- //2. remove devtools to prevent sourcemaps
- config.devtool = false
-
- //3. change assetLoader to load assets inline
- const loaders = helpers.getLoaders(config)
- const assetsLoader = loaders.find(lo => lo.rule.test.test('something.woff'))
- if (assetsLoader) {
- assetsLoader.rule.use = 'base64-inline-loader'
- assetsLoader.rule.loader = undefined
- }
-
- //4. remove critters
- //critters remove the css bundle from htmlWebpackPlugin.files.css
- //for now, pushing all the content into the html is enough
- const crittersWrapper = helpers.getPluginsByName(config, 'Critters')
- if (crittersWrapper && crittersWrapper.length > 0) {
- const [{ index }] = crittersWrapper
- config.plugins.splice(index, 1)
- }
-
- //5. remove favicon from src/assets
-
- //6. remove performance hints since we now that this is going to be big
- if (config.performance) {
- config.performance.hints = false
- }
-
- //7. template.html should have a favicon and add js/css content
- }
-}
diff --git a/packages/demobank-ui/remove-link-stylesheet.sh b/packages/demobank-ui/remove-link-stylesheet.sh
deleted file mode 100755
index d3376b8e6..000000000
--- a/packages/demobank-ui/remove-link-stylesheet.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-# This script has been placed in the public domain.
-
-FILE=$(ls build/bundle.*.css)
-BUNDLE=${FILE#build}
-grep -q '<link href="'$BUNDLE'" rel="stylesheet">' build/index.html || { echo bundle $BUNDLE not found in index.html; exit 1; }
-echo -n Removing link from index.html ...
-sed 's_<link href="'$BUNDLE'" rel="stylesheet">__' -i build/index.html
-echo done
diff --git a/packages/demobank-ui/src/assets/icons/auth_method/email.svg b/packages/demobank-ui/src/assets/icons/auth_method/email.svg
deleted file mode 100644
index 3e44b8779..000000000
--- a/packages/demobank-ui/src/assets/icons/auth_method/email.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M22 6c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6zm-2 0l-8 5-8-5h16zm0 12H4V8l8 5 8-5v10z"/></svg> \ No newline at end of file
diff --git a/packages/demobank-ui/src/assets/icons/auth_method/postal.svg b/packages/demobank-ui/src/assets/icons/auth_method/postal.svg
deleted file mode 100644
index 3787b8350..000000000
--- a/packages/demobank-ui/src/assets/icons/auth_method/postal.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M17 15h2v2h-2zM17 11h2v2h-2zM17 7h2v2h-2zM13.74 7l1.26.84V7z"/><path d="M10 3v1.51l2 1.33V5h9v14h-4v2h6V3z"/><path d="M8.17 5.7L15 10.25V21H1V10.48L8.17 5.7zM10 19h3v-7.84L8.17 8.09 3 11.38V19h3v-6h4v6z"/></svg> \ No newline at end of file
diff --git a/packages/demobank-ui/src/assets/icons/auth_method/question.svg b/packages/demobank-ui/src/assets/icons/auth_method/question.svg
deleted file mode 100644
index a346556b2..000000000
--- a/packages/demobank-ui/src/assets/icons/auth_method/question.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M11 23.59v-3.6c-5.01-.26-9-4.42-9-9.49C2 5.26 6.26 1 11.5 1S21 5.26 21 10.5c0 4.95-3.44 9.93-8.57 12.4l-1.43.69zM11.5 3C7.36 3 4 6.36 4 10.5S7.36 18 11.5 18H13v2.3c3.64-2.3 6-6.08 6-9.8C19 6.36 15.64 3 11.5 3zm-1 11.5h2v2h-2zm2-1.5h-2c0-3.25 3-3 3-5 0-1.1-.9-2-2-2s-2 .9-2 2h-2c0-2.21 1.79-4 4-4s4 1.79 4 4c0 2.5-3 2.75-3 5z"/></svg> \ No newline at end of file
diff --git a/packages/demobank-ui/src/assets/icons/auth_method/sms.svg b/packages/demobank-ui/src/assets/icons/auth_method/sms.svg
deleted file mode 100644
index ed15679bf..000000000
--- a/packages/demobank-ui/src/assets/icons/auth_method/sms.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M17 1.01L7 1c-1.1 0-1.99.9-1.99 2v18c0 1.1.89 2 1.99 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14z"/></svg> \ No newline at end of file
diff --git a/packages/demobank-ui/src/assets/icons/auth_method/video.svg b/packages/demobank-ui/src/assets/icons/auth_method/video.svg
deleted file mode 100644
index 69de5e0b4..000000000
--- a/packages/demobank-ui/src/assets/icons/auth_method/video.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24"/></g><g><g><path d="M18,10.48V6c0-1.1-0.9-2-2-2H4C2.9,4,2,4.9,2,6v12c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2v-4.48l4,3.98v-11L18,10.48z M16,9.69V18H4V6h12V9.69z"/><circle cx="10" cy="10" r="2"/><path d="M14,15.43c0-0.81-0.48-1.53-1.22-1.85C11.93,13.21,10.99,13,10,13c-0.99,0-1.93,0.21-2.78,0.58C6.48,13.9,6,14.62,6,15.43 V16h8V15.43z"/></g></g></svg> \ No newline at end of file
diff --git a/packages/demobank-ui/src/components/app.tsx b/packages/demobank-ui/src/components/app.tsx
index 5338c548e..ad8a45e9a 100644
--- a/packages/demobank-ui/src/components/app.tsx
+++ b/packages/demobank-ui/src/components/app.tsx
@@ -1,7 +1,6 @@
-import { FunctionalComponent, h } from 'preact';
-import { TranslationProvider } from '../context/translation';
-import { BankHome } from '../pages/home/index';
-import { Menu } from './menu';
+import { FunctionalComponent } from "preact";
+import { TranslationProvider } from "../context/translation";
+import { BankHome } from "../pages/home/index";
const App: FunctionalComponent = () => {
return (
diff --git a/packages/demobank-ui/src/hooks/index.ts b/packages/demobank-ui/src/hooks/index.ts
index 795df909d..2126cada5 100644
--- a/packages/demobank-ui/src/hooks/index.ts
+++ b/packages/demobank-ui/src/hooks/index.ts
@@ -19,14 +19,14 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { StateUpdater, useState } from 'preact/hooks';
+import { StateUpdater, useState } from "preact/hooks";
export type ValueOrFunction<T> = T | ((p: T) => T);
const calculateRootPath = () => {
const rootPath =
typeof window !== undefined
? window.location.origin + window.location.pathname
- : '/';
+ : "/";
return rootPath;
};
@@ -34,14 +34,14 @@ export function useBackendURL(
url?: string,
): [string, boolean, StateUpdater<string>, () => void] {
const [value, setter] = useNotNullLocalStorage(
- 'backend-url',
+ "backend-url",
url || calculateRootPath(),
);
- const [triedToLog, setTriedToLog] = useLocalStorage('tried-login');
+ const [triedToLog, setTriedToLog] = useLocalStorage("tried-login");
const checkedSetter = (v: ValueOrFunction<string>) => {
- setTriedToLog('yes');
- return setter((p) => (v instanceof Function ? v(p) : v).replace(/\/$/, ''));
+ setTriedToLog("yes");
+ return setter((p) => (v instanceof Function ? v(p) : v).replace(/\/$/, ""));
};
const resetBackend = () => {
@@ -53,8 +53,8 @@ export function useBackendURL(
export function useBackendDefaultToken(): [
string | undefined,
StateUpdater<string | undefined>,
- ] {
- return useLocalStorage('backend-token');
+] {
+ return useLocalStorage("backend-token");
}
export function useBackendInstanceToken(
@@ -64,59 +64,60 @@ export function useBackendInstanceToken(
const [defaultToken, defaultSetToken] = useBackendDefaultToken();
// instance named 'default' use the default token
- if (id === 'default')
- return [defaultToken, defaultSetToken];
+ if (id === "default") return [defaultToken, defaultSetToken];
return [token, setToken];
}
export function useLang(initial?: string): [string, StateUpdater<string>] {
const browserLang =
- typeof window !== 'undefined'
+ typeof window !== "undefined"
? navigator.language || (navigator as any).userLanguage
: undefined;
- const defaultLang = (browserLang || initial || 'en').substring(0, 2);
- const [value, setValue] = useNotNullLocalStorage('lang-preference', defaultLang);
- function updateValue(newValue: (string | ((v: string) => string))) {
+ const defaultLang = (browserLang || initial || "en").substring(0, 2);
+ const [value, setValue] = useNotNullLocalStorage(
+ "lang-preference",
+ defaultLang,
+ );
+ function updateValue(newValue: string | ((v: string) => string)) {
if (document.body.parentElement) {
- const htmlElement = document.body.parentElement
- if (typeof newValue === 'string') {
+ const htmlElement = document.body.parentElement;
+ if (typeof newValue === "string") {
htmlElement.lang = newValue;
- setValue(newValue)
- } else if (typeof newValue === 'function')
+ setValue(newValue);
+ } else if (typeof newValue === "function")
setValue((old) => {
- const nv = newValue(old)
+ const nv = newValue(old);
htmlElement.lang = nv;
- return nv
- })
- } else setValue(newValue)
+ return nv;
+ });
+ } else setValue(newValue);
}
- return [value, updateValue]
+ return [value, updateValue];
}
export function useLocalStorage(
key: string,
initialValue?: string,
): [string | undefined, StateUpdater<string | undefined>] {
- const [storedValue, setStoredValue] = useState<string | undefined>(():
- | string
- | undefined => {
- return typeof window !== 'undefined'
- ? window.localStorage.getItem(key) || initialValue
- : initialValue;
- });
+ const [storedValue, setStoredValue] = useState<string | undefined>(
+ (): string | undefined => {
+ return typeof window !== "undefined"
+ ? window.localStorage.getItem(key) || initialValue
+ : initialValue;
+ },
+ );
const setValue = (
value?: string | ((val?: string) => string | undefined),
) => {
setStoredValue((p) => {
+ console.log("calling setStoredValue");
+ console.log(window);
const toStore = value instanceof Function ? value(p) : value;
- if (typeof window !== 'undefined')
- if (!toStore)
- window.localStorage.removeItem(key);
- else
- window.localStorage.setItem(key, toStore);
-
+ if (typeof window !== "undefined")
+ if (!toStore) window.localStorage.removeItem(key);
+ else window.localStorage.setItem(key, toStore);
return toStore;
});
@@ -130,7 +131,7 @@ export function useNotNullLocalStorage(
initialValue: string,
): [string, StateUpdater<string>] {
const [storedValue, setStoredValue] = useState<string>((): string => {
- return typeof window !== 'undefined'
+ return typeof window !== "undefined"
? window.localStorage.getItem(key) || initialValue
: initialValue;
});
@@ -138,13 +139,9 @@ export function useNotNullLocalStorage(
const setValue = (value: string | ((val: string) => string)) => {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
- if (typeof window !== 'undefined')
- if (!valueToStore)
- window.localStorage.removeItem(key);
- else
- window.localStorage.setItem(key, valueToStore);
-
-
+ if (typeof window !== "undefined")
+ if (!valueToStore) window.localStorage.removeItem(key);
+ else window.localStorage.setItem(key, valueToStore);
};
return [storedValue, setValue];
diff --git a/packages/demobank-ui/src/index.html b/packages/demobank-ui/src/index.html
new file mode 100644
index 000000000..3df1ceb5c
--- /dev/null
+++ b/packages/demobank-ui/src/index.html
@@ -0,0 +1,34 @@
+<!--
+ This file is part of GNU Taler
+ (C) 2021--2022 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Sebastian Javier Marchano
+-->
+<!DOCTYPE html>
+<html lang="en" class="has-aside-left has-aside-mobile-transition has-navbar-fixed-top has-aside-expanded">
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width,initial-scale=1">
+ <meta name="mobile-web-app-capable" content="yes">
+ <meta name="apple-mobile-web-app-capable" content="yes">
+
+ <link rel="icon" href="data:;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABILAAASCwAAAAAAAAAAAAD///////////////////////////////////////////////////////////////////////////////////////////////////7//v38//78/P/+/fz//vz7///+/v/+/f3//vz7///+/v/+/fz//v38///////////////////////+/v3///7+/////////////////////////////////////////////////////////v3//v79///////+/v3///////r28v/ct5//06SG/9Gffv/Xqo7/7N/V/9e2nf/bsJb/6uDW/9Sskf/euKH/+/j2///////+/v3//////+3azv+/eE3/2rWd/9Kkhv/Vr5T/48i2/8J+VP/Qn3//3ryn/795Tf/WrpP/2LCW/8B6T//w4Nb///////Pn4P+/d0v/9u3n/+7d0v/EhV7//v///+HDr//fxLD/zph2/+TJt//8/Pv/woBX//Lm3f/y5dz/v3hN//bu6f/JjGn/4sW0///////Df1j/8OLZ//v6+P+/elH/+vj1//jy7f+/elL//////+zYzP/Eg13//////967p//MlHT/wn5X///////v4Nb/yY1s///////jw7H/06KG////////////z5t9/+fNvf//////x4pn//Pp4v/8+vn/w39X/8WEX///////5s/A/9CbfP//////27Oc/9y2n////////////9itlf/gu6f//////86Vdf/r2Mz//////8SCXP/Df1j//////+7d0v/KkG7//////+HBrf/VpYr////////////RnoH/5sq6///////Ii2n/8ubf//39/P/Cf1j/xohk/+bNvv//////wn5W//Tq4//58/D/wHxV//7+/f/59fH/v3xU//39/P/w4Nf/xIFb///////hw7H/yo9t/+/f1f/AeU3/+/n2/+nSxP/FhmD//////9qzm//Upon/4MSx/96+qf//////xINc/+3bz//48e3/v3hN//Pn3///////6M+//752S//gw6//06aK/8J+VP/kzLr/zZd1/8OCWv/q18r/17KZ/9Ooi//fv6r/v3dK/+vWyP///////v39///////27un/1aeK/9Opjv/m1cf/1KCC/9a0nP/n08T/0Jx8/82YdP/QnHz/16yR//jx7P///////v39///////+/f3///7+///////+//7//v7+///////+/v7//v/+/////////////////////////v7//v79///////////////////+/v/+/Pv//v39///+/v/+/Pv///7+//7+/f/+/Pv//v39//79/P/+/Pv///7+////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" />
+ <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon" />
+ </head>
+
+ <body>
+ <div id="app"></div>
+ <script type="module" src="index.tsx"></script>
+ </body>
+</html>
diff --git a/packages/demobank-ui/src/index.tsx b/packages/demobank-ui/src/index.tsx
index a2f7b30f8..9aa79f4aa 100644
--- a/packages/demobank-ui/src/index.tsx
+++ b/packages/demobank-ui/src/index.tsx
@@ -1,3 +1,7 @@
-import App from './components/app';
-
+import App from "./components/app";
export default App;
+import { render, h, Fragment } from "preact";
+
+const app = document.getElementById("app");
+
+render(<App />, app as any);
diff --git a/packages/demobank-ui/src/pages/home/index.tsx b/packages/demobank-ui/src/pages/home/index.tsx
index 2116e1f89..8f328b115 100644
--- a/packages/demobank-ui/src/pages/home/index.tsx
+++ b/packages/demobank-ui/src/pages/home/index.tsx
@@ -17,6 +17,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import useSWR, { SWRConfig as _SWRConfig, useSWRConfig } from "swr";
import { h, Fragment, VNode, createContext } from "preact";
+
import {
useRef,
useState,
@@ -24,20 +25,37 @@ import {
StateUpdater,
useContext,
} from "preact/hooks";
-import { Buffer } from "buffer";
-import { useTranslator, Translate } from "../../i18n";
-import { QR } from "../../components/QR";
-import { useNotNullLocalStorage, useLocalStorage } from "../../hooks";
+import { useTranslator, Translate } from "../../i18n/index.js";
+import { QR } from "../../components/QR.js";
+import { useNotNullLocalStorage, useLocalStorage } from "../../hooks/index.js";
import "../../scss/main.scss";
import talerLogo from "../../assets/logo-white.svg";
-import { LangSelectorLikePy as LangSelector } from "../../components/menu/LangSelector";
+import { LangSelectorLikePy as LangSelector } from "../../components/menu/LangSelector.js";
// FIXME: Fix usages of SWRConfig, doing this isn't the best practice (but hey, it works for now)
const SWRConfig = _SWRConfig as any;
-const UI_ALLOW_REGISTRATIONS = "__LIBEUFIN_UI_ALLOW_REGISTRATIONS__" ?? 1;
-const UI_IS_DEMO = "__LIBEUFIN_UI_IS_DEMO__" ?? 0;
-const UI_BANK_NAME = "__LIBEUFIN_UI_BANK_NAME__" ?? "Taler Bank";
+/**
+ * If the first argument does not look like a placeholder, return it.
+ * Otherwise, return the default.
+ *
+ * Useful for placeholder string replacements optionally
+ * done as part of the build system.
+ */
+const replacementOrDefault = (x: string, defaultVal: string) => {
+ if (x.startsWith("__")) {
+ return defaultVal;
+ }
+ return x;
+};
+
+const UI_ALLOW_REGISTRATIONS =
+ replacementOrDefault("__LIBEUFIN_UI_ALLOW_REGISTRATIONS__", "1") == "1";
+const UI_IS_DEMO = replacementOrDefault("__LIBEUFIN_UI_IS_DEMO__", "0") == "1";
+const UI_BANK_NAME = replacementOrDefault(
+ "__LIBEUFIN_UI_BANK_NAME__",
+ "Taler Bank",
+);
/**
* FIXME:
@@ -156,15 +174,6 @@ function maybeDemoContent(content: VNode) {
if (UI_IS_DEMO) return content;
}
-async function fetcher(url: string) {
- return fetch(url).then((r) => r.json());
-}
-
-function genCaptchaNumbers(): string {
- return `${Math.floor(Math.random() * 10)} + ${Math.floor(
- Math.random() * 10,
- )}`;
-}
/**
* Bring the state to show the public accounts page.
*/
@@ -276,22 +285,26 @@ function prepareHeaders(username: string, password: string) {
const headers = new Headers();
headers.append(
"Authorization",
- `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`,
+ `Basic ${window.btoa(`${username}:${password}`)}`,
);
headers.append("Content-Type", "application/json");
return headers;
}
-// Window can be mocked this way:
-// https://gist.github.com/theKashey/07090691c0a4680ed773375d8dbeebc1#file-webpack-conf-js
-// That allows the app to be pointed to a arbitrary
-// euFin backend when launched via "pnpm dev".
-const getRootPath = () => {
+const getBankBackendBaseUrl = () => {
+ const overrideUrl = localStorage.getItem("bank-base-url");
+ if (overrideUrl) {
+ console.log(
+ `using bank base URL ${overrideUrl} (override via bank-base-url localStorage)`,
+ );
+ return overrideUrl;
+ }
const maybeRootPath =
typeof window !== undefined
? window.location.origin + window.location.pathname
: "/";
if (!maybeRootPath.endsWith("/")) return `${maybeRootPath}/`;
+ console.log(`using bank base URL (${maybeRootPath})`);
return maybeRootPath;
};
@@ -785,7 +798,7 @@ async function loginCall(
* let the Account component request the balance to check
* whether the credentials are valid. */
pageStateSetter((prevState) => ({ ...prevState, isLoggedIn: true }));
- let baseUrl = getRootPath();
+ let baseUrl = getBankBackendBaseUrl();
if (!baseUrl.endsWith("/")) baseUrl += "/";
backendStateSetter((prevState) => ({
@@ -813,7 +826,7 @@ async function registrationCall(
backendStateSetter: StateUpdater<BackendStateTypeOpt>,
pageStateSetter: StateUpdater<PageStateType>,
) {
- let baseUrl = getRootPath();
+ let baseUrl = getBankBackendBaseUrl();
/**
* If the base URL doesn't end with slash and the path
* is not empty, then the concatenation made by URL()
@@ -873,19 +886,6 @@ async function registrationCall(
* Functional components. *
*************************/
-function Currency(): VNode {
- const { data, error } = useSWR(
- `${getRootPath()}integration-api/config`,
- fetcher,
- );
- if (typeof error !== "undefined")
- return <b>error: currency could not be retrieved</b>;
-
- if (typeof data === "undefined") return <Fragment>"..."</Fragment>;
- console.log("found bank config", data);
- return data.currency;
-}
-
function ErrorBanner(Props: any): VNode | null {
const [pageState, pageStateSetter] = Props.pageState;
const i18n = useTranslator();
@@ -2043,10 +2043,7 @@ function Account(Props: any): VNode {
function SWRWithCredentials(props: any): VNode {
const { username, password, backendUrl } = props;
const headers = new Headers();
- headers.append(
- "Authorization",
- `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`,
- );
+ headers.append("Authorization", `Basic ${btoa(`${username}:${password}`)}`);
console.log("Likely backend base URL", backendUrl);
return (
<SWRConfig
@@ -2179,13 +2176,11 @@ function PublicHistories(Props: any): VNode {
export function BankHome(): VNode {
const [backendState, backendStateSetter] = useBackendState();
const [pageState, pageStateSetter] = usePageState();
- const [accountState, accountStateSetter] = useAccountState();
- const setTxPageNumber = useTransactionPageNumber()[1];
const i18n = useTranslator();
if (pageState.showPublicHistories)
return (
- <SWRWithoutCredentials baseUrl={getRootPath()}>
+ <SWRWithoutCredentials baseUrl={getBankBackendBaseUrl()}>
<PageContext.Provider value={[pageState, pageStateSetter]}>
<BankFrame>
<PublicHistories pageStateSetter={pageStateSetter}>
diff --git a/packages/demobank-ui/src/scss/pure.scss b/packages/demobank-ui/src/scss/pure.scss
index 0d804d6bd..83fcadce7 100644
--- a/packages/demobank-ui/src/scss/pure.scss
+++ b/packages/demobank-ui/src/scss/pure.scss
@@ -1,404 +1,409 @@
/*!
-Pure v0.6.2
+Pure v2.2.0
Copyright 2013 Yahoo!
Licensed under the BSD License.
-https://github.com/yahoo/pure/blob/master/LICENSE.md
+https://github.com/pure-css/pure/blob/master/LICENSE
*/
/*!
-normalize.css v^3.0 | MIT License | git.io/normalize
+normalize.css v | MIT License | https://necolas.github.io/normalize.css/
Copyright (c) Nicolas Gallagher and Jonathan Neal
*/
-/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
+/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
+
+/* Document
+ ========================================================================== */
+
/**
- * 1. Set default font family to sans-serif.
- * 2. Prevent iOS and IE text size adjust after device orientation change,
- * without disabling user zoom.
+ * 1. Correct the line height in all browsers.
+ * 2. Prevent adjustments of font size after orientation changes in iOS.
*/
-html {
- font-family: sans-serif;
- /* 1 */
- -ms-text-size-adjust: 100%;
- /* 2 */
- -webkit-text-size-adjust: 100%;
- /* 2 */ }
+
+ html {
+ line-height: 1.15; /* 1 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+}
+
+/* Sections
+ ========================================================================== */
/**
- * Remove default margin.
+ * Remove the margin in all browsers.
*/
+
body {
- margin: 0; }
+ margin: 0;
+}
-/* HTML5 display definitions
- ========================================================================== */
/**
- * Correct `block` display not defined for any HTML5 element in IE 8/9.
- * Correct `block` display not defined for `details` or `summary` in IE 10/11
- * and Firefox.
- * Correct `block` display not defined for `main` in IE 11.
+ * Render the `main` element consistently in IE.
*/
-article,
-aside,
-details,
-figcaption,
-figure,
-footer,
-header,
-hgroup,
-main,
-menu,
-nav,
-section,
-summary {
- display: block; }
+
+main {
+ display: block;
+}
/**
- * 1. Correct `inline-block` display not defined in IE 8/9.
- * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
+ * Correct the font size and margin on `h1` elements within `section` and
+ * `article` contexts in Chrome, Firefox, and Safari.
*/
-audio,
-canvas,
-progress,
-video {
- display: inline-block;
- /* 1 */
- vertical-align: baseline;
- /* 2 */ }
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+/* Grouping content
+ ========================================================================== */
/**
- * Prevent modern browsers from displaying `audio` without controls.
- * Remove excess height in iOS 5 devices.
+ * 1. Add the correct box sizing in Firefox.
+ * 2. Show the overflow in Edge and IE.
*/
-audio:not([controls]) {
- display: none;
- height: 0; }
+
+hr {
+ -webkit-box-sizing: content-box;
+ box-sizing: content-box; /* 1 */
+ height: 0; /* 1 */
+ overflow: visible; /* 2 */
+}
/**
- * Address `[hidden]` styling not present in IE 8/9/10.
- * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
*/
-[hidden],
-template {
- display: none; }
-/* Links
+pre {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+
+/* Text-level semantics
========================================================================== */
+
/**
- * Remove the gray background color from active links in IE 10.
+ * Remove the gray background on active links in IE 10.
*/
+
a {
- background-color: transparent; }
+ background-color: transparent;
+}
/**
- * Improve readability of focused elements when they are also in an
- * active/hover state.
+ * 1. Remove the bottom border in Chrome 57-
+ * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
-a:active,
-a:hover {
- outline: 0; }
-/* Text-level semantics
- ========================================================================== */
-/**
- * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
- */
abbr[title] {
- border-bottom: 1px dotted; }
+ border-bottom: none; /* 1 */
+ text-decoration: underline; /* 2 */
+ -webkit-text-decoration: underline dotted;
+ text-decoration: underline dotted; /* 2 */
+}
/**
- * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
+ * Add the correct font weight in Chrome, Edge, and Safari.
*/
+
b,
strong {
- font-weight: bold; }
+ font-weight: bolder;
+}
/**
- * Address styling not present in Safari and Chrome.
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
*/
-dfn {
- font-style: italic; }
-/**
- * Address variable `h1` font-size and margin within `section` and `article`
- * contexts in Firefox 4+, Safari, and Chrome.
- */
-h1 {
- font-size: 2em;
- margin: 0.67em 0; }
+code,
+kbd,
+samp {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
/**
- * Address styling not present in IE 8/9.
+ * Add the correct font size in all browsers.
*/
-mark {
- background: #ff0;
- color: #000; }
-/**
- * Address inconsistent and variable font size in all browsers.
- */
small {
- font-size: 80%; }
+ font-size: 80%;
+}
/**
- * Prevent `sub` and `sup` affecting `line-height` in all browsers.
+ * Prevent `sub` and `sup` elements from affecting the line height in
+ * all browsers.
*/
+
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
- vertical-align: baseline; }
-
-sup {
- top: -0.5em; }
+ vertical-align: baseline;
+}
sub {
- bottom: -0.25em; }
+ bottom: -0.25em;
+}
-/* Embedded content
- ========================================================================== */
-/**
- * Remove border when inside `a` element in IE 8/9/10.
- */
-img {
- border: 0; }
-
-/**
- * Correct overflow not hidden in IE 9/10/11.
- */
-svg:not(:root) {
- overflow: hidden; }
+sup {
+ top: -0.5em;
+}
-/* Grouping content
+/* Embedded content
========================================================================== */
-/**
- * Address margin not present in IE 8/9 and Safari.
- */
-figure {
- margin: 1em 40px; }
-
-/**
- * Address differences between Firefox and other browsers.
- */
-hr {
- box-sizing: content-box;
- height: 0; }
/**
- * Contain overflow in all browsers.
+ * Remove the border on images inside links in IE 10.
*/
-pre {
- overflow: auto; }
-/**
- * Address odd `em`-unit font size rendering in all browsers.
- */
-code,
-kbd,
-pre,
-samp {
- font-family: monospace, monospace;
- font-size: 1em; }
+img {
+ border-style: none;
+}
/* Forms
========================================================================== */
+
/**
- * Known limitation: by default, Chrome and Safari on OS X allow very limited
- * styling of `select`, unless a `border` property is set.
- */
-/**
- * 1. Correct color not being inherited.
- * Known issue: affects color of disabled elements.
- * 2. Correct font properties not being inherited.
- * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
+ * 1. Change the font styles in all browsers.
+ * 2. Remove the margin in Firefox and Safari.
*/
+
button,
input,
optgroup,
select,
textarea {
- color: inherit;
- /* 1 */
- font: inherit;
- /* 2 */
- margin: 0;
- /* 3 */ }
+ font-family: inherit; /* 1 */
+ font-size: 100%; /* 1 */
+ line-height: 1.15; /* 1 */
+ margin: 0; /* 2 */
+}
/**
- * Address `overflow` set to `hidden` in IE 8/9/10/11.
+ * Show the overflow in IE.
+ * 1. Show the overflow in Edge.
*/
-button {
- overflow: visible; }
+
+button,
+input { /* 1 */
+ overflow: visible;
+}
/**
- * Address inconsistent `text-transform` inheritance for `button` and `select`.
- * All other form control elements do not inherit `text-transform` values.
- * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
- * Correct `select` style inheritance in Firefox.
+ * Remove the inheritance of text transform in Edge, Firefox, and IE.
+ * 1. Remove the inheritance of text transform in Firefox.
*/
+
button,
-select {
- text-transform: none; }
+select { /* 1 */
+ text-transform: none;
+}
/**
- * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
- * and `video` controls.
- * 2. Correct inability to style clickable `input` types in iOS.
- * 3. Improve usability and consistency of cursor style between image-type
- * `input` and others.
+ * Correct the inability to style clickable types in iOS and Safari.
*/
+
button,
-html input[type="button"],
-input[type="reset"],
-input[type="submit"] {
+[type="button"],
+[type="reset"],
+[type="submit"] {
-webkit-appearance: button;
- /* 2 */
- cursor: pointer;
- /* 3 */ }
+}
/**
- * Re-set default cursor for disabled elements.
+ * Remove the inner border and padding in Firefox.
*/
-button[disabled],
-html input[disabled] {
- cursor: default; }
+
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+ border-style: none;
+ padding: 0;
+}
/**
- * Remove inner padding and border in Firefox 4+.
+ * Restore the focus styles unset by the previous rule.
*/
-button::-moz-focus-inner,
-input::-moz-focus-inner {
- border: 0;
- padding: 0; }
+
+button:-moz-focusring,
+[type="button"]:-moz-focusring,
+[type="reset"]:-moz-focusring,
+[type="submit"]:-moz-focusring {
+ outline: 1px dotted ButtonText;
+}
/**
- * Address Firefox 4+ setting `line-height` on `input` using `!important` in
- * the UA stylesheet.
+ * Correct the padding in Firefox.
*/
-input {
- line-height: normal; }
+
+fieldset {
+ padding: 0.35em 0.75em 0.625em;
+}
/**
- * It's recommended that you don't attempt to style these elements.
- * Firefox's implementation doesn't respect box-sizing, padding, or width.
- *
- * 1. Address box sizing set to `content-box` in IE 8/9/10.
- * 2. Remove excess padding in IE 8/9/10.
+ * 1. Correct the text wrapping in Edge and IE.
+ * 2. Correct the color inheritance from `fieldset` elements in IE.
+ * 3. Remove the padding so developers are not caught out when they zero out
+ * `fieldset` elements in all browsers.
*/
-input[type="checkbox"],
-input[type="radio"] {
- box-sizing: border-box;
- /* 1 */
- padding: 0;
- /* 2 */ }
+
+legend {
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box; /* 1 */
+ color: inherit; /* 2 */
+ display: table; /* 1 */
+ max-width: 100%; /* 1 */
+ padding: 0; /* 3 */
+ white-space: normal; /* 1 */
+}
/**
- * Fix the cursor style for Chrome's increment/decrement buttons. For certain
- * `font-size` values of the `input`, it causes the cursor style of the
- * decrement button to change from `default` to `text`.
+ * Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
-input[type="number"]::-webkit-inner-spin-button,
-input[type="number"]::-webkit-outer-spin-button {
- height: auto; }
+
+progress {
+ vertical-align: baseline;
+}
/**
- * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
- * 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
+ * Remove the default vertical scrollbar in IE 10+.
*/
-input[type="search"] {
- -webkit-appearance: textfield;
- /* 1 */
- box-sizing: content-box;
- /* 2 */ }
+
+textarea {
+ overflow: auto;
+}
/**
- * Remove inner padding and search cancel button in Safari and Chrome on OS X.
- * Safari (but not Chrome) clips the cancel button when the search input has
- * padding (and `textfield` appearance).
+ * 1. Add the correct box sizing in IE 10.
+ * 2. Remove the padding in IE 10.
*/
-input[type="search"]::-webkit-search-cancel-button,
-input[type="search"]::-webkit-search-decoration {
- -webkit-appearance: none; }
+
+[type="checkbox"],
+[type="radio"] {
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+}
/**
- * Define consistent border, margin, and padding.
+ * Correct the cursor style of increment and decrement buttons in Chrome.
*/
-fieldset {
- border: 1px solid #c0c0c0;
- margin: 0 2px;
- padding: 0.35em 0.625em 0.75em; }
+
+[type="number"]::-webkit-inner-spin-button,
+[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
/**
- * 1. Correct `color` not being inherited in IE 8/9/10/11.
- * 2. Remove padding so people aren't caught out if they zero out fieldsets.
+ * 1. Correct the odd appearance in Chrome and Safari.
+ * 2. Correct the outline style in Safari.
*/
-legend {
- border: 0;
- /* 1 */
- padding: 0;
- /* 2 */ }
+
+[type="search"] {
+ -webkit-appearance: textfield; /* 1 */
+ outline-offset: -2px; /* 2 */
+}
/**
- * Remove default vertical scrollbar in IE 8/9/10/11.
+ * Remove the inner padding in Chrome and Safari on macOS.
*/
-textarea {
- overflow: auto; }
+
+[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
/**
- * Don't inherit the `font-weight` (applied by a rule above).
- * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
+ * 1. Correct the inability to style clickable types in iOS and Safari.
+ * 2. Change font properties to `inherit` in Safari.
*/
-optgroup {
- font-weight: bold; }
-/* Tables
+::-webkit-file-upload-button {
+ -webkit-appearance: button; /* 1 */
+ font: inherit; /* 2 */
+}
+
+/* Interactive
========================================================================== */
+
+/*
+ * Add the correct display in Edge, IE 10+, and Firefox.
+ */
+
+details {
+ display: block;
+}
+
+/*
+ * Add the correct display in all browsers.
+ */
+
+summary {
+ display: list-item;
+}
+
+/* Misc
+ ========================================================================== */
+
/**
- * Remove most spacing between table cells.
+ * Add the correct display in IE 10+.
*/
-table {
- border-collapse: collapse;
- border-spacing: 0; }
-td,
-th {
- padding: 0; }
+template {
+ display: none;
+}
+
+/**
+ * Add the correct display in IE 10.
+ */
+
+[hidden] {
+ display: none;
+}
/*csslint important:false*/
+
/* ==========================================================================
Pure Base Extras
========================================================================== */
+
/**
* Extra rules that Pure adds on top of Normalize.css
*/
+
+html {
+ font-family: sans-serif;
+}
+
/**
* Always hide an element when it has the `hidden` HTML attribute.
*/
+
.hidden,
[hidden] {
- display: none !important; }
+ display: none !important;
+}
/**
* Add this class to an image to make it fit within it's fluid parent wrapper while maintaining
* aspect ratio.
*/
.pure-img {
- max-width: 100%;
- height: auto;
- display: block; }
+ max-width: 100%;
+ height: auto;
+ display: block;
+}
/*csslint regex-selectors:false, known-properties:false, duplicate-properties:false*/
+
.pure-g {
- letter-spacing: -0.31em;
- /* Webkit: collapse white-space between units */
- *letter-spacing: normal;
- /* reset IE < 8 */
- *word-spacing: -0.43em;
- /* IE < 8: collapse white-space between units */
- text-rendering: optimizespeed;
- /* Webkit: fixes text-rendering: optimizeLegibility */
+ letter-spacing: -0.31em; /* Webkit: collapse white-space between units */
+ text-rendering: optimizespeed; /* Webkit: fixes text-rendering: optimizeLegibility */
+
/*
Sets the font stack to fonts known to work properly with the above letter
- and word spacings. See: https://github.com/yahoo/pure/issues/41/
+ and word spacings. See: https://github.com/pure-css/pure/issues/41/
The following font stack makes Pure Grids work on all known environments.
@@ -412,48 +417,53 @@ th {
* Helvetica, Arial, sans-serif: Common font stack on OS X and Windows.
*/
- font-family: FreeSans, Arimo, "Droid Sans", Helvetica, Arial, sans-serif;
- /* Use flexbox when possible to avoid `letter-spacing` side-effects. */
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-flex-flow: row wrap;
- -ms-flex-flow: row wrap;
- flex-flow: row wrap;
- /* Prevents distributing space between rows */
- -webkit-align-content: flex-start;
- -ms-flex-line-pack: start;
- align-content: flex-start; }
+ font-family: FreeSans, Arimo, "Droid Sans", Helvetica, Arial, sans-serif;
+
+ /* Use flexbox when possible to avoid `letter-spacing` side-effects. */
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: horizontal;
+ -webkit-box-direction: normal;
+ -ms-flex-flow: row wrap;
+ flex-flow: row wrap;
+
+ /* Prevents distributing space between rows */
+ -ms-flex-line-pack: start;
+ align-content: flex-start;
+}
/* IE10 display: -ms-flexbox (and display: flex in IE 11) does not work inside a table; fall back to block and rely on font hack */
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
- table .pure-g {
- display: block; } }
+ table .pure-g {
+ display: block;
+ }
+}
+
/* Opera as of 12 on Windows needs word-spacing.
The ".opera-only" selector is used to prevent actual prefocus styling
and is not required in markup.
*/
.opera-only :-o-prefocus,
.pure-g {
- word-spacing: -0.43em; }
+ word-spacing: -0.43em;
+}
.pure-u {
- display: inline-block;
- *display: inline;
- /* IE < 8: fake inline-block */
- zoom: 1;
- letter-spacing: normal;
- word-spacing: normal;
- vertical-align: top;
- text-rendering: auto; }
+ display: inline-block;
+ letter-spacing: normal;
+ word-spacing: normal;
+ vertical-align: top;
+ text-rendering: auto;
+}
/*
Resets the font family back to the OS/browser's default sans-serif font,
this the same font stack that Normalize.css sets for the `body`.
*/
-.pure-g [class*="pure-u"] {
- font-family: sans-serif; }
+.pure-g [class *= "pure-u"] {
+ font-family: sans-serif;
+}
.pure-u-1,
.pure-u-1-1,
@@ -501,260 +511,255 @@ this the same font stack that Normalize.css sets for the `body`.
.pure-u-22-24,
.pure-u-23-24,
.pure-u-24-24 {
- display: inline-block;
- *display: inline;
- zoom: 1;
- letter-spacing: normal;
- word-spacing: normal;
- vertical-align: top;
- text-rendering: auto; }
+ display: inline-block;
+ letter-spacing: normal;
+ word-spacing: normal;
+ vertical-align: top;
+ text-rendering: auto;
+}
.pure-u-1-24 {
- width: 4.1667%;
- *width: 4.1357%; }
+ width: 4.1667%;
+}
.pure-u-1-12,
.pure-u-2-24 {
- width: 8.3333%;
- *width: 8.3023%; }
+ width: 8.3333%;
+}
.pure-u-1-8,
.pure-u-3-24 {
- width: 12.5000%;
- *width: 12.4690%; }
+ width: 12.5000%;
+}
.pure-u-1-6,
.pure-u-4-24 {
- width: 16.6667%;
- *width: 16.6357%; }
+ width: 16.6667%;
+}
.pure-u-1-5 {
- width: 20%;
- *width: 19.9690%; }
+ width: 20%;
+}
.pure-u-5-24 {
- width: 20.8333%;
- *width: 20.8023%; }
+ width: 20.8333%;
+}
.pure-u-1-4,
.pure-u-6-24 {
- width: 25%;
- *width: 24.9690%; }
+ width: 25%;
+}
.pure-u-7-24 {
- width: 29.1667%;
- *width: 29.1357%; }
+ width: 29.1667%;
+}
.pure-u-1-3,
.pure-u-8-24 {
- width: 33.3333%;
- *width: 33.3023%; }
+ width: 33.3333%;
+}
.pure-u-3-8,
.pure-u-9-24 {
- width: 37.5000%;
- *width: 37.4690%; }
+ width: 37.5000%;
+}
.pure-u-2-5 {
- width: 40%;
- *width: 39.9690%; }
+ width: 40%;
+}
.pure-u-5-12,
.pure-u-10-24 {
- width: 41.6667%;
- *width: 41.6357%; }
+ width: 41.6667%;
+}
.pure-u-11-24 {
- width: 45.8333%;
- *width: 45.8023%; }
+ width: 45.8333%;
+}
.pure-u-1-2,
.pure-u-12-24 {
- width: 50%;
- *width: 49.9690%; }
+ width: 50%;
+}
.pure-u-13-24 {
- width: 54.1667%;
- *width: 54.1357%; }
+ width: 54.1667%;
+}
.pure-u-7-12,
.pure-u-14-24 {
- width: 58.3333%;
- *width: 58.3023%; }
+ width: 58.3333%;
+}
.pure-u-3-5 {
- width: 60%;
- *width: 59.9690%; }
+ width: 60%;
+}
.pure-u-5-8,
.pure-u-15-24 {
- width: 62.5000%;
- *width: 62.4690%; }
+ width: 62.5000%;
+}
.pure-u-2-3,
.pure-u-16-24 {
- width: 66.6667%;
- *width: 66.6357%; }
+ width: 66.6667%;
+}
.pure-u-17-24 {
- width: 70.8333%;
- *width: 70.8023%; }
+ width: 70.8333%;
+}
.pure-u-3-4,
.pure-u-18-24 {
- width: 75%;
- *width: 74.9690%; }
+ width: 75%;
+}
.pure-u-19-24 {
- width: 79.1667%;
- *width: 79.1357%; }
+ width: 79.1667%;
+}
.pure-u-4-5 {
- width: 80%;
- *width: 79.9690%; }
+ width: 80%;
+}
.pure-u-5-6,
.pure-u-20-24 {
- width: 83.3333%;
- *width: 83.3023%; }
+ width: 83.3333%;
+}
.pure-u-7-8,
.pure-u-21-24 {
- width: 87.5000%;
- *width: 87.4690%; }
+ width: 87.5000%;
+}
.pure-u-11-12,
.pure-u-22-24 {
- width: 91.6667%;
- *width: 91.6357%; }
+ width: 91.6667%;
+}
.pure-u-23-24 {
- width: 95.8333%;
- *width: 95.8023%; }
+ width: 95.8333%;
+}
.pure-u-1,
.pure-u-1-1,
.pure-u-5-5,
.pure-u-24-24 {
- width: 100%; }
-
+ width: 100%;
+}
.pure-button {
- /* Structure */
- display: inline-block;
- zoom: 1;
- line-height: normal;
- white-space: nowrap;
- vertical-align: middle;
- text-align: center;
- cursor: pointer;
- -webkit-user-drag: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- box-sizing: border-box; }
+ /* Structure */
+ display: inline-block;
+ line-height: normal;
+ white-space: nowrap;
+ vertical-align: middle;
+ text-align: center;
+ cursor: pointer;
+ -webkit-user-drag: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+}
/* Firefox: Get rid of the inner focus border */
.pure-button::-moz-focus-inner {
- padding: 0;
- border: 0; }
+ padding: 0;
+ border: 0;
+}
/* Inherit .pure-g styles */
.pure-button-group {
- letter-spacing: -0.31em;
- /* Webkit: collapse white-space between units */
- *letter-spacing: normal;
- /* reset IE < 8 */
- *word-spacing: -0.43em;
- /* IE < 8: collapse white-space between units */
- text-rendering: optimizespeed;
- /* Webkit: fixes text-rendering: optimizeLegibility */ }
+ letter-spacing: -0.31em; /* Webkit: collapse white-space between units */
+ text-rendering: optimizespeed; /* Webkit: fixes text-rendering: optimizeLegibility */
+}
.opera-only :-o-prefocus,
.pure-button-group {
- word-spacing: -0.43em; }
+ word-spacing: -0.43em;
+}
.pure-button-group .pure-button {
- letter-spacing: normal;
- word-spacing: normal;
- vertical-align: top;
- text-rendering: auto; }
+ letter-spacing: normal;
+ word-spacing: normal;
+ vertical-align: top;
+ text-rendering: auto;
+}
/*csslint outline-none:false*/
+
.pure-button {
- font-family: inherit;
- font-size: 100%;
- padding: 0.5em 1em;
- color: #444;
- /* rgba not supported (IE 8) */
- color: rgba(0, 0, 0, 0.8);
- /* rgba supported */
- border: 1px solid #999;
- /*IE 6/7/8*/
- border: none rgba(0, 0, 0, 0);
- /*IE9 + everything else*/
- background-color: #E6E6E6;
- text-decoration: none;
- border-radius: 2px; }
+ font-family: inherit;
+ font-size: 100%;
+ padding: 0.5em 1em;
+ color: rgba(0, 0, 0, 0.80);
+ border: none rgba(0, 0, 0, 0);
+ background-color: #E6E6E6;
+ text-decoration: none;
+ border-radius: 2px;
+}
.pure-button-hover,
.pure-button:hover,
.pure-button:focus {
- /* csslint ignore:start */
- filter: alpha(opacity=90);
- /* csslint ignore:end */
- background-image: -webkit-linear-gradient(transparent, rgba(0, 0, 0, 0.05) 40%, rgba(0, 0, 0, 0.1));
- background-image: linear-gradient(transparent, rgba(0, 0, 0, 0.05) 40%, rgba(0, 0, 0, 0.1)); }
-
+ background-image: -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(40%, rgba(0,0,0, 0.05)), to(rgba(0,0,0, 0.10)));
+ background-image: linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10));
+}
.pure-button:focus {
- outline: 0; }
-
+ outline: 0;
+}
.pure-button-active,
.pure-button:active {
- box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15) inset, 0 0 6px rgba(0, 0, 0, 0.2) inset;
- border-color: #000; }
+ -webkit-box-shadow: 0 0 0 1px rgba(0,0,0, 0.15) inset, 0 0 6px rgba(0,0,0, 0.20) inset;
+ box-shadow: 0 0 0 1px rgba(0,0,0, 0.15) inset, 0 0 6px rgba(0,0,0, 0.20) inset;
+ border-color: #000;
+}
.pure-button[disabled],
.pure-button-disabled,
.pure-button-disabled:hover,
.pure-button-disabled:focus,
.pure-button-disabled:active {
- border: none;
- background-image: none;
- /* csslint ignore:start */
- filter: alpha(opacity=40);
- /* csslint ignore:end */
- opacity: 0.40;
- cursor: not-allowed;
- box-shadow: none;
- pointer-events: none; }
+ border: none;
+ background-image: none;
+ opacity: 0.40;
+ cursor: not-allowed;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ pointer-events: none;
+}
.pure-button-hidden {
- display: none; }
+ display: none;
+}
.pure-button-primary,
.pure-button-selected,
a.pure-button-primary,
a.pure-button-selected {
- background-color: #00509b;
- color: #fff; }
+ background-color: rgb(0, 120, 231);
+ color: #fff;
+}
/* Button Groups */
.pure-button-group .pure-button {
- margin: 0;
- border-radius: 0;
- border-right: 1px solid #111;
- /* fallback color for rgba() for IE7/8 */
- border-right: 1px solid rgba(0, 0, 0, 0.2); }
+ margin: 0;
+ border-radius: 0;
+ border-right: 1px solid rgba(0, 0, 0, 0.2);
-.pure-button-group .pure-button:first-child {
- border-top-left-radius: 2px;
- border-bottom-left-radius: 2px; }
+}
+.pure-button-group .pure-button:first-child {
+ border-top-left-radius: 2px;
+ border-bottom-left-radius: 2px;
+}
.pure-button-group .pure-button:last-child {
- border-top-right-radius: 2px;
- border-bottom-right-radius: 2px;
- border-right: none; }
+ border-top-right-radius: 2px;
+ border-bottom-right-radius: 2px;
+ border-right: none;
+}
/*csslint box-model:false*/
/*
@@ -763,6 +768,7 @@ also have border and padding. This is done because some browsers don't render
the padding. We explicitly set the box-model for select elements to border-box,
so we can ignore the csslint warning.
*/
+
.pure-form input[type="text"],
.pure-form input[type="password"],
.pure-form input[type="email"],
@@ -779,30 +785,39 @@ so we can ignore the csslint warning.
.pure-form input[type="color"],
.pure-form select,
.pure-form textarea {
- padding: 0.5em 0.6em;
- display: inline-block;
- border: 1px solid #ccc;
- box-shadow: inset 0 1px 3px #ddd;
- border-radius: 4px;
- vertical-align: middle;
- box-sizing: border-box; }
+ padding: 0.5em 0.6em;
+ display: inline-block;
+ border: 1px solid #ccc;
+ -webkit-box-shadow: inset 0 1px 3px #ddd;
+ box-shadow: inset 0 1px 3px #ddd;
+ border-radius: 4px;
+ vertical-align: middle;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+}
/*
Need to separate out the :not() selector from the rest of the CSS 2.1 selectors
since IE8 won't execute CSS that contains a CSS3 selector.
*/
.pure-form input:not([type]) {
- padding: 0.5em 0.6em;
- display: inline-block;
- border: 1px solid #ccc;
- box-shadow: inset 0 1px 3px #ddd;
- border-radius: 4px;
- box-sizing: border-box; }
+ padding: 0.5em 0.6em;
+ display: inline-block;
+ border: 1px solid #ccc;
+ -webkit-box-shadow: inset 0 1px 3px #ddd;
+ box-shadow: inset 0 1px 3px #ddd;
+ border-radius: 4px;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
/* Chrome (as of v.32/34 on OS X) needs additional room for color to display. */
/* May be able to remove this tweak as color inputs become more standardized across browsers. */
.pure-form input[type="color"] {
- padding: 0.2em 0.5em; }
+ padding: 0.2em 0.5em;
+}
+
.pure-form input[type="text"]:focus,
.pure-form input[type="password"]:focus,
@@ -820,27 +835,30 @@ since IE8 won't execute CSS that contains a CSS3 selector.
.pure-form input[type="color"]:focus,
.pure-form select:focus,
.pure-form textarea:focus {
- outline: 0;
- border-color: #129FEA; }
+ outline: 0;
+ border-color: #129FEA;
+}
/*
Need to separate out the :not() selector from the rest of the CSS 2.1 selectors
since IE8 won't execute CSS that contains a CSS3 selector.
*/
.pure-form input:not([type]):focus {
- outline: 0;
- border-color: #129FEA; }
+ outline: 0;
+ border-color: #129FEA;
+}
.pure-form input[type="file"]:focus,
.pure-form input[type="radio"]:focus,
.pure-form input[type="checkbox"]:focus {
- outline: thin solid #129FEA;
- outline: 1px auto #129FEA; }
-
+ outline: thin solid #129FEA;
+ outline: 1px auto #129FEA;
+}
.pure-form .pure-checkbox,
.pure-form .pure-radio {
- margin: 0.5em 0;
- display: block; }
+ margin: 0.5em 0;
+ display: block;
+}
.pure-form input[type="text"][disabled],
.pure-form input[type="password"][disabled],
@@ -858,63 +876,64 @@ since IE8 won't execute CSS that contains a CSS3 selector.
.pure-form input[type="color"][disabled],
.pure-form select[disabled],
.pure-form textarea[disabled] {
- cursor: not-allowed;
- background-color: #eaeded;
- color: #cad2d3; }
+ cursor: not-allowed;
+ background-color: #eaeded;
+ color: #cad2d3;
+}
/*
Need to separate out the :not() selector from the rest of the CSS 2.1 selectors
since IE8 won't execute CSS that contains a CSS3 selector.
*/
.pure-form input:not([type])[disabled] {
- cursor: not-allowed;
- background-color: #eaeded;
- color: #cad2d3; }
-
+ cursor: not-allowed;
+ background-color: #eaeded;
+ color: #cad2d3;
+}
.pure-form input[readonly],
.pure-form select[readonly],
.pure-form textarea[readonly] {
- background-color: #eee;
- /* menu hover bg color */
- color: #777;
- /* menu text color */
- border-color: #ccc; }
+ background-color: #eee; /* menu hover bg color */
+ color: #777; /* menu text color */
+ border-color: #ccc;
+}
.pure-form input:focus:invalid,
.pure-form textarea:focus:invalid,
.pure-form select:focus:invalid {
- color: #b94a48;
- border-color: #e9322d; }
-
+ color: #b94a48;
+ border-color: #e9322d;
+}
.pure-form input[type="file"]:focus:invalid:focus,
.pure-form input[type="radio"]:focus:invalid:focus,
.pure-form input[type="checkbox"]:focus:invalid:focus {
- outline-color: #e9322d; }
-
+ outline-color: #e9322d;
+}
.pure-form select {
- /* Normalizes the height; padding is not sufficient. */
- height: 2.25em;
- border: 1px solid #ccc;
- background-color: white; }
-
+ /* Normalizes the height; padding is not sufficient. */
+ height: 2.25em;
+ border: 1px solid #ccc;
+ background-color: white;
+}
.pure-form select[multiple] {
- height: auto; }
-
+ height: auto;
+}
.pure-form label {
- margin: 0.5em 0 0.2em; }
-
+ margin: 0.5em 0 0.2em;
+}
.pure-form fieldset {
- margin: 0;
- padding: 0.35em 0 0.75em;
- border: 0; }
-
+ margin: 0;
+ padding: 0.35em 0 0.75em;
+ border: 0;
+}
.pure-form legend {
- display: block;
- width: 100%;
- padding: 0.3em 0;
- margin-bottom: 0.3em;
- color: #333;
- border-bottom: 1px solid #e5e5e5; }
+ display: block;
+ width: 100%;
+ padding: 0.3em 0;
+ margin-bottom: 0.3em;
+ color: #333;
+ border-bottom: 1px solid #e5e5e5;
+}
.pure-form-stacked input[type="text"],
.pure-form-stacked input[type="password"],
@@ -934,365 +953,394 @@ since IE8 won't execute CSS that contains a CSS3 selector.
.pure-form-stacked select,
.pure-form-stacked label,
.pure-form-stacked textarea {
- display: block;
- margin: 0.25em 0; }
+ display: block;
+ margin: 0.25em 0;
+}
/*
Need to separate out the :not() selector from the rest of the CSS 2.1 selectors
since IE8 won't execute CSS that contains a CSS3 selector.
*/
.pure-form-stacked input:not([type]) {
- display: block;
- margin: 0.25em 0; }
-
+ display: block;
+ margin: 0.25em 0;
+}
.pure-form-aligned input,
.pure-form-aligned textarea,
.pure-form-aligned select,
-.pure-form-aligned .pure-help-inline,
.pure-form-message-inline {
- display: inline-block;
- *display: inline;
- *zoom: 1;
- vertical-align: middle; }
-
+ display: inline-block;
+ vertical-align: middle;
+}
.pure-form-aligned textarea {
- vertical-align: top; }
+ vertical-align: top;
+}
/* Aligned Forms */
.pure-form-aligned .pure-control-group {
- margin-bottom: 0.5em; }
-
+ margin-bottom: 0.5em;
+}
.pure-form-aligned .pure-control-group label {
- text-align: right;
- display: inline-block;
- vertical-align: middle;
- width: 10em;
- margin: 0 1em 0 0; }
-
+ text-align: right;
+ display: inline-block;
+ vertical-align: middle;
+ width: 10em;
+ margin: 0 1em 0 0;
+}
.pure-form-aligned .pure-controls {
- margin: 1.5em 0 0 11em; }
+ margin: 1.5em 0 0 11em;
+}
/* Rounded Inputs */
.pure-form input.pure-input-rounded,
.pure-form .pure-input-rounded {
- border-radius: 2em;
- padding: 0.5em 1em; }
+ border-radius: 2em;
+ padding: 0.5em 1em;
+}
/* Grouped Inputs */
.pure-form .pure-group fieldset {
- margin-bottom: 10px; }
-
+ margin-bottom: 10px;
+}
.pure-form .pure-group input,
.pure-form .pure-group textarea {
- display: block;
- padding: 10px;
- margin: 0 0 -1px;
- border-radius: 0;
- position: relative;
- top: -1px; }
-
+ display: block;
+ padding: 10px;
+ margin: 0 0 -1px;
+ border-radius: 0;
+ position: relative;
+ top: -1px;
+}
.pure-form .pure-group input:focus,
.pure-form .pure-group textarea:focus {
- z-index: 3; }
-
+ z-index: 3;
+}
.pure-form .pure-group input:first-child,
.pure-form .pure-group textarea:first-child {
- top: 1px;
- border-radius: 4px 4px 0 0;
- margin: 0; }
-
+ top: 1px;
+ border-radius: 4px 4px 0 0;
+ margin: 0;
+}
.pure-form .pure-group input:first-child:last-child,
.pure-form .pure-group textarea:first-child:last-child {
- top: 1px;
- border-radius: 4px;
- margin: 0; }
-
+ top: 1px;
+ border-radius: 4px;
+ margin: 0;
+}
.pure-form .pure-group input:last-child,
.pure-form .pure-group textarea:last-child {
- top: -2px;
- border-radius: 0 0 4px 4px;
- margin: 0; }
-
+ top: -2px;
+ border-radius: 0 0 4px 4px;
+ margin: 0;
+}
.pure-form .pure-group button {
- margin: 0.35em 0; }
+ margin: 0.35em 0;
+}
.pure-form .pure-input-1 {
- width: 100%; }
-
+ width: 100%;
+}
.pure-form .pure-input-3-4 {
- width: 75%; }
-
+ width: 75%;
+}
.pure-form .pure-input-2-3 {
- width: 66%; }
-
+ width: 66%;
+}
.pure-form .pure-input-1-2 {
- width: 50%; }
-
+ width: 50%;
+}
.pure-form .pure-input-1-3 {
- width: 33%; }
-
+ width: 33%;
+}
.pure-form .pure-input-1-4 {
- width: 25%; }
+ width: 25%;
+}
/* Inline help for forms */
-/* NOTE: pure-help-inline is deprecated. Use .pure-form-message-inline instead. */
-.pure-form .pure-help-inline,
.pure-form-message-inline {
- display: inline-block;
- padding-left: 0.3em;
- color: #666;
- vertical-align: middle;
- font-size: 0.875em; }
+ display: inline-block;
+ padding-left: 0.3em;
+ color: #666;
+ vertical-align: middle;
+ font-size: 0.875em;
+}
/* Block help for forms */
.pure-form-message {
- display: block;
- color: #666;
- font-size: 0.875em; }
-
-@media only screen and (max-width: 480px) {
- .pure-form button[type="submit"] {
- margin: 0.7em 0 0; }
-
- .pure-form input:not([type]),
- .pure-form input[type="text"],
- .pure-form input[type="password"],
- .pure-form input[type="email"],
- .pure-form input[type="url"],
- .pure-form input[type="date"],
- .pure-form input[type="month"],
- .pure-form input[type="time"],
- .pure-form input[type="datetime"],
- .pure-form input[type="datetime-local"],
- .pure-form input[type="week"],
- .pure-form input[type="number"],
- .pure-form input[type="search"],
- .pure-form input[type="tel"],
- .pure-form input[type="color"],
- .pure-form label {
- margin-bottom: 0.3em;
- display: block; }
-
- .pure-group input:not([type]),
- .pure-group input[type="text"],
- .pure-group input[type="password"],
- .pure-group input[type="email"],
- .pure-group input[type="url"],
- .pure-group input[type="date"],
- .pure-group input[type="month"],
- .pure-group input[type="time"],
- .pure-group input[type="datetime"],
- .pure-group input[type="datetime-local"],
- .pure-group input[type="week"],
- .pure-group input[type="number"],
- .pure-group input[type="search"],
- .pure-group input[type="tel"],
- .pure-group input[type="color"] {
- margin-bottom: 0; }
-
- .pure-form-aligned .pure-control-group label {
- margin-bottom: 0.3em;
- text-align: left;
display: block;
- width: 100%; }
-
- .pure-form-aligned .pure-controls {
- margin: 1.5em 0 0 0; }
+ color: #666;
+ font-size: 0.875em;
+}
+
+@media only screen and (max-width : 480px) {
+ .pure-form button[type="submit"] {
+ margin: 0.7em 0 0;
+ }
+
+ .pure-form input:not([type]),
+ .pure-form input[type="text"],
+ .pure-form input[type="password"],
+ .pure-form input[type="email"],
+ .pure-form input[type="url"],
+ .pure-form input[type="date"],
+ .pure-form input[type="month"],
+ .pure-form input[type="time"],
+ .pure-form input[type="datetime"],
+ .pure-form input[type="datetime-local"],
+ .pure-form input[type="week"],
+ .pure-form input[type="number"],
+ .pure-form input[type="search"],
+ .pure-form input[type="tel"],
+ .pure-form input[type="color"],
+ .pure-form label {
+ margin-bottom: 0.3em;
+ display: block;
+ }
+
+ .pure-group input:not([type]),
+ .pure-group input[type="text"],
+ .pure-group input[type="password"],
+ .pure-group input[type="email"],
+ .pure-group input[type="url"],
+ .pure-group input[type="date"],
+ .pure-group input[type="month"],
+ .pure-group input[type="time"],
+ .pure-group input[type="datetime"],
+ .pure-group input[type="datetime-local"],
+ .pure-group input[type="week"],
+ .pure-group input[type="number"],
+ .pure-group input[type="search"],
+ .pure-group input[type="tel"],
+ .pure-group input[type="color"] {
+ margin-bottom: 0;
+ }
+
+ .pure-form-aligned .pure-control-group label {
+ margin-bottom: 0.3em;
+ text-align: left;
+ display: block;
+ width: 100%;
+ }
+
+ .pure-form-aligned .pure-controls {
+ margin: 1.5em 0 0 0;
+ }
+
+ .pure-form-message-inline,
+ .pure-form-message {
+ display: block;
+ font-size: 0.75em;
+ /* Increased bottom padding to make it group with its related input element. */
+ padding: 0.2em 0 0.8em;
+ }
+}
- /* NOTE: pure-help-inline is deprecated. Use .pure-form-message-inline instead. */
- .pure-form .pure-help-inline,
- .pure-form-message-inline,
- .pure-form-message {
- display: block;
- font-size: 0.75em;
- /* Increased bottom padding to make it group with its related input element. */
- padding: 0.2em 0 0.8em; } }
/*csslint adjoining-classes: false, box-model:false*/
.pure-menu {
- box-sizing: border-box; }
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+}
.pure-menu-fixed {
- position: fixed;
- left: 0;
- top: 0;
- z-index: 3; }
+ position: fixed;
+ left: 0;
+ top: 0;
+ z-index: 3;
+}
.pure-menu-list,
.pure-menu-item {
- position: relative; }
+ position: relative;
+}
.pure-menu-list {
- list-style: none;
- margin: 0;
- padding: 0; }
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
.pure-menu-item {
- padding: 0;
- margin: 0;
- height: 100%; }
+ padding: 0;
+ margin: 0;
+ height: 100%;
+}
.pure-menu-link,
.pure-menu-heading {
- display: block;
- text-decoration: none;
- white-space: nowrap; }
+ display: block;
+ text-decoration: none;
+ white-space: nowrap;
+}
/* HORIZONTAL MENU */
.pure-menu-horizontal {
- width: 100%;
- white-space: nowrap; }
+ width: 100%;
+ white-space: nowrap;
+}
.pure-menu-horizontal .pure-menu-list {
- display: inline-block; }
+ display: inline-block;
+}
/* Initial menus should be inline-block so that they are horizontal */
.pure-menu-horizontal .pure-menu-item,
.pure-menu-horizontal .pure-menu-heading,
.pure-menu-horizontal .pure-menu-separator {
- display: inline-block;
- *display: inline;
- zoom: 1;
- vertical-align: middle; }
+ display: inline-block;
+ vertical-align: middle;
+}
/* Submenus should still be display: block; */
.pure-menu-item .pure-menu-item {
- display: block; }
+ display: block;
+}
.pure-menu-children {
- display: none;
- position: absolute;
- left: 100%;
- top: 0;
- margin: 0;
- padding: 0;
- z-index: 3; }
+ display: none;
+ position: absolute;
+ left: 100%;
+ top: 0;
+ margin: 0;
+ padding: 0;
+ z-index: 3;
+}
.pure-menu-horizontal .pure-menu-children {
- left: 0;
- top: auto;
- width: inherit; }
+ left: 0;
+ top: auto;
+ width: inherit;
+}
.pure-menu-allow-hover:hover > .pure-menu-children,
.pure-menu-active > .pure-menu-children {
- display: block;
- position: absolute; }
+ display: block;
+ position: absolute;
+}
/* Vertical Menus - show the dropdown arrow */
.pure-menu-has-children > .pure-menu-link:after {
- padding-left: 0.5em;
- content: "\25B8";
- font-size: small; }
+ padding-left: 0.5em;
+ content: "\25B8";
+ font-size: small;
+}
/* Horizontal Menus - show the dropdown arrow */
.pure-menu-horizontal .pure-menu-has-children > .pure-menu-link:after {
- content: "\25BE"; }
+ content: "\25BE";
+}
/* scrollable menus */
.pure-menu-scrollable {
- overflow-y: scroll;
- overflow-x: hidden; }
+ overflow-y: scroll;
+ overflow-x: hidden;
+}
.pure-menu-scrollable .pure-menu-list {
- display: block; }
+ display: block;
+}
.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list {
- display: inline-block; }
+ display: inline-block;
+}
.pure-menu-horizontal.pure-menu-scrollable {
- white-space: nowrap;
- overflow-y: hidden;
- overflow-x: auto;
- -ms-overflow-style: none;
- -webkit-overflow-scrolling: touch;
- /* a little extra padding for this style to allow for scrollbars */
- padding: .5em 0; }
-
-.pure-menu-horizontal.pure-menu-scrollable::-webkit-scrollbar {
- display: none; }
+ white-space: nowrap;
+ overflow-y: hidden;
+ overflow-x: auto;
+ /* a little extra padding for this style to allow for scrollbars */
+ padding: .5em 0;
+}
/* misc default styling */
+
.pure-menu-separator,
.pure-menu-horizontal .pure-menu-children .pure-menu-separator {
- background-color: #ccc;
- height: 1px;
- margin: .3em 0; }
+ background-color: #ccc;
+ height: 1px;
+ margin: .3em 0;
+}
.pure-menu-horizontal .pure-menu-separator {
- width: 1px;
- height: 1.3em;
- margin: 0 0.3em; }
+ width: 1px;
+ height: 1.3em;
+ margin: 0 .3em ;
+}
/* Need to reset the separator since submenu is vertical */
.pure-menu-horizontal .pure-menu-children .pure-menu-separator {
- display: block;
- width: auto; }
+ display: block;
+ width: auto;
+}
.pure-menu-heading {
- text-transform: uppercase;
- color: #565d64; }
+ text-transform: uppercase;
+ color: #565d64;
+}
.pure-menu-link {
- color: #777; }
+ color: #777;
+}
.pure-menu-children {
- background-color: #fff; }
+ background-color: #fff;
+}
.pure-menu-link,
-.pure-menu-disabled,
.pure-menu-heading {
- padding: .5em 1em; }
+ padding: .5em 1em;
+}
.pure-menu-disabled {
- opacity: .5; }
+ opacity: .5;
+}
.pure-menu-disabled .pure-menu-link:hover {
- background-color: transparent; }
+ background-color: transparent;
+ cursor: default;
+}
.pure-menu-active > .pure-menu-link,
.pure-menu-link:hover,
.pure-menu-link:focus {
- background-color: #eee; }
+ background-color: #eee;
+}
-.pure-menu-selected .pure-menu-link,
-.pure-menu-selected .pure-menu-link:visited {
- color: #000; }
+.pure-menu-selected > .pure-menu-link,
+.pure-menu-selected > .pure-menu-link:visited {
+ color: #000;
+}
.pure-table {
- /* Remove spacing between table cells (from Normalize.css) */
- border-collapse: collapse;
- border-spacing: 0;
- empty-cells: show;
- border: 1px solid #cbcbcb; }
+ /* Remove spacing between table cells (from Normalize.css) */
+ border-collapse: collapse;
+ border-spacing: 0;
+ empty-cells: show;
+ border: 1px solid #cbcbcb;
+}
.pure-table caption {
- color: #000;
- font: italic 85%/1 arial, sans-serif;
- padding: 1em 0;
- text-align: center; }
+ color: #000;
+ font: italic 85%/1 arial, sans-serif;
+ padding: 1em 0;
+ text-align: center;
+}
.pure-table td,
.pure-table th {
- border-left: 1px solid #cbcbcb;
- /* inner column border */
- border-width: 0 0 0 1px;
- font-size: inherit;
- margin: 0;
- overflow: visible;
- /*to make ths where the title is really long work*/
- padding: 0.5em 1em;
- /* cell padding */ }
-
-/* Consider removing this next declaration block, as it causes problems when
-there's a rowspan on the first cell. Case added to the tests. issue#432 */
-.pure-table td:first-child,
-.pure-table th:first-child {
- border-left-width: 0; }
+ border-left: 1px solid #cbcbcb;/* inner column border */
+ border-width: 0 0 0 1px;
+ font-size: inherit;
+ margin: 0;
+ overflow: visible; /*to make ths where the title is really long work*/
+ padding: 0.5em 1em; /* cell padding */
+}
.pure-table thead {
- background-color: #e0e0e0;
- color: #000;
- text-align: left;
- vertical-align: bottom; }
+ background-color: #e0e0e0;
+ color: #000;
+ text-align: left;
+ vertical-align: bottom;
+}
/*
striping:
@@ -1300,29 +1348,33 @@ striping:
odd - #f2f2f2 (light gray)
*/
.pure-table td {
- background-color: transparent; }
-
+ background-color: transparent;
+}
.pure-table-odd td {
- background-color: #f2f2f2; }
+ background-color: #f2f2f2;
+}
/* nth-child selector for modern browsers */
.pure-table-striped tr:nth-child(2n-1) td {
- background-color: #f2f2f2; }
+ background-color: #f2f2f2;
+}
/* BORDERED TABLES */
.pure-table-bordered td {
- border-bottom: 1px solid #cbcbcb; }
-
+ border-bottom: 1px solid #cbcbcb;
+}
.pure-table-bordered tbody > tr:last-child > td {
- border-bottom-width: 0; }
+ border-bottom-width: 0;
+}
+
/* HORIZONTAL BORDERED TABLES */
+
.pure-table-horizontal td,
.pure-table-horizontal th {
- border-width: 0 0 1px 0;
- border-bottom: 1px solid #cbcbcb; }
-
+ border-width: 0 0 1px 0;
+ border-bottom: 1px solid #cbcbcb;
+}
.pure-table-horizontal tbody > tr:last-child > td {
- border-bottom-width: 0; }
-
-/*# sourceMappingURL=pure.css.map */
+ border-bottom-width: 0;
+} \ No newline at end of file
diff --git a/packages/demobank-ui/src/template.html b/packages/demobank-ui/src/template.html
deleted file mode 100644
index 6d8443130..000000000
--- a/packages/demobank-ui/src/template.html
+++ /dev/null
@@ -1,52 +0,0 @@
-<!--
- This file is part of GNU Taler
- (C) 2021--2022 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-
- @author Sebastian Javier Marchano
--->
-<!DOCTYPE html>
-<html lang="en" class="has-aside-left has-aside-mobile-transition has-navbar-fixed-top has-aside-expanded">
- <head>
- <meta charset="utf-8">
- <title><%= htmlWebpackPlugin.options.title %></title>
- <meta name="viewport" content="width=device-width,initial-scale=1">
- <meta name="mobile-web-app-capable" content="yes">
- <meta name="apple-mobile-web-app-capable" content="yes">
-
- <link rel="icon" href="data:;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABILAAASCwAAAAAAAAAAAAD///////////////////////////////////////////////////////////////////////////////////////////////////7//v38//78/P/+/fz//vz7///+/v/+/f3//vz7///+/v/+/fz//v38///////////////////////+/v3///7+/////////////////////////////////////////////////////////v3//v79///////+/v3///////r28v/ct5//06SG/9Gffv/Xqo7/7N/V/9e2nf/bsJb/6uDW/9Sskf/euKH/+/j2///////+/v3//////+3azv+/eE3/2rWd/9Kkhv/Vr5T/48i2/8J+VP/Qn3//3ryn/795Tf/WrpP/2LCW/8B6T//w4Nb///////Pn4P+/d0v/9u3n/+7d0v/EhV7//v///+HDr//fxLD/zph2/+TJt//8/Pv/woBX//Lm3f/y5dz/v3hN//bu6f/JjGn/4sW0///////Df1j/8OLZ//v6+P+/elH/+vj1//jy7f+/elL//////+zYzP/Eg13//////967p//MlHT/wn5X///////v4Nb/yY1s///////jw7H/06KG////////////z5t9/+fNvf//////x4pn//Pp4v/8+vn/w39X/8WEX///////5s/A/9CbfP//////27Oc/9y2n////////////9itlf/gu6f//////86Vdf/r2Mz//////8SCXP/Df1j//////+7d0v/KkG7//////+HBrf/VpYr////////////RnoH/5sq6///////Ii2n/8ubf//39/P/Cf1j/xohk/+bNvv//////wn5W//Tq4//58/D/wHxV//7+/f/59fH/v3xU//39/P/w4Nf/xIFb///////hw7H/yo9t/+/f1f/AeU3/+/n2/+nSxP/FhmD//////9qzm//Upon/4MSx/96+qf//////xINc/+3bz//48e3/v3hN//Pn3///////6M+//752S//gw6//06aK/8J+VP/kzLr/zZd1/8OCWv/q18r/17KZ/9Ooi//fv6r/v3dK/+vWyP///////v39///////27un/1aeK/9Opjv/m1cf/1KCC/9a0nP/n08T/0Jx8/82YdP/QnHz/16yR//jx7P///////v39///////+/f3///7+///////+//7//v7+///////+/v7//v/+/////////////////////////v7//v79///////////////////+/v/+/Pv//v39///+/v/+/Pv///7+//7+/f/+/Pv//v39//79/P/+/Pv///7+////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" />
- <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon" />
-
- <% if (htmlWebpackPlugin.options.manifest.theme_color) { %>
- <meta name="theme-color" content="<%= htmlWebpackPlugin.options.manifest.theme_color %>">
- <% } %>
-
- <% for (const index in htmlWebpackPlugin.files.css) { %>
- <% const file = htmlWebpackPlugin.files.css[index] %>
- <style data-href='<%= file %>' >
- <%= compilation.assets[file.substr(htmlWebpackPlugin.files.publicPath.length)].source() %>
- </style>
- <% } %>
-
- </head>
- <body>
-
- <script>
- <%= compilation.assets[htmlWebpackPlugin.files.chunks["polyfills"].entry.substr(htmlWebpackPlugin.files.publicPath.length)].source() %>
- </script>
- <script>
- <%= compilation.assets[htmlWebpackPlugin.files.chunks["bundle"].entry.substr(htmlWebpackPlugin.files.publicPath.length)].source() %>
- </script>
-
- </body>
-</html>
diff --git a/packages/demobank-ui/static/index.html b/packages/demobank-ui/static/index.html
new file mode 100644
index 000000000..6597eb26f
--- /dev/null
+++ b/packages/demobank-ui/static/index.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <title>Demobank</title>
+ <script type="module" src="index.js"></script>
+ <link rel="stylesheet" href="index.css" />
+ </head>
+ <body>
+ <div id="app"></div>
+ </body>
+</html>
diff --git a/packages/demobank-ui/tests/__mocks__/browserMocks.ts b/packages/demobank-ui/tests/__mocks__/browserMocks.ts
deleted file mode 100644
index 5be8c3ce6..000000000
--- a/packages/demobank-ui/tests/__mocks__/browserMocks.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-// Mock Browser API's which are not supported by JSDOM, e.g. ServiceWorker, LocalStorage
-/**
- * An example how to mock localStorage is given below 👇
- */
-
-/*
-// Mocks localStorage
-const localStorageMock = (function() {
- let store = {};
-
- return {
- getItem: (key) => store[key] || null,
- setItem: (key, value) => store[key] = value.toString(),
- clear: () => store = {}
- };
-
-})();
-
-Object.defineProperty(window, 'localStorage', {
- value: localStorageMock
-}); */
diff --git a/packages/demobank-ui/tests/__mocks__/fileMocks.ts b/packages/demobank-ui/tests/__mocks__/fileMocks.ts
deleted file mode 100644
index 87109e355..000000000
--- a/packages/demobank-ui/tests/__mocks__/fileMocks.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-// This fixed an error related to the CSS and loading gif breaking my Jest test
-// See https://facebook.github.io/jest/docs/en/webpack.html#handling-static-assets
-export default 'test-file-stub';
diff --git a/packages/demobank-ui/tests/__mocks__/setupTests.ts b/packages/demobank-ui/tests/__mocks__/setupTests.ts
deleted file mode 100644
index b0bebb589..000000000
--- a/packages/demobank-ui/tests/__mocks__/setupTests.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { configure } from 'enzyme';
-import Adapter from 'enzyme-adapter-preact-pure';
-
-configure({
- adapter: new Adapter() as any
-});
diff --git a/packages/demobank-ui/tests/__tests__/homepage.js b/packages/demobank-ui/tests/__tests__/homepage.js
deleted file mode 100644
index 9ea0ed410..000000000
--- a/packages/demobank-ui/tests/__tests__/homepage.js
+++ /dev/null
@@ -1,466 +0,0 @@
-import "core-js/stable";
-import "regenerator-runtime/runtime";
-import "@testing-library/jest-dom";
-import { BankHome } from '../../src/pages/home';
-import { h } from 'preact';
-import { waitFor, cleanup, render, fireEvent, screen } from '@testing-library/preact';
-import expect from 'expect';
-import fetchMock from "jest-fetch-mock";
-
-/**
- * This mock makes the translator always return the
- * english string. It didn't work within the 'beforeAll'
- * function...
- */
-jest.mock("../../src/i18n")
-const i18n = require("../../src/i18n")
-i18n.useTranslator.mockImplementation(() => function(arg) {return arg})
-
-beforeAll(() => {
- Object.defineProperty(window, 'location', {
- value: {
- origin: "http://localhost",
- pathname: "/demobanks/default"
- }
- })
- global.Storage.prototype.setItem = jest.fn((key, value) => {})
-})
-
-function fillCredentialsForm() {
- const username = Math.random().toString().substring(2);
- const u = screen.getByPlaceholderText("username");
- const p = screen.getByPlaceholderText("password");
- fireEvent.input(u, {target: {value: username}})
- fireEvent.input(p, {target: {value: "bar"}})
- const signinButton = screen.getByText("Login");
- return {
- username: username,
- signinButton: signinButton
- };
-}
-fetchMock.enableMocks();
-
-function mockSuccessLoginOrRegistration() {
- fetch.once("{}", {
- status: 200
- }).once(JSON.stringify({
- balance: {
- amount: "EUR:10",
- credit_debit_indicator: "credit"
- },
- paytoUri: "payto://iban/123/ABC"
- }))
-}
-
-/**
- * Render homepage -> navigate to register page -> submit registration.
- * 'webMock' is called before submission to mock the server response
- */
-function signUp(context, webMock) {
- render(<BankHome />);
- const registerPage = screen.getByText("Register!");
- fireEvent.click(registerPage);
- const username = Math.random().toString().substring(2);
- const u = screen.getByPlaceholderText("username");
- const p = screen.getByPlaceholderText("password");
- fireEvent.input(u, {target: {value: username}})
- fireEvent.input(p, {target: {value: "bar"}})
- const registerButton = screen.getByText("Register");
- webMock();
- fireEvent.click(registerButton);
- context.username = username;
- return context;
-}
-
-describe("wire transfer", () => {
- beforeEach(() => {
- signUp({}, mockSuccessLoginOrRegistration); // context unused
- })
- test("Wire transfer success", async () => {
- const transferButton = screen.getByText("Create wire transfer");
- const payto = screen.getByPlaceholderText("payto address");
- fireEvent.input(payto, {target: {value: "payto://only-checked-by-the-backend!"}})
- fetch.once("{}"); // 200 OK
- fireEvent.click(transferButton);
- await screen.findByText("wire transfer created", {exact: false})
- })
- test("Wire transfer fail", async () => {
- const transferButton = screen.getByText("Create wire transfer");
- const payto = screen.getByPlaceholderText("payto address");
- fireEvent.input(payto, {target: {value: "payto://only-checked-by-the-backend!"}})
- fetch.once("{}", {status: 400});
- fireEvent.click(transferButton);
- // assert this below does NOT appear.
- await waitFor(() => expect(
- screen.queryByText("wire transfer created", {exact: false})).not.toBeInTheDocument());
- })
-})
-
-describe("withdraw", () => {
- afterEach(() => {
- fetch.resetMocks();
- cleanup();
- })
-
-
- let context = {};
- // Register and land on the profile page.
- beforeEach(() => {
- context = signUp(context, mockSuccessLoginOrRegistration);
- })
-
- test("network failure before withdrawal creation", async () => {
- const a = screen.getAllByPlaceholderText("amount")[0];
- fireEvent.input(a, {target: {value: "10"}});
- let withdrawButton = screen.getByText("Charge Taler wallet");
- // mock network failure.
- fetch.mockReject("API is down");
- fireEvent.click(withdrawButton);
- await screen.findByText("could not create withdrawal operation", {exact: false})
- })
-
- test("HTTP response error upon withdrawal creation", async () => {
- const a = screen.getAllByPlaceholderText("amount")[0];
- fireEvent.input(a, {target: {value: "10,0"}});
- let withdrawButton = screen.getByText("Charge Taler wallet");
- fetch.once("{}", {status: 404});
- fireEvent.click(withdrawButton);
- await screen.findByText("gave response error", {exact: false})
- })
-
- test("Abort withdrawal", async () => {
- const a = screen.getAllByPlaceholderText("amount")[0];
- fireEvent.input(a, {target: {value: "10,0"}});
- let withdrawButton = screen.getByText("Charge Taler wallet");
- fetch.once(JSON.stringify({
- taler_withdraw_uri: "taler://withdraw/foo",
- withdrawal_id: "foo"
- }));
- /**
- * After triggering a withdrawal, check if the taler://withdraw URI
- * rendered, and confirm if so. Lastly, check that a success message
- * appeared on the screen.
- */
- fireEvent.click(withdrawButton);
- const abortButton = await screen.findByText("abort withdrawal", {exact: false})
- fireEvent.click(abortButton);
- expect(fetch).toHaveBeenLastCalledWith(
- `http://localhost/demobanks/default/access-api/accounts/${context.username}/withdrawals/foo/abort`,
- expect.anything()
- )
- await waitFor(() => expect(
- screen.queryByText("abort withdrawal", {exact: false})).not.toBeInTheDocument());
- })
-
- test("Successful withdrawal creation and confirmation", async () => {
- const a = screen.getAllByPlaceholderText("amount")[0];
- fireEvent.input(a, {target: {value: "10,0"}});
- let withdrawButton = await screen.findByText("Charge Taler wallet");
- fetch.once(JSON.stringify({
- taler_withdraw_uri: "taler://withdraw/foo",
- withdrawal_id: "foo"
- }));
- /**
- * After triggering a withdrawal, check if the taler://withdraw URI
- * rendered, and confirm if so. Lastly, check that a success message
- * appeared on the screen. */
- fireEvent.click(withdrawButton);
- expect(fetch).toHaveBeenCalledWith(
- `http://localhost/demobanks/default/access-api/accounts/${context.username}/withdrawals`,
- expect.objectContaining({body: JSON.stringify({amount: "EUR:10.0"})})
- )
- // assume wallet POSTed the payment details.
- const confirmButton = await screen.findByText("confirm withdrawal", {exact: false})
- /**
- * Not expecting a new withdrawal possibility while one is being processed.
- */
- await waitFor(() => expect(
- screen.queryByText("charge taler wallet", {exact: false})).not.toBeInTheDocument());
- fetch.once("{}")
- // Confirm currently processed withdrawal.
- fireEvent.click(confirmButton);
- /**
- * After having confirmed above, wait that the
- * pre-withdrawal elements disappears and a success
- * message appears.
- */
- await waitFor(() => expect(
- screen.queryByText(
- "confirm withdrawal",
- {exact: false})).not.toBeInTheDocument()
- );
- await waitFor(() => expect(
- screen.queryByText(
- "give this address to the taler wallet",
- {exact: false})).not.toBeInTheDocument()
- );
- expect(fetch).toHaveBeenLastCalledWith(
- `http://localhost/demobanks/default/access-api/accounts/${context.username}/withdrawals/foo/confirm`,
- expect.anything())
- // success message
- await screen.findByText("withdrawal confirmed", {exact: false})
-
- /**
- * Click on a "return to homepage / close" button, and
- * check that the withdrawal confirmation is gone, and
- * the option to withdraw again reappeared.
- */
- const closeButton = await screen.findByText("close", {exact: false})
- fireEvent.click(closeButton);
-
- /**
- * After closing the operation, the confirmation message is not expected.
- */
- await waitFor(() => expect(
- screen.queryByText("withdrawal confirmed", {exact: false})).not.toBeInTheDocument()
- );
-
- /**
- * After closing the operation, the possibility to withdraw again should be offered.
- */
- await waitFor(() => expect(
- screen.queryByText(
- "charge taler wallet",
- {exact: false})).toBeInTheDocument()
- );
- })
-})
-
-describe("home page", () => {
- afterEach(() => {
- fetch.resetMocks();
- cleanup();
- })
- test("public histories", async () => {
- render(<BankHome />);
- /**
- * Mock list of public accounts. 'bar' is
- * the shown account, since it occupies the last
- * position (and SPA picks it via the 'pop()' method) */
- fetch.once(JSON.stringify({
- "publicAccounts" : [ {
- "balance" : "EUR:1",
- "iban" : "XXX",
- "accountLabel" : "foo"
- }, {
- "balance" : "EUR:2",
- "iban" : "YYY",
- "accountLabel" : "bar"
- }]
- })).once(JSON.stringify({
- transactions: [{
- debtorIban: "XXX",
- debtorBic: "YYY",
- debtorName: "Foo",
- creditorIban: "AAA",
- creditorBic: "BBB",
- creditorName: "Bar",
- direction: "DBIT",
- amount: "EUR:5",
- subject: "Reimbursement",
- date: "1970-01-01"
- }, {
- debtorIban: "XXX",
- debtorBic: "YYY",
- debtorName: "Foo",
- creditorIban: "AAA",
- creditorBic: "BBB",
- creditorName: "Bar",
- direction: "CRDT",
- amount: "EUR:5",
- subject: "Bonus",
- date: "2000-01-01"
- }]
- })).once(JSON.stringify({
- transactions: [{
- debtorIban: "XXX",
- debtorBic: "YYY",
- debtorName: "Foo",
- creditorIban: "AAA",
- creditorBic: "BBB",
- creditorName: "Bar",
- direction: "DBIT",
- amount: "EUR:5",
- subject: "Donation",
- date: "1970-01-01"
- }, {
- debtorIban: "XXX",
- debtorBic: "YYY",
- debtorName: "Foo",
- creditorIban: "AAA",
- creditorBic: "BBB",
- creditorName: "Bar",
- direction: "CRDT",
- amount: "EUR:5",
- subject: "Refund",
- date: "2000-01-01"
- }]
- }))
-
- // Navigate to dedicate public histories page.
- const publicTxsPage = screen.getByText("transactions");
- fireEvent.click(publicTxsPage);
-
- /**
- * Check that transactions data appears on the page.
- */
- await screen.findByText("reimbursement", {exact: false});
- await screen.findByText("bonus", {exact: false});
- /**
- * The transactions below should not appear, because only
- * one public account renders.
- */
- await waitFor(() => expect(
- screen.queryByText("refund", {exact: false})).not.toBeInTheDocument());
- await waitFor(() => expect(
- screen.queryByText("donation", {exact: false})).not.toBeInTheDocument());
- /**
- * First HTTP mock:
- */
- await expect(fetch).toHaveBeenCalledWith(
- "http://localhost/demobanks/default/access-api/public-accounts"
- )
- /**
- * Only expecting this request (second mock), as SWR doesn't let
- * the unshown history request to the backend:
- */
- await expect(fetch).toHaveBeenCalledWith(
- "http://localhost/demobanks/default/access-api/accounts/bar/transactions?page=0"
- )
- /**
- * Switch tab:
- */
- let fooTab = await screen.findByText("foo", {exact: false});
- fireEvent.click(fooTab);
- /**
- * Last two HTTP mocks should render now:
- */
- await screen.findByText("refund", {exact: false});
- await screen.findByText("donation", {exact: false});
-
- // Expect SWR to have requested 'foo' history
- // (consuming the last HTTP mock):
- await expect(fetch).toHaveBeenCalledWith(
- "http://localhost/demobanks/default/access-api/accounts/foo/transactions?page=0"
- )
- let backButton = await screen.findByText("Go back", {exact: false});
- fireEvent.click(backButton);
- await waitFor(() => expect(
- screen.queryByText("donation", {exact: false})).not.toBeInTheDocument());
- await screen.findByText("welcome to eufin bank", {exact: false})
- })
-
- // check page informs about the current balance
- // after a successful registration.
-
- test("new registration response error 404", async () => {
- var context = signUp({}, () => fetch.mockResponseOnce("Not found", {status: 404}));
- await screen.findByText("has a problem", {exact: false});
- expect(fetch).toHaveBeenCalledWith(
- "http://localhost/demobanks/default/access-api/testing/register",
- expect.objectContaining(
- {body: JSON.stringify({username: context.username, password: "bar"}), method: "POST"},
- ))
- })
-
- test("registration network failure", async () => {
- let context = signUp({}, ()=>fetch.mockReject("API is down"));
- await screen.findByText("has a problem", {exact: false});
- expect(fetch).toHaveBeenCalledWith(
- "http://localhost/demobanks/default/access-api/testing/register",
- expect.objectContaining(
- {body: JSON.stringify({username: context.username, password: "bar"}), method: "POST"}
- ))
- })
-
- test("login non existent user", async () => {
- render(<BankHome />);
- const { username, signinButton } = fillCredentialsForm();
- fetch.once("{}", {status: 404});
- fireEvent.click(signinButton);
- await screen.findByText("username or account label not found", {exact: false})
- })
- test("login wrong credentials", async () => {
- render(<BankHome />);
- const { username, signinButton } = fillCredentialsForm();
- fetch.once("{}", {status: 401});
- fireEvent.click(signinButton);
- await screen.findByText("wrong credentials given", {exact: false})
- })
-
- /**
- * Test that balance and last transactions get shown
- * after a successful login.
- */
- test("login success", async () => {
- render(<BankHome />);
- const { username, signinButton } = fillCredentialsForm();
-
- // Response to balance request.
- fetch.once(JSON.stringify({
- balance: {
- amount: "EUR:10",
- credit_debit_indicator: "credit"
- },
- paytoUri: "payto://iban/123/ABC"
- })).once(JSON.stringify({ // Response to history request.
- transactions: [{
- debtorIban: "XXX",
- debtorBic: "YYY",
- debtorName: "Foo",
- creditorIban: "AAA",
- creditorBic: "BBB",
- creditorName: "Bar",
- direction: "DBIT",
- amount: "EUR:5",
- subject: "Donation",
- date: "01-01-1970"
- }, {
- debtorIban: "XXX",
- debtorBic: "YYY",
- debtorName: "Foo",
- creditorIban: "AAA",
- creditorBic: "BBB",
- creditorName: "Bar",
- direction: "CRDT",
- amount: "EUR:5",
- subject: "Refund",
- date: "01-01-2000"
- }]
- }))
- fireEvent.click(signinButton);
- expect(fetch).toHaveBeenCalledWith(
- `http://localhost/demobanks/default/access-api/accounts/${username}`,
- expect.anything()
- )
- await screen.findByText("balance is 10 EUR", {exact: false})
- // The two transactions in the history mocked above.
- await screen.findByText("refund", {exact: false})
- await screen.findByText("donation", {exact: false})
- expect(fetch).toHaveBeenCalledWith(
- `http://localhost/demobanks/default/access-api/accounts/${username}/transactions?page=0`,
- expect.anything()
- )
- })
-
- test("registration success", async () => {
- let context = signUp({}, mockSuccessLoginOrRegistration);
- /**
- * Tests that a balance is shown after the successful
- * registration.
- */
- await screen.findByText("balance is 10 EUR", {exact: false})
- /**
- * The expectation below tests whether the account
- * balance was requested after the successful registration.
- */
- expect(fetch).toHaveBeenCalledWith(
- "http://localhost/demobanks/default/access-api/testing/register",
- expect.anything() // no need to match auth headers.
- )
- expect(fetch).toHaveBeenCalledWith(
- `http://localhost/demobanks/default/access-api/accounts/${context.username}`,
- expect.anything() // no need to match auth headers.
- )
- })
-})
diff --git a/packages/demobank-ui/tests/declarations.d.ts b/packages/demobank-ui/tests/declarations.d.ts
deleted file mode 100644
index 67e940277..000000000
--- a/packages/demobank-ui/tests/declarations.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-// Enable enzyme adapter's integration with TypeScript
-// See: https://github.com/preactjs/enzyme-adapter-preact-pure#usage-with-typescript
-/// <reference types="enzyme-adapter-preact-pure" />
diff --git a/packages/demobank-ui/tsconfig.json b/packages/demobank-ui/tsconfig.json
index d04c5b964..d9d56ad4f 100644
--- a/packages/demobank-ui/tsconfig.json
+++ b/packages/demobank-ui/tsconfig.json
@@ -1,19 +1,13 @@
{
"compilerOptions": {
/* Basic Options */
- "target": "ES5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */,
- "module": "ESNext" /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
- // "lib": [], /* Specify library files to be included in the compilation: */
+ "target": "ES5",
+ "module": "ES6",
+ "lib": ["DOM", "ES2016"],
"allowJs": true /* Allow javascript files to be compiled. */,
// "checkJs": true, /* Report errors in .js files. */
- "jsx": "react" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */,
- "jsxFactory": "h" /* Specify the JSX factory function to use when targeting react JSX emit, e.g. React.createElement or h. */,
- // "declaration": true, /* Generates corresponding '.d.ts' file. */
- // "sourceMap": true, /* Generates corresponding '.map' file. */
- // "outFile": "./", /* Concatenate and emit output to single file. */
- // "outDir": "./", /* Redirect output structure to the directory. */
- // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
- // "removeComments": true, /* Do not emit comments to output. */
+ "jsx": "react-jsx" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */,
+ "jsxImportSource": "preact",
"noEmit": true /* Do not emit outputs. */,
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
@@ -21,11 +15,7 @@
/* Strict Type-Checking Options */
"strict": true /* Enable all strict type-checking options. */,
- // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
- // "strictNullChecks": true, /* Enable strict null checks. */
- // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
- // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
-
+ "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
@@ -33,14 +23,14 @@
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
- "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
+ "moduleResolution": "Node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
"esModuleInterop": true /* */,
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
- // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
+ "allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */,
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
/* Source Map Options */
@@ -56,5 +46,5 @@
/* Advanced Options */
"skipLibCheck": true /* Skip type checking of declaration files. */
},
- "include": ["src/**/*", "tests/**/*"]
+ "include": ["src/**/*"]
}