Fixed conflicts

This commit is contained in:
Aleksander Rem 2022-09-20 00:17:20 +02:00
commit 8473c648b0
89 changed files with 35960 additions and 25967 deletions

54
.eslintrc.json Normal file
View file

@ -0,0 +1,54 @@
{
"root": true,
"ignorePatterns": [
"projects/**/*"
],
"overrides": [
{
"files": [
"*.ts"
],
"parserOptions": {
"project": [
"tsconfig.json",
"e2e/tsconfig.json"
],
"createDefaultProgram": true
},
"extends": [
"plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@angular-eslint/component-selector": [
"error",
{
"prefix": "app",
"style": "kebab-case",
"type": "element"
}
],
"@angular-eslint/directive-selector": [
"error",
{
"prefix": "app",
"style": "camelCase",
"type": "attribute"
}
],
"@angular-eslint/no-empty-lifecycle-method": "off"
}
},
{
"files": [
"*.html"
],
"extends": [
"plugin:@angular-eslint/template/recommended"
],
"rules": {
"@angular-eslint/template/eqeqeq": "off"
}
}
]
}

View file

@ -7,7 +7,7 @@ on:
jobs: jobs:
# Release draft and share app version via package.json # Release draft and share app version via package.json
pre_build: pre_build:
runs-on: ubuntu-latest runs-on: ubuntu-20.04
outputs: outputs:
output1: ${{ steps.release_drafter.outputs.upload_url }} output1: ${{ steps.release_drafter.outputs.upload_url }}
output2: ${{ steps.package-version.outputs.current-version }} output2: ${{ steps.package-version.outputs.current-version }}
@ -38,17 +38,17 @@ jobs:
strategy: strategy:
matrix: matrix:
include: include:
- os: ubuntu-latest - os: ubuntu-20.04
artifact_name: checksums artifact_name: checksums
asset_name: checksums asset_name: checksums
app_ext: AppImage app_ext: AppImage
app_os: linux app_os: linux
- os: macos-latest - os: macos-11
artifact_name: checksums artifact_name: checksums
asset_name: checksums asset_name: checksums
app_ext: dmg app_ext: dmg
app_os: mac app_os: mac
- os: windows-latest - os: windows-2022
artifact_name: checksums artifact_name: checksums
asset_name: checksums asset_name: checksums
app_ext: exe app_ext: exe
@ -60,12 +60,13 @@ jobs:
uses: actions/checkout@v1 uses: actions/checkout@v1
- name: Install Node.js, NPM and Yarn - name: Install Node.js, NPM and Yarn
uses: actions/setup-node@v1 uses: actions/setup-node@v3
with: with:
node-version: 14 node-version: 16
cache: 'npm'
- name: Install APT dependencies - name: Install APT dependencies
if: matrix.os == 'ubuntu-latest' if: matrix.os == 'ubuntu-20.04'
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install build-essential git -y sudo apt-get install build-essential git -y
@ -74,35 +75,13 @@ jobs:
- name: Install and Build Desktop App - name: Install and Build Desktop App
run: | run: |
npm install -g @angular/cli
npm install npm install
npm run desktop:build npm run desktop:build
- name: Temporarily fix electron-builder - name: Build Electron app
# https://github.com/electron-userland/electron-builder/issues/4176
if: matrix.os != 'macos-latest'
run: | run: |
sed -i 's/\^\[\\w/\^\[.\\w/g' node_modules/builder-util/out/util.js npm run desktop:local
shell: bash
- name: Temporarily fix electron-builder (MacOS)
# https://github.com/electron-userland/electron-builder/issues/4176
if: matrix.os == 'macos-latest'
run: |
sed -i '' 's/\^\[\\w/\^\[.\\w/g' node_modules/builder-util/out/util.js
shell: bash
- name: Build/release Electron app
uses: samuelmeuli/action-electron-builder@v1
with:
# GitHub token, automatically provided to the action
# (No need to define this secret in the repo settings)
github_token: ${{ secrets.GITHUB_TOKEN }}
# is already built
skip_build: true
release: false
args: "-p never" # Do not publish, done in the next step instead
- name: Create Hashes - name: Create Hashes
if: startsWith(github.ref, 'refs/tags/') if: startsWith(github.ref, 'refs/tags/')
@ -116,27 +95,27 @@ jobs:
shell: bash shell: bash
- name: Rename file paths in .yml (Linux) - name: Rename file paths in .yml (Linux)
if: matrix.os == 'ubuntu-latest' && startsWith(github.ref, 'refs/tags/') if: matrix.os == 'ubuntu-20.04' && startsWith(github.ref, 'refs/tags/')
run: | run: |
sed -i '/.AppImage/ s//-Linux.AppImage/g' desktop-app/build/latest-linux.yml | bash sed -i '/.AppImage/ s//-Linux.AppImage/g' desktop-app/build/latest-linux.yml | bash
shell: bash shell: bash
# Special sed command for mac # Special sed command for mac
- name: Rename file paths in .yml (Mac) - name: Rename file paths in .yml (Mac)
if: matrix.os == 'macos-latest' && startsWith(github.ref, 'refs/tags/') if: matrix.os == 'macos-11' && startsWith(github.ref, 'refs/tags/')
run: | run: |
sed -i '' '/.dmg/ s//-Mac.dmg/g' desktop-app/build/latest-mac.yml sed -i '' '/.dmg/ s//-Mac.dmg/g' desktop-app/build/latest-mac.yml
shell: bash shell: bash
- name: Rename file paths in .yml (Windows) - name: Rename file paths in .yml (Windows)
if: matrix.os == 'windows-latest' && startsWith(github.ref, 'refs/tags/') if: matrix.os == 'windows-2022' && startsWith(github.ref, 'refs/tags/')
run: | run: |
sed -i '/.exe/ s//-Windows.exe/g' desktop-app/build/latest.yml | bash sed -i '/.exe/ s//-Windows.exe/g' desktop-app/build/latest.yml | bash
shell: bash shell: bash
# Upload binaries separately for better control which release draft they go into # Upload binaries separately for better control which release draft they go into
- name: Upload Binaries Linux - name: Upload Binaries Linux
if: matrix.os == 'ubuntu-latest' && startsWith(github.ref, 'refs/tags/') if: matrix.os == 'ubuntu-20.04' && startsWith(github.ref, 'refs/tags/')
uses: actions/upload-release-asset@v1 uses: actions/upload-release-asset@v1
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -147,7 +126,7 @@ jobs:
asset_content_type: application/octet-stream asset_content_type: application/octet-stream
- name: Upload Binaries Mac - name: Upload Binaries Mac
if: matrix.os == 'macos-latest' && startsWith(github.ref, 'refs/tags/') if: matrix.os == 'macos-11' && startsWith(github.ref, 'refs/tags/')
uses: actions/upload-release-asset@v1 uses: actions/upload-release-asset@v1
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -158,7 +137,7 @@ jobs:
asset_content_type: application/octet-stream asset_content_type: application/octet-stream
- name: Upload Binaries Windows - name: Upload Binaries Windows
if: matrix.os == 'windows-latest' && startsWith(github.ref, 'refs/tags/') if: matrix.os == 'windows-2022' && startsWith(github.ref, 'refs/tags/')
uses: actions/upload-release-asset@v1 uses: actions/upload-release-asset@v1
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -180,7 +159,7 @@ jobs:
asset_content_type: application/octet-stream asset_content_type: application/octet-stream
- name: Upload yml Linux - name: Upload yml Linux
if: matrix.os == 'ubuntu-latest' && startsWith(github.ref, 'refs/tags/') if: matrix.os == 'ubuntu-20.04' && startsWith(github.ref, 'refs/tags/')
uses: actions/upload-release-asset@v1 uses: actions/upload-release-asset@v1
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -191,7 +170,7 @@ jobs:
asset_content_type: application/octet-stream asset_content_type: application/octet-stream
- name: Upload yml Mac - name: Upload yml Mac
if: matrix.os == 'macos-latest' && startsWith(github.ref, 'refs/tags/') if: matrix.os == 'macos-11' && startsWith(github.ref, 'refs/tags/')
uses: actions/upload-release-asset@v1 uses: actions/upload-release-asset@v1
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -202,7 +181,7 @@ jobs:
asset_content_type: application/octet-stream asset_content_type: application/octet-stream
- name: Upload yml Windows - name: Upload yml Windows
if: matrix.os == 'windows-latest' && startsWith(github.ref, 'refs/tags/') if: matrix.os == 'windows-2022' && startsWith(github.ref, 'refs/tags/')
uses: actions/upload-release-asset@v1 uses: actions/upload-release-asset@v1
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -16,7 +16,7 @@ jobs:
- name: Setup NodeJS - name: Setup NodeJS
uses: actions/setup-node@v1 uses: actions/setup-node@v1
with: with:
node-version: 14 node-version: 16
- name: Install APT dependencies - name: Install APT dependencies
run: | run: |

View file

@ -12,9 +12,9 @@ jobs:
uses: actions/checkout@v1 uses: actions/checkout@v1
- name: Install Node.js, NPM and Yarn - name: Install Node.js, NPM and Yarn
uses: actions/setup-node@v1 uses: actions/setup-node@v2
with: with:
node-version: 14 node-version: '16'
- name: Install APT dependencies - name: Install APT dependencies
run: | run: |

1
.gitignore vendored
View file

@ -28,6 +28,7 @@
!.vscode/extensions.json !.vscode/extensions.json
# misc # misc
/.angular/cache
/.sass-cache /.sass-cache
/connect.lock /connect.lock
/coverage /coverage

View file

@ -6,7 +6,7 @@
- Communication with the network is done via nano RPC and Websocket protocols, private or public on any nano network. - Communication with the network is done via nano RPC and Websocket protocols, private or public on any nano network.
## Development Prerequisites ## Development Prerequisites
- [NodeJS](https://nodejs.org) v14.x + NPM v6.x - [NodeJS](https://nodejs.org) v16.x + NPM v8.x
- Angular CLI: `npm install -g @angular/cli` - Angular CLI: `npm install -g @angular/cli`
## Development Guide ## Development Guide

View file

@ -1,5 +1,5 @@
# build the angular app # build the angular app
FROM node:14 AS build FROM node:16 AS build
WORKDIR /usr/src/app WORKDIR /usr/src/app
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
libudev-dev \ libudev-dev \

View file

@ -11,7 +11,6 @@
"build": { "build": {
"builder": "@angular-devkit/build-angular:browser", "builder": "@angular-devkit/build-angular:browser",
"options": { "options": {
"aot": true,
"outputPath": "dist", "outputPath": "dist",
"index": "src/index.html", "index": "src/index.html",
"main": "src/main.ts", "main": "src/main.ts",
@ -28,27 +27,33 @@
], ],
"scripts": [], "scripts": [],
"allowedCommonJsDependencies": [ "allowedCommonJsDependencies": [
"qrcode", "qrcode",
"bip39", "bip39",
"@zxing/library", "@zxing/library",
"bignumber.js", "bignumber.js",
"nanocurrency", "nanocurrency",
"hw-app-nano", "hw-app-nano",
"crypto-js", "crypto-js",
"blakejs", "blakejs",
"nanocurrency-web", "nanocurrency-web",
"bignumber.js", "bignumber.js",
"u2f-api", "u2f-api",
"create-hash", "create-hash",
"randombytes", "randombytes",
"pbkdf2", "pbkdf2",
"zxcvbn", "zxcvbn",
"url", "url",
"punycode", "punycode",
"querystring", "querystring",
"hw-transport-webusb", "hw-transport-webusb",
"hw-transport-web-ble" "hw-transport-web-ble"
] ],
"vendorChunk": true,
"extractLicenses": false,
"buildOptimizer": false,
"sourceMap": true,
"optimization": false,
"namedChunks": true
}, },
"configurations": { "configurations": {
"production": { "production": {
@ -61,9 +66,7 @@
"optimization": true, "optimization": true,
"outputHashing": "all", "outputHashing": "all",
"sourceMap": false, "sourceMap": false,
"extractCss": true,
"namedChunks": false, "namedChunks": false,
"aot": true,
"extractLicenses": true, "extractLicenses": true,
"vendorChunk": false, "vendorChunk": false,
"buildOptimizer": true, "buildOptimizer": true,
@ -86,9 +89,7 @@
"optimization": true, "optimization": true,
"outputHashing": "all", "outputHashing": "all",
"sourceMap": false, "sourceMap": false,
"extractCss": true,
"namedChunks": false, "namedChunks": false,
"aot": true,
"extractLicenses": true, "extractLicenses": true,
"vendorChunk": false, "vendorChunk": false,
"buildOptimizer": true, "buildOptimizer": true,
@ -99,7 +100,8 @@
} }
] ]
} }
} },
"defaultConfiguration": ""
}, },
"serve": { "serve": {
"builder": "@angular-devkit/build-angular:dev-server", "builder": "@angular-devkit/build-angular:dev-server",
@ -140,14 +142,11 @@
} }
}, },
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@angular-eslint/builder:lint",
"options": { "options": {
"tsConfig": [ "lintFilePatterns": [
"src/tsconfig.app.json", "src/**/*.ts",
"src/tsconfig.spec.json" "src/**/*.html"
],
"exclude": [
"**/node_modules/**"
] ]
} }
} }
@ -164,17 +163,6 @@
"protractorConfig": "./protractor.conf.js", "protractorConfig": "./protractor.conf.js",
"devServerTarget": "nault:serve" "devServerTarget": "nault:serve"
} }
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"e2e/tsconfig.e2e.json"
],
"exclude": [
"**/node_modules/**"
]
}
} }
} }
} }
@ -188,5 +176,8 @@
"@schematics/angular:directive": { "@schematics/angular:directive": {
"prefix": "app" "prefix": "app"
} }
},
"cli": {
"defaultCollection": "@angular-eslint/schematics"
} }
} }

View file

@ -6,15 +6,16 @@
"declaration": false, "declaration": false,
"moduleResolution": "node", "moduleResolution": "node",
"esModuleInterop": true, "esModuleInterop": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"target": "es5", "allowSyntheticDefaultImports": true,
"target": "es2017",
"module": "commonjs",
"baseUrl": ".", "baseUrl": ".",
"typeRoots": [ "typeRoots": [
"../node_modules/@types" "../node_modules/@types"
], ],
"lib": [ "lib": [
"es2017", "es2020",
"dom" "dom"
] ]
}, },

View file

