Merge branch 'device-page' of selene repository into tartarus-overhaul branch

pull/1/head
Chris Veilleux 2019-01-24 15:41:01 -06:00
commit 1bd8a8c47a
267 changed files with 19229 additions and 0 deletions

2
.dockerignore Normal file
View File

@ -0,0 +1,2 @@
dist
node_modules

13
.editorconfig Normal file
View File

@ -0,0 +1,13 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

39
.gitignore vendored Normal file
View File

@ -0,0 +1,39 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/tmp
/out-tsc
# dependencies
/node_modules
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
# System Files
.DS_Store
Thumbs.db

16
Dockerfile Normal file
View File

@ -0,0 +1,16 @@
# Multistage Dockerfile to build the marketplace UI and a web server to run it
# STAGE ONE: build the marketplace angular application
FROM node:latest as build
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
ARG selene_env
ARG application_name
RUN npm run build -- --project=globalnav
RUN npm run build-${selene_env} -- --project=${application_name}
# STAGE TWO: build the web server and copy the compiled angular app to it.
FROM nginx:latest
COPY --from=build /usr/src/app/dist/${application_name} /usr/share/nginx/html

739
angular.json Normal file
View File

@ -0,0 +1,739 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"internet": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"prefix": "app",
"schematics": {
"@schematics/angular:component": {
"styleext": "scss"
}
},
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/internet",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss",
"src/theme.scss"
],
"stylePreprocessorOptions": {
"includePaths": [
"./src/stylesheets"
]
},
"scripts": []
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "internet:build"
},
"configurations": {
"production": {
"browserTarget": "internet:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "internet:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.spec.json",
"karmaConfig": "src/karma.conf.js",
"styles": [
"src/styles.scss",
"src/theme.scss"
],
"stylePreprocessorOptions": {
"includePaths": [
"./src/stylesheets"
]
},
"scripts": [],
"assets": [
"src/favicon.ico",
"src/assets"
]
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"src/tsconfig.app.json",
"src/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"internet-e2e": {
"root": "e2e/",
"projectType": "application",
"prefix": "",
"architect": {
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "internet:serve"
},
"configurations": {
"production": {
"devServerTarget": "internet:serve:production"
}
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": "e2e/tsconfig.e2e.json",
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"market": {
"root": "projects/market/",
"sourceRoot": "projects/market/src",
"projectType": "application",
"prefix": "market",
"schematics": {
"@schematics/angular:component": {
"styleext": "scss",
"spec": false
},
"@schematics/angular:class": {
"spec": false
},
"@schematics/angular:directive": {
"spec": false
},
"@schematics/angular:guard": {
"spec": false
},
"@schematics/angular:module": {
"spec": false
},
"@schematics/angular:pipe": {
"spec": false
},
"@schematics/angular:service": {
"spec": false
}
},
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/market",
"index": "projects/market/src/index.html",
"main": "projects/market/src/main.ts",
"polyfills": "projects/market/src/polyfills.ts",
"tsConfig": "projects/market/tsconfig.app.json",
"assets": [
"projects/market/src/favicon.ico",
"projects/market/src/assets"
],
"styles": [
"src/styles.scss",
"src/theme.scss"
],
"stylePreprocessorOptions": {
"includePaths": [
"./src/stylesheets"
]
},
"scripts": []
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "projects/market/src/environments/environment.ts",
"with": "projects/market/src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
}
]
},
"test": {
"fileReplacements": [
{
"replace": "projects/market/src/environments/environment.ts",
"with": "projects/market/src/environments/environment.test.ts"
}
]
},
"development": {
"fileReplacements": [
{
"replace": "projects/market/src/environments/environment.ts",
"with": "projects/market/src/environments/environment.dev.ts"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "market:build"
},
"configurations": {
"production": {
"browserTarget": "market:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "market:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/market/src/test.ts",
"polyfills": "projects/market/src/polyfills.ts",
"tsConfig": "projects/market/tsconfig.spec.json",
"karmaConfig": "projects/market/karma.conf.js",
"styles": [
"src/styles.scss",
"src/theme.scss"
],
"stylePreprocessorOptions": {
"includePaths": [
"./src/stylesheets"
]
},
"scripts": [],
"assets": [
"projects/market/src/favicon.ico",
"projects/market/src/assets"
]
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"projects/market/tsconfig.app.json",
"projects/market/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"market-e2e": {
"root": "projects/market-e2e/",
"projectType": "application",
"prefix": "",
"architect": {
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "projects/market-e2e/protractor.conf.js",
"devServerTarget": "market:serve"
},
"configurations": {
"production": {
"devServerTarget": "market:serve:production"
}
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": "projects/market-e2e/tsconfig.e2e.json",
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"sso": {
"root": "projects/sso/",
"sourceRoot": "projects/sso/src",
"projectType": "application",
"prefix": "sso",
"schematics": {
"@schematics/angular:component": {
"styleext": "scss",
"spec": false
},
"@schematics/angular:class": {
"spec": false
},
"@schematics/angular:directive": {
"spec": false
},
"@schematics/angular:guard": {
"spec": false
},
"@schematics/angular:module": {
"spec": false
},
"@schematics/angular:pipe": {
"spec": false
},
"@schematics/angular:service": {
"spec": false
}
},
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/sso",
"index": "projects/sso/src/index.html",
"main": "projects/sso/src/main.ts",
"polyfills": "projects/sso/src/polyfills.ts",
"tsConfig": "projects/sso/tsconfig.app.json",
"assets": [
"projects/sso/src/favicon.ico",
"projects/sso/src/assets"
],
"styles": [
"src/styles.scss",
"src/theme.scss"
],
"stylePreprocessorOptions": {
"includePaths": [
"./src/stylesheets"
]
},
"scripts": []
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "projects/sso/src/environments/environment.ts",
"with": "projects/sso/src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
}
]
},
"test": {
"fileReplacements": [
{
"replace": "projects/market/src/environments/environment.ts",
"with": "projects/market/src/environments/environment.test.ts"
}
]
},
"development": {
"fileReplacements": [
{
"replace": "projects/market/src/environments/environment.ts",
"with": "projects/market/src/environments/environment.dev.ts"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "sso:build"
},
"configurations": {
"production": {
"browserTarget": "sso:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "sso:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/sso/src/test.ts",
"polyfills": "projects/sso/src/polyfills.ts",
"tsConfig": "projects/sso/tsconfig.spec.json",
"karmaConfig": "projects/sso/karma.conf.js",
"styles": [
"src/styles.scss",
"src/theme.scss"
],
"stylePreprocessorOptions": {
"includePaths": [
"./src/stylesheets"
]
},
"scripts": [],
"assets": [
"projects/sso/src/favicon.ico",
"projects/sso/src/assets"
]
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"projects/sso/tsconfig.app.json",
"projects/sso/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"sso-e2e": {
"root": "projects/sso-e2e/",
"projectType": "application",
"prefix": "",
"architect": {
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "projects/sso-e2e/protractor.conf.js",
"devServerTarget": "sso:serve"
},
"configurations": {
"production": {
"devServerTarget": "sso:serve:production"
}
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": "projects/sso-e2e/tsconfig.e2e.json",
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"globalnav": {
"root": "projects/globalnav",
"sourceRoot": "projects/globalnav/src",
"projectType": "library",
"prefix": "globalnav",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "projects/globalnav/tsconfig.lib.json",
"project": "projects/globalnav/ng-package.json"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/globalnav/src/test.ts",
"tsConfig": "projects/globalnav/tsconfig.spec.json",
"karmaConfig": "projects/globalnav/karma.conf.js"
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"projects/globalnav/tsconfig.lib.json",
"projects/globalnav/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"account": {
"root": "projects/account/",
"sourceRoot": "projects/account/src",
"projectType": "application",
"prefix": "account",
"schematics": {
"@schematics/angular:component": {
"styleext": "scss",
"spec": false
},
"@schematics/angular:class": {
"spec": false
},
"@schematics/angular:directive": {
"spec": false
},
"@schematics/angular:guard": {
"spec": false
},
"@schematics/angular:module": {
"spec": false
},
"@schematics/angular:pipe": {
"spec": false
},
"@schematics/angular:service": {
"spec": false
}
},
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/account",
"index": "projects/account/src/index.html",
"main": "projects/account/src/main.ts",
"polyfills": "projects/account/src/polyfills.ts",
"tsConfig": "projects/account/tsconfig.app.json",
"assets": [
"projects/account/src/favicon.ico",
"projects/account/src/assets"
],
"styles": [
"src/styles.scss",
"src/theme.scss"
],
"stylePreprocessorOptions": {
"includePaths": [
"./src/stylesheets"
]
},
"scripts": []
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "projects/account/src/environments/environment.ts",
"with": "projects/account/src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "account:build"
},
"configurations": {
"production": {
"browserTarget": "account:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "account:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/account/src/test.ts",
"polyfills": "projects/account/src/polyfills.ts",
"tsConfig": "projects/account/tsconfig.spec.json",
"karmaConfig": "projects/account/karma.conf.js",
"styles": [
"src/styles.scss",
"src/theme.scss"
],
"stylePreprocessorOptions": {
"includePaths": [
"./src/stylesheets"
]
},
"scripts": [],
"assets": [
"projects/account/src/favicon.ico",
"projects/account/src/assets"
]
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"projects/account/tsconfig.app.json",
"projects/account/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"account-e2e": {
"root": "projects/account-e2e/",
"projectType": "application",
"prefix": "",
"architect": {
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "projects/account-e2e/protractor.conf.js",
"devServerTarget": "account:serve"
},
"configurations": {
"production": {
"devServerTarget": "account:serve:production"
}
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": "projects/account-e2e/tsconfig.e2e.json",
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"page-not-found": {
"root": "projects/page-not-found",
"sourceRoot": "projects/page-not-found/src",
"projectType": "library",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "projects/page-not-found/tsconfig.lib.json",
"project": "projects/page-not-found/ng-package.json"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/page-not-found/src/test.ts",
"tsConfig": "projects/page-not-found/tsconfig.spec.json",
"karmaConfig": "projects/page-not-found/karma.conf.js"
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"projects/page-not-found/tsconfig.lib.json",
"projects/page-not-found/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
}
},
"defaultProject": "internet"
}

28
e2e/protractor.conf.js Normal file
View File

@ -0,0 +1,28 @@
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./src/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: require('path').join(__dirname, './tsconfig.e2e.json')
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};

14
e2e/src/app.e2e-spec.ts Normal file
View File

@ -0,0 +1,14 @@
import { AppPage } from './app.po';
describe('workspace-project App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('Welcome to internet!');
});
});

11
e2e/src/app.po.ts Normal file
View File

@ -0,0 +1,11 @@
import { browser, by, element } from 'protractor';
export class AppPage {
navigateTo() {
return browser.get('/');
}
getParagraphText() {
return element(by.css('app-root h1')).getText();
}
}

13
e2e/tsconfig.e2e.json Normal file
View File

@ -0,0 +1,13 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}

11516
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

64
package.json Normal file
View File

@ -0,0 +1,64 @@
{
"name": "internet",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"build-dev": "ng build --configuration=development",
"build-test": "ng build --configuration=test",
"build-prod": "ng build --prod",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "~7.0.0",
"@angular/cdk": "^7.0.1",
"@angular/common": "~7.0.0",
"@angular/compiler": "~7.0.0",
"@angular/core": "~7.0.0",
"@angular/flex-layout": "^7.0.0-beta.19",
"@angular/forms": "~7.0.0",
"@angular/http": "~7.0.0",
"@angular/material": "^7.0.1",
"@angular/platform-browser": "~7.0.0",
"@angular/platform-browser-dynamic": "~7.0.0",
"@angular/router": "~7.0.0",
"@fortawesome/angular-fontawesome": "^0.3.0",
"@fortawesome/fontawesome-svg-core": "^1.2.7",
"@fortawesome/free-brands-svg-icons": "^5.4.2",
"@fortawesome/free-solid-svg-icons": "^5.4.2",
"angular-font-awesome": "^3.1.2",
"core-js": "^2.5.4",
"font-awesome": "^4.7.0",
"rxjs": "~6.3.3",
"zone.js": "~0.8.26"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.10.0",
"@angular-devkit/build-ng-packagr": "~0.10.0",
"@angular/cli": "~7.0.3",
"@angular/compiler-cli": "~7.0.0",
"@angular/language-service": "~7.0.0",
"@types/node": "~8.9.4",
"@types/jasmine": "~2.8.8",
"@types/jasminewd2": "~2.0.3",
"codelyzer": "~4.5.0",
"jasmine-core": "~2.99.1",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~3.0.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~1.1.2",
"karma-jasmine-html-reporter": "^0.2.2",
"ng-packagr": "^4.2.0",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",
"tsickle": ">=0.29.0",
"tslib": "^1.9.0",
"tslint": "~5.11.0",
"typescript": "~3.1.1"
}
}

View File

@ -0,0 +1,11 @@
# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
#
# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11

View File

@ -0,0 +1,31 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require('path').join(__dirname, '../../coverage'),
reports: ['html', 'lcovonly'],
fixWebpackSourcePaths: true
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};

View File

@ -0,0 +1,8 @@
{
"/api/*": {
"target": "http://localhost:5003",
"secure": false,
"logLevel": "debug",
"changeOrigin": true
}
}

View File

@ -0,0 +1,22 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { DeviceComponent } from './device/device.component';
import { PageNotFoundComponent } from 'page-not-found';
import { ProfileComponent } from './profile/profile.component';
// import { SkillComponent } from './skill/skill.component';
const routes: Routes = [
{ path: 'device', component: DeviceComponent },
{ path: 'profile', component: ProfileComponent },
// { path: 'skill', component: ProfileComponent },
{ path: '', redirectTo: '/profile', pathMatch: 'full' },
{ path: '**', component: PageNotFoundComponent }
];
@NgModule({
imports: [ RouterModule.forRoot(routes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule {
}

View File

@ -0,0 +1,12 @@
<globalnav-sidenav
[mycroftUrls]="environment.mycroftUrls"
[user$]="user$"
>
<!--
Inject the marketplace app into the <mat-sidenav-content> component
of the global navigation menu library.
-->
<div appBody id="account-body">
<router-outlet></router-outlet>
</div>
</globalnav-sidenav>

View File

@ -0,0 +1,14 @@
import { Component } from '@angular/core';
import { environment } from '../environments/environment';
@Component({
selector: 'account-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
public environment = environment;
title = 'account';
}

View File

@ -0,0 +1,31 @@
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { GlobalnavModule } from 'globalnav';
import { PageNotFoundModule } from 'page-not-found';
import { DeviceModule } from './device/device.module';
import { ProfileModule } from './profile/profile.module';
@NgModule(
{
// declarations: [ AppComponent, PageNotFoundComponent ],
declarations: [ AppComponent ],
imports: [
BrowserModule,
BrowserAnimationsModule,
GlobalnavModule,
HttpClientModule,
DeviceModule,
PageNotFoundModule,
ProfileModule,
AppRoutingModule
],
providers: [ ],
bootstrap: [ AppComponent ]
}
)
export class AppModule { }

View File

@ -0,0 +1,39 @@
<div mat-dialog-title class="mat-h2-primary">{{dialogTitle}}</div>
<div mat-dialog-content>
<div class="mat-body">{{dialogInstructions}}</div>
<mat-radio-group fxLayout="column" [(ngModel)]="dialogData">
<ng-container *ngFor="let possibleValue of possibleValues">
<!-- Radio buttons for pre-defined placements -->
<mat-radio-button *ngIf="possibleValue.preDefined" class="predefined-group" [value]="possibleValue.name">
{{possibleValue.name}}
</mat-radio-button>
<!-- Radio buttons for user-defined placements -->
<div *ngIf="!possibleValue.preDefined" fxLayout="row" fxLayoutAlign="space-between center">
<mat-radio-button [value]="possibleValue.name">
<mat-form-field [floatLabel]="'never'">
<input matInput class="user-defined-group" value="{{possibleValue.name}}">
</mat-form-field>
</mat-radio-button>
<button mat-icon-button [disableRipple]="true">
<fa-icon [icon]="deleteIcon"></fa-icon>
</button>
</div>
</ng-container>
<!-- Radio button to add a new user-defined group -->
<mat-radio-button>
<mat-form-field [floatLabel]="'never'">
<input matInput placeholder="Add {{dialogTitle}}">
</mat-form-field>
</mat-radio-button>
</mat-radio-group>
</div>
<div mat-dialog-actions align="end">
<button mat-button (click)="onCancelClick()">CANCEL</button>
<button mat-button class="attribute-save-button" [mat-dialog-close]="dialogData">SAVE</button>
</div>

View File

@ -0,0 +1,22 @@
@import '~@angular/material/theming';
@import '~src/stylesheets/mycroft-colors';
@import '~src/stylesheets/components/buttons';
.predefined-group {
margin-bottom: 12px;
margin-top: 12px;
}
.mat-body{
margin-bottom: 16px;
width: 250px;
}
fa-icon {
color: mat-color($mycroft-warn);
margin-left: 16px;
}
.attribute-save-button {
@include action-button-primary;
}

View File

@ -0,0 +1,34 @@
import {Component, Input, OnInit} from '@angular/core';
import { MatDialogRef } from '@angular/material';
import { faTrashAlt } from '@fortawesome/free-solid-svg-icons';
import { DeviceAttribute } from '../device.service';
import { GeographyEditComponent } from './geography/geography-edit.component';
import { GroupEditComponent } from './group/group-edit.component';
import { PlacementEditComponent } from './placement/placement-edit.component';
@Component({
selector: 'account-device-attribute-edit',
templateUrl: './attr-edit.component.html',
styleUrls: ['./attr-edit.component.scss']
})
export class AttrEditComponent implements OnInit {
@Input() dialogData: string;
@Input() dialogInstructions: string;
@Input() dialogRef: MatDialogRef<GeographyEditComponent | GroupEditComponent | PlacementEditComponent>;
@Input() dialogTitle: string;
@Input() possibleValues: DeviceAttribute[];
public deleteIcon = faTrashAlt;
constructor() {
}
ngOnInit() {
}
onCancelClick(): void {
this.dialogRef.close();
}
}

View File

@ -0,0 +1,13 @@
<mat-form-field [appearance]="'outline'" (click)="onClick()">
<mat-label>{{label}}</mat-label>
<div fxLayout="row" fxLayoutAlign="none center">
<input
matInput
[readonly]="true"
type="text"
value="{{value.name}}"
>
<fa-icon matSuffix [icon]="editIcon" style="font-size: 16px;"></fa-icon>
</div>
<mat-hint>{{hint}}</mat-hint>
</mat-form-field>

View File

@ -0,0 +1,9 @@
mat-form-field {
margin-bottom: 20px;
width: 100%;
}
fa-icon {
padding-right: 10px
}

View File

@ -0,0 +1,43 @@
import { Component, Input, OnInit } from '@angular/core';
import { MatDialog } from '@angular/material';
import { faCaretRight } from '@fortawesome/free-solid-svg-icons';
@Component({
selector: 'account-device-attribute-view',
templateUrl: './attr-view.component.html',
styleUrls: ['./attr-view.component.scss']
})
export class AttrViewComponent implements OnInit {
@Input() editDialog: any;
@Input() hint: string;
@Input() label: string;
@Input() possibleValues: any[];
@Input() value: any;
public editIcon = faCaretRight;
constructor(private dialog: MatDialog) {
}
ngOnInit() {
}
onClick() {
const dialogRef = this.dialog.open(this.editDialog, { data: this.value.name });
dialogRef.afterClosed().subscribe(
(result) => { this.updateDevice(result); }
);
}
updateDevice(newValue: string) {
if (newValue) {
this.possibleValues.forEach(
(value) => {
if (value.name === newValue) {
this.value = value;
}
}
);
}
}
}

View File

@ -0,0 +1,43 @@
<account-device-attribute-edit
[dialogData]="data"
[dialogInstructions]="dialogInstructions"
[dialogRef]="dialogRef"
[dialogTitle]="'Geography'"
[possibleValues]="deviceGeographies"
>
</account-device-attribute-edit>
<!--<div mat-dialog-title class="mat-h2-primary">Geography</div>-->
<!--<div mat-dialog-content>-->
<!--<div class="mat-body">-->
<!--Groups are useful to organize multiple devices. You can reuse device names if they are in different groups.-->
<!--</div>-->
<!--<mat-radio-group fxLayout="column" [(ngModel)]="data">-->
<!--<ng-container *ngFor="let geo of deviceGeographies">-->
<!--&lt;!&ndash; Radio buttons for user-defined groups &ndash;&gt;-->
<!--<div fxLayout="row" fxLayoutAlign="space-between center">-->
<!--<mat-radio-button [value]="geo.name">-->
<!--<mat-form-field [floatLabel]="'never'">-->
<!--<input matInput value="{{geo.name}}">-->
<!--</mat-form-field>-->
<!--</mat-radio-button>-->
<!--<button mat-icon-button [disableRipple]="true">-->
<!--<fa-icon class="danger-icon" [icon]="deleteIcon"></fa-icon>-->
<!--</button>-->
<!--</div>-->
<!--</ng-container>-->
<!--&lt;!&ndash; Radio button to add a new user-defined group &ndash;&gt;-->
<!--<mat-radio-button>-->
<!--<mat-form-field [floatLabel]="'never'">-->
<!--<input matInput placeholder="Add Geographic Location">-->
<!--</mat-form-field>-->
<!--</mat-radio-button>-->
<!--</mat-radio-group>-->
<!--</div>-->
<!--<div mat-dialog-actions align="end">-->
<!--<button mat-button (click)="onCancelClick()">CANCEL</button>-->
<!--<button mat-button [mat-dialog-close]="data" class="action-button">SAVE</button>-->
<!--</div>-->

View File

@ -0,0 +1,25 @@
import { Component, Inject, OnInit } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { DeviceAttribute, DeviceService} from '../../device.service';
@Component({
selector: 'account-device-geography-edit',
templateUrl: './geography-edit.component.html',
styleUrls: ['./geography-edit.component.scss']
})
export class GeographyEditComponent implements OnInit {
public deviceGeographies: DeviceAttribute[];
public dialogInstructions = '';
constructor(
private deviceService: DeviceService,
public dialogRef: MatDialogRef<GeographyEditComponent>,
@Inject(MAT_DIALOG_DATA) public data: string) {
}
ngOnInit() {
this.deviceGeographies = this.deviceService.deviceGeographies;
}
}

View File

@ -0,0 +1,9 @@
<account-device-attribute-view
[editDialog]="dialog"
[hint]="'Country, postal code, time zone'"
[label]="'Geography'"
[possibleValues]="deviceGeographies"
[value]="device.location"
>
</account-device-attribute-view>

View File

@ -0,0 +1,22 @@
import { Component, Input, OnInit } from '@angular/core';
import { Device, DeviceAttribute, DeviceService } from '../../device.service';
import { GeographyEditComponent } from './geography-edit.component';
@Component({
selector: 'account-device-geography-view',
templateUrl: './geography-view.component.html',
styleUrls: ['./geography-view.component.scss']
})
export class GeographyViewComponent implements OnInit {
@Input() device: Device;
public deviceGeographies: DeviceAttribute[];
public dialog = GeographyEditComponent;
constructor( private service: DeviceService) {
}
ngOnInit() {
this.deviceGeographies = this.service.deviceGeographies;
}
}

View File

@ -0,0 +1,8 @@
<account-device-attribute-edit
[dialogData]="data"
[dialogInstructions]="dialogInstructions"
[dialogRef]="dialogRef"
[dialogTitle]="'Group'"
[possibleValues]="deviceGroups"
>
</account-device-attribute-edit>

View File

@ -0,0 +1,25 @@
import { Component, Inject, OnInit } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { DeviceAttribute, DeviceService} from '../../device.service';
@Component({
selector: 'account-device-group-edit',
templateUrl: './group-edit.component.html',
styleUrls: ['./group-edit.component.scss']
})
export class GroupEditComponent implements OnInit {
public deviceGroups: DeviceAttribute[];
public dialogInstructions = 'Groups are useful to organize multiple ' +
'devices. You can reuse device names if they are in different groups.';
constructor(
private deviceService: DeviceService,
public dialogRef: MatDialogRef<GroupEditComponent>,
@Inject(MAT_DIALOG_DATA) public data: DeviceAttribute) {
}
ngOnInit() {
this.deviceGroups = this.deviceService.deviceGroups;
}
}

View File

@ -0,0 +1,9 @@
<account-device-attribute-view
[editDialog]="dialog"
[hint]="'Mechanism to categorize devices'"
[label]="'Group'"
[possibleValues]="deviceGroups"
[value]="device.group"
>
</account-device-attribute-view>

View File

@ -0,0 +1,22 @@
import { Component, Input, OnInit } from '@angular/core';
import { Device, DeviceAttribute, DeviceService } from '../../device.service';
import { GroupEditComponent } from './group-edit.component';
@Component({
selector: 'account-device-group-view',
templateUrl: './group-view.component.html',
styleUrls: ['./group-view.component.scss']
})
export class GroupViewComponent implements OnInit {
@Input() device: Device;
public deviceGroups: DeviceAttribute[];
public dialog = GroupEditComponent;
constructor( private service: DeviceService) {
}
ngOnInit() {
this.deviceGroups = this.service.deviceGroups;
}
}

View File

@ -0,0 +1,8 @@
<account-device-attribute-edit
[dialogData]="data"
[dialogInstructions]="dialogInstructions"
[dialogRef]="dialogRef"
[dialogTitle]="'Placement'"
[possibleValues]="devicePlacements"
>
</account-device-attribute-edit>

View File

@ -0,0 +1,26 @@
import { Component, Inject, OnInit } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { DeviceAttribute, DeviceService} from '../../device.service';
@Component({
selector: 'account-device-placement-edit',
templateUrl: './placement-edit.component.html',
styleUrls: ['./placement-edit.component.scss']
})
export class PlacementEditComponent implements OnInit {
public devicePlacements: DeviceAttribute[];
public dialogInstructions = 'You can optionally indicate where a device is ' +
'placed within a location. Field is informational only.';
constructor(
private deviceService: DeviceService,
public dialogRef: MatDialogRef<PlacementEditComponent>,
@Inject(MAT_DIALOG_DATA) public data: string) {
}
ngOnInit() {
this.devicePlacements = this.deviceService.devicePlacements;
}
}

View File

@ -0,0 +1,9 @@
<account-device-attribute-view
[editDialog]="dialog"
[hint]="'Where a device is placed within a location'"
[label]="'Placement'"
[possibleValues]="devicePlacements"
[value]="device.placement"
>
</account-device-attribute-view>

View File

@ -0,0 +1,22 @@
import { Component, Input, OnInit } from '@angular/core';
import {Device, DeviceAttribute, DeviceService} from '../../device.service';
import { PlacementEditComponent } from './placement-edit.component';
@Component({
selector: 'account-device-placement-view',
templateUrl: './placement-view.component.html',
styleUrls: ['./placement-view.component.scss']
})
export class PlacementViewComponent implements OnInit {
@Input() device: Device;
public devicePlacements: DeviceAttribute[];
public dialog = PlacementEditComponent;
constructor( private service: DeviceService) {
}
ngOnInit() {
this.devicePlacements = this.service.devicePlacements;
}
}

View File

@ -0,0 +1,62 @@
<div class="app-body">
<!-- Button for adding a new device centered at top of page-->
<div fxLayout="row" fxLayoutAlign="center">
<button fxFlex mat-flat-button class="action-button">
<div fxLayout="row" fxLayoutAlign="space-between">
<span class="mat-h2">ADD DEVICE</span>
<fa-icon [icon]="addIcon"></fa-icon>
</div>
</button>
</div>
<!-- Device listing - show summary in expansion panel header and editable fields in expansion panel detail -->
<div fxLayout="row wrap" fxLayoutAlign="start start">
<mat-expansion-panel *ngFor="let device of devices">
<!-- Put the platform icon, device name and device placement in the panel header -->
<mat-expansion-panel-header fxLayout="row" fxLayoutAlign="start center" [expandedHeight]="'100px'" [collapsedHeight]="'100px'">
<img [src]="getDeviceIcon(device)"/>
<div>
<div class="mat-h2-primary">{{device.name}}</div>
<div class="mat-subheader">{{device.placement.name}}</div>
</div>
</mat-expansion-panel-header>
<!-- Navigation to skill settings for this device. -->
<button mat-flat-button color="primary" class="settings-button">
<fa-icon [icon]="settingsIcon"></fa-icon>
SKILL SETTINGS
</button>
<mat-form-field [appearance]="'outline'">
<mat-label>Name</mat-label>
<input
id="deviceName"
matInput
name="deviceName"
required
type="text"
value="{{device.name}}"
>
<mat-hint>Must be unique within a device group (if defined)</mat-hint>
</mat-form-field>
<account-device-group-view [device]="device"></account-device-group-view>
<account-device-geography-view [device]="device"></account-device-geography-view>
<account-device-placement-view [device]="device"></account-device-placement-view>
<!-- Static fields that display platform, software version and hardware version -->
<div *ngFor="let staticData of defineStaticDeviceFields(device)">
<span class="mat-body">{{staticData.name}}:&nbsp;&nbsp;</span>
<span class="mat-body-primary">{{staticData.value}}</span>
</div>
<!-- Last but not least, the delete device button -->
<button mat-flat-button color="warn" class="delete-button" (click)="onRemovalClick(device)">
<fa-icon [icon]="deleteIcon"></fa-icon>
REMOVE DEVICE
</button>
</mat-expansion-panel>
</div>
</div>

View File

@ -0,0 +1,61 @@
.action-button {
border-radius: 12px;
height: 100px;
margin-bottom: 20px;
max-width: 350px;
min-width: 250px;
.mat-h2 {
margin-bottom: 0;
}
fa-icon {
color: yellow;
font-size: 28px;
}
}
mat-expansion-panel {
border-radius: 12px;
margin: 10px;
max-width: 350px;
min-width: 250px;
button {
width: 100%;
}
fa-icon {
padding-right: 10px
}
img {
height: 60px;
padding-right: 10px;
}
mat-form-field {
margin-bottom: 20px;
width: 100%;
}
.delete-button {
margin-top: 20px;
}
.mat-body-primary {
margin-bottom: 0;
}
.mat-h2-primary {
margin-bottom: 0;
}
.mat-subheader {
padding: 0;
}
.settings-button {
margin-bottom: 20px;
}
}

View File

@ -0,0 +1,57 @@
import { Component, OnInit } from '@angular/core';
import { MatDialog } from '@angular/material';
import { faCogs, faPlusCircle, faTrash } from '@fortawesome/free-solid-svg-icons';
import { DeviceService, Device } from './device.service';
import { RemoveComponent } from './remove/remove.component';
@Component({
selector: 'account-device',
templateUrl: './device.component.html',
styleUrls: ['./device.component.scss']
})
export class DeviceComponent implements OnInit {
public addIcon = faPlusCircle;
public deleteIcon = faTrash;
public devices: Device[];
public platforms = {
'mark-one': {icon: '../assets/mark-1-icon.svg', displayName: 'Mark I'},
'mark-two': {icon: '../assets/mark-2-icon.svg', displayName: 'Mark II'},
'picroft': {icon: '../assets/picroft-icon.svg', displayName: 'Picroft'},
'kde': {icon: '../assets/kde-icon.svg', displayName: 'KDE'}
};
public settingsIcon = faCogs;
private selectedDevice: Device;
constructor(public dialog: MatDialog, private deviceService: DeviceService) { }
ngOnInit() {
this.devices = this.deviceService.devices;
}
onRemovalClick (device: Device) {
const removalDialogRef = this.dialog.open(RemoveComponent, {data: false});
this.selectedDevice = device;
removalDialogRef.afterClosed().subscribe(
(result) => {
if (result) { this.deviceService.deleteDevice(device); }
}
);
}
defineStaticDeviceFields(device: Device) {
const knownPlatform = this.platforms[device.platform];
return [
{name: 'Platform', value: knownPlatform ? knownPlatform.displayName : device.platform},
{name: 'Core Version', value: device.coreVersion},
{name: 'Enclosure Version', value: device.enclosureVersion}
];
}
getDeviceIcon(device: Device) {
const knownPlatform = this.platforms[device.platform];
// TODO: get unknown product icon from design team.
return knownPlatform ? knownPlatform.icon : '../assets/mark-1-icon.svg';
}
}

View File

@ -0,0 +1,71 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DragDropModule } from '@angular/cdk/drag-drop';
import { FlexLayoutModule } from '@angular/flex-layout';
import { FormsModule } from '@angular/forms';
import {
MatButtonModule,
MatCardModule,
MatCheckboxModule,
MatDialogModule,
MatExpansionModule,
MatFormFieldModule,
MatInputModule,
MatRadioModule,
MatSelectModule,
} from '@angular/material';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { AttrEditComponent } from './attribute/attr-edit.component';
import { AttrViewComponent } from './attribute/attr-view.component';
import { DeviceComponent } from './device.component';
import { DeviceService } from './device.service';
import { GeographyEditComponent } from './attribute/geography/geography-edit.component';
import { GeographyViewComponent } from './attribute/geography/geography-view.component';
import { GroupEditComponent } from './attribute/group/group-edit.component';
import { GroupViewComponent } from './attribute/group/group-view.component';
import { PlacementEditComponent } from './attribute/placement/placement-edit.component';
import { PlacementViewComponent } from './attribute/placement/placement-view.component';
import { RemoveComponent } from './remove/remove.component';
@NgModule({
declarations: [
AttrEditComponent,
AttrViewComponent,
DeviceComponent,
GeographyEditComponent,
GeographyViewComponent,
GroupEditComponent,
GroupViewComponent,
PlacementEditComponent,
PlacementViewComponent,
RemoveComponent
],
entryComponents: [
GeographyEditComponent,
GroupEditComponent,
PlacementEditComponent,
RemoveComponent
],
imports: [
CommonModule,
DragDropModule,
FlexLayoutModule,
FontAwesomeModule,
FormsModule,
MatButtonModule,
MatCardModule,
MatCheckboxModule,
MatDialogModule,
MatExpansionModule,
MatFormFieldModule,
MatInputModule,
MatRadioModule,
MatSelectModule,
],
providers: [
DeviceService
]
})
export class DeviceModule { }

View File

@ -0,0 +1,91 @@
import { Injectable } from '@angular/core';
export interface DeviceAttribute {
id?: string;
name: string;
preDefined: boolean;
}
export interface Device {
coreVersion: string;
enclosureVersion: string;
group: DeviceAttribute;
id: string;
location: DeviceAttribute;
name: string;
placement: DeviceAttribute;
platform: string;
}
@Injectable({
providedIn: 'root'
})
export class DeviceService {
public devices: Device[] = [
{
coreVersion: '18.08',
enclosureVersion: '1.2.3',
group: {id: '1', name: 'None', preDefined: true},
id: 'abc-def-ghi',
location: {id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST', preDefined: false},
name: 'Mark',
placement: {id: 'bbb-bbb-bbb', name: 'Living Room', preDefined: false},
platform: 'mark-one'
},
{
coreVersion: '18.08',
enclosureVersion: '1.2.3',
group: {id: '1', name: 'None', preDefined: true},
id: 'bcd-efg-hij',
location: {id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST', preDefined: false},
name: 'Marky Mark',
placement: {id: 'bbb-bbb-bbb', name: 'Kitchen', preDefined: true},
platform: 'mark-two'
},
{
coreVersion: '18.08',
enclosureVersion: '1.2.3',
group: {id: '2', name: 'Parent House', preDefined: false},
id: 'cde-fgh-ijk',
location: {id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST', preDefined: false},
name: 'American Pie',
placement: {id: 'ddd-ddd-ddd', name: 'Bedroom', preDefined: true},
platform: 'picroft'
},
{
coreVersion: '18.08',
enclosureVersion: '1.2.3',
group: {id: '2', name: 'Parent House', preDefined: false},
id: 'def-ghi-jkl',
location: {id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST', preDefined: false},
name: 'Kappa Delta Epsilon',
placement: {id: 'fff-fff-fff', name: 'Kitchen', preDefined: true},
platform: 'kde'
}
];
public deviceGroups: DeviceAttribute[] = [
{ id: '1', name: 'None', preDefined: true},
{ id: null, name: 'Home', preDefined: true},
{ id: null, name: 'Office', preDefined: true},
{ id: '2', name: 'Parent House', preDefined: false}
];
public devicePlacements: DeviceAttribute[] = [
{ id: '1', name: 'None', preDefined: true},
{ id: null, name: 'Bedroom', preDefined: true},
{ id: null, name: 'Kitchen', preDefined: true},
{ id: '2', name: 'Living Room', preDefined: false}
];
public deviceGeographies: DeviceAttribute[] = [
{id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST', preDefined: false},
{id: 'a1b2-c3d4-e5f6', name: 'United Kingdom, ABCDE, BST', preDefined: false}
];
constructor() { }
deleteDevice(device: Device): void {
console.log('deleting device... ');
}
}

View File

@ -0,0 +1,12 @@
<div mat-dialog-title class="mat-h2-primary">Remove Device</div>
<div mat-dialog-content>
<div class="mat-body">
Just double checking. Device removal cannot be undone.
</div>
</div>
<div mat-dialog-actions align="end">
<button id="device-remove-cancel-button" mat-button (click)="onCancelClick()">CANCEL</button>
<button id="device-remove-button" mat-button [mat-dialog-close]="true">REMOVE</button>
</div>

View File

@ -0,0 +1,10 @@
@import '~src/stylesheets/components/buttons';
.mat-body{
margin-bottom: 16px;
width: 250px;
}
#device-remove-button {
@include action-button-warn;
}

View File

@ -0,0 +1,22 @@
import {Component, Inject, OnInit} from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
@Component({
selector: 'account-device-remove',
templateUrl: './remove.component.html',
styleUrls: ['./remove.component.scss']
})
export class RemoveComponent implements OnInit {
constructor(
public dialogRef: MatDialogRef<RemoveComponent>,
@Inject(MAT_DIALOG_DATA) public data: boolean) {
}
ngOnInit() {
}
onCancelClick(): void {
this.dialogRef.close();
}
}

View File

@ -0,0 +1,47 @@
<mat-card class="section-card">
<mat-toolbar class="section-card-title-bar">
<div class="section-card-title">Agreements</div>
</mat-toolbar>
<div id="agreement-panels">
<mat-accordion>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
Terms of Use
</mat-panel-title>
<mat-panel-description>
Accepted July 10, 2018
</mat-panel-description>
</mat-expansion-panel-header>
Terms of Use goes here.
</mat-expansion-panel>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
Privacy Policy
</mat-panel-title>
<mat-panel-description>
Accepted July 10, 2018
</mat-panel-description>
</mat-expansion-panel-header>
Privacy Policy goes here.
</mat-expansion-panel>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
Open Data Set
</mat-panel-title>
<mat-panel-description>
Opted In July 10, 2018
</mat-panel-description>
</mat-expansion-panel-header>
Open Data Set agreement goes here.
<mat-action-row>
<button mat-button>OPT OUT</button>
</mat-action-row>
</mat-expansion-panel>
</mat-accordion>
</div>
</mat-card>

View File

@ -0,0 +1,3 @@
#agreement-panels {
margin: 8px;
}

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'account-agreements',
templateUrl: './agreements.component.html',
styleUrls: ['./agreements.component.scss']
})
export class AgreementsComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}

View File

@ -0,0 +1,12 @@
<mat-card class="section-card">
<mat-toolbar class="section-card-title-bar">
<div class="section-card-title">Delete Account</div>
</mat-toolbar>
<div fxLayout="column">
<span class="mat-h3">CAUTION</span>
<div id="delete-warning">
<div *ngFor="let paragraph of deleteWarning" class="mat-body-2">{{paragraph}}</div>
</div>
<button mat-raised-button color="warn">DELETE ACCOUNT</button>
</div>
</mat-card>

View File

@ -0,0 +1,21 @@
mat-card {
button {
color: white;
margin-bottom: 10px;
margin-left: auto;
margin-right: auto;
}
#delete-warning {
margin-bottom: 24px;
.mat-body-2 {
text-align: center;
}
}
.mat-h3 {
text-align: center;
font-weight: bold;
}
}

View File

@ -0,0 +1,20 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'account-delete',
templateUrl: './delete.component.html',
styleUrls: ['./delete.component.scss']
})
export class DeleteComponent implements OnInit {
public deleteWarning: string[];
constructor() { }
ngOnInit() {
this.deleteWarning = [
'Pressing the button below will delete your account and all data related to it from Mycroft servers.',
'It cannot be undone.'
];
}
}

View File

@ -0,0 +1,44 @@
<mat-card class="section-card">
<mat-toolbar class="section-card-title-bar">
<div class="section-card-title">Login</div>
</mat-toolbar>
<div fxLayout="row wrap" fxLayoutAlign="space-around">
<div id="antisocial-login" fxFlex fxLayout="column" fxLayoutAlign="start stretch">
<mat-form-field appearance="outline">
<mat-label>Email Address</mat-label>
<input
id="emailAddress"
matInput
name="emailAddress"
placeholder="Enter Email Address"
required
type="email"
>
<mat-hint>Uniquely identifies your account</mat-hint>
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Password</mat-label>
<input
id="password"
matInput
name="password"
placeholder="Enter a Secure Password"
type="password"
>
<mat-hint>Required when no external account is linked</mat-hint>
</mat-form-field>
</div>
<div id="social-login" fxFlex fxLayout="column">
<div class="mat-subheading-2">Social Login</div>
<div class="mat-body">Connect to a platform for faster login.</div>
<div id="social-platform" *ngFor="let platform of socialPlatforms" fxLayout="row" fxLayoutAlign="start center">
<div fxLayout="row" fxLayoutAlign="start center">
<img *ngIf="platform.image" [src]="platform.image"/>
<fa-icon *ngIf="platform.icon" [icon]="platform.icon"></fa-icon>
<mat-label>{{platform.label}}</mat-label>
</div>
<button mat-flat-button class="action-button">CONNECT</button>
</div>
</div>
</div>
</mat-card>

View File

@ -0,0 +1,40 @@
#antisocial-login {
margin: 16px;
mat-form-field {
max-width: 350px;
}
}
#social-login {
margin: 16px;
.mat-subheading-2 {
font-weight: bold;
margin: 0;
}
#social-platform {
margin: 8px;
fa-icon {
font-size: 30px;
margin-right: 10px;
}
img {
height: 30px;
margin-right: 10px;
width: 30px;
}
mat-label {
color: rgba(0, 0, 0, 0.6);
width: 100px;
}
}
}

View File

@ -0,0 +1,38 @@
import { Component, OnInit } from '@angular/core';
import { faGithub, IconDefinition } from '@fortawesome/free-brands-svg-icons';
export interface ToggleLabel {
label: string;
image?: string;
icon?: IconDefinition;
}
@Component({
selector: 'account-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
public socialPlatforms: ToggleLabel[];
constructor() { }
ngOnInit() {
const githubLabel: ToggleLabel = {
label: 'GitHub',
icon: faGithub
};
const googleLabel: ToggleLabel = {
label: 'Google',
image: '../../assets/google-logo.png'
};
const facebookLabel: ToggleLabel = {
label: 'Facebook',
image: '../../assets/facebook_logo.png'
};
this.socialPlatforms = [googleLabel, facebookLabel, githubLabel];
}
}

View File

@ -0,0 +1,68 @@
<mat-card class="section-card">
<mat-toolbar class="section-card-title-bar">
<div class="section-card-title">PERSONAL</div>
</mat-toolbar>
<form>
<div fxLayout="row wrap">
<!-- first and last name fields go on left when screen is large enough -->
<div id="user-name" fxFlex fxLayout="column">
<mat-form-field appearance="outline">
<mat-label>First Name</mat-label>
<input
id="firstName2"
matInput
name="lastName"
placeholder="Enter First Name"
type="text"
>
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Last Name</mat-label>
<input
id="lastName2"
matInput
name="lastName"
placeholder="Enter Last Name"
type="text"
>
</mat-form-field>
</div>
<!-- location fields go on right when screen is large enough -->
<div id="user-location" fxFlex fxLayout="column">
<mat-form-field appearance=outline>
<mat-label>Country</mat-label>
<mat-select>
<mat-option value="option1">Option 1</mat-option>
<mat-option value="option2" disabled>Option 2 (disabled)</mat-option>
<mat-option value="option3">Option 3</mat-option>
</mat-select>
<mat-hint>Filter for postal code and time zone</mat-hint>
</mat-form-field>
<mat-form-field appearance=outline>
<mat-label>Postal Code</mat-label>
<mat-select placeholder="Select country">
<mat-option value="option1">Option 1</mat-option>
<mat-option value="option2" disabled>Option 2 (disabled)</mat-option>
<mat-option value="option3">Option 3</mat-option>
</mat-select>
<mat-hint>Default postal code for skills (e.g. weather)</mat-hint>
</mat-form-field>
<mat-form-field appearance=outline>
<mat-label>Time Zone</mat-label>
<mat-select>
<mat-option value="option1">Option 1</mat-option>
<mat-option value="option2" disabled>Option 2 (disabled)</mat-option>
<mat-option value="option3">Option 3</mat-option>
</mat-select>
<mat-hint>Default time zone for skills (e.g. alarm clock)</mat-hint>
</mat-form-field>
</div>
</div>
</form>
</mat-card>

View File

@ -0,0 +1,45 @@
@import '~@angular/material/theming';
@import "mycroft-colors";
// Angular Material does not support a form field with a map control inside it.
// Do our best to make this look like the other form fields
@mixin mimic-form-field {
border: 1px solid rgba(0, 0, 0, 0.12);
border-radius: 6px;
color: rgba(0, 0, 0, 0.6);
padding: 15px;
&:hover {
border: 2px solid rgba(0, 0, 0, 0.87);
padding: 14px;
}
legend {
font-size: 13px;
font-weight: 400;
margin-left: -7px;
padding-top: 5px;
padding-left: 3px;
padding-right: 5px;
}
}
.mat-h3 {
margin-bottom: 10px;
}
mat-card {
mat-form-field {
max-width: 400px;
}
fieldset {
@include mimic-form-field;
.map {
width: 100%;
height: 300px;
}
}
}

View File

@ -0,0 +1,13 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'account-personal',
templateUrl: './personal.component.html',
styleUrls: ['./personal.component.scss']
})
export class PersonalComponent implements OnInit {
constructor() { }
ngOnInit() { }
}

