Merge branch 'develop' of ssh://gitlab.zakscode.com:2224/zakscode/LegioXXX into develop
Conflicts: src/app/app.routing.ts
This commit is contained in:
		@@ -1,12 +1,16 @@
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { BrowserModule } from '@angular/platform-browser';
 | 
			
		||||
import { AppRouting } from './app.routing';
 | 
			
		||||
import {NgModule} from '@angular/core';
 | 
			
		||||
import {BrowserModule} from '@angular/platform-browser';
 | 
			
		||||
import {NgxGoogleAnalyticsModule} from 'ngx-google-analytics';
 | 
			
		||||
import {environment} from '../environments/environment';
 | 
			
		||||
import {AppRouting} from './app.routing';
 | 
			
		||||
import {BannerComponent} from './components/banner/banner.component';
 | 
			
		||||
import {FooterComponent} from './components/footer/footer.component';
 | 
			
		||||
import {LogoComponent} from './components/logo/logo.component';
 | 
			
		||||
import {NavbarComponent} from './components/navbar/navbar.component';
 | 
			
		||||
import { AppComponent } from './containers/app/app.component';
 | 
			
		||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 | 
			
		||||
import {AppComponent} from './containers/app/app.component';
 | 
			
		||||
import {BrowserAnimationsModule } from '@angular/platform-browser/animations';
 | 
			
		||||
import {MaterialModule} from './material.module';
 | 
			
		||||
import {PrelaodService} from './services/prelaod.service';
 | 
			
		||||
import {FourOFourComponent} from './views/404/404.component';
 | 
			
		||||
import {AboutComponent} from './views/about/about.component';
 | 
			
		||||
import {AestivaComponent} from './views/events/aestiva/aestiva.component';
 | 
			
		||||
@@ -19,7 +23,7 @@ import {DrillComponent} from './views/reenact/drill/drill.component';
 | 
			
		||||
import {GettingStartedComponent} from './views/reenact/getting-started/getting-started.component';
 | 
			
		||||
import {RulesComponent} from './views/reenact/rules/rules.component';
 | 
			
		||||
 | 
			
		||||