@ -1,5 +1,5 @@
{ {
"extends": "../tsconfig.base.json", "extends": "../tsconfig.json",
"compilerOptions": { "compilerOptions": {
"outDir": "../out-tsc/e2e", "outDir": "../out-tsc/e2e",
"baseUrl": "./", "baseUrl": "./",

37059
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -16,44 +16,43 @@
"release": "npm run desktop:build && electron-builder", "release": "npm run desktop:build && electron-builder",
"wallet:dev": "ng serve --open", "wallet:dev": "ng serve --open",
"wallet:dev-ssl": "ng serve --ssl --open", "wallet:dev-ssl": "ng serve --ssl --open",
"wallet:build": "ng build --prod", "wallet:build": "ng build --configuration production",
"wallet:build-desktop": "ng build --configuration=desktop --base-href ", "wallet:build-desktop": "ng build --configuration=desktop --base-href ",
"desktop:compile": "cd desktop-app && tsc && cd ..", "desktop:compile": "cd desktop-app && tsc && cd ..",
"desktop:build": "npm run wallet:build-desktop && npm run desktop:compile", "desktop:build": "npm run wallet:build-desktop && npm run desktop:compile",
"desktop:build-local": "npm run desktop:build && npm run desktop:local", "desktop:build-local": "npm run desktop:build && npm run desktop:local",
"desktop:dev": "npm run desktop:compile && electron desktop-app/dist/desktop-app.js", "desktop:dev": "npm run desktop:compile && electron desktop-app/dist/desktop-app.js",
"desktop:local": "electron-builder", "desktop:local": "electron-builder -p never"
"desktop:full": "electron-builder -wml --x64",
"desktop:publish": "electron-builder -wml --x64 -p always"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular-devkit/core": "10.0.5", "@angular-devkit/core": "13.1.2",
"@angular/animations": "^10.0.7", "@angular/animations": "^13.1.1",
"@angular/common": "^10.0.7", "@angular/common": "^13.1.1",
"@angular/compiler": "^10.0.7", "@angular/compiler": "^13.1.1",
"@angular/core": "^10.0.7", "@angular/core": "^13.1.1",
"@angular/forms": "^10.0.7", "@angular/forms": "^13.1.1",
"@angular/localize": "^10.0.7", "@angular/localize": "^13.1.1",
"@angular/platform-browser": "^10.0.7", "@angular/platform-browser": "^13.1.1",
"@angular/platform-browser-dynamic": "^10.0.7", "@angular/platform-browser-dynamic": "^13.1.1",
"@angular/router": "^10.0.7", "@angular/router": "^13.1.1",
"@angular/service-worker": "^10.2.5", "@angular/service-worker": "^13.1.1",
"@ledgerhq/hw-transport": "^5.51.1", "@ledgerhq/hw-transport": "^6.27.1",
"@ledgerhq/hw-transport-node-ble": "^6.20.0", "@ledgerhq/hw-transport-node-ble": "^6.27.1",
"@ledgerhq/hw-transport-node-hid": "^6.20.0", "@ledgerhq/hw-transport-node-hid": "^6.27.1",
"@ledgerhq/hw-transport-u2f": "^5.34.0", "@ledgerhq/hw-transport-u2f": "^5.34.0",
"@ledgerhq/hw-transport-web-ble": "^5.51.1", "@ledgerhq/hw-transport-web-ble": "^6.27.1",
"@ledgerhq/hw-transport-webhid": "^5.51.1", "@ledgerhq/hw-transport-webhid": "^6.27.1",
"@ledgerhq/hw-transport-webusb": "^5.53.1", "@ledgerhq/hw-transport-webusb": "^6.27.1",
"@ledgerhq/logs": "^5.50.0", "@ledgerhq/logs": "^6.10.0",
"@ng-bootstrap/ng-bootstrap": "^7.0.0", "@ng-bootstrap/ng-bootstrap": "^11.0.0",
"@ngneat/transloco": "^2.22.0", "@ngneat/transloco": "^3.1.1",
"@types/crypto-js": "^3.1.38", "@types/crypto-js": "^3.1.38",
"@types/w3c-web-hid": "^1.0.2", "@types/w3c-web-hid": "^1.0.2",
"@types/w3c-web-usb": "^1.0.5", "@types/w3c-web-usb": "^1.0.5",
"@zxing/ngx-scanner": "^3.0.0", "@zxing/browser": "^0.0.10",
"angular-password-strength-meter": "^3.0.0", "@zxing/library": "^0.18.6",
"@zxing/ngx-scanner": "^3.4.0",
"babel-polyfill": "^6.26.0", "babel-polyfill": "^6.26.0",
"babel-runtime": "^6.26.0", "babel-runtime": "^6.26.0",
"bignumber.js": "^5.0.0", "bignumber.js": "^5.0.0",
@ -77,37 +76,44 @@
"safe-buffer": "^5.2.1", "safe-buffer": "^5.2.1",
"tslib": "^2.0.0", "tslib": "^2.0.0",
"tweetnacl": "^1.0.0", "tweetnacl": "^1.0.0",
"zone.js": "~0.10.3" "url": "^0.11.0",
"usb": "^2.0.3",
"zone.js": "~0.11.4"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^0.1000.5", "@angular-devkit/build-angular": "^13.1.2",
"@angular/cli": "^10.0.5", "@angular-eslint/builder": "13.2.1",
"@angular/compiler-cli": "^10.0.7", "@angular-eslint/eslint-plugin": "13.2.1",
"@angular/language-service": "^10.0.7", "@angular-eslint/eslint-plugin-template": "13.2.1",
"@angular-eslint/schematics": "13.2.1",
"@angular-eslint/template-parser": "13.2.1",
"@angular/cli": "^13.1.2",
"@angular/compiler-cli": "^13.1.1",
"@angular/language-service": "^13.1.1",
"@types/bip39": "^2.4.0", "@types/bip39": "^2.4.0",
"@types/jasmine": "~2.5.53", "@types/jasmine": "~3.6.0",
"@types/jasminewd2": "~2.0.2", "@types/jasminewd2": "~2.0.2",
"@types/ledgerhq__hw-transport": "^4.21.3", "@types/ledgerhq__hw-transport": "^4.21.3",
"@types/node": "^12.20.39", "@types/node": "^12.20.39",
"@types/qrcode": "^0.8.1", "@types/qrcode": "^0.8.1",
"codelyzer": "^6.0.0", "@typescript-eslint/eslint-plugin": "5.17.0",
"@typescript-eslint/parser": "5.17.0",
"electron": "^9.4.0", "electron": "^9.4.0",
"electron-builder": "^22.7.0", "electron-builder": "^22.14.5",
"jasmine-core": "~3.5.0", "eslint": "^8.12.0",
"jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~5.0.0", "jasmine-spec-reporter": "~5.0.0",
"karma": "~5.0.0", "karma": "~6.3.9",
"karma-chrome-launcher": "~3.1.0", "karma-chrome-launcher": "~3.1.0",
"karma-cli": "~2.0.0", "karma-cli": "~2.0.0",
"karma-coverage-istanbul-reporter": "~3.0.2", "karma-coverage-istanbul-reporter": "~3.0.2",
"karma-jasmine": "~3.3.0", "karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0", "karma-jasmine-html-reporter": "^1.5.0",
"protractor": "~7.0.0", "protractor": "~7.0.0",
"ts-node": "~3.2.0", "ts-node": "~3.2.0",
"tslint": "~6.1.3", "typescript": "~4.5.4",
"typescript": "~3.9.7", "uikit": "^3.9.4",
"uikit": "^3.0.0-beta.40", "worker-loader": "^3.0.8"
"worker-loader": "^2.0.0",
"zxcvbn3": "^0.1.1"
}, },
"build": { "build": {
"appId": "cc.nault", "appId": "cc.nault",

View file

@ -52,7 +52,7 @@ const routes: Routes = [
@NgModule({ @NgModule({
imports: [ imports: [
// On the desktop apps, use hashes so it works properly using only index.html // On the desktop apps, use hashes so it works properly using only index.html
RouterModule.forRoot(routes, { useHash: environment.desktop }), RouterModule.forRoot(routes, { useHash: environment.desktop, relativeLinkResolution: 'legacy' }),
], ],
declarations: [], declarations: [],
exports: [RouterModule] exports: [RouterModule]

View file

@ -1,24 +1,24 @@
import { TestBed, async } from '@angular/core/testing'; import { TestBed, waitForAsync } from '@angular/core/testing';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
describe('AppComponent', () => { describe('AppComponent', () => {
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ declarations: [
AppComponent AppComponent
], ],
}).compileComponents(); }).compileComponents();
})); }));
it('should create the app', async(() => { it('should create the app', waitForAsync(() => {
const fixture = TestBed.createComponent(AppComponent); const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance; const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy(); expect(app).toBeTruthy();
})); }));
it(`should have as title 'app'`, async(() => { it(`should have as title 'app'`, waitForAsync(() => {
const fixture = TestBed.createComponent(AppComponent); const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance; const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('app'); expect(app.title).toEqual('app');
})); }));
it('should render title in a h1 tag', async(() => { it('should render title in a h1 tag', waitForAsync(() => {
const fixture = TestBed.createComponent(AppComponent); const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges(); fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement; const compiled = fixture.debugElement.nativeElement;

View file

@ -57,7 +57,6 @@ import { InstallWidgetComponent } from './components/install-widget/install-widg
import { QrModalComponent } from './components/qr-modal/qr-modal.component'; import { QrModalComponent } from './components/qr-modal/qr-modal.component';
import { QrModalService } from './services/qr-modal.service'; import { QrModalService } from './services/qr-modal.service';
import { NgbModule, NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { NgbModule, NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { PasswordStrengthMeterModule } from 'angular-password-strength-meter';
import {MusigService} from './services/musig.service'; import {MusigService} from './services/musig.service';
// QR code module // QR code module
@ -71,6 +70,7 @@ import { MultisigComponent } from './components/multisig/multisig.component';
import { KeygeneratorComponent } from './components/keygenerator/keygenerator.component'; import { KeygeneratorComponent } from './components/keygenerator/keygenerator.component';
import { NanoTransactionMobileComponent } from './components/helpers/nano-transaction-mobile/nano-transaction-mobile.component'; import { NanoTransactionMobileComponent } from './components/helpers/nano-transaction-mobile/nano-transaction-mobile.component';
import { TranslocoRootModule } from './transloco/transloco-root.module'; import { TranslocoRootModule } from './transloco/transloco-root.module';
import { NoPaddingZerosPipe } from './pipes/no-padding-zeros.pipe';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -111,6 +111,7 @@ import { TranslocoRootModule } from './transloco/transloco-root.module';
MultisigComponent, MultisigComponent,
KeygeneratorComponent, KeygeneratorComponent,
NanoTransactionMobileComponent, NanoTransactionMobileComponent,
NoPaddingZerosPipe
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
@ -121,7 +122,6 @@ import { TranslocoRootModule } from './transloco/transloco-root.module';
ClipboardModule, ClipboardModule,
ZXingScannerModule, ZXingScannerModule,
NgbModule, NgbModule,
PasswordStrengthMeterModule,
ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production && !environment.desktop }), ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production && !environment.desktop }),
TranslocoRootModule, TranslocoRootModule,
], ],
@ -148,6 +148,7 @@ import { TranslocoRootModule } from './transloco/transloco-root.module';
QrModalService, QrModalService,
DeeplinkService, DeeplinkService,
MusigService, MusigService,
NoPaddingZerosPipe
], ],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })

View file

@ -519,7 +519,7 @@
</div> </div>
<!-- Modal for remote receive incoming --> <!-- Modal for remote receive incoming -->
<div id="receive-modal" uk-modal> <div class="modal-position-bottom" id="receive-modal" uk-modal>
<div class="uk-modal-dialog uk-modal-body modal-qr"> <div class="uk-modal-dialog uk-modal-body modal-qr">
<button class="uk-modal-close-default" type="button" uk-close></button> <button class="uk-modal-close-default" type="button" uk-close></button>
<div class="uk-modal-header"> <div class="uk-modal-header">
@ -547,7 +547,7 @@
</div> </div>
<!-- Modal for creating send and change block for remote signing--> <!-- Modal for creating send and change block for remote signing-->
<div id="block-modal" uk-modal> <div class="modal-position-bottom" id="block-modal" uk-modal>
<div class="uk-modal-dialog uk-modal-body modal-block"> <div class="uk-modal-dialog uk-modal-body modal-block">
<button class="uk-modal-close-default" type="button" uk-close></button> <button class="uk-modal-close-default" type="button" uk-close></button>
<div class="uk-modal-header"> <div class="uk-modal-header">
@ -678,7 +678,7 @@
</div> </div>
</div> </div>
<div id="qr-code-modal" uk-modal> <div class="modal-position-bottom" id="qr-code-modal" uk-modal>
<div class="uk-modal-dialog uk-margin-auto-vertical"> <div class="uk-modal-dialog uk-margin-auto-vertical">
<button class="uk-modal-close-default" type="button" uk-close></button> <button class="uk-modal-close-default" type="button" uk-close></button>
<div class="uk-modal-body"> <div class="uk-modal-body">

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { AccountDetailsComponent } from './account-details.component'; import { AccountDetailsComponent } from './account-details.component';
@ -6,7 +6,7 @@ describe('AccountDetailsComponent', () => {
let component: AccountDetailsComponent; let component: AccountDetailsComponent;
let fixture: ComponentFixture<AccountDetailsComponent>; let fixture: ComponentFixture<AccountDetailsComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ AccountDetailsComponent ] declarations: [ AccountDetailsComponent ]
}) })

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { AccountsComponent } from './accounts.component'; import { AccountsComponent } from './accounts.component';
@ -6,7 +6,7 @@ describe('AccountsComponent', () => {
let component: AccountsComponent; let component: AccountsComponent;
let fixture: ComponentFixture<AccountsComponent>; let fixture: ComponentFixture<AccountsComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ AccountsComponent ] declarations: [ AccountsComponent ]
}) })

View file

@ -184,8 +184,8 @@
</div> </div>
</div> </div>
<div class="uk-card-footer uk-text-right@s nlt-button-group"> <div class="uk-card-footer uk-text-right@s nlt-button-group">
<button class="uk-button uk-button-danger" (click)="cancelNewAddress()">{{ 'general.cancel' | transloco }}</button> <button class="uk-button uk-button-danger uk-width-1-1@s uk-width-auto@m" (click)="cancelNewAddress()">{{ 'general.cancel' | transloco }}</button>
<button class="uk-button uk-button-primary" (click)="saveNewAddress()">{{ 'general.save' | transloco }}</button> <button class="uk-button uk-button-primary uk-width-1-1@s uk-width-auto@m" (click)="saveNewAddress()">{{ 'general.save' | transloco }}</button>
</div> </div>
</div> </div>
</div> </div>
@ -231,9 +231,9 @@
<span *ngIf="!addressBookShowQRExport">{{ 'address-book.you-can-still-import-your-address-book-by-using-the-url' | transloco }}</span> <span *ngIf="!addressBookShowQRExport">{{ 'address-book.you-can-still-import-your-address-book-by-using-the-url' | transloco }}</span>
<br><br> <br><br>
<input type="text" class="uk-input" style="max-width: 750px;" value="{{ addressBookQRExportUrl }}"><br> <input type="text" class="uk-input" style="max-width: 750px;" value="{{ addressBookQRExportUrl }}"><br>
<div class="nlt-button-group uk-margin-small-top"> <div class="nlt-button-group">
<button ngxClipboard [cbContent]="addressBookQRExportUrl" (cbOnSuccess)="notificationService.sendSuccess('Address book export copied to clipboard!')" class="uk-button uk-button-secondary" style="margin-left: 0;">{{ 'general.copy-to-clipboard' | transloco }}</button> <button ngxClipboard [cbContent]="addressBookQRExportUrl" (cbOnSuccess)="notificationService.sendSuccess('Address book export copied to clipboard!')" class="uk-button uk-button-secondary uk-width-1-1@s uk-width-auto@m uk-margin-small-top" style="margin-left: 0;">{{ 'general.copy-to-clipboard' | transloco }}</button>
<button (click)="exportAddressBookToFile()" class="uk-button uk-button-primary">{{ 'address-book.export-as-file' | transloco }}</button> <button (click)="exportAddressBookToFile()" class="uk-button uk-button-primary uk-width-1-1@s uk-width-auto@m uk-margin-small-top">{{ 'address-book.export-as-file' | transloco }}</button>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { AddressBookComponent } from './address-book.component'; import { AddressBookComponent } from './address-book.component';
@ -6,7 +6,7 @@ describe('AddressBookComponent', () => {
let component: AddressBookComponent; let component: AddressBookComponent;
let fixture: ComponentFixture<AddressBookComponent>; let fixture: ComponentFixture<AddressBookComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ AddressBookComponent ] declarations: [ AddressBookComponent ]
}) })

View file

@ -423,24 +423,20 @@ export class AddressBookComponent implements OnInit, AfterViewInit, OnDestroy {
// Check for iOS, which is weird with saving files // Check for iOS, which is weird with saving files
const iOS = !!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform); const iOS = !!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform);
if (window.navigator.msSaveOrOpenBlob) { const elem = window.document.createElement('a');
window.navigator.msSaveBlob(blob, fileName); const objUrl = window.URL.createObjectURL(blob);
if (iOS) {
elem.href = `data:attachment/file,${JSON.stringify(exportData)}`;
} else { } else {
const elem = window.document.createElement('a'); elem.href = objUrl;
const objUrl = window.URL.createObjectURL(blob);
if (iOS) {
elem.href = `data:attachment/file,${JSON.stringify(exportData)}`;
} else {
elem.href = objUrl;
}
elem.download = fileName;
document.body.appendChild(elem);
elem.click();
setTimeout(function() {
document.body.removeChild(elem);
window.URL.revokeObjectURL(objUrl);
}, 200);
} }
elem.download = fileName;
document.body.appendChild(elem);
elem.click();
setTimeout(function() {
document.body.removeChild(elem);
window.URL.revokeObjectURL(objUrl);
}, 200);
} }
} }

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ChangeRepWidgetComponent } from './change-rep-widget.component'; import { ChangeRepWidgetComponent } from './change-rep-widget.component';
@ -6,7 +6,7 @@ describe('ChangeRepWidgetComponent', () => {
let component: ChangeRepWidgetComponent; let component: ChangeRepWidgetComponent;
let fixture: ComponentFixture<ChangeRepWidgetComponent>; let fixture: ComponentFixture<ChangeRepWidgetComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ChangeRepWidgetComponent ] declarations: [ ChangeRepWidgetComponent ]
}) })

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ConfigureAppComponent } from './configure-app.component'; import { ConfigureAppComponent } from './configure-app.component';
@ -6,7 +6,7 @@ describe('ConfigureAppComponent', () => {
let component: ConfigureAppComponent; let component: ConfigureAppComponent;
let fixture: ComponentFixture<ConfigureAppComponent>; let fixture: ComponentFixture<ConfigureAppComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ConfigureAppComponent ] declarations: [ ConfigureAppComponent ]
}) })

View file

@ -348,7 +348,13 @@ export class ConfigureAppComponent implements OnInit {
if (resaveWallet && newStorage === this.storageOptions[1].value) { if (resaveWallet && newStorage === this.storageOptions[1].value) {
const UIkit = window['UIkit']; const UIkit = window['UIkit'];
try { try {
await UIkit.modal.confirm('<p class="uk-alert uk-alert-danger"><br><span class="uk-flex"><span uk-icon="icon: warning; ratio: 3;" class="uk-align-center"></span></span><span style="font-size: 18px;">' + this.translocoService.translate('configure-app.you-are-about-to-disable-storage-of-all-wallet-data-which') + '</span><br><br><b style="font-size: 18px;">' + this.translocoService.translate('reset-wallet.before-continuing-make-sure-you-have-saved-the-nano-seed') + '</b><br><br><span style="font-size: 18px;"><b>' + this.translocoService.translate('reset-wallet.you-will-not-be-able-to-recover-the-funds-without-a-backup') + '</b></span></p><br>'); await UIkit.modal.confirm(
`<p class="uk-alert uk-alert-danger"><br><span class="uk-flex"><span uk-icon="icon: warning; ratio: 3;" class="uk-align-center"></span></span>
<span style="font-size: 18px;">
${ this.translocoService.translate('configure-app.you-are-about-to-disable-storage-of-all-wallet-data-which') }
</span><br>
${ this.walletService.isConfigured() ? '<br><b style="font-size: 18px;">' + this.translocoService.translate('reset-wallet.before-continuing-make-sure-you-have-saved-the-nano-seed') + '</b><br><br><span style="font-size: 18px;"><b>' + this.translocoService.translate('reset-wallet.you-will-not-be-able-to-recover-the-funds-without-a-backup') + '</b></span></p><br>' : '' }`
);
} catch (err) { } catch (err) {
// pressing cancel, reset storage setting and interrupt // pressing cancel, reset storage setting and interrupt
this.selectedStorage = this.storageOptions[0].value; this.selectedStorage = this.storageOptions[0].value;

View file

@ -508,7 +508,7 @@
<div uk-grid> <div uk-grid>
<div class="uk-width-1-2@m"> <div class="uk-width-1-2@m">
<input type="password" class="uk-input" [(ngModel)]="walletPasswordModel" placeholder="New Wallet Password"> <input type="password" class="uk-input" [(ngModel)]="walletPasswordModel" placeholder="New Wallet Password">
<password-strength-meter *ngIf="walletPasswordModel.length > 0" [password]="walletPasswordModel" [enableFeedback]="true" [minPasswordLength]="6"></password-strength-meter> <!-- <password-strength-meter *ngIf="walletPasswordModel.length > 0" [password]="walletPasswordModel" [enableFeedback]="true" [minPasswordLength]="6"></password-strength-meter> -->
<span class="password-helper" *ngIf="walletPasswordModel.length > 0 && walletPasswordModel.length < 6">{{ 'configure-wallet.set-wallet-password.errors.password-must-be-at-least-x-characters-long' | transloco: { minCharacters: 6 } }}</span> <span class="password-helper" *ngIf="walletPasswordModel.length > 0 && walletPasswordModel.length < 6">{{ 'configure-wallet.set-wallet-password.errors.password-must-be-at-least-x-characters-long' | transloco: { minCharacters: 6 } }}</span>
<span class="password-helper" *ngIf="walletPasswordConfirmModel.length >= 6 && walletPasswordModel !== walletPasswordConfirmModel">{{ 'configure-wallet.set-wallet-password.errors.passwords-do-not-match' | transloco }}</span> <span class="password-helper" *ngIf="walletPasswordConfirmModel.length >= 6 && walletPasswordModel !== walletPasswordConfirmModel">{{ 'configure-wallet.set-wallet-password.errors.passwords-do-not-match' | transloco }}</span>
</div> </div>

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ConfigureWalletComponent } from './configure-wallet.component'; import { ConfigureWalletComponent } from './configure-wallet.component';
@ -6,7 +6,7 @@ describe('ConfigureWalletComponent', () => {
let component: ConfigureWalletComponent; let component: ConfigureWalletComponent;
let fixture: ComponentFixture<ConfigureWalletComponent>; let fixture: ComponentFixture<ConfigureWalletComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ConfigureWalletComponent ] declarations: [ ConfigureWalletComponent ]
}) })

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ConverterComponent } from './converter.component'; import { ConverterComponent } from './converter.component';
@ -6,7 +6,7 @@ describe('ConverterComponent', () => {
let component: ConverterComponent; let component: ConverterComponent;
let fixture: ComponentFixture<ConverterComponent>; let fixture: ComponentFixture<ConverterComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ConverterComponent ] declarations: [ ConverterComponent ]
}) })

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { NanoAccountIdComponent } from './nano-account-id.component'; import { NanoAccountIdComponent } from './nano-account-id.component';
@ -6,7 +6,7 @@ describe('NanoAccountIdComponent', () => {
let component: NanoAccountIdComponent; let component: NanoAccountIdComponent;
let fixture: ComponentFixture<NanoAccountIdComponent>; let fixture: ComponentFixture<NanoAccountIdComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ NanoAccountIdComponent ] declarations: [ NanoAccountIdComponent ]
}) })

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { NanoIdenticonComponent } from './nano-identicon.component'; import { NanoIdenticonComponent } from './nano-identicon.component';
@ -6,7 +6,7 @@ describe('NanoIdenticonComponent', () => {
let component: NanoIdenticonComponent; let component: NanoIdenticonComponent;
let fixture: ComponentFixture<NanoIdenticonComponent>; let fixture: ComponentFixture<NanoIdenticonComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ NanoIdenticonComponent ] declarations: [ NanoIdenticonComponent ]
}) })

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { NanoTransactionMobileComponent } from './nano-transaction-mobile.component'; import { NanoTransactionMobileComponent } from './nano-transaction-mobile.component';
@ -6,7 +6,7 @@ describe('NanoTransactionMobileComponent', () => {
let component: NanoTransactionMobileComponent; let component: NanoTransactionMobileComponent;
let fixture: ComponentFixture<NanoTransactionMobileComponent>; let fixture: ComponentFixture<NanoTransactionMobileComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ NanoTransactionMobileComponent ] declarations: [ NanoTransactionMobileComponent ]
}) })

