diff --git a/src/app/layout/topbar/topbar.component.html b/src/app/layout/topbar/topbar.component.html index 494864a..3ef7b06 100644 --- a/src/app/layout/topbar/topbar.component.html +++ b/src/app/layout/topbar/topbar.component.html @@ -1,11 +1,7 @@ - + - + {{ 'APP.TITLE' | translate }} @@ -17,11 +13,7 @@ - @@ -46,7 +38,8 @@ - @@ -58,7 +51,7 @@ {{ 'LANG.DE' | translate }} @if (lang.lang() === 'de') { - check + check } @@ -82,4 +75,4 @@ - + \ No newline at end of file diff --git a/src/app/pages/projects/projects.component.ts b/src/app/pages/projects/projects.component.ts index 4f8d522..64de3bc 100644 --- a/src/app/pages/projects/projects.component.ts +++ b/src/app/pages/projects/projects.component.ts @@ -1,14 +1,14 @@ -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"; +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; @@ -46,124 +46,124 @@ export interface Projects { }) export class ProjectsComponent implements OnInit, OnDestroy { - private readonly route = inject(ActivatedRoute); - private readonly dialog = inject(MatDialog); - private readonly router = inject(Router); - private queryParamSub: Subscription | undefined; + private readonly route = inject(ActivatedRoute); + private readonly dialog = inject(MatDialog); + private readonly router = inject(Router); + private queryParamSub: Subscription | undefined; - allProjects: Projects[] = [ - { - identifier: "playground", - title: 'PROJECTS.PLAYGROUND.TITLE', - shortDescription: 'PROJECTS.PLAYGROUND.SHORT_DESCRIPTION', - introduction: 'PROJECTS.PLAYGROUND.INTRODUCTION', - images: [], - icon: 'web', - assets: '', - links: [{name: 'PROJECTS.LINK_TO_PROJECT', url: 'https://andreas-dahm.eu'}], - bulletPoints: [ - 'PROJECTS.PLAYGROUND.BULLET_1', - 'PROJECTS.PLAYGROUND.BULLET_2', - 'PROJECTS.PLAYGROUND.BULLET_3', - 'PROJECTS.PLAYGROUND.BULLET_4', - ], - isFeatured: false, - technologies: ['Angular', 'TypeScript', 'SCSS', 'HTML', 'GitHub Actions', 'Docker'] - }, - { - identifier: "elmucho", - title: 'PROJECTS.EL_MUCHO.TITLE', - shortDescription: 'PROJECTS.EL_MUCHO.SHORT_DESCRIPTION', - introduction: 'PROJECTS.EL_MUCHO.INTRODUCTION', - images: AssetsConstants.EL_MUCHO_IMAGES.map(url => ({ url, source: '' })), - icon: 'sports_esports', - assets: '', - links: [{name: 'PROJECTS.LINK_TO_PROJECT', url: 'https://store.steampowered.com/app/1532640/El_Mucho/'}], - bulletPoints: [ - 'PROJECTS.EL_MUCHO.BULLET_1', - 'PROJECTS.EL_MUCHO.BULLET_2', - 'PROJECTS.EL_MUCHO.BULLET_3', - 'PROJECTS.EL_MUCHO.BULLET_4', - ], - isFeatured: true, - technologies: ['Unity', 'C#', 'Steamworks', 'Git'] - }, - { - identifier: "gamejams", - title: 'PROJECTS.GAME_JAMS.TITLE', - shortDescription: 'PROJECTS.GAME_JAMS.SHORT_DESCRIPTION', - introduction: 'PROJECTS.GAME_JAMS.INTRODUCTION', - images: AssetsConstants.GAME_JAMS_IMAGES.map(url => ({ url, source: '' })), - icon: 'videogame_asset', - assets: '', - links: [{name: 'PROJECTS.LINK_TO_PROJECT', url: 'https://itch.io/c/6628860/lobos-collection'}], - bulletPoints: [ - 'PROJECTS.GAME_JAMS.BULLET_1', - 'PROJECTS.GAME_JAMS.BULLET_2', - 'PROJECTS.GAME_JAMS.BULLET_3', - 'PROJECTS.GAME_JAMS.BULLET_4', - ], - isFeatured: false, - technologies: ['Unity', 'C#', 'Git'] - }, - { - identifier: "diploma", - title: 'PROJECTS.DIPLOMA.TITLE', - shortDescription: 'PROJECTS.DIPLOMA.SHORT_DESCRIPTION', - introduction: 'PROJECTS.DIPLOMA.INTRODUCTION', - images: AssetsConstants.DIPLOMA_IMAGES.map(url => ({ url, source: '' })), - icon: 'history_edu', - assets: AssetsConstants.DIPLOMA, - links: [{name: 'PROJECTS.LINK_TO_PROJECT', url: 'https://www.th-bingen.de'}], - bulletPoints: [ - 'PROJECTS.DIPLOMA.BULLET_1', - 'PROJECTS.DIPLOMA.BULLET_2', - 'PROJECTS.DIPLOMA.BULLET_3', - 'PROJECTS.DIPLOMA.BULLET_4', - ], - isFeatured: false, - technologies: ['C++', 'OpenGL', 'Qt', '3D-Scanner'] - }, - { - identifier: "tribble-the-homeserver", - title: 'PROJECTS.TRIBBLE.TITLE', - shortDescription: 'PROJECTS.TRIBBLE.SHORT_DESCRIPTION', - introduction: 'PROJECTS.TRIBBLE.INTRODUCTION', - images: [ - { url: AssetsConstants.TRIBBLE_IMAGES[0], source: 'https://upload.wikimedia.org/wikipedia/commons/0/03/Hostinger_Logo.png'}, - { url: AssetsConstants.TRIBBLE_IMAGES[1], source: 'https://dashboardicons.com/icons/docker-engine'}, - { url: AssetsConstants.TRIBBLE_IMAGES[2], source: 'https://dashboardicons.com/icons/gitea'}, - { url: AssetsConstants.TRIBBLE_IMAGES[3], source: 'https://commons.wikimedia.org/wiki/File:Traefik.logo.png'} - ], - icon: 'dns', - assets: '', - links: [ - {name: 'Ubuntu Server', url: 'https://ubuntu.com/server'}, - {name: 'Docker', url: 'https://www.docker.com/'}, - {name: 'Traefik', url: 'https://traefik.io/'}, - {name: 'Gitea', url: 'https://gitea.io/'}, - {name: 'Jellyfin', url: 'https://jellyfin.org/'}, - {name: 'AdGuard Home', url: 'https://adguard.com/en/adguard-home/overview.html'}, - {name: 'Paperless-ngx', url: 'https://paperless-ngx.com/'}, - {name: 'Tailscale', url: 'https://tailscale.com/'} - ], - bulletPoints: [ - 'PROJECTS.TRIBBLE.BULLET_1', - 'PROJECTS.TRIBBLE.BULLET_2', - 'PROJECTS.TRIBBLE.BULLET_3', - 'PROJECTS.TRIBBLE.BULLET_4', - ], - isFeatured: false, - technologies: ['Ubuntu Server', 'Docker', 'Traefik', 'Gitea', 'Jellyfin', 'AdGuard Home', 'Paperless-ngx', 'Tailscale'] - } - ] + allProjects: Projects[] = [ + { + identifier: "playground", + title: 'PROJECTS.PLAYGROUND.TITLE', + shortDescription: 'PROJECTS.PLAYGROUND.SHORT_DESCRIPTION', + introduction: 'PROJECTS.PLAYGROUND.INTRODUCTION', + images: [], + icon: 'web', + assets: '', + links: [{ name: 'PROJECTS.LINK_TO_PROJECT', url: 'https://andreas-dahm.eu' }], + bulletPoints: [ + 'PROJECTS.PLAYGROUND.BULLET_1', + 'PROJECTS.PLAYGROUND.BULLET_2', + 'PROJECTS.PLAYGROUND.BULLET_3', + 'PROJECTS.PLAYGROUND.BULLET_4', + ], + isFeatured: false, + technologies: ['Angular', 'TypeScript', 'SCSS', 'HTML', 'GitHub Actions', 'Docker'] + }, + { + identifier: "elmucho", + title: 'PROJECTS.EL_MUCHO.TITLE', + shortDescription: 'PROJECTS.EL_MUCHO.SHORT_DESCRIPTION', + introduction: 'PROJECTS.EL_MUCHO.INTRODUCTION', + images: AssetsConstants.EL_MUCHO_IMAGES.map(url => ({ url, source: '' })), + icon: 'sports_esports', + assets: '', + links: [{ name: 'PROJECTS.LINK_TO_PROJECT', url: 'https://store.steampowered.com/app/1532640/El_Mucho/' }], + bulletPoints: [ + 'PROJECTS.EL_MUCHO.BULLET_1', + 'PROJECTS.EL_MUCHO.BULLET_2', + 'PROJECTS.EL_MUCHO.BULLET_3', + 'PROJECTS.EL_MUCHO.BULLET_4', + ], + isFeatured: true, + technologies: ['Unity', 'C#', 'Steamworks', 'Git'] + }, + { + identifier: "gamejams", + title: 'PROJECTS.GAME_JAMS.TITLE', + shortDescription: 'PROJECTS.GAME_JAMS.SHORT_DESCRIPTION', + introduction: 'PROJECTS.GAME_JAMS.INTRODUCTION', + images: AssetsConstants.GAME_JAMS_IMAGES.map(url => ({ url, source: '' })), + icon: 'videogame_asset', + assets: '', + links: [{ name: 'PROJECTS.LINK_TO_PROJECT', url: 'https://itch.io/c/6628860/lobos-collection' }], + bulletPoints: [ + 'PROJECTS.GAME_JAMS.BULLET_1', + 'PROJECTS.GAME_JAMS.BULLET_2', + 'PROJECTS.GAME_JAMS.BULLET_3', + 'PROJECTS.GAME_JAMS.BULLET_4', + ], + isFeatured: false, + technologies: ['Unity', 'C#', 'Git'] + }, + { + identifier: "diploma", + title: 'PROJECTS.DIPLOMA.TITLE', + shortDescription: 'PROJECTS.DIPLOMA.SHORT_DESCRIPTION', + introduction: 'PROJECTS.DIPLOMA.INTRODUCTION', + images: AssetsConstants.DIPLOMA_IMAGES.map(url => ({ url, source: '' })), + icon: 'history_edu', + assets: AssetsConstants.DIPLOMA, + links: [{ name: 'PROJECTS.LINK_TO_PROJECT', url: 'https://www.th-bingen.de' }], + bulletPoints: [ + 'PROJECTS.DIPLOMA.BULLET_1', + 'PROJECTS.DIPLOMA.BULLET_2', + 'PROJECTS.DIPLOMA.BULLET_3', + 'PROJECTS.DIPLOMA.BULLET_4', + ], + isFeatured: false, + technologies: ['C++', 'OpenGL', 'Qt', '3D-Scanner'] + }, + { + identifier: "tribble-the-homeserver", + title: 'PROJECTS.TRIBBLE.TITLE', + shortDescription: 'PROJECTS.TRIBBLE.SHORT_DESCRIPTION', + introduction: 'PROJECTS.TRIBBLE.INTRODUCTION', + images: [ + { url: AssetsConstants.TRIBBLE_IMAGES[0], source: 'https://upload.wikimedia.org/wikipedia/commons/0/03/Hostinger_Logo.png' }, + { url: AssetsConstants.TRIBBLE_IMAGES[1], source: 'https://dashboardicons.com/icons/docker-engine' }, + { url: AssetsConstants.TRIBBLE_IMAGES[2], source: 'https://dashboardicons.com/icons/gitea' }, + { url: AssetsConstants.TRIBBLE_IMAGES[3], source: 'https://commons.wikimedia.org/wiki/File:Traefik.logo.png' } + ], + icon: 'dns', + assets: '', + links: [ + { name: 'Ubuntu Server', url: 'https://ubuntu.com/server' }, + { name: 'Docker', url: 'https://www.docker.com/' }, + { name: 'Traefik', url: 'https://traefik.io/' }, + { name: 'Gitea', url: 'https://gitea.io/' }, + { name: 'Jellyfin', url: 'https://jellyfin.org/' }, + { name: 'AdGuard Home', url: 'https://adguard.com/en/adguard-home/overview.html' }, + { name: 'Paperless-ngx', url: 'https://paperless-ngx.com/' }, + { name: 'Tailscale', url: 'https://tailscale.com/' } + ], + bulletPoints: [ + 'PROJECTS.TRIBBLE.BULLET_1', + 'PROJECTS.TRIBBLE.BULLET_2', + 'PROJECTS.TRIBBLE.BULLET_3', + 'PROJECTS.TRIBBLE.BULLET_4', + ], + isFeatured: false, + technologies: ['Ubuntu Server', 'Docker', 'Traefik', 'Gitea', 'Jellyfin', 'AdGuard Home', 'Paperless-ngx', 'Tailscale'] + } + ] featuredProject = computed(() => this.allProjects.find(p => p.isFeatured)); otherProjects = computed(() => this.allProjects.filter(p => !p.isFeatured)); ngOnInit(): void { window.scrollTo({ top: 0, behavior: 'smooth' }); - setTimeout(() =>{ this.dialogOpenFunction(); },10); + setTimeout(() => { this.dialogOpenFunction(); }, 10); } ngOnDestroy(): void { @@ -172,8 +172,7 @@ export class ProjectsComponent implements OnInit, OnDestroy { } } - private dialogOpenFunction() : void - { + private dialogOpenFunction(): void { this.queryParamSub = this.route.queryParamMap.subscribe(params => { const projectIdentifier = params.get('project'); if (projectIdentifier) { diff --git a/src/styles.scss b/src/styles.scss index bd09e8f..0e0fcef 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -425,16 +425,21 @@ app-root { } /* ---- Topbar ---- */ -.topbar { +app-topbar { position: sticky; top: 0; z-index: 100; + display: block; +} + +.topbar { backdrop-filter: saturate(1.1) blur(8px); background: color-mix(in srgb, var(--card-bg) 80%, transparent); border-bottom: 1px solid rgba(0, 0, 0, .08); display: flex; align-items: center; padding: clamp(0.5rem, 1vw, 1rem); + color: var(--app-fg); } .topbar .brand { @@ -539,8 +544,8 @@ app-root { } .hero { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(min(100%, 425px), 1fr)); + display: flex; + flex-wrap: wrap; gap: clamp(1rem, 4vw, 1.5rem); border-radius: var(--card-radius); background: var(--card-bg); @@ -550,7 +555,8 @@ app-root { .hero .photo { display: flex; align-items: flex-start; - justify-content: center; + justify-content: flex-start; + flex: 0 0 clamp(300px, 100%, 425px); } .hero .photo img { @@ -567,6 +573,7 @@ app-root { display: flex; flex-direction: column; gap: clamp(0.5rem, 2vw, 1rem); + flex: 1 1 300px; } .hero .intro h1 { @@ -748,7 +755,9 @@ app-root { .project-grid { display: grid; gap: clamp(1rem, 3vw, 1.5rem); - grid-template-columns: repeat(auto-fill, minmax(min(100%, 350px), 1fr)); + grid-template-columns: repeat(auto-fill, minmax(min(100%, 450px), 1fr)); + max-width: 1200px; + margin: 0 auto; } .project-card { @@ -763,9 +772,7 @@ app-root { box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); } -.project-card.featured { - grid-column: 1 / -1; -} + .project-card mat-card-header { padding-bottom: 1rem;