Skip to content
This repository was archived by the owner on Oct 28, 2024. It is now read-only.

Commit fddd613

Browse files
committed
customizable UI
Signed-off-by: Matthew Fisher <matt.fisher@fermyon.com>
1 parent 2004fd0 commit fddd613

File tree

14 files changed

+103
-29
lines changed

14 files changed

+103
-29
lines changed

src/Web/ClientApp/angular.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@
9494
"src/assets"
9595
],
9696
"styles": [
97-
"src/styles.css"
97+
"src/styles.scss"
9898
],
9999
"scripts": []
100100
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export interface AppConfig {
2+
title?: string;
3+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { HttpClient } from "@angular/common/http";
2+
import { Injectable } from "@angular/core";
3+
import { AppConfig } from "../_interfaces/app-config";
4+
5+
@Injectable({ providedIn: 'root' })
6+
export class AppConfigService {
7+
private config: any;
8+
9+
constructor(private readonly http: HttpClient) { }
10+
11+
load(defaults?: AppConfig): Promise<AppConfig> {
12+
return new Promise<AppConfig>(resolve => {
13+
this.http.get('/assets/config.json').subscribe(
14+
{
15+
next: (response) => {
16+
console.log('using server-side configuration')
17+
this.config = Object.assign({}, defaults || {}, response || {});
18+
resolve(this.config);
19+
},
20+
error: () => {
21+
console.log('using default configuration');
22+
this.config = Object.assign({}, defaults || {});
23+
resolve(this.config);
24+
}
25+
}
26+
);
27+
});
28+
}
29+
30+
get title() : string {
31+
return this.config.title;
32+
}
33+
}
Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
import { NgModule } from "@angular/core";
2-
import { RouterModule, Routes } from "@angular/router";
1+
import { Injectable, NgModule } from "@angular/core";
2+
import { Title } from "@angular/platform-browser";
3+
import { RouterModule, RouterStateSnapshot, Routes, TitleStrategy } from "@angular/router";
4+
import { environment } from "src/environments/environment";
35
import { LoginComponent } from "./components/account/login/login.component";
46
import { RegisterComponent } from "./components/account/register/register.component";
57
import { ListComponent } from "./components/application/list/list.component";
@@ -8,21 +10,39 @@ import { ChannelComponent } from "./components/channel/channel.component";
810
import { NotFoundComponent } from "./components/not-found/not-found.component";
911
import { StyleguideComponent } from "./components/styleguide/styleguide.component";
1012
import { AuthGuard } from "./_helpers/auth.guard";
13+
import { AppConfigService } from "./_services/app-config.service";
1114

1215
const routes: Routes = [
13-
{ path: '404', component: NotFoundComponent },
14-
{ path: 'channel/:id', component: ChannelComponent, canActivate: [AuthGuard] },
15-
{ path: 'app/new', component: NewComponent, canActivate: [AuthGuard] },
16-
{ path: 'login', component: LoginComponent },
17-
{ path: 'register', component: RegisterComponent },
18-
{ path: 'styleguide', component: StyleguideComponent },
19-
{ path: '', component: ListComponent, canActivate: [AuthGuard] },
20-
{ path: '**', redirectTo: '404' }
16+
{ path: '404', component: NotFoundComponent, title: 'Not Found' },
17+
{ path: 'channel/:id', component: ChannelComponent, canActivate: [AuthGuard], title: 'Overview' },
18+
{ path: 'app/new', component: NewComponent, canActivate: [AuthGuard], title: 'Create a new App' },
19+
{ path: 'login', component: LoginComponent, title: 'Log in' },
20+
{ path: 'register', component: RegisterComponent , title: 'Sign up' },
21+
{ path: 'styleguide', component: StyleguideComponent, title: 'Style Guide' },
22+
{ path: '', component: ListComponent, canActivate: [AuthGuard], title: 'Dashboard' },
23+
{ path: '**', redirectTo: '404' }
2124
];
2225

26+
@Injectable()
27+
export class TemplatePageTitleStrategy extends TitleStrategy {
28+
constructor(private readonly title: Title, private readonly appConfigService: AppConfigService) {
29+
super();
30+
}
31+
32+
override updateTitle(routerState: RouterStateSnapshot) {
33+
const title = this.buildTitle(routerState);
34+
if (title !== undefined) {
35+
this.title.setTitle(`${this.appConfigService.title} | ${title}`);
36+
}
37+
}
38+
}
39+
2340
@NgModule({
2441
imports: [RouterModule.forRoot(routes, { useHash: true })],
25-
exports: [RouterModule]
42+
exports: [RouterModule],
43+
providers: [
44+
{provide: TitleStrategy, useClass: TemplatePageTitleStrategy},
45+
]
2646
})
2747

2848
export class AppRoutingModule { }
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import { Component } from '@angular/core';
2+
import { AppConfigService } from './_services/app-config.service';
23

34
@Component({
45
selector: 'app-root',
56
templateUrl: './app.component.html',
67
styleUrls: ['./app.component.scss']
78
})
89
export class AppComponent {
9-
title = 'Hippo';
10+
constructor(private readonly appConfigService: AppConfigService) { }
11+
12+
title = this.appConfigService.title;
1013
}

src/Web/ClientApp/src/app/app.module.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { NgModule } from '@angular/core';
1+
import { APP_INITIALIZER, NgModule } from '@angular/core';
22
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
33
import { BrowserModule } from '@angular/platform-browser';
44
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
@@ -20,11 +20,11 @@ import { NewComponent } from './components/application/new/new.component';
2020
import { NewComponent as NewChannelComponent } from './components/channel/new/new.component';
2121
import { ChannelComponent } from './components/channel/channel.component';
2222
import { HealthCheckComponent } from './components/health-check/health-check.component';
23-
import { environment } from './../environments/environment';
2423
import { SettingsComponent } from './components/application/settings/settings.component';
2524
import { LogsComponent } from './components/channel/logs/logs.component';
2625
import { OverviewComponent } from './components/channel/overview/overview.component';
2726
import { NgxJdenticonModule, JDENTICON_CONFIG } from 'ngx-jdenticon';
27+
import { AppConfigService } from './_services/app-config.service';
2828

2929
export function apiConfigFactory(): Configuration {
3030
const params: ConfigurationParameters = {
@@ -78,6 +78,12 @@ export function apiConfigFactory(): Configuration {
7878
useValue: {
7979
replaceMode: "observe"
8080
}
81+
},
82+
{
83+
provide: APP_INITIALIZER,
84+
multi: true,
85+
deps: [AppConfigService],
86+
useFactory: (appConfigService : AppConfigService) => () => appConfigService.load()
8187
}
8288
],
8389
bootstrap: [AppComponent]

src/Web/ClientApp/src/app/components/account/login/login.component.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<h1 class="title has-text-centered">Log in to <span class="has-text-primary">Hippo</span></h1>
1+
<h1 class="title has-text-primary has-text-centered">Log in</h1>
22

33
<article *ngIf="error" class="message is-danger">
44
<div class="message-header">
@@ -16,7 +16,7 @@ <h1 class="title has-text-centered">Log in to <span class="has-text-primary">Hip
1616
<div class="control has-icons-left has-icons-right">
1717
<input type="text" formControlName="username"
1818
[ngClass]="{ 'is-danger': submitted && f['username'].errors }"
19-
class="input" placeholder="e.g. rhymenoceros" />
19+
class="input" placeholder="Enter your username here" />
2020
<div *ngIf="submitted && f['username'].errors" class="help is-danger">
2121
<div *ngIf="f['username'].errors['required']">Username is required.</div>
2222
</div>
@@ -28,7 +28,7 @@ <h1 class="title has-text-centered">Log in to <span class="has-text-primary">Hip
2828
<div class="control has-icons-left">
2929
<input type="password" formControlName="password"
3030
[ngClass]="{ 'is-danger': submitted && f['password'].errors }"
31-
class="input" placeholder="make it strong!" />
31+
class="input" />
3232
<div *ngIf="submitted && f['password'].errors" class="help is-danger">
3333
<div *ngIf="f['password'].errors['required']">Password is required.</div>
3434
</div>

src/Web/ClientApp/src/app/components/account/register/register.component.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<div class="control has-icons-left has-icons-right">
1616
<input type="text" formControlName="username"
1717
[ngClass]="{ 'is-danger': submitted && f['username'].errors }"
18-
class="input" placeholder="e.g. rhymenoceros" />
18+
class="input" />
1919
<div *ngIf="submitted && f['username'].errors" class="help is-danger">
2020
<div *ngIf="f['username'].errors['required']">Username is required.</div>
2121
</div>
@@ -27,7 +27,7 @@
2727
<div class="control has-icons-left">
2828
<input type="password" formControlName="password"
2929
[ngClass]="{ 'is-danger': submitted && f['password'].errors }"
30-
class="input" placeholder="make it strong!" />
30+
class="input" />
3131
<div *ngIf="submitted && f['password'].errors" class="help is-danger">
3232
<div *ngIf="f['password'].errors['required']">Password is required.</div>
3333
<div *ngIf="f['password'].errors['minlength']">Password must be at least 6 characters long.</div>
@@ -43,7 +43,7 @@
4343
<div class="control has-icons-left">
4444
<input type="password" formControlName="passwordConfirm"
4545
[ngClass]="{ 'is-danger': submitted && f['passwordConfirm'].errors }"
46-
class="input" placeholder="make it strong!" />
46+
class="input" />
4747
<div *ngIf="submitted && f['passwordConfirm'].errors" class="help is-danger">
4848
<div *ngIf="f['passwordConfirm'].errors['required']">Password is required.</div>
4949
<div *ngIf="f['passwordConfirm'].errors['minlength']">Password must be at least 6 characters long.</div>

src/Web/ClientApp/src/app/components/navbar/navbar.component.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,11 @@
22
margin: 2rem 4rem;
33
font-size: 1.25rem;
44
}
5+
6+
.navbar-brand {
7+
padding-left: 1rem;
8+
}
9+
10+
.navbar-end {
11+
padding-right: 1rem;
12+
}

src/Web/ClientApp/src/app/components/navbar/navbar.component.html

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
<nav class="navbar" role="navigation" aria-label="main navigation">
1+
<nav id="topbar" class="navbar" role="navigation" aria-label="main navigation">
22
<div class="navbar-brand">
33
<a class="navbar-item" routerLink="/">
4-
<fa-icon [icon]="faHippo" size="2x"></fa-icon><h1 class="title">Hippo</h1>
4+
<div class="logo">
5+
<img src="/assets/logo.svg" alt="banner logo" />
6+
</div>
57
</a>
68

79
<a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="hippoMenu">

0 commit comments

Comments
 (0)