Face lift

This commit is contained in:
Zakary Timson 2018-07-03 10:10:47 -04:00
parent 3ad6de5b6c
commit fb459928c4
31 changed files with 427 additions and 110 deletions

View File

@ -19,7 +19,8 @@
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"assets": [
"src/assets"
"src/assets",
"src/manifest.json"
],
"styles": [
"src/assets/css/base.scss"
@ -42,7 +43,8 @@
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true
"buildOptimizer": true,
"serviceWorker": true
}
}
},
@ -75,7 +77,8 @@
],
"scripts": [],
"assets": [
"src/assets"
"src/assets",
"src/manifest.json"
]
}
},
@ -117,4 +120,4 @@
}
},
"defaultProject": "fhsons"
}
}

20
ngsw-config.json Normal file
View File

@ -0,0 +1,20 @@
{
"index": "/index.html",
"assetGroups": [
{
"name": "app",
"installMode": "prefetch",
"resources": {
"files": ["/index.html", "/*.css", "/*.js"]
}
},
{
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch",
"resources": {
"files": ["/assets/**"]
}
}
]
}

View File

@ -21,6 +21,7 @@
"@angular/material": "^6.3.0",
"@angular/platform-browser": "^6.0.0",
"@angular/platform-browser-dynamic": "^6.0.0",
"@angular/pwa": "^0.6.8",
"@angular/router": "^6.0.0",
"angularfire2": "^5.0.0-rc.11",
"core-js": "^2.5.4",
@ -28,7 +29,8 @@
"firebase-tools": "^3.19.0",
"hammerjs": "^2.0.8",
"rxjs": "^6.0.0",
"zone.js": "^0.8.26"
"zone.js": "^0.8.26",
"@angular/service-worker": "^6.0.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.6.0",
@ -51,4 +53,4 @@
"tslint": "~5.9.1",
"typescript": "~2.7.2"
}
}
}

View File

@ -1,33 +1,93 @@
<!-- Nav -->
<nav class="navbar navbar-expand-lg fixed-top navbar-light bg-light">
<div class="container">
<a class="navbar-brand roboto" [routerLink]="['/']">
fh
<span class="rainbow">&</span> sons
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar" aria-expanded="false">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbar">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" [routerLink]="['/about']">About</a>
</li>
<li class="nav-item">
<a class="nav-link" [routerLink]="['/store']">Store</a>
</li>
<li class="nav-item">
<a class="nav-link" [routerLink]="['/formulaManager']">Formula Manager</a>
</li>
</ul>
<button mat-stroked-button class="ml-auto" color="primary" data-toggle="modal" data-target="#loginModal">Login</button>
</div>
</div>
</nav>
<!-- Content -->
<div>
<div *ngFor="let f of formulas | async">
<button (click)="displayFormula(f)">{{f.name}}</button>
</div>
<div *ngIf="formula">
<table class="table">
<thead>
<tr>
<td>Name</td>
<td>Quantity</td>
<td>Cost</td>
</tr>
</thead>
<tbody>
<tr *ngFor="let c of formula.components">
<td>{{(c.component | async)?.name}}</td>
<td>{{c.quantity | scale: formula.total : _newTotal | convertFromG: unit}} {{unit}}</td>
<td>{{(c.component | async)?.cost | currency}}</td>
</tbody>
</table>
<mat-form-field style="width: 75px">
<input matInput type="number" placeholder="Yield" [(ngModel)]="newTotal">
</mat-form-field>
<mat-form-field style="width: 40px">
<mat-select placeholder="Unit" [(ngModel)]="unit">
<mat-option value="g">g</mat-option>
<mat-option value="oz">oz</mat-option>
<mat-option value="kg">kg</mat-option>
<mat-option value="lb">lb</mat-option>
</mat-select>
</mat-form-field>
</div>
<div style="height: 56px"></div>
<router-outlet></router-outlet>
</div>
<!-- Footer -->
<footer>
<div class="container-fluid bg-light">
<div class="container">
<div class="d-inline-block py-3">
<div class="d-inline-block mr-5">
<h5>MAIN MENU</h5>
<ul style="padding-left: 20px;">
<li>
<a [routerLink]="['/about']">About</a>
</li>
<li>
<a [routerLink]="['/store']">Store</a>
</li>
<li>
<a [routerLink]="['/formulaManager']">Formula Manager</a>
</li>
</ul>
</div>
<div class="d-inline-block mx-5">
<h5>PRODUCTS</h5>
</div>
<div class="d-inline-block ml-5">
<h5>REVIEWS</h5>
</div>
</div>
</div>
</div>
<div class="container-fluid bg-white">
<div class="container text-center">
<p class="mb-0 p-2">© 2018 fh & sons. Created By
<a href="http://zakscode.com">Zak Timson</a>
</p>
</div>
</div>
</footer>
<!-- Login Modal -->
<div class="modal fade" id="loginModal" tabindex="-1" role="dialog" aria-labelledby="loginModal" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Login</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div id="incorrectAlert" class="alert alert-danger collapse" role="alert">Username or password is incorrect.</div>
<input id="username" class="form-control mb-3" placeholder="Username">
<input id="password" class="form-control" type="password" placeholder="Password">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button id="loginBtn" type="button" class="btn btn-primary">Login</button>
</div>
</div>
</div>
</div>