View File

@ -0,0 +1,7 @@
<div>
<account-login></account-login>
<account-subscription></account-subscription>
<!--<account-personal></account-personal>-->
<account-agreements></account-agreements>
<account-delete></account-delete>
</div>

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'account-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.scss']
})
export class ProfileComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}

View File

@ -0,0 +1,54 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FlexLayoutModule } from '@angular/flex-layout';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import {
MatButtonModule,
MatButtonToggleModule,
MatCardModule,
MatDividerModule,
MatExpansionModule,
MatFormFieldModule,
MatInputModule,
MatSelectModule,
MatSlideToggleModule,
MatToolbarModule
} from '@angular/material';
import { ProfileComponent } from './profile.component';
import { LoginComponent } from './login/login.component';
import { PersonalComponent } from './personal/personal.component';
import { SubscriptionComponent } from './subscription/subscription.component';
import { DeleteComponent } from './delete/delete.component';
import { AgreementsComponent } from './agreements/agreements.component';
@NgModule({
declarations: [
ProfileComponent,
LoginComponent,
PersonalComponent,
SubscriptionComponent,
DeleteComponent,
AgreementsComponent
],
entryComponents: [
LoginComponent
],
imports: [
CommonModule,
FlexLayoutModule,
FontAwesomeModule,
MatButtonModule,
MatButtonToggleModule,
MatCardModule,
MatDividerModule,
MatExpansionModule,
MatFormFieldModule,
MatInputModule,
MatSelectModule,
MatSlideToggleModule,
MatToolbarModule
]
})
export class ProfileModule { }

