44 files changed
+1675
-475
No files matched your search
+1
-1
@@ -25,7 +25,7 @@
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets/favicon.ico",
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "public"
|
||||
|
||||
Generated
+331
-293
File diff suppressed because it is too large.
Load diff
+12
-12
@@ -10,26 +10,26 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular-devkit/build-angular": "~20.3.9",
|
||||
"@angular/animations": "20.3.10",
|
||||
"@angular-devkit/build-angular": "~20.3.12",
|
||||
"@angular/animations": "20.3.14",
|
||||
"@angular/cdk": "20.2.11",
|
||||
"@angular/common": "20.3.10",
|
||||
"@angular/compiler": "20.3.10",
|
||||
"@angular/core": "20.3.10",
|
||||
"@angular/forms": "20.3.10",
|
||||
"@angular/common": "~20.3.14",
|
||||
"@angular/compiler": "20.3.14",
|
||||
"@angular/core": "20.3.14",
|
||||
"@angular/forms": "~20.3.14",
|
||||
"@angular/material": "20.2.11",
|
||||
"@angular/platform-browser": "20.3.10",
|
||||
"@angular/router": "20.3.10",
|
||||
"@angular/platform-browser": "~20.3.14",
|
||||
"@angular/router": "~20.3.14",
|
||||
"@ngx-translate/core": "~17.0.0",
|
||||
"@ngx-translate/http-loader": "~17.0.0",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/build": "20.3.9",
|
||||
"@angular/cli": "20.3.9",
|
||||
"@angular/compiler-cli": "20.3.10",
|
||||
"@angular/platform-browser-dynamic": "20.3.10",
|
||||
"@angular/build": "20.3.12",
|
||||
"@angular/cli": "20.3.12",
|
||||
"@angular/compiler-cli": "20.3.14",
|
||||
"@angular/platform-browser-dynamic": "~20.3.14",
|
||||
"@types/jasmine": "~5.1.0",
|
||||
"jasmine-core": "~5.9.0",
|
||||
"karma": "~6.4.0",
|
||||
|
||||
@@ -6,7 +6,7 @@ import {provideAnimations} from '@angular/platform-browser/animations';
|
||||
import {provideHttpClient} from '@angular/common/http';
|
||||
import {provideTranslateService} from '@ngx-translate/core';
|
||||
import {provideTranslateHttpLoader} from '@ngx-translate/http-loader';
|
||||
import {Constants} from './constants/Constants';
|
||||
import {LocalStoreConstants} from './constants/LocalStoreConstants';
|
||||
|
||||
|
||||
const INITIAL_LANG = getInitialLang();
|
||||
@@ -30,7 +30,7 @@ export const appConfig: ApplicationConfig = {
|
||||
};
|
||||
|
||||
function getInitialLang(): string {
|
||||
const saved = localStorage.getItem(Constants.LANGUAGE_KEY);
|
||||
const saved = localStorage.getItem(LocalStoreConstants.LANGUAGE_KEY);
|
||||
if (saved) return saved;
|
||||
const nav = typeof navigator !== 'undefined' ? navigator.language?.toLowerCase() : 'en';
|
||||
return nav?.startsWith('de') ? 'de' : 'en';
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
<mat-toolbar color="primary">
|
||||
<span>{{ 'APP.TITLE' | translate }}</span>
|
||||
<span class="spacer"></span>
|
||||
|
||||
<!-- Language -->
|
||||
<mat-form-field appearance="outline" style="width: 170px; margin-right: 8px;">
|
||||
<mat-select [value]="lang.lang()" (selectionChange)="lang.use($event.value)">
|
||||
<mat-select-trigger>
|
||||
<img class="flag-icon" [src]="lang.lang() === 'de' ? '/assets/flags/de.svg' : '/assets/flags/gb.svg'"
|
||||
alt="" aria-hidden="true">
|
||||
<span style="margin-left: 8px;">
|
||||
{{ lang.lang() === 'de' ? ('LANG.DE' | translate) : ('LANG.EN' | translate) }}
|
||||
</span>
|
||||
</mat-select-trigger>
|
||||
|
||||
<mat-option value="de">
|
||||
<img class="flag-icon" src="/assets/flags/de.svg" alt="" aria-hidden="true">
|
||||
<span> {{ 'LANG.DE' | translate }} </span>
|
||||
</mat-option>
|
||||
|
||||
<mat-option value="en">
|
||||
<img class="flag-icon" src="/assets/flags/gb.svg" alt="" aria-hidden="true">
|
||||
<span> {{ 'LANG.EN' | translate }} </span>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Theme -->
|
||||
<button mat-icon-button (click)="theme.toggle()">
|
||||
<mat-icon>{{ themeIcon() }}</mat-icon>
|
||||
</button>
|
||||
</mat-toolbar>
|
||||
|
||||
<main class="container app-surface">
|
||||
<router-outlet />
|
||||
</main>
|
||||
@@ -1,6 +1,10 @@
|
||||
import { Routes } from '@angular/router';
|
||||
import {WelcomeComponent} from './features/welcome/welcome';
|
||||
import {AboutComponent} from './pages/about/about.component';
|
||||
import {ProjectsComponent} from './pages/projects/projects.component';
|
||||
|
||||
export const routes: Routes = [
|
||||
{ path: '', component: WelcomeComponent },
|
||||
{ path: '', component: AboutComponent },
|
||||
{ path: 'about', component: AboutComponent},
|
||||
{ path: 'projects', component: ProjectsComponent},
|
||||
];
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
.spacer { flex: 1 1 auto; }
|
||||
.container { max-width: 960px; margin: 24px auto; padding: 0 16px; }
|
||||
mat-form-field { --mdc-outlined-text-field-container-shape: 20px; }
|
||||
|
||||
.flag-icon {
|
||||
width: 20px;
|
||||
height: 14px;
|
||||
object-fit: cover;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 0 0 1px rgba(0,0,0,.08) inset;
|
||||
vertical-align: -2px;
|
||||
}
|
||||
mat-option .flag-icon { margin-right: 8px; }
|
||||
@@ -1,32 +0,0 @@
|
||||
import {Component, computed, effect, inject} from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ThemeService } from './service/theme.service';
|
||||
|
||||
import {LanguageService} from './service/language.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
standalone: true,
|
||||
imports: [
|
||||
RouterOutlet,
|
||||
MatToolbarModule, MatIconModule, MatButtonModule,
|
||||
MatFormFieldModule, MatSelectModule,
|
||||
FormsModule,
|
||||
TranslateModule
|
||||
],
|
||||
templateUrl: './app.html',
|
||||
styleUrl: './app.scss',
|
||||
})
|
||||
export class App {
|
||||
readonly theme = inject(ThemeService);
|
||||
readonly lang = inject(LanguageService);
|
||||
readonly themeIcon = computed(() => this.theme.theme() === 'dark' ? 'light_mode' : 'dark_mode');
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
export class AssetsConstants {
|
||||
|
||||
static readonly ME = '/assets/me.webp';
|
||||
static readonly LOGO = '/assets/favicon.ico';
|
||||
static readonly FLAG_DE = '/assets/flags/de.svg';
|
||||
static readonly FLAG_EN = '/assets/flags/gb.svg';
|
||||
|
||||
//logos
|
||||
static readonly CHAMAELEON_LOGO = '/assets/logos/logo_chamaeleon.svg';
|
||||
static readonly TH_BINGEN_LOGO = '/assets/logos/bingen-logo-white.svg';
|
||||
static readonly ASSYST_LOG = '/assets/logos/assyst_gmbh_logo.jpg';
|
||||
static readonly COLORDIGITAL_LOGO = '/assets/logos/dmixcloud_logo.jpg';
|
||||
static readonly TERAPORT_LOGO = '/assets/logos/teraport_gmbh_logo.jpg';
|
||||
|
||||
static readonly CV: 'assets/cv/andreas-dahm-cv.pdf';
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
export class Constants{
|
||||
export class LocalStoreConstants {
|
||||
|
||||
static readonly THEME_KEY = 'theme';
|
||||
static readonly LANGUAGE_KEY = 'lang';
|
||||
@@ -0,0 +1,4 @@
|
||||
export class UrlConstants {
|
||||
static readonly LINKED_IN = 'https://www.linkedin.com/in/andreas-dahm-2395991ba';
|
||||
static readonly GIT_HUB = 'https://github.com/LoboTheDark';
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{ `WELCOME.TITLE` | translate }} </mat-card-title>
|
||||
<mat-card-subtitle>{{ `WELCOME.SUB` | translate }}</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content>
|
||||
<p>{{ `WELCOME.TEXT` | translate }}</p>
|
||||
<p style="margin-top: 8px;">
|
||||
{{ `WELCOME.COUNTER` | translate }}: <strong data-testid="counter">{{ count() }}</strong>
|
||||
</p>
|
||||
</mat-card-content>
|
||||
|
||||
<mat-card-actions>
|
||||
<button mat-raised-button color="primary"
|
||||
(click)="inc()"
|
||||
data-testid="inc"
|
||||
>
|
||||
<mat-icon>add</mat-icon> {{ `WELCOME.INC` | translate }}
|
||||
</button>
|
||||
<button mat-stroked-button
|
||||
(click)="reset()"
|
||||
data-testid="reset"
|
||||
>
|
||||
<mat-icon>restart_alt</mat-icon> {{ `WELCOME.RESET` | translate }}
|
||||
</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
@@ -1,5 +0,0 @@
|
||||
mat-card {
|
||||
margin-top: 2rem;
|
||||
display: block;
|
||||
background-color: var(--app-card-background);
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { Component, signal } from '@angular/core';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import {TranslatePipe} from '@ngx-translate/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-welcome',
|
||||
standalone: true,
|
||||
imports: [MatCardModule, MatButtonModule, MatIconModule, TranslatePipe],
|
||||
templateUrl: './welcome.html',
|
||||
styleUrl: './welcome.scss',
|
||||
})
|
||||
export class WelcomeComponent {
|
||||
readonly count = signal(0);
|
||||
inc() { this.count.update(v => v + 1); }
|
||||
reset() { this.count.set(0); }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<app-topbar />
|
||||
|
||||
<main class="container app-surface">
|
||||
<router-outlet />
|
||||
</main>
|
||||
|
||||
<footer class="foot">
|
||||
<small>© {{ currentYear }} Andreas Dahm - {{ `APP.COPYRIGHT` | translate }}</small>
|
||||
</footer>
|
||||
@@ -0,0 +1,10 @@
|
||||
.container { max-width: 1100px; margin: 0 auto; padding: 1rem; }
|
||||
.app-surface {
|
||||
background: var(--app-bg);
|
||||
color: var(--app-fg);
|
||||
transition: background-color 220ms ease, color 220ms ease;
|
||||
}
|
||||
.foot {
|
||||
border-top: 1px solid rgba(0,0,0,.08);
|
||||
padding: 1rem; text-align: center; opacity: .8;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import {TopbarComponent} from '../topbar/topbar.component';
|
||||
import {TranslatePipe} from '@ngx-translate/core';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
standalone: true,
|
||||
imports: [RouterOutlet, TopbarComponent, TranslatePipe],
|
||||
templateUrl: './app.component.html',
|
||||
styleUrl: './app.component.scss'
|
||||
})
|
||||
export class AppComponent {
|
||||
currentYear = new Date().getFullYear();
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<mat-toolbar class="topbar" color="primary" (keydown)="onKeydown($event)">
|
||||
<a class="brand" routerLink="/">
|
||||
<img class="logo-dot"
|
||||
src="{{AssetsConstants.LOGO}}"
|
||||
alt="" aria-hidden="true"
|
||||
draggable="false"
|
||||
oncontextmenu="return false;"
|
||||
>
|
||||
<span class="brand-text">{{ 'APP.TITLE' | translate }}</span>
|
||||
</a>
|
||||
|
||||
<nav class="nav">
|
||||
<a routerLink="/about" mat-button>{{ 'TOPBAR.ABOUT' | translate }}</a>
|
||||
<a routerLink="/projects" mat-button>{{ 'TOPBAR.PROJECTS' | translate }}</a>
|
||||
<a routerLink="/projects" mat-button>{{ 'TOPBAR.HOBBY' | translate }}</a>
|
||||
<a routerLink="/projects" mat-button>{{ 'TOPBAR.CONTACT' | translate }}</a>
|
||||
</nav>
|
||||
|
||||
<span class="spacer"></span>
|
||||
|
||||
<!-- Settings: Sprache + Theme -->
|
||||
<button mat-icon-button [matMenuTriggerFor]="settingsMenu" aria-label="Open settings" matTooltip="{{ 'TOPBAR.SETTINGS' | translate }}">
|
||||
<mat-icon>tune</mat-icon>
|
||||
</button>
|
||||
|
||||
<mat-menu #settingsMenu="matMenu" xPosition="before">
|
||||
<div class="menu-section">
|
||||
<div class="menu-title">{{ 'TOPBAR.LANGUAGE' | translate }}</div>
|
||||
<button mat-menu-item (click)="setLang('de')">
|
||||
<img class="flag-icon" src="{{AssetsConstants.FLAG_DE}}" alt="" aria-hidden="true">
|
||||
<span>{{ 'LANG.DE' | translate }}</span>
|
||||
@if (lang.lang() === 'de')
|
||||
{
|
||||
<mat-icon >check</mat-icon>
|
||||
}
|
||||
</button>
|
||||
<button mat-menu-item (click)="setLang('en')">
|
||||
<img class="flag-icon" src="{{AssetsConstants.FLAG_EN}}" alt="" aria-hidden="true">
|
||||
<span>{{ 'LANG.EN' | translate }}</span>
|
||||
@if (lang.lang() === 'en')
|
||||
{
|
||||
<mat-icon>check</mat-icon>
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<div class="menu-section">
|
||||
<div class="menu-title">{{ 'TOPBAR.APPEARANCE' | translate }}</div>
|
||||
<button mat-menu-item (click)="theme.toggle()">
|
||||
<mat-icon>{{ themeIcon() }}</mat-icon>
|
||||
<span>
|
||||
{{ theme.theme() === 'dark' ? ('THEME.LIGHT' | translate) : ('THEME.DARK' | translate) }}
|
||||
</span>
|
||||
<span class="kbd">Ctrl/⌘ + J</span>
|
||||
</button>
|
||||
</div>
|
||||
</mat-menu>
|
||||
</mat-toolbar>
|
||||
@@ -0,0 +1,73 @@
|
||||
.topbar {
|
||||
position: sticky; top: 0; z-index: 100;
|
||||
backdrop-filter: saturate(1.1) blur(8px);
|
||||
background:
|
||||
color-mix(in oklab, var(--app-bg) 80%, transparent);
|
||||
border-bottom: 1px solid rgba(0,0,0,.08);
|
||||
|
||||
.brand {
|
||||
display:flex; align-items:center; gap:.6rem;
|
||||
color: inherit; text-decoration: none;
|
||||
.logo-dot {
|
||||
width: 48px; height: 48px; border-radius: 50%;
|
||||
}
|
||||
.brand-text { font-weight: 600; letter-spacing:.2px; }
|
||||
}
|
||||
|
||||
.nav { display:flex; gap:.25rem; margin-left:.5rem; }
|
||||
|
||||
.spacer { flex: 1; }
|
||||
|
||||
.flag-icon { width: 18px; height: 18px; border-radius: 2px; margin-right:.5rem; }
|
||||
|
||||
.menu-section { padding:.25rem .5rem .5rem; }
|
||||
.menu-title { font-size:.75rem; opacity:.75; padding:.25rem .75rem .5rem; }
|
||||
|
||||
.kbd {
|
||||
margin-left:auto; font-size:.7rem; opacity:.65; border:1px solid currentColor;
|
||||
border-radius:4px; padding:0 .35rem;
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .mat-mdc-menu-item .mdc-list-item__primary-text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: .5rem;
|
||||
}
|
||||
|
||||
::ng-deep .mat-mdc-menu-item .kbd {
|
||||
margin-left: auto;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
|
||||
font-size: 11px;
|
||||
line-height: 1.6;
|
||||
padding: 0 .35rem;
|
||||
border: 0px solid currentColor;
|
||||
border-radius: 4px;
|
||||
opacity: .65;
|
||||
}
|
||||
|
||||
::ng-deep .mat-mdc-menu-item .mat-icon {
|
||||
width: 20px; height: 20px; font-size: 20px;
|
||||
}
|
||||
|
||||
::ng-deep .mat-mdc-menu-item .flag-icon {
|
||||
width: 20px !important;
|
||||
height: 14px !important;
|
||||
object-fit: cover;
|
||||
border-radius: 2px;
|
||||
margin-right: .5rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
::ng-deep .mat-mdc-menu-panel {
|
||||
border-radius: 10px !important;
|
||||
border: 1px solid rgba(0,0,0,.14);
|
||||
}
|
||||
.dark ::ng-deep .mat-mdc-menu-panel {
|
||||
border-color: rgba(255,255,255,.06);
|
||||
}
|
||||
|
||||
/* Responsive: Collapse navigation to icon if width is smaller than 760px */
|
||||
@media (max-width: 760px) {
|
||||
.topbar .nav { display:none; }
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import { Component, computed, inject } from '@angular/core';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ThemeService } from '../../service/theme.service';
|
||||
import { LanguageService } from '../../service/language.service';
|
||||
import { MatDivider } from '@angular/material/divider';
|
||||
import {AssetsConstants} from '../../constants/AssetsConstants';
|
||||
|
||||
@Component({
|
||||
selector: 'app-topbar',
|
||||
standalone: true,
|
||||
imports: [
|
||||
RouterLink,
|
||||
MatToolbarModule, MatIconModule, MatButtonModule, MatMenuModule, MatTooltipModule,
|
||||
TranslateModule, MatDivider
|
||||
],
|
||||
templateUrl: './topbar.component.html',
|
||||
styleUrl: './topbar.component.scss'
|
||||
})
|
||||
export class TopbarComponent {
|
||||
readonly theme = inject(ThemeService);
|
||||
readonly lang = inject(LanguageService);
|
||||
|
||||
readonly themeIcon = computed(() =>
|
||||
this.theme.theme() === 'dark' ? 'light_mode' : 'dark_mode'
|
||||
);
|
||||
|
||||
onKeydown(e: KeyboardEvent) {
|
||||
const metaOrCtrl = e.metaKey || e.ctrlKey;
|
||||
if (metaOrCtrl && (e.key.toLowerCase() === 'j')) {
|
||||
e.preventDefault();
|
||||
this.theme.toggle();
|
||||
}
|
||||
}
|
||||
|
||||
setLang(code: 'de' | 'en') { this.lang.use(code); }
|
||||
|
||||
protected readonly AssetsConstants = AssetsConstants;
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
<section class="about">
|
||||
<mat-card class="hero">
|
||||
<div class="photo">
|
||||
<img
|
||||
[ngSrc]="AssetsConstants.ME"
|
||||
width="320" height="400"
|
||||
alt="{{ 'ABOUT.ALT.PROFILE' | translate }}"
|
||||
draggable="false"
|
||||
oncontextmenu="return false;"
|
||||
priority />
|
||||
</div>
|
||||
|
||||
<div class="intro">
|
||||
<h1>{{ 'ABOUT.HELLO' | translate }}</h1>
|
||||
<p class="lead">
|
||||
{{ 'ABOUT.LEAD' | translate }}
|
||||
</p>
|
||||
|
||||
<div class="meta">
|
||||
<div class="row">
|
||||
<mat-icon aria-hidden="true">work</mat-icon>
|
||||
<span>{{ 'ABOUT.ROLE' | translate }}</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<mat-icon aria-hidden="true">location_on</mat-icon>
|
||||
<span>{{ 'ABOUT.LOCATION' | translate }}</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<mat-icon aria-hidden="true">email</mat-icon>
|
||||
<a href="" (click)="openMail($event)">
|
||||
{{ 'ABOUT.CONTACT_ME' | translate }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="row">
|
||||
<mat-icon aria-hidden="true">link</mat-icon>
|
||||
<a href="{{UrlConstants.GIT_HUB}}" target="_blank" rel="noopener">GitHub</a>
|
||||
<span>·</span>
|
||||
<a href="{{UrlConstants.LINKED_IN}}" target="_blank" rel="noopener">LinkedIn</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card>
|
||||
|
||||
<mat-card class="skills">
|
||||
<h2>{{ 'ABOUT.SECTION.SKILLS' | translate }}</h2>
|
||||
<div class="chip-groups">
|
||||
<div>
|
||||
<h3>{{ 'ABOUT.SECTION.PRIMARY' | translate }}</h3>
|
||||
<mat-chip-set aria-label="Primary skills">
|
||||
@for (s of primarySkills; track primarySkills) {
|
||||
<mat-chip >{{ s | translate }}</mat-chip>
|
||||
}
|
||||
</mat-chip-set>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>{{ 'ABOUT.SECTION.TOOLSET' | translate }}</h3>
|
||||
<mat-chip-set aria-label="Toolset">
|
||||
@for (t of toolset; track toolset) {
|
||||
<mat-chip>{{ t | translate }}</mat-chip>
|
||||
}
|
||||
</mat-chip-set>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card>
|
||||
|
||||
<mat-card class="experience">
|
||||
<h2>{{ 'ABOUT.SECTION.EXPERIENCE' | translate }}</h2>
|
||||
<div class="xp-list">
|
||||
@for (entry of xpKeys; track entry) {
|
||||
<div class="xp-item">
|
||||
<div class="xp-head-grid">
|
||||
<div class="logo-wrap">
|
||||
<img
|
||||
src="{{entry.logo}}"
|
||||
alt=""
|
||||
class="company-logo"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
<div class="head-row">
|
||||
<strong>{{ (entry.key + '.ROLE') | translate }}</strong>
|
||||
<span class="time">{{ (entry.key + '.TIME') | translate }}</span>
|
||||
</div>
|
||||
|
||||
<div class="company-row">
|
||||
{{ (entry.key + '.COMPANY') | translate }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="highlights">
|
||||
<ul>
|
||||
<li>{{ entry.key + '.HIGHLIGHTS.P1' | translate }}</li>
|
||||
<li>{{ entry.key + '.HIGHLIGHTS.P2' | translate }}</li>
|
||||
<li>{{ entry.key + '.HIGHLIGHTS.P3' | translate }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if(entry.key !== xpKeys.at(xpKeys.length-1)?.key)
|
||||
{
|
||||
<mat-divider></mat-divider>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</mat-card>
|
||||
<mat-card class="projects">
|
||||
<h2>{{ 'ABOUT.SECTION.PROJECTS' | translate }}</h2>
|
||||
|
||||
<div class="xp-list">
|
||||
@for (entry of projectKeys; track entry) {
|
||||
<div class="xp-item">
|
||||
<div class="head-row">
|
||||
<strong>{{ (entry.key + '.TITLE') | translate }}</strong>
|
||||
</div>
|
||||
<div class="company-row">
|
||||
{{ (entry.key + '.DESCRIPTION') | translate }}
|
||||
</div>
|
||||
<div class="link-row">
|
||||
<a class="link-with-icon"
|
||||
href="{{entry.externalLink}}"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">
|
||||
<mat-icon>open_in_new</mat-icon>
|
||||
{{ (entry.key + '.LINK_EXTERNAL') | translate }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="link-row">
|
||||
<a class="link-with-icon"
|
||||
href="{{entry.internalLink}}"
|
||||
rel="noopener noreferrer">
|
||||
<mat-icon>link</mat-icon>
|
||||
{{ (entry.key + '.LINK_INTERNAL') | translate }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="highlights-noMargin">
|
||||
<ul>
|
||||
<li>{{ entry.key + '.HIGHLIGHTS.P1' | translate }}</li>
|
||||
<li>{{ entry.key + '.HIGHLIGHTS.P2' | translate }}</li>
|
||||
<li>{{ entry.key + '.HIGHLIGHTS.P3' | translate }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if(entry.key !== projectKeys.at(projectKeys.length-1)?.key)
|
||||
{
|
||||
<mat-divider></mat-divider>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</mat-card>
|
||||
|
||||
<mat-card class="education">
|
||||
<h2>{{ 'ABOUT.SECTION.EDUCATION' | translate }}</h2>
|
||||
|
||||
<div class="xp-list">
|
||||
<div class="xp-item">
|
||||
@for (entry of educationKeys; track entry) {
|
||||
<div class="head-row">
|
||||
<strong>{{ (entry.key + '.WHERE') | translate }}</strong>
|
||||
<span class="time">{{ (entry.key + '.WHEN') | translate }}</span>
|
||||
</div>
|
||||
<div class="company-row">
|
||||
{{ (entry.key + '.WHAT') | translate }}
|
||||
</div>
|
||||
|
||||
@if(entry.key !== educationKeys.at(educationKeys.length-1)?.key)
|
||||
{
|
||||
<mat-divider style="margin-top: .5rem; margin-bottom: .5rem"></mat-divider>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</mat-card>
|
||||
</section>
|
||||
@@ -0,0 +1,217 @@
|
||||
.about {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
/* Hero block: Photo + Intro */
|
||||
.hero {
|
||||
display: grid;
|
||||
grid-template-columns: 240px 1fr;
|
||||
gap: 1.25rem;
|
||||
border-radius: 16px;
|
||||
background: var(--app-card-background);
|
||||
|
||||
.photo {
|
||||
align-items:flex-start; justify-content:center;
|
||||
img {
|
||||
display:block;
|
||||
width: 100%; height: auto;
|
||||
max-width: 220px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 6px 24px rgba(0,0,0,.25);
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.intro {
|
||||
display:flex; flex-direction:column; gap:.5rem;
|
||||
h1 { margin-top: .25rem }
|
||||
.lead { opacity:.9; margin: .25rem 0 0.5rem; }
|
||||
|
||||
.meta {
|
||||
display:flex; flex-direction:column; gap:.25rem; margin-bottom: 0.5rem;
|
||||
.row {
|
||||
display:flex; align-items:center; gap:.4rem;
|
||||
a { color: inherit; }
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
display:flex; gap:.5rem; flex-wrap:wrap; margin-top:.5rem;
|
||||
.mat-icon { margin-right:.25rem; }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Skills block */
|
||||
.skills {
|
||||
border-radius: 16px;
|
||||
padding: 5px;
|
||||
background: var(--app-card-background);
|
||||
|
||||
h2 { margin-top: .25rem; margin-left: .25rem; }
|
||||
.chip-groups {
|
||||
margin-left: .25rem;
|
||||
display:grid; gap:1rem;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
margin-bottom: .5rem;
|
||||
h3 { margin: .2rem 0 .4rem; font-size: .95rem; opacity:.85; }
|
||||
mat-chip-set {
|
||||
display:flex; flex-wrap:wrap; gap:.4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Experience block */
|
||||
.experience {
|
||||
border-radius: 16px;
|
||||
padding: 5px;
|
||||
background: var(--app-card-background);
|
||||
h2 { margin-top: .25rem;margin-left: .25rem; }
|
||||
.xp-list {
|
||||
margin-left: .25rem;
|
||||
display: grid; gap: .75rem;
|
||||
}
|
||||
.xp-item {
|
||||
.xp-head {
|
||||
display:flex; align-items:baseline; gap:.5rem;
|
||||
.time { opacity:.75; font-size:.9rem; }
|
||||
}
|
||||
.xp-sub { opacity:.9; margin-bottom:.25rem; }
|
||||
ul { margin: .25rem 0 .5rem 1.15rem; }
|
||||
}
|
||||
}
|
||||
|
||||
/* Experience block */
|
||||
.projects {
|
||||
border-radius: 16px;
|
||||
padding: 5px;
|
||||
background: var(--app-card-background);
|
||||
h2 { margin-top: .25rem;margin-left: .25rem; }
|
||||
.xp-list {
|
||||
margin-left: .25rem;
|
||||
display: grid; gap: .75rem;
|
||||
}
|
||||
.xp-item {
|
||||
.xp-head {
|
||||
display:flex; align-items:baseline; gap:.5rem;
|
||||
.time { opacity:.75; font-size:.9rem; }
|
||||
}
|
||||
.xp-sub { opacity:.9; margin-bottom:.25rem; }
|
||||
ul { margin: .25rem 0 .5rem 1.15rem; }
|
||||
}
|
||||
}
|
||||
|
||||
/* Experience block */
|
||||
.education {
|
||||
border-radius: 16px;
|
||||
padding: 5px;
|
||||
background: var(--app-card-background);
|
||||
h2 { margin-top: .25rem;margin-left: .25rem; }
|
||||
.xp-list {
|
||||
margin-left: .25rem;
|
||||
display: grid; gap: .75rem;
|
||||
}
|
||||
.xp-item {
|
||||
.xp-head {
|
||||
display:flex; align-items:baseline; gap:.5rem;
|
||||
.time { opacity:.75; font-size:.9rem; }
|
||||
}
|
||||
.xp-sub { opacity:.9; margin-bottom:.25rem; }
|
||||
ul { margin: .25rem 0 .5rem 1.15rem; }
|
||||
}
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 900px) {
|
||||
.hero { grid-template-columns: 1fr; }
|
||||
.hero .photo { justify-content: flex-start; }
|
||||
.skills .chip-groups { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
.xp-head-grid {
|
||||
display: grid;
|
||||
grid-template-columns: calc(48px + .75rem) 1fr; /* 1: Logo, 2: Text */
|
||||
grid-template-rows: auto auto; /* 1: Role/Time, 2: Company */
|
||||
column-gap: .75rem;
|
||||
}
|
||||
|
||||
.logo-wrap {
|
||||
grid-row: 1 / span 2;
|
||||
grid-column: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.company-logo {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
object-fit: contain;
|
||||
opacity: .9;
|
||||
border-radius: 10%;
|
||||
background-color: var(--app-logo-bg);
|
||||
}
|
||||
|
||||
|
||||
.head-row {
|
||||
grid-row: 1;
|
||||
grid-column: 2;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: baseline;
|
||||
gap: .5rem 1rem;
|
||||
|
||||
strong {
|
||||
font-size: 1rem;
|
||||
}
|
||||
.time {
|
||||
opacity: .75; font-size: .9rem;
|
||||
}
|
||||
}
|
||||
|
||||
.company-row {
|
||||
grid-row: 2;
|
||||
grid-column: 2;
|
||||
margin-top: .1rem;
|
||||
opacity: .85;
|
||||
}
|
||||
|
||||
.link-row {
|
||||
grid-row: 2;
|
||||
grid-column: 2;
|
||||
margin-top: .1rem;
|
||||
opacity: .85;
|
||||
vertical-align: center;
|
||||
}
|
||||
|
||||
.link-with-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: .35rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.link-with-icon mat-icon {
|
||||
font-size: 18px;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
.highlights {
|
||||
margin-top: .4rem;
|
||||
margin-left: .75rem;
|
||||
padding-left: 1.2rem;
|
||||
|
||||
li {
|
||||
margin: .2rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
.highlights-noMargin {
|
||||
margin-top: .4rem;
|
||||
|
||||
li {
|
||||
margin: .2rem 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
import { Component} from '@angular/core';
|
||||
import { CommonModule, NgOptimizedImage } from '@angular/common';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatChipsModule } from '@angular/material/chips';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import {UrlConstants} from '../../constants/UrlConstants';
|
||||
import {AssetsConstants} from '../../constants/AssetsConstants';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-about',
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule, NgOptimizedImage,
|
||||
MatCardModule, MatChipsModule, MatIconModule, MatButtonModule, MatDividerModule,
|
||||
TranslateModule
|
||||
],
|
||||
templateUrl: './about.component.html',
|
||||
styleUrl: './about.component.scss'
|
||||
})
|
||||
export class AboutComponent {
|
||||
cvHref = AssetsConstants.CV;
|
||||
|
||||
xpKeys = [
|
||||
{
|
||||
key: 'ABOUT.XP.COMPANY8',
|
||||
logo: AssetsConstants.TERAPORT_LOGO
|
||||
},
|
||||
{
|
||||
key: 'ABOUT.XP.COMPANY7',
|
||||
logo: AssetsConstants.COLORDIGITAL_LOGO
|
||||
},
|
||||
{
|
||||
key: 'ABOUT.XP.COMPANY6',
|
||||
logo: AssetsConstants.COLORDIGITAL_LOGO
|
||||
},
|
||||
{
|
||||
key: 'ABOUT.XP.COMPANY5',
|
||||
logo: AssetsConstants.ASSYST_LOG
|
||||
},
|
||||
{
|
||||
key: 'ABOUT.XP.COMPANY4',
|
||||
logo: AssetsConstants.ASSYST_LOG
|
||||
},
|
||||
{
|
||||
key: 'ABOUT.XP.COMPANY3',
|
||||
logo: AssetsConstants.ASSYST_LOG
|
||||
},
|
||||
{
|
||||
key: 'ABOUT.XP.COMPANY2',
|
||||
logo: AssetsConstants.TH_BINGEN_LOGO
|
||||
},
|
||||
{
|
||||
key: 'ABOUT.XP.COMPANY1',
|
||||
logo: AssetsConstants.TH_BINGEN_LOGO
|
||||
},
|
||||
{
|
||||
key: 'ABOUT.XP.COMPANY0',
|
||||
logo: AssetsConstants.CHAMAELEON_LOGO
|
||||
}
|
||||
];
|
||||
|
||||
projectKeys = [
|
||||
{
|
||||
key: 'ABOUT.PROJECT.P2',
|
||||
externalLink: 'https://andreas-dahm.eu/',
|
||||
internalLink: 'projects'
|
||||
},
|
||||
{
|
||||
key: 'ABOUT.PROJECT.P1',
|
||||
externalLink: 'https://store.steampowered.com/app/1532640/El_Mucho/',
|
||||
internalLink: 'projects'
|
||||
},
|
||||
{
|
||||
key: 'ABOUT.PROJECT.P0',
|
||||
externalLink: 'https://itch.io/c/6628860/lobos-collection',
|
||||
internalLink: 'projects'
|
||||
}
|
||||
];
|
||||
|
||||
educationKeys = [
|
||||
{
|
||||
key: 'ABOUT.EDUCATION.E6'
|
||||
},
|
||||
{
|
||||
key: 'ABOUT.EDUCATION.E5'
|
||||
},
|
||||
{
|
||||
key: 'ABOUT.EDUCATION.E4'
|
||||
},
|
||||
{
|
||||
key: 'ABOUT.EDUCATION.E3'
|
||||
},
|
||||
{
|
||||
key: 'ABOUT.EDUCATION.E2'
|
||||
},
|
||||
{
|
||||
key: 'ABOUT.EDUCATION.E1'
|
||||
},
|
||||
{
|
||||
key: 'ABOUT.EDUCATION.E0'
|
||||
}
|
||||
]
|
||||
|
||||
primarySkills = [
|
||||
'ABOUT.SKILLS.JAVA',
|
||||
'ABOUT.SKILLS.SPRING',
|
||||
'ABOUT.SKILLS.ANGULAR',
|
||||
'ABOUT.SKILLS.DOCKER',
|
||||
'ABOUT.SKILLS.UNITY',
|
||||
'ABOUT.SKILLS.PYTHON',
|
||||
'ABOUT.SKILLS.CSHARP',
|
||||
'ABOUT.SKILLS.TYPESCRIPT'
|
||||
];
|
||||
|
||||
toolset = [
|
||||
'ABOUT.TOOLS.GIT',
|
||||
'ABOUT.TOOLS.GITHUB',
|
||||
'ABOUT.TOOLS.GITLAB',
|
||||
'ABOUT.TOOLS.JENKINS',
|
||||
'ABOUT.TOOLS.K8S',
|
||||
'ABOUT.TOOLS.POSTGRES',
|
||||
'ABOUT.TOOLS.MONGO',
|
||||
'ABOUT.TOOLS.GRAFANA',
|
||||
];
|
||||
|
||||
openMail(event: Event) {
|
||||
event.preventDefault();
|
||||
const user = 'andreas.dahm';
|
||||
const domain = 'gmail.com';
|
||||
globalThis.location.href = `mailto:${user}@${domain}`;
|
||||
}
|
||||
|
||||
protected readonly UrlConstants = UrlConstants;
|
||||
protected readonly AssetsConstants = AssetsConstants;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<p>project-details works!</p>
|
||||
Whitespace-only changes.
@@ -0,0 +1,11 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-project-details',
|
||||
imports: [],
|
||||
templateUrl: './project-details.component.html',
|
||||
styleUrl: './project-details.component.scss',
|
||||
})
|
||||
export class ProjectDetailsComponent {
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<p>Working in progress!</p>
|
||||
Whitespace-only changes.
@@ -0,0 +1,11 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-projects',
|
||||
imports: [],
|
||||
templateUrl: './projects.component.html',
|
||||
styleUrl: './projects.component.scss',
|
||||
})
|
||||
export class ProjectsComponent {
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Injectable, inject, signal } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {Constants} from '../constants/Constants';
|
||||
import {LocalStoreConstants} from '../constants/LocalStoreConstants';
|
||||
|
||||
type Lang = 'de' | 'en';
|
||||
|
||||
@@ -19,12 +19,12 @@ export class LanguageService {
|
||||
use(l: Lang) {
|
||||
this.lang.set(l);
|
||||
this.translate.use(l);
|
||||
try { localStorage.setItem(Constants.LANGUAGE_KEY, l); } catch {}
|
||||
try { localStorage.setItem(LocalStoreConstants.LANGUAGE_KEY, l); } catch {}
|
||||
}
|
||||
|
||||
private getInitial(): Lang {
|
||||
try {
|
||||
const stored = localStorage.getItem(Constants.LANGUAGE_KEY) as Lang | null;
|
||||
const stored = localStorage.getItem(LocalStoreConstants.LANGUAGE_KEY) as Lang | null;
|
||||
if (stored === 'de' || stored === 'en') return stored;
|
||||
} catch {}
|
||||
const browser = (navigator.language || 'en').toLowerCase();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Injectable, NgZone, signal } from '@angular/core';
|
||||
import {Constants} from '../constants/Constants';
|
||||
import {LocalStoreConstants} from '../constants/LocalStoreConstants';
|
||||
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
@@ -20,13 +20,13 @@ export class ReloadService {
|
||||
|
||||
|
||||
private informListeners(e: StorageEvent, zone: NgZone) {
|
||||
if (e.key === Constants.LANGUAGE_KEY) {
|
||||
if (e.key === LocalStoreConstants.LANGUAGE_KEY) {
|
||||
zone.run(() => this._languageChangedTick.update(v => v + 1));
|
||||
}
|
||||
}
|
||||
|
||||
bumpLanguageChanged(): void {
|
||||
this._reloadTick.update(v => v + 1);
|
||||
localStorage.setItem(Constants.RELOAD_ALL_LANG_LISTENER_KEY, String(Date.now()));
|
||||
localStorage.setItem(LocalStoreConstants.RELOAD_ALL_LANG_LISTENER_KEY, String(Date.now()));
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Injectable, effect, inject, signal } from '@angular/core';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { OverlayContainer } from '@angular/cdk/overlay';
|
||||
import {Constants} from '../constants/Constants';
|
||||
import {LocalStoreConstants} from '../constants/LocalStoreConstants';
|
||||
|
||||
type Theme = 'light' | 'dark';
|
||||
|
||||
@@ -20,13 +20,13 @@ export class ThemeService {
|
||||
body.classList.toggle('dark', isDark);
|
||||
overlayEl.classList.toggle('dark', isDark);
|
||||
|
||||
try { localStorage.setItem(Constants.THEME_KEY, this.theme()); } catch {}
|
||||
try { localStorage.setItem(LocalStoreConstants.THEME_KEY, this.theme()); } catch {}
|
||||
});
|
||||
|
||||
try {
|
||||
const mm = globalThis.matchMedia('(prefers-color-scheme: dark)');
|
||||
mm.addEventListener('change', e => {
|
||||
const stored = localStorage.getItem(Constants.THEME_KEY) as Theme | null;
|
||||
const stored = localStorage.getItem(LocalStoreConstants.THEME_KEY) as Theme | null;
|
||||
if (!stored) this.setTheme(e.matches ? 'dark' : 'light');
|
||||
});
|
||||
} catch {}
|
||||
@@ -37,7 +37,7 @@ export class ThemeService {
|
||||
|
||||
private getInitialTheme(): Theme {
|
||||
try {
|
||||
const stored = localStorage.getItem(Constants.THEME_KEY) as Theme | null;
|
||||
const stored = localStorage.getItem(LocalStoreConstants.THEME_KEY) as Theme | null;
|
||||
if (stored === 'dark' || stored === 'light') return stored;
|
||||
} catch {}
|
||||
try {
|
||||
|
||||
File renamed without changes.
+215
-9
@@ -1,13 +1,219 @@
|
||||
{
|
||||
"APP": { "TITLE": "Playground" },
|
||||
"WELCOME": {
|
||||
"TITLE": "Willkommen 👋",
|
||||
"SUB": "Angular 20 + Material",
|
||||
"TEXT": "Das ist eine einfache Start-Komponente als Basis.",
|
||||
"COUNTER": "Zähler",
|
||||
"INC": "Inkrementieren",
|
||||
"RESET": "Zurücksetzen"
|
||||
"APP": {
|
||||
"TITLE": "Playground",
|
||||
"COPYRIGHT": "Bilder urheberrechtlich geschützt, keine Nutzung ohne Zustimmung!"
|
||||
},
|
||||
"TOPBAR": {
|
||||
"ABOUT": "Über mich",
|
||||
"CONTACT": "Kontakt",
|
||||
"PROJECTS": "Projekte",
|
||||
"HOBBY": "Hobbies",
|
||||
"SETTINGS": "Einstellungen",
|
||||
"LANGUAGE": "Sprache",
|
||||
"APPEARANCE": "Darstellung"
|
||||
},
|
||||
"THEME": { "LIGHT": "Hell", "DARK": "Dunkel" },
|
||||
"LANG": { "LABEL": "Sprache", "EN": "Englisch", "DE": "Deutsch" }
|
||||
"LANG": { "LABEL": "Sprache", "EN": "Englisch", "DE": "Deutsch" },
|
||||
"ABOUT": {
|
||||
"ALT": { "PROFILE": "Profilfoto von Andreas Dahm" },
|
||||
"HELLO": "Hallo, ich bin Andreas Dahm.",
|
||||
"LEAD": "Bereits in meiner Ausbildung zum Fachinformatiker hat mich fasziniert, wie man durch Code komplexe Probleme elegant lösen kann. Nach meinem Studium der Angewandten Informatik an der FH Bingen konnte ich diese Begeisterung in verschiedensten Projekten vertiefen – von 3D-Simulationen bis zu modernen Web-Applikationen. Heute arbeite ich als Senior Software Developer und Architekt mit Fokus auf Java, Angular und DevOps. Danke, dass du vorbeischaust!",
|
||||
"ROLE": "Senior Software Entwickler / Full-Stack Entwickler / Softwarearchitekt",
|
||||
"LOCATION": "München · Remote",
|
||||
"DOWNLOAD_CV": "Lebenslauf herunterladen",
|
||||
"VIEW_PROJECTS": "Projekte ansehen",
|
||||
"CONTACT_ME": "Kontaktiere mich",
|
||||
"SECTION": {
|
||||
"SKILLS": "Fähigkeiten & Stack",
|
||||
"PRIMARY": "Schwerpunkte",
|
||||
"TOOLSET": "Toolset",
|
||||
"EXPERIENCE": "Erfahrung",
|
||||
"PROJECTS": "Projekte",
|
||||
"EDUCATION": "Ausbildung"
|
||||
},
|
||||
"SKILLS": {
|
||||
"JAVA": "Java 8/Java 21+",
|
||||
"SPRING": "Spring Boot 2/3",
|
||||
"ANGULAR": "Angular 20+",
|
||||
"DOCKER": "Docker",
|
||||
"UNITY": "Unity",
|
||||
"PYTHON": "Python",
|
||||
"CSHARP": "C#",
|
||||
"TYPESCRIPT": "TypeScript"
|
||||
},
|
||||
"TOOLS": {
|
||||
"GIT": "Git",
|
||||
"GITHUB": "Github",
|
||||
"GITLAB": "Gitlab",
|
||||
"JENKINS": "Jenkins",
|
||||
"K8S": "Kubernetes / k3d",
|
||||
"POSTGRES": "PostgreSQL",
|
||||
"MONGO": "MongoDB",
|
||||
"GRAFANA": "Grafana/Prometheus"
|
||||
},
|
||||
"XP": {
|
||||
"COMPANY8": {
|
||||
"COMPANY": "Teraport GmbH",
|
||||
"ROLE": "Senior Software Developer / Architect",
|
||||
"TIME": "Feb. 2024 – heute",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Architektur und Implementierung der Datenbankanbindung mit Hibernate 6.x.",
|
||||
"P2": "Konzeption und Entwicklung einer Full-Stack-Webanwendung für Kollisionsanalysen (Angular + Spring Boot + Docker).",
|
||||
"P3": "Entwicklung eines Kostenanalysetools mit dem Namen MIDO."
|
||||
}
|
||||
},
|
||||
"COMPANY7": {
|
||||
"COMPANY": "ColorDigital GmbH",
|
||||
"ROLE": "Lead Software Developer",
|
||||
"TIME": "März 2023 – Dez. 2023",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Planung einer neuen Cloud-Architektur zur Migration eines umfangreichen Legacy-Monolithen in eine moderne Microservice-Plattform.",
|
||||
"P2": "Leitung eines Teams von drei bis vier Backend-Entwickler:innen.",
|
||||
"P3": "Zusammenarbeit mit Partnern und Kund:innen bei der Integration ihrer Systeme in die DMIx-Cloud."
|
||||
}
|
||||
},
|
||||
"COMPANY6": {
|
||||
"COMPANY": "ColorDigital GmbH",
|
||||
"ROLE": "Senior Software Developer",
|
||||
"TIME": "März 2021 – März 2023",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Arbeit an der DMIx-Core-Cloud, darunter die Implementierung einer Elasticsearch-basierten Echtzeit-Suchfunktion.",
|
||||
"P2": "Implementierung des neuen Browser-Tools „Moodboard“ (Node.js + Vue.js).",
|
||||
"P3": "Entwicklung von „PAX“, einem Tool für den Datenaustausch zwischen der DMIx-Cloud und PLM/ERP-Systemen, inkl. CI/CD-Integration."
|
||||
}
|
||||
},
|
||||
"COMPANY5": {
|
||||
"COMPANY": "Assyst GmbH",
|
||||
"ROLE": "Teamleitung",
|
||||
"TIME": "Sep. 2015 – Feb. 2021",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Teamleitung der Vidya-Softwareabteilung, inkl. Personalverantwortung und Bewerbungsprozesse.",
|
||||
"P2": "Leitung mehrerer Projekte mit externen Partnern und Freelancer:innen.",
|
||||
"P3": "Steuerung strategischer Initiativen im Bereich 3D-Softwareentwicklung."
|
||||
}
|
||||
},
|
||||
"COMPANY4": {
|
||||
"COMPANY": "Assyst GmbH",
|
||||
"ROLE": "Software Engineer",
|
||||
"TIME": "Apr. 2010 – Feb. 2021",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Arbeit an Kerntechnologien wie Algorithmen, Simulation, Rendering und Kollisionserkennung.",
|
||||
"P2": "Einsatz verschiedener Technologien, u. a. Java, OpenCL, OpenGL, GLSL-Shader, C++ und REST-Schnittstellen.",
|
||||
"P3": "Mitarbeit an nationalen und internationalen Forschungsprojekten (EU7 und ZIM)."
|
||||
}
|
||||
},
|
||||
"COMPANY3": {
|
||||
"COMPANY": "Assyst GmbH",
|
||||
"ROLE": "Praktikum und Diplomarbeit",
|
||||
"TIME": "Apr. 2009 – Apr. 2010",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Implementierung produktiver Funktionen in der Echtzeit-Kleidersimulationssoftware Vidya.",
|
||||
"P2": "Durchführung von Recherchen und Literaturstudien für die Diplomarbeit.",
|
||||
"P3": "Erfolgreiche Umsetzung des Diplomthemas in Vidya."
|
||||
}
|
||||
},
|
||||
"COMPANY2": {
|
||||
"COMPANY": "TH Bingen (University of Applied Sciences)",
|
||||
"ROLE": "Tutor für Grundlagen der Java-Programmierung",
|
||||
"TIME": "Apr. 2008 – Aug. 2008",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Erstellung praktischer und theoretischer Lehrmaterialien.",
|
||||
"P2": "Durchführung einer 20-stündigen Vorlesungsreihe für den Bioinformatik-Studiengang.",
|
||||
"P3": "Unterstützung bei praktischen Programmierübungen."
|
||||
}
|
||||
},
|
||||
"COMPANY1": {
|
||||
"COMPANY": "TH Bingen (University of Applied Sciences)",
|
||||
"ROLE": "Wissenschaftliche Hilfskraft",
|
||||
"TIME": "Okt. 2007 – Apr. 2008",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Evaluation verschiedener Web-2.0-Technologien.",
|
||||
"P2": "Implementierung einer Java-basierten Schnittstelle zu Microsoft Excel.",
|
||||
"P3": "Integration des MIT-Exhibit-Frameworks und Vorbereitung für die CeBIT 2008."
|
||||
}
|
||||
},
|
||||
"COMPANY0": {
|
||||
"COMPANY": "Chamaeleon AG",
|
||||
"ROLE": "Ausbildung Fachinformatiker Anwendungsentwicklung",
|
||||
"TIME": "Jul. 2002 – Jun. 2005",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Entwicklung in PERL, PHP und ASP.",
|
||||
"P2": "Portierung, Wartung und Reengineering von bestender Software.",
|
||||
"P3": "Regelmäßige Durchführung von Systemtests und Qualitätskontrollen, sowie deren Dokumentation."
|
||||
}
|
||||
}
|
||||
},
|
||||
"PROJECT": {
|
||||
"P2": {
|
||||
"TITLE": "Playground",
|
||||
"DESCRIPTION": "Dieses Projekt ist, wie der Name schon sagt, ein persönlicher Playground, der im Laufe der Zeit wachsen soll. Es präsentiert verschiedene private Projekte, an denen ich arbeite, und dokumentiert deren Fortschritt, zentrale Ideen und wichtige Meilensteine.",
|
||||
"LINK_EXTERNAL": "andreas-dahm.eu",
|
||||
"LINK_INTERNAL": "Projektdetails",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Einsatz moderner Technologien und CI/CD-Pipelines (Angular 20+, Spring Boot 4, GitHub).",
|
||||
"P2": "Präsentation persönlicher Projekte und kontinuierliche Verbesserung algorithmischer Fähigkeiten.",
|
||||
"P3": "Vertiefung von JavaScript/TypeScript-, Angular- und Spring-Boot-Kenntnissen durch praktisches Arbeiten."
|
||||
}
|
||||
},
|
||||
"P1": {
|
||||
"TITLE": "El Mucho",
|
||||
"DESCRIPTION": "Dies ist mein erstes veröffentlichtes Spiel auf Steam. Ich habe es gemeinsam mit meinem Bruder entwickelt und damit eines meiner persönlichen Ziele erreicht: ein eigenes Videospiel zu erstellen und zu veröffentlichen.",
|
||||
"LINK_EXTERNAL": "Steam Store",
|
||||
"LINK_INTERNAL": "Projektdetails",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Veröffentlichung eines Spiels auf Steam und Integration der Steam-API.",
|
||||
"P2": "Konzeption, Planung und vollständige Entwicklung eines eigenen Spiels.",
|
||||
"P3": "Implementierung komplexer Algorithmen wie einer eigenen A*-Pfadfindungslogik und Spiel-KI."
|
||||
}
|
||||
},
|
||||
"P0": {
|
||||
"TITLE": "Game Jams",
|
||||
"DESCRIPTION": "Dieser Bereich zeigt einige meiner bisherigen Game-Jam-Beiträge. Game Jams sind eine großartige Möglichkeit, neue Spielideen auszuprobieren und schnell zu überprüfen, ob ein Game-Loop funktioniert. Die engen Zeitvorgaben fördern den Fokus, es ist faszinierend, was man in so kurzer Zeit alles schaffen kann.",
|
||||
"LINK_EXTERNAL": "Itch.io Sammlung",
|
||||
"LINK_INTERNAL": "Projektdetails",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Planung eines realistischen Projektumfangs mit einem Team, der innerhalb von 48 Stunden umsetzbar ist.",
|
||||
"P2": "Lernen, fokussiert und effizient unter strengen Zeitvorgaben zu arbeiten.",
|
||||
"P3": "Die Freude zu erleben, in kurzer Zeit ein spielbares Projekt zu erstellen und andere damit spielen zu sehen."
|
||||
}
|
||||
}
|
||||
},
|
||||
"EDUCATION": {
|
||||
"E6": {
|
||||
"WHERE": "FH Bingen (University of Applied Sciences)",
|
||||
"WHEN": "2006 - 2010",
|
||||
"WHAT": "Diplom (FH), Angewandte Informatik (Schnitt 1.4)"
|
||||
},
|
||||
"E5": {
|
||||
"WHERE": "FH Koblenz (University of Applied Sciences)",
|
||||
"WHEN": "2005 - 2006",
|
||||
"WHAT": "1 Semester Ingenieurinformatik"
|
||||
},
|
||||
"E4": {
|
||||
"WHERE": "BBS Montabaur",
|
||||
"WHEN": "2002 - 2005",
|
||||
"WHAT": "Ausbildung zum Fachinformatiker Anwendungsentwicklung"
|
||||
},
|
||||
"E3": {
|
||||
"WHERE": "BBS Andernach - Höhere Berufsbachschule (Informatik)",
|
||||
"WHEN": "2000 - 2002",
|
||||
"WHAT": "Fachhochschulreife"
|
||||
},
|
||||
"E2": {
|
||||
"WHERE": "BBS Andernach - Berufsfachschule Technik (E-Technik)",
|
||||
"WHEN": "1998 - 2000",
|
||||
"WHAT": "Realschulabschluss"
|
||||
},
|
||||
"E1": {
|
||||
"WHERE": "Hauptschule Hinter Burg Mayen (Albert Schweitzer Realschule plus)",
|
||||
"WHEN": "1995 - 1998 ",
|
||||
"WHAT": "Hauptschulabschluss"
|
||||
},
|
||||
"E0": {
|
||||
"WHERE": "Albert Schweitzer Realschule Mayen",
|
||||
"WHEN": "1993 - 1995",
|
||||
"WHAT": "Kein Abschluss. Wechsel zur Hauptschule"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+205
-9
@@ -1,13 +1,209 @@
|
||||
{
|
||||
"APP": { "TITLE": "Playground" },
|
||||
"WELCOME": {
|
||||
"TITLE": "Welcome 👋",
|
||||
"SUB": "Angular 20 + Material",
|
||||
"TEXT": "This is a simple start component.",
|
||||
"COUNTER": "Counter",
|
||||
"INC": "Increment",
|
||||
"RESET": "Reset"
|
||||
"APP": {
|
||||
"TITLE": "Playground",
|
||||
"COPYRIGHT": "Images protected by copyright, no use without permission!"
|
||||
},
|
||||
"TOPBAR": {
|
||||
"ABOUT": "About me",
|
||||
"CONTACT": "Contact",
|
||||
"PROJECTS": "Projects",
|
||||
"HOBBY": "Hobby's",
|
||||
"SETTINGS": "Settings",
|
||||
"LANGUAGE": "Language",
|
||||
"APPEARANCE": "Appearance"
|
||||
},
|
||||
"THEME": { "LIGHT": "Light", "DARK": "Dark" },
|
||||
"LANG": { "LABEL": "Language", "EN": "English", "DE": "Deutsch" }
|
||||
"LANG": { "LABEL": "Language", "EN": "English", "DE": "Deutsch" },
|
||||
"ABOUT": {
|
||||
"ALT": { "PROFILE": "Profile photo of Andreas Dahm" },
|
||||
"HELLO": "Hello, I’m Andreas Dahm.",
|
||||
"LEAD": "During my training as an application developer, I became fascinated by how complex problems can be solved elegantly through code. After studying Applied Computer Science at FH Bingen, I was able to deepen this passion in a wide variety of projects – from 3D simulations to modern web applications. Today, I work as a Senior Software Developer and Architect with a focus on Java, Angular, and DevOps. Thanks for stopping by!",
|
||||
"ROLE": "Senior Software Developer / Full-Stack Developer / Software Architect",
|
||||
"LOCATION": "Munich · Remote",
|
||||
"DOWNLOAD_CV": "Download CV",
|
||||
"VIEW_PROJECTS": "View projects",
|
||||
"CONTACT_ME": "Contact me",
|
||||
"SECTION": {
|
||||
"SKILLS": "Skills & Stack",
|
||||
"PRIMARY": "Core",
|
||||
"TOOLSET": "Toolset",
|
||||
"EXPERIENCE": "Experience",
|
||||
"PROJECTS": "Projects",
|
||||
"EDUCATION": "Education"
|
||||
},
|
||||
"SKILLS": {
|
||||
"JAVA": "Java 8/Java 21+",
|
||||
"SPRING": "Spring Boot 2/3",
|
||||
"ANGULAR": "Angular 20+",
|
||||
"DOCKER": "Docker",
|
||||
"UNITY": "Unity",
|
||||
"PYTHON": "Python",
|
||||
"CSHARP": "C#",
|
||||
"TYPESCRIPT": "TypeScript"
|
||||
},
|
||||
"TOOLS": {
|
||||
"GIT": "Git",
|
||||
"GITHUB": "Github",
|
||||
"GITLAB": "Gitlab",
|
||||
"JENKINS": "Jenkins",
|
||||
"K8S": "Kubernetes / k3d",
|
||||
"POSTGRES": "PostgreSQL",
|
||||
"MONGO": "MongoDB",
|
||||
"GRAFANA": "Grafana/Prometheus"
|
||||
},
|
||||
"XP": {
|
||||
"COMPANY8": {
|
||||
"COMPANY": "Teraport GmbH",
|
||||
"ROLE": "Senior Software Developer / Architect",
|
||||
"TIME": "Feb. 2024 – now",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Architecture and implementation of database connectivity using Hibernate 6.x.",
|
||||
"P2": "Design and development of a full-stack web application for collision analysis (Angular + Spring Boot + Docker).",
|
||||
"P3": "Development of a cost analysis tool called MIDO."
|
||||
}
|
||||
},
|
||||
"COMPANY7": {
|
||||
"COMPANY": "ColorDigital GmbH",
|
||||
"ROLE": "Lead Software Developer",
|
||||
"TIME": "Mar. 2023 – Dec. 2023",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Planning a new cloud architecture to migrate a large legacy monolith to a modern microservice-based platform.",
|
||||
"P2": "Led the development team of three to four backend engineers.",
|
||||
"P3": "Collaborated with partners and customers on integrating their systems with the DMIx."
|
||||
}
|
||||
},
|
||||
"COMPANY6": {
|
||||
"COMPANY": "ColorDigital GmbH",
|
||||
"ROLE": "Senior Software Developer",
|
||||
"TIME": "Mar. 2021 – Mar. 2023",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Worked on the DMIx core cloud, including the implementation of an Elasticsearch-based real-time search module.",
|
||||
"P2": "Implementation of a new browser tool called 'Moodboard' (Node.js + Vue.js).",
|
||||
"P3": "Development of 'PAX', a tool for data exchange between the DMIx cloud and customer PLM/ERP systems, including CI/CD integration."
|
||||
}
|
||||
},
|
||||
"COMPANY5": {
|
||||
"COMPANY": "Assyst GmbH",
|
||||
"ROLE": "Team leadership",
|
||||
"TIME": "Sep. 2015 – Feb. 2021",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Team lead of the Vidya software department, including disciplinary responsibility and interviews.",
|
||||
"P2": "Led several projects with external partners and freelancers.",
|
||||
"P3": "Managed strategic initiatives in 3D software development."
|
||||
}
|
||||
},
|
||||
"COMPANY4": {
|
||||
"COMPANY": "Assyst GmbH",
|
||||
"ROLE": "Software engineer",
|
||||
"TIME": "Apr. 2010 – Feb. 2021",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Worked on core technologies such as algorithms, simulation, rendering, and collision detection.",
|
||||
"P2": "Used technologies including Java, OpenCL, OpenGL, GLSL shaders, C++, and REST interfaces.",
|
||||
"P3": "Participated in national and international research projects (EU7 and ZIM)."
|
||||
}
|
||||
},
|
||||
"COMPANY3": {
|
||||
"COMPANY": "Assyst GmbH",
|
||||
"ROLE": "Internship and Diploma",
|
||||
"TIME": "Apr. 2009 – Apr. 2010",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Implemented production features in the real-time cloth simulation software Vidya.",
|
||||
"P2": "Conducted research and literature review for the diploma thesis.",
|
||||
"P3": "Successfully implemented the diploma topic in Vidya."
|
||||
}
|
||||
},
|
||||
"COMPANY2": {
|
||||
"COMPANY": "TH Bingen (University of Applied Sciences)",
|
||||
"ROLE": "Tutorial for fundamentals of Java programming",
|
||||
"TIME": "Apr. 2008 – Aug. 2008",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Preparation of practical and theoretical course material.",
|
||||
"P2": "Held a 20-hour lecture series for the bioinformatics programme.",
|
||||
"P3": "Provided assistance during practical programming exercises."
|
||||
}
|
||||
},
|
||||
"COMPANY1": {
|
||||
"COMPANY": "TH Bingen (University of Applied Sciences)",
|
||||
"ROLE": "Research Asssitent",
|
||||
"TIME": "Oct. 2007 – Apr. 2008",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Evaluation of various Web 2.0 technologies.",
|
||||
"P2": "Implementation of a Java-based interface for Microsoft Excel.",
|
||||
"P3": "Integration of the MIT Exhibit framework and preparation for CeBIT 2008."
|
||||
}
|
||||
}
|
||||
},
|
||||
"PROJECT": {
|
||||
"P2": {
|
||||
"TITLE": "Playground",
|
||||
"DESCRIPTION": "This project is, as the name suggests, a personal playground that will grow over time. It showcases various private projects I’m working on and documents their progress, key ideas, and milestones.",
|
||||
"LINK_EXTERNAL": "andreas-dahm.eu",
|
||||
"LINK_INTERNAL": "Project details",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Using modern technologies and CI/CD pipelines (Angular 20+, Spring Boot 4, GitHub).",
|
||||
"P2": "Showcasing personal projects and improving algorithmic skills over time.",
|
||||
"P3": "Deepening knowledge in JavaScript/TypeScript, Angular, Spring Boot and related technologies through hands-on practice."
|
||||
}
|
||||
},
|
||||
"P1": {
|
||||
"TITLE": "El Mucho",
|
||||
"DESCRIPTION": "This is my first published game on Steam. I developed it together with my brother, fulfilling one of my personal goals: creating and releasing my own video game.",
|
||||
"LINK_EXTERNAL": "Steam Store",
|
||||
"LINK_INTERNAL": "Project details",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Publishing a game on Steam and integrating the Steam API.",
|
||||
"P2": "Designing, planning and developing a complete game from scratch.",
|
||||
"P3": "Implementing complex algorithms, including a custom A* pathfinding system and game AI logic."
|
||||
}
|
||||
},
|
||||
"P0": {
|
||||
"TITLE": "Game Jams",
|
||||
"DESCRIPTION": "This section showcases several of my past game jam creations. Game jams are a great way to explore new game ideas and quickly validate whether a game loop works. The tight time constraints force you to focus, and it’s always exciting to see what can be achieved within such a short timeframe.",
|
||||
"LINK_EXTERNAL": "Itch.io Collection",
|
||||
"LINK_INTERNAL": "Project details",
|
||||
"HIGHLIGHTS": {
|
||||
"P1": "Planning a realistic project scope with a team that can be built within 48 hours.",
|
||||
"P2": "Learning to stay focused and work effectively under strict time constraints.",
|
||||
"P3": "Experiencing the joy of creating a playable game in a short timeframe and seeing others enjoy it."
|
||||
}
|
||||
}
|
||||
},
|
||||
"EDUCATION": {
|
||||
"E6": {
|
||||
"WHERE": "FH Bingen (University of Applied Sciences)",
|
||||
"WHEN": "2006 – 2010",
|
||||
"WHAT": "Diploma (FH), Applied Computer Science (final grade 1.4)"
|
||||
},
|
||||
"E5": {
|
||||
"WHERE": "FH Koblenz (University of Applied Sciences)",
|
||||
"WHEN": "2005 – 2006",
|
||||
"WHAT": "1 semester of Engineering Informatics"
|
||||
},
|
||||
"E4": {
|
||||
"WHERE": "BBS Montabaur",
|
||||
"WHEN": "2002 – 2005",
|
||||
"WHAT": "Apprenticeship as IT Specialist for Application Development"
|
||||
},
|
||||
"E3": {
|
||||
"WHERE": "BBS Andernach – Higher Vocational School (Computer Science)",
|
||||
"WHEN": "2000 – 2002",
|
||||
"WHAT": "University entrance qualification (Fachhochschulreife)"
|
||||
},
|
||||
"E2": {
|
||||
"WHERE": "BBS Andernach – Vocational School for Technology (Electrical Engineering)",
|
||||
"WHEN": "1998 – 2000",
|
||||
"WHAT": "Secondary school certificate (Realschulabschluss)"
|
||||
},
|
||||
"E1": {
|
||||
"WHERE": "Hauptschule Hinter Burg Mayen (Albert Schweitzer Realschule Plus)",
|
||||
"WHEN": "1995 – 1998",
|
||||
"WHAT": "Lower secondary school certificate (Hauptschulabschluss)"
|
||||
},
|
||||
"E0": {
|
||||
"WHERE": "Albert Schweitzer Realschule Mayen",
|
||||
"WHEN": "1993 – 1995",
|
||||
"WHAT": "No degree (transferred to lower secondary school)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg width="167" height="56" viewBox="0 0 167 56" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<g clip-path="url(#clip0_1140_148)">
|
||||
<path d="M126.544 13.3578H166.645L161.975 0.308258L126.544 13.3578Z" fill="white" />
|
||||
<path
|
||||
d="M9.2383 53.3798C8.37538 53.3798 8.07082 52.7633 8.07082 51.7871V48.4991H6.9541V52.1468C6.9541 53.6881 7.81702 54.3046 9.2383 54.3046C10.6596 54.3046 11.5225 53.6881 11.5225 52.1468V48.4991H10.4058V51.7871C10.4058 52.7633 10.1012 53.3798 9.2383 53.3798ZM12.7915 49.989V54.2018H13.8574V52.1468C13.8574 51.633 14.0097 50.7596 14.8219 50.7596C15.5325 50.7596 15.5325 51.4789 15.5325 51.9926V54.2532H16.5985V51.5816C16.5985 50.6569 16.1924 49.9376 15.1772 49.9376C14.6188 49.9376 14.162 50.1431 13.8067 50.6055V50.0404H12.7915V49.989ZM17.8167 49.989H18.8827V54.2018H17.8167V49.989ZM17.8167 48.1394H18.8827V49.167H17.8167V48.1394ZM23.9079 49.989H22.7912L21.8267 53.0202H21.776L20.7608 49.989H19.5933L21.1669 54.2018H22.3851L23.9079 49.989ZM26.1413 49.8862C24.8723 49.8862 24.2125 50.9137 24.2125 52.0954C24.2125 53.4826 25.0246 54.2532 26.3951 54.2532C26.9535 54.2532 27.4103 54.1504 27.8164 53.8936V53.0202C27.4103 53.2257 26.9535 53.4312 26.4459 53.4312C25.786 53.4312 25.3292 53.0715 25.2784 52.3523H28.1717C28.121 50.9651 27.7149 49.8862 26.1413 49.8862ZM25.2784 51.6844C25.3292 51.1193 25.6337 50.7082 26.2429 50.7082C26.852 50.7082 27.1058 51.1706 27.1058 51.6844H25.2784ZM29.0854 49.989V54.2018H30.1514V52.6605C30.1514 52.044 30.1514 50.9651 31.0143 50.9651C31.2173 50.9651 31.4204 51.0165 31.5219 51.0679V49.989C31.4204 49.9376 31.3188 49.9376 31.1666 49.9376C30.5067 49.9376 30.1006 50.6055 30.0498 51.0165V50.0404H29.0854V49.989ZM33.9076 50.6569C34.3137 50.6569 34.5675 50.7082 34.872 50.8624L34.9228 50.0404C34.5675 49.989 34.2629 49.8862 33.7553 49.8862C32.8924 49.8862 32.131 50.2972 32.131 51.1706C32.131 52.7119 34.0091 52.1468 34.0091 52.9688C34.0091 53.3798 33.5523 53.4826 33.2985 53.4826C32.9432 53.4826 32.5878 53.3798 32.2325 53.2257L32.1818 54.1504C32.5878 54.2532 32.9939 54.3046 33.4 54.3046C34.2629 54.3046 35.1258 53.8936 35.1258 52.9174C35.1258 51.3761 33.2477 51.8385 33.2477 51.1706C33.2477 50.811 33.603 50.6569 33.9076 50.6569ZM36.0903 49.989H37.1562V54.2018H36.0903V49.989ZM36.0903 48.1394H37.1562V49.167H36.0903V48.1394Z"
|
||||
fill="white" />
|
||||
<path
|
||||
d="M38.679 52.9174C38.679 53.7394 39.1359 54.3046 39.9988 54.3046C40.3034 54.3046 40.5572 54.2532 40.811 54.2018L40.7602 53.3284C40.6587 53.3798 40.4556 53.4312 40.2526 53.4312C39.8465 53.4312 39.745 53.0715 39.745 52.7119V50.7596H40.7094V49.9376H39.745V48.756L38.679 49.1156V49.9376H37.8669V50.7596H38.679V52.9174ZM44.0088 54.1504L45.5824 49.989H44.4657L43.4505 53.0715L42.4353 49.989H41.217L42.7906 54.4073C42.7906 54.8697 42.5368 55.178 42.08 55.178C41.8262 55.178 41.6739 55.178 41.5216 55.1266L41.4708 55.9486C41.5724 56 41.7246 56 41.8262 56.0514H42.486C43.4505 55.8459 43.7043 54.9725 44.0088 54.1504Z"
|
||||
fill="white" />
|
||||
<path
|
||||
d="M48.1711 52.0954C48.1711 53.3284 48.9833 54.2532 50.3538 54.2532C51.7243 54.2532 52.5365 53.2771 52.5365 52.0954C52.5365 50.7083 51.572 49.8862 50.3538 49.8862C49.1356 49.8862 48.1711 50.7083 48.1711 52.0954ZM51.4198 51.9927C51.4198 52.7119 51.2167 53.4312 50.3538 53.4312C49.5416 53.4312 49.2878 52.6606 49.2878 51.9927C49.2878 51.3761 49.6432 50.7596 50.3538 50.7596C51.0644 50.7083 51.4198 51.3248 51.4198 51.9927ZM55.379 48.8073C55.6328 48.8073 55.7343 48.9101 55.8359 48.9615L55.9374 48.0367C55.7343 47.9853 55.4298 47.9339 55.1252 47.9339C54.2623 47.9339 53.8055 48.4991 53.8055 49.3725V49.9376H52.9933V50.7596H53.8055V54.1505H54.8714V50.7596H55.8359V49.9376H54.8714V49.4239C54.9222 49.1156 55.0237 48.8073 55.379 48.8073ZM60.5058 48.4991L58.3231 54.2018H59.4906L59.9982 52.9174H62.2824L62.79 54.2018H64.059L61.8255 48.4991H60.5058ZM60.3027 51.9927L61.1149 49.6294L61.9271 51.9927H60.3027ZM64.7696 49.989V55.8973H65.8356V53.6881C66.1909 54.1505 66.597 54.2532 67.0538 54.2532C68.3736 54.2532 68.8304 53.1743 68.8304 52.044C68.8304 50.8624 68.3736 49.8349 67.1046 49.8349C66.4447 49.8349 66.0386 50.1431 65.8356 50.5541V49.9376H64.7696V49.989ZM66.8508 50.7083C67.5614 50.7083 67.7644 51.4789 67.7644 52.044C67.7644 52.6092 67.5614 53.4312 66.8508 53.4312C66.1401 53.4312 65.8863 52.6606 65.8863 52.044C65.8356 51.4789 66.1401 50.7083 66.8508 50.7083ZM72.1298 54.3046C73.4496 54.3046 73.9064 53.2257 73.9064 52.0954C73.9064 50.9138 73.4495 49.8862 72.1805 49.8862C71.5207 49.8862 71.1146 50.1945 70.9116 50.6055V49.989H69.8964V55.8973H70.9623V53.6881C71.2669 54.1505 71.673 54.3046 72.1298 54.3046ZM71.876 50.7083C72.5866 50.7083 72.7897 51.4789 72.7897 52.044C72.7897 52.6092 72.5866 53.4312 71.876 53.4312C71.1654 53.4312 70.9116 52.6606 70.9116 52.044C70.9116 51.4789 71.1654 50.7083 71.876 50.7083ZM74.8708 48.0367V54.2018H75.9368V48.0367H74.8708ZM77.155 49.989H78.221V54.2018H77.155V49.989ZM77.155 48.1395H78.221V49.167H77.155V48.1395ZM81.1143 49.8862C79.8453 49.8862 79.1854 50.9138 79.1854 52.0954C79.1854 53.4826 79.9976 54.2532 81.3681 54.2532C81.9265 54.2532 82.3833 54.1505 82.7894 53.8936V53.0202C82.3833 53.2257 81.9264 53.4312 81.4188 53.4312C80.759 53.4312 80.3021 53.0716 80.2514 52.3523H83.1447C83.0939 50.9651 82.6879 49.8862 81.1143 49.8862ZM80.2514 51.6844C80.3021 51.1193 80.6067 50.7083 81.2158 50.7083C81.8249 50.7083 82.0787 51.1706 82.0787 51.6844H80.2514ZM87.9161 54.2018V48.0881H86.7994V50.5028C86.4948 50.0917 86.0888 49.9376 85.5812 49.9376C84.3122 49.9376 83.8553 50.9651 83.8553 52.1468C83.8553 53.2771 84.3122 54.356 85.5812 54.356C86.0888 54.356 86.5456 54.2018 86.8502 53.7908V54.2532H87.9161V54.2018ZM85.8857 53.4312C85.1751 53.4312 84.972 52.6606 84.972 52.044C84.972 51.4789 85.1751 50.7083 85.8857 50.7083C86.5964 50.7083 86.8502 51.4789 86.8502 52.044C86.7994 52.6606 86.5964 53.4312 85.8857 53.4312ZM92.6368 53.3798C92.1799 53.3798 91.7231 53.2257 91.3678 53.0202L91.2663 54.0477C91.8246 54.2018 92.0784 54.2532 92.6875 54.2532C93.8043 54.2532 94.8195 53.7908 94.8195 52.5064C94.8195 50.6055 92.3322 51.0165 92.3322 50.0404C92.3322 49.4239 92.8398 49.2697 93.1951 49.2697C93.6012 49.2697 94.0073 49.3725 94.3626 49.5266L94.4641 48.6018C94.0581 48.4477 93.6012 48.3963 93.0936 48.3963C92.0784 48.3963 91.114 48.8587 91.114 50.1431C91.114 52.044 93.6012 51.5817 93.6012 52.6606C93.652 53.1743 93.0936 53.3798 92.6368 53.3798ZM97.8143 50.7083C98.1696 50.7083 98.3727 50.7596 98.5249 50.8624L98.6264 49.989C98.3219 49.8862 98.0173 49.8349 97.5605 49.8349C96.2407 49.8349 95.5301 50.811 95.5301 51.9927C95.5301 53.2771 96.2407 54.2018 97.5605 54.2018C98.0173 54.2018 98.3219 54.1505 98.6264 54.0477L98.5757 53.1229C98.3727 53.2257 98.0681 53.3284 97.7635 53.3284C97.0021 53.3284 96.6468 52.7119 96.6468 51.9413C96.6976 51.2734 97.1544 50.7083 97.8143 50.7083ZM99.5909 49.989H100.657V54.2018H99.5909V49.989ZM99.5909 48.1395H100.657V49.167H99.5909V48.1395ZM103.55 49.8862C102.281 49.8862 101.621 50.9138 101.621 52.0954C101.621 53.4826 102.433 54.2532 103.804 54.2532C104.362 54.2532 104.819 54.1505 105.225 53.8936V53.0202C104.819 53.2257 104.362 53.4312 103.855 53.4312C103.195 53.4312 102.738 53.0716 102.687 52.3523H105.581C105.53 50.9651 105.073 49.8862 103.55 49.8862ZM102.636 51.6844C102.687 51.1193 102.992 50.7083 103.601 50.7083C104.21 50.7083 104.464 51.1706 104.464 51.6844H102.636ZM110.301 54.2018V51.5303C110.301 50.6055 109.895 49.8862 108.88 49.8862C108.322 49.8862 107.865 50.0917 107.509 50.5541V49.989H106.494V54.2018H107.56V52.1468C107.56 51.633 107.712 50.7596 108.525 50.7596C109.235 50.7596 109.235 51.4789 109.235 51.9927V54.2532H110.301V54.2018ZM113.448 50.7083C113.804 50.7083 114.007 50.7596 114.159 50.8624L114.26 49.989C113.956 49.8862 113.651 49.8349 113.195 49.8349C111.875 49.8349 111.164 50.811 111.164 51.9927C111.164 53.2771 111.875 54.2018 113.195 54.2018C113.651 54.2018 113.956 54.1505 114.26 54.0477L114.21 53.1229C114.007 53.2257 113.702 53.3284 113.398 53.3284C112.636 53.3284 112.281 52.7119 112.281 51.94Line truncated
|
||||
fill="white" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1140_148">
|
||||
<rect width="167" height="56" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Konstruktion_Kopie" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
|
||||
y="0px" viewBox="0 0 216 120" style="enable-background:new 0 0 216 120;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#58585A;}
|
||||
.st1{fill:#007CBF;}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M0.8,108.8V108c0-6.7,3.5-10.6,8.1-10.6c2,0,3.5,0.7,5,2l-2,3.4c-0.7-0.7-1.6-1.5-2.9-1.5c-2.3,0-4,2.6-4,7
|
||||
v0.3c0,4.5,1.6,7,4.1,6.9c1.3,0,2.1-0.7,2.9-1.6l2,3.1c-1.2,1.4-3,2.3-5.3,2.3C4,119.3,0.8,115.5,0.8,108.8z"/>
|
||||
<path class="st0" d="M16.7,90.5h4.1v10.2c1-1.8,2.4-3.3,4.9-3.3c3.3,0,5.3,2.5,5.3,6.6v15h-4.1v-13.9c0-2.6-1.1-4-2.9-4
|
||||
s-3.1,1.5-3.1,4v13.8h-4.1V90.5z"/>
|
||||
<path class="st0" d="M33.9,112.9v-0.4c0-4.5,2.5-6.8,6.2-6.8c1.5,0,2.7,0.4,3.9,0.8v-1.3c0-2.7-1.5-4-3.8-4c-1.7,0-3.2,0.8-4,1.3
|
||||
l-1.3-3.4c1.7-0.9,3.6-1.6,5.9-1.6c2.3,0,4.1,0.7,5.3,1.9c1.3,1.3,2,3.2,2,5.7v13.8H44v-2.5c-1,1.8-2.6,2.9-4.7,2.9
|
||||
C36.2,119.3,33.9,116.9,33.9,112.9z M44,112.4v-2.9c-0.8-0.4-1.9-0.6-2.9-0.6c-2,0-3.1,1.4-3.1,3.6v0.2c0,2.2,1.1,3.4,2.7,3.5
|
||||
C42.5,116.1,44,114.4,44,112.4z"/>
|
||||
<path class="st0" d="M51.9,97.7h4.1v2.9c1-1.9,2.5-3.3,4.8-3.3c2.1,0,3.7,1.1,4.6,3c1.1-1.6,2.6-3,5.1-3c3.1,0,5.4,2.2,5.4,6.6v15
|
||||
h-4.1v-13.8c0-2.7-1-4-2.8-4c-1.8,0-3,1.5-3,4.1v13.8h-4.2v-13.8c0-2.7-1-4-2.7-4c-1.8,0-3,1.6-3,4.1v13.8h-4.1V97.7z"/>
|
||||
<path class="st0" d="M78.9,112.9v-0.4c0-4.5,2.5-6.8,6.2-6.8c1.5,0,2.7,0.4,3.9,0.8v-1.3c0-2.7-1.5-4-3.8-4c-1.7,0-3.2,0.8-4,1.3
|
||||
l-1.3-3.4c1.7-0.9,3.6-1.6,5.9-1.6c2.3,0,4.1,0.7,5.3,1.9c1.3,1.3,2,3.2,2,5.7v13.8H89v-2.5c-1,1.8-2.6,2.9-4.7,2.9
|
||||
C81.3,119.3,78.9,116.9,78.9,112.9z M89,112.4v-2.9c-0.8-0.4-1.9-0.6-2.9-0.6c-2,0-3.1,1.4-3.1,3.6v0.2c0,2.2,1.1,3.4,2.7,3.5
|
||||
C87.5,116.1,89,114.4,89,112.4z"/>
|
||||
<path class="st0" d="M96.2,108.7v-0.6c0-6.7,3.3-10.8,7.6-10.8c4.7,0,7.3,4.2,7.3,10.8c0,0.2,0,1,0,1.9h-10.7
|
||||
c0.3,3.7,2.2,5.6,4.6,5.6c1.6,0,2.8-0.9,3.9-2l1.9,3.1c-1.8,1.6-3.7,2.5-6.1,2.5C99.9,119.3,96.2,115.5,96.2,108.7z M107.1,107
|
||||
c-0.1-3.6-1.3-6.1-3.3-6.1c-1.9,0-3.3,2.2-3.5,6.1H107.1z"/>
|
||||
<path class="st0" d="M114.4,90.5h4.1v28.4h-4.1V90.5z"/>
|
||||
<path class="st0" d="M122,108.7v-0.6c0-6.7,3.3-10.8,7.6-10.8c4.7,0,7.3,4.2,7.3,10.8c0,0.2,0,1,0,1.9h-10.7
|
||||
c0.3,3.7,2.2,5.6,4.6,5.6c1.6,0,2.8-0.9,3.9-2l1.9,3.1c-1.8,1.6-3.7,2.5-6.1,2.5C125.8,119.3,122,115.5,122,108.7z M132.9,107
|
||||
c-0.1-3.6-1.3-6.1-3.3-6.1c-1.9,0-3.3,2.2-3.5,6.1H132.9z"/>
|
||||
<path class="st0" d="M139.4,108.7v-0.7c0-6.5,3.4-10.7,8-10.7c4.6,0,8,4.1,8,10.6v0.7c0,6.5-3.4,10.6-8,10.6
|
||||
C142.7,119.3,139.4,115.2,139.4,108.7z M151.2,108.6v-0.4c0-4.3-1.6-7.1-3.9-7.1c-2.3,0-3.9,2.8-3.9,7.1v0.4
|
||||
c0,4.3,1.6,7.1,3.9,7.1C149.7,115.7,151.2,112.8,151.2,108.6z"/>
|
||||
<path class="st0" d="M158.7,97.7h4.1v2.9c1-1.8,2.4-3.3,4.9-3.3c3.3,0,5.3,2.5,5.3,6.6v15h-4.1v-13.9c0-2.6-1.1-4-2.9-4
|
||||
s-3.1,1.5-3.1,4v13.8h-4.1V97.7z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M189.3,96l-6.5,22.9h3.9l1.4-5.1h6.1l1.4,5.1h4.1L193.1,96H189.3z M193.2,110.2H189l2.1-7.7L193.2,110.2z"/>
|
||||
<path class="st0" d="M208.3,106.1v3.5h3.5v5.4c-0.5,0.3-1.3,0.5-2,0.5c-3.1,0-5.1-3-5.1-7.8v-0.4c0-4.6,2-7.7,5-7.7
|
||||
c1.3,0,2.4,0.5,3.3,1.5l0.2,0.2l2.2-3.3l-0.2-0.1c-1.6-1.4-3.4-2-5.6-2c-5.4,0-9,4.6-9,11.4v0.4c0,7,3.4,11.4,8.9,11.4
|
||||
c2,0,3.9-0.6,5.9-1.9l0.1-0.1v-11.1H208.3z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M92.2,50.7C93.8,33,107.1,18,125.4,14.9c21.7-3.6,42.3,11.1,45.9,32.8c0.2,1.3,0.4,2.6,0.5,4
|
||||
c0.4-5.3-0.4-9.6-0.4-9.6c-4.8-27-30.5-45.1-57.6-40.6C101.4,3.6,90.9,10,83.4,18.9c0.6-4.6,0.4-10.2-1.9-7.8
|
||||
c-3.2,3.3-13.2,6.4-16.5,7.1c0,0,0,0,0,0c-8.5,1.9-15.8,9-18.9,21.8c-3,12.1-14.5,20.2-14.6,20.3l0,0c7,8,26.7-3.2,26.9-3.3
|
||||
l0.9,1.8c-0.2,0.1-8.5,4.8-18.4,5.9c0,0,10.7,5.2,32-3.5c0,0,0,0,0,0c0,0,0.4-0.2,1.1-0.5c0.2-0.1,0.4-0.2,0.7-0.3c0,0,0,0,0,0
|
||||
C78.2,58.8,86.4,54.6,92.2,50.7z M64,40.9c-4.7,1.3-9.7-1.5-11-6.2c-1.3-4.7,1.5-9.7,6.2-11c4.7-1.3,9.7,1.5,11,6.2
|
||||
C71.5,34.6,68.7,39.6,64,40.9z"/>
|
||||
</g>
|
||||
<path class="st1" d="M89.3,21.2c-0.4-2.3-1-4.5-1.7-6.7c-1.5,1.4-2.9,2.9-4.2,4.4c0.6-4.6,0.4-10.2-1.9-7.8
|
||||
c-3.2,3.3-13.2,6.4-16.5,7.1c0,0,0,0,0,0c-8.5,1.9-15.8,9-18.9,21.8c-3,12.1-14.5,20.2-14.6,20.3l0,0c7,8,26.7-3.2,26.9-3.3l0.9,1.8
|
||||
c-0.2,0.1-8.5,4.8-18.4,5.9c0,0,0.7,0.3,1.9,0.7c2.7,0.6,5.4,0.9,8.2,0.9c2.5,0,5.5-0.3,8.9-1C79.7,60.7,92.7,41.5,89.3,21.2z
|
||||
M53,34.6c-1.3-4.7,1.5-9.7,6.2-11c4.7-1.3,9.7,1.5,11,6.2c1.3,4.7-1.5,9.7-6.2,11C59.2,42.2,54.3,39.4,53,34.6z"/>
|
||||
<path class="st1" d="M65.7,35.7c1.5-0.4,2.3-1.6,2-3.5c-0.1-1-1.1-2.4-3.3-2.1c-2.2,0.4-2.1,2.2-1.8,3.5
|
||||
C62.9,34.8,64.2,36.1,65.7,35.7z"/>
|
||||
<path class="st1" d="M171.3,47.8c-3.6-21.7-24.2-36.4-45.9-32.8c-18.3,3-31.6,18.1-33.2,35.8c0.2-0.2,0.5-0.3,0.7-0.5
|
||||
c0.8,0.3,2.6,0.5,5,0.6c-0.1,1.5-0.8,4.2-4.1,6.4C92,58.5,91,59.4,89,59.9c-3.3,0.8-6.8,2.9-7.3,3.7c-0.5,0.8-0.4,1-0.1,1.5
|
||||
c0.5,0.6,1.3,1,5.6,0.6c2.9-0.2,4.8-0.6,5.4-0.6c0.6-0.1,0.7-0.7,0.9-1.4c0.9-3.4,15.2-6.8,16.2-10.8c0.2-0.7,0.2-1.5,0.2-2.2
|
||||
c4.4-0.2,9.2-0.7,13.9-1.2c-0.4,0.7-0.7,1.4-0.9,2.1c-0.9,3.1-0.1,6.7,0.7,9.1c-4.1,1.1-6.4,2.8-6.4,3.8c0,1,3.8,1.5,6.9,1.4
|
||||
c2.3-0.1,5.1-0.1,5.6-0.7c0.4-0.4,0.6-0.7,0.1-1.9c-0.3-0.6-1.7-4.1,0.5-8.1c1.7-3,2.8-3.8,9.6-7.1c2.4-1.2,4.5-2.1,6.4-2.9
|
||||
c3.1-0.5,6.5-0.6,9.2,0.4c3.6,1.3,5.5,3.8,6.2,7.9c0.8,4.3-2.6,9.3-6.6,9.9l-1-1.9c3.5-0.6,5.8-3.9,5.3-7.4c-0.6-3.9-3-6.9-8.8-6.6
|
||||
c-2.8,0.2-4.2,1-6.4,2.6c-10.7,9.1,0.6,24.8,12.4,21.9c11.5-2.9,14.6-12.7,15.1-20.2C171.6,50.4,171.5,49.1,171.3,47.8z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 105 KiB |
+2
-2
@@ -2,10 +2,10 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>PlaygroundFrontend</title>
|
||||
<title>Andreas Dahm - Playground</title>
|
||||
<base href="/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
<link rel="icon" type="image/x-icon" href="assets/favicon.ico">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined&display=swap" rel="stylesheet">
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
import { bootstrapApplication } from '@angular/platform-browser';
|
||||
import { appConfig } from './app/app.config';
|
||||
import { App } from './app/app';
|
||||
import packageJson from '../package.json';
|
||||
import {AppComponent} from './app/layout/app/app.component';
|
||||
|
||||
if (packageJson.version) {
|
||||
console.log(`🌟 Frontend version: ${packageJson.version}`);
|
||||
}
|
||||
|
||||
bootstrapApplication(App, appConfig)
|
||||
bootstrapApplication(AppComponent, appConfig)
|
||||
.catch((err) => console.error(err));
|
||||
@@ -26,11 +26,17 @@ $dark-theme: mat.define-theme((
|
||||
--app-bg: #{mat.get-theme-color($light-theme, surface-container-low)};
|
||||
--app-fg: #{mat.get-theme-color($light-theme, on-surface)};
|
||||
--app-card-background: #fafafa;
|
||||
--app-logo-bg: #313131;
|
||||
--link-color: #38a7ff;
|
||||
--link-color-hover: #66bfff;
|
||||
}
|
||||
.dark {
|
||||
--app-bg: #{mat.get-theme-color($dark-theme, surface-container-low)};
|
||||
--app-fg: #{mat.get-theme-color($dark-theme, on-surface)};
|
||||
--app-card-background: #313131;
|
||||
--app-logo-bg: #313131;
|
||||
--link-color: #6dbcff;
|
||||
--link-color-hover: #9ad2ff;
|
||||
}
|
||||
|
||||
/* ---- global background and tests ---- */
|
||||
@@ -67,3 +73,15 @@ body {
|
||||
box-shadow 220ms ease,
|
||||
fill 220ms ease;
|
||||
}
|
||||
|
||||
/* links */
|
||||
a {
|
||||
color: var(--link-color);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
|
||||
&:hover {
|
||||
color: var(--link-color-hover);
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user