Merge branch 'develop' of ssh://gitlab.zakscode.com:2224/zakscode/LegioXXX into develop
Conflicts: src/app/app.routing.ts
This commit is contained in:
commit
8193f23668
@ -44,6 +44,7 @@ audit:
|
|||||||
metrics: metrics.txt
|
metrics: metrics.txt
|
||||||
rules:
|
rules:
|
||||||
- if: $CI_COMMIT_BRANCH
|
- if: $CI_COMMIT_BRANCH
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
registry:
|
registry:
|
||||||
stage: deploy
|
stage: deploy
|
||||||
@ -61,6 +62,7 @@ registry:
|
|||||||
- docker push "$CI_REGISTRY_IMAGE:$TAG"
|
- docker push "$CI_REGISTRY_IMAGE:$TAG"
|
||||||
rules:
|
rules:
|
||||||
- if: $CI_COMMIT_BRANCH
|
- if: $CI_COMMIT_BRANCH
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
tag:
|
tag:
|
||||||
stage: deploy
|
stage: deploy
|
||||||
|
@ -17,12 +17,14 @@ COPY . .
|
|||||||
RUN if [ ! -d "dist" ] && [ ! -d "node_modules" ]; then npm install; fi
|
RUN if [ ! -d "dist" ] && [ ! -d "node_modules" ]; then npm install; fi
|
||||||
|
|
||||||
# Build
|
# Build
|
||||||
RUN BUILD_MODE=$([ "$NODE_ENV" = "prod" ] && echo "dynmaic-prod" || echo "dynamic") && \
|
RUN BUILD_MODE=$([ "$NODE_ENV" = "prod" ] && echo "prod" || echo "dev") && \
|
||||||
if [ ! -d "dist" ]; then npm run "build:$BUILD_MODE"; fi
|
if [ ! -d "dist" ]; then npm run "build:$BUILD_MODE"; fi
|
||||||
|
|
||||||
# Use Nginx to serve
|
# Use Nginx to serve
|
||||||
FROM nginx:1.20-alpine
|
FROM nginx:1.20-alpine
|
||||||
COPY --from=build /app/dist /usr/share/nginx/html
|
COPY --from=build /app/dist /usr/share/nginx/html
|
||||||
COPY docker/robots.txt /usr/share/nginx/html/robots.txt
|
COPY docker/config/robots.txt /usr/share/nginx/html/robots.txt
|
||||||
COPY docker/nginx.conf /etc/nginx/nginx.conf
|
COPY docker/config/nginx.conf /etc/nginx/nginx.conf
|
||||||
|
COPY docker/scripts/setup-environment.sh /docker-entrypoint.d/setup-environment.sh
|
||||||
|
RUN chmod +x /docker-entrypoint.d/setup-environment.sh
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
3
docker/scripts/setup-environment.sh
Normal file
3
docker/scripts/setup-environment.sh
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
if [ -n "$ANALYTICS" ]; then sed -i -e "s/:[[:space:]]\?['\"]{{ANALYTICS}}['\"]/:'$ANALYTICS'/g" /usr/share/nginx/html/main*.js; fi
|
21
package-lock.json
generated
21
package-lock.json
generated
@ -20,6 +20,7 @@
|
|||||||
"@angular/router": "^14.2.0",
|
"@angular/router": "^14.2.0",
|
||||||
"bootstrap": "^5.2.1",
|
"bootstrap": "^5.2.1",
|
||||||
"jquery": "^3.6.1",
|
"jquery": "^3.6.1",
|
||||||
|
"ngx-google-analytics": "^14.0.1",
|
||||||
"rxjs": "~7.5.0",
|
"rxjs": "~7.5.0",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"webstorage-decorators": "^4.2.0",
|
"webstorage-decorators": "^4.2.0",
|
||||||
@ -7891,6 +7892,18 @@
|
|||||||
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
|
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/ngx-google-analytics": {
|
||||||
|
"version": "14.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ngx-google-analytics/-/ngx-google-analytics-14.0.1.tgz",
|
||||||
|
"integrity": "sha512-PfOtnshSyq15EKevKlFW9IRgH+dTtPG4Q9HJYksuRNYDzjce0eqK3Bf6hz0tAZdyqbzTCyx5g+NgWBfpqQfb2w==",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@angular/common": ">=12.0.0",
|
||||||
|
"@angular/core": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/nice-napi": {
|
"node_modules/nice-napi": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz",
|
||||||
@ -17380,6 +17393,14 @@
|
|||||||
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
|
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"ngx-google-analytics": {
|
||||||
|
"version": "14.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ngx-google-analytics/-/ngx-google-analytics-14.0.1.tgz",
|
||||||
|
"integrity": "sha512-PfOtnshSyq15EKevKlFW9IRgH+dTtPG4Q9HJYksuRNYDzjce0eqK3Bf6hz0tAZdyqbzTCyx5g+NgWBfpqQfb2w==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nice-napi": {
|
"nice-napi": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz",
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
"@angular/router": "^14.2.0",
|
"@angular/router": "^14.2.0",
|
||||||
"bootstrap": "^5.2.1",
|
"bootstrap": "^5.2.1",
|
||||||
"jquery": "^3.6.1",
|
"jquery": "^3.6.1",
|
||||||
|
"ngx-google-analytics": "^14.0.1",
|
||||||
"rxjs": "~7.5.0",
|
"rxjs": "~7.5.0",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"webstorage-decorators": "^4.2.0",
|
"webstorage-decorators": "^4.2.0",
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import {BrowserModule} from '@angular/platform-browser';
|
import {BrowserModule} from '@angular/platform-browser';
|
||||||
|
import {NgxGoogleAnalyticsModule} from 'ngx-google-analytics';
|
||||||
|
import {environment} from '../environments/environment';
|
||||||
import {AppRouting} from './app.routing';
|
import {AppRouting} from './app.routing';
|
||||||
import {BannerComponent} from './components/banner/banner.component';
|
import {BannerComponent} from './components/banner/banner.component';
|
||||||
import {FooterComponent} from './components/footer/footer.component';
|
import {FooterComponent} from './components/footer/footer.component';
|
||||||
|
import {LogoComponent} from './components/logo/logo.component';
|
||||||
import {NavbarComponent} from './components/navbar/navbar.component';
|
import {NavbarComponent} from './components/navbar/navbar.component';
|
||||||
import {AppComponent} from './containers/app/app.component';
|
import {AppComponent} from './containers/app/app.component';
|
||||||
import {BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import {BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import {MaterialModule} from './material.module';
|
import {MaterialModule} from './material.module';
|
||||||
|
import {PrelaodService} from './services/prelaod.service';
|
||||||
import {FourOFourComponent} from './views/404/404.component';
|
import {FourOFourComponent} from './views/404/404.component';
|
||||||
import {AboutComponent} from './views/about/about.component';
|
import {AboutComponent} from './views/about/about.component';
|
||||||
import {AestivaComponent} from './views/events/aestiva/aestiva.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 {GettingStartedComponent} from './views/reenact/getting-started/getting-started.component';
|
||||||
import {RulesComponent} from './views/reenact/rules/rules.component';
|
import {RulesComponent} from './views/reenact/rules/rules.component';
|
||||||
|
|
||||||
export const APP_COMPONENTS = [
|
export const APP_COMPONENTS: any[] = [
|
||||||
AboutComponent,
|
AboutComponent,
|
||||||
AestivaComponent,
|
AestivaComponent,
|
||||||
AgoniumComponent,
|
AgoniumComponent,
|
||||||
@ -27,25 +31,33 @@ export const APP_COMPONENTS = [
|
|||||||
BannerComponent,
|
BannerComponent,
|
||||||
CalendarComponent,
|
CalendarComponent,
|
||||||
DrillComponent,
|
DrillComponent,
|
||||||
GettingStartedComponent,
|
|
||||||
HibernaComponent,
|
|
||||||
FooterComponent,
|
FooterComponent,
|
||||||
FourOFourComponent,
|
FourOFourComponent,
|
||||||
GalleryComponent,
|
GalleryComponent,
|
||||||
|
GettingStartedComponent,
|
||||||
|
HibernaComponent,
|
||||||
HomeComponent,
|
HomeComponent,
|
||||||
|
LogoComponent,
|
||||||
NavbarComponent,
|
NavbarComponent,
|
||||||
RulesComponent
|
RulesComponent
|
||||||
]
|
]
|
||||||
|
|
||||||
@NgModule({
|
export const APP_IMPORTS: any[] = [
|
||||||
declarations: APP_COMPONENTS,
|
|
||||||
imports: [
|
|
||||||
BrowserModule,
|
|
||||||
AppRouting,
|
AppRouting,
|
||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
|
BrowserModule,
|
||||||
MaterialModule
|
MaterialModule
|
||||||
],
|
]
|
||||||
|
|
||||||
|
if(environment.analytics && (<any>environment.analytics) != '{{ANALYTICS}}')
|
||||||
|
APP_IMPORTS.push(NgxGoogleAnalyticsModule.forRoot(<any>environment.analytics));
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: APP_COMPONENTS,
|
||||||
|
imports: APP_IMPORTS,
|
||||||
providers: [],
|
providers: [],
|
||||||
bootstrap: [AppComponent]
|
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 = [
|
const routes: Routes = [
|
||||||
{path: '', pathMatch: 'full', component: HomeComponent},
|
{path: '', pathMatch: 'full', component: HomeComponent},
|
||||||
{path: 'about', component: AboutComponent},
|
{path: 'about', component: AboutComponent, data: {title: 'About'}},
|
||||||
{path: 'drill', component: DrillComponent},
|
{path: 'drill', component: DrillComponent, data: {title: 'Drill Commands'}},
|
||||||
{path: 'events/aestiva', component: AestivaComponent},
|
{path: 'events/aestiva', component: AestivaComponent, data: {title: 'Castra Aestiva'}},
|
||||||
{path: 'events/agonium', component: AgoniumComponent},
|
{path: 'events/agonium', component: AgoniumComponent, data: {title: 'Agonium'}},
|
||||||
{path: 'events/hiberna', component: HibernaComponent},
|
{path: 'events/hiberna', component: HibernaComponent, data: {title: 'Castra Hiberna'}},
|
||||||
{path: 'events/calendar', component: CalendarComponent},
|
{path: 'events/calendar', component: CalendarComponent, data: {title: 'Calendar'}},
|
||||||
{path: 'gallery', component: GalleryComponent},
|
{path: 'gallery', component: GalleryComponent, data: {title: 'Gallery'}},
|
||||||
{path: 'getting-started', component: GettingStartedComponent},
|
{path: 'getting-started', component: GettingStartedComponent, data: {title: 'Getting Started'}},
|
||||||
{path: 'rules', component: RulesComponent},
|
{path: 'rules', component: RulesComponent, data: {title: 'Rules & Regulations'}},
|
||||||
{path: '**', component: FourOFourComponent}
|
{path: '**', component: FourOFourComponent, data: {title: '404'}}
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@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>
|
<div>
|
||||||
<a class="navbar-brand d-flex align-items-center" routerLink="/" fragment="banner" (click)="scroll('banner')">
|
<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">
|
<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>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow-1"></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 {ActivatedRoute, NavigationEnd, Router} from '@angular/router';
|
||||||
import {combineLatest, filter, Subscription} from 'rxjs';
|
import {combineLatest, filter, Subscription} from 'rxjs';
|
||||||
import {NAVIGATION} from '../../misc/navigation';
|
import {NAVIGATION} from '../../misc/navigation';
|
||||||
|
import {BreakpointService} from '../../services/breakpoint.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'xxx-navbar',
|
selector: 'xxx-navbar',
|
||||||
@ -20,7 +21,7 @@ export class NavbarComponent implements AfterViewInit, OnDestroy {
|
|||||||
|
|
||||||
@Output() hamburgerClick = new EventEmitter<void>();
|
@Output() hamburgerClick = new EventEmitter<void>();
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute, private router: Router) { }
|
constructor(private route: ActivatedRoute, private router: Router, public breakpoint: BreakpointService) { }
|
||||||
|
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
this.sub = combineLatest([this.router.events.pipe(filter(e => e instanceof NavigationEnd)), this.route.fragment]).subscribe(([url, frag]) => {
|
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 { Component } from '@angular/core';
|
||||||
import {ActivatedRoute, NavigationEnd, Router} from '@angular/router';
|
import {NavigationEnd, Router} from '@angular/router';
|
||||||
import {filter} from 'rxjs';
|
import {combineLatest, filter, Subscription} from 'rxjs';
|
||||||
|
import {BreakpointService} from '../../services/breakpoint.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
@ -9,15 +9,22 @@ import {filter} from 'rxjs';
|
|||||||
styleUrls: ['./app.component.scss']
|
styleUrls: ['./app.component.scss']
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
|
private sub?: Subscription;
|
||||||
|
|
||||||
mobile = false;
|
mobile = false;
|
||||||
open = false;
|
open = false;
|
||||||
|
|
||||||
constructor(private router: Router, route: ActivatedRoute, breakpointObserver: BreakpointObserver) {
|
constructor(private breakpoint: BreakpointService, private router: Router) {
|
||||||
router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe(() => this.open = false);
|
this.sub = combineLatest([
|
||||||
breakpointObserver.observe(['(max-width: 750px)']).subscribe(result => {
|
router.events.pipe(filter(event => event instanceof NavigationEnd)),
|
||||||
this.mobile = result.matches;
|
breakpoint.isMobile$
|
||||||
|
]).subscribe(([event, mobile]) => {
|
||||||
|
this.mobile = mobile;
|
||||||
this.open = !this.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 = {
|
export const environment = {
|
||||||
|
analytics: 'G-7HLT4FQY9V',
|
||||||
production: true
|
production: true
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
export const environment = {
|
export const environment = {
|
||||||
|
analytics: false,
|
||||||
production: false
|
production: false
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user