View file

@ -65,8 +65,8 @@
<div class="uk-card-footer"> <div class="uk-card-footer">
<div uk-grid> <div uk-grid>
<div class="nlt-button-group uk-width-1-1 uk-text-right"> <div class="nlt-button-group uk-width-1-1 uk-text-right">
<button routerLink="/address-book" class="uk-button uk-button-danger">Cancel</button> <button routerLink="/address-book" class="uk-button uk-button-danger uk-width-1-1@s uk-width-auto@m">Cancel</button>
<button (click)="confirmImport()" class="uk-button uk-button-primary">Import Entries</button> <button (click)="confirmImport()" class="uk-button uk-button-primary uk-width-1-1@s uk-width-auto@m">Import Entries</button>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ImportAddressBookComponent } from './import-address-book.component'; import { ImportAddressBookComponent } from './import-address-book.component';
@ -6,7 +6,7 @@ describe('ImportAddressBookComponent', () => {
let component: ImportAddressBookComponent; let component: ImportAddressBookComponent;
let fixture: ComponentFixture<ImportAddressBookComponent>; let fixture: ComponentFixture<ImportAddressBookComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ImportAddressBookComponent ] declarations: [ ImportAddressBookComponent ]
}) })

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ImportWalletComponent } from './import-wallet.component'; import { ImportWalletComponent } from './import-wallet.component';
@ -6,7 +6,7 @@ describe('ImportWalletComponent', () => {
let component: ImportWalletComponent; let component: ImportWalletComponent;
let fixture: ComponentFixture<ImportWalletComponent>; let fixture: ComponentFixture<ImportWalletComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ImportWalletComponent ] declarations: [ ImportWalletComponent ]
}) })

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { InstallWidgetComponent } from './install-widget.component'; import { InstallWidgetComponent } from './install-widget.component';
@ -6,7 +6,7 @@ describe('InstallWidgetComponent', () => {
let component: InstallWidgetComponent; let component: InstallWidgetComponent;
let fixture: ComponentFixture<InstallWidgetComponent>; let fixture: ComponentFixture<InstallWidgetComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ InstallWidgetComponent ] declarations: [ InstallWidgetComponent ]
}) })

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { KeygeneratorComponent } from './keygenerator.component'; import { KeygeneratorComponent } from './keygenerator.component';
@ -6,7 +6,7 @@ describe('KeygeneratorComponent', () => {
let component: KeygeneratorComponent; let component: KeygeneratorComponent;
let fixture: ComponentFixture<KeygeneratorComponent>; let fixture: ComponentFixture<KeygeneratorComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ KeygeneratorComponent ] declarations: [ KeygeneratorComponent ]
}) })

View file

@ -6,7 +6,7 @@ import {NotificationService} from '../../services/notification.service';
@Component({ @Component({
selector: 'app-keygenerator', selector: 'app-keygenerator',
templateUrl: './keygenerator.component.html', templateUrl: './keygenerator.component.html',
styleUrls: ['./keygenerator.component.less'] styleUrls: ['./keygenerator.component.css']
}) })
export class KeygeneratorComponent implements OnInit { export class KeygeneratorComponent implements OnInit {
seed = ''; seed = '';

View file

@ -116,8 +116,8 @@
</div> </div>
</div> </div>
<div class="uk-card-footer uk-text-right@s nlt-button-group"> <div class="uk-card-footer uk-text-right@s nlt-button-group">
<button class="uk-button uk-button-danger" (click)="cancelNewRep()">Cancel</button> <button class="uk-button uk-button-danger uk-width-1-1@s uk-width-auto@m" (click)="cancelNewRep()">Cancel</button>
<button class="uk-button uk-button-primary" (click)="saveNewRepresentative()">Save</button> <button class="uk-button uk-button-primary uk-width-1-1@s uk-width-auto@m" (click)="saveNewRepresentative()">Save</button>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ManageRepresentativesComponent } from './manage-representatives.component'; import { ManageRepresentativesComponent } from './manage-representatives.component';
@ -6,7 +6,7 @@ describe('ManageRepresentativesComponent', () => {
let component: ManageRepresentativesComponent; let component: ManageRepresentativesComponent;
let fixture: ComponentFixture<ManageRepresentativesComponent>; let fixture: ComponentFixture<ManageRepresentativesComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ManageRepresentativesComponent ] declarations: [ ManageRepresentativesComponent ]
}) })

View file

@ -11,7 +11,7 @@
<div uk-grid> <div uk-grid>
<div class="uk-width-1-2@s"> <div class="uk-width-1-2@s">
<input class="uk-input" [(ngModel)]="newPassword" placeholder="New Password" type="password"> <input class="uk-input" [(ngModel)]="newPassword" placeholder="New Password" type="password">
<password-strength-meter *ngIf="newPassword.length > 0" [password]="newPassword" [enableFeedback]="true" [minPasswordLength]="6"></password-strength-meter> <!-- <password-strength-meter *ngIf="newPassword.length > 0" [password]="newPassword" [enableFeedback]="true" [minPasswordLength]="6"></password-strength-meter> -->
<span class="password-helper" *ngIf="newPassword.length > 0 && newPassword.length < 6">Password must be at least 6 characters long</span> <span class="password-helper" *ngIf="newPassword.length > 0 && newPassword.length < 6">Password must be at least 6 characters long</span>
<span class="password-helper" *ngIf="confirmPassword.length >= 6 && newPassword !== confirmPassword">Passwords do not match!</span> <span class="password-helper" *ngIf="confirmPassword.length >= 6 && newPassword !== confirmPassword">Passwords do not match!</span>
</div> </div>

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ManageWalletComponent } from './manage-wallet.component'; import { ManageWalletComponent } from './manage-wallet.component';
@ -6,7 +6,7 @@ describe('ManageWalletComponent', () => {
let component: ManageWalletComponent; let component: ManageWalletComponent;
let fixture: ComponentFixture<ManageWalletComponent>; let fixture: ComponentFixture<ManageWalletComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ManageWalletComponent ] declarations: [ ManageWalletComponent ]
}) })

View file

@ -155,31 +155,27 @@ export class ManageWalletComponent implements OnInit {
// Check for iOS, which is weird with saving files // Check for iOS, which is weird with saving files
const iOS = !!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform); const iOS = !!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform);
if (window.navigator.msSaveOrOpenBlob) { const elem = window.document.createElement('a');
window.navigator.msSaveBlob(blob, fileName); const objUrl = window.URL.createObjectURL(blob);
} else { if (iOS) {
const elem = window.document.createElement('a'); switch (type) {
const objUrl = window.URL.createObjectURL(blob); case 'json':
if (iOS) { elem.href = `data:attachment/file,${JSON.stringify(exportData)}`;
switch (type) { break;
case 'json': case 'csv':
elem.href = `data:attachment/file,${JSON.stringify(exportData)}`; elem.href = `data:attachment/file,${csvFile}`;
break; break;
case 'csv':
elem.href = `data:attachment/file,${csvFile}`;
break;
}
} else {
elem.href = objUrl;
} }
elem.download = fileName; } else {
document.body.appendChild(elem); elem.href = objUrl;
elem.click();
setTimeout(function() {
document.body.removeChild(elem);
window.URL.revokeObjectURL(objUrl);
}, 200);
} }
elem.download = fileName;
document.body.appendChild(elem);
elem.click();
setTimeout(function() {
document.body.removeChild(elem);
window.URL.revokeObjectURL(objUrl);
}, 200);
} }
async exportToFile() { async exportToFile() {

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { MultisigComponent } from './multisig.component'; import { MultisigComponent } from './multisig.component';
@ -6,7 +6,7 @@ describe('MultisigComponent', () => {
let component: MultisigComponent; let component: MultisigComponent;
let fixture: ComponentFixture<MultisigComponent>; let fixture: ComponentFixture<MultisigComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ MultisigComponent ] declarations: [ MultisigComponent ]
}) })

View file

@ -9,7 +9,7 @@ import { MusigService } from '../../services/musig.service';
@Component({ @Component({
selector: 'app-multisig', selector: 'app-multisig',
templateUrl: './multisig.component.html', templateUrl: './multisig.component.html',
styleUrls: ['./multisig.component.less'] styleUrls: ['./multisig.component.css']
}) })
export class MultisigComponent implements OnInit { export class MultisigComponent implements OnInit {
accountAdd = ''; accountAdd = '';

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { NotificationsComponent } from './notifications.component'; import { NotificationsComponent } from './notifications.component';
@ -6,7 +6,7 @@ describe('NotificationsComponent', () => {
let component: NotificationsComponent; let component: NotificationsComponent;
let fixture: ComponentFixture<NotificationsComponent>; let fixture: ComponentFixture<NotificationsComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ NotificationsComponent ] declarations: [ NotificationsComponent ]
}) })

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { QrGeneratorComponent } from './qr-generator.component'; import { QrGeneratorComponent } from './qr-generator.component';
@ -6,7 +6,7 @@ describe('QrGeneratorComponent', () => {
let component: QrGeneratorComponent; let component: QrGeneratorComponent;
let fixture: ComponentFixture<QrGeneratorComponent>; let fixture: ComponentFixture<QrGeneratorComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ QrGeneratorComponent ] declarations: [ QrGeneratorComponent ]
}) })

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { QrModalComponent } from './qr-modal.component'; import { QrModalComponent } from './qr-modal.component';
@ -6,7 +6,7 @@ describe('QrModalComponent', () => {
let component: QrModalComponent; let component: QrModalComponent;
let fixture: ComponentFixture<QrModalComponent>; let fixture: ComponentFixture<QrModalComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ QrModalComponent ] declarations: [ QrModalComponent ]
}) })

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { QrScanComponent } from './qr-scan.component'; import { QrScanComponent } from './qr-scan.component';
@ -6,7 +6,7 @@ describe('AddressBookComponent', () => {
let component: QrScanComponent; let component: QrScanComponent;
let fixture: ComponentFixture<QrScanComponent>; let fixture: ComponentFixture<QrScanComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ QrScanComponent ] declarations: [ QrScanComponent ]
}) })

View file

@ -1,3 +1,18 @@
.merchant-mode-text-full {
display: none;
}
.merchant-mode-text-short {
display: inline-block;
}
@media (min-width: 460px) {
.merchant-mode-text-full {
display: inline-block;
}
.merchant-mode-text-short {
display: none;
}
}
.label-block { .label-block {
margin-left: 10px; margin-left: 10px;
margin-bottom: 10px; margin-bottom: 10px;
@ -63,9 +78,6 @@
max-width: 280px; max-width: 280px;
margin: 25px auto 0 auto; margin: 25px auto 0 auto;
} }
.copy-address-button {
margin-top: 25px;
}
@media (max-width: 959px) { @media (max-width: 959px) {
.qr-code { .qr-code {
max-width: 250px; max-width: 250px;
@ -162,3 +174,116 @@
opacity: 1; opacity: 1;
} }
} }
.merchant-mode-overlay {
background-color: #FFF;
z-index: 1050; /* above notifications */
padding: 15px !important;
}
.merchant-mode-contents {
box-sizing: border-box;
height: 100%;
padding: 20px;
}
@media (max-width: 699px) {
.merchant-mode-contents {
padding: 10px;
}
}
.merchant-mode-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-left: 25px;
}
@media (max-width: 699px) {
.merchant-mode-header {
flex-direction: column;
padding-left: 0;
}
}
@media (min-width: 1200px) {
.merchant-mode-header {
position: fixed;
width: calc(100% - 86px);
}
}
.merchant-mode-exit .label {
font-size: 1.2em;
}
.merchant-mode-logo {
width: 200px;
height: 85px;
background: url('../../../assets/img/nault-logo.svg');
background-size: contain;
background-repeat: no-repeat;
flex-shrink: 0;
}
.merchant-mode-exit {
cursor: pointer;
padding: 6px 23px 8px 20px;
border: 2px solid transparent;
border-radius: 50px;
transition: border-color 100ms ease-in-out;
}
.merchant-mode-exit:hover {
border-color: #676686AA;
}
.merchant-centered-container {
padding-bottom: 170px;
max-width: 500px;
}
@media (min-width: 1200px) {
.merchant-centered-container {
padding-bottom: 0;
}
}
.merchant-mode-icon-qr-code {
width: 19px;
height: 19px;
margin-right: 10px;
background-color: currentcolor;
-webkit-mask-image: url('assets/img/qr-code.svg');
mask-image: url('assets/img/qr-code.svg');
}
.merchant-mode-qr-code {
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
width: 290px;
height: 290px;
border-radius: 20px;
border: 2px solid #19191B;
background-color: #FFF;
}
.merchant-mode-amount-integer,
.merchant-mode-amount-fractional,
.merchant-mode-currency-name {
font-family: 'Montserrat', Arial, Helvetica, sans-serif;
font-size: 34px;
}
.merchant-mode-amount-integer {
font-weight: 700;
}
.merchant-mode-amount-fractional {
font-weight: 500;
}
.merchant-mode-currency-name {
font-weight: 400;
}
.merchant-mode-currency-margin {
margin-left: 10px;
}

View file

