Merge pull request 'bugfix/translationProblems' (#2) from bugfix/translationProblems into main
All checks were successful
Build & Push Frontend A / docker (push) Successful in 1m3s

Reviewed-on: #2
This commit was merged in pull request #2.
This commit is contained in:
2026-01-18 10:55:32 +01:00
7 changed files with 60 additions and 33 deletions

View File

@@ -46,7 +46,7 @@
"budgets": [ "budgets": [
{ {
"type": "initial", "type": "initial",
"maximumWarning": "500kB", "maximumWarning": "1MB",
"maximumError": "1MB" "maximumError": "1MB"
}, },
{ {

View File

@@ -1,5 +1,5 @@
<h2 mat-dialog-title>{{ project.title | translate }}</h2> <h2 mat-dialog-title>{{ project.title | translate }}</h2>
<mat-dialog-content> <mat-dialog-content #dialogContent>
<p>{{ project.introduction | translate }}</p> <p>{{ project.introduction | translate }}</p>
<ul> <ul>
@@ -28,7 +28,7 @@
/> />
@if (img.source) { @if (img.source) {
<div class="slide-source"> <div class="slide-source">
{{ 'PROJECTS.IMAGE_SOURCE' | translate }}: {{ img.source }} {{ img.source }}
</div> </div>
} }
</swiper-slide> </swiper-slide>

View File

@@ -18,7 +18,6 @@
} }
.my-swiper { .my-swiper {
background-color: #222;
border-radius: 12px; border-radius: 12px;
} }
@@ -26,24 +25,30 @@
bottom: 12px; bottom: 12px;
} }
swiper-slide {
border-radius: 12px;
overflow: hidden;
display: flex;
flex-direction: column;
background-color: #222;
}
.slide-img { .slide-img {
width: 100%; width: 100%;
height: auto; height: auto;
max-height: 512px !important; max-height: 512px !important;
object-fit: contain; object-fit: contain;
border-radius: 12px;
display: block; display: block;
flex-shrink: 0;
} }
.slide-source { .slide-source {
font-size: 0.75rem; font-size: 0.75rem;
color: white; color: #aaa;
background: rgba(0,0,0,.5); background: #2a2a2a;
padding: 0.25rem 0.5rem; padding: 0.5rem;
border-radius: 4px; text-align: right;
position: absolute; border-top: 1px solid #444;
bottom: 8px;
right: 8px;
} }
ul { ul {

View File

@@ -1,4 +1,4 @@
import {Component, inject, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core'; import {AfterViewInit, Component, inject, CUSTOM_ELEMENTS_SCHEMA, ViewChild, ElementRef} from '@angular/core';
import { import {
MAT_DIALOG_DATA, MAT_DIALOG_DATA,
MatDialogActions, MatDialogActions,
@@ -30,6 +30,14 @@ import {MatButton} from '@angular/material/button';
], ],
schemas: [CUSTOM_ELEMENTS_SCHEMA] schemas: [CUSTOM_ELEMENTS_SCHEMA]
}) })
export class ProjectDialogComponent { export class ProjectDialogComponent implements AfterViewInit {
project: Projects = inject(MAT_DIALOG_DATA); project: Projects = inject(MAT_DIALOG_DATA);
@ViewChild('dialogContent') dialogContent: ElementRef | undefined;
ngAfterViewInit(): void {
if (this.dialogContent) {
this.dialogContent.nativeElement.scrollTop = 0;
}
}
} }

View File

@@ -1,14 +1,14 @@
import {Component, computed, inject, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core'; import {Component, computed, inject, CUSTOM_ELEMENTS_SCHEMA, OnDestroy, OnInit} from '@angular/core';
import {MatCardModule} from '@angular/material/card'; import {ActivatedRoute, Router} from '@angular/router';
import {MatChipsModule} from '@angular/material/chips'; import {Subscription} from "rxjs";
import {MatIcon} from '@angular/material/icon'; import {MatCardModule} from "@angular/material/card";
import {TranslatePipe, TranslateService} from '@ngx-translate/core'; import {MatChipsModule} from "@angular/material/chips";
import {ActivatedRoute} from '@angular/router'; import {MatIcon} from "@angular/material/icon";
import {AssetsConstants} from '../../constants/AssetsConstants'; import {TranslatePipe} from "@ngx-translate/core";
import {MatDialog} from '@angular/material/dialog'; import {MatButtonModule} from "@angular/material/button";
import {MatButtonModule} from '@angular/material/button'; import {MatDialog} from "@angular/material/dialog";
import {ProjectDialogComponent} from './dialog/project-dialog.component'; import {ProjectDialogComponent} from "./dialog/project-dialog.component";
import {AssetsConstants} from "../../constants/AssetsConstants";
export interface Projects { export interface Projects {
identifier: string; identifier: string;
@@ -32,6 +32,7 @@ export interface Projects {
@Component({ @Component({
selector: 'app-projects', selector: 'app-projects',
standalone: true,
imports: [ imports: [
MatCardModule, MatCardModule,
MatChipsModule, MatChipsModule,
@@ -43,11 +44,12 @@ export interface Projects {
styleUrl: './projects.component.scss', styleUrl: './projects.component.scss',
schemas: [CUSTOM_ELEMENTS_SCHEMA], schemas: [CUSTOM_ELEMENTS_SCHEMA],
}) })
export class ProjectsComponent { export class ProjectsComponent implements OnInit, OnDestroy {
private readonly route = inject(ActivatedRoute); private readonly route = inject(ActivatedRoute);
private readonly dialog = inject(MatDialog); private readonly dialog = inject(MatDialog);
private readonly translateService = inject(TranslateService); private readonly router = inject(Router);
private queryParamSub: Subscription | undefined;
allProjects: Projects[] = [ allProjects: Projects[] = [
{ {
@@ -175,8 +177,20 @@ export class ProjectsComponent {
featuredProject = computed(() => this.allProjects.find(p => p.isFeatured)); featuredProject = computed(() => this.allProjects.find(p => p.isFeatured));
otherProjects = computed(() => this.allProjects.filter(p => !p.isFeatured)); otherProjects = computed(() => this.allProjects.filter(p => !p.isFeatured));
constructor() { ngOnInit(): void {
this.route.queryParamMap.subscribe(params => { window.scrollTo({ top: 0, behavior: 'smooth' });
setTimeout(() =>{ this.dialogOpenFunction(); },10);
}
ngOnDestroy(): void {
if (this.queryParamSub) {
this.queryParamSub.unsubscribe();
}
}
private dialogOpenFunction() : void
{
this.queryParamSub = this.route.queryParamMap.subscribe(params => {
const projectIdentifier = params.get('project'); const projectIdentifier = params.get('project');
if (projectIdentifier) { if (projectIdentifier) {
const project = this.allProjects.find(p => p.identifier === projectIdentifier); const project = this.allProjects.find(p => p.identifier === projectIdentifier);
@@ -192,6 +206,8 @@ export class ProjectsComponent {
data: project, data: project,
width: '90vw', width: '90vw',
maxWidth: '900px', maxWidth: '900px',
autoFocus: false,
restoreFocus: false
}); });
} }
} }

View File

@@ -241,7 +241,6 @@
"READ_MORE": "Mehr erfahren", "READ_MORE": "Mehr erfahren",
"LINK_TO_PROJECT": "Zum Projekt", "LINK_TO_PROJECT": "Zum Projekt",
"CLOSE": "Schließen", "CLOSE": "Schließen",
"IMAGE_SOURCE": "Bildquelle",
"PLAYGROUND": { "PLAYGROUND": {
"TITLE": "Playground Website", "TITLE": "Playground Website",
"SHORT_DESCRIPTION": "Hier geht es um diese Webseite.", "SHORT_DESCRIPTION": "Hier geht es um diese Webseite.",
@@ -252,7 +251,7 @@
"BULLET_4": "Die Seite ist Open Source und auf GitHub verfügbar." "BULLET_4": "Die Seite ist Open Source und auf GitHub verfügbar."
}, },
"TRIBBLE": { "TRIBBLE": {
"TITLE": "Ärger mit meinem Homeserver Tribble", "TITLE": "Trouble with Tribble",
"SHORT_DESCRIPTION": "Ein Projekt, das die Einrichtung und Wartung eines Homeservers beschreibt, auf dem verschiedene Docker-Container für Self-Hosting-Dienste laufen.", "SHORT_DESCRIPTION": "Ein Projekt, das die Einrichtung und Wartung eines Homeservers beschreibt, auf dem verschiedene Docker-Container für Self-Hosting-Dienste laufen.",
"INTRODUCTION": "Dieses Projekt dokumentiert die Einrichtung eines persönlichen Homeservers mit dem Spitznamen \"Tribble\". Es umfasst die Installation von Ubuntu Server und die Containerisierung von Diensten wie Gitea für die Versionskontrolle, Jellyfin für das Mediastreaming und AdGuard Home für das Blockieren von Werbung im Netzwerk. Der Server ist über Traefik als Reverse-Proxy und Tailscale für eine sichere Netzwerkverbindung mit dem Internet verbunden, was das Self-Hosting der CI/CD-Pipeline dieser Website ermöglicht.", "INTRODUCTION": "Dieses Projekt dokumentiert die Einrichtung eines persönlichen Homeservers mit dem Spitznamen \"Tribble\". Es umfasst die Installation von Ubuntu Server und die Containerisierung von Diensten wie Gitea für die Versionskontrolle, Jellyfin für das Mediastreaming und AdGuard Home für das Blockieren von Werbung im Netzwerk. Der Server ist über Traefik als Reverse-Proxy und Tailscale für eine sichere Netzwerkverbindung mit dem Internet verbunden, was das Self-Hosting der CI/CD-Pipeline dieser Website ermöglicht.",
"BULLET_1": "Self-Hosting verschiedener Dienste mit Docker.", "BULLET_1": "Self-Hosting verschiedener Dienste mit Docker.",

View File

@@ -241,7 +241,6 @@
"READ_MORE": "Read More", "READ_MORE": "Read More",
"LINK_TO_PROJECT": "To the project", "LINK_TO_PROJECT": "To the project",
"CLOSE": "Close", "CLOSE": "Close",
"IMAGE_SOURCE": "Image source",
"PLAYGROUND": { "PLAYGROUND": {
"TITLE": "Playground Website", "TITLE": "Playground Website",
"SHORT_DESCRIPTION": "This is about this website.", "SHORT_DESCRIPTION": "This is about this website.",
@@ -252,7 +251,7 @@
"BULLET_4": "The site is open source and available on GitHub." "BULLET_4": "The site is open source and available on GitHub."
}, },
"TRIBBLE": { "TRIBBLE": {
"TITLE": "Trouble with my homeserver tribble", "TITLE": "Trouble with Tribble",
"SHORT_DESCRIPTION": "A project detailing the setup and maintenance of a home server running various Docker containers for self-hosting services.", "SHORT_DESCRIPTION": "A project detailing the setup and maintenance of a home server running various Docker containers for self-hosting services.",
"INTRODUCTION": "This project documents the journey of setting up a personal home server, nicknamed \"Tribble\". It involves installing Ubuntu Server and containerizing services like Gitea for version control, Jellyfin for media streaming, and AdGuard Home for network-wide ad-blocking. The server is connected via Traefik as a reverse proxy and Tailscale for secure networking, enabling the self-hosted CI/CD pipeline for this website.", "INTRODUCTION": "This project documents the journey of setting up a personal home server, nicknamed \"Tribble\". It involves installing Ubuntu Server and containerizing services like Gitea for version control, Jellyfin for media streaming, and AdGuard Home for network-wide ad-blocking. The server is connected via Traefik as a reverse proxy and Tailscale for secure networking, enabling the self-hosted CI/CD pipeline for this website.",
"BULLET_1": "Self-hosting of various services using Docker.", "BULLET_1": "Self-hosting of various services using Docker.",