View File

@ -0,0 +1,17 @@
<mat-card class="section-card">
<mat-toolbar class="section-card-title-bar">
<div class="section-card-title">Support Mycroft</div>
</mat-toolbar>
<div fxLayout="column" fxLayoutAlign="center center">
<mat-button-toggle-group [vertical]="alignVertical">
<ng-container *ngFor="let subscription of subscriptionTypes">
<mat-button-toggle style="padding: 8px">
<div class="mat-h3">{{subscription.name}}</div>
<div class="mat-body">{{subscription.price}} USD</div>
</mat-button-toggle>
</ng-container>
</mat-button-toggle-group>
<div id="subscription-date" class="mat-body">Proudly supporting Mycroft for {{subscriptionDuration}}</div>
</div>
</mat-card>

View File

@ -0,0 +1,16 @@
.mat-h3 {
margin-bottom: 10px;
}
mat-button-toggle-group {
border: none;
padding: 16px;
mat-button-toggle {
margin: 8px;
}
}
#subscription-date {
margin-bottom: 16px;
}

View File

@ -0,0 +1,51 @@
import { Component, OnDestroy } from '@angular/core';
import { MediaChange, ObservableMedia } from '@angular/flex-layout';
import { Subscription } from 'rxjs';
export interface SubscriptionType {
name: string;
price: string;
period: string;
}
const nonSupporter: SubscriptionType = {
name: 'NON-SUPPORTER',
price: '$0',
period: null
};
const monthlySupporter: SubscriptionType = {
name: 'MONTHLY SUPPORTER',
price: '$1.99',
period: 'month'
};
const yearlySupporter: SubscriptionType = {
name: 'YEARLY SUPPORTER',
price: '$19.99',
period: 'year'
};
@Component({
selector: 'account-subscription',
templateUrl: './subscription.component.html',
styleUrls: ['./subscription.component.scss']
})
export class SubscriptionComponent implements OnDestroy {
public subscriptionTypes: SubscriptionType[];
public subscriptionDuration = '3 years 10 months';
public alignVertical: boolean;
private mediaWatcher: Subscription;
constructor(public media: ObservableMedia) {
this.mediaWatcher = media.subscribe(
(change: MediaChange) => {
this.alignVertical = ['xs', 'sm'].includes(change.mqAlias);
}
);
this.subscriptionTypes = [yearlySupporter, monthlySupporter, nonSupporter];
}
ngOnDestroy(): void {
this.mediaWatcher.unsubscribe();
}
}

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,10 @@
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="60" height="60" fill="#22A7F0"/>
<rect x="19" y="11" width="22" height="38" rx="8" fill="white"/>
<rect x="16.5" y="8.5" width="27" height="43" rx="9.5" stroke="white"/>
<line x1="30" y1="38" x2="30" y2="22" stroke="#22A7F0" stroke-width="2" stroke-linecap="round"/>
<line x1="33" y1="35" x2="33" y2="25" stroke="#22A7F0" stroke-width="2" stroke-linecap="round"/>
<line x1="24" y1="32" x2="24" y2="28" stroke="#22A7F0" stroke-width="2" stroke-linecap="round"/>
<line x1="27" y1="35" x2="27" y2="25" stroke="#22A7F0" stroke-width="2" stroke-linecap="round"/>
<line x1="36" y1="32" x2="36" y2="28" stroke="#22A7F0" stroke-width="2" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 771 B

