bugfix/translationProblems #2
@@ -46,7 +46,7 @@
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kB",
|
||||
"maximumWarning": "1MB",
|
||||
"maximumError": "1MB"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<h2 mat-dialog-title>{{ project.title | translate }}</h2>
|
||||
<mat-dialog-content>
|
||||
<mat-dialog-content #dialogContent>
|
||||
<p>{{ project.introduction | translate }}</p>
|
||||
|
||||
<ul>
|
||||
@@ -28,7 +28,7 @@
|
||||
/>
|
||||
@if (img.source) {
|
||||
<div class="slide-source">
|
||||
{{ 'PROJECTS.IMAGE_SOURCE' | translate }}: {{ img.source }}
|
||||
{{ img.source }}
|
||||
</div>
|
||||
}
|
||||
</swiper-slide>
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
}
|
||||
|
||||
.my-swiper {
|
||||
background-color: #222;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
@@ -26,24 +25,30 @@
|
||||
bottom: 12px;
|
||||
}
|
||||
|
||||
swiper-slide {
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
.slide-img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
max-height: 512px !important;
|
||||
object-fit: contain;
|
||||
border-radius: 12px;
|
||||
display: block;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.slide-source {
|
||||
font-size: 0.75rem;
|
||||
color: white;
|
||||
background: rgba(0,0,0,.5);
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
right: 8px;
|
||||
color: #aaa;
|
||||
background: #2a2a2a;
|
||||
padding: 0.5rem;
|
||||
text-align: right;
|
||||
border-top: 1px solid #444;
|
||||
}
|
||||
|
||||
ul {
|
||||
|
||||
@@ -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 {
|
||||
MAT_DIALOG_DATA,
|
||||
MatDialogActions,
|
||||
@@ -30,6 +30,14 @@ import {MatButton} from '@angular/material/button';
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
})
|
||||
export class ProjectDialogComponent {
|
||||
export class ProjectDialogComponent implements AfterViewInit {
|
||||
project: Projects = inject(MAT_DIALOG_DATA);
|
||||
|
||||
@ViewChild('dialogContent') dialogContent: ElementRef | undefined;
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
if (this.dialogContent) {
|
||||
this.dialogContent.nativeElement.scrollTop = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import {Component, computed, inject, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
||||
import {MatCardModule} from '@angular/material/card';
|
||||
import {MatChipsModule} from '@angular/material/chips';
|
||||
import {MatIcon} from '@angular/material/icon';
|
||||
import {TranslatePipe, TranslateService} from '@ngx-translate/core';
|
||||
import {ActivatedRoute} from '@angular/router';
|
||||
import {AssetsConstants} from '../../constants/AssetsConstants';
|
||||
import {MatDialog} from '@angular/material/dialog';
|
||||
import {MatButtonModule} from '@angular/material/button';
|
||||
import {ProjectDialogComponent} from './dialog/project-dialog.component';
|
||||
|
||||
import {Component, computed, inject, CUSTOM_ELEMENTS_SCHEMA, OnDestroy, OnInit} from '@angular/core';
|
||||
import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {Subscription} from "rxjs";
|
||||
import {MatCardModule} from "@angular/material/card";
|
||||
import {MatChipsModule} from "@angular/material/chips";
|
||||
import {MatIcon} from "@angular/material/icon";
|
||||
import {TranslatePipe} from "@ngx-translate/core";
|
||||
import {MatButtonModule} from "@angular/material/button";
|
||||
import {MatDialog} from "@angular/material/dialog";
|
||||
import {ProjectDialogComponent} from "./dialog/project-dialog.component";
|
||||
import {AssetsConstants} from "../../constants/AssetsConstants";
|
||||
|
||||
export interface Projects {
|
||||
identifier: string;
|
||||
@@ -32,6 +32,7 @@ export interface Projects {
|
||||
|
||||
@Component({
|
||||
selector: 'app-projects',
|
||||
standalone: true,
|
||||
imports: [
|
||||
MatCardModule,
|
||||
MatChipsModule,
|
||||
@@ -43,11 +44,12 @@ export interface Projects {
|
||||
styleUrl: './projects.component.scss',
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
})
|
||||
export class ProjectsComponent {
|
||||
export class ProjectsComponent implements OnInit, OnDestroy {
|
||||
|
||||
private readonly route = inject(ActivatedRoute);
|
||||
private readonly dialog = inject(MatDialog);
|
||||
private readonly translateService = inject(TranslateService);
|
||||
private readonly router = inject(Router);
|
||||
private queryParamSub: Subscription | undefined;
|
||||
|
||||
allProjects: Projects[] = [
|
||||
{
|
||||
@@ -175,8 +177,20 @@ export class ProjectsComponent {
|
||||
featuredProject = computed(() => this.allProjects.find(p => p.isFeatured));
|
||||
otherProjects = computed(() => this.allProjects.filter(p => !p.isFeatured));
|
||||
|
||||
constructor() {
|
||||
this.route.queryParamMap.subscribe(params => {
|
||||
ngOnInit(): void {
|
||||
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');
|
||||
if (projectIdentifier) {
|
||||
const project = this.allProjects.find(p => p.identifier === projectIdentifier);
|
||||
@@ -192,6 +206,8 @@ export class ProjectsComponent {
|
||||
data: project,
|
||||
width: '90vw',
|
||||
maxWidth: '900px',
|
||||
autoFocus: false,
|
||||
restoreFocus: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +241,6 @@
|
||||
"READ_MORE": "Mehr erfahren",
|
||||
"LINK_TO_PROJECT": "Zum Projekt",
|
||||
"CLOSE": "Schließen",
|
||||
"IMAGE_SOURCE": "Bildquelle",
|
||||
"PLAYGROUND": {
|
||||
"TITLE": "Playground Website",
|
||||
"SHORT_DESCRIPTION": "Hier geht es um diese Webseite.",
|
||||
@@ -252,7 +251,7 @@
|
||||
"BULLET_4": "Die Seite ist Open Source und auf GitHub verfügbar."
|
||||
},
|
||||
"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.",
|
||||
"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.",
|
||||
|
||||
@@ -241,7 +241,6 @@
|
||||
"READ_MORE": "Read More",
|
||||
"LINK_TO_PROJECT": "To the project",
|
||||
"CLOSE": "Close",
|
||||
"IMAGE_SOURCE": "Image source",
|
||||
"PLAYGROUND": {
|
||||
"TITLE": "Playground Website",
|
||||
"SHORT_DESCRIPTION": "This is about this website.",
|
||||
@@ -252,7 +251,7 @@
|
||||
"BULLET_4": "The site is open source and available on GitHub."
|
||||
},
|
||||
"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.",
|
||||
"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.",
|
||||
|
||||
Reference in New Issue
Block a user