Files
playground-frontend/src/app/pages/projects/projects.component.ts
T
lobo 82228e9141 docs(projects): update claude-in-a-box project text and diagram
The box now runs an agent pipeline, assist mode and evals.
The old card and diagram only described rule loading and the commit hook.
2026-10-21 08:27:27 +02:00

330 lines
11 KiB
TypeScript

import { Component, computed, inject, CUSTOM_ELEMENTS_SCHEMA, OnDestroy, OnInit, PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
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;
title: string,
shortDescription: string,
introduction: string,
images: {
url: string,
source: string
}[],
diagram?: string,
icon: string,
assets: string,
links: {
name: string,
url: string
}[],
bulletPoints: string[],
challenges: string[],
learnings: string[],
isFeatured: boolean,
technologies: string[]
}
@Component({
selector: 'app-projects',
imports: [
MatCardModule,
MatChipsModule,
MatIcon,
TranslatePipe,
MatButtonModule
],
templateUrl: './projects.component.html',
styleUrl: './projects.component.scss',
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class ProjectsComponent implements OnInit, OnDestroy {
private readonly route = inject(ActivatedRoute);
private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
private readonly dialog = inject(MatDialog);
private readonly router = inject(Router);
private queryParamSub: Subscription | undefined;
allProjects: Projects[] = [
{
identifier: "to-be-played",
title: 'PROJECTS.TBP.TITLE',
shortDescription: 'PROJECTS.TBP.SHORT_DESCRIPTION',
introduction: 'PROJECTS.TBP.INTRODUCTION',
images: AssetsConstants.TBP_IMAGES.map(url => ({ url, source: '' })),
diagram: AssetsConstants.TBP_DIAGRAM,
icon: 'playlist_add_check',
assets: '',
links: [
{ name: 'PROJECTS.LINK_TO_PROJECT', url: 'https://tbp.andreas-dahm.eu' },
{ name: 'ToBePlayed-Frontend', url: 'https://git.andreas-dahm.eu/Lobo_Corp/ToBePlayed-Frontend' },
{ name: 'ToBePlayed-Core', url: 'https://git.andreas-dahm.eu/Lobo_Corp/ToBePlayed-Core' },
{ name: 'ToBePlayed-Auth', url: 'https://git.andreas-dahm.eu/Lobo_Corp/ToBePlayed-Auth' }
],
bulletPoints: [
'PROJECTS.TBP.BULLET_1',
'PROJECTS.TBP.BULLET_2',
'PROJECTS.TBP.BULLET_3',
'PROJECTS.TBP.BULLET_4',
'PROJECTS.TBP.BULLET_5',
],
challenges: [
'PROJECTS.TBP.CHALLENGE_1',
'PROJECTS.TBP.CHALLENGE_2',
'PROJECTS.TBP.CHALLENGE_3',
'PROJECTS.TBP.CHALLENGE_4',
],
learnings: [
'PROJECTS.TBP.LEARNING_1',
'PROJECTS.TBP.LEARNING_2',
],
isFeatured: true,
technologies: ['Java', 'Spring Boot', 'PostgreSQL', 'React', 'Tailwind CSS', 'Docker']
},
{
identifier: "claude-in-a-box",
title: 'PROJECTS.CLAUDE_BOX.TITLE',
shortDescription: 'PROJECTS.CLAUDE_BOX.SHORT_DESCRIPTION',
introduction: 'PROJECTS.CLAUDE_BOX.INTRODUCTION',
images: [],
diagram: AssetsConstants.CLAUDE_BOX_DIAGRAM,
icon: 'smart_toy',
assets: '',
links: [],
bulletPoints: [
'PROJECTS.CLAUDE_BOX.BULLET_1',
'PROJECTS.CLAUDE_BOX.BULLET_2',
'PROJECTS.CLAUDE_BOX.BULLET_3',
'PROJECTS.CLAUDE_BOX.BULLET_4',
'PROJECTS.CLAUDE_BOX.BULLET_5',
'PROJECTS.CLAUDE_BOX.BULLET_6',
],
challenges: [
'PROJECTS.CLAUDE_BOX.CHALLENGE_1',
'PROJECTS.CLAUDE_BOX.CHALLENGE_2',
'PROJECTS.CLAUDE_BOX.CHALLENGE_3',
'PROJECTS.CLAUDE_BOX.CHALLENGE_4',
],
learnings: [
'PROJECTS.CLAUDE_BOX.LEARNING_1',
'PROJECTS.CLAUDE_BOX.LEARNING_2',
'PROJECTS.CLAUDE_BOX.LEARNING_3',
],
isFeatured: false,
technologies: ['Claude Code', 'MCP', 'Docker', 'Bash', 'Node.js', 'Playwright']
},
{
identifier: "playground",
title: 'PROJECTS.PLAYGROUND.TITLE',
shortDescription: 'PROJECTS.PLAYGROUND.SHORT_DESCRIPTION',
introduction: 'PROJECTS.PLAYGROUND.INTRODUCTION',
images: AssetsConstants.PLAYGROUND_IMAGES.map(url => ({ url, source: '' })),
diagram: AssetsConstants.PLAYGROUND_DIAGRAM,
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',
'PROJECTS.PLAYGROUND.BULLET_5',
'PROJECTS.PLAYGROUND.BULLET_6',
],
challenges: [
'PROJECTS.PLAYGROUND.CHALLENGE_1',
'PROJECTS.PLAYGROUND.CHALLENGE_2',
'PROJECTS.PLAYGROUND.CHALLENGE_3',
],
learnings: [
'PROJECTS.PLAYGROUND.LEARNING_1',
'PROJECTS.PLAYGROUND.LEARNING_2',
'PROJECTS.PLAYGROUND.LEARNING_3',
],
isFeatured: false,
technologies: ['Angular', 'TypeScript', 'Tailwind CSS', 'WebGPU', 'GLSL', 'Babylon.js', 'Gitea Actions', 'Docker', 'Traefik', 'nginx', 'Tailscale']
},
{
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',
],
challenges: [
'PROJECTS.EL_MUCHO.CHALLENGE_1',
'PROJECTS.EL_MUCHO.CHALLENGE_2',
'PROJECTS.EL_MUCHO.CHALLENGE_3',
],
learnings: [
'PROJECTS.EL_MUCHO.LEARNING_1',
'PROJECTS.EL_MUCHO.LEARNING_2',
],
isFeatured: false,
technologies: ['Unity', 'C#', 'Steamworks']
},
{
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: 'Peter Blue and the carnival of death', url: 'https://lobothedark.itch.io/beansjam' },
{ name: 'Arkonauts', url: 'https://lobothedark.itch.io/arkonauts' },
{ name: 'Sloth Bros', url: 'https://lobothedark.itch.io/sloth-bros' },
{ name: 'PROJECTS.GAME_JAMS.LINK_COLLECTION', 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',
],
challenges: [
'PROJECTS.GAME_JAMS.CHALLENGE_1',
'PROJECTS.GAME_JAMS.CHALLENGE_2',
],
learnings: [
'PROJECTS.GAME_JAMS.LEARNING_1',
'PROJECTS.GAME_JAMS.LEARNING_2',
],
isFeatured: false,
technologies: ['Unity', 'C#']
},
{
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',
'PROJECTS.DIPLOMA.BULLET_5',
],
challenges: [
'PROJECTS.DIPLOMA.CHALLENGE_1',
'PROJECTS.DIPLOMA.CHALLENGE_2',
'PROJECTS.DIPLOMA.CHALLENGE_3',
],
learnings: [
'PROJECTS.DIPLOMA.LEARNING_1',
'PROJECTS.DIPLOMA.LEARNING_2',
],
isFeatured: false,
technologies: ['Java', 'BVH / k-DOP', 'Collision detection', 'Cloth simulation']
},
{
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://dashboardicons.com/icons/docker-engine' },
{ url: AssetsConstants.TRIBBLE_IMAGES[1], source: 'https://dashboardicons.com/icons/gitea' },
{ url: AssetsConstants.TRIBBLE_IMAGES[2], source: 'https://dashboardicons.com/icons/traefik' }
],
diagram: AssetsConstants.TRIBBLE_DIAGRAM,
icon: 'dns',
assets: '',
links: [
{ name: 'Ubuntu Server', url: 'https://ubuntu.com/server' },
{ name: 'Docker', url: 'https://www.docker.com/' },
{ name: 'Portainer', url: 'https://www.portainer.io/' },
{ 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/' },
{ name: 'Watchtower', url: 'https://containrrr.dev/watchtower/' }
],
bulletPoints: [
'PROJECTS.TRIBBLE.BULLET_1',
'PROJECTS.TRIBBLE.BULLET_2',
'PROJECTS.TRIBBLE.BULLET_3',
'PROJECTS.TRIBBLE.BULLET_4',
'PROJECTS.TRIBBLE.BULLET_5',
],
challenges: [
'PROJECTS.TRIBBLE.CHALLENGE_1',
'PROJECTS.TRIBBLE.CHALLENGE_2',
],
learnings: [
'PROJECTS.TRIBBLE.LEARNING_1',
'PROJECTS.TRIBBLE.LEARNING_2',
],
isFeatured: false,
technologies: ['Ubuntu Server', 'Docker', 'Portainer', 'Traefik', 'Gitea', 'Jellyfin', 'AdGuard Home', 'Paperless-ngx', 'Tailscale', 'Watchtower']
}
]
featuredProject = computed(() => this.allProjects.find(p => p.isFeatured));
otherProjects = computed(() => this.allProjects.filter(p => !p.isFeatured));
cardImage(project: Projects): string | undefined {
return project.images[0]?.url ?? project.diagram;
}
ngOnInit(): void {
if (this.isBrowser) {
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);
if (project) {
this.openProjectDialog(project);
}
}
});
}
openProjectDialog(project: Projects) {
this.dialog.open(ProjectDialogComponent, {
data: project,
width: '90vw',
maxWidth: '900px',
autoFocus: false,
restoreFocus: false
});
}
}