View File

@ -0,0 +1,10 @@
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="60" height="60" fill="white"/>
<rect x="19" y="11" width="22" height="38" rx="8" fill="#5B6984"/>
<rect x="16.5" y="8.5" width="27" height="43" rx="9.5" stroke="#5B6984"/>
<line x1="30" y1="38" x2="30" y2="22" stroke="white" stroke-width="2" stroke-linecap="round"/>
<line x1="33" y1="35" x2="33" y2="25" stroke="white" stroke-width="2" stroke-linecap="round"/>
<line x1="24" y1="32" x2="24" y2="28" stroke="white" stroke-width="2" stroke-linecap="round"/>
<line x1="27" y1="35" x2="27" y2="25" stroke="white" stroke-width="2" stroke-linecap="round"/>
<line x1="36" y1="32" x2="36" y2="28" stroke="white" stroke-width="2" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 763 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1"
id="svg821" inkscape:version="0.91 r13725" sodipodi:docname="KDElogoBoxBlue.svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 40 40"
style="enable-background:new 0 0 40 40;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st1{fill:#6C7A89;}
</style>
<sodipodi:namedview bordercolor="#666666" borderopacity="1.0" id="base" inkscape:bbox-nodes="true" inkscape:current-layer="layer1" inkscape:cx="62.936714" inkscape:cy="68.6291" inkscape:document-units="mm" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:snap-bbox="true" inkscape:window-height="2045" inkscape:window-maximized="1" inkscape:window-width="3840" inkscape:window-x="0" inkscape:window-y="0" inkscape:zoom="5.6" pagecolor="#ffffff" showgrid="true" units="px" width="128px">
<inkscape:grid id="grid1391" type="xygrid"></inkscape:grid>
</sodipodi:namedview>
<g>
<rect id="rect4157" x="5.6" y="5.6" class="st0" width="28.8" height="28.8"/>
<path id="path5692_2_-3" inkscape:connector-curvature="0" class="st1" d="M21.6,9.3l-3.7,0.4v15.1l3.6-0.5v-6.4l4.9,7.1l3.8-1.2
l-5-6.9l5-6.5l-3.9-0.9l-4.8,6.5L21.6,9.3z M13.3,13c0,0-0.1,0-0.1,0.1l-1.4,1.4c-0.1,0.1-0.1,0.2,0,0.2l1.7,2.8
c-0.3,0.5-0.5,1-0.7,1.6l-3.1,0.6c-0.1,0-0.1,0.1-0.1,0.2v2c0,0.1,0.1,0.2,0.1,0.2l3,0.7c0.2,0.7,0.4,1.3,0.7,1.9l-1.7,2.6
c0,0.1,0,0.2,0,0.2l1.4,1.4c0.1,0.1,0.2,0.1,0.2,0l2.7-1.7c0.5,0.3,1.1,0.6,1.7,0.7l0.6,3c0,0.1,0.1,0.1,0.2,0.1h2
c0.1,0,0.2-0.1,0.2-0.1l0.7-3.1c0.6-0.2,1.2-0.4,1.8-0.7l2.7,1.8c0.1,0,0.2,0,0.2,0l1.4-1.4c0.1-0.1,0.1-0.2,0-0.2l-1-1.6l-0.3,0.1
c0,0-0.1,0-0.1,0c0,0-0.6-0.9-1.4-2.1c-1,1.9-2.9,3.2-5.2,3.2c-3.2,0-5.8-2.6-5.8-5.8c0-2.4,1.4-4.4,3.4-5.3v-1.5
c-0.4,0.1-0.7,0.3-1.1,0.5c0,0,0,0,0,0L13.4,13C13.4,13,13.3,13,13.3,13L13.3,13z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,7 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M37.7801 9.38C37.7801 11.48 36.6301 13 34.5501 14.05C34.3901 14.96 34.2701 16.12 34.2601 16.27C34.2649 16.386 34.2283 16.5 34.1569 16.5916C34.0854 16.6832 33.9838 16.7464 33.8701 16.77C33.4945 16.8409 33.1119 16.8677 32.7301 16.85C32.2857 16.8524 31.8426 16.802 31.4101 16.7C31.0201 16.61 30.9901 16.5 30.9901 16.5C30.8806 16.1776 30.6954 15.8861 30.4501 15.65C30.3843 15.5725 30.3106 15.5021 30.2301 15.44C26.4847 16.0743 22.688 16.3555 18.8901 16.28C15.004 16.3662 11.1187 16.0715 7.29008 15.4C7.16467 15.4893 7.05051 15.5933 6.95009 15.71C6.70849 15.9433 6.52669 16.2315 6.42008 16.55C6.42008 16.55 6.42008 16.66 6.00008 16.76C5.56716 16.8586 5.12407 16.9056 4.68008 16.9C4.29496 16.9172 3.90912 16.8904 3.53008 16.82C3.41725 16.7962 3.31675 16.7326 3.24697 16.6408C3.17719 16.549 3.1428 16.4351 3.15008 16.32C3.15008 16.16 2.99008 14.76 2.81008 13.84C1.97279 13.4321 1.26607 12.7984 0.769591 12.0104C0.273107 11.2224 0.00659219 10.3114 8.47899e-05 9.38C-0.00235877 8.95211 0.0480221 8.52555 0.150085 8.11V8.11C0.650085 4.98 5.41009 1.84 12.6101 1.17C13.4601 1.09 14.5001 1.06 15.6801 1.06V0.24L15.8901 0C15.8901 0 17.0101 0 18.7301 0C20.4501 0 21.6701 0 21.6701 0L21.8901 0.21V1.05C23.4601 1.05 24.7601 1.11 25.5901 1.21C32.5901 2.02 37.0601 5.04 37.6501 8.03C37.7536 8.47217 37.7973 8.92621 37.7801 9.38V9.38Z" transform="translate(1 12)" stroke="#6C7A89" stroke-width="0.75" stroke-linejoin="round"/>
<path d="M35.7 6C35.7 11 27.7 12 17.85 12C8 12 0 10.84 0 6C0 1.16 8 0 17.85 0C27.7 0 35.7 1.06 35.7 6Z" transform="translate(2.04004 15.1602)" fill="#6C7A89"/>
<path d="M2.87 5.74C4.45506 5.74 5.74 4.45506 5.74 2.87C5.74 1.28494 4.45506 0 2.87 0C1.28494 0 0 1.28494 0 2.87C0 4.45506 1.28494 5.74 2.87 5.74Z" transform="translate(4.11035 18.3599)" stroke="white" stroke-linejoin="round"/>
<path d="M2.87 5.74C4.45506 5.74 5.74 4.45506 5.74 2.87C5.74 1.28494 4.45506 0 2.87 0C1.28495 0 0 1.28494 0 2.87C0 4.45506 1.28495 5.74 2.87 5.74Z" transform="translate(29.5996 18.3599)" stroke="white" stroke-linejoin="round"/>
<path d="M0 0L1.65 1.08H7.7L9.36 0H0Z" transform="translate(15.04 22.6299)" fill="white" stroke="white" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,6 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19.52 29.8869C19.4771 30.5082 19.3766 31.1241 19.22 31.7269C19.2264 31.7532 19.2264 31.7806 19.22 31.8069C19.0677 32.3492 18.8874 32.8832 18.68 33.4069C18.57 33.6669 18.43 33.9369 18.29 34.1969C18.1326 34.4505 17.9554 34.6913 17.76 34.9169C17.5849 35.1432 17.3676 35.3334 17.12 35.4769C16.8678 35.6114 16.5858 35.6802 16.3 35.6769H3.53C3.24706 35.683 2.96756 35.614 2.72 35.4769C2.46971 35.3332 2.2491 35.1432 2.07 34.9169C1.88106 34.6909 1.71052 34.4501 1.56 34.1969C1.4 33.9369 1.28 33.6669 1.16 33.4069C1.02759 33.1247 0.914004 32.8341 0.820001 32.5369C0.820001 32.5369 0.700001 32.1169 0.650001 31.8969C0.650001 31.8369 0.43 30.7269 0.39 30.1369C0.0600003 25.3569 0 11.2269 0 11.2269C0 5.42689 3.17 0.00689305 9.88 0.00689305C11.2703 -0.0466351 12.655 0.212137 13.9321 0.764182C15.2092 1.31623 16.3464 2.14751 17.26 3.19689C18.9775 5.33145 19.8781 8.00826 19.8 10.7469C19.8 10.7469 19.89 25.1869 19.52 29.8869Z" transform="translate(10 2)" stroke="#6C7A89" stroke-width="0.75" stroke-linejoin="round"/>
<path d="M13.8432 19.94C13.8432 19.53 13.8432 19.11 13.8432 18.69V9.77C13.8432 9.62333 13.8432 9.47667 13.8432 9.33C13.8432 4.4 12.9932 0 7.00319 0C0.81319 0 0.00318953 4.47 0.00318953 9.45V19.06C0.00318953 19.49 0.00318953 19.93 0.00318953 20.35C-0.0288053 22.0015 0.180056 23.6488 0.623189 25.24C1.34319 27.77 3.15319 29.53 6.84319 29.59C12.8432 29.69 13.7332 25.01 13.7832 19.96L13.8432 19.94Z" transform="translate(13.0469 5.1167)" fill="#6C7A89"/>
<path d="M0.380812 1.96426C0.323184 1.96438 0.266283 1.9514 0.214414 1.92628C0.162545 1.90117 0.117067 1.86459 0.0814202 1.81931C0.0457737 1.77403 0.0208922 1.72123 0.00865958 1.66492C-0.00357306 1.6086 -0.00283688 1.55025 0.010812 1.49426C0.122676 1.06626 0.373284 0.687426 0.723414 0.417047C1.07354 0.146667 1.50344 0 1.94581 0C2.38819 0 2.81808 0.146667 3.16821 0.417047C3.51834 0.687426 3.76895 1.06626 3.88081 1.49426C3.89446 1.55025 3.8952 1.6086 3.88296 1.66492C3.87073 1.72123 3.84585 1.77403 3.8102 1.81931C3.77456 1.86459 3.72908 1.90117 3.67721 1.92628C3.62534 1.9514 3.56844 1.96438 3.51081 1.96426C3.42466 1.96216 3.34163 1.93158 3.27469 1.87731C3.20775 1.82303 3.16067 1.74812 3.14081 1.66426C3.072 1.40106 2.91787 1.1681 2.70255 1.00184C2.48722 0.835573 2.22286 0.745385 1.95081 0.745385C1.67877 0.745385 1.4144 0.835573 1.19908 1.00184C0.983753 1.1681 0.829625 1.40106 0.760812 1.66426C0.74095 1.74812 0.693873 1.82303 0.626934 1.87731C0.559995 1.93158 0.476964 1.96216 0.390812 1.96426H0.380812Z" transform="translate(14.4189 15.1528)" fill="white"/>
<path d="M0.380812 1.96426C0.323184 1.96438 0.266282 1.9514 0.214413 1.92628C0.162544 1.90117 0.117066 1.86459 0.0814196 1.81931C0.0457732 1.77403 0.0208927 1.72123 0.00866002 1.66492C-0.00357263 1.6086 -0.0028374 1.55025 0.0108115 1.49426C0.122675 1.06626 0.373284 0.687426 0.723414 0.417047C1.07354 0.146667 1.50344 0 1.94581 0C2.38819 0 2.81808 0.146667 3.16821 0.417047C3.51834 0.687426 3.76895 1.06626 3.88081 1.49426C3.89446 1.55025 3.8952 1.6086 3.88296 1.66492C3.87073 1.72123 3.84585 1.77403 3.8102 1.81931C3.77456 1.86459 3.72908 1.90117 3.67721 1.92628C3.62534 1.9514 3.56844 1.96438 3.51081 1.96426C3.42466 1.96216 3.34163 1.93158 3.27469 1.87731C3.20775 1.82303 3.16067 1.74812 3.14081 1.66426C3.072 1.40106 2.91787 1.1681 2.70255 1.00184C2.48722 0.835573 2.22286 0.745385 1.95081 0.745385C1.67877 0.745385 1.4144 0.835573 1.19908 1.00184C0.983753 1.1681 0.829625 1.40106 0.760812 1.66426C0.74095 1.74812 0.693872 1.82303 0.626933 1.87731C0.559994 1.93158 0.476965 1.96216 0.390813 1.96426H0.380812Z" transform="translate(21.6191 15.1528)" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1,12 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22.01 0H0.889999C0.398466 0 0 0.398466 0 0.889999V14.16C0 14.6515 0.398466 15.05 0.889999 15.05H22.01C22.5015 15.05 22.9 14.6515 22.9 14.16V0.889999C22.9 0.398466 22.5015 0 22.01 0Z" transform="translate(8 12)" fill="#6C7A89"/>
<path d="M4.47 0H0V3.5H4.47V0Z" transform="translate(27.1201 12.6602)" fill="white" stroke="#6C7A89" stroke-width="0.26" stroke-miterlimit="10"/>
<path d="M5.11 0H0V4.24H5.11V0Z" transform="translate(26.4902 21.9399)" fill="white" stroke="#6C7A89" stroke-width="0.25" stroke-miterlimit="10"/>
<path d="M0.75 1.5C1.16421 1.5 1.5 1.16421 1.5 0.75C1.5 0.335786 1.16421 0 0.75 0C0.335786 0 0 0.335786 0 0.75C0 1.16421 0.335786 1.5 0.75 1.5Z" transform="translate(9.0498 24.5601)" fill="white"/>
<path d="M0.75 1.5C1.16421 1.5 1.5 1.16421 1.5 0.75C1.5 0.335786 1.16421 0 0.75 0C0.335786 0 0 0.335786 0 0.75C0 1.16421 0.335786 1.5 0.75 1.5Z" transform="translate(24.0898 24.5601)" fill="white"/>
<path d="M0.75 1.5C1.16421 1.5 1.5 1.16421 1.5 0.75C1.5 0.335786 1.16421 0 0.75 0C0.335786 0 0 0.335786 0 0.75C0 1.16421 0.335786 1.5 0.75 1.5Z" transform="translate(24.0898 12.98)" fill="white"/>
<path d="M0.75 1.5C1.16421 1.5 1.5 1.16421 1.5 0.75C1.5 0.335786 1.16421 0 0.75 0C0.335786 0 0 0.335786 0 0.75C0 1.16421 0.335786 1.5 0.75 1.5Z" transform="translate(9.0498 12.98)" fill="white"/>
<path d="M4.47 0H0V3.5H4.47V0Z" transform="translate(27.1201 17.3501)" fill="white" stroke="#6C7A89" stroke-width="0.26" stroke-miterlimit="10"/>
<path d="M4.78 9.56C3.83461 9.56 2.91044 9.27966 2.12438 8.75443C1.33831 8.22919 0.725645 7.48266 0.363858 6.60923C0.00207138 5.7358 -0.0925889 4.7747 0.0918484 3.84747C0.276286 2.92024 0.731537 2.06853 1.40003 1.40003C2.06853 0.731536 2.92024 0.276286 3.84747 0.0918484C4.7747 -0.0925889 5.7358 0.00207138 6.60923 0.363858C7.48266 0.725645 8.22919 1.33831 8.75443 2.12438C9.27966 2.91044 9.56 3.83461 9.56 4.78C9.56 5.40772 9.43636 6.02929 9.19615 6.60923C8.95593 7.18917 8.60384 7.71611 8.15997 8.15997C7.71611 8.60384 7.18916 8.95593 6.60923 9.19615C6.02929 9.43636 5.40772 9.56 4.78 9.56Z" transform="translate(12.5195 14.6401)" fill="white"/>
<path d="M4 0C3.20888 0 2.43552 0.234596 1.77772 0.674122C1.11992 1.11365 0.607234 1.73836 0.304484 2.46927C0.00173312 3.20017 -0.0774802 4.00444 0.0768607 4.78036C0.231202 5.55629 0.612165 6.26902 1.17157 6.82843C1.73098 7.38784 2.44372 7.7688 3.21964 7.92314C3.99556 8.07748 4.79983 7.99827 5.53074 7.69552C6.26164 7.39277 6.88635 6.88008 7.32588 6.22228C7.76541 5.56448 8 4.79113 8 4C7.98703 2.94316 7.56144 1.93327 6.81409 1.18591C6.06674 0.43856 5.05684 0.0129688 4 0ZM4 7.38C3.11683 7.38 2.26983 7.02916 1.64534 6.40466C1.02084 5.78017 0.670002 4.93317 0.670002 4.05C0.670002 3.16683 1.02084 2.31983 1.64534 1.69534C2.26983 1.07084 3.11683 0.719999 4 0.719999V7.38Z" transform="translate(13.2998 15.3599)" fill="#6C7A89"/>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,3 @@
export const environment = {
production: true
};