@ -1,7 +1,24 @@
<div class="uk-animation-slide-left-small" uk-grid> <div class="uk-animation-slide-left-small" uk-grid>
<div class="uk-width-1-1"> <div class="uk-width-1-1">
<h2 class="uk-heading-divider">Receive Nano</h2> <ng-template #switchToMerchantModeButton>
<button
class="uk-width-1-1 uk-width-auto@s uk-button uk-button-primary uk-text-center nlt-icon-button nlt-button-green"
type="button"
(click)="merchantModeEnable()"
>
<span class="nlt-icon" uk-icon="icon: cart;"></span>
<span class="merchant-mode-text-full">Switch to Merchant Mode</span>
<span class="merchant-mode-text-short">Merchant Mode</span>
</button>
</ng-template>
<div class="uk-margin-bottom uk-flex uk-flex-between">
<h2 class="uk-flex-1 uk-heading-divider uk-margin-remove">Receive Nano</h2>
<div class="uk-flex-none uk-visible@s uk-flex uk-flex-top uk-margin-medium-left">
<ng-container *ngTemplateOutlet="switchToMerchantModeButton"></ng-container>
</div>
</div>
<div class="uk-card uk-card-default uk-margin"> <div class="uk-card uk-card-default uk-margin">
<div class="uk-card-body"> <div class="uk-card-body">
@ -53,14 +70,15 @@
<div style="padding-top: 100%"></div> <div style="padding-top: 100%"></div>
</div> </div>
</ng-template> </ng-template>
<div *ngIf="(pendingAccountModel !== '0')"> <div>
<div class="uk-flex uk-flex-center uk-flex-middle uk-text-center qr-address"> <div class="uk-flex uk-flex-center uk-flex-middle uk-text-center qr-address" *ngIf="(pendingAccountModel !== '0')">
<app-nano-account-id [accountID]="pendingAccountModel" middle="break" class="nano-address-monospace uk-width-auto" style="max-width: 90%;"></app-nano-account-id> <app-nano-account-id [accountID]="pendingAccountModel" middle="break" class="nano-address-monospace uk-width-auto" style="max-width: 90%;"></app-nano-account-id>
<a class="span-icon hide-on-small-viewports" ngxClipboard [cbContent]="pendingAccountModel" (cbOnSuccess)="copied()" uk-icon="icon: copy" title="Copy Account Address" uk-tooltip></a> <a class="span-icon hide-on-small-viewports" ngxClipboard [cbContent]="pendingAccountModel" (cbOnSuccess)="copied()" uk-icon="icon: copy" title="Copy Account Address" uk-tooltip></a>
</div> </div>
<div class="only-on-small-viewports uk-text-center"> <div class="uk-margin-medium-top only-on-small-viewports nlt-button-group uk-flex uk-flex-column uk-flex-middle">
<button <button
class="copy-address-button uk-width-1-1 uk-width-4-5@s uk-button uk-button-primary uk-text-center" *ngIf="(pendingAccountModel !== '0')"
class="uk-width-1-1 uk-width-4-5@s uk-button uk-button-primary uk-text-center nlt-icon-button"
[class.nlt-button-success]="recentlyCopiedAccountAddress" [class.nlt-button-success]="recentlyCopiedAccountAddress"
[class.uk-disabled]="recentlyCopiedAccountAddress" [class.uk-disabled]="recentlyCopiedAccountAddress"
type="button" type="button"
@ -68,8 +86,12 @@
[cbContent]="pendingAccountModel" [cbContent]="pendingAccountModel"
(cbOnSuccess)="copiedAccountAddress()" (cbOnSuccess)="copiedAccountAddress()"
> >
<span class="nlt-icon" uk-icon="icon: copy;"></span>
{{ recentlyCopiedAccountAddress ? 'Copied!' : 'Copy address' }} {{ recentlyCopiedAccountAddress ? 'Copied!' : 'Copy address' }}
</button> </button>
<div class="uk-hidden@s uk-width-1-1 uk-flex">
<ng-container *ngTemplateOutlet="switchToMerchantModeButton"></ng-container>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -281,3 +303,264 @@
</div> </div>
</div> </div>
<div class="merchant-mode-overlay" id="merchant-mode-modal" uk-modal>
<div class="merchant-mode-contents uk-flex uk-flex-column uk-flex-middle">
<div
class="uk-width-1-1 merchant-mode-header"
[class.uk-margin-medium-bottom]="inMerchantModeQR === false"
[class.uk-margin-bottom]="inMerchantModeQR === true"
>
<div class="merchant-mode-logo"></div>
<div
class="merchant-mode-exit uk-flex uk-flex-middle"
[class.uk-visible@s]="(inMerchantModeQR === true)"
(click)="inMerchantModeQR ? merchantModeHideQR() : merchantModeDisable()"
>
<span uk-icon="icon: close; ratio: 1.4;" class="uk-margin-small-right" style="margin-top: 2px;"></span>
<span class="label">{{ inMerchantModeQR ? 'Cancel Payment' : 'Exit Merchant Mode' }}</span>
</div>
</div>
<div class="merchant-centered-container uk-flex-1 uk-width-1-1 uk-flex uk-flex-column uk-flex-center uk-flex-middle uk-text-center">
<ng-container *ngIf="(inMerchantModePaymentComplete === false) && (inMerchantModeQR === false) && (pendingAccountModel === '0')">
<div class="uk-width-1-1 uk-card uk-card-default uk-margin-bottom">
<div class="uk-card-body">
<p class="uk-text-large">Select the <span class="uk-text-primary">destination account</span></p>
<select id="form-horizontal-select" class="uk-select" [(ngModel)]="pendingAccountModel" (change)="onSelectedAccountChange(pendingAccountModel)">
<option [value]="0"></option>
<option *ngFor="let account of accounts" [value]="account.id">{{account.addressBookName ? account.addressBookName + ' - ' : '#' + account.index + ' - ' }} {{ account.id | squeeze }}</option>
</select>
</div>
</div>
</ng-container>
<ng-container *ngIf="(inMerchantModePaymentComplete === false) && (inMerchantModeQR === false) && (pendingAccountModel !== '0')">
<div class="identicon-name-row uk-text-truncate">
<app-nano-identicon scale="6" [accountID]="pendingAccountModel" [settingIdenticonsStyle]="settings.settings.identiconsStyle" class="nano-identicon" *ngIf="(settings.settings.identiconsStyle !== 'none')"></app-nano-identicon>
<div class="account-label uk-text-truncate">{{ selectedAccountAddressBookName }}</div>
</div>
<app-nano-account-id [accountID]="pendingAccountModel" middle="off" class="nano-address-monospace uk-width-auto"></app-nano-account-id>
<button
class="uk-width-auto uk-button uk-button-secondary uk-text-center nlt-icon-button uk-margin-small-top"
type="button"
(click)="unsetSelectedAccount()"
>
<span class="nlt-icon" uk-icon="icon: pencil;"></span>
Change account
</button>
<div
class="uk-width-1-1 uk-card uk-card-default uk-margin-bottom"
style="margin-top: 60px;"
>
<div class="uk-card-body">
<p class="uk-text-large">Enter the <span class="uk-text-primary">requested amount</span></p>
<div class="form-amount">
<div class="uk-width-1-1 uk-inline">
<label class="uk-form-icon uk-link-reset uk-link-muted xno-symbol" for="form-horizontal-amount"></label>
<input [(ngModel)]="amountNano" [ngClass]="{ 'uk-form-danger': !validNano }" [attr.disabled]="pendingAccountModel == '0' || null" autocomplete="off" class="uk-input" id="form-horizontal-amount" (input)="nanoAmountChange()" style="padding-left: 52px !important;" type="number" step="any" placeholder="Amount of XNO" maxlength="40">
</div>
<div style="margin-top: 10px;" *ngIf="settings.settings.displayCurrency">
<p class="text-half-muted" style="margin: 0 0 14px 0;">or</p>
<div class="uk-width-1-1 uk-inline">
<a class="uk-form-icon uk-link-reset uk-link-muted fiat-currency-ticker" uk-tooltip title="Last Price: {{ price.price.lastPrice | fiat: settings.settings.displayCurrency }} / XNO">{{ settings.settings.displayCurrency | currencySymbol }}</a>
<input [(ngModel)]="amountFiat" [ngClass]="{ 'uk-form-danger': !validFiat }" [attr.disabled]="pendingAccountModel == '0' || null" autocomplete="off" (input)="fiatAmountChange()" style="padding-left: 52px !important;" class="uk-input" id="form-horizontal-text-fiat" type="number" step="any" placeholder="Amount of {{ settings.settings.displayCurrency }}">
</div>
</div>
</div>
<button
class="uk-width-1-1 uk-button uk-button-primary uk-text-center nlt-icon-button uk-margin-medium-top"
type="button"
(click)="merchantModeShowQR()"
>
<span class="merchant-mode-icon-qr-code"></span>
Create QR code
</button>
</div>
</div>
</ng-container>
<ng-container *ngIf="(inMerchantModeQR === true)">
<p class="uk-text-large uk-margin-remove-bottom">Send</p>
<p class="uk-text-large uk-text-primary uk-margin-remove-top" *ngIf="(amountNano === '')">
<span class="merchant-mode-currency-name">XNO</span>
</p>
<p class="uk-text-large uk-text-primary uk-margin-remove-top" *ngIf="(amountNano !== '')">
<span
class="merchant-mode-amount-integer"
>{{ merchantModeRawRequestedQR | rai: 'mnano,true' | amountsplit: 0 }}</span>
<span
class="merchant-mode-amount-fractional"
>{{ merchantModeRawRequestedQR | rai: 'mnano,true' | amountsplit: 1 }}</span>
<span class="merchant-mode-currency-name merchant-mode-currency-margin">XNO</span>
</p>
<p class="text-half-muted" style="margin: -16px 0 10px 0;">to</p>
<app-nano-account-id
[accountID]="pendingAccountModel" middle="break"
class="nano-address-monospace uk-width-auto"
style="display: inline-block; max-width: 325px;"
></app-nano-account-id>
<div
class="uk-width-1-1 uk-flex uk-flex-center uk-margin-top"
style="margin-bottom: 40px;"
>
<img class="merchant-mode-qr-code" [src]="qrCodeImage" alt="QR code" *ngIf="qrCodeImage">
<div class="merchant-mode-qr-code" *ngIf="!qrCodeImage"><div uk-spinner="ratio: 2;"></div></div>
</div>
<div
class="uk-width-1-1 uk-card uk-card-default uk-margin-bottom"
*ngFor="let prompt of merchantModePrompts; let promptIdx = index"
>
<div class="uk-card-body">
<p
*ngIf="(amountNano === '')"
class="uk-text-large text-half-muted uk-margin-remove-bottom"
>
Received
</p>
<p
*ngIf="(amountNano !== '') && prompt.moreThanRequested"
class="uk-text-large text-half-muted uk-margin-remove-bottom"
>
Received <span class="uk-text-success">more</span> than requested
</p>
<p
*ngIf="(amountNano !== '') && prompt.lessThanRequested"
class="uk-text-large text-half-muted uk-margin-remove-bottom"
>
Received <span class="uk-text-warning">less</span> than requested
</p>
<p
class="uk-text-large uk-margin-remove-top"
[class.uk-text-success]="prompt.moreThanRequested"
[class.uk-text-warning]="prompt.lessThanRequested"
>
<span
class="merchant-mode-amount-integer"
>{{ prompt.amountRaw | rai: 'mnano,true' | amountsplit: 0 }}</span>
<span
class="merchant-mode-amount-fractional"
>{{ prompt.amountRaw | rai: 'mnano,true' | amountsplit: 1 }}</span>
<span class="merchant-mode-currency-name merchant-mode-currency-margin">XNO</span>
</p>
<div
*ngIf="prompt.amountHiddenRaw.gt(0)"
class="uk-text-small text-half-muted block-hash-monospace"
style="margin: -22px 0 28px 0;"
>
+{{ prompt.amountHiddenRaw.toString(10) }} raw
</div>
<button
*ngIf="prompt.moreThanRequested"
class="uk-width-1-1 uk-button uk-button-primary uk-text-center nlt-icon-button uk-margin-bottom nlt-button-green"
type="button"
(click)="merchantModeMarkCompleteFromPrompt(prompt)"
>
<span class="nlt-icon" uk-icon="icon: check;" style="margin-top: -2px;"></span>
Mark Payment Complete
</button>
<button
*ngIf="prompt.lessThanRequested"
class="uk-width-1-1 uk-button uk-button-primary uk-text-center nlt-icon-button uk-margin-bottom"
type="button"
(click)="merchantModeSubtractAmountFromPrompt(prompt, promptIdx)"
>
<span class="nlt-icon" uk-icon="icon: pencil;" style="margin-top: -2px;"></span>
Subtract From Amount
</button>
<button
class="uk-width-1-1 uk-button uk-button-secondary uk-text-danger uk-text-center nlt-icon-button"
type="button"
(click)="merchantModeDiscardPrompt(promptIdx)"
>
<span class="nlt-icon" uk-icon="icon: close;" style="margin-top: -2px;"></span>
Discard As Unrelated
</button>
</div>
</div>
<ng-container *ngIf="merchantModePrompts.length === 0">
<p class="uk-text-large uk-margin-top text-half-muted">Awaiting payment...</p>
<button
class="uk-width-auto uk-button uk-text-center nlt-icon-button"
[class.uk-button-primary]="!loadingIncomingTxList"
[class.uk-button-secondary]="loadingIncomingTxList"
[class.uk-disabled]="loadingIncomingTxList"
type="button"
(click)="!loadingIncomingTxList && getPending()"
>
<span class="nlt-icon" uk-icon="icon: refresh;" style="margin-top: -2px;" *ngIf="!loadingIncomingTxList"></span>
<span class="spinner" uk-spinner="ratio: 0.5;" *ngIf="loadingIncomingTxList"></span>
{{ loadingIncomingTxList ? 'Checking Payment...' : 'Check Payment' }}
</button>
</ng-container>
<div
class="merchant-mode-exit uk-flex uk-flex-middle uk-hidden@s"
style="margin-top: 70px;"
(click)="merchantModeHideQR()"
>
<span uk-icon="icon: close; ratio: 1.4;" class="uk-margin-small-right" style="margin-top: 2px;"></span>
<span class="label">Cancel Payment</span>
</div>
</ng-container>
<ng-container *ngIf="(inMerchantModePaymentComplete === true)">
<p class="uk-text-large uk-margin-remove-bottom uk-text-success">Received</p>
<p class="uk-text-large uk-text-success uk-margin-remove-top">
<span
class="merchant-mode-amount-integer"
>{{ merchantModeRawReceivedTotal | rai: 'mnano,true' | amountsplit: 0 }}</span>
<span
class="merchant-mode-amount-fractional"
>{{ merchantModeRawReceivedTotal | rai: 'mnano,true' | amountsplit: 1 }}</span>
<span class="merchant-mode-currency-name merchant-mode-currency-margin">XNO</span>
</p>
<div
*ngIf="merchantModeRawReceivedTotalHiddenRaw.gt(0)"
class="uk-text-small text-half-muted block-hash-monospace"
style="margin: -22px 0 28px 0;"
>
+{{ merchantModeRawReceivedTotalHiddenRaw.toString(10) }} raw
</div>
<img style="width: 50%; margin-top: -40px;" src="data:image/svg+xml,%3Csvg width='200mm' height='200mm' viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='m157.05 40.584c-2.5562-2e-6 -5.1127 0.97964-7.0714 2.9383l-65.687 65.687-34.266-34.266c-3.9174-3.9174-10.225-3.9174-14.142 1e-6l-12.915 12.915c-3.9174 3.9174-3.9174 10.225-1e-6 14.142l39.526 39.526c0.4262 0.72955 0.95143 1.4181 1.5782 2.0448l12.915 12.915c3.9174 3.9174 10.225 3.9174 14.142 0l85.906-85.907c3.9174-3.9174 3.9174-10.224 0-14.142l-12.915-12.915c-1.9587-1.9587-4.5147-2.9383-7.0709-2.9383z' fill='none' stop-color='%23000000' stroke='%2332d296' stroke-linejoin='round' stroke-width='2' style='paint-order:stroke fill markers'/%3E%3C/svg%3E" />
<p class="uk-flex uk-flex-center uk-flex-middle text-half-muted uk-margin-remove-bottom">
<button
class="uk-button uk-button-secondary uk-text-center nlt-icon-button"
type="button"
ngxClipboard
[cbContent]="(
'Amount Requested: '
+ ( merchantModeRawRequestedTotal | rai: 'mnano,true' | amountsplit: 0 )
+ ( merchantModeRawRequestedTotal | rai: 'mnano,true' | amountsplit: 1 )
+ ' XNO'
+ '\n\n'
+ 'Amount Paid: '
+ ( merchantModeRawReceivedTotal | rai: 'mnano,true' | amountsplit: 0 )
+ ( merchantModeRawReceivedTotal | rai: 'mnano,true' | amountsplit: 1 )
+ ' XNO'
+ '\n\n'
+ 'Transaction ID\'s:'
+ '\n- '
+ merchantModeTransactionHashes.join('\n- ')
)"
>
<span class="nlt-icon" uk-icon="icon: copy;"></span>
Copy Payment Information
</button>
</p>
<ul class="uk-width-1-1">
<li
*ngFor="let hash of merchantModeTransactionHashes"
class="uk-text-left text-half-muted block-hash-monospace"
style="word-wrap: anywhere;"
>
{{ hash }}
</li>
</ul>
<div
class="merchant-mode-exit uk-flex uk-flex-middle"
style="margin-top: 70px;"
(click)="merchantModeResetState()"
>
<span uk-icon="icon: plus-circle; ratio: 1.4;" class="uk-margin-small-right" style="margin-top: 2px;"></span>
<span class="label">New Payment</span>
</div>
</ng-container>
</div>
</div>
</div>

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ReceiveComponent } from './receive.component'; import { ReceiveComponent } from './receive.component';
@ -6,7 +6,7 @@ describe('ReceiveComponent', () => {
let component: ReceiveComponent; let component: ReceiveComponent;
let fixture: ComponentFixture<ReceiveComponent>; let fixture: ComponentFixture<ReceiveComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ReceiveComponent ] declarations: [ ReceiveComponent ]
}) })

View file

@ -29,6 +29,7 @@ export class ReceiveComponent implements OnInit, OnDestroy {
timeoutIdClearingRecentlyCopiedState: any = null; timeoutIdClearingRecentlyCopiedState: any = null;
mobileTransactionMenuModal: any = null; mobileTransactionMenuModal: any = null;
merchantModeModal: any = null;
mobileTransactionData: any = null; mobileTransactionData: any = null;
selectedAccountAddressBookName = ''; selectedAccountAddressBookName = '';
@ -48,6 +49,17 @@ export class ReceiveComponent implements OnInit, OnDestroy {
validFiat = true; validFiat = true;
qrSuccessClass = ''; qrSuccessClass = '';
inMerchantMode = false;
inMerchantModeQR = false;
inMerchantModePaymentComplete = false;
merchantModeRawRequestedQR: BigNumber = null;
merchantModeRawRequestedTotal: BigNumber = null;
merchantModeRawReceivedTotal: BigNumber = null;
merchantModeRawReceivedTotalHiddenRaw: BigNumber = null;
merchantModeSeenBlockHashes = {};
merchantModePrompts = [];
merchantModeTransactionHashes = [];
routerSub = null; routerSub = null;
constructor( constructor(
@ -67,12 +79,17 @@ export class ReceiveComponent implements OnInit, OnDestroy {
async ngOnInit() { async ngOnInit() {
const UIkit = window['UIkit']; const UIkit = window['UIkit'];
const mobileTransactionMenuModal = UIkit.modal('#mobile-transaction-menu-modal'); const mobileTransactionMenuModal = UIkit.modal('#mobile-transaction-menu-modal');
this.mobileTransactionMenuModal = mobileTransactionMenuModal; this.mobileTransactionMenuModal = mobileTransactionMenuModal;
const merchantModeModal = UIkit.modal('#merchant-mode-modal');
this.merchantModeModal = merchantModeModal;
this.routerSub = this.route.events.subscribe(event => { this.routerSub = this.route.events.subscribe(event => {
if (event instanceof ChildActivationEnd) { if (event instanceof ChildActivationEnd) {
this.mobileTransactionMenuModal.hide(); this.mobileTransactionMenuModal.hide();
this.merchantModeModal.hide();
} }
}); });
@ -110,12 +127,16 @@ export class ReceiveComponent implements OnInit, OnDestroy {
this.showQrConfirmation(); this.showQrConfirmation();
setTimeout(() => this.resetAmount(), 500); setTimeout(() => this.resetAmount(), 500);
} }
if ( (this.inMerchantModeQR === true) && (transaction.block.link_as_account === this.qrAccount) ) {
this.onMerchantModeReceiveTransaction(transaction);
}
} }
}); });
} }
ngOnDestroy() { ngOnDestroy() {
this.mobileTransactionMenuModal.hide(); this.mobileTransactionMenuModal.hide();
this.merchantModeModal.hide();
if (this.routerSub) { if (this.routerSub) {
this.routerSub.unsubscribe(); this.routerSub.unsubscribe();
} }
@ -164,6 +185,14 @@ export class ReceiveComponent implements OnInit, OnDestroy {
// Blocks for selected account // Blocks for selected account
this.pendingBlocksForSelectedAccount = this.pendingBlocksForSelectedAccount =
this.pendingBlocks.filter(block => (block.destination === selectedAccountID)); this.pendingBlocks.filter(block => (block.destination === selectedAccountID));
if (this.inMerchantModeQR === true) {
this.pendingBlocksForSelectedAccount.forEach(
(pendingBlock) => {
this.onMerchantModeReceiveTransaction(pendingBlock);
}
)
}
} }
showMobileMenuForTransaction(transaction) { showMobileMenuForTransaction(transaction) {
@ -364,4 +393,140 @@ export class ReceiveComponent implements OnInit, OnDestroy {
return new BigNumber(value); return new BigNumber(value);
} }
unsetSelectedAccount() {
this.pendingAccountModel = '0';
this.onSelectedAccountChange(this.pendingAccountModel);
}
getRawAmountWithoutTinyRaws(rawAmountWithTinyRaws) {
const tinyRaws =
rawAmountWithTinyRaws.mod(this.nano);
return rawAmountWithTinyRaws.minus(tinyRaws);
}
merchantModeResetState() {
this.unsetSelectedAccount();
this.resetAmount();
this.inMerchantModeQR = false;
this.inMerchantModePaymentComplete = false;
}
merchantModeEnable() {
this.merchantModeResetState();
this.inMerchantMode = true;
this.merchantModeModal.show();
}
merchantModeDisable() {
this.inMerchantMode = false;
this.inMerchantModeQR = false;
this.inMerchantModePaymentComplete = false;
this.merchantModeModal.hide();
}
merchantModeShowQR() {
const isRequestingAnyAmount = (this.validNano === false || Number(this.amountNano) === 0);
if(isRequestingAnyAmount === true) {
this.resetAmount();
}
this.merchantModeRawRequestedTotal =
(isRequestingAnyAmount === true)
? new BigNumber(0)
: this.util.nano.mnanoToRaw(this.amountNano);
this.merchantModeRawRequestedQR =
(isRequestingAnyAmount === true)
? new BigNumber(0)
: this.util.nano.mnanoToRaw(this.amountNano);
this.merchantModeSeenBlockHashes =
this.pendingBlocksForSelectedAccount.reduce(
(seenHashes, receivableBlock) => {
seenHashes[receivableBlock.hash] = true
return seenHashes
},
{}
);
this.merchantModeTransactionHashes = [];
this.inMerchantModeQR = true;
}
merchantModeHideQR() {
this.inMerchantModeQR = false;
}
onMerchantModeReceiveTransaction(transaction) {
if( this.merchantModeSeenBlockHashes[transaction.hash] != null ) {
return;
}
this.merchantModeSeenBlockHashes[transaction.hash] = true;
const receivedAmountWithTinyRaws = new BigNumber(transaction.amount);
const receivedAmount =
this.getRawAmountWithoutTinyRaws(receivedAmountWithTinyRaws);
const requestedAmount =
this.getRawAmountWithoutTinyRaws(this.merchantModeRawRequestedQR);
if( receivedAmount.eq(requestedAmount) ) {
this.merchantModeTransactionHashes.push(transaction.hash);
this.merchantModeMarkCompleteWithAmount(this.merchantModeRawRequestedTotal);
} else {
const transactionPrompt = {
moreThanRequested: receivedAmount.gt(requestedAmount),
lessThanRequested: receivedAmount.lt(requestedAmount),
amountRaw: receivedAmountWithTinyRaws,
amountHiddenRaw: receivedAmountWithTinyRaws.mod(this.nano),
transactionHash: transaction.hash,
}
this.merchantModePrompts.push(transactionPrompt);
}
}
merchantModeSubtractAmountFromPrompt(prompt, promptIdx) {
const subtractedRawWithTinyRaws = prompt.amountRaw;
const subtractedRaw =
this.getRawAmountWithoutTinyRaws(subtractedRawWithTinyRaws);
const newAmountRaw =
this.merchantModeRawRequestedQR.minus(subtractedRaw);
this.merchantModeRawRequestedQR = newAmountRaw;
this.changeQRAmount(newAmountRaw.toFixed());
this.merchantModeTransactionHashes.push(prompt.transactionHash);
this.merchantModePrompts.splice(promptIdx, 1);
}
merchantModeMarkCompleteFromPrompt(prompt) {
this.merchantModeTransactionHashes.push(prompt.transactionHash);
this.merchantModeMarkCompleteWithAmount(prompt.amountRaw);
}
merchantModeDiscardPrompt(promptIdx) {
this.merchantModePrompts.splice(promptIdx, 1);
}
merchantModeMarkCompleteWithAmount(amountRaw) {
this.merchantModeRawReceivedTotal = amountRaw;
this.merchantModeRawReceivedTotalHiddenRaw = amountRaw.mod(this.nano);
this.inMerchantModePaymentComplete = true;
this.inMerchantModeQR = false;
}
} }

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { RemoteSigningComponent } from './remote-signing.component'; import { RemoteSigningComponent } from './remote-signing.component';
@ -6,7 +6,7 @@ describe('RemoteSigningComponent', () => {
let component: RemoteSigningComponent; let component: RemoteSigningComponent;
let fixture: ComponentFixture<RemoteSigningComponent>; let fixture: ComponentFixture<RemoteSigningComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ RemoteSigningComponent ] declarations: [ RemoteSigningComponent ]
}) })

