added global navigation library and implemented it in the marketplace
parent
f2718378e5
commit
9fba5f6371
|
@ -433,6 +433,41 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"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/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "internet"
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -35,6 +35,7 @@
|
|||
},
|
||||
"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",
|
||||
|
@ -49,8 +50,11 @@
|
|||
"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"
|
||||
}
|
||||
|
|
|
@ -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
|
||||
});
|
||||
};
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<div fxFlex="nogrow" class="nav-footer">
|
||||
<mat-divider></mat-divider>
|
||||
<div fxLayout="row wrap" fxLayoutAlign="start" style="margin-left: -10px;">
|
||||
<button
|
||||
*ngFor="let media of socialMediaIcons"
|
||||
mat-icon-button
|
||||
(click)="navigateToSocialMedia(media.url)"
|
||||
>
|
||||
<fa-icon [icon]="media.icon"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button mat-flat-button (click)="navigateToContactUs()" class="footer-text">Contact Us</button>
|
||||
</div>
|
||||
<div>
|
||||
<button mat-flat-button (click)="navigateToMediaKit()" class="footer-text">Media Kit</button>
|
||||
</div>
|
||||
<div>
|
||||
<button mat-flat-button (click)="navigateToTermsOfUse()" class="footer-text">Terms of Use</button>
|
||||
</div>
|
||||
<div>
|
||||
<button mat-flat-button (click)="navigateToPrivacyPolicy()" class="footer-text">Privacy Policy</button>
|
||||
</div>
|
||||
<div class="mat-body-2">© Mycroft AI, Inc.</div>
|
||||
</div>
|
|
@ -0,0 +1,24 @@
|
|||
.nav-footer {
|
||||
//bottom: 0;
|
||||
padding: 16px;
|
||||
//position: fixed;
|
||||
}
|
||||
|
||||
fa-icon {
|
||||
color: #6c7a89;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.footer-text {
|
||||
color: #6c7a89;
|
||||
line-height: 30px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mat-body-2 {
|
||||
color: #6c7a89;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.mat-divider.mat-divider-vertical {
|
||||
height: 30px;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
|
||||
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() contactUsUrl: string;
|
||||
@Input() mediaKitUrl: string;
|
||||
@Input() privacyPolicyUrl: string;
|
||||
public socialMediaIcons = [
|
||||
{icon: faFacebook, url: 'https://www.facebook.com/aiforeveryone/'},
|
||||
{icon: faInstagram, url: 'https://www.instagram.com/mycroft_ai/'},
|
||||
{icon: faLinkedin, url: 'https://www.linkedin.com/company/mycroft-a.i./'},
|
||||
{icon: faMedium, url: 'https://medium.com/@mycroftai'},
|
||||
{icon: faReddit, url: 'https://www.reddit.com/r/Mycroftai/'},
|
||||
{icon: faTelegram, url: 'https://t.me/mycroft_ai'},
|
||||
{icon: faTwitter, url: 'https://twitter.com/mycroft_ai'},
|
||||
{icon: faYoutube, url: 'https://www.youtube.com/channel/UC1dlmB1lup9RwFQBSGnhA-g'}
|
||||
];
|
||||
@Input() termsOfUseUrl: string;
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
navigateToSocialMedia(url) {
|
||||
window.location.assign(url);
|
||||
}
|
||||
|
||||
navigateToTermsOfUse() {
|
||||
window.location.assign(this.termsOfUseUrl);
|
||||
}
|
||||
|
||||
navigateToPrivacyPolicy() {
|
||||
window.location.assign(this.privacyPolicyUrl);
|
||||
}
|
||||
|
||||
navigateToContactUs() {
|
||||
window.location.assign(this.contactUsUrl);
|
||||
}
|
||||
|
||||
navigateToMediaKit() {
|
||||
window.location.assign(this.mediaKitUrl);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<mat-sidenav-container>
|
||||
<mat-sidenav [mode]="'side'" [disableClose]="true" [opened]="true" [fixedInViewport]="true">
|
||||
<div fxFill fxLayout="column">
|
||||
<div fxFlex="initial">
|
||||
<div class="globalnav-logo"></div>
|
||||
<mat-divider></mat-divider>
|
||||
</div>
|
||||
<div fxFlex>
|
||||
<mat-nav-list >
|
||||
<globalnav-primary-nav-item
|
||||
*ngFor="let nav of navigationItems"
|
||||
[primaryNavItem]="nav"
|
||||
>
|
||||
</globalnav-primary-nav-item>
|
||||
</mat-nav-list>
|
||||
</div>
|
||||
<globalnav-footer
|
||||
[contactUsUrl]="contactUsUrl"
|
||||
[mediaKitUrl]="mediaKitUrl"
|
||||
[privacyPolicyUrl]="privacyPolicyUrl"
|
||||
[termsOfUseUrl]="termsOfUseUrl"
|
||||
>
|
||||
</globalnav-footer>
|
||||
</div>
|
||||
</mat-sidenav>
|
||||
<mat-sidenav-content>
|
||||
<ng-content select="[appBody]"></ng-content>
|
||||
</mat-sidenav-content>
|
||||
</mat-sidenav-container>
|
|
@ -0,0 +1,23 @@
|
|||
// Use inline css to display the logo at top of sidebar because Angular
|
||||
// libraries do not support static assets yet.
|
||||
.globalnav-logo {
|
||||
background: url("sidenav-logo.svg") no-repeat;
|
||||
height: 30px;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
mat-sidenav {
|
||||
width: 220px;
|
||||
|
||||
mat-divider {
|
||||
width: 200px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
mat-nav-list {
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
mat-sidenav-content {
|
||||
background-color: #f1f3f4;
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
|
||||
import { PrimaryNavItem } from './globalnav.service';
|
||||
import {
|
||||
faLightbulb,
|
||||
faRobot,
|
||||
faRocket,
|
||||
faRss,
|
||||
faStore,
|
||||
faUser,
|
||||
faUsers
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
@Component({
|
||||
selector: 'globalnav-sidenav',
|
||||
templateUrl: './globalnav.component.html',
|
||||
styleUrls: ['./globalnav.component.scss']
|
||||
})
|
||||
|
||||
export class GlobalnavComponent implements OnInit {
|
||||
public navigationItems: PrimaryNavItem[];
|
||||
@Input() environment: any;
|
||||
public contactUsUrl: string;
|
||||
public mediaKitUrl: string;
|
||||
public termsOfUseUrl: string;
|
||||
public privacyPolicyUrl: string;
|
||||
public isLoggedIn: boolean;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.buildNavigationItems();
|
||||
this.setLoginStatus();
|
||||
this.buildAccountNav();
|
||||
}
|
||||
|
||||
buildNavigationItems(): void {
|
||||
const aboutMycroftNav: PrimaryNavItem = {
|
||||
children: [
|
||||
{text: 'Team', url: this.environment.wordpressUrl + '/team'},
|
||||
{text: 'Careers', url: this.environment.wordpressUrl + '/careers'}
|
||||
],
|
||||
icon: faRobot,
|
||||
text: 'About Mycroft'
|
||||
};
|
||||
const blogNav: PrimaryNavItem = {
|
||||
icon: faRss,
|
||||
text: 'Blog',
|
||||
url: this.environment.wordpressUrl + '/blog'
|
||||
};
|
||||
const communityNav: PrimaryNavItem = {
|
||||
children: [
|
||||
{text: 'Chat', url: this.environment.chatUrl},
|
||||
{text: 'Forum', url: this.environment.forumUrl}
|
||||
],
|
||||
icon: faUsers,
|
||||
text: 'Community'
|
||||
};
|
||||
const contributeNav: PrimaryNavItem = {
|
||||
children: [
|
||||
{text: 'GitHub', url: 'https://github.com/MycroftAI'},
|
||||
{text: 'Translate', url: this.environment.translateUrl},
|
||||
{text: 'Wake Word Tagger', url: this.environment.accountUrl + '/#/precise'},
|
||||
{text: 'Text-to-Speech Tagger', url: this.environment.accountUrl + '/#/deepspeech'}
|
||||
],
|
||||
icon: faLightbulb,
|
||||
text: 'Contribute'
|
||||
};
|
||||
const getStartedNav: PrimaryNavItem = {
|
||||
children: [
|
||||
{text: 'Get Mycroft', url: this.environment.wordpressUrl + '/download'},
|
||||
{text: 'Documentation', url: this.environment.wordpressUrl + '/documentation'}
|
||||
],
|
||||
icon: faRocket,
|
||||
text: 'Get Started'
|
||||
};
|
||||
const marketplaceNav: PrimaryNavItem = {
|
||||
children: [
|
||||
{text: 'Skills', url: this.environment.marketplaceUrl + '/skills'},
|
||||
{text: 'Hardware', url: this.environment.wordpressUrl + '/shop'}
|
||||
],
|
||||
icon: faStore,
|
||||
text: 'Marketplace'
|
||||
};
|
||||
|
||||
this.navigationItems = [
|
||||
aboutMycroftNav,
|
||||
getStartedNav,
|
||||
blogNav,
|
||||
communityNav,
|
||||
contributeNav,
|
||||
marketplaceNav,
|
||||
];
|
||||
this.contactUsUrl = this.environment.wordpressUrl + '/contact';
|
||||
this.mediaKitUrl = this.environment.wordpressUrl + '/media';
|
||||
this.privacyPolicyUrl = this.environment.accountUrl + '/#/privacy-policy';
|
||||
this.termsOfUseUrl = this.environment.accountUrl + '/#/terms-of-use';
|
||||
}
|
||||
|
||||
setLoginStatus(): void {
|
||||
const cookies = document.cookie;
|
||||
const seleneTokenExists = cookies.includes('seleneToken');
|
||||
const seleneTokenEmpty = cookies.includes('seleneToken=""');
|
||||
this.isLoggedIn = seleneTokenExists && !seleneTokenEmpty;
|
||||
}
|
||||
|
||||
buildAccountNav() {
|
||||
const accountNav: PrimaryNavItem = {
|
||||
icon: faUser,
|
||||
text: 'Account'
|
||||
};
|
||||
if (this.isLoggedIn) {
|
||||
accountNav.children = [
|
||||
{text: 'Devices', url: this.environment.accountUrl + '/#/device'},
|
||||
{text: 'Profile', url: this.environment.accountUrl + '/#/profile'},
|
||||
{text: 'Skill Settings', url: this.environment.accountUrl + '/#/skill'},
|
||||
{text: 'Subscription', url: this.environment.accountUrl + '/#/account'},
|
||||
{text: 'User Settings', url: this.environment.accountUrl + '/#/setting/basic'},
|
||||
{text: 'Logout', url: this.environment.singleSignOnUrl + '/logout?redirect=' + window.location.href}
|
||||
];
|
||||
} else {
|
||||
accountNav.children = [
|
||||
{text: 'Log In', url: this.environment.singleSignOnUrl + '/login?redirect=' + window.location.href},
|
||||
{text: 'Sign Up', url: this.environment.singleSignOnUrl + '/signup'}
|
||||
];
|
||||
}
|
||||
this.navigationItems.push(accountNav);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
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 { MatSidenavModule } from '@angular/material/sidenav';
|
||||
|
||||
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||
|
||||
import { GlobalnavComponent } from './globalnav.component';
|
||||
import { GlobalnavService } from './globalnav.service';
|
||||
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,
|
||||
MatSidenavModule
|
||||
],
|
||||
declarations: [
|
||||
GlobalnavComponent,
|
||||
NavItemComponent,
|
||||
PrimaryNavItemComponent,
|
||||
FooterComponent
|
||||
],
|
||||
exports: [
|
||||
GlobalnavComponent
|
||||
],
|
||||
providers: [
|
||||
GlobalnavService
|
||||
]
|
||||
})
|
||||
export class GlobalnavModule { }
|
|
@ -0,0 +1,25 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { IconDefinition } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
export interface NavItem {
|
||||
text: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface PrimaryNavItem {
|
||||
children?: NavItem[];
|
||||
icon: IconDefinition;
|
||||
text: string;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class GlobalnavService {
|
||||
|
||||
constructor() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
<mat-list-item (click)="navigateToUrl()">
|
||||
<div fxLayout="row" [ngStyle]="navItemStyle">
|
||||
<span fxFlex="20"></span>
|
||||
<span fxFlex class="mat-body-1">{{item.text}}</span>
|
||||
</div>
|
||||
</mat-list-item>
|
|
@ -0,0 +1,4 @@
|
|||
.mat-list-item {
|
||||
height: 30px;
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
|
||||
import { NavItem } from '../globalnav.service';
|
||||
|
||||
@Component({
|
||||
selector: 'globalnav-nav-item',
|
||||
templateUrl: './nav-item.component.html',
|
||||
styleUrls: ['./nav-item.component.scss']
|
||||
})
|
||||
export class NavItemComponent implements OnInit {
|
||||
@Input() item: NavItem;
|
||||
public navItemStyle: object;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.buildNavItemStyle();
|
||||
}
|
||||
|
||||
buildNavItemStyle() {
|
||||
this.navItemStyle = {'width': '100%'};
|
||||
if (window.location.href.includes(this.item.url)) {
|
||||
this.navItemStyle['background-color'] = '#22a7f0';
|
||||
this.navItemStyle['color'] = 'white';
|
||||
this.navItemStyle['border-radius'] = '4px';
|
||||
}
|
||||
}
|
||||
navigateToUrl() {
|
||||
window.location.assign(this.item.url);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<mat-list-item (click)="onItemSelected()" class="nav-item">
|
||||
<div fxLayout="row" style="width: 100%;">
|
||||
<fa-icon fxFlex="20" [icon]="primaryNavItem.icon" class="nav-item-icon"></fa-icon>
|
||||
<span fxFlex>
|
||||
{{primaryNavItem.text}}
|
||||
</span>
|
||||
</div>
|
||||
</mat-list-item>
|
||||
<div *ngIf="expanded">
|
||||
<globalnav-nav-item
|
||||
*ngFor="let child of primaryNavItem.children"
|
||||
[item]="child"
|
||||
>
|
||||
</globalnav-nav-item>
|
||||
</div>
|
|
@ -0,0 +1,7 @@
|
|||
.nav-item:hover {
|
||||
background-color: #e4f1fe;
|
||||
}
|
||||
|
||||
.nav-item-icon {
|
||||
color: #22a7f0;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
|
||||
import { PrimaryNavItem } from '../globalnav.service';
|
||||
|
||||
@Component({
|
||||
selector: 'globalnav-primary-nav-item',
|
||||
templateUrl: './primary-nav-item.component.html',
|
||||
styleUrls: ['./primary-nav-item.component.scss']
|
||||
})
|
||||
export class PrimaryNavItemComponent implements OnInit {
|
||||
public expanded = false;
|
||||
@Input() primaryNavItem: PrimaryNavItem;
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
this.expandCurrentLocation();
|
||||
}
|
||||
|
||||
expandCurrentLocation() {
|
||||
if (this.primaryNavItem.children && this.primaryNavItem.children.length) {
|
||||
this.primaryNavItem.children.forEach(
|
||||
(navItem) => {
|
||||
if (window.location.href.includes(navItem.url)) {
|
||||
this.expanded = true;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
onItemSelected() {
|
||||
if (this.primaryNavItem.children && this.primaryNavItem.children.length) {
|
||||
this.expanded = !this.expanded;
|
||||
} else {
|
||||
window.location.assign(this.primaryNavItem.url);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 1181 212" style="enable-background:new 0 0 1181 212;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#22A7F0;}
|
||||
.st1{fill:#FFFFFF;}
|
||||
.st2{fill:#2C3E50;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st2" d="M50.5,81l41.3,91.7L133.2,81c1.5-3.3,4.8-5.5,8.5-5.5h0.2c5.1,0,9.3,4.2,9.3,9.3v98.3c0,3.2-2.6,5.8-5.8,5.8h0
|
||||
c-3.2,0-5.8-2.6-5.8-5.8v-40.6l1.1-52.8L98,184.9c-1.1,2.4-3.5,4-6.2,4h0c-2.7,0-5.1-1.6-6.2-4L43.3,90.3l1.1,52.2v40.6
|
||||
c0,3.2-2.6,5.8-5.8,5.8h0c-3.2,0-5.8-2.6-5.8-5.8V84.8c0-5.1,4.2-9.3,9.3-9.3h0C45.7,75.6,49,77.7,50.5,81z"/>
|
||||
<path class="st2" d="M232.5,137.4L267,78.4c1-1.7,2.9-2.8,4.9-2.8h0c4.4,0,7.1,4.8,4.9,8.6l-38.5,63.6v35.3c0,3.2-2.6,5.8-5.8,5.8
|
||||
h0c-3.2,0-5.8-2.6-5.8-5.8v-35.8l-38.2-63.1c-2.3-3.8,0.4-8.6,4.9-8.6h0c2,0,3.9,1.1,4.9,2.8L232.5,137.4z"/>
|
||||
<path class="st2" d="M394.3,153.2c3.7,0,6.5,3.4,5.6,7c-2.1,8.6-6.4,15.5-12.6,20.6c-7.9,6.4-18.3,9.6-31.4,9.6
|
||||
c-13.8,0-24.9-4.6-33.4-13.9c-8.5-9.3-12.8-22.1-12.8-38.3v-12.5c0-10.2,1.9-19.3,5.8-27.2c3.9-7.9,9.3-13.9,16.4-18.2
|
||||
c7.1-4.2,15.3-6.4,24.6-6.4c13,0,23.3,3.3,31,9.8c6.1,5.2,10.3,12.1,12.4,20.8c0.9,3.6-2,7-5.6,7h0c-2.7,0-5-1.8-5.6-4.4
|
||||
c-1.6-6.7-4.5-12-8.8-15.9c-5.3-4.8-13-7.1-23.3-7.1c-10.9,0-19.5,3.7-25.8,11.1c-6.3,7.4-9.4,17.7-9.4,30.9v12.8
|
||||
c0,12.9,3.1,23.1,9.3,30.5c6.2,7.5,14.6,11.2,25.3,11.2c10.4,0,18.3-2.3,23.7-6.8c4.5-3.8,7.5-9.2,9.1-16.2
|
||||
C389.3,155,391.6,153.2,394.3,153.2L394.3,153.2z"/>
|
||||
<path class="st2" d="M486.2,143.4h-34.4v39.7c0,3.2-2.6,5.8-5.8,5.8h0c-3.2,0-5.8-2.6-5.8-5.8V75.6h40.2c13,0,23.2,3,30.6,9.1
|
||||
c7.4,6.1,11,14.5,11,25.1c0,7.5-2.3,14-6.8,19.5c-4.5,5.5-10.5,9.4-18,11.4l25.1,39.5c2.2,3.5-0.1,8.1-4.2,8.4l0,0
|
||||
c-2,0.2-4-0.8-5.1-2.6L486.2,143.4z M451.7,133.4h30.7c8.4,0,15.2-2.2,20.2-6.5c5.1-4.3,7.6-9.9,7.6-16.8c0-7.6-2.6-13.5-7.8-17.9
|
||||
c-5.2-4.3-12.5-6.5-21.8-6.6h-28.9V133.4z"/>
|
||||
<path class="st2" d="M789.9,137h-51.2v46.1c0,3.2-2.6,5.8-5.8,5.8l0,0c-3.2,0-5.8-2.6-5.8-5.8V75.6h70.9c2.7,0,5,2.2,5,5v0.2
|
||||
c0,2.7-2.2,5-5,5h-59.3v41.4h51.2c2.7,0,5,2.2,5,5v0C794.9,134.8,792.7,137,789.9,137z"/>
|
||||
<path class="st2" d="M916.8,85.7h-36.4v97.4c0,3.2-2.6,5.8-5.8,5.8l0,0c-3.2,0-5.8-2.6-5.8-5.8V85.7h-36.3c-2.8,0-5.1-2.3-5.1-5.1
|
||||
v0c0-2.8,2.3-5.1,5.1-5.1h84.3c2.8,0,5.1,2.3,5.1,5.1v0C921.8,83.4,919.6,85.7,916.8,85.7z"/>
|
||||
<path class="st2" d="M1085.8,158.6h-55l-10.7,26.8c-0.8,2.1-2.9,3.5-5.1,3.5h-0.1c-3.9,0-6.6-4-5.1-7.6l40.9-100.6
|
||||
c1.3-3.1,4.3-5.2,7.7-5.2l0,0c3.4,0,6.4,2.1,7.7,5.2l40.6,100.5c1.5,3.6-1.2,7.6-5.1,7.6l0,0c-2.3,0-4.3-1.4-5.1-3.5L1085.8,158.6z
|
||||
M1034.7,148.7h47.1l-23.4-59.3L1034.7,148.7z"/>
|
||||
<path class="st2" d="M1150.2,188.9L1150.2,188.9c-3.2,0-5.8-2.6-5.8-5.8V81.4c0-3.2,2.6-5.8,5.8-5.8l0,0c3.2,0,5.8,2.6,5.8,5.8
|
||||
v101.7C1156,186.3,1153.4,188.9,1150.2,188.9z"/>
|
||||
<g>
|
||||
<path class="st0" d="M623.4,66.2c-36.1,0-65.3,29.2-65.3,65.3s29.2,65.3,65.3,65.3s65.3-29.2,65.3-65.3S659.4,66.2,623.4,66.2z
|
||||
M623.4,186.7c-30.5,0-55.2-24.8-55.2-55.2c0-30.5,24.8-55.2,55.2-55.2s55.2,24.8,55.2,55.2C678.6,162,653.8,186.7,623.4,186.7z"
|
||||
/>
|
||||
<path class="st0" d="M577.9,131.5c0,25.1,20.3,45.4,45.4,45.4V86.1C598.3,86.1,577.9,106.4,577.9,131.5z"/>
|
||||
<circle class="st0" cx="623.4" cy="37.8" r="11.6"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.3 KiB |
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Public API Surface of globalnav
|
||||
*/
|
||||
|
||||
export * from './lib/globalnav.service';
|
||||
export * from './lib/globalnav.component';
|
||||
export * from './lib/globalnav.module';
|
|
@ -0,0 +1,22 @@
|
|||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'core-js/es7/reflect';
|
||||
import 'zone.js/dist/zone';
|
||||
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);
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"module": "es2015",
|
||||
"moduleResolution": "node",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"inlineSources": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"importHelpers": true,
|
||||
"types": [],
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2018"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"annotateForClosureCompiler": true,
|
||||
"skipTemplateCodegen": true,
|
||||
"strictMetadataEmit": true,
|
||||
"fullTemplateTypeCheck": true,
|
||||
"strictInjectionParameters": true,
|
||||
"enableResourceInlining": true
|
||||
},
|
||||
"exclude": [
|
||||
"src/test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"src/test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../tslint.json",
|
||||
"rules": {
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"globalnav",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"globalnav",
|
||||
"kebab-case"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,4 +1,9 @@
|
|||
<market-header></market-header>
|
||||
<div class="app-body">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
<globalnav-sidenav [environment]="environment">
|
||||
<!--
|
||||
Inject the marketplace app into the <mat-sidenav-content> component
|
||||
of the global navigation menu library.
|
||||
-->
|
||||
<div appBody class="app-body">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</globalnav-sidenav>
|
||||
|
|
|
@ -5,3 +5,8 @@
|
|||
margin-right: 3vw;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 20px;
|
||||
margin-top: -7px;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,18 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
import { environment } from '../environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'market-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss']
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
constructor() { }
|
||||
ngOnInit() { }
|
||||
public environment = environment;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,8 @@ import { NgModule } from '@angular/core';
|
|||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { HeaderModule } from './header/header.module';
|
||||
import { GlobalnavModule } from 'globalnav';
|
||||
import { MaterialModule } from './shared/material.module';
|
||||
import { LoginService } from './shared/login.service';
|
||||
import { SkillsModule } from './skills/skills.module';
|
||||
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';
|
||||
|
||||
|
@ -17,13 +16,13 @@ import { PageNotFoundComponent } from './page-not-found/page-not-found.component
|
|||
imports: [
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
GlobalnavModule,
|
||||
HttpClientModule,
|
||||
HeaderModule,
|
||||
MaterialModule,
|
||||
SkillsModule,
|
||||
AppRoutingModule
|
||||
],
|
||||
providers: [ LoginService ],
|
||||
providers: [ ],
|
||||
bootstrap: [ AppComponent ]
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
<mat-toolbar>
|
||||
<img src="../../assets/header-logo.svg">
|
||||
<fa-icon class='separator' [icon]="separatorIcon"></fa-icon>
|
||||
<div class="mat-subheading-1" style="margin-bottom: 0">MARKETPLACE</div>
|
||||
|
||||
<div fxFlex fxLayout="row" fxLayoutAlign="end center">
|
||||
<button mat-button (click)="login()" *ngIf="!isLoggedIn">
|
||||
<fa-icon [icon]="signInIcon"></fa-icon>
|
||||
LOG IN
|
||||
</button>
|
||||
<button mat-button class="menu-button" [matMenuTriggerFor]="menu" *ngIf="isLoggedIn">
|
||||
{{userMenuButtonText}}
|
||||
<fa-icon [icon]="menuButtonIcon"></fa-icon>
|
||||
</button>
|
||||
<mat-menu [overlapTrigger]="false" #menu="matMenu">
|
||||
<button mat-menu-item (click)="logout()">
|
||||
<fa-icon [icon]="signOutIcon"></fa-icon>
|
||||
Logout
|
||||
</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
</mat-toolbar>
|
|
@ -1,26 +0,0 @@
|
|||
@import '../../stylesheets/global';
|
||||
|
||||
mat-toolbar {
|
||||
background-color: $mycroft-primary;
|
||||
color: $mycroft-white;
|
||||
img {
|
||||
height: 20px;
|
||||
margin-top: -7px;
|
||||
}
|
||||
.separator {
|
||||
font-size: 5px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
.mat-subheading-1 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
fa-icon {
|
||||
padding-right: 5px;
|
||||
}
|
||||
.menu-button {
|
||||
fa-icon {
|
||||
padding-left: 5px;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Subscription } from 'rxjs/internal/Subscription';
|
||||
|
||||
import {
|
||||
faCaretDown,
|
||||
faCircle,
|
||||
faSignInAlt,
|
||||
faSignOutAlt
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
import { InstallService } from '../skills/install.service';
|
||||
import { LoginService } from '../shared/login.service';
|
||||
|
||||
@Component({
|
||||
selector: 'market-header',
|
||||
templateUrl: './header.component.html',
|
||||
styleUrls: ['./header.component.scss']
|
||||
})
|
||||
export class HeaderComponent implements OnInit, OnDestroy {
|
||||
public isLoggedIn: boolean;
|
||||
private loginStatus: Subscription;
|
||||
public separatorIcon = faCircle;
|
||||
public signInIcon = faSignInAlt;
|
||||
public signOutIcon = faSignOutAlt;
|
||||
public menuButtonIcon = faCaretDown;
|
||||
public userMenuButtonText: string;
|
||||
|
||||
constructor(
|
||||
private installService: InstallService,
|
||||
private loginService: LoginService
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.loginStatus = this.loginService.isLoggedIn.subscribe(
|
||||
(isLoggedIn) => { this.onLoginStateChange(isLoggedIn); }
|
||||
);
|
||||
this.loginService.setLoginStatus();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.loginStatus.unsubscribe();
|
||||
}
|
||||
|
||||
onLoginStateChange(isLoggedIn) {
|
||||
this.isLoggedIn = isLoggedIn;
|
||||
if (isLoggedIn) {
|
||||
this.loginService.getUser().subscribe(
|
||||
(user) => { this.userMenuButtonText = user.name; }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
login() {
|
||||
this.loginService.login();
|
||||
}
|
||||
|
||||
logout() {
|
||||
this.loginService.logout();
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
|
||||
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||
|
||||
import { InstallService } from '../skills/install.service';
|
||||
import { HeaderComponent } from './header.component';
|
||||
import { MaterialModule } from '../shared/material.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FlexLayoutModule,
|
||||
FontAwesomeModule,
|
||||
MaterialModule
|
||||
],
|
||||
declarations: [ HeaderComponent],
|
||||
exports: [ HeaderComponent ],
|
||||
providers: [ InstallService ]
|
||||
})
|
||||
export class HeaderModule { }
|
|
@ -1,15 +0,0 @@
|
|||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { LoginService } from './login.service';
|
||||
|
||||
describe('LoginService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [LoginService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([LoginService], (service: LoginService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
|
@ -1,41 +0,0 @@
|
|||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { Subject } from 'rxjs/internal/Subject';
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
const redirectQuery = '?redirect=';
|
||||
export class User {
|
||||
name: string;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class LoginService {
|
||||
public isLoggedIn = new Subject<boolean>();
|
||||
public loginUrl: string = environment.loginUrl + '/login';
|
||||
private logoutUrl = environment.loginUrl + '/logout';
|
||||
private userUrl = '/api/user';
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
}
|
||||
|
||||
getUser(): Observable<User> {
|
||||
return this.http.get<User>(this.userUrl);
|
||||
}
|
||||
|
||||
setLoginStatus(): void {
|
||||
const cookies = document.cookie;
|
||||
const seleneTokenExists = cookies.includes('seleneToken');
|
||||
const seleneTokenEmpty = cookies.includes('seleneToken=""');
|
||||
this.isLoggedIn.next( seleneTokenExists && !seleneTokenEmpty);
|
||||
}
|
||||
|
||||
login(): void {
|
||||
window.location.assign(this.loginUrl + redirectQuery + window.location.href);
|
||||
}
|
||||
|
||||
logout(): void {
|
||||
window.location.assign(this.logoutUrl + redirectQuery + window.location.href);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,10 @@
|
|||
export const environment = {
|
||||
production: false,
|
||||
loginUrl: 'http://login.mycroft.test'
|
||||
chatUrl: 'https://chat.mycroft.ai',
|
||||
forumUrl: 'https://forum.mycroft.ai',
|
||||
singleSignOnUrl: 'http://sso.mycroft.test',
|
||||
accountUrl: 'https://home-test.mycroft.ai',
|
||||
marketplaceUrl: 'http://market.mycroft.test',
|
||||
translateUrl: 'https://translate-test.mycroft.ai',
|
||||
wordpressUrl: 'https://test.mycroft.ai'
|
||||
};
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
export const environment = {
|
||||
production: true,
|
||||
loginUrl: 'https://login.mycroft.ai'
|
||||
chatUrl: 'https://chat.mycroft.ai',
|
||||
forumUrl: 'https://forum.mycroft.ai',
|
||||
singleSignOnUrl: 'https://sso.mycroft.ai',
|
||||
accountUrl: 'https://home.mycroft.ai',
|
||||
marketplaceUrl: 'https://market.mycroft.ai',
|
||||
translateUrl: 'https://translate.mycroft.ai',
|
||||
wordpressUrl: 'https://test.mycroft.ai'
|
||||
};
|
||||
|
||||
document.write(
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
export const environment = {
|
||||
production: false,
|
||||
loginUrl: 'https://login.mycroft-test.net'
|
||||
chatUrl: 'https://chat.mycroft.ai',
|
||||
forumUrl: 'https://forum.mycroft.ai',
|
||||
singleSignOnUrl: 'https://sso.mycroft-test.net',
|
||||
accountUrl: 'https://home-test.mycroft.ai',
|
||||
marketplaceUrl: 'https://market.mycroft-test.net',
|
||||
translateUrl: 'https://translate-test.mycroft.ai',
|
||||
wordpressUrl: 'https://test.mycroft.ai'
|
||||
};
|
||||
|
|
|
@ -4,8 +4,13 @@
|
|||
|
||||
export const environment = {
|
||||
production: false,
|
||||
apiUrl: 'http://localhost:5002',
|
||||
loginUrl: 'http://localhost:4201'
|
||||
chatUrl: 'https://chat.mycroft.ai',
|
||||
forumUrl: 'https://forum.mycroft.ai',
|
||||
singleSignOnUrl: 'http://localhost:4201',
|
||||
accountUrl: 'https://home-test.mycroft.ai',
|
||||
marketplaceUrl: 'http://localhost:4202',
|
||||
translateUrl: 'https://translate-test.mycroft.ai',
|
||||
wordpressUrl: 'https://test.mycroft.ai'
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -16,6 +16,14 @@
|
|||
"lib": [
|
||||
"es2018",
|
||||
"dom"
|
||||
]
|
||||
],
|
||||
"paths": {
|
||||
"globalnav": [
|
||||
"dist/globalnav"
|
||||
],
|
||||
"globalnav/*": [
|
||||
"dist/globalnav/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue