diff --git a/Dockerfile b/Dockerfile index 6271c84..6fe780d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ RUN apk update RUN apk upgrade RUN apk add bash -### Configuration of NGINX +### ConfigurationInterface of NGINX COPY docker/nginx.conf /etc/nginx/nginx.template.conf EXPOSE 80 diff --git a/docker/env.template.js b/docker/env.template.js index b84a68c..944c9c3 100644 --- a/docker/env.template.js +++ b/docker/env.template.js @@ -20,7 +20,10 @@ "REPORTER_DEFAULT_TEMPLATE_ID": "${REPORTER_DEFAULT_TEMPLATE_ID}", "EXPORTER_DEFAULT_TEMPLATE_ID": "${EXPORTER_DEFAULT_TEMPLATE_ID}", "TEILER_USER": "${TEILER_USER}", - "TEILER_ADMIN": "${TEILER_ADMIN}" + "TEILER_ADMIN": "${TEILER_ADMIN}", + "BACKGROUND_IMAGE_URL": "${BACKGROUND_IMAGE_URL}", + "LOGO_URL": "${LOGO_URL}", + "COLOR_PALETTE": "${COLOR_PALETTE}", }; })(this); diff --git a/src/app/app.component.css b/src/app/app.component.css index 88d46ec..a57c374 100644 --- a/src/app/app.component.css +++ b/src/app/app.component.css @@ -16,6 +16,7 @@ --color-green: #06D6A0; } + h1, h2, h3, @@ -34,6 +35,8 @@ h6 { display: flex; flex-direction: column; min-height: 100vh; + color: var(--text-color); + font-family: var(--font-style); } /* header */ @@ -52,7 +55,6 @@ h6 { } .toolbar * { - color: black; text-decoration: none; } @@ -98,6 +100,17 @@ h6 { .login-link span { color: rgb(0, 102, 204); } +.b-img{ + position: absolute; + top: 0; + left: 0; + width: 100%; + min-height: 100%; + z-index: 0; + background-size: cover; + background-repeat: no-repeat; +} + @media screen and (min-width: 768px) { .toolbar { grid-template-columns: auto 1fr auto; diff --git a/src/app/app.component.html b/src/app/app.component.html index c4d8a5e..4a1b26a 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -2,7 +2,7 @@
@@ -26,16 +26,9 @@
-
+ DKTK Teiler + diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 68b382f..ff68188 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -2,7 +2,8 @@ import {Component, OnInit} from '@angular/core'; import {RouteManagerService} from "./route/route-manager.service"; import {TeilerAuthService} from "./security/teiler-auth.service"; import {from, Observable} from "rxjs"; -import { ColorSchemeService } from './color-scheme.service'; +import {environment} from "../environments/environment"; +import {ColorPaletteService} from "./color-palette.service"; @Component({ @@ -10,23 +11,53 @@ import { ColorSchemeService } from './color-scheme.service'; templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) -export class AppComponent { - selectedColor: string = 'lightgrey'; +export class AppComponent implements OnInit{ title = 'teiler-dashboard'; isLoggedIn: boolean = false; user: string = ''; - constructor(public routeManagerService: RouteManagerService, public authService: TeilerAuthService,private colorSchemeService: ColorSchemeService) { + constructor(public routeManagerService: RouteManagerService, public authService: TeilerAuthService, private colorPaletteService: ColorPaletteService) { from(authService.isLoggedId()).subscribe(isLoggedIn => { this.isLoggedIn = isLoggedIn; - if (isLoggedIn){ - from(authService.loadUserProfile()).subscribe(keycloakProfile => this.user = keycloakProfile.firstName + ' '+ keycloakProfile.lastName); + if (isLoggedIn) { + from(authService.loadUserProfile()).subscribe(keycloakProfile => this.user = keycloakProfile.firstName + ' ' + keycloakProfile.lastName); } }); } - changeColor() { - this.colorSchemeService.setColor(this.selectedColor); + + ngOnInit(): void { + this.colorPaletteService.getPalettesLoadedStatus().subscribe(loaded => { + if (loaded) { + const selectedPaletteName = this.colorPaletteService.getSelectedPaletteName(); + if (selectedPaletteName) { + this.setCSSVariables(); + } else { + console.error('Keine Farbpalette ausgewählt.'); + } + } else { + console.error('Farbpaletten wurden nicht geladen.'); + } + }); + } + + private setCSSVariables() { + + const iconColor = this.colorPaletteService.getIconColor(); + const textColor = this.colorPaletteService.getTextColor(); + const lineColor = this.colorPaletteService.getLineColor(); + const fontStyle = this.colorPaletteService.getFontStyle() + ', sans-serif'; + + this.setCSSVariable('--icon-color', iconColor); + this.setCSSVariable('--text-color', textColor); + this.setCSSVariable('--line-color', lineColor); + this.setCSSVariable('--font-style', fontStyle); } + + private setCSSVariable(variableName: string, value: string) { + document.documentElement.style.setProperty(variableName, value); + } + + protected readonly environment = environment; } diff --git a/src/app/color-palette.model.ts b/src/app/color-palette.model.ts new file mode 100644 index 0000000..d07c01c --- /dev/null +++ b/src/app/color-palette.model.ts @@ -0,0 +1,15 @@ +export interface ColorPalette { + name: string; + colors: { + icon: string; + text: string; + line: string; + }; + style: { + font: string; + }; +} + +export interface ColorPalettes { + 'color-palettes': ColorPalette[]; +} diff --git a/src/app/color-palette.service.spec.ts b/src/app/color-palette.service.spec.ts new file mode 100644 index 0000000..bf4cd1c --- /dev/null +++ b/src/app/color-palette.service.spec.ts @@ -0,0 +1,91 @@ +import { TestBed } from '@angular/core/testing'; +import { ColorPaletteService } from './color-palette.service'; +import { ColorPalette, ColorPalettes } from './color-palette.model'; +import * as data from '../assets/color-palettes.json'; +import { environment } from '../environments/environment'; + +describe('ColorPaletteService', () => { + let service: ColorPaletteService; + const mockPalettes: ColorPalettes = (data as any).default; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(ColorPaletteService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + it('should load color palettes on initialization', () => { + spyOn(console, 'log'); + service = new ColorPaletteService(); + expect(console.log).toHaveBeenCalledWith('loadColorPalettes method called'); + expect(service['colorPalettes']).toEqual(jasmine.objectContaining(mockPalettes['color-palettes'].reduce((acc: { [key: string]: ColorPalette }, palette: ColorPalette) => { + acc[palette.name] = palette; + return acc; + }, {}))); + expect(console.log).toHaveBeenCalledWith('Color palettes loaded successfully:', service['colorPalettes']); + }); + + it('should set palettesLoaded$ to true after loading palettes', () => { + service = new ColorPaletteService(); + expect(service.getPalettesLoadedStatus().getValue()).toBe(true); + }); + + it('should select palette specified in environment configuration', () => { + service = new ColorPaletteService(); + const paletteName = environment.config.COLOR_PALETTE; + expect(service.getSelectedPaletteName()).toBe(paletteName); + }); + + it('should return font style of selected palette', () => { + const mockPalette: ColorPalette = mockPalettes['color-palettes'][0]; + service.selectPalette(mockPalette.name); + expect(service.getFontStyle()).toBe(mockPalette.style.font); + }); + + it('should return default color if no palette is selected when getting font style', () => { + expect(service.getFontStyle()).toBe('defaultColor'); + }); + + it('should return background color of selected palette', () => { + const mockPalette: ColorPalette = mockPalettes['color-palettes'][0]; + service.selectPalette(mockPalette.name); + expect(service.getBackgroundColor()).toBe(mockPalette.colors.background); + }); + + it('should return default color if no palette is selected when getting background color', () => { + expect(service.getBackgroundColor()).toBe('defaultColor'); + }); + + it('should return text color of selected palette', () => { + const mockPalette: ColorPalette = mockPalettes['color-palettes'][0]; + service.selectPalette(mockPalette.name); + expect(service.getTextColor()).toBe(mockPalette.colors.text); + }); + + it('should return default color if no palette is selected when getting text color', () => { + expect(service.getTextColor()).toBe('defaultColor'); + }); + + it('should return line color of selected palette', () => { + const mockPalette: ColorPalette = mockPalettes['color-palettes'][0]; + service.selectPalette(mockPalette.name); + expect(service.getLineColor()).toBe(mockPalette.colors.line); + }); + + it('should return default color if no palette is selected when getting line color', () => { + expect(service.getLineColor()).toBe('defaultColor'); + }); + + it('should return icon color of selected palette', () => { + const mockPalette: ColorPalette = mockPalettes['color-palettes'][0]; + service.selectPalette(mockPalette.name); + expect(service.getIconColor()).toBe(mockPalette.colors.icon); + }); + + it('should return default color if no palette is selected when getting icon color', () => { + expect(service.getIconColor()).toBe('defaultColor'); + }); +}); diff --git a/src/app/color-palette.service.ts b/src/app/color-palette.service.ts new file mode 100644 index 0000000..aa929ae --- /dev/null +++ b/src/app/color-palette.service.ts @@ -0,0 +1,112 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject } from 'rxjs'; +import { environment } from '../environments/environment'; +import { ColorPalettes, ColorPalette } from './color-palette.model'; +import * as localData from '../assets/color-palettes.json'; +import { HttpClient } from '@angular/common/http'; + +@Injectable({ + providedIn: 'root' +}) +export class ColorPaletteService { + + private colorPalettes: { [key: string]: ColorPalette } = {}; + private selectedPalette: ColorPalette | null = null; + private palettesLoaded$: BehaviorSubject = new BehaviorSubject(false); + + constructor(private http: HttpClient) { + this.loadColorPalettes(); + } + + private loadColorPalettes(): void { + const paletteConfig = environment.config.COLOR_PALETTE; + + if (this.isUrl(paletteConfig)) { + // Farbpaletten vom Server laden + this.http.get(paletteConfig).subscribe( + palettes => { + this.processColorPalettes(palettes); + // Der Name der Farbpalette ist im URL-Parameter enthalten + const url = new URL(paletteConfig); + const paletteName = url.hash.substring(1); + this.selectPalette(paletteName); + }, + error => { + console.error('Fehler beim Laden der Farbpaletten vom Server', error); + this.palettesLoaded$.next(false); + } + ); + } else { + // Lokale Farbpaletten laden + this.loadLocalColorPalettes(paletteConfig); + } + } + + private isUrl(paletteConfig: string): boolean { + try { + new URL(paletteConfig); + return true; + } catch (_) { + return false; + } + } + + private loadLocalColorPalettes(paletteName: string): void { + console.log('loadLocalColorPalettes method called'); // Vor dem Laden der Farbpaletten + const palettes: ColorPalettes = (localData as any).default; + this.processColorPalettes(palettes); + this.selectPalette(paletteName); + } + + private processColorPalettes(palettes: ColorPalettes): void { + palettes['color-palettes'].forEach(palette => { + this.colorPalettes[palette.name] = palette; + }); + console.log('Color palettes loaded successfully:', this.colorPalettes); // Nach dem Laden der Farbpaletten + this.palettesLoaded$.next(true); + } + + selectPalette(paletteName: string) { + this.selectedPalette = this.colorPalettes[paletteName]; + } + + getPalettesLoadedStatus(): BehaviorSubject { + return this.palettesLoaded$; + } + + getSelectedPaletteName(): string | null { + return this.selectedPalette ? this.selectedPalette.name : null; + } + + getFontStyle(): string { + if (!this.selectedPalette) { + console.error('No palette selected.'); + return 'defaultColor'; + } + return this.selectedPalette.style.font; + } + + getTextColor(): string { + if (!this.selectedPalette) { + console.error('No palette selected.'); + return 'defaultColor'; + } + return this.selectedPalette.colors.text; + } + + getLineColor(): string { + if (!this.selectedPalette) { + console.error('No palette selected.'); + return 'defaultColor'; + } + return this.selectedPalette.colors.line; + } + + getIconColor(): string { + if (!this.selectedPalette) { + console.error('No palette selected.'); + return 'defaultColor'; + } + return this.selectedPalette.colors.icon; + } +} diff --git a/src/app/configuration.service.spec.ts b/src/app/configuration.service.spec.ts new file mode 100644 index 0000000..6440dc3 --- /dev/null +++ b/src/app/configuration.service.spec.ts @@ -0,0 +1,17 @@ +import { TestBed } from '@angular/core/testing'; + +// @ts-ignore +import { ConfigurationService } from './configuration.service'; + +describe('ConfigurationService', () => { + let service: ConfigurationService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(ConfigurationService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/embedded/boxes.ts b/src/app/embedded/boxes.ts deleted file mode 100644 index fdc3df3..0000000 --- a/src/app/embedded/boxes.ts +++ /dev/null @@ -1,98 +0,0 @@ -export interface Boxes { - id: number; - inf: string; - inf1: string; - inf2: string; - inf3: string; - inf4: string; - inf5: string; - name: string; - icon: object; - icon_source: string; - -} -export const boxes =[ - { - id: 1, - inf: 'Verwalten Sie die', - inf1: 'Einstellungen Ihres', - inf2: 'Teilers', - name:'Konfiguration', - icon:"bi bi-gear-fill", - icon_source: "https://cdn.jsdelivr.net/npm/bootstrap-icons@1.9.1/font/bootstrap-icons.css", - }, - { - id: 2, - inf:'Benutzer', - inf1: 'verwalten', - name:'Benutzer', - icon:"bi bi-people-fill", - }, - { - id: 3, - inf: '1 derzeit', - inf1: 'registrierter', - inf2: 'Suchbroker', - name:'Suchbroker', - icon:"bi bi-diagram-3-fill", - }, - { - id: 4, - inf: 'Aufgaben derzeit', - inf1:'geplant', - name: 'Geplante Aufgaben', - icon:"bi bi-list-check", - }, - { - id: 5, - inf:'Zugangsdaten für', - inf1:'Suchbroker und', - inf2:'andere Dienste', - inf3:'verwalten', - name:'Zugangsdaten', - icon:"bi bi-key-fill", - }, - { - id:6, - inf:'Hier können Sie', - inf1:'einstellen, wie', - inf2: 'eingehende', - inf3: 'Suchanfragen', - inf4: 'behandelt werden', - inf5:'sollen', - name:'Behandlung von Suchanfragen', - icon:"bi bi-reply-all-fill", - }, - { - id:7, - inf:'Hier können Sie', - inf1:'Qualitätsberichte', - inf2: 'erzeugen und', - inf3:'ansehen', - name:'Qualitätsbericht', - icon:"bi bi-file-earmark-x", - }, - { - id:8, - inf:'Ereignisse', - inf1:'überprüfen', - name:'Log', - icon:"bi bi-terminal", - }, - { - id:9, - inf:'Liste vorheriger', - inf1:'Uploads', - name:'Uploads', - icon:"bi bi-upload", - }, - { - id: 10, - inf:'Überprüfen Sie die', - inf1:'Kommunikation', - inf2: 'mit anderen', - inf3:'Komponenten', - name:'Funktionstest', - icon:"bi bi-plug-fill" - }, -] diff --git a/src/app/sidebar/Backgrounds_Boxes.svg b/src/app/sidebar/Backgrounds_Boxes.svg deleted file mode 100644 index 251c03e..0000000 --- a/src/app/sidebar/Backgrounds_Boxes.svg +++ /dev/null @@ -1,242 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/app/sidebar/sidebar.component.css b/src/app/sidebar/sidebar.component.css index 8064a23..9bf9f5a 100644 --- a/src/app/sidebar/sidebar.component.css +++ b/src/app/sidebar/sidebar.component.css @@ -5,6 +5,7 @@ z-index:1; position: relative; } + .main-content { display: flex; height: 100%; @@ -34,17 +35,13 @@ width: 300px; } -.router-style, .b-img{ - position: absolute; -} + .router-style{ margin-top: 6%; z-index: 2; position: relative; } -.b-img{ - z-index: 1; -} + .sidebar { font-size: 18px; transition: all 3ms ease; diff --git a/src/app/sidebar/sidebar.component.html b/src/app/sidebar/sidebar.component.html index 7421f2f..a8e4760 100644 --- a/src/app/sidebar/sidebar.component.html +++ b/src/app/sidebar/sidebar.component.html @@ -61,9 +61,8 @@ -
-
+
- + +
+ diff --git a/src/app/sidebar/sidebar.component.ts b/src/app/sidebar/sidebar.component.ts index bd3c48b..0a79b6c 100644 --- a/src/app/sidebar/sidebar.component.ts +++ b/src/app/sidebar/sidebar.component.ts @@ -4,6 +4,8 @@ import {createMainRouterLink} from "../route/route-utils"; import {ColorSchemeService} from "../color-scheme.service"; import {RouteManagerService} from "../route/route-manager.service"; import {TeilerApp} from "../teiler/teiler-app"; +import {environment} from "../../environments/environment"; + @Component({ selector: 'app-sidebar', @@ -16,8 +18,14 @@ export class SidebarComponent implements OnInit { public innerWidth: any; public menuVisibleMobile: boolean = false; + selectedBackground: string = 'background1'; + constructor(public teilerService: TeilerService, private colorSchemeService: ColorSchemeService, public routeManagerService: RouteManagerService) { } + + + + isGreyTheme(): boolean { return this.colorSchemeService.getColor() === 'rgb(211,211,211)'; } @@ -60,4 +68,6 @@ export class SidebarComponent implements OnInit { (app.backendReachable === undefined && app.frontendReachable) || (app.backendReachable === null && app.frontendReachable)); } + + protected readonly environment = environment; } diff --git a/src/app/teiler-box/teiler-box.component.css b/src/app/teiler-box/teiler-box.component.css index a79f160..6836813 100644 --- a/src/app/teiler-box/teiler-box.component.css +++ b/src/app/teiler-box/teiler-box.component.css @@ -3,7 +3,6 @@ @import url("https://cdn.jsdelivr.net/npm/bootstrap-icons@1.9.1/font/bootstrap-icons.css"); h3{ - color: black; font-size: 130%; margin:0; } @@ -18,18 +17,17 @@ h3{ margin: auto; } p{ - color: black; font-size: 110%; margin: 0; } .teiler-box-icon { font-size: 470%; transition: transform 50ms ease; - color: grey; margin: 0 auto 5px auto; width: fit-content; min-height: 92px; display: flex; + color: var(--icon-color); } .teiler-box { float:left; @@ -47,6 +45,7 @@ p{ align-content: center; background-color: white; overflow: clip; + color: var(--text-color); } .teiler-box.clickable { box-shadow: 6px 5px 12px 4px lightgrey; @@ -78,11 +77,13 @@ p{ transform-origin:left; transform:scaleX(0); transition: transform 200ms ease; + color: var(--line-color); } hr{ height: 1px; border: none; - background-color: grey; + background-color:var(--line-color); + color: var(--line-color); } .icon-footer { position: absolute; diff --git a/src/app/teiler-welcome/teiler-welcome.component.ts b/src/app/teiler-welcome/teiler-welcome.component.ts index 10b51ad..83e88ba 100644 --- a/src/app/teiler-welcome/teiler-welcome.component.ts +++ b/src/app/teiler-welcome/teiler-welcome.component.ts @@ -43,4 +43,5 @@ export class TeilerWelcomeComponent implements OnInit { ngOnInit(): void { } + protected readonly environment = environment; } diff --git a/src/assets/color-palettes.json b/src/assets/color-palettes.json new file mode 100644 index 0000000..64830ca --- /dev/null +++ b/src/assets/color-palettes.json @@ -0,0 +1,26 @@ +{ + "color-palettes": [ + { + "name": "Color-Palette-1", + "colors": { + "text": "grey", + "line": "grey", + "icon": "grey" + }, + "style": { + "font": "Bahnschrift" + } + }, + { + "name": "Color-Palette-2", + "colors": { + "text": "black", + "line": "black", + "icon": "black" + }, + "style": { + "font": "Calibri" + } + } + ] +} diff --git a/src/assets/env.js b/src/assets/env.js index 3d47b59..7a648b5 100644 --- a/src/assets/env.js +++ b/src/assets/env.js @@ -20,7 +20,10 @@ "REPORTER_DEFAULT_TEMPLATE_ID": "ccp-qb", "EXPORTER_DEFAULT_TEMPLATE_ID": "ccp", "TEILER_USER": "bridgehead-test", - "TEILER_ADMIN": "bridgehead-test-admin" + "TEILER_ADMIN": "bridgehead-test-admin", + "BACKGROUND_IMAGE_URL": "http://localhost:8085/assets/Background_Box2.svg", + "LOGO_URL": "http://localhost:8085/assets/DKTK_TEILER_LOGO.svg", + "COLOR_PALETTE": "Color-Palette-1", }; })(this); diff --git a/src/assets/images/Background_Box1.svg b/src/assets/images/Background_Box1.svg index 810fc50..5e8c8ad 100644 --- a/src/assets/images/Background_Box1.svg +++ b/src/assets/images/Background_Box1.svg @@ -1,4 +1,6 @@ - + diff --git a/src/environments/environment.ts b/src/environments/environment.ts index b9692e3..12e0ec6 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -1,4 +1,5 @@ export const environment = { production: false, - config: (window as any).env.teiler.config || {} + config: (window as any).env.teiler.config || { + } }; diff --git a/src/i18n/messages.en.xlf b/src/i18n/messages.en.xlf index 64896ee..39a22f9 100644 --- a/src/i18n/messages.en.xlf +++ b/src/i18n/messages.en.xlf @@ -53,7 +53,7 @@ Teilers Konfiguration - Teiler Configuration + Teiler ConfigurationInterface diff --git a/src/styles.css b/src/styles.css index bf249ed..730d105 100644 --- a/src/styles.css +++ b/src/styles.css @@ -6,5 +6,10 @@ --color-yellow: #FFC43D; --color-pink: #EF476F; --color-green: #06D6A0; + --icon-color: grey; + --text-color: black; + --line-color: black; + --font-style: Arial, sans-serif; } + diff --git a/tsconfig.json b/tsconfig.json index ed65089..a22962d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,7 +22,9 @@ "ES2022", "dom" ], - "useDefineForClassFields": false + "useDefineForClassFields": false, + "resolveJsonModule": true, + "esModuleInterop": true }, "angularCompilerOptions": { "enableI18nLegacyMessageIdFormat": false,