View File

@ -0,0 +1,25 @@
// This file can be replaced during build by using the `fileReplacements` array.
// `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
export const environment = {
production: false,
mycroftUrls: {
chat: 'https://chat.mycroft.ai',
forum: 'https://community.mycroft.ai',
singleSignOn: 'http://localhost:4201',
account: 'https://home-test.mycroft.ai',
marketplace: 'http://localhost:4202',
mimic: 'http://mimic.mycroft,ai',
translate: 'https://translate-test.mycroft.ai',
wordpress: 'https://test.mycroft.ai'
}
};
/*
* In development mode, to ignore zone related error stack frames such as
* `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can
* import the following file, but please comment it out in production mode
* because it will have performance impact when throw error
*/
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

View File

@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Account</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body style="margin: 0;">
<account-root></account-root>
</body>
</html>

View File

@ -0,0 +1,12 @@
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));

View File

@ -0,0 +1,80 @@
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/guide/browser-support
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
// import 'core-js/es6/symbol';
// import 'core-js/es6/object';
// import 'core-js/es6/function';
// import 'core-js/es6/parse-int';
// import 'core-js/es6/parse-float';
// import 'core-js/es6/number';
// import 'core-js/es6/math';
// import 'core-js/es6/string';
// import 'core-js/es6/date';
// import 'core-js/es6/array';
// import 'core-js/es6/regexp';
// import 'core-js/es6/map';
// import 'core-js/es6/weak-map';
// import 'core-js/es6/set';
/**
* If the application will be indexed by Google Search, the following is required.
* Googlebot uses a renderer based on Chrome 41.
* https://developers.google.com/search/docs/guides/rendering
**/
// import 'core-js/es6/array';
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/** IE10 and IE11 requires the following for the Reflect API. */
// import 'core-js/es6/reflect';
/**
* Web Animations `@angular/platform-browser/animations`
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
**/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/**
* By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags
*/
// (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
// (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
// (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
/*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*/
// (window as any).__Zone_enable_cross_context_check = true;
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import 'zone.js/dist/zone'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/