View File

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

View File

@ -1,41 +1,7 @@
import {Component} from '@angular/core';
import {AngularFirestore} from 'angularfire2/firestore';
import {share} from 'rxjs/operators';
import {ConvertFromGPipe, ConvertToGPipe} from './units.pipe';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
templateUrl: 'app.component.html'
})
export class AppComponent {
formulas;
formula;
components;
unit = 'g';
_newTotal: number = 0;
get newTotal() {
return new ConvertFromGPipe().transform(this._newTotal, this.unit);
}
set newTotal(total) {
this._newTotal = new ConvertToGPipe().transform(total, this.unit);
}
constructor(private db: AngularFirestore) {
this.formulas = this.db.collection('formulas').valueChanges();
}
displayFormula(formula) {
formula.components.map(
row =>
(row.component = this.db
.doc(`components/${row.component.id}`)
.valueChanges()
.pipe(share()))
);
formula.total = formula.components.reduce((acc, row) => (acc += row.quantity), 0);
this.newTotal = formula.total;
this.formula = formula;
}
}
export class AppComponent {}

View File

@ -1,17 +1,20 @@
import {BrowserModule} from '@angular/platform-browser';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {RouterModule} from '@angular/router';
import {AngularFireModule} from 'angularfire2';
import {AngularFirestoreModule} from 'angularfire2/firestore';
import {NgModule} from '@angular/core';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {AppComponent} from './app.component';
import {environment} from '../environments/environment.prod';
import {ConvertFromGPipe, ConvertToGPipe} from './units.pipe';
import {ScalePipe} from './scale.pipe';
import {environment} from '../environments/environment';
import {ConvertFromGPipe, ConvertToGPipe} from './formulaManager/units.pipe';
import {ScalePipe} from './formulaManager/scale.pipe';
import {AngularMaterialModule} from './material.module';
import {HomeComponent} from './home/home.component';
import { ServiceWorkerModule } from '@angular/service-worker';
@NgModule({
declarations: [AppComponent, ConvertFromGPipe, ConvertToGPipe, ScalePipe],
declarations: [AppComponent, ConvertFromGPipe, ConvertToGPipe, HomeComponent, ScalePipe],
imports: [
AngularMaterialModule,
AngularFireModule.initializeApp(environment.firebase),
@ -19,7 +22,9 @@ import {AngularMaterialModule} from './material.module';
BrowserAnimationsModule,
BrowserModule,
FormsModule,
ReactiveFormsModule
ReactiveFormsModule,
RouterModule.forRoot([{path: '**', component: HomeComponent}]),
ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production })
],
providers: [],
bootstrap: [AppComponent]

View File

@ -0,0 +1,52 @@
<mat-drawer-container class="h-100">
<mat-drawer mode="push" [opened]="true" style="width: 400px">
<mat-list>
<ng-container *ngFor="let f of formulas | async; let i = index">
<mat-divider *ngIf="i > 0"></mat-divider>
<mat-list-item (click)="displayFormula(f)">{{f.name}}</mat-list-item>
</ng-container>
</mat-list>
</mat-drawer>
<mat-drawer-content>
<div *ngIf="formula">
<table class="w-100 table">
<thead>
<tr>
<td style="width: 10%">Name</td>
<td style="width: 10%">Quantity</td>
<td style="width: 10%">Cost</td>
</tr>
</thead>
<tbody>
<tr *ngFor="let c of formula.components">
<td style="width: 80%">{{c.component?.name}}</td>
<td style="width: 10%">{{c.quantity | scale: formula.total : _newTotal | convertFromG: unit}} {{unit}}</td>
<td style="width: 10%">{{c.quantity | scale: formula.total : _newTotal / 1000 * c.component.cost | currency}}</td>
</tbody>
</table>
<table class="w-100 mt-5">
<tr>
<td style="width: 80%"></td>
<td style="width: 10%">
<mat-form-field style="width: 75px">
<input matInput type="number" placeholder="Yield" [(ngModel)]="newTotal">
</mat-form-field>
<mat-form-field style="width: 40px">
<mat-select placeholder="Unit" [(ngModel)]="unit">
<mat-option value="g">g</mat-option>
<mat-option value="oz">oz</mat-option>
<mat-option value="kg">kg</mat-option>
<mat-option value="lb">lb</mat-option>
</mat-select>
</mat-form-field>
</td>
<td style="width: 10%">
<mat-form-field>
<input matInput placeholder="Cost" [value]="cost() | currency" [readonly]="true">
</mat-form-field>
</td>
</tr>
</table>
</div>
</mat-drawer-content>
</mat-drawer-container>

