dev env setup

This commit is contained in:
tw-blue
2025-12-06 21:27:29 +01:00
parent 987a380758
commit bc9f0f9f3b
38 changed files with 5953 additions and 733 deletions
+1
View File
@@ -39,6 +39,7 @@
"zone.js": "~0.15.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^21.0.2",
"@angular/build": "^20.3.8",
"@angular/cli": "^20.3.8",
"@angular/compiler-cli": "^20.3.0",
+3 -2
View File
@@ -1,5 +1,6 @@
import {
ApplicationConfig,
isDevMode,
provideBrowserGlobalErrorListeners,
provideZoneChangeDetection,
} from '@angular/core';
@@ -29,7 +30,7 @@ export const appConfig: ApplicationConfig = {
provideZoneChangeDetection({ eventCoalescing: true }),
provideKeycloak({
config: {
url: 'https://keycloak.toni714.de:8443/',
url: isDevMode() ? 'http://localhost:8080/' : 'https://keycloak.toni714.de:8443/',
realm: 'taekwondo',
clientId: 'angular-frontend',
},
@@ -44,7 +45,7 @@ export const appConfig: ApplicationConfig = {
provide: INCLUDE_BEARER_TOKEN_INTERCEPTOR_CONFIG,
useValue: [
createInterceptorCondition<IncludeBearerTokenCondition>({
urlPattern: /^https:\/\/tkd-api\.toni714\.de.*$/,
urlPattern: isDevMode()? /^http:\/\/localhost:3000.*$/ : /^https:\/\/tkd-api\.toni714\.de.*$/,
}),
],
},
+3 -3
View File
@@ -1,7 +1,7 @@
@if(this.loggedIn()){
@if(this.auth.loggedIn()){
<div class="no-print">
<button mat-flat-button color="accent" (click)="onLogOut()">LogOut</button>
<a mat-stroked-button color="primary" [routerLink]="['/home']">Home</a>
<button mat-flat-button color="accent" (click)="this.auth.logout()">LogOut</button>
<button mat-stroked-button color="primary" [routerLink]="['/home']">Home</button>
</div>
}
<router-outlet></router-outlet>
+7 -2
View File
@@ -16,7 +16,7 @@ export const roles = {
MemberAdmin: 'memberadmin',
};
function requireRoles(roles: string[], any: boolean = false): CanActivateFn {
function requireRoles(roles: string[]=[], any: boolean = false): CanActivateFn {
const isAllowed = async (
_: ActivatedRouteSnapshot,
__: RouterStateSnapshot,
@@ -44,7 +44,12 @@ export const routes: Routes = [
{
path: '',
loadComponent: () => import('./components/home/home').then((mod) => mod.Home),
canActivate: [requireRoles([roles.MemberAdmin, roles.UserAdmin], true)],
canActivate: [requireRoles()],
},
{
path: 'home',
loadComponent: () => import('./components/home/home').then((mod) => mod.Home),
canActivate: [requireRoles()],
},
{ path: '**', component: MissingPage },
];
+3 -6
View File
@@ -1,6 +1,7 @@
import { Component, signal } from '@angular/core';
import { Component, inject, signal } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule, RouterOutlet } from '@angular/router';
import { Authentication } from './services/authentication';
@Component({
selector: 'app-root',
@@ -9,10 +10,6 @@ import { RouterModule, RouterOutlet } from '@angular/router';
styleUrl: './app.scss',
})
export class App {
protected loggedIn = signal(false);
protected readonly title = signal('frontend');
protected onLogOut() {
this.loggedIn.set(false);
}
protected readonly auth = inject(Authentication);
}
@@ -1 +1,14 @@
<p>home works!</p>
<h1>Startseite</h1>
<ul>
<!--TODO fix theming/colors-->
<button matButton="outlined" class="warn-button" [routerLink]="['/test']">
Entwichlungsinformationen
</button>
<button matButton="filled" color="primary" [routerLink]="['/list']">Mitglieder</button>
<button matButton="filled" color="warn" [routerLink]="['/manageUsers']">
Benutzer Verwalten
</button>
<button matButton="filled" color="primary" [routerLink]="['/exam']">
Prüfungsanmeldung
</button>
</ul>
@@ -1,8 +1,10 @@
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router';
@Component({
selector: 'app-home',
imports: [],
imports: [RouterModule, MatButtonModule],
templateUrl: './home.html',
styleUrl: './home.scss',
})
@@ -1,4 +1,5 @@
import { Component, inject } from '@angular/core';
import { Router } from '@angular/router';
import { Authentication } from '../../services/authentication';
@Component({
@@ -9,7 +10,13 @@ import { Authentication } from '../../services/authentication';
})
export class Login {
private readonly authentication = inject(Authentication);
private readonly router = inject(Router);
public constructor() {
this.authentication.login();
if(this.authentication.loggedIn()){
this.router.navigate(['/home']);
}else{
this.authentication.login();
}
}
}
@@ -1,4 +1,4 @@
import { effect, inject, Injectable, signal } from '@angular/core';
import { computed, effect, inject, Injectable, signal } from '@angular/core';
import {
KEYCLOAK_EVENT_SIGNAL,
KeycloakEventType,
@@ -22,6 +22,9 @@ export class Authentication {
private readonly _authenticationState = signal<AuthenticationState>(AuthenticationState.Unknown);
private readonly _userInfo = signal<KeycloakProfile | null>(null);
public readonly authenticationState = this._authenticationState.asReadonly();
public readonly loggedIn = computed(()=>{
return this.authenticationState() === AuthenticationState.Authenticated;
});
public readonly userInfo = this._userInfo.asReadonly();
public constructor() {
@@ -69,6 +72,10 @@ export class Authentication {
}
public async login(location?: string): Promise<void> {
if(this._authenticationState() === AuthenticationState.Authenticated){
return;
}
var redirectUri = location
? `${window.location.origin}/${location}`
: `${window.location.origin}/login`;
+205
View File
@@ -0,0 +1,205 @@
// This file was generated by running 'ng generate @angular/material:theme-color'.
// Proceed with caution if making changes to this file.
@use 'sass:map';
@use '@angular/material' as mat;
// Note: Color palettes are generated from primary: #0047a0, secondary: #cc9c00, tertiary: #cd2e3a, error: #E63241
$_palettes: (
primary: (
0: #000000,
10: #001a43,
20: #002d6c,
25: #003881,
30: #004397,
35: #134fa8,
40: #275bb5,
50: #4575cf,
60: #618feb,
70: #83aaff,
80: #afc6ff,
90: #d8e2ff,
95: #edf0ff,
98: #faf9ff,
99: #fefbff,
100: #ffffff,
),
secondary: (
0: #000000,
10: #251a00,
20: #3f2e00,
25: #4c3800,
30: #5a4300,
35: #694f00,
40: #775a00,
50: #967200,
60: #b58a00,
70: #d5a411,
80: #f3bf33,
90: #ffdf99,
95: #ffefd2,
98: #fff8f2,
99: #fffbff,
100: #ffffff,
),
tertiary: (
0: #000000,
10: #410007,
20: #680010,
25: #7d0016,
30: #92001b,
35: #a60a23,
40: #b81d2d,
50: #db3943,
60: #ff535a,
70: #ff8887,
80: #ffb3b0,
90: #ffdad8,
95: #ffedeb,
98: #fff8f7,
99: #fffbff,
100: #ffffff,
),
neutral: (
0: #000000,
10: #191b21,
20: #2e3036,
25: #393b42,
30: #45464d,
35: #515259,
40: #5d5e65,
50: #75777e,
60: #8f9098,
70: #aaabb2,
80: #c5c6ce,
90: #e2e2ea,
95: #f0f0f8,
98: #faf9ff,
99: #fefbff,
100: #ffffff,
4: #0c0e14,
6: #111319,
12: #1d1f25,
17: #282a30,
22: #33353b,
24: #37393f,
87: #d9d9e1,
92: #e7e7f0,
94: #ededf5,
96: #f3f3fb,
),
neutral-variant: (
0: #000000,
10: #171b25,
20: #2c303b,
25: #373b46,
30: #434752,
35: #4e525e,
40: #5a5e6a,
50: #737783,
60: #8d909d,
70: #a7abb8,
80: #c3c6d4,
90: #dfe2f0,
95: #edf0ff,
98: #faf9ff,
99: #fefbff,
100: #ffffff,
),
error: (
0: #000000,
10: #410007,
20: #680011,
25: #7d0016,
30: #92001c,
35: #a90021,
40: #bd0b29,
50: #e12e3e,
60: #ff535a,
70: #ff8887,
80: #ffb3b1,
90: #ffdad8,
95: #ffedeb,
98: #fff8f7,
99: #fffbff,
100: #ffffff,
),
);
$_rest: (
secondary: map.get($_palettes, secondary),
neutral: map.get($_palettes, neutral),
neutral-variant: map.get($_palettes, neutral-variant),
error: map.get($_palettes, error),
);
$primary-palette: map.merge(map.get($_palettes, primary), $_rest);
$tertiary-palette: map.merge(map.get($_palettes, tertiary), $_rest);
@function _high-contrast-value($light, $dark, $theme-type) {
@if ($theme-type == light) {
@return $light;
}
@if ($theme-type == dark) {
@return $dark;
}
@if ($theme-type == color-scheme) {
@return light-dark(#{$light}, #{$dark});
}
@error 'Unknown theme-type #{$theme-type}. Expected light, dark, or color-scheme';
}
@mixin high-contrast-overrides($theme-type) {
@include mat.theme-overrides((
primary: _high-contrast-value(#002963, #ecefff, $theme-type),
on-primary: _high-contrast-value(#ffffff, #000000, $theme-type),
primary-container: _high-contrast-value(#00459c, #a9c2ff, $theme-type),
on-primary-container: _high-contrast-value(#ffffff, #000a23, $theme-type),
inverse-primary: _high-contrast-value(#afc6ff, #00449a, $theme-type),
primary-fixed: _high-contrast-value(#00459c, #d8e2ff, $theme-type),
primary-fixed-dim: _high-contrast-value(#003070, #afc6ff, $theme-type),
on-primary-fixed: _high-contrast-value(#ffffff, #000000, $theme-type),
on-primary-fixed-variant: _high-contrast-value(#ffffff, #00102f, $theme-type),
secondary: _high-contrast-value(#392a00, #ffeecf, $theme-type),
on-secondary: _high-contrast-value(#ffffff, #000000, $theme-type),
secondary-container: _high-contrast-value(#5d4600, #efbb2f, $theme-type),
on-secondary-container: _high-contrast-value(#ffffff, #110a00, $theme-type),
secondary-fixed: _high-contrast-value(#5d4600, #ffdf99, $theme-type),
secondary-fixed-dim: _high-contrast-value(#413000, #f3bf33, $theme-type),
on-secondary-fixed: _high-contrast-value(#ffffff, #000000, $theme-type),
on-secondary-fixed-variant: _high-contrast-value(#ffffff, #181000, $theme-type),
tertiary: _high-contrast-value(#60000e, #ffecea, $theme-type),
on-tertiary: _high-contrast-value(#ffffff, #000000, $theme-type),
tertiary-container: _high-contrast-value(#97001c, #ffadab, $theme-type),
on-tertiary-container: _high-contrast-value(#ffffff, #220002, $theme-type),
tertiary-fixed: _high-contrast-value(#97001c, #ffdad8, $theme-type),
tertiary-fixed-dim: _high-contrast-value(#6c0011, #ffb3b0, $theme-type),
on-tertiary-fixed: _high-contrast-value(#ffffff, #000000, $theme-type),
on-tertiary-fixed-variant: _high-contrast-value(#ffffff, #2d0003, $theme-type),
background: _high-contrast-value(#faf9ff, #111319, $theme-type),
on-background: _high-contrast-value(#191b21, #e2e2ea, $theme-type),
surface: _high-contrast-value(#faf9ff, #111319, $theme-type),
surface-dim: _high-contrast-value(#b8b8c0, #111319, $theme-type),
surface-bright: _high-contrast-value(#faf9ff, #4e5056, $theme-type),
surface-container-low: _high-contrast-value(#f0f0f8, #1d1f25, $theme-type),
surface-container-lowest: _high-contrast-value(#ffffff, #000000, $theme-type),
surface-container: _high-contrast-value(#e2e2ea, #2e3036, $theme-type),
surface-container-high: _high-contrast-value(#d3d4dc, #393b42, $theme-type),
surface-container-highest: _high-contrast-value(#c5c6ce, #45464d, $theme-type),
on-surface: _high-contrast-value(#000000, #ffffff, $theme-type),
shadow: _high-contrast-value(#000000, #000000, $theme-type),
scrim: _high-contrast-value(#000000, #000000, $theme-type),
surface-tint: _high-contrast-value(#275bb5, #afc6ff, $theme-type),
inverse-surface: _high-contrast-value(#2e3036, #e2e2ea, $theme-type),
inverse-on-surface: _high-contrast-value(#ffffff, #000000, $theme-type),
outline: _high-contrast-value(#282c37, #edeffe, $theme-type),
outline-variant: _high-contrast-value(#454954, #bfc2d0, $theme-type),
error: _high-contrast-value(#60000e, #ffecea, $theme-type),
on-error: _high-contrast-value(#ffffff, #000000, $theme-type),
error-container: _high-contrast-value(#97001d, #ffadab, $theme-type),
on-error-container: _high-contrast-value(#ffffff, #220002, $theme-type),
surface-variant: _high-contrast-value(#dfe2f0, #434752, $theme-type),
on-surface-variant: _high-contrast-value(#000000, #ffffff, $theme-type),
))
}
+16 -8
View File
@@ -5,16 +5,24 @@
// Learn more about theming and how to use it for your application's
// custom components at https://material.angular.dev/guide/theming
@use '@angular/material' as mat;
@use './styles.colors.scss' as my-theme;
@include mat.core();
@include mat.all-component-themes(my-theme.$light-theme);
@include mat.color-variants-backwards-compatibility(my-theme.$light-theme);
html {
@include mat.theme((
color: (
primary: mat.$cyan-palette,
tertiary: mat.$orange-palette,
),
typography: Roboto,
density: 0,
));
// @include mat.theme((
// color: (
// primary: my-theme.$primary-palette,
// tertiary: my-theme.$tertiary-palette,
// ),
// typography: Roboto,
// density: 0,
// ));
@include mat.core-theme(my-theme.$light-theme);
@include mat.button-theme(my-theme.$light-theme);
}
body {