export const APP_COMPONENTS = [
 | 
			
		||||
export const APP_COMPONENTS: any[] = [
 | 
			
		||||
	AboutComponent,
 | 
			
		||||
	AestivaComponent,
 | 
			
		||||
	AgoniumComponent,
 | 
			
		||||
@@ -27,25 +31,33 @@ export const APP_COMPONENTS = [
 | 
			
		||||
	BannerComponent,
 | 
			
		||||
	CalendarComponent,
 | 
			
		||||
	DrillComponent,
 | 
			
		||||
	GettingStartedComponent,
 | 
			
		||||
	HibernaComponent,
 | 
			
		||||
	FooterComponent,
 | 
			
		||||
	FourOFourComponent,
 | 
			
		||||
	GalleryComponent,
 | 
			
		||||
	GettingStartedComponent,
 | 
			
		||||
	HibernaComponent,
 | 
			
		||||
	HomeComponent,
 | 
			
		||||
	LogoComponent,
 | 
			
		||||
	NavbarComponent,
 | 
			
		||||
	RulesComponent
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
export const APP_IMPORTS: any[] = [
 | 
			
		||||
	AppRouting,
 | 
			
		||||
	BrowserAnimationsModule,
 | 
			
		||||
	BrowserModule,
 | 
			
		||||
	MaterialModule
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
if(environment.analytics && (<any>environment.analytics) != '{{ANALYTICS}}')
 | 
			
		||||
	APP_IMPORTS.push(NgxGoogleAnalyticsModule.forRoot(<any>environment.analytics));
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  declarations: APP_COMPONENTS,
 | 
			
		||||
  imports: [
 | 
			
		||||
	  BrowserModule,
 | 
			
		||||
	  AppRouting,
 | 
			
		||||
	  BrowserAnimationsModule,
 | 
			
		||||
	  MaterialModule
 | 
			
		||||
  ],
 | 
			
		||||
  imports: APP_IMPORTS,
 | 
			
		||||
  providers: [],
 | 
			
		||||
  bootstrap: [AppComponent]
 | 
			
		||||
})
 | 
			
		||||
export class AppModule { }
 | 
			
		||||
export class AppModule {
 | 
			
		||||
	constructor(preload: PrelaodService) { }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,16 +14,16 @@ import {RulesComponent} from './views/reenact/rules/rules.component';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
	{path: '', pathMatch: 'full', component: HomeComponent},
 | 
			
		||||
	{path: 'about', component: AboutComponent},
 | 
			
		||||
	{path: 'drill', component: DrillComponent},
 | 
			
		||||
	{path: 'events/aestiva', component: AestivaComponent},
 | 
			
		||||
	{path: 'events/agonium', component: AgoniumComponent},
 | 
			
		||||
	{path: 'events/hiberna', component: HibernaComponent},
 | 
			
		||||
	{path: 'events/calendar', component: CalendarComponent},
 | 
			
		||||
	{path: 'gallery', component: GalleryComponent},
 | 
			
		||||
	{path: 'getting-started', component: GettingStartedComponent},
 | 
			
		||||
	{path: 'rules', component: RulesComponent},
 | 
			
		||||
	{path: '**', component: FourOFourComponent}
 | 
			
		||||
	{path: 'about', component: AboutComponent, data: {title: 'About'}},
 | 
			
		||||
	{path: 'drill', component: DrillComponent, data: {title: 'Drill Commands'}},
 | 
			
		||||
	{path: 'events/aestiva', component: AestivaComponent, data: {title: 'Castra Aestiva'}},
 | 
			
		||||
	{path: 'events/agonium', component: AgoniumComponent, data: {title: 'Agonium'}},
 | 
			
		||||
	{path: 'events/hiberna', component: HibernaComponent, data: {title: 'Castra Hiberna'}},
 | 
			
		||||
	{path: 'events/calendar', component: CalendarComponent, data: {title: 'Calendar'}},
 | 
			
		||||
	{path: 'gallery', component: GalleryComponent, data: {title: 'Gallery'}},
 | 
			
		||||
	{path: 'getting-started', component: GettingStartedComponent, data: {title: 'Getting Started'}},
 | 
			
		||||
	{path: 'rules', component: RulesComponent, data: {title: 'Rules & Regulations'}},
 | 
			
		||||
	{path: '**', component: FourOFourComponent, data: {title: '404'}}
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										9
									
								
								src/app/components/logo/logo.component.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/app/components/logo/logo.component.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
<div class="logo">
 | 
			
		||||
	<div class="d-flex" aria-label="Legio XXX">
 | 
			
		||||
		<div>L</div>
 | 
			
		||||
		<div [@slide]="expand ? 'expand' : 'shrink'" style="overflow: hidden">EGIO · </div>
 | 
			
		||||
		<div [@margin]="expand ? 'expand' : 'shrink'" [style.marginLeft]="expand ? '0.25rem' : 0">XXX</div>
 | 
			
		||||
		<div *ngIf="loading">{{dots | async}}</div>
 | 
			
		||||
	</div>
 | 
			
		||||
    <div *ngIf="loadingText" class="logo-footer text-center">{{loadingText}}</div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										26
									
								
								src/app/components/logo/logo.component.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/app/components/logo/logo.component.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
//.logo {
 | 
			
		||||
//  .expandable {
 | 
			
		||||
//    width: 0;
 | 
			
		||||
//  }
 | 
			
		||||
//
 | 
			
		||||
//  &.expanded {
 | 
			
		||||
//    .expandable {
 | 
			
		||||
//      width: auto;
 | 
			
		||||
//    }
 | 
			
		||||
//  }
 | 
			
		||||
//
 | 
			
		||||
//  .logo-segment {
 | 
			
		||||
//    font-family: Arial, sans-serif !important;
 | 
			
		||||
//    overflow: hidden;
 | 
			
		||||
//    padding: 0.3em 0;
 | 
			
		||||
//    width: auto;
 | 
			
		||||
//  }
 | 
			
		||||
//
 | 
			
		||||
//  .logo-dots {
 | 
			
		||||
//    width: 30px;
 | 
			
		||||
//  }
 | 
			
		||||
//
 | 
			
		||||
//  .logo-footer {
 | 
			
		||||
//    transform: translate(-15px, -8px);
 | 
			
		||||
//  }
 | 
			
		||||
//}
 | 
			
		||||
							
								
								
									
										35
									
								
								src/app/components/logo/logo.component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/app/components/logo/logo.component.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
 | 
			
		||||
import {animate, state, style, transition, trigger} from '@angular/animations';
 | 
			
		||||
import {Observable, timer} from 'rxjs';
 | 
			
		||||
import {map} from 'rxjs/operators';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
	selector: 'xxx-logo',
 | 
			
		||||
	templateUrl: './logo.component.html',
 | 
			
		||||
	animations: [
 | 
			
		||||
		trigger('slide', [
 | 
			
		||||
			state('expand', style({width: '*'})),
 | 
			
		||||
			state('shrink', style({width: '0px'})),
 | 
			
		||||
			transition('* => *', [animate('0.5s')])
 | 
			
		||||
		]),
 | 
			
		||||
		trigger('margin', [
 | 
			
		||||
			state('expand', style({marginLeft: '0.25rem'})),
 | 
			
		||||
			state('shrink', style({marginLeft: '0'})),
 | 
			
		||||
			transition('* => *', [animate('0.5s')])
 | 
			
		||||
		])
 | 
			
		||||
	],
 | 
			
		||||
	changeDetection: ChangeDetectionStrategy.OnPush
 | 
			
		||||
})
 | 
			
		||||
export class LogoComponent {
 | 
			
		||||
	@Input() expand = true;
 | 
			
		||||
	@Input() loading = false;
 | 
			
		||||
	@Input() loadingText = '';
 | 
			
		||||
 | 
			
		||||
	dots: Observable<string>;
 | 
			
		||||
 | 
			
		||||
	constructor() {
 | 
			
		||||
		this.dots = timer(0, 1000).pipe(map(i => {
 | 
			
		||||
			return Array(i % 4).fill('.').join('');
 | 
			
		||||
		}));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
		<div>
 | 
			
		||||
			<a class="navbar-brand d-flex align-items-center" routerLink="/" fragment="banner" (click)="scroll('banner')">
 | 
			
		||||
				<img src="assets/img/eagle.png" alt="SPQR" height="45px" width="45px">
 | 
			
		||||
				<div class="px-2">LEGIO · XXX</div>
 | 
			
		||||
				<xxx-logo class="px-2" [expand]="true"></xxx-logo>
 | 
			
		||||
			</a>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="flex-grow-1"></div>
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ import {AfterViewInit, Component, EventEmitter, Input, OnDestroy, Output} from '
 | 
			
		||||
import {ActivatedRoute, NavigationEnd, Router} from '@angular/router';
 | 
			
		||||
import {combineLatest, filter, Subscription} from 'rxjs';
 | 
			
		||||
import {NAVIGATION} from '../../misc/navigation';
 | 
			
		||||
import {BreakpointService} from '../../services/breakpoint.service';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
	selector: 'xxx-navbar',
 | 
			
		||||
@@ -20,7 +21,7 @@ export class NavbarComponent implements AfterViewInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
	@Output() hamburgerClick = new EventEmitter<void>();
 | 
			
		||||
 | 
			
		||||
	constructor(private route: ActivatedRoute, private router: Router) { }
 | 
			
		||||
	constructor(private route: ActivatedRoute, private router: Router, public breakpoint: BreakpointService) { }
 | 
			
		||||
 | 
			
		||||
	ngAfterViewInit() {
 | 
			
		||||
		this.sub = combineLatest([this.router.events.pipe(filter(e => e instanceof NavigationEnd)), this.route.fragment]).subscribe(([url, frag]) => {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
import {BreakpointObserver} from '@angular/cdk/layout';
 | 
			
		||||
import { Component } from '@angular/core';
 | 
			
		||||
import {ActivatedRoute, NavigationEnd, Router} from '@angular/router';
 | 
			
		||||
import {filter} from 'rxjs';
 | 
			
		||||
import {NavigationEnd, Router} from '@angular/router';
 | 
			
		||||
import {combineLatest, filter, Subscription} from 'rxjs';
 | 
			
		||||
import {BreakpointService} from '../../services/breakpoint.service';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-root',
 | 
			
		||||
@@ -9,15 +9,22 @@ import {filter} from 'rxjs';
 | 
			
		||||
  styleUrls: ['./app.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class AppComponent {
 | 
			
		||||
	private sub?: Subscription;
 | 
			
		||||
 | 
			
		||||
	mobile = false;
 | 
			
		||||
	open = false;
 | 
			
		||||
 | 
			
		||||
	constructor(private router: Router, route: ActivatedRoute, breakpointObserver: BreakpointObserver) {
 | 
			
		||||
		router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe(() => this.open = false);
 | 
			
		||||
		breakpointObserver.observe(['(max-width: 750px)']).subscribe(result => {
 | 
			
		||||
			this.mobile = result.matches;
 | 
			
		||||
	constructor(private breakpoint: BreakpointService, private router: Router) {
 | 
			
		||||
		this.sub = combineLatest([
 | 
			
		||||
			router.events.pipe(filter(event => event instanceof NavigationEnd)),
 | 
			
		||||
			breakpoint.isMobile$
 | 
			
		||||
		]).subscribe(([event, mobile]) => {
 | 
			
		||||
			this.mobile = mobile;
 | 
			
		||||
			this.open = !this.mobile;
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ngOnDestroy() {
 | 
			
		||||
		if(this.sub) this.sub.unsubscribe();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										33
									
								
								src/app/services/analytics.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/app/services/analytics.service.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
import {Injectable, OnDestroy, Optional} from '@angular/core';
 | 
			
		||||
import {NavigationEnd, Router} from '@angular/router';
 | 
			
		||||
import {GoogleAnalyticsService} from 'ngx-google-analytics';
 | 
			
		||||
import {combineLatest, Subscription} from 'rxjs';
 | 
			
		||||
import {filter} from 'rxjs/operators';
 | 
			
		||||
import {TitleService} from './title.service';
 | 
			
		||||
 | 
			
		||||
@Injectable({providedIn: 'root'})
 | 
			
		||||
export class AnalyticsService implements OnDestroy {
 | 
			
		||||
	private sub?: Subscription;
 | 
			
		||||
 | 
			
		||||
	constructor(@Optional() private analyticsService: GoogleAnalyticsService,
 | 
			
		||||
				private router: Router,
 | 
			
		||||
				private title: TitleService
 | 
			
		||||
	) {
 | 
			
		||||
		if(this.analyticsService) {
 | 
			
		||||
			combineLatest([
 | 
			
		||||
				this.router.events.pipe(filter((e): e is NavigationEnd => e instanceof NavigationEnd))
 | 
			
		||||
			]).subscribe(([navigation]) => {
 | 
			
		||||
				this.analyticsService.pageView(navigation.urlAfterRedirects, this.title.title);
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log(action: string, category?: string, label?: string, value?: any, interaction?: boolean) {
 | 
			
		||||
		if(!this.analyticsService) return;
 | 
			
		||||
		return this.analyticsService.event(action, category, label, value, interaction);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ngOnDestroy() {
 | 
			
		||||
		if(this.sub) this.sub.unsubscribe();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								src/app/services/breakpoint.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/app/services/breakpoint.service.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
import {Injectable} from '@angular/core';
 | 
			
		||||
import {BreakpointObserver, Breakpoints} from '@angular/cdk/layout';
 | 
			
		||||
import {map, tap} from 'rxjs/operators';
 | 
			
		||||
 | 
			
		||||
@Injectable({providedIn: 'root'})
 | 
			
		||||
export class BreakpointService {
 | 
			
		||||
	private _isMobile?: boolean;
 | 
			
		||||
	get isMobile() { return !!this.isMobile$; }
 | 
			
		||||
	isMobile$ = this.breakpointObserver.observe([Breakpoints.XSmall]).pipe(
 | 
			
		||||
		map(e => e.matches),
 | 
			
		||||
		tap(e => this._isMobile = e)
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	constructor(private breakpointObserver: BreakpointObserver) {  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								src/app/services/prelaod.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/app/services/prelaod.service.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
import {Injectable} from '@angular/core';
 | 
			
		||||
import {AnalyticsService} from './analytics.service';
 | 
			
		||||
import {BreakpointService} from './breakpoint.service';
 | 
			
		||||
import {TitleService} from './title.service';
 | 
			
		||||
 | 
			
		||||
@Injectable({providedIn: 'root'})
 | 
			
		||||
export class PrelaodService {
 | 
			
		||||
	constructor(private analytics: AnalyticsService,
 | 
			
		||||
				private breakpoint: BreakpointService,
 | 
			
		||||
				private title: TitleService
 | 
			
		||||
	) { }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								src/app/services/title.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/app/services/title.service.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
import {Injectable, OnDestroy} from '@angular/core';
 | 
			
		||||
import {Title} from '@angular/platform-browser';
 | 
			
		||||
import {ActivatedRoute, NavigationEnd, Router} from '@angular/router';
 | 
			
		||||
import {filter} from 'rxjs/operators';
 | 
			
		||||
import {Observable, Subscription} from 'rxjs';
 | 
			
		||||
 | 
			
		||||
@Injectable({providedIn: 'root'})
 | 
			
		||||
export class TitleService implements OnDestroy {
 | 
			
		||||
	private readonly orgTitle: string = 'LEGIO · XXX';
 | 
			
		||||
 | 
			
		||||
	private routeSub?: Subscription;
 | 
			
		||||
	private titleSub?: Subscription;
 | 
			
		||||
 | 
			
		||||
	get title(): string {
 | 
			
		||||
		const title = this._title.getTitle();
 | 
			
		||||
		if(title.includes(this.orgTitle) && title.length > this.orgTitle.length)
 | 
			
		||||
			return title.substring(this.orgTitle.length);
 | 
			
		||||
		return this._title.getTitle();
 | 
			
		||||
	}
 | 
			
		||||
	set title(title: string | null) {
 | 
			
		||||
		if(!title) this._title.setTitle(this.orgTitle);
 | 
			
		||||
		else this._title.setTitle(`${this.orgTitle} | ${title}`);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	constructor(private router: Router,
 | 
			
		||||
				private route: ActivatedRoute,
 | 
			
		||||
				private _title: Title
 | 
			
		||||
	) {
 | 
			
		||||
		// this.orgTitle = this.title; // Hardcoding because HMR breaks this
 | 
			
		||||
		this.routeSub = this.router.events
 | 
			
		||||
			.pipe(filter(e => e instanceof NavigationEnd))
 | 
			
		||||
			.subscribe(() => this.getTitleFromRoute());
 | 
			
		||||
		this.getTitleFromRoute();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private async getTitleFromRoute() {
 | 
			
		||||
		if(this.titleSub) this.titleSub.unsubscribe();
 | 
			
		||||
		let route = this.route, title = route.snapshot.data['title'];
 | 
			
		||||
		while (route.firstChild) {
 | 
			
		||||
			route = route.firstChild;
 | 
			
		||||
			if(route.snapshot.data['title']) title = route.snapshot.data['title'];
 | 
			
		||||
		}
 | 
			
		||||
		if(title instanceof Observable) { this.titleSub = title.subscribe(t => this.title = t); }
 | 
			
		||||
		else { this.title = title; }
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ngOnDestroy() {
 | 
			
		||||
		if(this.routeSub) this.routeSub.unsubscribe();
 | 
			
		||||
		if(this.titleSub) this.titleSub.unsubscribe();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
export const environment = {
 | 
			
		||||
  production: true
 | 
			
		||||
	analytics: 'G-7HLT4FQY9V',
 | 
			
		||||
  	production: true
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
export const environment = {
 | 
			
		||||
  production: false
 | 
			
		||||
	analytics: false,
 | 
			
		||||
  	production: false
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user