This commit is contained in:
2022-05-02 21:10:15 -04:00
parent 200574099b
commit 8e818b179b
60 changed files with 617 additions and 879 deletions

View File

@ -1,58 +0,0 @@
<div class="w-100">
<div class="container d-flex align-items-center" style="height: 300px">
<div class="w-100 text-center">
<typewriter text="Admin Panel" [delay]="500"></typewriter>
</div>
</div>
<div class="container mb-md-5 p-0 bg-white">
<div class="p-4">
<h3>Users</h3>
<table class="table mt-3">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th class="text-center">Admin</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let user of adminService.users | async">
<td>{{user.firstName}}</td>
<td>{{user.lastName}}</td>
<td>{{user.email}}</td>
<td class="text-center">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="adminCheck" [checked]="user.admin"
disabled>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="p-4">
<h3>Quotes</h3>
<table class="table mt-3">
<thead>
<tr>
<th>Quote</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let quote of store.quotes | async">
<td>{{quote.text}}</td>
</tr>
<tr>
<td>
<a routerLink="">+ Add Quote</a>
</td>
</tr>
</tbody>
</table>
</div>
<footer class="p-1 bg-dark text-center" style="color: grey">
© 2019 ZaksCode
</footer>
</div>
</div>

View File

@ -1,11 +0,0 @@
import {Component} from '@angular/core';
import {AdminService} from './admin.service';
import {AppStore} from '../app.store';
@Component({
selector: 'admin',
templateUrl: 'admin.component.html'
})
export class AdminComponent {
constructor(public adminService: AdminService, public store: AppStore) {}
}

View File

@ -1,15 +0,0 @@
import {Observable} from 'rxjs';
import {DbUser} from '../models/dbUser';
import {AngularFirestore} from '@angular/fire/firestore';
import {Injectable} from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class AdminService {
users: Observable<DbUser[]>;
constructor(private firestore: AngularFirestore) {
this.users = this.firestore.collection<DbUser>('users').valueChanges();
}
}

View File

@ -1,10 +0,0 @@
<div style="position: absolute; top: 1em; right: 1em">
<div *ngIf="loggedIn">
<a routerLink="/admin" class="mr-3">Admin Panel</a>
<a routerLink="" (click)="authService.logout()">Logout</a>
</div>
<div *ngIf="!loggedIn">
<a routerLink="" (click)="authService.googleLogin()">Login</a>
</div>
</div>
<router-outlet></router-outlet>

View File

@ -1,20 +0,0 @@
import {Component} from '@angular/core';
import {AuthService} from './auth.service';
import {ActivatedRoute} from '@angular/router';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html'
})
export class AppComponent {
loggedIn = false;
set title(title: string) {
document.getElementsByTagName('title')[0].innerHTML = `Zaks Code${title ? ` - ${title}` : ''}`;
}
constructor(private route: ActivatedRoute, public authService: AuthService) {
this.route.url.subscribe(() => this.title = ''); // Clear the title on nav event
this.authService.user.subscribe(user => this.loggedIn = !!user);
}
}

View File

@ -1,24 +1,17 @@
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {AngularFireModule} from '@angular/fire';
import {AngularFirestoreModule, FirestoreSettingsToken} from '@angular/fire/firestore';
import {HomeComponent} from './home/home.component';
import {HomeComponent} from './views/home/home.component';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {MaterialModule} from './material.module';
import {FormsModule} from '@angular/forms';
import {TypewriterComponent} from './components/typewriter/typewriter.component';
import {SlideShowComponent} from './components/slideShow/slideShow.component';
import {environment} from '../environments/environment';
import {AppComponent} from './app.component';
import {AppComponent} from './views/app/app.component';
import {AppRouting} from './app.routing';
import {AdminComponent} from './admin/admin.component';
import {AngularFireAuthModule} from '@angular/fire/auth';
import {ConsoleComponent} from './components/console/console.component';
@NgModule({
declarations: [
AdminComponent,
AppComponent,
ConsoleComponent,
HomeComponent,
@ -26,18 +19,12 @@ import {ConsoleComponent} from './components/console/console.component';
TypewriterComponent
],
imports: [
AngularFireAuthModule,
AngularFireModule.initializeApp(environment.firebase),
AngularFirestoreModule,
AppRouting,
BrowserModule,
BrowserAnimationsModule,
FormsModule,
MaterialModule,
],
providers: [
{ provide: FirestoreSettingsToken, useValue: {} }
],
bootstrap: [AppComponent]
})
export class AppModule { }