View File

@ -0,0 +1 @@
/* You can add global styles to this file, and also import other style files */

View File

@ -0,0 +1,20 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
declare const require: any;
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);

View File

@ -0,0 +1,11 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/app",
"types": []
},
"exclude": [
"test.ts",
"**/*.spec.ts"
]
}

View File

@ -0,0 +1,18 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/spec",
"types": [
"jasmine",
"node"
]
},
"files": [
"src/test.ts",
"src/polyfills.ts"
],
"include": [
"**/*.spec.ts",
"**/*.d.ts"
]
}

View File

@ -0,0 +1,17 @@
{
"extends": "../../tslint.json",
"rules": {
"directive-selector": [
true,
"attribute",
"account",
"camelCase"
],
"component-selector": [
true,
"element",
"account",
"kebab-case"
]
}
}

View File

@ -0,0 +1,31 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require('path').join(__dirname, '../../coverage'),
reports: ['html', 'lcovonly'],
fixWebpackSourcePaths: true
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};

View File

@ -0,0 +1,13 @@
{
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/globalnav",
"lib": {
"entryFile": "src/public_api.ts",
"cssUrl": "inline",
"umdModuleIds": {
"@fortawesome/angular-fontawesome": "angularFontawesome",
"@fortawesome/free-brands-svg-icons": "freeBrandsSvgIcons",
"@fortawesome/free-solid-svg-icons": "freeSolidSvgIcons"
}
}
}