View file

@ -248,7 +248,7 @@
</div> </div>
</div> </div>
<div class="uk-card-footer"> <div class="uk-card-footer">
<button class="uk-button uk-button-primary uk-width-1-1" type="button" (click)="changeRepresentatives()" *ngIf="!changingRepresentatives">Update Representatives</button> <button class="uk-button uk-button-primary uk-width-1-1@s uk-width-auto@m uk-float-right" type="button" (click)="changeRepresentatives()" *ngIf="!changingRepresentatives">Update Representatives</button>
<button class="uk-button uk-button-secondary uk-width-1-1 uk-disabled nlt-icon-button" type="button" *ngIf="changingRepresentatives"><span class="spinner" uk-spinner="ratio: 0.5;"></span> Updating Representatives</button> <button class="uk-button uk-button-secondary uk-width-1-1 uk-disabled nlt-icon-button" type="button" *ngIf="changingRepresentatives"><span class="spinner" uk-spinner="ratio: 0.5;"></span> Updating Representatives</button>
</div> </div>
</div> </div>

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { RepresentativesComponent } from './representatives.component'; import { RepresentativesComponent } from './representatives.component';
@ -6,7 +6,7 @@ describe('RepresentativesComponent', () => {
let component: RepresentativesComponent; let component: RepresentativesComponent;
let fixture: ComponentFixture<RepresentativesComponent>; let fixture: ComponentFixture<RepresentativesComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ RepresentativesComponent ] declarations: [ RepresentativesComponent ]
}) })

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { SendComponent } from './send.component'; import { SendComponent } from './send.component';
@ -6,7 +6,7 @@ describe('SendComponent', () => {
let component: SendComponent; let component: SendComponent;
let fixture: ComponentFixture<SendComponent>; let fixture: ComponentFixture<SendComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ SendComponent ] declarations: [ SendComponent ]
}) })

View file

@ -334,15 +334,13 @@
<a *ngIf="processedHash" [routerLink]="'/account/' + signatureAccount" [queryParams]="{ sign: 1 }" class="uk-button uk-button-primary uk-width-auto" title="Account detail view" uk-tooltip>Account Detail View</a> <a *ngIf="processedHash" [routerLink]="'/account/' + signatureAccount" [queryParams]="{ sign: 1 }" class="uk-button uk-button-primary uk-width-auto" title="Account detail view" uk-tooltip>Account Detail View</a>
</div> </div>
<div *ngIf="!processedHash" uk-grid> <div *ngIf="!processedHash">
<div class="uk-width-1-2@s"> <div class="nlt-button-group uk-width-1-1 uk-text-right">
<a class="uk-button uk-button-danger uk-width-1-1" (click)="cancel()">Cancel</a> <button class="uk-button uk-button-danger uk-width-1-1@s uk-width-auto@m" (click)="cancel()">Cancel</button>
</div> <button *ngIf="!confirmingTransaction && shouldSign && signTypeSelected !== signTypes[3]" class="uk-button uk-button-primary uk-width-1-1@s uk-width-auto@m" (click)="confirmTransaction()">Confirm & Sign</button>
<div class="uk-width-1-2@s"> <button *ngIf="!confirmingTransaction && shouldSign && signTypeSelected === signTypes[3]" class="uk-button uk-button-primary uk-width-1-1@s uk-width-auto@m" (click)="startMultisig()" [disabled]="!this.validPrivkey || !this.validParticipants || finalSignature || (this.activeStep > 1 && !this.isInputAddDisabled)">{{this.activeStep !== 4 ? (this.activeStep === 1 ? 'Start Multi-signing' : 'Step '+ (this.activeStep - 1) + '/3 | Next') : 'Step '+ (this.activeStep - 1) + '/3 | Final Step'}}</button>
<button *ngIf="!confirmingTransaction && shouldSign && signTypeSelected !== signTypes[3]" class="uk-button uk-button-primary uk-width-1-1" (click)="confirmTransaction()">Confirm & Sign</button>
<button *ngIf="!confirmingTransaction && shouldSign && signTypeSelected === signTypes[3]" class="uk-button uk-button-primary uk-width-1-1" (click)="startMultisig()" [disabled]="!this.validPrivkey || !this.validParticipants || finalSignature || (this.activeStep > 1 && !this.isInputAddDisabled)">{{this.activeStep !== 4 ? (this.activeStep === 1 ? 'Start Multi-signing' : 'Step '+ (this.activeStep - 1) + '/3 | Next') : 'Step '+ (this.activeStep - 1) + '/3 | Final Step'}}</button>
<button *ngIf="confirmingTransaction && shouldSign" class="uk-button uk-button-primary uk-disabled uk-width-1-1"><span class="uk-margin-right" uk-spinner></span> Loading</button> <button *ngIf="confirmingTransaction && shouldSign" class="uk-button uk-button-primary uk-disabled uk-width-1-1"><span class="uk-margin-right" uk-spinner></span> Loading</button>
<button *ngIf="!confirmingTransaction && !shouldSign" class="uk-button uk-button-primary uk-width-1-1" (click)="confirmBlock()">Confirm & Process</button> <button *ngIf="!confirmingTransaction && !shouldSign" class="uk-button uk-button-primary uk-width-1-1@s uk-width-auto@m" (click)="confirmBlock()">Confirm & Process</button>
<button *ngIf="confirmingTransaction && !shouldSign" class="uk-button uk-button-primary uk-disabled uk-width-1-1"><span class="uk-margin-right" uk-spinner></span> Loading</button> <button *ngIf="confirmingTransaction && !shouldSign" class="uk-button uk-button-primary uk-disabled uk-width-1-1"><span class="uk-margin-right" uk-spinner></span> Loading</button>
</div> </div>
</div> </div>
@ -362,7 +360,7 @@
</div> </div>
<!-- Modal for result QR --> <!-- Modal for result QR -->
<div id="signed-modal" uk-modal> <div class="modal-position-bottom" id="signed-modal" uk-modal>
<div class="uk-modal-dialog uk-modal-body modal-qr"> <div class="uk-modal-dialog uk-modal-body modal-qr">
<button class="uk-modal-close-default" type="button" uk-close></button> <button class="uk-modal-close-default" type="button" uk-close></button>
<div class="uk-modal-header"> <div class="uk-modal-header">
@ -390,7 +388,7 @@
</div> </div>
<!-- Modal for output data QR --> <!-- Modal for output data QR -->
<div id="qr-code-modal" uk-modal> <div class="modal-position-bottom" id="qr-code-modal" uk-modal>
<div class="uk-modal-dialog uk-margin-auto-vertical"> <div class="uk-modal-dialog uk-margin-auto-vertical">
<button class="uk-modal-close-default" type="button" uk-close></button> <button class="uk-modal-close-default" type="button" uk-close></button>
<div class="uk-modal-body"> <div class="uk-modal-body">

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { SignComponent } from './sign.component'; import { SignComponent } from './sign.component';
@ -6,7 +6,7 @@ describe('SignComponent', () => {
let component: SignComponent; let component: SignComponent;
let fixture: ComponentFixture<SignComponent>; let fixture: ComponentFixture<SignComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ SignComponent ] declarations: [ SignComponent ]
}) })

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { SweeperComponent } from './sweeper.component'; import { SweeperComponent } from './sweeper.component';
@ -6,7 +6,7 @@ describe('SweeperComponent', () => {
let component: SweeperComponent; let component: SweeperComponent;
let fixture: ComponentFixture<SweeperComponent>; let fixture: ComponentFixture<SweeperComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ SweeperComponent ] declarations: [ SweeperComponent ]
}) })

View file

@ -191,6 +191,29 @@
</div> </div>
</div> </div>
</div> </div>
<div class="uk-margin" *ngIf="successorHash">
<label class="uk-form-label">Successor:</label>
<div class="uk-form-controls uk-text-truncate">
<div uk-grid class="uk-flex-nowrap uk-text-truncate">
<a
class="uk-width-auto uk-text-truncate block-hash-monospace block-hash-clickable"
[routerLink]="'/transaction/' + successorHash"
style="max-width: calc(100% - 35px);"
title="View Block Details"
uk-tooltip
>{{ successorHash }}</a>
<div class="uk-width-auto block-hash-actions">
<ul class="uk-iconnav">
<li><a ngxClipboard [cbContent]="successorHash" (cbOnSuccess)="copied()" uk-icon="icon: copy" title="Copy Successor Block Hash" uk-tooltip></a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="uk-margin" *ngIf="blockHeight != -1">
<label class="uk-form-label">Height:</label>
<div class="uk-form-controls uk-text-truncate">{{ blockHeight | number:'':'en-US' }}</div>
</div>
<div class="uk-margin" *ngIf="(transaction?.contents?.link || transaction?.contents?.source) && (blockType == 'open' || blockType == 'receive')"> <div class="uk-margin" *ngIf="(transaction?.contents?.link || transaction?.contents?.source) && (blockType == 'open' || blockType == 'receive')">
<label class="uk-form-label">Link (Source):</label> <label class="uk-form-label">Link (Source):</label>
<div class="uk-form-controls uk-text-truncate"> <div class="uk-form-controls uk-text-truncate">
@ -220,10 +243,6 @@
</a> </a>
</div> </div>
</div> </div>
<div class="uk-margin" *ngIf="blockHeight != -1">
<label class="uk-form-label">Height:</label>
<div class="uk-form-controls uk-text-truncate">{{ blockHeight | number:'':'en-US' }}</div>
</div>
<div class="uk-margin" *ngIf="transaction?.contents?.work"> <div class="uk-margin" *ngIf="transaction?.contents?.work">
<label class="uk-form-label">Work:</label> <label class="uk-form-label">Work:</label>
<div class="uk-form-controls uk-text-truncate"> <div class="uk-form-controls uk-text-truncate">

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { TransactionDetailsComponent } from './transaction-details.component'; import { TransactionDetailsComponent } from './transaction-details.component';
@ -6,7 +6,7 @@ describe('TransactionDetailsComponent', () => {
let component: TransactionDetailsComponent; let component: TransactionDetailsComponent;
let fixture: ComponentFixture<TransactionDetailsComponent>; let fixture: ComponentFixture<TransactionDetailsComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ TransactionDetailsComponent ] declarations: [ TransactionDetailsComponent ]
}) })

View file