View File

@ -0,0 +1,59 @@
import {Component, ElementRef, ViewChildren} from '@angular/core';
import {AngularFirestore} from 'angularfire2/firestore';
import {share} from 'rxjs/operators';
import {ConvertFromGPipe, ConvertToGPipe} from './units.pipe';
@Component({
selector: 'formula-manager',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
@ViewChildren('cost') componentCosts: ElementRef[];
formulas;
formula;
components;
unit = 'g';
_newTotal: number = 0;
get newTotal() {
return new ConvertFromGPipe().transform(this._newTotal, this.unit);
}
set newTotal(total) {
this._newTotal = new ConvertToGPipe().transform(total, this.unit);
}
constructor(private db: AngularFirestore) {
this.db.firestore.enablePersistence();
this.formulas = this.db.collection('formulas').valueChanges();
}
displayFormula(formula) {
formula.components.forEach((row, i, arr) => row.component.get().then(row => (arr[i].component = row.data())));
formula.total = formula.components.reduce((acc, row) => (acc += row.quantity), 0);
this.newTotal = formula.total;
this.formula = formula;
}
create(row: string) {
let data = new RegExp(/(.+?)\t(.+?)\t(.+?)\t\$(\d\.\d\d)\s*?(\w.*)/).exec(row);
this.db.collection('components').add({
name: data[1],
vendor: 'GCm9FzeJ8NNpBl6G9BCu',
description: data[3],
cost: data[4],
created: new Date(data[5])
});
}
cost() {
console.log(
this.componentCosts.reduce((acc, row) => {
console.log(row.nativeElement.html);
//acc + Number(new RegExp(/\$(\d+\.\d+)/).exec(row.nativeElement.innerHtml)[1])
return acc;
}, 0)
);
}
}

View File

@ -0,0 +1,99 @@
<div class="container-fluid m-0 p-0">
<div class="row m-0">
<img src="assets/img/banner.jpg" style="width:100%; height: auto;">
</div>
</div>
<div class="container-fluid m-0 p-0 bg-light">
<div class="container py-5">
<div class="row py-5">
<div class="col-12 col-md-4 text-center">
<a style="max-width: 20rem" [routerLink]="['/about']">
<mat-icon style="font-size: 75px;">help_outline</mat-icon>
<h3 class="text-dark">About Us</h3>
<p class="text-muted">Learn more about us and our 30+ years experience!</p>
</a>
</div>
<div class="col-12 col-md-4 text-center">
<a style="max-width: 20rem" [routerLink]="['/store']">
<mat-icon style="font-size: 75px;">local_grocery_store</mat-icon>
<h3 class="text-dark">Store</h3>
<p class="text-muted">Buy equipment, ink and anything else you might need!</p>
</a>
</div>
<div class="col-12 col-md-4 text-center">
<a style="max-width: 20rem" [routerLink]="['/formulaManager']">
<mat-icon style="font-size: 75px;">opacity</mat-icon>
<h3 class="text-dark">Formula Manager</h3>
<p class="text-muted">Check out our browser formula manager!</p>
</a>
</div>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row">
<div class="col p-0" style="position: relative">
<div class="d-inline-block" style="position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%)">
<h2 class="d-none d-lg-inline">Free Shipping</h2>
<div class="">
<br>
<p class="d-inline">We accept Visa, MasterCard & American Express at check-out. You must contact us within 5 days of purchase
at info@fhsons.com to return purchased items.</p>
</div>
</div>
</div>
<div class="col p-0">
<img src="/assets/img/shipping.png" style="width: 100%; height: auto">
</div>
</div>
<div class="row">
<div class="col p-0">
<div class="row m-0">
<div class="col p-0">
<img src="assets/img/partners/m&r.png" style="width: 100%; height: auto">
</div>
<div class="col p-0">
<img src="assets/img/partners/soba.png" style="width: 100%; height: auto">
</div>
<div class="col p-0">
<img src="assets/img/partners/rhinotech.png" style="width: 100%; height: auto">
</div>
</div>
<div class="row m-0">
<div class="col p-0">
<img src="assets/img/partners/chromatex.png" style="width: 100%; height: auto">
</div>
<div class="col p-0">
<img src="assets/img/partners/actionengineering.png" style="width: 100%; height: auto">
</div>
<div class="col p-0">
<img src="assets/img/partners/bbc.png" style="width: 100%; height: auto">
</div>
</div>
<div class="row m-0">
<div class="col p-0">
<img src="assets/img/partners/amrep.png" style="width: 100%; height: auto">
</div>
<div class="col p-0">
<img src="assets/img/partners/chromaline.png" style="width: 100%; height: auto">
</div>
<div class="col p-0">
<img src="assets/img/partners/printersedge.png" style="width: 100%; height: auto">
</div>
</div>
</div>
<div class="col p-0" style="position: relative">
<div class="d-inline-block" style="position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%)">
<h2 class="d-none d-lg-inline">Proud Distributor</h2>
<div class="">
<br>
<p class="d-inline">We proudly distribute products for these screen printing industry leaders.</p>
</div>
</div>
</div>
</div>
</div>
<div class="container-fluid px-0" style="width: 100%; height: 400px">
<iframe style="width: 100%; height: 100%;" src="https://www.google.com/maps/embed?pb=!1m14!1m8!1m3!1d11529.15485962886!2d-79.6054727!3d43.746101!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x0%3A0x55ebba8b241a8cc!2sFH+%26+Son&#39;s+Mfg+Ltd!5e0!3m2!1sen!2sca!4v1526647428011"
frameborder="0"></iframe>
</div>

View File

@ -0,0 +1,7 @@
import {Component} from '@angular/core';
@Component({
selector: 'home',
templateUrl: './home.component.html'
})
export class HomeComponent {}

View File

@ -1 +1,23 @@
@import '~@angular/material/prebuilt-themes/indigo-pink.css';
@import url('https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css');
@import url('https://fonts.googleapis.com/css?family=Roboto+Condensed');
@import url('https://fonts.googleapis.com/icon?family=Material+Icons');
html,
body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
.rainbow {
background: linear-gradient(to top, black, black, yellow, magenta, blue, blue);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.roboto {
font-family: 'Roboto Condensed', sans-serif;
}

BIN
src/assets/img/banner.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

BIN
src/assets/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1016 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

BIN
src/assets/img/shipping.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -1,15 +1,29 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Fhsons</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="FH & Sons has been in business for 40 years. We have been ISO 9001:2000 certified since May 2000. Our company manufactures
plastisol silk screen inks, plastisols for moulding and dipping applications, as well as bulk pigment dispersions. We also
distribute for several top end equipment and chemical manufacturers. We strive to provide value in everything we sell, coupled
with unmatched customer service and guidance.">
<title>fh & sons</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css">
<link rel="icon" type="image/png" href="assets/img/logo.png">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.1/js/bootstrap.min.js"></script>
<link rel="manifest" href="manifest.json">
<meta name="theme-color" content="#1976d2">
</head>
<body>
<app-root></app-root>
</body>
</html>
</html>

16
src/manifest.json Normal file
View File

@ -0,0 +1,16 @@
{
"name": "fh & sons",
"short_name": "fh & sons",
"theme_color": "#f8f9fa",
"background_color": "#fafafa",
"display": "standalone",
"scope": "/",
"start_url": "/",
"icons": [
{
"src": "assets/img/logo.png",
"sizes": "64x64",
"type": "image/png"
}
]
}

View File

@ -181,12 +181,27 @@
dependencies:
tslib "^1.9.0"
"@angular/pwa@^0.6.8":
version "0.6.8"
resolved "https://registry.yarnpkg.com/@angular/pwa/-/pwa-0.6.8.tgz#2bc0d8e64e997bdfb39bbd2301322c0d2163851a"
dependencies:
"@angular-devkit/core" "0.6.8"
"@angular-devkit/schematics" "0.6.8"
"@schematics/angular" "0.6.8"
typescript "~2.6.2"
"@angular/router@^6.0.0":
version "6.0.6"
resolved "https://registry.yarnpkg.com/@angular/router/-/router-6.0.6.tgz#30a2281e88fbdb5b530fe4cd14bb5b18bae96c52"
dependencies:
tslib "^1.9.0"
"@angular/service-worker@^6.0.0":
version "6.0.7"
resolved "https://registry.yarnpkg.com/@angular/service-worker/-/service-worker-6.0.7.tgz#33e61f8818dcfd1814deb346a2337962be0d88ef"
dependencies:
tslib "^1.9.0"
"@firebase/app-types@0.3.2":
version "0.3.2"
resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.3.2.tgz#a92dc544290e2893bd8c02a81e684dae3d8e7c85"
@ -7835,6 +7850,10 @@ typedarray@^0.0.6:
version "2.7.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.7.2.tgz#2d615a1ef4aee4f574425cdff7026edf81919836"
typescript@~2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4"
typescript@~2.9.1:
version "2.9.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c"