View File

@ -0,0 +1,10 @@
{
"name": "globalnav",
"version": "0.0.1",
"peerDependencies": {
"@angular/common": "^7.0.0",
"@angular/core": "^7.0.0",
"@angular/flex-layout": "^7.0.0-beta.19"
}
}

View File

@ -0,0 +1,16 @@
<div class="nav-footer">
<mat-divider></mat-divider>
<div fxLayout="row wrap" fxLayoutAlign="start" class="social-icons">
<a *ngFor="let media of socialMediaIcons" href="{{media.url}}">
<button mat-icon-button class="social-icon-button">
<fa-icon [icon]="media.icon"></fa-icon>
</button>
</a>
</div>
<div *ngFor="let item of footerItems">
<a href="{{item.url}}">
<button mat-flat-button class="footer-text">{{item.text}}</button>
</a>
</div>
<div class="mat-body-2">&copy; Mycroft AI, Inc.</div>
</div>

View File

@ -0,0 +1,26 @@
.nav-footer {
padding: 16px;
}
.social-icons {
width: 180px;
margin-left: -10px;
}
.social-icon-button {
color: #6c7a89;
font-size: 20px;
}
.footer-text {
color: #6c7a89;
font-weight: 400;
line-height: 30px;
padding: 0;
}
.mat-body-2 {
color: #6c7a89;
margin-top: 5px;
font-weight: 400;
}

View File