@ -34,6 +34,7 @@ export class TransactionDetailsComponent implements OnInit {
showBlockData = false; showBlockData = false;
amountRaw = new BigNumber(0); amountRaw = new BigNumber(0);
successorHash = '';
constructor( constructor(
private walletService: WalletService, private walletService: WalletService,
@ -69,6 +70,7 @@ export class TransactionDetailsComponent implements OnInit {
let legacyFromAccount = ''; let legacyFromAccount = '';
this.blockType = ''; this.blockType = '';
this.amountRaw = new BigNumber(0); this.amountRaw = new BigNumber(0);
this.successorHash = '';
const hash = this.route.snapshot.params.transaction; const hash = this.route.snapshot.params.transaction;
this.hashID = hash; this.hashID = hash;
@ -90,9 +92,11 @@ export class TransactionDetailsComponent implements OnInit {
this.isUnconfirmedBlock = (hashData.confirmed === 'false') ? true : false; this.isUnconfirmedBlock = (hashData.confirmed === 'false') ? true : false;
this.blockHeight = hashData.height; this.blockHeight = hashData.height;
const HASH_ONLY_ZEROES = '0000000000000000000000000000000000000000000000000000000000000000';
const blockType = hashData.contents.type; const blockType = hashData.contents.type;
if (blockType === 'state') { if (blockType === 'state') {
const isOpen = hashData.contents.previous === '0000000000000000000000000000000000000000000000000000000000000000'; const isOpen = (hashData.contents.previous === HASH_ONLY_ZEROES);
if (isOpen) { if (isOpen) {
this.blockType = 'open'; this.blockType = 'open';
@ -126,6 +130,13 @@ export class TransactionDetailsComponent implements OnInit {
this.amountRaw = new BigNumber(hashData.amount).mod(this.nano); this.amountRaw = new BigNumber(hashData.amount).mod(this.nano);
} }
if (
(hashData.successor != null)
&& (hashData.successor !== HASH_ONLY_ZEROES)
) {
this.successorHash = hashData.successor;
}
this.transaction = hashData; this.transaction = hashData;
let fromAccount = ''; let fromAccount = '';

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { WalletWidgetComponent } from './wallet-widget.component'; import { WalletWidgetComponent } from './wallet-widget.component';
@ -6,7 +6,7 @@ describe('WalletWidgetComponent', () => {
let component: WalletWidgetComponent; let component: WalletWidgetComponent;
let fixture: ComponentFixture<WalletWidgetComponent>; let fixture: ComponentFixture<WalletWidgetComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ WalletWidgetComponent ] declarations: [ WalletWidgetComponent ]
}) })

View file

@ -136,7 +136,7 @@ export class WalletWidgetComponent implements OnInit {
this.notificationService.sendSuccess(`Wallet unlocked`); this.notificationService.sendSuccess(`Wallet unlocked`);
this.modal.hide(); this.modal.hide();
if (this.unlockPassword.length < 6) { if (this.unlockPassword.length < 6) {
// tslint:disable-next-line: max-line-length // eslint-disable-next-line max-len
this.notificationService.sendWarning(`You are using an insecure password and encouraged to change it from settings > manage wallet`); this.notificationService.sendWarning(`You are using an insecure password and encouraged to change it from settings > manage wallet`);
} }

View file

@ -0,0 +1,19 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'noPaddingZeros'
})
export class NoPaddingZerosPipe implements PipeTransform {
transform(input: string): string {
const sig = input.split('.')[0];
const frac = input.split('.')[1].replace(/0+$/g, '');
// 1.000000 XNO >> 1 XNO
if (!frac) {
return sig;
}
// 0.002200 >> 0.0022 XNO
return `${sig}.${frac}`;
}
}

View file

@ -22,14 +22,21 @@ export class ApiService {
this.node.setLoading(); this.node.setLoading();
} }
} }
let header; let options: any = {
responseType: 'json',
};
if (this.appSettings.settings.serverAuth != null && this.appSettings.settings.serverAuth !== '') { if (this.appSettings.settings.serverAuth != null && this.appSettings.settings.serverAuth !== '') {
header = { options =
headers: new HttpHeaders() Object.assign(
.set('Authorization', this.appSettings.settings.serverAuth) {},
}; options,
{
headers: new HttpHeaders()
.set('Authorization', this.appSettings.settings.serverAuth)
}
);
} }
return await this.http.post(apiUrl, data, header).toPromise() return await this.http.post(apiUrl, data, options).toPromise()
.then(res => { .then(res => {
this.node.setOnline(); this.node.setOnline();
return res; return res;

View file

@ -64,17 +64,35 @@ export class NinjaService {
// false - does not exist, null - any other error // false - does not exist, null - any other error
async getAccount(account: string): Promise<any> { async getAccount(account: string): Promise<any> {
return await this.http.get(this.ninjaUrl + 'accounts/' + account).toPromise() const REQUEST_TIMEOUT_MS = 10000;
.then(res => {
return res;
})
.catch(err => {
if (err.status === 404) {
return false;
}
return null; const successPromise =
this.http.get(this.ninjaUrl + 'accounts/' + account).toPromise()
.then(res => {
return res;
})
.catch(err => {
if (err.status === 404) {
return false;
}
return null;
});
const timeoutPromise =
new Promise(resolve => {
setTimeout(
() => {
resolve(null);
},
REQUEST_TIMEOUT_MS
);
}); });
return await Promise.race([
successPromise,
timeoutPromise
]);
} }
} }

View file

@ -453,11 +453,11 @@ export class RepresentativeService {
} }
// Default representatives list // Default representatives list
// tslint:disable-next-line:member-ordering // eslint-disable-next-line @typescript-eslint/member-ordering
defaultRepresentatives = []; defaultRepresentatives = [];
// Bad representatives hardcoded to be avoided. Not visible in the user rep list // Bad representatives hardcoded to be avoided. Not visible in the user rep list
// tslint:disable-next-line:member-ordering // eslint-disable-next-line @typescript-eslint/member-ordering
nfReps = [ nfReps = [
{ {
id: 'nano_3arg3asgtigae3xckabaaewkx3bzsh7nwz7jkmjos79ihyaxwphhm6qgjps4', id: 'nano_3arg3asgtigae3xckabaaewkx3bzsh7nwz7jkmjos79ihyaxwphhm6qgjps4',

View file

@ -100,7 +100,7 @@ function hexToUint4(hexValue) {
return uint4; return uint4;
} }
function hexToUint8(hexValue) { function hexToUint8(hexValue) {
// tslint:disable-next-line:no-bitwise // eslint-disable-next-line no-bitwise
const length = (hexValue.length / 2) | 0; const length = (hexValue.length / 2) | 0;
const uint8 = new Uint8Array(length); const uint8 = new Uint8Array(length);
for (let i = 0; i < length; i++) uint8[i] = parseInt(hexValue.substr(i * 2, 2), 16); for (let i = 0; i < length; i++) uint8[i] = parseInt(hexValue.substr(i * 2, 2), 16);
@ -124,7 +124,7 @@ function uint4ToUint8(uintValue) {
return uint8; return uint8;
} }
// tslint:disable:no-bitwise /* eslint-disable no-bitwise */
function uint4ToUint5(uintValue) { function uint4ToUint5(uintValue) {
const length = uintValue.length / 5 * 4; const length = uintValue.length / 5 * 4;
const uint5 = new Uint8Array(length); const uint5 = new Uint8Array(length);
@ -140,7 +140,7 @@ function uint4ToUint5(uintValue) {
} }
return uint5; return uint5;
} }
// tslint:enable:no-bitwise /* eslint-enable no-bitwise */
function uint4ToHex(uint4) { function uint4ToHex(uint4) {
let hex = ''; let hex = '';
@ -158,7 +158,7 @@ function uint5ToString(uint5) {
return string; return string;
} }
// tslint:disable:no-bitwise /* eslint-disable no-bitwise */
function uint5ToUint4(uint5) { function uint5ToUint4(uint5) {
const length = uint5.length / 4 * 5; const length = uint5.length / 4 * 5;
const uint4 = new Uint8Array(length); const uint4 = new Uint8Array(length);
@ -172,7 +172,7 @@ function uint5ToUint4(uint5) {
} }
return uint4; return uint4;
} }
// tslint:enable:no-bitwise /* eslint-enable no-bitwise */
/** Uint8 Functions **/ /** Uint8 Functions **/
@ -191,7 +191,7 @@ function uint8ToHex(uintValue) {
return(hex); return(hex);
} }
// tslint:disable:no-bitwise /* eslint-disable no-bitwise */
function uint8ToUint4(uintValue) { function uint8ToUint4(uintValue) {
const uint4 = new Uint8Array(uintValue.length * 2); const uint4 = new Uint8Array(uintValue.length * 2);
for (let i = 0; i < uintValue.length; i++) { for (let i = 0; i < uintValue.length; i++) {
@ -201,12 +201,12 @@ function uint8ToUint4(uintValue) {
return uint4; return uint4;
} }
// tslint:enable:no-bitwise /* eslint-enable no-bitwise */
/** Dec Functions **/ /** Dec Functions **/
function decToHex(decValue, bytes = null) { function decToHex(decValue, bytes = null) {
// tslint:disable-next-line:prefer-const // eslint-disable-next-line prefer-const
let dec = decValue.toString().split(''), sum = [], hex = '', hexArray = [], i, s; let dec = decValue.toString().split(''), sum = [], hex = '', hexArray = [], i, s;
while (dec.length) { while (dec.length) {
s = 1 * dec.shift(); s = 1 * dec.shift();

View file

@ -12,6 +12,7 @@ import {NotificationService} from './notification.service';
import {AppSettingsService} from './app-settings.service'; import {AppSettingsService} from './app-settings.service';
import {PriceService} from './price.service'; import {PriceService} from './price.service';
import {LedgerService} from './ledger.service'; import {LedgerService} from './ledger.service';
import { NoPaddingZerosPipe } from 'app/pipes/no-padding-zeros.pipe';
export type WalletType = 'seed' | 'ledger' | 'privateKey' | 'expandedKey'; export type WalletType = 'seed' | 'ledger' | 'privateKey' | 'expandedKey';
@ -136,6 +137,7 @@ export class WalletService {
private websocket: WebsocketService, private websocket: WebsocketService,
private nanoBlock: NanoBlockService, private nanoBlock: NanoBlockService,
private ledgerService: LedgerService, private ledgerService: LedgerService,
private noZerosPipe: NoPaddingZerosPipe,
private notifications: NotificationService) { private notifications: NotificationService) {
this.websocket.newTransactions$.subscribe(async (transaction) => { this.websocket.newTransactions$.subscribe(async (transaction) => {
if (!transaction) return; // Not really a new transaction if (!transaction) return; // Not really a new transaction
@ -853,7 +855,7 @@ export class WalletService {
this.wallet.balanceFiat = this.util.nano.rawToMnano(walletBalance).times(fiatPrice).toNumber(); this.wallet.balanceFiat = this.util.nano.rawToMnano(walletBalance).times(fiatPrice).toNumber();
this.wallet.pendingFiat = this.util.nano.rawToMnano(walletPendingAboveThresholdConfirmed).times(fiatPrice).toNumber(); this.wallet.pendingFiat = this.util.nano.rawToMnano(walletPendingAboveThresholdConfirmed).times(fiatPrice).toNumber();
// tslint:disable-next-line // eslint-disable-next-line
this.wallet.hasPending = walletPendingAboveThresholdConfirmed.gt(0); this.wallet.hasPending = walletPendingAboveThresholdConfirmed.gt(0);
this.wallet.updatingBalance = false; this.wallet.updatingBalance = false;
@ -1018,7 +1020,7 @@ export class WalletService {
const receiveAmount = this.util.nano.rawToMnano(nextBlock.amount); const receiveAmount = this.util.nano.rawToMnano(nextBlock.amount);
this.notifications.removeNotification('success-receive'); this.notifications.removeNotification('success-receive');
this.notifications.sendSuccess(`Successfully received ${receiveAmount.isZero() ? '' : receiveAmount.toFixed(6)} XNO!`, { identifier: 'success-receive' }); this.notifications.sendSuccess(`Successfully received ${receiveAmount.isZero() ? '' : this.noZerosPipe.transform(receiveAmount.toFixed(6)) } XNO!`, { identifier: 'success-receive' });
// remove after processing // remove after processing
// list also updated with reloadBalances but not if called too fast // list also updated with reloadBalances but not if called too fast

View file

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { WelcomeComponent } from './welcome.component'; import { WelcomeComponent } from './welcome.component';
@ -6,7 +6,7 @@ describe('WelcomeComponent', () => {
let component: WelcomeComponent; let component: WelcomeComponent;
let fixture: ComponentFixture<WelcomeComponent>; let fixture: ComponentFixture<WelcomeComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ WelcomeComponent ] declarations: [ WelcomeComponent ]
}) })

View file

@ -1,10 +1,10 @@
/*! UIkit 3.5.4 | https://www.getuikit.com | (c) 2014 - 2020 YOOtheme | MIT License */ /*! UIkit 3.9.4 | https://www.getuikit.com | (c) 2014 - 2021 YOOtheme | MIT License */
(function (global, factory) { (function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define('uikiticons', factory) : typeof define === 'function' && define.amd ? define('uikiticons', factory) :
(global = global || self, global.UIkitIcons = factory()); (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.UIkitIcons = factory());
}(this, (function () { 'use strict'; })(this, (function () { 'use strict';
function plugin(UIkit) { function plugin(UIkit) {
@ -19,6 +19,7 @@
"arrow-left": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" points=\"10 14 5 9.5 10 5\"/><line fill=\"none\" stroke=\"#000\" x1=\"16\" y1=\"9.5\" x2=\"5\" y2=\"9.52\"/></svg>", "arrow-left": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" points=\"10 14 5 9.5 10 5\"/><line fill=\"none\" stroke=\"#000\" x1=\"16\" y1=\"9.5\" x2=\"5\" y2=\"9.52\"/></svg>",
"arrow-right": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" points=\"10 5 15 9.5 10 14\"/><line fill=\"none\" stroke=\"#000\" x1=\"4\" y1=\"9.5\" x2=\"15\" y2=\"9.5\"/></svg>", "arrow-right": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" points=\"10 5 15 9.5 10 14\"/><line fill=\"none\" stroke=\"#000\" x1=\"4\" y1=\"9.5\" x2=\"15\" y2=\"9.5\"/></svg>",
"arrow-up": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"10.5,4 15.37,9.4 14.63,10.08 10.5,5.49 6.37,10.08 5.63,9.4\"/><line fill=\"none\" stroke=\"#000\" x1=\"10.5\" y1=\"16\" x2=\"10.5\" y2=\"5\"/></svg>", "arrow-up": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"10.5,4 15.37,9.4 14.63,10.08 10.5,5.49 6.37,10.08 5.63,9.4\"/><line fill=\"none\" stroke=\"#000\" x1=\"10.5\" y1=\"16\" x2=\"10.5\" y2=\"5\"/></svg>",
"bag": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" d=\"M7.5,7.5V4A2.48,2.48,0,0,1,10,1.5,2.54,2.54,0,0,1,12.5,4V7.5\"/><polygon fill=\"none\" stroke=\"#000\" points=\"16.5 7.5 3.5 7.5 2.5 18.5 17.5 18.5 16.5 7.5\"/></svg>",
"ban": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" cx=\"10\" cy=\"10\" r=\"9\"/><line fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" x1=\"4\" y1=\"3.5\" x2=\"16\" y2=\"16.5\"/></svg>", "ban": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" cx=\"10\" cy=\"10\" r=\"9\"/><line fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" x1=\"4\" y1=\"3.5\" x2=\"16\" y2=\"16.5\"/></svg>",
"behance": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M9.5,10.6c-0.4-0.5-0.9-0.9-1.6-1.1c1.7-1,2.2-3.2,0.7-4.7C7.8,4,6.3,4,5.2,4C3.5,4,1.7,4,0,4v12c1.7,0,3.4,0,5.2,0 c1,0,2.1,0,3.1-0.5C10.2,14.6,10.5,12.3,9.5,10.6L9.5,10.6z M5.6,6.1c1.8,0,1.8,2.7-0.1,2.7c-1,0-2,0-2.9,0V6.1H5.6z M2.6,13.8v-3.1 c1.1,0,2.1,0,3.2,0c2.1,0,2.1,3.2,0.1,3.2L2.6,13.8z\"/><path d=\"M19.9,10.9C19.7,9.2,18.7,7.6,17,7c-4.2-1.3-7.3,3.4-5.3,7.1c0.9,1.7,2.8,2.3,4.7,2.1c1.7-0.2,2.9-1.3,3.4-2.9h-2.2 c-0.4,1.3-2.4,1.5-3.5,0.6c-0.4-0.4-0.6-1.1-0.6-1.7H20C20,11.7,19.9,10.9,19.9,10.9z M13.5,10.6c0-1.6,2.3-2.7,3.5-1.4 c0.4,0.4,0.5,0.9,0.6,1.4H13.5L13.5,10.6z\"/><rect x=\"13\" y=\"4\" width=\"5\" height=\"1.4\"/></svg>", "behance": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M9.5,10.6c-0.4-0.5-0.9-0.9-1.6-1.1c1.7-1,2.2-3.2,0.7-4.7C7.8,4,6.3,4,5.2,4C3.5,4,1.7,4,0,4v12c1.7,0,3.4,0,5.2,0 c1,0,2.1,0,3.1-0.5C10.2,14.6,10.5,12.3,9.5,10.6L9.5,10.6z M5.6,6.1c1.8,0,1.8,2.7-0.1,2.7c-1,0-2,0-2.9,0V6.1H5.6z M2.6,13.8v-3.1 c1.1,0,2.1,0,3.2,0c2.1,0,2.1,3.2,0.1,3.2L2.6,13.8z\"/><path d=\"M19.9,10.9C19.7,9.2,18.7,7.6,17,7c-4.2-1.3-7.3,3.4-5.3,7.1c0.9,1.7,2.8,2.3,4.7,2.1c1.7-0.2,2.9-1.3,3.4-2.9h-2.2 c-0.4,1.3-2.4,1.5-3.5,0.6c-0.4-0.4-0.6-1.1-0.6-1.7H20C20,11.7,19.9,10.9,19.9,10.9z M13.5,10.6c0-1.6,2.3-2.7,3.5-1.4 c0.4,0.4,0.5,0.9,0.6,1.4H13.5L13.5,10.6z\"/><rect x=\"13\" y=\"4\" width=\"5\" height=\"1.4\"/></svg>",
"bell": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M17,15.5 L3,15.5 C2.99,14.61 3.79,13.34 4.1,12.51 C4.58,11.3 4.72,10.35 5.19,7.01 C5.54,4.53 5.89,3.2 7.28,2.16 C8.13,1.56 9.37,1.5 9.81,1.5 L9.96,1.5 C9.96,1.5 11.62,1.41 12.67,2.17 C14.08,3.2 14.42,4.54 14.77,7.02 C15.26,10.35 15.4,11.31 15.87,12.52 C16.2,13.34 17.01,14.61 17,15.5 L17,15.5 Z\"/><path fill=\"none\" stroke=\"#000\" d=\"M12.39,16 C12.39,17.37 11.35,18.43 9.91,18.43 C8.48,18.43 7.42,17.37 7.42,16\"/></svg>", "bell": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M17,15.5 L3,15.5 C2.99,14.61 3.79,13.34 4.1,12.51 C4.58,11.3 4.72,10.35 5.19,7.01 C5.54,4.53 5.89,3.2 7.28,2.16 C8.13,1.56 9.37,1.5 9.81,1.5 L9.96,1.5 C9.96,1.5 11.62,1.41 12.67,2.17 C14.08,3.2 14.42,4.54 14.77,7.02 C15.26,10.35 15.4,11.31 15.87,12.52 C16.2,13.34 17.01,14.61 17,15.5 L17,15.5 Z\"/><path fill=\"none\" stroke=\"#000\" d=\"M12.39,16 C12.39,17.37 11.35,18.43 9.91,18.43 C8.48,18.43 7.42,17.37 7.42,16\"/></svg>",
@ -48,6 +49,7 @@
"credit-card": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect fill=\"none\" stroke=\"#000\" x=\"1.5\" y=\"4.5\" width=\"17\" height=\"12\"/><rect x=\"1\" y=\"7\" width=\"18\" height=\"3\"/></svg>", "credit-card": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect fill=\"none\" stroke=\"#000\" x=\"1.5\" y=\"4.5\" width=\"17\" height=\"12\"/><rect x=\"1\" y=\"7\" width=\"18\" height=\"3\"/></svg>",
"database": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><ellipse fill=\"none\" stroke=\"#000\" cx=\"10\" cy=\"4.64\" rx=\"7.5\" ry=\"3.14\"/><path fill=\"none\" stroke=\"#000\" d=\"M17.5,8.11 C17.5,9.85 14.14,11.25 10,11.25 C5.86,11.25 2.5,9.84 2.5,8.11\"/><path fill=\"none\" stroke=\"#000\" d=\"M17.5,11.25 C17.5,12.99 14.14,14.39 10,14.39 C5.86,14.39 2.5,12.98 2.5,11.25\"/><path fill=\"none\" stroke=\"#000\" d=\"M17.49,4.64 L17.5,14.36 C17.5,16.1 14.14,17.5 10,17.5 C5.86,17.5 2.5,16.09 2.5,14.36 L2.5,4.64\"/></svg>", "database": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><ellipse fill=\"none\" stroke=\"#000\" cx=\"10\" cy=\"4.64\" rx=\"7.5\" ry=\"3.14\"/><path fill=\"none\" stroke=\"#000\" d=\"M17.5,8.11 C17.5,9.85 14.14,11.25 10,11.25 C5.86,11.25 2.5,9.84 2.5,8.11\"/><path fill=\"none\" stroke=\"#000\" d=\"M17.5,11.25 C17.5,12.99 14.14,14.39 10,14.39 C5.86,14.39 2.5,12.98 2.5,11.25\"/><path fill=\"none\" stroke=\"#000\" d=\"M17.49,4.64 L17.5,14.36 C17.5,16.1 14.14,17.5 10,17.5 C5.86,17.5 2.5,16.09 2.5,14.36 L2.5,4.64\"/></svg>",
"desktop": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"8\" y=\"15\" width=\"1\" height=\"2\"/><rect x=\"11\" y=\"15\" width=\"1\" height=\"2\"/><rect x=\"5\" y=\"16\" width=\"10\" height=\"1\"/><rect fill=\"none\" stroke=\"#000\" x=\"1.5\" y=\"3.5\" width=\"17\" height=\"11\"/></svg>", "desktop": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"8\" y=\"15\" width=\"1\" height=\"2\"/><rect x=\"11\" y=\"15\" width=\"1\" height=\"2\"/><rect x=\"5\" y=\"16\" width=\"10\" height=\"1\"/><rect fill=\"none\" stroke=\"#000\" x=\"1.5\" y=\"3.5\" width=\"17\" height=\"11\"/></svg>",
"discord": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\"><path d=\"M16.074,4.361a14.243,14.243,0,0,0-3.61-1.134,10.61,10.61,0,0,0-.463.96,13.219,13.219,0,0,0-4,0,10.138,10.138,0,0,0-.468-.96A14.206,14.206,0,0,0,3.919,4.364,15.146,15.146,0,0,0,1.324,14.5a14.435,14.435,0,0,0,4.428,2.269A10.982,10.982,0,0,0,6.7,15.21a9.294,9.294,0,0,1-1.494-.727c.125-.093.248-.19.366-.289a10.212,10.212,0,0,0,8.854,0c.119.1.242.2.366.289a9.274,9.274,0,0,1-1.5.728,10.8,10.8,0,0,0,.948,1.562,14.419,14.419,0,0,0,4.431-2.27A15.128,15.128,0,0,0,16.074,4.361Zm-8.981,8.1a1.7,1.7,0,0,1-1.573-1.79A1.689,1.689,0,0,1,7.093,8.881a1.679,1.679,0,0,1,1.573,1.791A1.687,1.687,0,0,1,7.093,12.462Zm5.814,0a1.7,1.7,0,0,1-1.573-1.79,1.689,1.689,0,0,1,1.573-1.791,1.679,1.679,0,0,1,1.573,1.791A1.688,1.688,0,0,1,12.907,12.462Z\"/></svg>",
"download": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" points=\"14,10 9.5,14.5 5,10\"/><rect x=\"3\" y=\"17\" width=\"13\" height=\"1\"/><line fill=\"none\" stroke=\"#000\" x1=\"9.5\" y1=\"13.91\" x2=\"9.5\" y2=\"3\"/></svg>", "download": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" points=\"14,10 9.5,14.5 5,10\"/><rect x=\"3\" y=\"17\" width=\"13\" height=\"1\"/><line fill=\"none\" stroke=\"#000\" x1=\"9.5\" y1=\"13.91\" x2=\"9.5\" y2=\"3\"/></svg>",
"dribbble": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.4\" d=\"M1.3,8.9c0,0,5,0.1,8.6-1c1.4-0.4,2.6-0.9,4-1.9 c1.4-1.1,2.5-2.5,2.5-2.5\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.4\" d=\"M3.9,16.6c0,0,1.7-2.8,3.5-4.2 c1.8-1.3,4-2,5.7-2.2C16,10,19,10.6,19,10.6\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.4\" d=\"M6.9,1.6c0,0,3.3,4.6,4.2,6.8 c0.4,0.9,1.3,3.1,1.9,5.2c0.6,2,0.9,4.4,0.9,4.4\"/><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.4\" cx=\"10\" cy=\"10\" r=\"9\"/></svg>", "dribbble": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.4\" d=\"M1.3,8.9c0,0,5,0.1,8.6-1c1.4-0.4,2.6-0.9,4-1.9 c1.4-1.1,2.5-2.5,2.5-2.5\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.4\" d=\"M3.9,16.6c0,0,1.7-2.8,3.5-4.2 c1.8-1.3,4-2,5.7-2.2C16,10,19,10.6,19,10.6\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.4\" d=\"M6.9,1.6c0,0,3.3,4.6,4.2,6.8 c0.4,0.9,1.3,3.1,1.9,5.2c0.6,2,0.9,4.4,0.9,4.4\"/><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.4\" cx=\"10\" cy=\"10\" r=\"9\"/></svg>",
"etsy": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\"><path d=\"M8,4.26C8,4.07,8,4,8.31,4h4.46c.79,0,1.22.67,1.53,1.91l.25,1h.76c.14-2.82.26-4,.26-4S13.65,3,12.52,3H6.81L3.75,2.92v.84l1,.2c.73.11.9.27,1,1,0,0,.06,2,.06,5.17s-.06,5.14-.06,5.14c0,.59-.23.81-1,.94l-1,.2v.84l3.06-.1h5.11c1.15,0,3.82.1,3.82.1,0-.7.45-3.88.51-4.22h-.73l-.76,1.69a2.25,2.25,0,0,1-2.45,1.47H9.4c-1,0-1.44-.4-1.44-1.24V10.44s2.16,0,2.86.06c.55,0,.85.19,1.06,1l.23,1H13L12.9,9.94,13,7.41h-.85l-.28,1.13c-.16.74-.28.84-1,1-1,.1-2.89.09-2.89.09Z\"/></svg>", "etsy": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\"><path d=\"M8,4.26C8,4.07,8,4,8.31,4h4.46c.79,0,1.22.67,1.53,1.91l.25,1h.76c.14-2.82.26-4,.26-4S13.65,3,12.52,3H6.81L3.75,2.92v.84l1,.2c.73.11.9.27,1,1,0,0,.06,2,.06,5.17s-.06,5.14-.06,5.14c0,.59-.23.81-1,.94l-1,.2v.84l3.06-.1h5.11c1.15,0,3.82.1,3.82.1,0-.7.45-3.88.51-4.22h-.73l-.76,1.69a2.25,2.25,0,0,1-2.45,1.47H9.4c-1,0-1.44-.4-1.44-1.24V10.44s2.16,0,2.86.06c.55,0,.85.19,1.06,1l.23,1H13L12.9,9.94,13,7.41h-.85l-.28,1.13c-.16.74-.28.84-1,1-1,.1-2.89.09-2.89.09Z\"/></svg>",
@ -67,7 +69,6 @@
"github-alt": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M10,0.5 C4.75,0.5 0.5,4.76 0.5,10.01 C0.5,15.26 4.75,19.51 10,19.51 C15.24,19.51 19.5,15.26 19.5,10.01 C19.5,4.76 15.25,0.5 10,0.5 L10,0.5 Z M12.81,17.69 C12.81,17.69 12.81,17.7 12.79,17.69 C12.47,17.75 12.35,17.59 12.35,17.36 L12.35,16.17 C12.35,15.45 12.09,14.92 11.58,14.56 C12.2,14.51 12.77,14.39 13.26,14.21 C13.87,13.98 14.36,13.69 14.74,13.29 C15.42,12.59 15.76,11.55 15.76,10.17 C15.76,9.25 15.45,8.46 14.83,7.8 C15.1,7.08 15.07,6.29 14.75,5.44 L14.51,5.42 C14.34,5.4 14.06,5.46 13.67,5.61 C13.25,5.78 12.79,6.03 12.31,6.35 C11.55,6.16 10.81,6.05 10.09,6.05 C9.36,6.05 8.61,6.15 7.88,6.35 C7.28,5.96 6.75,5.68 6.26,5.54 C6.07,5.47 5.9,5.44 5.78,5.44 L5.42,5.44 C5.06,6.29 5.04,7.08 5.32,7.8 C4.7,8.46 4.4,9.25 4.4,10.17 C4.4,11.94 4.96,13.16 6.08,13.84 C6.53,14.13 7.05,14.32 7.69,14.43 C8.03,14.5 8.32,14.54 8.55,14.55 C8.07,14.89 7.82,15.42 7.82,16.16 L7.82,17.51 C7.8,17.69 7.7,17.8 7.51,17.8 C4.21,16.74 1.82,13.65 1.82,10.01 C1.82,5.5 5.49,1.83 10,1.83 C14.5,1.83 18.17,5.5 18.17,10.01 C18.18,13.53 15.94,16.54 12.81,17.69 L12.81,17.69 Z\"/></svg>", "github-alt": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M10,0.5 C4.75,0.5 0.5,4.76 0.5,10.01 C0.5,15.26 4.75,19.51 10,19.51 C15.24,19.51 19.5,15.26 19.5,10.01 C19.5,4.76 15.25,0.5 10,0.5 L10,0.5 Z M12.81,17.69 C12.81,17.69 12.81,17.7 12.79,17.69 C12.47,17.75 12.35,17.59 12.35,17.36 L12.35,16.17 C12.35,15.45 12.09,14.92 11.58,14.56 C12.2,14.51 12.77,14.39 13.26,14.21 C13.87,13.98 14.36,13.69 14.74,13.29 C15.42,12.59 15.76,11.55 15.76,10.17 C15.76,9.25 15.45,8.46 14.83,7.8 C15.1,7.08 15.07,6.29 14.75,5.44 L14.51,5.42 C14.34,5.4 14.06,5.46 13.67,5.61 C13.25,5.78 12.79,6.03 12.31,6.35 C11.55,6.16 10.81,6.05 10.09,6.05 C9.36,6.05 8.61,6.15 7.88,6.35 C7.28,5.96 6.75,5.68 6.26,5.54 C6.07,5.47 5.9,5.44 5.78,5.44 L5.42,5.44 C5.06,6.29 5.04,7.08 5.32,7.8 C4.7,8.46 4.4,9.25 4.4,10.17 C4.4,11.94 4.96,13.16 6.08,13.84 C6.53,14.13 7.05,14.32 7.69,14.43 C8.03,14.5 8.32,14.54 8.55,14.55 C8.07,14.89 7.82,15.42 7.82,16.16 L7.82,17.51 C7.8,17.69 7.7,17.8 7.51,17.8 C4.21,16.74 1.82,13.65 1.82,10.01 C1.82,5.5 5.49,1.83 10,1.83 C14.5,1.83 18.17,5.5 18.17,10.01 C18.18,13.53 15.94,16.54 12.81,17.69 L12.81,17.69 Z\"/></svg>",
"github": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M10,1 C5.03,1 1,5.03 1,10 C1,13.98 3.58,17.35 7.16,18.54 C7.61,18.62 7.77,18.34 7.77,18.11 C7.77,17.9 7.76,17.33 7.76,16.58 C5.26,17.12 4.73,15.37 4.73,15.37 C4.32,14.33 3.73,14.05 3.73,14.05 C2.91,13.5 3.79,13.5 3.79,13.5 C4.69,13.56 5.17,14.43 5.17,14.43 C5.97,15.8 7.28,15.41 7.79,15.18 C7.87,14.6 8.1,14.2 8.36,13.98 C6.36,13.75 4.26,12.98 4.26,9.53 C4.26,8.55 4.61,7.74 5.19,7.11 C5.1,6.88 4.79,5.97 5.28,4.73 C5.28,4.73 6.04,4.49 7.75,5.65 C8.47,5.45 9.24,5.35 10,5.35 C10.76,5.35 11.53,5.45 12.25,5.65 C13.97,4.48 14.72,4.73 14.72,4.73 C15.21,5.97 14.9,6.88 14.81,7.11 C15.39,7.74 15.73,8.54 15.73,9.53 C15.73,12.99 13.63,13.75 11.62,13.97 C11.94,14.25 12.23,14.8 12.23,15.64 C12.23,16.84 12.22,17.81 12.22,18.11 C12.22,18.35 12.38,18.63 12.84,18.54 C16.42,17.35 19,13.98 19,10 C19,5.03 14.97,1 10,1 L10,1 Z\"/></svg>", "github": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M10,1 C5.03,1 1,5.03 1,10 C1,13.98 3.58,17.35 7.16,18.54 C7.61,18.62 7.77,18.34 7.77,18.11 C7.77,17.9 7.76,17.33 7.76,16.58 C5.26,17.12 4.73,15.37 4.73,15.37 C4.32,14.33 3.73,14.05 3.73,14.05 C2.91,13.5 3.79,13.5 3.79,13.5 C4.69,13.56 5.17,14.43 5.17,14.43 C5.97,15.8 7.28,15.41 7.79,15.18 C7.87,14.6 8.1,14.2 8.36,13.98 C6.36,13.75 4.26,12.98 4.26,9.53 C4.26,8.55 4.61,7.74 5.19,7.11 C5.1,6.88 4.79,5.97 5.28,4.73 C5.28,4.73 6.04,4.49 7.75,5.65 C8.47,5.45 9.24,5.35 10,5.35 C10.76,5.35 11.53,5.45 12.25,5.65 C13.97,4.48 14.72,4.73 14.72,4.73 C15.21,5.97 14.9,6.88 14.81,7.11 C15.39,7.74 15.73,8.54 15.73,9.53 C15.73,12.99 13.63,13.75 11.62,13.97 C11.94,14.25 12.23,14.8 12.23,15.64 C12.23,16.84 12.22,17.81 12.22,18.11 C12.22,18.35 12.38,18.63 12.84,18.54 C16.42,17.35 19,13.98 19,10 C19,5.03 14.97,1 10,1 L10,1 Z\"/></svg>",
"gitter": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"3.5\" y=\"1\" width=\"1.531\" height=\"11.471\"/><rect x=\"7.324\" y=\"4.059\" width=\"1.529\" height=\"15.294\"/><rect x=\"11.148\" y=\"4.059\" width=\"1.527\" height=\"15.294\"/><rect x=\"14.971\" y=\"4.059\" width=\"1.529\" height=\"8.412\"/></svg>", "gitter": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"3.5\" y=\"1\" width=\"1.531\" height=\"11.471\"/><rect x=\"7.324\" y=\"4.059\" width=\"1.529\" height=\"15.294\"/><rect x=\"11.148\" y=\"4.059\" width=\"1.527\" height=\"15.294\"/><rect x=\"14.971\" y=\"4.059\" width=\"1.529\" height=\"8.412\"/></svg>",
"google-plus": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M12.9,9c0,2.7-0.6,5-3.2,6.3c-3.7,1.8-8.1,0.2-9.4-3.6C-1.1,7.6,1.9,3.3,6.1,3c1.7-0.1,3.2,0.3,4.6,1.3 c0.1,0.1,0.3,0.2,0.4,0.4c-0.5,0.5-1.2,1-1.7,1.6c-1-0.8-2.1-1.1-3.5-0.9C5,5.6,4.2,6,3.6,6.7c-1.3,1.3-1.5,3.4-0.5,5 c1,1.7,2.6,2.3,4.6,1.9c1.4-0.3,2.4-1.2,2.6-2.6H6.9V9H12.9z\"/><polygon points=\"20,9 20,11 18,11 18,13 16,13 16,11 14,11 14,9 16,9 16,7 18,7 18,9\"/></svg>",
"google": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M17.86,9.09 C18.46,12.12 17.14,16.05 13.81,17.56 C9.45,19.53 4.13,17.68 2.47,12.87 C0.68,7.68 4.22,2.42 9.5,2.03 C11.57,1.88 13.42,2.37 15.05,3.65 C15.22,3.78 15.37,3.93 15.61,4.14 C14.9,4.81 14.23,5.45 13.5,6.14 C12.27,5.08 10.84,4.72 9.28,4.98 C8.12,5.17 7.16,5.76 6.37,6.63 C4.88,8.27 4.62,10.86 5.76,12.82 C6.95,14.87 9.17,15.8 11.57,15.25 C13.27,14.87 14.76,13.33 14.89,11.75 L10.51,11.75 L10.51,9.09 L17.86,9.09 L17.86,9.09 Z\"/></svg>", "google": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M17.86,9.09 C18.46,12.12 17.14,16.05 13.81,17.56 C9.45,19.53 4.13,17.68 2.47,12.87 C0.68,7.68 4.22,2.42 9.5,2.03 C11.57,1.88 13.42,2.37 15.05,3.65 C15.22,3.78 15.37,3.93 15.61,4.14 C14.9,4.81 14.23,5.45 13.5,6.14 C12.27,5.08 10.84,4.72 9.28,4.98 C8.12,5.17 7.16,5.76 6.37,6.63 C4.88,8.27 4.62,10.86 5.76,12.82 C6.95,14.87 9.17,15.8 11.57,15.25 C13.27,14.87 14.76,13.33 14.89,11.75 L10.51,11.75 L10.51,9.09 L17.86,9.09 L17.86,9.09 Z\"/></svg>",
"grid": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"2\" y=\"2\" width=\"3\" height=\"3\"/><rect x=\"8\" y=\"2\" width=\"3\" height=\"3\"/><rect x=\"14\" y=\"2\" width=\"3\" height=\"3\"/><rect x=\"2\" y=\"8\" width=\"3\" height=\"3\"/><rect x=\"8\" y=\"8\" width=\"3\" height=\"3\"/><rect x=\"14\" y=\"8\" width=\"3\" height=\"3\"/><rect x=\"2\" y=\"14\" width=\"3\" height=\"3\"/><rect x=\"8\" y=\"14\" width=\"3\" height=\"3\"/><rect x=\"14\" y=\"14\" width=\"3\" height=\"3\"/></svg>", "grid": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"2\" y=\"2\" width=\"3\" height=\"3\"/><rect x=\"8\" y=\"2\" width=\"3\" height=\"3\"/><rect x=\"14\" y=\"2\" width=\"3\" height=\"3\"/><rect x=\"2\" y=\"8\" width=\"3\" height=\"3\"/><rect x=\"8\" y=\"8\" width=\"3\" height=\"3\"/><rect x=\"14\" y=\"8\" width=\"3\" height=\"3\"/><rect x=\"2\" y=\"14\" width=\"3\" height=\"3\"/><rect x=\"8\" y=\"14\" width=\"3\" height=\"3\"/><rect x=\"14\" y=\"14\" width=\"3\" height=\"3\"/></svg>",
"happy": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle cx=\"13\" cy=\"7\" r=\"1\"/><circle cx=\"7\" cy=\"7\" r=\"1\"/><circle fill=\"none\" stroke=\"#000\" cx=\"10\" cy=\"10\" r=\"8.5\"/><path fill=\"none\" stroke=\"#000\" d=\"M14.6,11.4 C13.9,13.3 12.1,14.5 10,14.5 C7.9,14.5 6.1,13.3 5.4,11.4\"/></svg>", "happy": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle cx=\"13\" cy=\"7\" r=\"1\"/><circle cx=\"7\" cy=\"7\" r=\"1\"/><circle fill=\"none\" stroke=\"#000\" cx=\"10\" cy=\"10\" r=\"8.5\"/><path fill=\"none\" stroke=\"#000\" d=\"M14.6,11.4 C13.9,13.3 12.1,14.5 10,14.5 C7.9,14.5 6.1,13.3 5.4,11.4\"/></svg>",
@ -131,6 +132,7 @@
"tablet": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" d=\"M5,18.5 C4.2,18.5 3.5,17.8 3.5,17 L3.5,3 C3.5,2.2 4.2,1.5 5,1.5 L16,1.5 C16.8,1.5 17.5,2.2 17.5,3 L17.5,17 C17.5,17.8 16.8,18.5 16,18.5 L5,18.5 L5,18.5 L5,18.5 Z\"/><circle cx=\"10.5\" cy=\"16.3\" r=\".8\"/></svg>", "tablet": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" d=\"M5,18.5 C4.2,18.5 3.5,17.8 3.5,17 L3.5,3 C3.5,2.2 4.2,1.5 5,1.5 L16,1.5 C16.8,1.5 17.5,2.2 17.5,3 L17.5,17 C17.5,17.8 16.8,18.5 16,18.5 L5,18.5 L5,18.5 L5,18.5 Z\"/><circle cx=\"10.5\" cy=\"16.3\" r=\".8\"/></svg>",
"tag": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M17.5,3.71 L17.5,7.72 C17.5,7.96 17.4,8.2 17.21,8.39 L8.39,17.2 C7.99,17.6 7.33,17.6 6.93,17.2 L2.8,13.07 C2.4,12.67 2.4,12.01 2.8,11.61 L11.61,2.8 C11.81,2.6 12.08,2.5 12.34,2.5 L16.19,2.5 C16.52,2.5 16.86,2.63 17.11,2.88 C17.35,3.11 17.48,3.4 17.5,3.71 L17.5,3.71 Z\"/><circle cx=\"14\" cy=\"6\" r=\"1\"/></svg>", "tag": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M17.5,3.71 L17.5,7.72 C17.5,7.96 17.4,8.2 17.21,8.39 L8.39,17.2 C7.99,17.6 7.33,17.6 6.93,17.2 L2.8,13.07 C2.4,12.67 2.4,12.01 2.8,11.61 L11.61,2.8 C11.81,2.6 12.08,2.5 12.34,2.5 L16.19,2.5 C16.52,2.5 16.86,2.63 17.11,2.88 C17.35,3.11 17.48,3.4 17.5,3.71 L17.5,3.71 Z\"/><circle cx=\"14\" cy=\"6\" r=\"1\"/></svg>",
"thumbnails": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect fill=\"none\" stroke=\"#000\" x=\"3.5\" y=\"3.5\" width=\"5\" height=\"5\"/><rect fill=\"none\" stroke=\"#000\" x=\"11.5\" y=\"3.5\" width=\"5\" height=\"5\"/><rect fill=\"none\" stroke=\"#000\" x=\"11.5\" y=\"11.5\" width=\"5\" height=\"5\"/><rect fill=\"none\" stroke=\"#000\" x=\"3.5\" y=\"11.5\" width=\"5\" height=\"5\"/></svg>", "thumbnails": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect fill=\"none\" stroke=\"#000\" x=\"3.5\" y=\"3.5\" width=\"5\" height=\"5\"/><rect fill=\"none\" stroke=\"#000\" x=\"11.5\" y=\"3.5\" width=\"5\" height=\"5\"/><rect fill=\"none\" stroke=\"#000\" x=\"11.5\" y=\"11.5\" width=\"5\" height=\"5\"/><rect fill=\"none\" stroke=\"#000\" x=\"3.5\" y=\"11.5\" width=\"5\" height=\"5\"/></svg>",
"tiktok": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M17.24,6V8.82a6.79,6.79,0,0,1-4-1.28v5.81A5.26,5.26,0,1,1,8,8.1a4.36,4.36,0,0,1,.72.05v2.9A2.57,2.57,0,0,0,7.64,11a2.4,2.4,0,1,0,2.77,2.38V2h2.86a4,4,0,0,0,1.84,3.38A4,4,0,0,0,17.24,6Z\"/></svg>",
"trash": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" points=\"6.5 3 6.5 1.5 13.5 1.5 13.5 3\"/><polyline fill=\"none\" stroke=\"#000\" points=\"4.5 4 4.5 18.5 15.5 18.5 15.5 4\"/><rect x=\"8\" y=\"7\" width=\"1\" height=\"9\"/><rect x=\"11\" y=\"7\" width=\"1\" height=\"9\"/><rect x=\"2\" y=\"3\" width=\"16\" height=\"1\"/></svg>", "trash": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" points=\"6.5 3 6.5 1.5 13.5 1.5 13.5 3\"/><polyline fill=\"none\" stroke=\"#000\" points=\"4.5 4 4.5 18.5 15.5 18.5 15.5 4\"/><rect x=\"8\" y=\"7\" width=\"1\" height=\"9\"/><rect x=\"11\" y=\"7\" width=\"1\" height=\"9\"/><rect x=\"2\" y=\"3\" width=\"16\" height=\"1\"/></svg>",
"triangle-down": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"5 7 15 7 10 12\"/></svg>", "triangle-down": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"5 7 15 7 10 12\"/></svg>",
"triangle-left": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"12 5 7 10 12 15\"/></svg>", "triangle-left": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"12 5 7 10 12 15\"/></svg>",
@ -139,6 +141,7 @@
"tripadvisor": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M19.021,7.866C19.256,6.862,20,5.854,20,5.854h-3.346C14.781,4.641,12.504,4,9.98,4C7.363,4,4.999,4.651,3.135,5.876H0\tc0,0,0.738,0.987,0.976,1.988c-0.611,0.837-0.973,1.852-0.973,2.964c0,2.763,2.249,5.009,5.011,5.009\tc1.576,0,2.976-0.737,3.901-1.879l1.063,1.599l1.075-1.615c0.475,0.611,1.1,1.111,1.838,1.451c1.213,0.547,2.574,0.612,3.825,0.15\tc2.589-0.963,3.913-3.852,2.964-6.439c-0.175-0.463-0.4-0.876-0.675-1.238H19.021z M16.38,14.594\tc-1.002,0.371-2.088,0.328-3.06-0.119c-0.688-0.317-1.252-0.817-1.657-1.438c-0.164-0.25-0.313-0.52-0.417-0.811\tc-0.124-0.328-0.186-0.668-0.217-1.014c-0.063-0.689,0.037-1.396,0.339-2.043c0.448-0.971,1.251-1.71,2.25-2.079\tc2.075-0.765,4.375,0.3,5.14,2.366c0.762,2.066-0.301,4.37-2.363,5.134L16.38,14.594L16.38,14.594z M8.322,13.066\tc-0.72,1.059-1.935,1.76-3.309,1.76c-2.207,0-4.001-1.797-4.001-3.996c0-2.203,1.795-4.002,4.001-4.002\tc2.204,0,3.999,1.8,3.999,4.002c0,0.137-0.024,0.261-0.04,0.396c-0.067,0.678-0.284,1.313-0.648,1.853v-0.013H8.322z M2.472,10.775\tc0,1.367,1.112,2.479,2.476,2.479c1.363,0,2.472-1.11,2.472-2.479c0-1.359-1.11-2.468-2.472-2.468\tC3.584,8.306,2.473,9.416,2.472,10.775L2.472,10.775z M12.514,10.775c0,1.367,1.104,2.479,2.471,2.479\tc1.363,0,2.474-1.108,2.474-2.479c0-1.359-1.11-2.468-2.474-2.468c-1.364,0-2.477,1.109-2.477,2.468H12.514z M3.324,10.775\tc0-0.893,0.726-1.618,1.614-1.618c0.889,0,1.625,0.727,1.625,1.618c0,0.898-0.725,1.627-1.625,1.627\tc-0.901,0-1.625-0.729-1.625-1.627H3.324z M13.354,10.775c0-0.893,0.726-1.618,1.627-1.618c0.886,0,1.61,0.727,1.61,1.618\tc0,0.898-0.726,1.627-1.626,1.627s-1.625-0.729-1.625-1.627H13.354z M9.977,4.875c1.798,0,3.425,0.324,4.849,0.968\tc-0.535,0.015-1.061,0.108-1.586,0.3c-1.264,0.463-2.264,1.388-2.815,2.604c-0.262,0.551-0.398,1.133-0.448,1.72\tC9.79,7.905,7.677,5.873,5.076,5.82C6.501,5.208,8.153,4.875,9.94,4.875H9.977z\"/></svg>", "tripadvisor": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M19.021,7.866C19.256,6.862,20,5.854,20,5.854h-3.346C14.781,4.641,12.504,4,9.98,4C7.363,4,4.999,4.651,3.135,5.876H0\tc0,0,0.738,0.987,0.976,1.988c-0.611,0.837-0.973,1.852-0.973,2.964c0,2.763,2.249,5.009,5.011,5.009\tc1.576,0,2.976-0.737,3.901-1.879l1.063,1.599l1.075-1.615c0.475,0.611,1.1,1.111,1.838,1.451c1.213,0.547,2.574,0.612,3.825,0.15\tc2.589-0.963,3.913-3.852,2.964-6.439c-0.175-0.463-0.4-0.876-0.675-1.238H19.021z M16.38,14.594\tc-1.002,0.371-2.088,0.328-3.06-0.119c-0.688-0.317-1.252-0.817-1.657-1.438c-0.164-0.25-0.313-0.52-0.417-0.811\tc-0.124-0.328-0.186-0.668-0.217-1.014c-0.063-0.689,0.037-1.396,0.339-2.043c0.448-0.971,1.251-1.71,2.25-2.079\tc2.075-0.765,4.375,0.3,5.14,2.366c0.762,2.066-0.301,4.37-2.363,5.134L16.38,14.594L16.38,14.594z M8.322,13.066\tc-0.72,1.059-1.935,1.76-3.309,1.76c-2.207,0-4.001-1.797-4.001-3.996c0-2.203,1.795-4.002,4.001-4.002\tc2.204,0,3.999,1.8,3.999,4.002c0,0.137-0.024,0.261-0.04,0.396c-0.067,0.678-0.284,1.313-0.648,1.853v-0.013H8.322z M2.472,10.775\tc0,1.367,1.112,2.479,2.476,2.479c1.363,0,2.472-1.11,2.472-2.479c0-1.359-1.11-2.468-2.472-2.468\tC3.584,8.306,2.473,9.416,2.472,10.775L2.472,10.775z M12.514,10.775c0,1.367,1.104,2.479,2.471,2.479\tc1.363,0,2.474-1.108,2.474-2.479c0-1.359-1.11-2.468-2.474-2.468c-1.364,0-2.477,1.109-2.477,2.468H12.514z M3.324,10.775\tc0-0.893,0.726-1.618,1.614-1.618c0.889,0,1.625,0.727,1.625,1.618c0,0.898-0.725,1.627-1.625,1.627\tc-0.901,0-1.625-0.729-1.625-1.627H3.324z M13.354,10.775c0-0.893,0.726-1.618,1.627-1.618c0.886,0,1.61,0.727,1.61,1.618\tc0,0.898-0.726,1.627-1.626,1.627s-1.625-0.729-1.625-1.627H13.354z M9.977,4.875c1.798,0,3.425,0.324,4.849,0.968\tc-0.535,0.015-1.061,0.108-1.586,0.3c-1.264,0.463-2.264,1.388-2.815,2.604c-0.262,0.551-0.398,1.133-0.448,1.72\tC9.79,7.905,7.677,5.873,5.076,5.82C6.501,5.208,8.153,4.875,9.94,4.875H9.977z\"/></svg>",
"tumblr": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M6.885,8.598c0,0,0,3.393,0,4.996c0,0.282,0,0.66,0.094,0.942c0.377,1.509,1.131,2.545,2.545,3.11 c1.319,0.472,2.356,0.472,3.676,0c0.565-0.188,1.132-0.659,1.132-0.659l-0.849-2.263c0,0-1.036,0.378-1.603,0.283 c-0.565-0.094-1.226-0.66-1.226-1.508c0-1.603,0-4.902,0-4.902h2.828V5.771h-2.828V2H8.205c0,0-0.094,0.66-0.188,0.942 C7.828,3.791,7.262,4.733,6.603,5.394C5.848,6.147,5,6.43,5,6.43v2.168H6.885z\"/></svg>", "tumblr": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M6.885,8.598c0,0,0,3.393,0,4.996c0,0.282,0,0.66,0.094,0.942c0.377,1.509,1.131,2.545,2.545,3.11 c1.319,0.472,2.356,0.472,3.676,0c0.565-0.188,1.132-0.659,1.132-0.659l-0.849-2.263c0,0-1.036,0.378-1.603,0.283 c-0.565-0.094-1.226-0.66-1.226-1.508c0-1.603,0-4.902,0-4.902h2.828V5.771h-2.828V2H8.205c0,0-0.094,0.66-0.188,0.942 C7.828,3.791,7.262,4.733,6.603,5.394C5.848,6.147,5,6.43,5,6.43v2.168H6.885z\"/></svg>",
"tv": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"7\" y=\"16\" width=\"6\" height=\"1\"/><rect fill=\"none\" stroke=\"#000\" x=\".5\" y=\"3.5\" width=\"19\" height=\"11\"/></svg>", "tv": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"7\" y=\"16\" width=\"6\" height=\"1\"/><rect fill=\"none\" stroke=\"#000\" x=\".5\" y=\"3.5\" width=\"19\" height=\"11\"/></svg>",
"twitch": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M5.23,1,2,4.23V15.85H5.88v3.23L9.1,15.85h2.59L17.5,10V1Zm11,8.4L13.62,12H11L8.78,14.24V12H5.88V2.29H16.21Z\"/><rect x=\"12.98\" y=\"4.55\" width=\"1.29\" height=\"3.88\"/><rect x=\"9.43\" y=\"4.55\" width=\"1.29\" height=\"3.88\"/></svg>",
"twitter": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M19,4.74 C18.339,5.029 17.626,5.229 16.881,5.32 C17.644,4.86 18.227,4.139 18.503,3.28 C17.79,3.7 17.001,4.009 16.159,4.17 C15.485,3.45 14.526,3 13.464,3 C11.423,3 9.771,4.66 9.771,6.7 C9.771,6.99 9.804,7.269 9.868,7.539 C6.795,7.38 4.076,5.919 2.254,3.679 C1.936,4.219 1.754,4.86 1.754,5.539 C1.754,6.82 2.405,7.95 3.397,8.61 C2.79,8.589 2.22,8.429 1.723,8.149 L1.723,8.189 C1.723,9.978 2.997,11.478 4.686,11.82 C4.376,11.899 4.049,11.939 3.713,11.939 C3.475,11.939 3.245,11.919 3.018,11.88 C3.49,13.349 4.852,14.419 6.469,14.449 C5.205,15.429 3.612,16.019 1.882,16.019 C1.583,16.019 1.29,16.009 1,15.969 C2.635,17.019 4.576,17.629 6.662,17.629 C13.454,17.629 17.17,12 17.17,7.129 C17.17,6.969 17.166,6.809 17.157,6.649 C17.879,6.129 18.504,5.478 19,4.74\"/></svg>", "twitter": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M19,4.74 C18.339,5.029 17.626,5.229 16.881,5.32 C17.644,4.86 18.227,4.139 18.503,3.28 C17.79,3.7 17.001,4.009 16.159,4.17 C15.485,3.45 14.526,3 13.464,3 C11.423,3 9.771,4.66 9.771,6.7 C9.771,6.99 9.804,7.269 9.868,7.539 C6.795,7.38 4.076,5.919 2.254,3.679 C1.936,4.219 1.754,4.86 1.754,5.539 C1.754,6.82 2.405,7.95 3.397,8.61 C2.79,8.589 2.22,8.429 1.723,8.149 L1.723,8.189 C1.723,9.978 2.997,11.478 4.686,11.82 C4.376,11.899 4.049,11.939 3.713,11.939 C3.475,11.939 3.245,11.919 3.018,11.88 C3.49,13.349 4.852,14.419 6.469,14.449 C5.205,15.429 3.612,16.019 1.882,16.019 C1.583,16.019 1.29,16.009 1,15.969 C2.635,17.019 4.576,17.629 6.662,17.629 C13.454,17.629 17.17,12 17.17,7.129 C17.17,6.969 17.166,6.809 17.157,6.649 C17.879,6.129 18.504,5.478 19,4.74\"/></svg>",
"uikit": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"14.4,3.1 11.3,5.1 15,7.3 15,12.9 10,15.7 5,12.9 5,8.5 2,6.8 2,14.8 9.9,19.5 18,14.8 18,5.3\"/><polygon points=\"9.8,4.2 6.7,2.4 9.8,0.4 12.9,2.3\"/></svg>", "uikit": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"14.4,3.1 11.3,5.1 15,7.3 15,12.9 10,15.7 5,12.9 5,8.5 2,6.8 2,14.8 9.9,19.5 18,14.8 18,5.3\"/><polygon points=\"9.8,4.2 6.7,2.4 9.8,0.4 12.9,2.3\"/></svg>",
"unlock": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect fill=\"none\" stroke=\"#000\" x=\"3.5\" y=\"8.5\" width=\"13\" height=\"10\"/><path fill=\"none\" stroke=\"#000\" d=\"M6.5,8.5 L6.5,4.9 C6.5,3 8.1,1.5 10,1.5 C11.9,1.5 13.5,3 13.5,4.9\"/></svg>", "unlock": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect fill=\"none\" stroke=\"#000\" x=\"3.5\" y=\"8.5\" width=\"13\" height=\"10\"/><path fill=\"none\" stroke=\"#000\" d=\"M6.5,8.5 L6.5,4.9 C6.5,3 8.1,1.5 10,1.5 C11.9,1.5 13.5,3 13.5,4.9\"/></svg>",
@ -164,4 +167,4 @@
return plugin; return plugin;
}))); }));

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

1
src/assets/lib/base/uikit-rtl.min.css vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -186,6 +186,10 @@
border-bottom-color: @dark-mode-background-1; border-bottom-color: @dark-mode-background-1;
} }
.uk-table-striped > tr:nth-of-type(2n):last-child, .uk-table-striped tbody tr:nth-of-type(2n):last-child {
border-bottom: 1px solid @dark-mode-background-2;
}
// General (List) // General (List)
.uk-list { .uk-list {
background: @dark-mode-background-2; background: @dark-mode-background-2;
@ -449,6 +453,16 @@
background: @dark-mode-background-2 !important; background: @dark-mode-background-2 !important;
} }
.merchant-mode-overlay {
background: @dark-mode-background-1 !important;
.merchant-mode-logo {
background: url('../../assets/img/nault-logo-night-mode.svg');
background-size: contain;
background-repeat: no-repeat;
}
}
// Representatives page // Representatives page
.delegating-account-row, .representative-row { .delegating-account-row, .representative-row {
background: @dark-mode-background-3 !important; background: @dark-mode-background-3 !important;

View file

@ -575,6 +575,10 @@
border-left-color: @global-primary-background; border-left-color: @global-primary-background;
color: @global-primary-background; color: @global-primary-background;
} }
> .uk-grid-stack {
flex: 1;
}
} }
.label-new { .label-new {
@ -582,8 +586,10 @@
margin: -10px 0px -10px -9px; margin: -10px 0px -10px -9px;
> .uk-badge { > .uk-badge {
display: flex;
height: 22px;
font-size: 16px; font-size: 16px;
padding-bottom: 2px; padding: 1px 0 0 0;
} }
} }

View file

@ -28,7 +28,7 @@ h1, h2, h3, h4, h5, .uk-text-lead, .uk-button, .uk-alert, .uk-description-list d
@media (max-width: 939px) { @media (max-width: 939px) {
.nlt-button-group button { .nlt-button-group button {
margin-bottom: @nlt-intro-margin / 2 !important; margin-bottom: 20px !important;
} }
h2:not(.uk-card-title):not(.uk-modal-title) { h2:not(.uk-card-title):not(.uk-modal-title) {
@ -1336,6 +1336,30 @@ input[type=number] {
} }
} }
// Receive page
.merchant-centered-container {
.identicon-name-row {
display: flex;
flex-direction: row;
align-items: center;
height: 28px;
padding-bottom: 8px;
.nano-identicon {
display: inline-block;
width: 27px;
height: 27px;
margin-right: 12px;
margin-left: 1px;
flex-shrink: 0;
.canvas-container canvas {
border-radius: 3px;
}
}
}
}
// Representatives page // Representatives page
.delegating-account-row { .delegating-account-row {
border-top: none !important; border-top: none !important;
@ -1527,6 +1551,14 @@ input[type=number] {
background-color: #16A670 !important; background-color: #16A670 !important;
} }
.nlt-button-green {
background-color: #16A670 !important;
&:hover {
background-color: #069660 !important;
}
}
.nlt-page-intro { .nlt-page-intro {
margin-bottom: @nlt-intro-margin; margin-bottom: @nlt-intro-margin;
} }

View file

@ -13,18 +13,12 @@ import '@angular/localize/init';
// (window as any).global = window; // (window as any).global = window;
global.Buffer = global.Buffer || require('buffer').Buffer; global.Buffer = global.Buffer || require('buffer').Buffer;
/**
* Required to support Web Animations `@angular/platform-browser/animations`.
* Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
**/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/*************************************************************************************************** /***************************************************************************************************
* Zone JS is required by default for Angular itself. * Zone JS is required by default for Angular itself.
*/ */
import 'zone.js/dist/zone'; // Included with Angular CLI. import 'zone.js'; // Included with Angular CLI.

View file

@ -22,7 +22,9 @@ __karma__.loaded = function () {};
// First, initialize the Angular testing environment. // First, initialize the Angular testing environment.
getTestBed().initTestEnvironment( getTestBed().initTestEnvironment(
BrowserDynamicTestingModule, BrowserDynamicTestingModule,
platformBrowserDynamicTesting() platformBrowserDynamicTesting(), {
teardown: { destroyAfterEach: false }
}
); );
// Then we find all the tests. // Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/); const context = require.context('./', true, /\.spec\.ts$/);

View file

@ -1,5 +1,5 @@
{ {
"extends": "../tsconfig.base.json", "extends": "../tsconfig.json",
"compilerOptions": { "compilerOptions": {
"outDir": "../out-tsc/app", "outDir": "../out-tsc/app",
"baseUrl": "./", "baseUrl": "./",

View file

@ -1,5 +1,5 @@
{ {
"extends": "../tsconfig.base.json", "extends": "../tsconfig.json",
"compilerOptions": { "compilerOptions": {
"outDir": "../out-tsc/spec", "outDir": "../out-tsc/spec",
"baseUrl": "./", "baseUrl": "./",

View file

@ -1,27 +0,0 @@
{
"compileOnSave": false,
"compilerOptions": {
"downlevelIteration": true,
"importHelpers": true,
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es2015",
"typeRoots": [
"node_modules/@types",
"./src/typings"
],
"lib": [
"es2017",
"dom"
],
"module": "es2020",
"baseUrl": "./",
"paths": {
"stream": ["../node_modules/readable-stream/readable.js"]
}
}
}

View file

@ -1,17 +1,27 @@
/*
This is a "Solution Style" tsconfig.json file, and is used by editors and TypeScripts language server to improve development experience.
It is not intended to be used to perform a compilation.
To learn more about this file see: https://angular.io/config/solution-tsconfig.
*/
{ {
"files": [], "compileOnSave": false,
"references": [ "compilerOptions": {
{ "downlevelIteration": true,
"path": "./src/tsconfig.app.json" "importHelpers": true,
}, "outDir": "./dist/out-tsc",
{ "sourceMap": true,
"path": "./src/tsconfig.spec.json" "declaration": false,
"moduleResolution": "node",
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "es2017",
"typeRoots": [
"node_modules/@types",
"./src/typings"
],
"lib": [
"es2020",
"dom"
],
"module": "es2020",
"baseUrl": "./",
"paths": {
"stream": ["../node_modules/readable-stream/readable.js"]
} }
] }
} }

View file

@ -7,7 +7,6 @@
"sourceMap": true, "sourceMap": true,
"declaration": false, "declaration": false,
"moduleResolution": "node", "moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"target": "es2015", "target": "es2015",
"typeRoots": [ "typeRoots": [

View file

@ -1,141 +0,0 @@
{
"rulesDirectory": [
"node_modules/codelyzer"
],
"rules": {
"arrow-return-shorthand": true,
"callable-types": true,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": [true, "ignore-same-line"],
"deprecation": {
"severity": "warn"
},
"eofline": true,
"forin": true,
"import-blacklist": [
true,
"rxjs/Rx"
],
"import-spacing": true,
"indent": [
true,
"spaces"
],
"interface-over-type-literal": true,
"label-position": true,
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-super": true,
"no-empty": false,
"no-empty-interface": true,
"no-eval": true,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-misused-new": true,
"no-non-null-assertion": true,
"no-shadowed-variable": true,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unnecessary-initializer": true,
"no-unused-expression": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"prefer-const": true,
"quotemark": [
true,
"single"
],
"radix": true,
"semicolon": [
true,
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"unified-signatures": true,
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
],
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"no-output-on-prefix": true,
"no-inputs-metadata-property": true,
"no-outputs-metadata-property": true,
"no-host-metadata-property": true,
"no-input-rename": true,
"no-output-rename": true,
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true,
"component-class-suffix": true,
"directive-class-suffix": true
}
}