View File

@ -1,14 +1,11 @@
import {NgModule} from '@angular/core';
import {RouterModule} from '@angular/router';
import {HomeComponent} from './home/home.component';
import {AdminComponent} from './admin/admin.component';
import {AuthService} from './auth.service';
import {HomeComponent} from './views/home/home.component';
@NgModule({
imports: [
RouterModule.forRoot([
{path: '', component: HomeComponent},
{path: 'admin', component: AdminComponent, canActivate: [AuthService]},
{path: '**', redirectTo: ''}
])
],

View File

@ -1,25 +0,0 @@
import {Injectable} from '@angular/core';
import {BehaviorSubject, Observable} from 'rxjs';
import {AngularFirestore} from '@angular/fire/firestore';
import {Quote} from './models/quote';
import {DbUser} from './models/dbUser';
@Injectable({
providedIn: 'root'
})
export class AppStore {
quotes: Observable<Quote[]>;
constructor(private firestore: AngularFirestore) {
this.quotes = this.firestore.collection<Quote>('quotes').valueChanges();
}
addQuote(text: string) {
return this.firestore.collection<Quote>('quotes').add({text: text});
}
async getUser(uid: string) {
let user = await this.firestore.collection<DbUser>('users').doc(uid).get().toPromise();
return user.data();
}
}

View File

@ -1,41 +0,0 @@
import {Injectable} from '@angular/core';
import {AngularFireAuth} from '@angular/fire/auth';
import {CanActivate, Router} from '@angular/router';
import {BehaviorSubject, Observable} from 'rxjs';
import { auth } from 'firebase';
import {map} from 'rxjs/operators';
import {User} from './models/user';
import {AppStore} from './app.store';
import {tap} from 'rxjs/internal/operators/tap';
import {filter} from 'rxjs/internal/operators/filter';
@Injectable({
providedIn: 'root'
})
export class AuthService implements CanActivate {
user = new BehaviorSubject<User>(null);
constructor(private store: AppStore, private afAuth: AngularFireAuth, private router: Router) {
this.afAuth.user.subscribe(async user => {
this.user.next(user ? <User>Object.assign(await this.store.getUser(user.uid), user): null);
});
}
canActivate(): Observable<boolean> {
return this.user.pipe(
filter(user => !!user),
map(user => !user.isAnonymous),
tap(user => user ? null : this.googleLogin())
);
}
googleLogin() {
return this.afAuth.auth.signInWithPopup(new auth.GoogleAuthProvider());
}
async logout() {
await this.afAuth.auth.signOut();
this.router.navigate(['/']);
}
}

View File

@ -1,8 +1,10 @@
<div clas="p-1" style="background-color: #353535; color: #fff;">
<div class="pl-2 pt-2" style="height: 10rem;">
<h4 *ngFor="let o of output">{{o}}</h4>
<div class="p-3 d-flex flex-column justify-content-end console overflow-hidden" [style.height]="height">
<div>
<h4 class="m-0" *ngFor="let o of output">{{o}}</h4>
</div>
<div class="pl-2 pb-2">
<h4 class="d-inline mr-2" style="color: #22ff22">></h4><typewriter [text]="input" (done)="enter()"></typewriter>
<div class="mt-2">
<h4 class="m-0">
{{prompt}} <typewriter class="pl-2" [text]="input" (done)="done()"></typewriter>
</h4>
</div>
</div>

View File

@ -1,32 +1,35 @@
import {Component} from '@angular/core';
import {AppStore} from '../../app.store';
import {map} from 'rxjs/operators';
import {Component, Input, ViewChild} from '@angular/core';
import { take } from 'rxjs';
import {TypewriterComponent} from '../typewriter/typewriter.component';
export type ConsoleConfig = {
input: string,
output: () => string
}
@Component({
selector: 'console',
templateUrl: './console.component.html'
templateUrl: './console.component.html',
styleUrls: ['./console.component.scss']
})
export class ConsoleComponent {
private done = false;
input = '';
output: string[] = [];
prompt = '>'
input = './motd.sh';
output = [];
quote;
done = () => {};
constructor(private store: AppStore) {
store.quotes.subscribe(quotes => {
const quote = quotes[Math.floor(Math.random() * quotes.length)];
this.quote = quote.text;
});
}
@Input() height: string = 'auto';
enter() {
if(this.done) return;
setTimeout(() => {
this.output.push(this.input);
this.input = '';
setTimeout(() => this.output.push(this.quote), 500);
}, 1500);
this.done = true;
}
@ViewChild(TypewriterComponent) typewriter!: TypewriterComponent;
exec(input: string, output: () => string) {
this.done = () => {
this.output.push(`${this.prompt} ${input}`);
console.log(output());
this.output.push(output());
this.input = '';
};
this.input = input;
}
}

View File

@ -1,10 +1,15 @@
import {Component, Input} from '@angular/core';
import {Slide} from '../../models/slide';
export type Slide = {
title: string;
description: string;
image: string;
}
@Component({
selector: 'slideshow',
templateUrl: 'slideShow.component.html'
})
export class SlideShowComponent {
@Input() slides: Slide[];
@Input() slides: Slide[] = [];
}

View File

@ -1,27 +1,30 @@
import {Component, EventEmitter, Input, Output} from '@angular/core';
import {Observable, timer} from 'rxjs';
import {Observable, of, timer} from 'rxjs';
import {filter, map, tap} from 'rxjs/operators';
@Component({
selector: 'typewriter',
template: `
<div class="d-inline typewriter"><h4 class="d-inline">{{output | async}}</h4></div>`,
template: `<span class="typewriter">{{output | async}}</span>`,
styleUrls: ['typewriter.component.scss']
})
export class TypewriterComponent {
output?: Observable<string>;
@Input() delay = 1500;
@Input() speed = 100;
@Input() set text(text: string) {
this.output = timer(this.delay, this.speed).pipe(
filter(n => n <= (text.length || 0)),
tap(n => {
if(n == text.length) this.done.emit();
}),
map(n => text.slice(0, n))
);
if(!text) {
this.output = of('');
} else {
this.output = timer(this.delay, this.speed).pipe(
filter(n => n <= (text.length || 0)),
tap(n => {
if(n == text.length) this.done.emit();
}),
map(n => text.slice(0, n))
);
}
}
@Output() done = new EventEmitter<void>();
output: Observable<string>;
}

View File

@ -1,67 +0,0 @@
<div class="w-100">
<div class="w-100" style="height: calc(100vh - 140px)"></div>
<div class="container p-0 bg-white">
<div class="px-4" style="background-color: #732222">
<mat-card style="max-width: 600px; transform: translateY(-33%)">
<mat-card-content class="d-flex p-3">
<div class="d-none d-md-block pr-3">
<img src="assets/img/portrait.jpg" width="150px" height="150px" style="border-radius: 50%" alt="Zakary Timson">
</div>
<div>
<h1 class="mb-0">Zakary Timson</h1>
<h5 class="text-muted">FULL STACK SOFTWARE ENGINEER</h5>
<div class="mt-3">
<div><i class="mr-2 fa fa-map-marker-alt"></i> London Ontario, Canada</div>
<div><i class="mr-2 fa fa-envelope"></i> <a href="mailto:zaktimson@gmail.com">zaktimson@gmail.com</a>
</div>
<div><i class="mr-2 fab fa-github"></i> <a href="https://github.com/ztimson" target="_blank">github.com/ztimson</a></div>
</div>
</div>
</mat-card-content>
</mat-card>
</div>
<div class="p-4">
<console></console>
</div>
<div class="p-4">
<h3>About Me</h3>
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<p>
Zak was born with a keyboard in hand and was learning his first programming language by thirteen. Nearly
entirely self taught, Zak challenged his programming courses through both highschool and college while
working in the industry to gain professional experience. He is very passionate about technology and as a
lifelong learner it has opened the door to many other hobbies like robotics, space and physics. Some of his
personal projects include a full sized arcade machine, home automation and a power wall for a home solar
system.
</p>
</div>
<div class="flex-shrink-1 p-3">
<img src="assets/img/keyboard-in-hand.jpg" height="150px" width="auto" style="border-radius: 50%">
</div>
</div>
</div>
<!-- <div class="p-4 text-white" style="background-color: #1c7fc1">
<h3>Projects</h3>
<div style="height: 400px">
<slideshow></slideshow>
</div>
</div> -->
<div class="p-4">
<h3>Resume & References</h3>
<a class="btn btn-outline-primary" href="https://docs.google.com/document/d/1xP6HASPerXKMJM_x6-PhHVvoYgq-Hym5IRO7g47EX8o/edit?usp=sharing" target="_blank">Resume</a>
<div class="ml-3 btn-group" role="group" aria-label="Basic example">
<a class="btn btn-outline-info" href="https://drive.google.com/file/d/0B_iz0vkzXmAyNWw0UDFzT0ZTeVU/view?usp=sharing" target="_blank">Manager</a>
<a class="btn btn-outline-info" href="https://drive.google.com/file/d/0B_iz0vkzXmAyaFBhcXBEaGp6YWc/view?usp=sharing" target="_blank">Contractor</a>
<a class="btn btn-outline-info" href="https://drive.google.com/file/d/0B_iz0vkzXmAyM0YtTWcxQzk0dEE/view?usp=sharing" target="_blank">Teacher</a>
<a class="btn btn-outline-info" href="https://drive.google.com/file/d/0B_iz0vkzXmAyX2owd0xURjh3RlE/view?usp=sharing" target="_blank">Principle</a>
<a class="btn btn-outline-info" href="https://drive.google.com/file/d/0B_iz0vkzXmAyMHdaM1BjZ1MwbWxva2lOY290NElwanN4b2JV/view?usp=sharing" target="_blank">CD Project Red</a>
</div>
</div>
<footer class="p-1 bg-dark text-center" style="color: grey">
Copyright © Zakary Timson 2019 | All Rights Reserved
</footer>
<div class="skirt"></div>
</div>
</div>

View File

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

View File

@ -1,5 +1,5 @@
import {NgModule} from '@angular/core';
import {MatCardModule} from '@angular/material';
import {MatCardModule} from '@angular/material/card';
const MODULES = [
MatCardModule

View File

@ -1,6 +0,0 @@
export interface DbUser {
admin: boolean;
email: string;
firstName: string;
lastName: string;
}

View File

@ -1,3 +0,0 @@
export interface Quote {
text: string;
}

View File

@ -1,7 +0,0 @@
import {SafeUrl} from '@angular/platform-browser';
export interface Slide {
title: string
description: string
image: string | SafeUrl
}

View File

@ -1,4 +0,0 @@
import {User as FirebaseUser} from 'firebase';
import {DbUser} from './dbUser';
export interface User extends FirebaseUser, DbUser { }

View File

@ -0,0 +1 @@
<router-outlet></router-outlet>

View File

@ -0,0 +1,17 @@
import {Component} from '@angular/core';
import {Title} from '@angular/platform-browser';
import {ActivatedRoute} from '@angular/router';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html'
})
export class AppComponent {
constructor(private route: ActivatedRoute, private title: Title) {
this.route.url.subscribe(() => this.setTitle(''));
}
setTitle(title: string) {
this.title.setTitle(`Zak's Code${title ? ` - ${title}` : ''}`);
}
}

View File

@ -0,0 +1,69 @@
<div class="w-100">
<div class="w-100" style="height: calc(100vh - 140px)"></div>
<div class="container p-0 bg-white">
<div class="px-3" style="background-color: #732222">
<mat-card style="max-width: 600px; transform: translateY(-33%)">
<mat-card-content class="d-flex p-3">
<div class="d-none d-md-block pr-3">
<img src="assets/img/portrait.jpg" width="150px" height="150px" style="border-radius: 50%" alt="Zakary Timson">
</div>
<div>
<h1 class="mb-0">Zakary Timson</h1>
<h5 class="text-muted">DEVOPS & SOFTWARE ENGINEER</h5>
<div class="mt-3">
<div><i class="mr-2 fa fa-map-marker-alt"></i> London Ontario, Canada</div>
<div><i class="mr-2 fa fa-envelope"></i> <a href="mailto:zaktimson@gmail.com">zaktimson@gmail.com</a>
</div>
<div><i class="mr-2 fab fa-github"></i> <a href="https://github.com/ztimson" target="_blank">github.com/ztimson</a></div>
</div>
</div>
</mat-card-content>
</mat-card>
</div>
<div class="p-3">
<console height="12rem"></console>
</div>
<!-- <div class="p-3">-->
<!-- <h3>Projects</h3>-->
<!-- <iframe class="border-0" src="https://gitlab.zakscode.com/explore" width="100%" height="75vh">-->
<!-- </iframe>-->
<!-- </div>-->
<div class="p-3">
<h3>About Me</h3>
<div>
<img alt="Childhood" class="float-right m-3 m-md-0 ml-md-3" src="assets/img/keyboard-in-hand.jpg" height="150px" width="auto" style="border-radius: 50%">
<p>
Zak was born with a keyboard in hand and was learning his first programming language by thirteen. Nearly
entirely self taught, Zak challenged his programming courses through both high-school and college while
working in the industry to gain professional experience. He is very passionate about technology and as a
lifelong learner it has opened the door to many other hobbies like robotics, space and physics. Some of his
personal projects include a full sized arcade machine, home automation and a power wall for a home solar
system.
</p>
</div>
</div>
<div class="p-3 overflow-hidden">
<h3>Resume & References</h3>
<a class="mb-3 btn btn-outline-primary" href="https://docs.google.com/document/d/1xP6HASPerXKMJM_x6-PhHVvoYgq-Hym5IRO7g47EX8o/edit?usp=sharing" target="_blank">Resume</a>
<ul class="d-md-none list-group">
<a class="list-group-item list-group-item-action border-info text-info" href="https://docs.google.com/document/d/1xP6HASPerXKMJM_x6-PhHVvoYgq-Hym5IRO7g47EX8o/edit?usp=sharing" target="_blank">Resume</a>
<a class="list-group-item list-group-item-action border-info text-info" href="https://drive.google.com/file/d/0B_iz0vkzXmAyNWw0UDFzT0ZTeVU/view?usp=sharing" target="_blank">Manager</a>
<a class="list-group-item list-group-item-action border-info text-info" href="https://drive.google.com/file/d/0B_iz0vkzXmAyaFBhcXBEaGp6YWc/view?usp=sharing" target="_blank">Contractor</a>
<a class="list-group-item list-group-item-action border-info text-info" href="https://drive.google.com/file/d/0B_iz0vkzXmAyM0YtTWcxQzk0dEE/view?usp=sharing" target="_blank">Teacher</a>
<a class="list-group-item list-group-item-action border-info text-info" href="https://drive.google.com/file/d/0B_iz0vkzXmAyX2owd0xURjh3RlE/view?usp=sharing" target="_blank">Principle</a>
<a class="list-group-item list-group-item-action border-info text-info" href="https://drive.google.com/file/d/0B_iz0vkzXmAyMHdaM1BjZ1MwbWxva2lOY290NElwanN4b2JV/view?usp=sharing" target="_blank">CD Projekt Red</a>
</ul>
<div class="d-none d-md-block btn-group" role="group" aria-label="Basic example">
<a class="btn btn-outline-info" href="https://drive.google.com/file/d/0B_iz0vkzXmAyNWw0UDFzT0ZTeVU/view?usp=sharing" target="_blank">Manager</a>
<a class="btn btn-outline-info" href="https://drive.google.com/file/d/0B_iz0vkzXmAyaFBhcXBEaGp6YWc/view?usp=sharing" target="_blank">Contractor</a>
<a class="btn btn-outline-info" href="https://drive.google.com/file/d/0B_iz0vkzXmAyM0YtTWcxQzk0dEE/view?usp=sharing" target="_blank">Teacher</a>
<a class="btn btn-outline-info" href="https://drive.google.com/file/d/0B_iz0vkzXmAyX2owd0xURjh3RlE/view?usp=sharing" target="_blank">Principle</a>
<a class="btn btn-outline-info" href="https://drive.google.com/file/d/0B_iz0vkzXmAyMHdaM1BjZ1MwbWxva2lOY290NElwanN4b2JV/view?usp=sharing" target="_blank">CD Projekt Red</a>
</div>
</div>
<footer class="p-1 bg-dark text-center" style="color: grey">
Copyright © Zakary Timson 2019 | All Rights Reserved
</footer>
<div class="d-none d-sm-block skirt"></div>
</div>
</div>

View File

@ -0,0 +1,15 @@
import {Component, ViewChild} from '@angular/core';
import {ConsoleComponent, ConsoleConfig} from '../../components/console/console.component';
import {QuoteService} from '../../services/quote.service';
@Component({
selector: 'home',
templateUrl: './home.component.html'
})
export class HomeComponent {
@ViewChild(ConsoleComponent) console!: ConsoleComponent;
constructor(private quotes: QuoteService) {
setTimeout(() => this.console.exec('bash ./random-thought.sh', () => quotes.random()), 3000);
}
}