@ -0,0 +1,38 @@
import { Component, Input, OnInit } from '@angular/core';
import { NavItem } from '../globalnav.service';
import {
faFacebook,
faInstagram,
faLinkedin,
faMedium,
faReddit,
faTelegram,
faTwitter,
faYoutube,
} from '@fortawesome/free-brands-svg-icons';
@Component({
selector: 'globalnav-footer',
templateUrl: './footer.component.html',
styleUrls: ['./footer.component.scss']
})
export class FooterComponent implements OnInit {
@Input() footerItems: NavItem[];
public socialMediaIcons = [
{icon: faTwitter, url: 'https://twitter.com/mycroft_ai'},
{icon: faFacebook, url: 'https://www.facebook.com/aiforeveryone/'},
{icon: faInstagram, url: 'https://www.instagram.com/mycroft_ai/'},
{icon: faYoutube, url: 'https://www.youtube.com/channel/UC1dlmB1lup9RwFQBSGnhA-g'},
{icon: faTelegram, url: 'https://t.me/mycroft_ai'},
{icon: faReddit, url: 'https://www.reddit.com/r/Mycroftai/'},
{icon: faLinkedin, url: 'https://www.linkedin.com/company/mycroft-a.i./'},
{icon: faMedium, url: 'https://medium.com/@mycroftai'}
];
constructor() { }
ngOnInit() {
}
}

View File

@ -0,0 +1,74 @@
<mat-toolbar fxLayout="row" fxLayoutAlign="space-between" color="primary">
<!-- At the start of the title bar, put the hamburger menu icon and -->
<!-- the Mycroft logo. The latter is also a link to the WordPress home page-->
<div fxLayout="row" fxLayoutAlign="start center" fxFlex>
<button mat-icon-button class="menu-button" (click)="snav.toggle()">
<fa-icon [icon]="menuIcon"></fa-icon>
</button>
<a href="{{mycroftUrls.wordpress}}">
<div class="globalnav-logo"></div>
</a>
</div>
<!-- At the end of the title bar is a login/logout control -->
<!-- The logout control is displayed whenever the user is logged in... -->
<div *ngIf="isLoggedIn" fxLayout="row" fxLayoutAlign="end center">
<button
mat-flat-button
class="sign-in-button"
[matMenuTriggerFor]="authMenu"
>
<fa-icon [icon]="userIcon"></fa-icon>
{{userName}}
</button>
<mat-menu #authMenu="matMenu">
<button mat-menu-item (click)="navigateToSignOut()">
<fa-icon [icon]="signOutIcon" style="margin-right: 10px;"></fa-icon>
Logout
</button>
</mat-menu>
</div>
<!-- ...and the login control is displayed whenever the user is logged out. -->
<button
*ngIf="!isLoggedIn"
mat-flat-button
class="sign-in-button"
(click)="navigateToSignIn()"
>
<fa-icon [icon]="signInIcon"></fa-icon>
SIGN IN
</button>
</mat-toolbar>
<mat-sidenav-container>
<!-- This is the global sidenav menu for navigating all Mycroft sites -->
<mat-sidenav
#snav
[mode]="mobileQuery.matches ? 'over' : 'side'"
[opened]="!mobileQuery.matches"
[fixedInViewport]="true"
>
<div fxFill fxLayout="column">
<mat-nav-list fxFlex [disableRipple]="true">
<globalnav-primary-nav-item
*ngFor="let nav of navigationItems"
[primaryNavItem]="nav"
>
</globalnav-primary-nav-item>
</mat-nav-list>
<globalnav-footer [footerItems]="footerItems"></globalnav-footer>
</div>
</mat-sidenav>
<!-- This is the area where any non-menu content can go. -->
<!-- Mycroft web apps must specify the appBody identifier so that their -->
<!-- content is placed within the mat-sidenav-content area. -->
<mat-sidenav-content>
<ng-content select="[appBody]"></ng-content>
</mat-sidenav-content>
</mat-sidenav-container>

View File

@ -0,0 +1,64 @@
mat-toolbar {
height: 50px;
position: fixed;
z-index: 2; // Put this on top of the sidenav container
.menu-button {
margin-left: -10px;
margin-right: 10px;
fa-icon {
color: white;
font-size: 20px;
}
}
// Use inline css to display the logo at top of sidebar because Angular
// libraries do not support static assets yet.
.globalnav-logo {
background: url("toolbar-logo.svg") no-repeat;
height: 25px;
margin-top: -5px;
width: 168px;
}
.sign-in-button {
background-color: #22a7f0;
color: white;
font-size: 16px;
fa-icon {
color: white;
font-size: 16px;
margin-right: 10px
}
}
}
mat-sidenav-container {
min-height: 100vh;
width: 100%;
.mat-drawer-container{
overflow: visible;
}
mat-sidenav {
border: none;
margin-top: 50px;
mat-divider {
width: 200px;
margin-left: 10px;
}
mat-nav-list {
overflow-y: auto;
}
}
mat-sidenav-content {
padding-left: 3vw;
padding-right: 3vw;
margin-top: 80px;
}
}

View File

@ -0,0 +1,171 @@
import { Component, Input, OnInit } from '@angular/core';
import { MediaMatcher } from '@angular/cdk/layout';
import { Observable } from 'rxjs';
import {
faBars,
faLightbulb,
faRobot,
faRocket,
faRss,
faSignInAlt,
faSignOutAlt,
faStore,
faUserCircle,
faUsers
} from '@fortawesome/free-solid-svg-icons';
import {
expireTokenCookies,
NavItem,
PrimaryNavItem,
setLoginStatus,
User
} from './globalnav.service';
@Component({
selector: 'globalnav-sidenav',
templateUrl: './globalnav.component.html',
styleUrls: ['./globalnav.component.scss']
})
export class GlobalnavComponent implements OnInit {
@Input() mycroftUrls: any;
@Input() user$: Observable<User>;
public footerItems: NavItem[];
public isLoggedIn: boolean;
public signInIcon = faSignInAlt;
public signOutIcon = faSignOutAlt;
public menuIcon = faBars;
public mobileQuery: MediaQueryList;
public navigationItems: PrimaryNavItem[];
public userIcon = faUserCircle;
public userName: string;
constructor(private media: MediaMatcher) {
this.mobileQuery = media.matchMedia('(max-width: 600px)');
}
ngOnInit() {
this.isLoggedIn = setLoginStatus();
this.getUser();
this.buildNavigationItems();
this.buildAccountNav();
}
getUser() {
if (this.isLoggedIn) {
this.user$.subscribe(
(user) => {
if (user.name) {
this.userName = user.name;
} else {
this.userName = 'Logged In';
}
},
(response) => {
if (response.status === 401) {
expireTokenCookies();
this.isLoggedIn = setLoginStatus();
}
}
);
}
}
buildNavigationItems(): void {
const aboutMycroftNav: PrimaryNavItem = {
children: [
{text: 'Team', url: this.mycroftUrls.wordpress + '/team'},
{text: 'Careers', url: this.mycroftUrls.wordpress + '/careers'}
],
icon: faRobot,
text: 'About Mycroft'
};
const blogNav: PrimaryNavItem = {
icon: faRss,
text: 'Blog',
url: this.mycroftUrls.wordpress + '/blog'
};
const communityNav: PrimaryNavItem = {
children: [
{text: 'Chat', url: this.mycroftUrls.chat},
{text: 'Forum', url: this.mycroftUrls.forum}
],
icon: faUsers,
text: 'Community'
};
const contributeNav: PrimaryNavItem = {
children: [
{text: 'Source Code', url: 'https://github.com/MycroftAI'},
{text: 'Translate', url: this.mycroftUrls.translate},
{text: 'Wake Word', url: this.mycroftUrls.account + '/#/precise'},
{text: 'Speech to Text', url: this.mycroftUrls.account + '/#/deepspeech'},
{text: 'Text to Speech', url: this.mycroftUrls.mimic}
],
icon: faLightbulb,
text: 'Contribute'
};
const getStartedNav: PrimaryNavItem = {
children: [
{text: 'Get Mycroft', url: this.mycroftUrls.wordpress + '/download'},
{text: 'Documentation', url: this.mycroftUrls.wordpress + '/documentation'}
],
icon: faRocket,
text: 'Get Started'
};
const marketplaceNav: PrimaryNavItem = {
children: [
{text: 'Skills', url: this.mycroftUrls.marketplace + '/skills'},
{text: 'Hardware', url: this.mycroftUrls.wordpress + '/shop'}
],
icon: faStore,
text: 'Marketplace'
};
this.navigationItems = [
aboutMycroftNav,
getStartedNav,
blogNav,
communityNav,
contributeNav,
marketplaceNav,
];
this.footerItems = [
{text: 'Contact Us', url: this.mycroftUrls.wordpress + '/contact'},
{text: 'Media Kit', url: this.mycroftUrls.wordpress + '/media'},
{text: 'Privacy Policy', url: this.mycroftUrls.account + '/#/privacy-policy'},
{text: 'Terms of Use', url: this.mycroftUrls.account + '/#/terms-of-use'}
];
}
buildAccountNav() {
const accountNav: PrimaryNavItem = {
children: [
{text: 'Devices', url: this.mycroftUrls.account + '/#/device'},
{text: 'Profile', url: this.mycroftUrls.account + '/#/profile'},
{text: 'Skill Settings', url: this.mycroftUrls.account + '/#/skill'},
{text: 'Subscription', url: this.mycroftUrls.account + '/#/account'},
{text: 'User Settings', url: this.mycroftUrls.account + '/#/setting/basic'},
],
icon: faUserCircle,
text: 'My Account',
};
if (this.isLoggedIn) {
this.navigationItems.push(accountNav);
}
}
navigateToSignIn() {
window.location.assign(
this.mycroftUrls.singleSignOn + '/login?redirect=' + window.location.href
);
}
navigateToSignOut() {
window.location.assign(
this.mycroftUrls.singleSignOn + '/logout?redirect=' + window.location.href
);
}
}

View File

@ -0,0 +1,43 @@
import { CommonModule } from '@angular/common';
import { FlexLayoutModule } from '@angular/flex-layout';
import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatDividerModule } from '@angular/material/divider';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatListModule } from '@angular/material';
import { MatMenuModule } from '@angular/material/menu';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatToolbarModule } from '@angular/material/toolbar';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { GlobalnavComponent } from './globalnav.component';
import { NavItemComponent } from './nav-item/nav-item.component';
import { PrimaryNavItemComponent } from './primary-nav-item/primary-nav-item.component';
import { FooterComponent } from './footer/footer.component';
@NgModule({
imports: [
CommonModule,
FlexLayoutModule,
FontAwesomeModule,
MatButtonModule,
MatDividerModule,
MatExpansionModule,
MatListModule,
MatMenuModule,
MatSidenavModule,
MatToolbarModule,
],
declarations: [
GlobalnavComponent,
NavItemComponent,
PrimaryNavItemComponent,
FooterComponent
],
exports: [
GlobalnavComponent
],
providers: []
})
export class GlobalnavModule { }

Some files were not shown because too many files have changed in this diff Show More