Add complete bewerbung Next.js application
- Add all Next.js application files - Include components, app structure, and public assets - Remove empty bewerbung placeholder folder - Update .gitignore for Next.js project 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
No files matched your search
@@ -1,23 +1,41 @@
|
|||||||
# macOS
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.*
|
||||||
|
.yarn/*
|
||||||
|
!.yarn/patches
|
||||||
|
!.yarn/plugins
|
||||||
|
!.yarn/releases
|
||||||
|
!.yarn/versions
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# next.js
|
||||||
|
/.next/
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.AppleDouble
|
*.pem
|
||||||
.LSOverride
|
|
||||||
|
|
||||||
# Thumbnails
|
# debug
|
||||||
._*
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
.pnpm-debug.log*
|
||||||
|
|
||||||
# Files that might appear in the root of a volume
|
# env files (can opt-in for committing if needed)
|
||||||
.DocumentRevisions-V100
|
.env*
|
||||||
.fseventsd
|
|
||||||
.Spotlight-V100
|
|
||||||
.TemporaryItems
|
|
||||||
.Trashes
|
|
||||||
.VolumeIcon.icns
|
|
||||||
.com.apple.timemachine.donotpresent
|
|
||||||
|
|
||||||
# Directories potentially created on remote AFP share
|
# vercel
|
||||||
.AppleDB
|
.vercel
|
||||||
.AppleDesktop
|
|
||||||
Network Trash Folder
|
# typescript
|
||||||
Temporary Items
|
*.tsbuildinfo
|
||||||
.apdisk
|
next-env.d.ts
|
||||||
@@ -0,0 +1,186 @@
|
|||||||
|
# 🗂️ Ungenutzte Dateien - Backup & Cleanup
|
||||||
|
|
||||||
|
## 📋 Übersicht
|
||||||
|
|
||||||
|
Dieses Dokument listet alle ungenutzten Dateien auf, die sicher in einen Backup-Ordner verschoben werden können.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📁 Downloads (/public/downloads/)
|
||||||
|
|
||||||
|
### ✅ **AKTIV - Werden verwendet:**
|
||||||
|
```
|
||||||
|
✓ Lebenslauf_2025.pdf → page.tsx
|
||||||
|
✓ Zeugnisse_2025.pdf → page.tsx
|
||||||
|
✓ Referenzen.pdf → page.tsx
|
||||||
|
```
|
||||||
|
|
||||||
|
### ❌ **INAKTIV - Können verschoben werden:**
|
||||||
|
```
|
||||||
|
✗ Lebenslauf2020.pdf → Veraltet (ersetzt durch _2025)
|
||||||
|
✗ Zeugnisse.pdf → Veraltet (ersetzt durch _2025)
|
||||||
|
✗ Bewerbungsmappe 2014...pdf → Sehr alt
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖼️ Bilder (/public/img/)
|
||||||
|
|
||||||
|
### ✅ **AKTIV - Werden verwendet:**
|
||||||
|
```
|
||||||
|
Hero Section:
|
||||||
|
✓ bg-ich-2025-background.jpg → Hero.tsx
|
||||||
|
✓ bg-ich-2025-foreground.png → Hero.tsx
|
||||||
|
|
||||||
|
Download Sections:
|
||||||
|
✓ bg-lebenslauf.jpg → page.tsx
|
||||||
|
✓ bg-arbeitszeugnisse.jpg → page.tsx
|
||||||
|
✓ keyboard-bg.jpg → page.tsx
|
||||||
|
|
||||||
|
Portfolio (Web):
|
||||||
|
✓ Referenz - e-stev -Web.jpg → Portfolio.tsx
|
||||||
|
✓ Referenz---Planet-Touristik---web.jpg → Portfolio.tsx
|
||||||
|
✓ Referenz---handstaubsauger---web.jpg → Portfolio.tsx
|
||||||
|
|
||||||
|
Portfolio (Print):
|
||||||
|
✓ Referenz---Illy---Print.jpg → Portfolio.tsx
|
||||||
|
✓ Referenz---SZ---Print.jpg → Portfolio.tsx
|
||||||
|
✓ Referenz---Planet-Touristik---print.jpg → Portfolio.tsx
|
||||||
|
```
|
||||||
|
|
||||||
|
### ❌ **INAKTIV - Können verschoben werden:**
|
||||||
|
```
|
||||||
|
Alte Hero-Bilder:
|
||||||
|
✗ bg-ich-1.png → Alt
|
||||||
|
✗ bg-ich-2.png → Alt
|
||||||
|
✗ bg-ich-2025.jpg → Duplikat
|
||||||
|
✗ bg-ich-2025-foreground.jpg → Ersetzt durch .png
|
||||||
|
✗ workspace-bg.jpg → Nicht verwendet
|
||||||
|
|
||||||
|
Alte Icons:
|
||||||
|
✗ Workspace.png
|
||||||
|
✗ controls.png
|
||||||
|
✗ h1-bg.png
|
||||||
|
✗ icon-os.png
|
||||||
|
✗ icons-cms.png
|
||||||
|
✗ icons-gfx.png
|
||||||
|
✗ icons-marketing.png
|
||||||
|
✗ icons-office.png
|
||||||
|
✗ icons-os.png
|
||||||
|
✗ icons-web.png
|
||||||
|
|
||||||
|
Portfolio Duplikate:
|
||||||
|
✗ Referenz - Illy-sommerkarte07.png
|
||||||
|
✗ Referenz - Planet Touristik - Frontansicht.jpg
|
||||||
|
✗ Referenz - Planet-Touristik - web01.jpg
|
||||||
|
✗ Referenz---Illy---Außenansicht.jpg
|
||||||
|
✗ Referenz---Planet-Touristik---Frontansicht.jpg
|
||||||
|
✗ Referenz---SZ---Frontansicht.jpg
|
||||||
|
✗ Referenz---e-stev--Web2.jpg
|
||||||
|
✗ Referenz---handstaubsauger---web2.jpg
|
||||||
|
|
||||||
|
System-Dateien:
|
||||||
|
✗ .DS_Store (macOS)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Verwendung des Cleanup-Scripts
|
||||||
|
|
||||||
|
### 1. Script ausführbar machen:
|
||||||
|
```bash
|
||||||
|
chmod +x cleanup-unused-files.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Script ausführen:
|
||||||
|
```bash
|
||||||
|
./cleanup-unused-files.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Was passiert:
|
||||||
|
- ✅ Erstellt `public/_unused/downloads/` und `public/_unused/img/`
|
||||||
|
- ✅ Verschiebt alle ungenutzten Dateien dorthin
|
||||||
|
- ✅ Zeigt detaillierte Ausgabe was verschoben wurde
|
||||||
|
- ✅ **LÖSCHT NICHTS** - nur verschieben!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Test-Checkliste nach Cleanup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Development Server starten
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# 2. Prüfe diese Seiten/Funktionen:
|
||||||
|
□ Hero-Section lädt (beide Hintergrundbilder)
|
||||||
|
□ Download: Lebenslauf_2025.pdf funktioniert
|
||||||
|
□ Download: Zeugnisse_2025.pdf funktioniert
|
||||||
|
□ Download: Referenzen.pdf funktioniert
|
||||||
|
□ Portfolio: Alle 6 Projekt-Bilder werden angezeigt
|
||||||
|
□ Keine 404-Fehler in der Browser-Console
|
||||||
|
|
||||||
|
# 3. Production Build testen
|
||||||
|
npm run build
|
||||||
|
npx serve out
|
||||||
|
|
||||||
|
# 4. Prüfe erneut alle Downloads und Bilder
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Dateien wiederherstellen (falls nötig)
|
||||||
|
|
||||||
|
Falls nach dem Test etwas fehlt:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Einzelne Datei zurückkopieren:
|
||||||
|
cp public/_unused/downloads/DATEINAME.pdf public/downloads/
|
||||||
|
|
||||||
|
# Oder kompletten Ordner zurückkopieren:
|
||||||
|
cp -r public/_unused/* public/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🗑️ Endgültiges Löschen
|
||||||
|
|
||||||
|
**NUR nach erfolgreichem Test!**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Backup-Ordner komplett entfernen:
|
||||||
|
rm -rf public/_unused/
|
||||||
|
|
||||||
|
# Oder im Finder in den Papierkorb verschieben
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Speicherplatz-Ersparnis
|
||||||
|
|
||||||
|
### Vorher:
|
||||||
|
- Downloads: ~7 Dateien (~15-20 MB geschätzt)
|
||||||
|
- Images: ~35 Dateien (~10-15 MB geschätzt)
|
||||||
|
|
||||||
|
### Nachher:
|
||||||
|
- Downloads: 3 Dateien (aktuelle Versionen)
|
||||||
|
- Images: ~12 Dateien (nur verwendete)
|
||||||
|
|
||||||
|
**Geschätzte Ersparnis:** ~15-20 MB
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Notizen
|
||||||
|
|
||||||
|
- **Datum des Cleanups:** [Füge Datum ein]
|
||||||
|
- **Build vor Cleanup:** [Version/Tag]
|
||||||
|
- **Funktionstest:** [ ] Bestanden
|
||||||
|
- **Backup-Ordner gelöscht am:** [Datum]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🆘 Support
|
||||||
|
|
||||||
|
Falls Probleme auftreten:
|
||||||
|
1. Backup-Ordner `_unused/` ist noch da
|
||||||
|
2. Alle Dateien können wiederhergestellt werden
|
||||||
|
3. Git-History hat alte Versionen
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
# beWerbung 2025 - Moderne Bewerbungswebseite
|
||||||
|
|
||||||
|
Eine moderne, responsive Bewerbungswebseite mit **Next.js 15**, **React 19**, **Tailwind CSS 4** und **TypeScript**.
|
||||||
|
|
||||||
|
## 🚀 Features
|
||||||
|
|
||||||
|
- ✅ **Modern Stack**: Next.js 15 App Router, React 19, Tailwind CSS 4
|
||||||
|
- ✅ **TypeScript**: Vollständig typisiert
|
||||||
|
- ✅ **Responsive**: Mobile-first Design
|
||||||
|
- ✅ **Performance**: Optimiert mit Next.js Image, lazy loading
|
||||||
|
- ✅ **Animationen**: Smooth scroll, fade-in effects, hover animations
|
||||||
|
- ✅ **SEO**: Meta-Tags, strukturierte Daten
|
||||||
|
- ✅ **Accessibility**: ARIA-Labels, semantisches HTML
|
||||||
|
|
||||||
|
## 📦 Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Dependencies installieren
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Development Server starten
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# Production Build erstellen
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# Production Server starten
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
Die Webseite läuft dann auf [http://localhost:3000](http://localhost:3000)
|
||||||
|
|
||||||
|
## 🏗️ Projektstruktur
|
||||||
|
|
||||||
|
```
|
||||||
|
bewerbung/
|
||||||
|
├── app/
|
||||||
|
│ ├── layout.tsx # Root Layout mit Metadata
|
||||||
|
│ ├── page.tsx # Hauptseite (Home)
|
||||||
|
│ └── globals.css # Globale Styles
|
||||||
|
├── components/
|
||||||
|
│ ├── Hero.tsx # Hero-Section mit Parallax
|
||||||
|
│ ├── Intro.tsx # Über mich Sektion
|
||||||
|
│ ├── Experience.tsx # Berufserfahrung
|
||||||
|
│ ├── Skills.tsx # Kompetenzen mit Progress Bars
|
||||||
|
│ ├── Portfolio.tsx # Portfolio mit Modal
|
||||||
|
│ ├── Contact.tsx # Kontakt-Section
|
||||||
|
│ ├── DownloadSection.tsx # Download-Komponente
|
||||||
|
│ └── Footer.tsx # Footer
|
||||||
|
├── public/
|
||||||
|
│ ├── downloads/ # PDFs (Lebenslauf, Zeugnisse, etc.)
|
||||||
|
│ └── img/ # Bilder
|
||||||
|
└── package.json
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎨 Anpassungen
|
||||||
|
|
||||||
|
### Farben ändern
|
||||||
|
|
||||||
|
In `app/globals.css`:
|
||||||
|
|
||||||
|
```css
|
||||||
|
:root {
|
||||||
|
--color-primary: #3dc9b3; /* Hauptfarbe */
|
||||||
|
--color-primary-dark: #309383; /* Dunklere Variante */
|
||||||
|
--color-text: #353535; /* Text */
|
||||||
|
--color-text-light: #8c9398; /* Heller Text */
|
||||||
|
--color-bg-light: #f3f5f8; /* Heller Hintergrund */
|
||||||
|
--color-bg-dark: #242830; /* Dunkler Hintergrund */
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Inhalte anpassen
|
||||||
|
|
||||||
|
#### Persönliche Daten
|
||||||
|
- `components/Intro.tsx` - Über mich Text & Alter
|
||||||
|
- `components/Contact.tsx` - Kontaktdaten
|
||||||
|
- `app/layout.tsx` - Meta-Tags
|
||||||
|
|
||||||
|
#### Skills
|
||||||
|
- `components/Skills.tsx` - Array `skillsData` anpassen
|
||||||
|
|
||||||
|
#### Berufserfahrung
|
||||||
|
- `components/Experience.tsx` - Array `jobs` anpassen
|
||||||
|
|
||||||
|
#### Portfolio
|
||||||
|
- `components/Portfolio.tsx` - Array `projects` anpassen
|
||||||
|
|
||||||
|
### Bilder hinzufügen
|
||||||
|
|
||||||
|
1. Bilder in `public/img/` ablegen
|
||||||
|
2. PDFs in `public/downloads/` ablegen
|
||||||
|
3. Pfade in Komponenten anpassen
|
||||||
|
|
||||||
|
## 🎯 Nächste Schritte
|
||||||
|
|
||||||
|
### Sofort einsatzbereit:
|
||||||
|
- [ ] Persönliche Daten anpassen
|
||||||
|
- [ ] PDFs hochladen (Lebenslauf, Zeugnisse, Referenzen)
|
||||||
|
- [ ] Bilder aus altem Projekt kopieren
|
||||||
|
- [ ] Favicon anpassen
|
||||||
|
|
||||||
|
### Erweiterungen:
|
||||||
|
- [ ] Kontaktformular mit Validierung
|
||||||
|
- [ ] Blog-Sektion
|
||||||
|
- [ ] Dark Mode Toggle
|
||||||
|
- [ ] Mehrsprachigkeit (i18n)
|
||||||
|
- [ ] Analytics (Google Analytics / Plausible)
|
||||||
|
- [ ] Cookie Consent Banner
|
||||||
|
|
||||||
|
## 🖼️ Bilder aus altem Projekt kopieren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Im Terminal ausführen:
|
||||||
|
cp -r /Users/sebastianfrohlich/Projekte/bewerbung/img/* /Users/sebastianfrohlich/Projekte/bewerbung2025/bewerbung/public/img/
|
||||||
|
cp -r /Users/sebastianfrohlich/Projekte/bewerbung/downloads/* /Users/sebastianfrohlich/Projekte/bewerbung2025/bewerbung/public/downloads/
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📱 Deployment
|
||||||
|
|
||||||
|
### Vercel (Empfohlen)
|
||||||
|
```bash
|
||||||
|
# Vercel CLI installieren
|
||||||
|
npm i -g vercel
|
||||||
|
|
||||||
|
# Deployen
|
||||||
|
vercel
|
||||||
|
```
|
||||||
|
|
||||||
|
### Netlify
|
||||||
|
1. GitHub Repository erstellen
|
||||||
|
2. Mit Netlify verbinden
|
||||||
|
3. Build Command: `npm run build`
|
||||||
|
4. Publish Directory: `.next`
|
||||||
|
|
||||||
|
## 🔧 Technologien
|
||||||
|
|
||||||
|
- **Framework**: Next.js 15.5.4
|
||||||
|
- **UI Library**: React 19.1.0
|
||||||
|
- **Styling**: Tailwind CSS 4
|
||||||
|
- **Language**: TypeScript 5
|
||||||
|
- **Font**: Varela Round (Google Fonts)
|
||||||
|
|
||||||
|
## 📄 Migration vom alten Projekt
|
||||||
|
|
||||||
|
### Was wurde modernisiert:
|
||||||
|
✅ jQuery → React Hooks
|
||||||
|
✅ Bootstrap → Tailwind CSS
|
||||||
|
✅ Google Charts → Custom Progress Bars
|
||||||
|
✅ FlexSlider → React State Management
|
||||||
|
✅ Magnific Popup → Custom Modal
|
||||||
|
✅ Veraltete Dependencies → Moderne Stack
|
||||||
|
|
||||||
|
### Was bleibt gleich:
|
||||||
|
- Design-Sprache und Farbschema
|
||||||
|
- Inhaltsstruktur
|
||||||
|
- Bewerbungskonzept "beWerbung"
|
||||||
|
|
||||||
|
## 🐛 Troubleshooting
|
||||||
|
|
||||||
|
### Port bereits belegt
|
||||||
|
```bash
|
||||||
|
# Port ändern
|
||||||
|
npm run dev -- -p 3001
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build Fehler
|
||||||
|
```bash
|
||||||
|
# Cache löschen
|
||||||
|
rm -rf .next
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
### TypeScript Fehler
|
||||||
|
```bash
|
||||||
|
# Types neu generieren
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📧 Kontakt
|
||||||
|
|
||||||
|
Sebastian Fröhlich
|
||||||
|
- Email: froehlich.sebastian@gmail.com
|
||||||
|
- Tel: +49 9874 322 429
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Made with ❤️ and ☕ in Neuendettelsau
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
# ✅ beWerbung 2025 - Setup Checkliste
|
||||||
|
|
||||||
|
## 🎉 Was wurde erstellt:
|
||||||
|
|
||||||
|
### Komponenten
|
||||||
|
- ✅ Hero.tsx - Hero-Section mit Parallax-Effekt
|
||||||
|
- ✅ Intro.tsx - Über mich mit Intersection Observer
|
||||||
|
- ✅ Experience.tsx - Berufserfahrung mit Tab-Navigation
|
||||||
|
- ✅ Skills.tsx - Kompetenzen mit animierten Progress Bars
|
||||||
|
- ✅ Portfolio.tsx - Portfolio mit Filter und Modal
|
||||||
|
- ✅ Contact.tsx - Kontakt-Section mit Icons
|
||||||
|
- ✅ DownloadSection.tsx - Wiederverwendbare Download-Komponente
|
||||||
|
- ✅ Footer.tsx - Footer mit Call-to-Action
|
||||||
|
|
||||||
|
### Konfiguration
|
||||||
|
- ✅ layout.tsx - SEO & Metadata konfiguriert
|
||||||
|
- ✅ page.tsx - Alle Komponenten zusammengeführt
|
||||||
|
- ✅ globals.css - Custom Farben & Animationen
|
||||||
|
- ✅ README.md - Vollständige Dokumentation
|
||||||
|
- ✅ .env.example - Environment Variables Template
|
||||||
|
|
||||||
|
## 🚀 Nächste Schritte zum Start:
|
||||||
|
|
||||||
|
### 1. Assets kopieren (Bilder & PDFs)
|
||||||
|
```bash
|
||||||
|
cd /Users/sebastianfrohlich/Projekte/bewerbung2025/bewerbung
|
||||||
|
npm run copy-assets
|
||||||
|
```
|
||||||
|
|
||||||
|
**Oder manuell:**
|
||||||
|
```bash
|
||||||
|
mkdir -p public/img public/downloads
|
||||||
|
cp /Users/sebastianfrohlich/Projekte/bewerbung/img/*.jpg public/img/
|
||||||
|
cp /Users/sebastianfrohlich/Projekte/bewerbung/img/*.png public/img/
|
||||||
|
cp /Users/sebastianfrohlich/Projekte/bewerbung/downloads/*.pdf public/downloads/
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Development Server starten
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Dann öffne: **http://localhost:3000**
|
||||||
|
|
||||||
|
### 3. Inhalte anpassen
|
||||||
|
|
||||||
|
#### 📝 Persönliche Daten
|
||||||
|
- [ ] `components/Intro.tsx` - Geburtsjahr in Zeile 26 anpassen
|
||||||
|
- [ ] `components/Contact.tsx` - Kontaktdaten prüfen
|
||||||
|
- [ ] `app/layout.tsx` - Meta-Beschreibung anpassen
|
||||||
|
|
||||||
|
#### 💼 Berufserfahrung
|
||||||
|
- [ ] `components/Experience.tsx` - Jobs-Array aktualisieren
|
||||||
|
- [ ] Aktuelle Tätigkeiten hinzufügen
|
||||||
|
- [ ] Zeiträume prüfen
|
||||||
|
|
||||||
|
#### 🎨 Skills
|
||||||
|
- [ ] `components/Skills.tsx` - skillsData Array anpassen
|
||||||
|
- [ ] Neue Technologien hinzufügen
|
||||||
|
- [ ] Level-Werte überprüfen (1-5)
|
||||||
|
|
||||||
|
#### 🖼️ Portfolio
|
||||||
|
- [ ] `components/Portfolio.tsx` - projects Array aktualisieren
|
||||||
|
- [ ] Neue Projekte hinzufügen
|
||||||
|
- [ ] Bilder-Pfade prüfen
|
||||||
|
|
||||||
|
### 4. Bilder optimieren
|
||||||
|
|
||||||
|
**Fehlende Bilder erstellen:**
|
||||||
|
- [ ] workspace-bg.jpg - Für Lebenslauf-Download-Section
|
||||||
|
- [ ] certificates-bg.jpg - Für Zeugnisse-Download-Section
|
||||||
|
- [ ] keyboard-bg.jpg - Für Referenzen-Download-Section
|
||||||
|
|
||||||
|
**Tipp:** Du kannst die vorhandenen Bilder aus dem alten Projekt umbenennen:
|
||||||
|
```bash
|
||||||
|
cp public/img/Workspace.png public/img/workspace-bg.jpg
|
||||||
|
cp public/img/Flyer-Mockup-3---Infinity---Zeugnisse.jpg public/img/certificates-bg.jpg
|
||||||
|
cp public/img/keyboard-bg.jpg public/img/keyboard-bg.jpg
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. PDFs prüfen
|
||||||
|
|
||||||
|
Stelle sicher, dass diese PDFs in `public/downloads/` liegen:
|
||||||
|
- [ ] Lebenslauf2020.pdf (oder aktualisiere zu Lebenslauf2025.pdf)
|
||||||
|
- [ ] Zeugnisse.pdf
|
||||||
|
- [ ] Referenzen.pdf
|
||||||
|
|
||||||
|
## 🎨 Farben anpassen (Optional)
|
||||||
|
|
||||||
|
In `app/globals.css`:
|
||||||
|
```css
|
||||||
|
:root {
|
||||||
|
--color-primary: #3dc9b3; /* Deine Wunschfarbe */
|
||||||
|
--color-primary-dark: #309383;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📱 Responsive Testen
|
||||||
|
|
||||||
|
Teste die Webseite auf verschiedenen Bildschirmgrößen:
|
||||||
|
- [ ] Desktop (1920px+)
|
||||||
|
- [ ] Laptop (1280px)
|
||||||
|
- [ ] Tablet (768px)
|
||||||
|
- [ ] Mobile (375px)
|
||||||
|
|
||||||
|
**Browser Dev Tools:** F12 → Responsive Design Mode
|
||||||
|
|
||||||
|
## 🚀 Deployment Vorbereiten
|
||||||
|
|
||||||
|
### Vercel (Empfohlen)
|
||||||
|
1. GitHub Repository erstellen
|
||||||
|
2. Code pushen
|
||||||
|
3. Mit Vercel verbinden
|
||||||
|
4. Automatisches Deployment
|
||||||
|
|
||||||
|
### Manuell
|
||||||
|
```bash
|
||||||
|
npm run build
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🐛 Bekannte Todos
|
||||||
|
|
||||||
|
- [ ] Bilder durch Next.js Image-Komponente ersetzen (Performance)
|
||||||
|
- [ ] Loading States für Animationen
|
||||||
|
- [ ] Error Boundaries hinzufügen
|
||||||
|
- [ ] 404 Seite erstellen
|
||||||
|
- [ ] Sitemap generieren
|
||||||
|
- [ ] robots.txt erstellen
|
||||||
|
|
||||||
|
## 💡 Optionale Erweiterungen
|
||||||
|
|
||||||
|
- [ ] Kontaktformular mit Backend (z.B. Resend, SendGrid)
|
||||||
|
- [ ] Blog-Sektion für Artikel
|
||||||
|
- [ ] Dark Mode Toggle
|
||||||
|
- [ ] Animations-Library (Framer Motion)
|
||||||
|
- [ ] Analytics Integration
|
||||||
|
- [ ] Cookie Consent Banner
|
||||||
|
- [ ] Newsletter Integration
|
||||||
|
|
||||||
|
## 📊 Vergleich Alt vs. Neu
|
||||||
|
|
||||||
|
| Feature | Alt (2014) | Neu (2025) |
|
||||||
|
|---------|------------|------------|
|
||||||
|
| Framework | Vanilla HTML | Next.js 15 |
|
||||||
|
| CSS | Bootstrap 3 | Tailwind 4 |
|
||||||
|
| JavaScript | jQuery 1.11 | React 19 |
|
||||||
|
| Charts | Google Charts | Custom Components |
|
||||||
|
| Responsive | Ja | Ja (Mobile-First) |
|
||||||
|
| TypeScript | Nein | Ja |
|
||||||
|
| Performance | 🟡 Mittel | 🟢 Hoch |
|
||||||
|
| Wartbarkeit | 🟡 Mittel | 🟢 Hoch |
|
||||||
|
| Modern | 🔴 Veraltet | 🟢 Aktuell |
|
||||||
|
|
||||||
|
## ✨ Verbesserungen gegenüber alter Version
|
||||||
|
|
||||||
|
1. **Performance:**
|
||||||
|
- Server-Side Rendering mit Next.js
|
||||||
|
- Automatisches Code Splitting
|
||||||
|
- Image Optimization
|
||||||
|
- Moderne JavaScript Features
|
||||||
|
|
||||||
|
2. **Wartbarkeit:**
|
||||||
|
- Komponentenbasiert
|
||||||
|
- TypeScript für Type Safety
|
||||||
|
- Modularer Code
|
||||||
|
- Klare Struktur
|
||||||
|
|
||||||
|
3. **Sicherheit:**
|
||||||
|
- Keine veralteten Dependencies
|
||||||
|
- Keine jQuery Vulnerabilities
|
||||||
|
- Moderne Security Headers möglich
|
||||||
|
|
||||||
|
4. **UX:**
|
||||||
|
- Smooth Animations
|
||||||
|
- Bessere Mobile Experience
|
||||||
|
- Schnellere Ladezeiten
|
||||||
|
- Moderne UI Patterns
|
||||||
|
|
||||||
|
## 📞 Support
|
||||||
|
|
||||||
|
Bei Fragen oder Problemen:
|
||||||
|
1. README.md lesen
|
||||||
|
2. Console Errors prüfen (F12)
|
||||||
|
3. Google / Stack Overflow
|
||||||
|
4. Next.js Dokumentation: https://nextjs.org/docs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
🎉 **Viel Erfolg mit deiner neuen Bewerbungswebseite!**
|
||||||
|
After Width: | Height: | Size: 25 KiB |
@@ -0,0 +1,65 @@
|
|||||||
|
@import "tailwindcss";
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--color-primary: #3dc9b3;
|
||||||
|
--color-primary-dark: #309383;
|
||||||
|
--color-text: #353535;
|
||||||
|
--color-text-light: #8c9398;
|
||||||
|
--color-bg-light: #f3f5f8;
|
||||||
|
--color-bg-dark: #242830;
|
||||||
|
}
|
||||||
|
|
||||||
|
@theme inline {
|
||||||
|
--font-varela: "Varela Round", system-ui, sans-serif;
|
||||||
|
|
||||||
|
--color-primary: #3dc9b3;
|
||||||
|
--color-primary-dark: #309383;
|
||||||
|
--color-text: #353535;
|
||||||
|
--color-text-light: #8c9398;
|
||||||
|
--color-bg-light: #f3f5f8;
|
||||||
|
--color-bg-dark: #242830;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: var(--color-text);
|
||||||
|
font-family: var(--font-varela);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Smooth scroll behavior */
|
||||||
|
html {
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom scrollbar */
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: var(--color-bg-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: var(--color-primary);
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: var(--color-primary-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Animations */
|
||||||
|
@keyframes fade-in {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(20px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-fade-in {
|
||||||
|
animation: fade-in 1s ease-out;
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import { Varela_Round } from "next/font/google";
|
||||||
|
import "./globals.css";
|
||||||
|
|
||||||
|
const varelaRound = Varela_Round({
|
||||||
|
weight: "400",
|
||||||
|
subsets: ["latin"],
|
||||||
|
variable: "--font-varela",
|
||||||
|
});
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "beWerbung - Sebastian Fröhlich",
|
||||||
|
description: "Die Bewerberwebseite von Sebastian Fröhlich - Full-Stack Developer, technischer PO, Team Leader mit Fokus auf moderne Webtechnologien",
|
||||||
|
keywords: ["Sebastian Fröhlich", "Bewerbung", "Full-Stack Developer", "Web Development", "PHP", "JavaScript", "Python"],
|
||||||
|
authors: [{ name: "Sebastian Fröhlich" }],
|
||||||
|
openGraph: {
|
||||||
|
title: "beWerbung - Sebastian Fröhlich",
|
||||||
|
description: "Full-Stack Developer, technischer PO, Team Leader mit Leidenschaft für moderne Webtechnologien",
|
||||||
|
type: "website",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function RootLayout({
|
||||||
|
children,
|
||||||
|
}: Readonly<{
|
||||||
|
children: React.ReactNode;
|
||||||
|
}>) {
|
||||||
|
return (
|
||||||
|
<html lang="de" className="scroll-smooth">
|
||||||
|
<body
|
||||||
|
className={`${varelaRound.variable} antialiased font-varela`}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import Hero from '@/components/Hero';
|
||||||
|
import Intro from '@/components/Intro';
|
||||||
|
import DownloadSection from '@/components/DownloadSection';
|
||||||
|
import Experience from '@/components/Experience';
|
||||||
|
import Skills from '@/components/Skills';
|
||||||
|
import SoftSkills from '@/components/SoftSkills';
|
||||||
|
import Portfolio from '@/components/Portfolio';
|
||||||
|
import Contact from '@/components/Contact';
|
||||||
|
import Footer from '@/components/Footer';
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<main className="min-h-screen">
|
||||||
|
<Hero />
|
||||||
|
|
||||||
|
<Intro />
|
||||||
|
|
||||||
|
<DownloadSection
|
||||||
|
title="Sebastian Fröhlich"
|
||||||
|
subtitle="Meinen Lebenslauf herunterladen"
|
||||||
|
buttonText="Jetzt downloaden"
|
||||||
|
href="/downloads/Lebenslauf_2025.pdf"
|
||||||
|
backgroundImage="/img/bg-lebenslauf.jpg"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Experience />
|
||||||
|
|
||||||
|
<Skills />
|
||||||
|
|
||||||
|
<SoftSkills />
|
||||||
|
|
||||||
|
<DownloadSection
|
||||||
|
title="Sebastian Fröhlich"
|
||||||
|
subtitle="Meine Arbeitszeugnisse herunterladen"
|
||||||
|
buttonText="Jetzt downloaden"
|
||||||
|
href="/downloads/Zeugnisse_2025.pdf"
|
||||||
|
backgroundImage="/img/bg-arbeitszeugnisse.jpg"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Portfolio />
|
||||||
|
|
||||||
|
<DownloadSection
|
||||||
|
title="Sebastian Fröhlich"
|
||||||
|
subtitle="Meine Referenzen herunterladen"
|
||||||
|
buttonText="Jetzt downloaden"
|
||||||
|
href="/downloads/Referenzen.pdf"
|
||||||
|
backgroundImage="/img/keyboard-bg.jpg"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Contact />
|
||||||
|
|
||||||
|
<Footer />
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Script zum sicheren Verschieben ungenutzter Dateien in Backup-Ordner
|
||||||
|
# Erstellt: $(date +%Y-%m-%d)
|
||||||
|
|
||||||
|
echo "🗂️ Erstelle Backup-Ordner..."
|
||||||
|
|
||||||
|
# Backup-Ordner erstellen
|
||||||
|
mkdir -p public/_unused/downloads
|
||||||
|
mkdir -p public/_unused/img
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "📦 Verschiebe ungenutzte DOWNLOADS..."
|
||||||
|
echo "======================================"
|
||||||
|
|
||||||
|
# Alte PDFs verschieben (falls vorhanden)
|
||||||
|
if [ -f "public/downloads/Lebenslauf2020.pdf" ]; then
|
||||||
|
mv "public/downloads/Lebenslauf2020.pdf" "public/_unused/downloads/"
|
||||||
|
echo "✅ Lebenslauf2020.pdf → _unused/downloads/"
|
||||||
|
else
|
||||||
|
echo "⏭️ Lebenslauf2020.pdf nicht gefunden (bereits verschoben?)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "public/downloads/Zeugnisse.pdf" ]; then
|
||||||
|
mv "public/downloads/Zeugnisse.pdf" "public/_unused/downloads/"
|
||||||
|
echo "✅ Zeugnisse.pdf → _unused/downloads/"
|
||||||
|
else
|
||||||
|
echo "⏭️ Zeugnisse.pdf nicht gefunden (bereits verschoben?)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "public/downloads/Bewerbungsmappe 2014 - Refererenzen.pdf" ]; then
|
||||||
|
mv "public/downloads/Bewerbungsmappe 2014 - Refererenzen.pdf" "public/_unused/downloads/"
|
||||||
|
echo "✅ Bewerbungsmappe 2014 - Refererenzen.pdf → _unused/downloads/"
|
||||||
|
else
|
||||||
|
echo "⏭️ Bewerbungsmappe nicht gefunden (bereits verschoben?)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "🖼️ Verschiebe ungenutzte BILDER..."
|
||||||
|
echo "======================================"
|
||||||
|
|
||||||
|
# Alte Hintergrundbilder
|
||||||
|
declare -a old_images=(
|
||||||
|
"bg-ich-1.png"
|
||||||
|
"bg-ich-2.png"
|
||||||
|
"bg-ich-2025.jpg"
|
||||||
|
"bg-ich-2025-foreground.jpg"
|
||||||
|
"workspace-bg.jpg"
|
||||||
|
)
|
||||||
|
|
||||||
|
for img in "${old_images[@]}"; do
|
||||||
|
if [ -f "public/img/$img" ]; then
|
||||||
|
mv "public/img/$img" "public/_unused/img/"
|
||||||
|
echo "✅ $img → _unused/img/"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Alte Icon-Dateien
|
||||||
|
declare -a old_icons=(
|
||||||
|
"Workspace.png"
|
||||||
|
"controls.png"
|
||||||
|
"h1-bg.png"
|
||||||
|
"icon-os.png"
|
||||||
|
"icons-cms.png"
|
||||||
|
"icons-gfx.png"
|
||||||
|
"icons-marketing.png"
|
||||||
|
"icons-office.png"
|
||||||
|
"icons-os.png"
|
||||||
|
"icons-web.png"
|
||||||
|
)
|
||||||
|
|
||||||
|
for icon in "${old_icons[@]}"; do
|
||||||
|
if [ -f "public/img/$icon" ]; then
|
||||||
|
mv "public/img/$icon" "public/_unused/img/"
|
||||||
|
echo "✅ $icon → _unused/img/"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Portfolio-Duplikate (vorsichtig - nur offensichtliche Duplikate)
|
||||||
|
declare -a portfolio_duplicates=(
|
||||||
|
"Referenz - Illy-sommerkarte07.png"
|
||||||
|
"Referenz - Planet Touristik - Frontansicht.jpg"
|
||||||
|
"Referenz - Planet-Touristik - web01.jpg"
|
||||||
|
"Referenz---Illy---Außenansicht.jpg"
|
||||||
|
"Referenz---Planet-Touristik---Frontansicht.jpg"
|
||||||
|
"Referenz---SZ---Frontansicht.jpg"
|
||||||
|
"Referenz---e-stev--Web2.jpg"
|
||||||
|
"Referenz---handstaubsauger---web2.jpg"
|
||||||
|
)
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "📸 Verschiebe Portfolio-Duplikate..."
|
||||||
|
echo "======================================"
|
||||||
|
|
||||||
|
for img in "${portfolio_duplicates[@]}"; do
|
||||||
|
if [ -f "public/img/$img" ]; then
|
||||||
|
mv "public/img/$img" "public/_unused/img/"
|
||||||
|
echo "✅ $img → _unused/img/"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# .DS_Store Dateien (macOS)
|
||||||
|
if [ -f "public/downloads/.DS_Store" ]; then
|
||||||
|
mv "public/downloads/.DS_Store" "public/_unused/downloads/"
|
||||||
|
echo "✅ .DS_Store (downloads) → _unused/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "public/img/.DS_Store" ]; then
|
||||||
|
mv "public/img/.DS_Store" "public/_unused/img/"
|
||||||
|
echo "✅ .DS_Store (img) → _unused/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ Fertig!"
|
||||||
|
echo ""
|
||||||
|
echo "📊 Zusammenfassung:"
|
||||||
|
echo "==================="
|
||||||
|
echo "Alle ungenutzten Dateien wurden nach public/_unused/ verschoben."
|
||||||
|
echo ""
|
||||||
|
echo "📁 Backup-Ordner:"
|
||||||
|
echo " public/_unused/downloads/"
|
||||||
|
echo " public/_unused/img/"
|
||||||
|
echo ""
|
||||||
|
echo "🔍 Nächste Schritte:"
|
||||||
|
echo " 1. Teste die Webseite: npm run dev"
|
||||||
|
echo " 2. Prüfe ob alles funktioniert"
|
||||||
|
echo " 3. Falls etwas fehlt, Dateien aus _unused/ zurückkopieren"
|
||||||
|
echo " 4. Nach erfolgreicher Prüfung: _unused/ Ordner komplett löschen"
|
||||||
|
echo ""
|
||||||
|
echo "🗑️ Zum endgültigen Löschen (erst nach Test!):"
|
||||||
|
echo " rm -rf public/_unused/"
|
||||||
|
echo ""
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
export default function Contact() {
|
||||||
|
const scrollToTop = () => {
|
||||||
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section id="contact" className="relative py-20 px-4 sm:px-6 lg:px-8 bg-bg-dark text-white">
|
||||||
|
{/* Scroll to Top Button */}
|
||||||
|
<button
|
||||||
|
onClick={scrollToTop}
|
||||||
|
className="absolute -top-6 left-1/2 -translate-x-1/2 w-12 h-12 bg-primary rounded-full flex items-center justify-center hover:bg-primary-dark transition-all shadow-lg group"
|
||||||
|
aria-label="Nach oben scrollen"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
className="w-6 h-6 text-white group-hover:-translate-y-1 transition-transform"
|
||||||
|
fill="none"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
>
|
||||||
|
<path d="M5 10l7-7m0 0l7 7m-7-7v18"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div className="max-w-6xl mx-auto">
|
||||||
|
<h2 className="text-3xl sm:text-4xl font-bold text-center mb-16 relative inline-block w-full after:content-[''] after:block after:w-12 after:h-1 after:bg-primary after:mt-6 after:mx-auto">
|
||||||
|
Jetzt Kontakt aufnehmen
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
|
{/* Address */}
|
||||||
|
<div className="bg-white/5 backdrop-blur-sm rounded-lg p-8 text-center hover:bg-white/10 transition-all hover:transform hover:scale-105">
|
||||||
|
<div className="w-16 h-16 bg-primary rounded-full flex items-center justify-center mx-auto mb-4">
|
||||||
|
<svg className="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-xl font-bold mb-2">Adresse</h3>
|
||||||
|
<p className="text-white/80">
|
||||||
|
Rosenstraße 4<br />
|
||||||
|
91564 Neuendettelsau
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Phone */}
|
||||||
|
<div className="bg-white/5 backdrop-blur-sm rounded-lg p-8 text-center hover:bg-white/10 transition-all hover:transform hover:scale-105">
|
||||||
|
<div className="w-16 h-16 bg-primary rounded-full flex items-center justify-center mx-auto mb-4">
|
||||||
|
<svg className="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-xl font-bold mb-2">Telefon</h3>
|
||||||
|
<a href="tel:+4915732469960" className="text-white/80 hover:text-primary transition-colors">
|
||||||
|
+49 157 32469960
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Email */}
|
||||||
|
<div className="bg-white/5 backdrop-blur-sm rounded-lg p-8 text-center hover:bg-white/10 transition-all hover:transform hover:scale-105">
|
||||||
|
<div className="w-16 h-16 bg-primary rounded-full flex items-center justify-center mx-auto mb-4">
|
||||||
|
<svg className="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-xl font-bold mb-2">Email</h3>
|
||||||
|
<a
|
||||||
|
href="mailto:froehlich.sebastian@gmail.com?subject=Antwort - Ihre Bewerbung"
|
||||||
|
className="text-white/80 hover:text-primary transition-colors break-all"
|
||||||
|
>
|
||||||
|
froehlich.sebastian@gmail.com
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
interface DownloadSectionProps {
|
||||||
|
title: string;
|
||||||
|
subtitle: string;
|
||||||
|
buttonText: string;
|
||||||
|
href: string;
|
||||||
|
backgroundImage: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function DownloadSection({
|
||||||
|
title,
|
||||||
|
subtitle,
|
||||||
|
buttonText,
|
||||||
|
href,
|
||||||
|
backgroundImage,
|
||||||
|
}: DownloadSectionProps) {
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
className="relative py-24 px-4 sm:px-6 lg:px-8 bg-cover bg-center bg-fixed"
|
||||||
|
style={{ backgroundImage: `url(${backgroundImage})` }}
|
||||||
|
>
|
||||||
|
{/* Overlay */}
|
||||||
|
<div className="absolute inset-0 bg-black/60" />
|
||||||
|
|
||||||
|
<div className="relative z-10 max-w-4xl mx-auto text-center">
|
||||||
|
<h2 className="text-4xl sm:text-5xl font-bold text-white mb-4">
|
||||||
|
{title}
|
||||||
|
</h2>
|
||||||
|
<p className="text-xl sm:text-2xl text-white/90 mb-8">
|
||||||
|
{subtitle}
|
||||||
|
</p>
|
||||||
|
<a
|
||||||
|
href={href}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="inline-block px-10 py-4 bg-primary text-white font-bold text-lg rounded-md hover:bg-primary-dark transition-all transform hover:scale-105 shadow-lg hover:shadow-xl"
|
||||||
|
>
|
||||||
|
{buttonText}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,256 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
interface Job {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
company: string;
|
||||||
|
location: string;
|
||||||
|
period: string;
|
||||||
|
description: string;
|
||||||
|
responsibilities: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const jobs: Job[] = [
|
||||||
|
{
|
||||||
|
id: 'job1',
|
||||||
|
title: 'Technischer Product Owner',
|
||||||
|
company: 'IT im Bereich Finanzen und Banken',
|
||||||
|
location: 'Regulatory & Risk, Nürnberg',
|
||||||
|
period: 'Juni 2021 - heute',
|
||||||
|
description: 'Technischer Product Owner in einem Nürnberger Unternehmen, welches die komplette Banken IT steuert.',
|
||||||
|
responsibilities: [
|
||||||
|
'Sicherstellung des Betriebs',
|
||||||
|
'Planung und Priorisierung der Ressourcen & Aufgaben',
|
||||||
|
'Technische Kommunikation und Architektur',
|
||||||
|
'Migration der Infrastruktur K8s on prem & Cloud',
|
||||||
|
'Aufbau neuer Services',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'job2',
|
||||||
|
title: 'Product Owner',
|
||||||
|
company: 'Mobile Applikationen Unternehmen',
|
||||||
|
location: 'Nürnberg',
|
||||||
|
period: 'Februar 2019 - März 2020',
|
||||||
|
description: 'Product Owner in einem Nürnberger Unternehmen, welches mobile Applikationen zur Digitalisierung von Prozessen herstellt.',
|
||||||
|
responsibilities: [
|
||||||
|
'Abklärung der Anforderungen zwischen Stakeholdern und Entwicklern',
|
||||||
|
'Planung und Priorisierung der Ressourcen & Aufgaben',
|
||||||
|
'Technische Kommunikation und Architektur',
|
||||||
|
'Migration der bestehenden Infrastruktur in die MagentaCloud (Kubernetes)',
|
||||||
|
'Weiterentwicklung des Produktes',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'job3',
|
||||||
|
title: 'Leiter IT',
|
||||||
|
company: 'Unternehmen im Bereich Fahrzeugtechnik',
|
||||||
|
location: 'Georgensgmünd',
|
||||||
|
period: 'März 2014 - Januar 2019',
|
||||||
|
description: 'Leiter einer IT-Abteilung in einem mittelfränkischen Unternehmen aus dem Bereich Fahrzeugtechnik.',
|
||||||
|
responsibilities: [
|
||||||
|
'Programmierung & Weiterentwicklung der Online Shops',
|
||||||
|
'Anbindung der Warenwirtschaft',
|
||||||
|
'Aufbau und Entwicklung eines Intranets',
|
||||||
|
'Architektur der Datenbanken',
|
||||||
|
'API Schnittstellenprogrammierung',
|
||||||
|
'Migration/Neuaufbau und Entwicklung der Linux Server',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'job4',
|
||||||
|
title: 'Marketing Manager',
|
||||||
|
company: 'Trustec Energy GmbH',
|
||||||
|
location: 'Solarbranche, Mittelfranken',
|
||||||
|
period: 'Januar 2010 - März 2014',
|
||||||
|
description: 'Marketing Manager in einem Unternehmen der Solarbranche mit Verantwortung für die komplette digitale Präsenz und Marketing-Kommunikation.',
|
||||||
|
responsibilities: [
|
||||||
|
'Aufbau, Programmierung und Pflege der Firmenwebseiten (trustec-energy.eu, mhm-marketing.com) mit Joomla CMS',
|
||||||
|
'Entwicklung und Programmierung neuer CMS-Inhaltstypen und Module',
|
||||||
|
'E-Mail Marketing: Erstellung, Versand und Erfolgsmessung von Newslettern und Messe-Respondern',
|
||||||
|
'Print Design: Kataloge, Preislisten, Flyer, Rollups und Messestände (InDesign, Photoshop, Illustrator)',
|
||||||
|
'Erstellung von 3D Produkt Mock-ups und Landing Pages',
|
||||||
|
'Web Analytics mit Google Analytics und Piwik',
|
||||||
|
'Koordination externer Dienstleister (Grafiker, Übersetzer, Messebauer)',
|
||||||
|
'IT-Support: Betreuung Windows Server 2008, CRM-Software und Telefonanlage',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'job5',
|
||||||
|
title: 'Freelancer Web Development & Design',
|
||||||
|
company: 'Selbstständig',
|
||||||
|
location: 'Verschiedene Branchen',
|
||||||
|
period: 'Januar 2000 - Dezember 2010',
|
||||||
|
description: 'Über 10 Jahre selbstständig für Unternehmenskunden aus unterschiedlichen Branchen tätig, mit Fokus auf webbasierte Lösungen.',
|
||||||
|
responsibilities: [
|
||||||
|
'Entwicklung von Präsentations- und Buchungssystemen',
|
||||||
|
'Programmierung von CMS-Systemen und Content-Management-Lösungen',
|
||||||
|
'Aufbau und Entwicklung von E-Commerce Shops',
|
||||||
|
'Webdesign und Frontend-Entwicklung (HTML, CSS, JavaScript, Flash/Actionscript)',
|
||||||
|
'Kundenberatung und Anforderungsanalyse',
|
||||||
|
'Print Design und Corporate Design Entwicklung',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Experience() {
|
||||||
|
const [activeJob, setActiveJob] = useState(0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section id="experience" className="py-20 px-4 sm:px-6 lg:px-8 bg-white">
|
||||||
|
<div className="max-w-6xl mx-auto">
|
||||||
|
<h2 className="text-3xl sm:text-4xl font-bold text-text text-center mb-16 relative inline-block w-full after:content-[''] after:block after:w-12 after:h-1 after:bg-primary after:mt-6 after:mx-auto">
|
||||||
|
Berufserfahrung
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||||
|
{/* Job Tabs - Jetzt mit besserer Mobile-Darstellung */}
|
||||||
|
<div className="lg:col-span-1">
|
||||||
|
<div className="flex flex-col gap-3">
|
||||||
|
{jobs.map((job, index) => (
|
||||||
|
<button
|
||||||
|
key={job.id}
|
||||||
|
onClick={() => setActiveJob(index)}
|
||||||
|
className={`text-left p-4 sm:p-5 rounded-lg transition-all duration-300 ${
|
||||||
|
activeJob === index
|
||||||
|
? 'bg-primary text-white shadow-lg scale-105'
|
||||||
|
: 'bg-gray-100 text-text hover:bg-gray-200 hover:shadow-md'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<h3 className="font-bold text-sm sm:text-base lg:text-lg mb-1">
|
||||||
|
{job.title}
|
||||||
|
</h3>
|
||||||
|
<p className={`text-xs sm:text-sm ${activeJob === index ? 'text-white/80' : 'text-text-light'}`}>
|
||||||
|
{job.company}
|
||||||
|
</p>
|
||||||
|
<p className={`text-xs mt-1 font-semibold ${activeJob === index ? 'text-white/90' : 'text-primary'}`}>
|
||||||
|
{job.period.split(' - ')[0]}
|
||||||
|
</p>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Job Details */}
|
||||||
|
<div className="lg:col-span-2">
|
||||||
|
<div className="bg-bg-light rounded-lg p-6 sm:p-8 shadow-md hover:shadow-xl transition-shadow">
|
||||||
|
{/* Header */}
|
||||||
|
<div className="mb-6 pb-6 border-b border-gray-200">
|
||||||
|
<h3 className="text-xl sm:text-2xl lg:text-3xl font-bold text-text mb-3">
|
||||||
|
{jobs[activeJob].title}
|
||||||
|
</h3>
|
||||||
|
<div className="flex flex-col gap-2 mb-2">
|
||||||
|
<p className="text-base sm:text-lg font-semibold text-text-light flex items-center">
|
||||||
|
<svg className="w-5 h-5 mr-2 text-primary flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
|
||||||
|
</svg>
|
||||||
|
{jobs[activeJob].company}
|
||||||
|
</p>
|
||||||
|
<p className="text-sm sm:text-base text-text-light flex items-center">
|
||||||
|
<svg className="w-5 h-5 mr-2 text-primary flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
|
{jobs[activeJob].location}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<p className="text-primary font-bold text-base sm:text-lg flex items-center">
|
||||||
|
<svg className="w-5 h-5 mr-2 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||||
|
</svg>
|
||||||
|
{jobs[activeJob].period}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Description */}
|
||||||
|
<p className="text-text-light mb-6 text-sm sm:text-base leading-relaxed">
|
||||||
|
{jobs[activeJob].description}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* Responsibilities */}
|
||||||
|
<h4 className="font-bold text-text mb-4 text-base sm:text-lg flex items-center">
|
||||||
|
<svg className="w-5 h-5 mr-2 text-primary flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4" />
|
||||||
|
</svg>
|
||||||
|
Verantwortlichkeiten:
|
||||||
|
</h4>
|
||||||
|
<ul className="space-y-3">
|
||||||
|
{jobs[activeJob].responsibilities.map((resp, idx) => (
|
||||||
|
<li
|
||||||
|
key={idx}
|
||||||
|
className="flex items-start group hover:translate-x-1 transition-transform"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
className="w-5 h-5 text-primary mt-0.5 mr-3 flex-shrink-0 group-hover:scale-110 transition-transform"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
|
||||||
|
clipRule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span className="text-text-light leading-relaxed text-sm sm:text-base">{resp}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{/* Tags for quick tech overview */}
|
||||||
|
<div className="mt-8 pt-6 border-t border-gray-200">
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{activeJob === 0 && (
|
||||||
|
<>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">Kubernetes</span>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">Cloud Migration</span>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">Systemarchitektur</span>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">Financial IT</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{activeJob === 1 && (
|
||||||
|
<>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">Kubernetes</span>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">Mobile Apps</span>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">Stakeholder Management</span>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">Digitalisierung</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{activeJob === 2 && (
|
||||||
|
<>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">E-Commerce</span>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">Laravel</span>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">Vue.js</span>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">API Development</span>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">Team Leadership</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{activeJob === 3 && (
|
||||||
|
<>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">Joomla</span>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">E-Mail Marketing</span>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">Adobe Suite</span>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">Google Analytics</span>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">3D Design</span>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">Print Design</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{activeJob === 4 && (
|
||||||
|
<>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">HTML/CSS/JS</span>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">CMS Development</span>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">E-Commerce</span>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">Flash/Actionscript</span>
|
||||||
|
<span className="px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">Webdesign</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
export default function Footer() {
|
||||||
|
return (
|
||||||
|
<footer className="bg-bg-dark text-white py-8 px-4 sm:px-6 lg:px-8">
|
||||||
|
<div className="max-w-6xl mx-auto">
|
||||||
|
<div className="flex flex-col md:flex-row justify-between items-center gap-4">
|
||||||
|
<div className="text-center md:text-left">
|
||||||
|
<h3 className="text-xl font-bold mb-1">Sebastian Fröhlich</h3>
|
||||||
|
<p className="text-white/60 text-sm">Full-Stack Developer, technischer PO, Team Leader</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="text-center md:text-right">
|
||||||
|
<p className="text-white/80 font-semibold mb-2">Nicht alles hat ein Ende...</p>
|
||||||
|
<a
|
||||||
|
href="mailto:froehlich.sebastian@gmail.com?subject=Antwort - Ihre Bewerbung"
|
||||||
|
className="inline-block px-6 py-2 bg-primary text-white font-semibold rounded-lg hover:bg-primary-dark transition-colors"
|
||||||
|
>
|
||||||
|
Jetzt Kontakt aufnehmen
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-8 pt-8 border-t border-white/10 text-center text-white/60 text-sm">
|
||||||
|
<p>© {new Date().getFullYear()} Sebastian Fröhlich. Alle Rechte vorbehalten.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import Image from 'next/image';
|
||||||
|
|
||||||
|
export default function Hero() {
|
||||||
|
const [scrollY, setScrollY] = useState(0);
|
||||||
|
const [isMobile, setIsMobile] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleScroll = () => setScrollY(window.scrollY);
|
||||||
|
const handleResize = () => setIsMobile(window.innerWidth < 768);
|
||||||
|
|
||||||
|
handleResize(); // Initial check
|
||||||
|
window.addEventListener('scroll', handleScroll);
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('scroll', handleScroll);
|
||||||
|
window.removeEventListener('resize', handleResize);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
id="hero"
|
||||||
|
className="relative min-h-screen flex items-center justify-center overflow-hidden"
|
||||||
|
>
|
||||||
|
{/* Background Image mit Next.js Image */}
|
||||||
|
<div className="absolute inset-0 w-full h-full">
|
||||||
|
<Image
|
||||||
|
src={isMobile ? "/img/bg-ich-mobile.jpg" : "/img/bg-ich-2.png"}
|
||||||
|
alt="Hero Background"
|
||||||
|
fill
|
||||||
|
priority
|
||||||
|
quality={90}
|
||||||
|
className="object-cover object-center"
|
||||||
|
style={{
|
||||||
|
transform: `translateY(${scrollY * 0.5}px)`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* Overlay für bessere Lesbarkeit */}
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-br from-slate-900/80 via-slate-800/70 to-slate-900/80" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="relative z-10 text-center px-4 sm:px-6 lg:px-8">
|
||||||
|
<div className="space-y-6 animate-fade-in">
|
||||||
|
<h1 className="text-5xl sm:text-6xl lg:text-7xl font-bold text-white tracking-wider drop-shadow-2xl">
|
||||||
|
be<span className="text-primary">Werbung</span>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p className="text-xl sm:text-2xl text-slate-300 max-w-2xl mx-auto drop-shadow-lg">
|
||||||
|
Die Bewerberwebseite von <br />
|
||||||
|
<em className="text-primary font-semibold">Sebastian Fröhlich</em>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Scroll indicator */}
|
||||||
|
<div className="absolute bottom-10 left-1/2 -translate-x-1/2 animate-bounce">
|
||||||
|
<button
|
||||||
|
onClick={() => document.getElementById('intro')?.scrollIntoView({ behavior: 'smooth' })}
|
||||||
|
className="w-12 h-12 rounded-full bg-primary/20 backdrop-blur-sm border-2 border-primary flex items-center justify-center hover:bg-primary/30 transition-all group"
|
||||||
|
aria-label="Scroll nach unten"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
className="w-6 h-6 text-primary group-hover:translate-y-1 transition-transform"
|
||||||
|
fill="none"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
>
|
||||||
|
<path d="M19 14l-7 7m0 0l-7-7m7 7V3"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
export default function Hero() {
|
||||||
|
const [scrollY, setScrollY] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleScroll = () => setScrollY(window.scrollY);
|
||||||
|
window.addEventListener('scroll', handleScroll);
|
||||||
|
return () => window.removeEventListener('scroll', handleScroll);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
id="hero"
|
||||||
|
className="relative min-h-screen flex items-center justify-center overflow-hidden"
|
||||||
|
>
|
||||||
|
{/* Background Layer 1 - Wiederholendes Muster - passt sich an Bildschirmhöhe an */}
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 w-full h-full"
|
||||||
|
style={{
|
||||||
|
backgroundImage: 'url(/img/bg-ich-2025-background.jpg)',
|
||||||
|
backgroundRepeat: 'repeat',
|
||||||
|
backgroundSize: 'auto 100%',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
transform: `translateY(${scrollY * 0.3}px)`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Background Layer 2 - Portrait rechts (PNG mit Transparenz) */}
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 w-full h-full"
|
||||||
|
style={{
|
||||||
|
backgroundImage: 'url(/img/bg-ich-2025-foreground.png)',
|
||||||
|
backgroundRepeat: 'no-repeat',
|
||||||
|
backgroundSize: 'auto 100%',
|
||||||
|
backgroundPosition: 'right center',
|
||||||
|
transform: `translateY(${scrollY * 0.5}px)`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Overlay für bessere Lesbarkeit */}
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-r from-slate-900/80 via-slate-900/50 to-transparent sm:from-slate-900/70 sm:via-slate-900/40 lg:from-slate-900/60 lg:via-slate-900/20" />
|
||||||
|
|
||||||
|
{/* Content - Responsive Positionierung */}
|
||||||
|
<div className="relative z-10 w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div className="max-w-full sm:max-w-2xl lg:max-w-xl space-y-6 animate-fade-in">
|
||||||
|
<h1 className="text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold text-white tracking-wider drop-shadow-2xl">
|
||||||
|
be<span className="text-primary">Werbung</span>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p className="text-lg sm:text-xl md:text-2xl text-slate-300 drop-shadow-lg">
|
||||||
|
Die Bewerberwebseite von <br />
|
||||||
|
<em className="text-primary font-semibold">Sebastian Fröhlich</em>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Scroll indicator */}
|
||||||
|
<div className="absolute bottom-10 left-1/2 -translate-x-1/2 animate-bounce z-20">
|
||||||
|
<button
|
||||||
|
onClick={() => document.getElementById('intro')?.scrollIntoView({ behavior: 'smooth' })}
|
||||||
|
className="w-12 h-12 rounded-full bg-primary/20 backdrop-blur-sm border-2 border-primary flex items-center justify-center hover:bg-primary/30 transition-all group"
|
||||||
|
aria-label="Scroll nach unten"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
className="w-6 h-6 text-primary group-hover:translate-y-1 transition-transform"
|
||||||
|
fill="none"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
>
|
||||||
|
<path d="M19 14l-7 7m0 0l-7-7m7 7V3"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,258 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
export default function Intro() {
|
||||||
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
const ref = useRef<HTMLElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const currentRef = ref.current;
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
([entry]) => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
setIsVisible(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ threshold: 0.1 }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (currentRef) {
|
||||||
|
observer.observe(currentRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (currentRef) {
|
||||||
|
observer.unobserve(currentRef);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const highlights = [
|
||||||
|
{ value: '20+', label: 'Jahre Erfahrung' },
|
||||||
|
{ value: '10+', label: 'Jahre Freelancing' },
|
||||||
|
{ value: '9+', label: 'Mitarbeiter geführt' },
|
||||||
|
{ value: '3', label: 'Produkte verantwortet' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const skills = [
|
||||||
|
'Product Owner',
|
||||||
|
'Technical Project Manager',
|
||||||
|
'Laravel',
|
||||||
|
'Vue.js',
|
||||||
|
'PHP',
|
||||||
|
'JavaScript',
|
||||||
|
'MySQL',
|
||||||
|
'MSSQL',
|
||||||
|
'Systemarchitektur',
|
||||||
|
'User Experience',
|
||||||
|
'Team Leadership',
|
||||||
|
'Compliance',
|
||||||
|
];
|
||||||
|
|
||||||
|
const timeline = [
|
||||||
|
{ year: '2021 - heute', company: 'Sopra Financial Technology GmbH', role: 'Technical Product Owner' },
|
||||||
|
{ year: '2019 - 2020', company: 'APPsolute Mobility', role: 'Product Owner & Technical Project Manager' },
|
||||||
|
{ year: '2014 - 2019', company: 'SCC Fahrzeugtechnik GmbH', role: 'Leiter IT Abteilung' },
|
||||||
|
{ year: '2010 - 2014', company: 'Trustec Energy GmbH', role: 'Marketing Manager' },
|
||||||
|
{ year: '2000 - 2010', company: 'Freelancer', role: 'Web Development & Design' },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
id="intro"
|
||||||
|
ref={ref}
|
||||||
|
className={`py-20 px-4 sm:px-6 lg:px-8 bg-white transition-opacity duration-1000 ${
|
||||||
|
isVisible ? 'opacity-100' : 'opacity-0'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="max-w-6xl mx-auto">
|
||||||
|
<h2 className="text-3xl sm:text-4xl font-bold text-text mb-12 text-center relative inline-block w-full after:content-[''] after:block after:w-12 after:h-1 after:bg-primary after:mt-6 after:mx-auto">
|
||||||
|
Über mich
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
{/* Highlights Box */}
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-12">
|
||||||
|
{highlights.map((item, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className={`bg-gradient-to-br from-primary/10 to-primary/5 rounded-lg p-6 text-center border border-primary/20 hover:border-primary/40 transition-all hover:shadow-lg ${
|
||||||
|
isVisible ? 'animate-fade-in' : 'opacity-0'
|
||||||
|
}`}
|
||||||
|
style={{ animationDelay: `${index * 100}ms` }}
|
||||||
|
>
|
||||||
|
<div className="text-3xl sm:text-4xl font-bold text-primary mb-2">
|
||||||
|
{item.value}
|
||||||
|
</div>
|
||||||
|
<div className="text-sm text-text-light font-semibold">
|
||||||
|
{item.label}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Main Text */}
|
||||||
|
<div className="max-w-4xl mx-auto space-y-6 text-text-light leading-relaxed text-base sm:text-lg mb-12">
|
||||||
|
<p>
|
||||||
|
Mein Name ist Sebastian Fröhlich, ich bin 47 Jahre alt und lebe zusammen mit meiner
|
||||||
|
Familie in Neuendettelsau im Landkreis Ansbach.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Von der Diskette zur Cloud durfte ich diesen spannenden und rasanten technischen
|
||||||
|
Wandel miterleben. Besonders die Themen{' '}
|
||||||
|
<strong className="text-text font-semibold">
|
||||||
|
redundante Datenerfassung, Systemarchitektur und User Experience
|
||||||
|
</strong>{' '}
|
||||||
|
haben mich schon immer besonders fasziniert.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Bereits während meiner Berufsausbildung wurde mir die Verantwortung für den
|
||||||
|
Firmenserver (Netware) übertragen.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Für die A-Socks GmbH, einem Unternehmen aus der Textilbranche entwickelte ich einen{' '}
|
||||||
|
<strong className="text-text font-semibold">
|
||||||
|
Shop (HTML/ Javascript/ Actionscript - Flash)
|
||||||
|
</strong>, gestaltete die Verkaufsverpackungen und programmierte ein automatisiertes
|
||||||
|
EAN Vergabe System.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Als Freelancer war ich über 10 Jahre für Unternehmenskunden aus unterschiedlichen
|
||||||
|
Branchen tätig. Mein Fokus lag dabei auf webbasierten Lösungen wie z.B.{' '}
|
||||||
|
<strong className="text-text font-semibold">
|
||||||
|
Präsentations- und Buchungssystemen, CMS-Systemen und Internetshops
|
||||||
|
</strong>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Im Jahr 2010 erhielt ich die Gelegenheit meine Kompetenzen als Marketing Manager für
|
||||||
|
die Trustec Energy GmbH in der Solarbranche einzusetzen. Nach 4 Jahren erhielt ich eine
|
||||||
|
betriebsbedingte Kündigung und wechselte 2014 zur SCC Fahrzeugtechnik GmbH.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Als{' '}
|
||||||
|
<strong className="text-text font-semibold">Leiter der IT Abteilung</strong> war ich
|
||||||
|
hier fachlich und disziplinarisch für 6 Mitarbeiter und 3 Auszubildende verantwortlich.
|
||||||
|
Darüber hinaus entwickelte und programmierte ich ein eigenes Firmen-Intranet{' '}
|
||||||
|
<strong className="text-text font-semibold">
|
||||||
|
(PHP Framework: Laravel, Javascript/ Vue.js, MySql/ MSSQL)
|
||||||
|
</strong>, wartete und migrierte die Server und sorgte für ein funktionierendes Backup-
|
||||||
|
und Sicherheitssystem{' '}
|
||||||
|
<strong className="text-text font-semibold">(Master-Master Replication, BashScript)</strong>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Die nächste Karrierestufe erreichte ich mit meinem Wechsel zu einem Startupunternehmen,
|
||||||
|
wo ich als{' '}
|
||||||
|
<strong className="text-text font-semibold">
|
||||||
|
Product Owner & Technical Project Manager
|
||||||
|
</strong>{' '}
|
||||||
|
für die Firma "APPsolute Mobility" tätig war. Leider konnte das Startup die gesetzten
|
||||||
|
Ziele nicht erreichen, weswegen ich 1 Jahr später zu meinem jetzigen Arbeitgeber wechselte.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Bei der{' '}
|
||||||
|
<strong className="text-text font-semibold">Sopra Financial Technology GmbH</strong> bin
|
||||||
|
ich seit 2021 als{' '}
|
||||||
|
<strong className="text-text font-semibold">Technical Product Owner</strong> im
|
||||||
|
Bereich Regulatory & Risk tätig. Ich verantworte{' '}
|
||||||
|
<strong className="text-text font-semibold">3 Fintech-Produkte</strong> im{' '}
|
||||||
|
<strong className="text-text font-semibold">Bankenmeldewesen</strong> und stelle
|
||||||
|
deren reibungslosen Betrieb unter strikten{' '}
|
||||||
|
<strong className="text-text font-semibold">regulatorischen Vorgaben</strong> sicher.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Zu meinen Kernaufgaben gehören die{' '}
|
||||||
|
<strong className="text-text font-semibold">
|
||||||
|
technische Projektleitung komplexer Migrationen
|
||||||
|
</strong>{' '}
|
||||||
|
(z.B. Kubernetes-Migration ohne Ausfallzeiten), die Steuerung{' '}
|
||||||
|
<strong className="text-text font-semibold">
|
||||||
|
internationaler Teams (inkl. Nearshore)
|
||||||
|
</strong>, Code Reviews sowie die aktive Teilnahme an{' '}
|
||||||
|
<strong className="text-text font-semibold">Cost-Savings-Programmen</strong>.
|
||||||
|
Darüber hinaus arbeite ich in den Bereichen{' '}
|
||||||
|
<strong className="text-text font-semibold">
|
||||||
|
Managed Application & Cloud Service
|
||||||
|
</strong>, wo ich neue Produkte architektonisch begleite und bei
|
||||||
|
Bieterverfahren meine Expertise einbringe.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p className="pt-4 border-t border-gray-200">
|
||||||
|
Mit dieser Präsentation möchte ich die Gelegenheit nutzen, mich als motivierten und
|
||||||
|
kompetenten Bewerber bei Ihrem Unternehmen vorzustellen.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Nachfolgend können Sie sich einen Eindruck über mich und meine abgeschlossenen Projekte{' '}
|
||||||
|
<a
|
||||||
|
href="#portfolio"
|
||||||
|
className="text-primary hover:text-primary-dark font-semibold underline underline-offset-4 transition-colors"
|
||||||
|
>
|
||||||
|
hier
|
||||||
|
</a>{' '}
|
||||||
|
verschaffen. Gerne überzeuge ich Sie auch in einem persönlichen Gespräch von mir.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Timeline */}
|
||||||
|
<div className="mb-12">
|
||||||
|
<h3 className="text-2xl font-bold text-text mb-8 text-center">
|
||||||
|
Karriere-Timeline
|
||||||
|
</h3>
|
||||||
|
<div className="max-w-3xl mx-auto">
|
||||||
|
{timeline.map((item, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className={`relative pl-8 pb-8 border-l-2 border-primary/30 last:border-transparent ${
|
||||||
|
isVisible ? 'animate-fade-in' : 'opacity-0'
|
||||||
|
}`}
|
||||||
|
style={{ animationDelay: `${(index + 4) * 100}ms` }}
|
||||||
|
>
|
||||||
|
{/* Timeline dot */}
|
||||||
|
<div className="absolute -left-[9px] top-0 w-4 h-4 rounded-full bg-primary border-4 border-white shadow-md" />
|
||||||
|
|
||||||
|
<div className="bg-bg-light rounded-lg p-6 hover:shadow-lg transition-shadow">
|
||||||
|
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-start mb-2">
|
||||||
|
<h4 className="text-lg font-bold text-text">{item.role}</h4>
|
||||||
|
<span className="text-sm font-semibold text-primary whitespace-nowrap">
|
||||||
|
{item.year}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-text-light">{item.company}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Skills Tags */}
|
||||||
|
<div className="max-w-4xl mx-auto">
|
||||||
|
<h3 className="text-2xl font-bold text-text mb-6 text-center">
|
||||||
|
Kernkompetenzen
|
||||||
|
</h3>
|
||||||
|
<div className="flex flex-wrap justify-center gap-3">
|
||||||
|
{skills.map((skill, index) => (
|
||||||
|
<span
|
||||||
|
key={index}
|
||||||
|
className={`px-4 py-2 bg-primary/10 text-primary font-semibold rounded-full text-sm border border-primary/20 hover:bg-primary hover:text-white transition-all cursor-default hover:scale-105 ${
|
||||||
|
isVisible ? 'animate-fade-in' : 'opacity-0'
|
||||||
|
}`}
|
||||||
|
style={{ animationDelay: `${(index + timeline.length + 4) * 50}ms` }}
|
||||||
|
>
|
||||||
|
{skill}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,255 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import Image from 'next/image';
|
||||||
|
|
||||||
|
interface Project {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
category: 'web' | 'print';
|
||||||
|
description: string;
|
||||||
|
image: string;
|
||||||
|
details: string[];
|
||||||
|
link?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const projects: Project[] = [
|
||||||
|
{
|
||||||
|
id: 'estev',
|
||||||
|
title: 'e-stev Radsport',
|
||||||
|
category: 'web',
|
||||||
|
description: '2013 für die STEV Radport GmbH in Gunzenhausen wurde die Webseite e-stev von Grund auf neu geschaffen und für ein CMS umgesetzt.',
|
||||||
|
image: '/img/Referenz - e-stev -Web.jpg',
|
||||||
|
details: [
|
||||||
|
'Modernes Responsive Design',
|
||||||
|
'CMS-Integration für einfache Pflege',
|
||||||
|
'Produktkatalog für E-Bikes',
|
||||||
|
'Kontaktformular mit Kartenfunktion',
|
||||||
|
],
|
||||||
|
link: 'https://e-stev.de',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'planet',
|
||||||
|
title: 'Planet-Touristik',
|
||||||
|
category: 'web',
|
||||||
|
description: 'Für Planet-Touristik, das Reisebüro im Nürnberger Norden, wurde die Startseite 2014 einem Redesign unterworfen.',
|
||||||
|
image: '/img/Referenz---Planet-Touristik---web.jpg',
|
||||||
|
details: [
|
||||||
|
'Redesign der Startseite',
|
||||||
|
'Optimierung der User Experience',
|
||||||
|
'Integration in bestehendes System',
|
||||||
|
'Responsive Layout',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'handstaubsauger',
|
||||||
|
title: 'Handstaubsauger24.de',
|
||||||
|
category: 'web',
|
||||||
|
description: 'Für handstaubsauger24.de wurde ein Magento E-Commerce Template gestaltet.',
|
||||||
|
image: '/img/Referenz---handstaubsauger---web.jpg',
|
||||||
|
details: [
|
||||||
|
'Magento Theme Development',
|
||||||
|
'E-Commerce Optimierung',
|
||||||
|
'Produktfilter und Suche',
|
||||||
|
'Mobile-First Ansatz',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'illy',
|
||||||
|
title: 'Illy Caffè Ansbach',
|
||||||
|
category: 'print',
|
||||||
|
description: '2007 für das Illy Caffe in Ansbach entstandener Trifolder als Menükarte.',
|
||||||
|
image: '/img/Referenz---Illy---Print.jpg',
|
||||||
|
details: [
|
||||||
|
'Tri-Folder Design',
|
||||||
|
'Hochwertige Druckvorlagen',
|
||||||
|
'Corporate Design Integration',
|
||||||
|
'Fotografie und Layout',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'sz',
|
||||||
|
title: 'SZ Kirchbirlingen',
|
||||||
|
category: 'print',
|
||||||
|
description: '2008 für die SZ in Kirchbirlingen entstandener Flyer als Wurfsendung.',
|
||||||
|
image: '/img/Referenz---SZ---Print.jpg',
|
||||||
|
details: [
|
||||||
|
'DIN Lang Format',
|
||||||
|
'Wurfsendung Konzept',
|
||||||
|
'Print Design',
|
||||||
|
'Layout und Satz',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'planet-print',
|
||||||
|
title: 'Planet-Touristik Flyer',
|
||||||
|
category: 'print',
|
||||||
|
description: '2014 wurde ein neuer Flyer für Planet Touristik geschaffen.',
|
||||||
|
image: '/img/Referenz---Planet-Touristik---print.jpg',
|
||||||
|
details: [
|
||||||
|
'DIN A5 Format',
|
||||||
|
'Verteiler und Auslage',
|
||||||
|
'Moderne Gestaltung',
|
||||||
|
'Print-Produktion',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Portfolio() {
|
||||||
|
const [activeCategory, setActiveCategory] = useState<'all' | 'web' | 'print'>('all');
|
||||||
|
const [selectedProject, setSelectedProject] = useState<Project | null>(null);
|
||||||
|
const [imageErrors, setImageErrors] = useState<Set<string>>(new Set());
|
||||||
|
|
||||||
|
const filteredProjects =
|
||||||
|
activeCategory === 'all'
|
||||||
|
? projects
|
||||||
|
: projects.filter((p) => p.category === activeCategory);
|
||||||
|
|
||||||
|
const handleImageError = (projectId: string) => {
|
||||||
|
setImageErrors(prev => new Set(prev).add(projectId));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section id="portfolio" className="py-20 px-4 sm:px-6 lg:px-8 bg-white">
|
||||||
|
<div className="max-w-7xl mx-auto">
|
||||||
|
<h2 className="text-3xl sm:text-4xl font-bold text-text text-center mb-6 relative inline-block w-full after:content-[''] after:block after:w-12 after:h-1 after:bg-primary after:mt-6 after:mx-auto">
|
||||||
|
Portfolio
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<p className="text-text-light text-center mb-12 max-w-3xl mx-auto">
|
||||||
|
Zwischen 2000 bis 2010 war ich auch als Freelancer tätig und arbeitete mit Kunden und
|
||||||
|
Agenturen zusammen. Eine Auswahl meiner Arbeiten aus diesem Zeitraum habe ich hier
|
||||||
|
zusammengestellt.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* Filter Buttons */}
|
||||||
|
<div className="flex justify-center gap-4 mb-12">
|
||||||
|
{(['all', 'web', 'print'] as const).map((cat) => (
|
||||||
|
<button
|
||||||
|
key={cat}
|
||||||
|
onClick={() => setActiveCategory(cat)}
|
||||||
|
className={`px-6 py-3 rounded-lg font-semibold transition-all capitalize ${
|
||||||
|
activeCategory === cat
|
||||||
|
? 'bg-primary text-white shadow-lg'
|
||||||
|
: 'bg-gray-100 text-text hover:bg-gray-200'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{cat === 'all' ? 'Alle' : cat === 'web' ? 'Web' : 'Print'}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Projects Grid */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||||
|
{filteredProjects.map((project) => (
|
||||||
|
<div
|
||||||
|
key={project.id}
|
||||||
|
className="group relative overflow-hidden rounded-lg shadow-lg hover:shadow-2xl transition-all duration-300 cursor-pointer bg-white"
|
||||||
|
onClick={() => setSelectedProject(project)}
|
||||||
|
>
|
||||||
|
<div className="relative h-64 bg-gray-200 overflow-hidden">
|
||||||
|
{!imageErrors.has(project.id) ? (
|
||||||
|
<Image
|
||||||
|
src={project.image}
|
||||||
|
alt={project.title}
|
||||||
|
fill
|
||||||
|
className="object-cover group-hover:scale-110 transition-transform duration-300"
|
||||||
|
onError={() => handleImageError(project.id)}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="w-full h-full bg-gradient-to-br from-primary/20 to-primary/5 flex items-center justify-center">
|
||||||
|
<div className="text-center p-4">
|
||||||
|
<svg className="w-16 h-16 mx-auto mb-2 text-primary/40" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||||
|
</svg>
|
||||||
|
<p className="text-sm text-gray-500">{project.title}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/40 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex flex-col justify-end p-6">
|
||||||
|
<h3 className="text-white font-bold text-xl mb-2">{project.title}</h3>
|
||||||
|
<p className="text-white/90 text-sm line-clamp-2">{project.description}</p>
|
||||||
|
<button className="mt-4 text-primary font-semibold hover:text-white transition-colors">
|
||||||
|
Details ansehen →
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="p-4 bg-white">
|
||||||
|
<h3 className="font-bold text-text mb-2">{project.title}</h3>
|
||||||
|
<span className="inline-block px-3 py-1 bg-primary/10 text-primary text-xs font-semibold rounded-full">
|
||||||
|
{project.category === 'web' ? 'Web Design' : 'Print Design'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Modal */}
|
||||||
|
{selectedProject && (
|
||||||
|
<div
|
||||||
|
className="fixed inset-0 bg-black/60 backdrop-blur-sm z-50 flex items-center justify-center p-4"
|
||||||
|
onClick={() => setSelectedProject(null)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="bg-white rounded-lg max-w-2xl w-full max-h-[90vh] overflow-y-auto"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<div className="sticky top-0 bg-white border-b p-4 flex justify-between items-center z-10">
|
||||||
|
<h3 className="text-2xl font-bold text-text">{selectedProject.title}</h3>
|
||||||
|
<button
|
||||||
|
onClick={() => setSelectedProject(null)}
|
||||||
|
className="text-gray-500 hover:text-text transition-colors"
|
||||||
|
>
|
||||||
|
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="p-6">
|
||||||
|
<div className="relative h-64 bg-gray-200 rounded-lg mb-6 overflow-hidden">
|
||||||
|
{!imageErrors.has(selectedProject.id) ? (
|
||||||
|
<Image
|
||||||
|
src={selectedProject.image}
|
||||||
|
alt={selectedProject.title}
|
||||||
|
fill
|
||||||
|
className="object-cover"
|
||||||
|
onError={() => handleImageError(selectedProject.id)}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="w-full h-full bg-gradient-to-br from-primary/20 to-primary/5 flex items-center justify-center">
|
||||||
|
<div className="text-center">
|
||||||
|
<svg className="w-20 h-20 mx-auto mb-2 text-primary/40" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||||
|
</svg>
|
||||||
|
<p className="text-sm text-gray-500">Bild wird geladen...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-text-light mb-6">{selectedProject.description}</p>
|
||||||
|
|
||||||
|
<h4 className="font-bold text-text mb-3">Details:</h4>
|
||||||
|
<ul className="space-y-2 mb-6">
|
||||||
|
{selectedProject.details.map((detail, idx) => (
|
||||||
|
<li key={idx} className="flex items-start">
|
||||||
|
<svg className="w-5 h-5 text-primary mt-0.5 mr-2 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||||
|
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
<span className="text-text-light">{detail}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
interface Skill {
|
||||||
|
name: string;
|
||||||
|
level: number; // 1-5
|
||||||
|
category: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const skillsData: Skill[] = [
|
||||||
|
// Programmiersprachen
|
||||||
|
{ name: 'PHP & FW Laravel', level: 4, category: 'Programmiersprachen' },
|
||||||
|
{ name: 'Python & Perl', level: 4, category: 'Programmiersprachen' },
|
||||||
|
{ name: 'JavaScript', level: 4, category: 'Programmiersprachen' },
|
||||||
|
{ name: 'Node.js', level: 3, category: 'Programmiersprachen' },
|
||||||
|
{ name: 'Vue.js / Next.js', level: 4, category: 'Programmiersprachen' },
|
||||||
|
{ name: 'HTML', level: 5, category: 'Programmiersprachen' },
|
||||||
|
{ name: 'CSS & Frameworks', level: 5, category: 'Programmiersprachen' },
|
||||||
|
{ name: 'Sass', level: 4, category: 'Programmiersprachen' },
|
||||||
|
|
||||||
|
// Datenbanken
|
||||||
|
{ name: 'SQL (MS/DB2/Oracle)', level: 4, category: 'Datenbanken' },
|
||||||
|
{ name: 'MySQL, MariaDB, Postgres', level: 4, category: 'Datenbanken' },
|
||||||
|
{ name: 'Redis', level: 4, category: 'Datenbanken' },
|
||||||
|
{ name: 'MongoDB', level: 3, category: 'Datenbanken' },
|
||||||
|
{ name: 'CouchDB', level: 3, category: 'Datenbanken' },
|
||||||
|
{ name: 'Firebase', level: 1, category: 'Datenbanken' },
|
||||||
|
|
||||||
|
// DevOps
|
||||||
|
{ name: 'Linux Bash Scripting', level: 4, category: 'DevOps' },
|
||||||
|
{ name: 'Git / SVN', level: 4, category: 'DevOps' },
|
||||||
|
{ name: 'Docker / Kubernetes', level: 3, category: 'DevOps' },
|
||||||
|
{ name: 'AWS', level: 3, category: 'DevOps' },
|
||||||
|
{ name: 'CI/CD Pipelines', level: 4, category: 'DevOps' },
|
||||||
|
{ name: 'Draw.io Architektur', level: 4, category: 'DevOps' },
|
||||||
|
|
||||||
|
// Grafik & Design
|
||||||
|
{ name: 'Adobe Suite (u.a. PS/XD)', level: 4, category: 'Grafik & Design' },
|
||||||
|
{ name: 'Affinity', level: 4, category: 'Grafik & Design' },
|
||||||
|
{ name: 'FinalCut', level: 4, category: 'Grafik & Design' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const categories = [
|
||||||
|
'Programmiersprachen',
|
||||||
|
'Datenbanken',
|
||||||
|
'DevOps',
|
||||||
|
'Grafik & Design',
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Skills() {
|
||||||
|
const [activeCategory, setActiveCategory] = useState<string>('Programmiersprachen');
|
||||||
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
const ref = useRef<HTMLElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const currentRef = ref.current;
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
([entry]) => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
setIsVisible(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ threshold: 0.1 }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (currentRef) {
|
||||||
|
observer.observe(currentRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (currentRef) {
|
||||||
|
observer.unobserve(currentRef);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const filteredSkills = skillsData.filter((skill) => skill.category === activeCategory);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
id="skills"
|
||||||
|
ref={ref}
|
||||||
|
className={`py-20 px-4 sm:px-6 lg:px-8 bg-gradient-to-br from-bg-light to-white transition-opacity duration-1000 ${
|
||||||
|
isVisible ? 'opacity-100' : 'opacity-0'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="max-w-6xl mx-auto">
|
||||||
|
<h2 className="text-3xl sm:text-4xl font-bold text-text text-center mb-4 relative inline-block w-full">
|
||||||
|
Technische Fähigkeiten
|
||||||
|
</h2>
|
||||||
|
<p className="text-center text-text-light mb-12 max-w-2xl mx-auto">
|
||||||
|
Umfassende Expertise in modernen Technologien und Frameworks
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* Category Tabs */}
|
||||||
|
<div className="flex flex-wrap justify-center gap-3 mb-12">
|
||||||
|
{categories.map((category, index) => (
|
||||||
|
<button
|
||||||
|
key={category}
|
||||||
|
onClick={() => setActiveCategory(category)}
|
||||||
|
className={`px-5 py-3 rounded-lg font-semibold text-sm transition-all duration-300 ${
|
||||||
|
activeCategory === category
|
||||||
|
? 'bg-primary text-white shadow-lg scale-105'
|
||||||
|
: 'bg-white text-text-light hover:bg-gray-100 hover:text-text shadow-md'
|
||||||
|
} ${isVisible ? 'animate-fade-in' : 'opacity-0'}`}
|
||||||
|
style={{ animationDelay: `${index * 50}ms` }}
|
||||||
|
>
|
||||||
|
{category}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Skills Grid */}
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
{filteredSkills.map((skill, index) => (
|
||||||
|
<div
|
||||||
|
key={skill.name}
|
||||||
|
className={`bg-white rounded-lg p-6 shadow-md hover:shadow-xl transition-all duration-300 hover:-translate-y-1 ${
|
||||||
|
isVisible ? 'animate-fade-in' : 'opacity-0'
|
||||||
|
}`}
|
||||||
|
style={{ animationDelay: `${(index + categories.length) * 50}ms` }}
|
||||||
|
>
|
||||||
|
{/* Skill Name */}
|
||||||
|
<h3 className="font-bold text-text mb-3 text-base">{skill.name}</h3>
|
||||||
|
|
||||||
|
{/* Level Bar */}
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="flex-1 bg-gray-200 rounded-full h-2.5 overflow-hidden">
|
||||||
|
<div
|
||||||
|
className="bg-gradient-to-r from-primary to-primary-dark h-full rounded-full transition-all duration-1000 ease-out"
|
||||||
|
style={{
|
||||||
|
width: isVisible ? `${(skill.level / 5) * 100}%` : '0%',
|
||||||
|
transitionDelay: `${(index + categories.length) * 50 + 200}ms`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span className="text-sm font-bold text-primary min-w-[2rem] text-right">
|
||||||
|
{skill.level}/5
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Level Dots */}
|
||||||
|
<div className="flex gap-1 mt-3">
|
||||||
|
{[1, 2, 3, 4, 5].map((dot) => (
|
||||||
|
<div
|
||||||
|
key={dot}
|
||||||
|
className={`w-2 h-2 rounded-full transition-all duration-300 ${
|
||||||
|
dot <= skill.level ? 'bg-primary' : 'bg-gray-300'
|
||||||
|
}`}
|
||||||
|
style={{
|
||||||
|
transitionDelay: `${(index + categories.length) * 50 + dot * 50}ms`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Info Text */}
|
||||||
|
<div className="mt-12 text-center">
|
||||||
|
<p className="text-text-light text-sm">
|
||||||
|
<strong className="text-primary">Bewertungsskala:</strong> 1 = Grundkenntnisse | 5 = Expertenwissen
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
interface SoftSkill {
|
||||||
|
name: string;
|
||||||
|
level: number; // 1-5
|
||||||
|
icon: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const softSkills: SoftSkill[] = [
|
||||||
|
{ name: 'Organisation', level: 4, icon: '📋' },
|
||||||
|
{ name: 'Kommunikation', level: 5, icon: '💬' },
|
||||||
|
{ name: 'Selbstständigkeit', level: 4, icon: '🎯' },
|
||||||
|
{ name: 'Teamfähigkeit', level: 5, icon: '🤝' },
|
||||||
|
{ name: 'Verantwortung', level: 5, icon: '✓' },
|
||||||
|
{ name: 'Engagement', level: 5, icon: '🚀' },
|
||||||
|
{ name: 'Kompromissbereitschaft', level: 4, icon: '🤔' },
|
||||||
|
{ name: 'Aufgeschlossenheit', level: 5, icon: '🌟' },
|
||||||
|
{ name: 'Lernbereitschaft', level: 5, icon: '📚' },
|
||||||
|
{ name: 'Zielstrebigkeit', level: 5, icon: '🎯' },
|
||||||
|
{ name: 'Überzeugungsfähigkeit', level: 4, icon: '💡' },
|
||||||
|
{ name: 'Lösungsorientiert', level: 5, icon: '🔧' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function SoftSkills() {
|
||||||
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
const ref = useRef<HTMLElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const currentRef = ref.current;
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
([entry]) => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
setIsVisible(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ threshold: 0.1 }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (currentRef) {
|
||||||
|
observer.observe(currentRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (currentRef) {
|
||||||
|
observer.unobserve(currentRef);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
id="soft-skills"
|
||||||
|
ref={ref}
|
||||||
|
className={`py-20 px-4 sm:px-6 lg:px-8 bg-white transition-opacity duration-1000 ${
|
||||||
|
isVisible ? 'opacity-100' : 'opacity-0'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="max-w-6xl mx-auto">
|
||||||
|
<h2 className="text-3xl sm:text-4xl font-bold text-text text-center mb-4 relative inline-block w-full">
|
||||||
|
Persönliche Fähigkeiten
|
||||||
|
</h2>
|
||||||
|
<p className="text-center text-text-light mb-12 max-w-2xl mx-auto">
|
||||||
|
Soft Skills, die mich als Teamplayer und Leader auszeichnen
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* Skills Grid */}
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
|
||||||
|
{softSkills.map((skill, index) => (
|
||||||
|
<div
|
||||||
|
key={skill.name}
|
||||||
|
className={`group bg-gradient-to-br from-white to-bg-light rounded-xl p-6 shadow-md hover:shadow-2xl transition-all duration-300 hover:-translate-y-2 border border-gray-100 hover:border-primary/30 ${
|
||||||
|
isVisible ? 'animate-fade-in' : 'opacity-0'
|
||||||
|
}`}
|
||||||
|
style={{ animationDelay: `${index * 50}ms` }}
|
||||||
|
>
|
||||||
|
{/* Icon */}
|
||||||
|
<div className="text-4xl mb-4 group-hover:scale-110 transition-transform duration-300">
|
||||||
|
{skill.icon}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Skill Name */}
|
||||||
|
<h3 className="font-bold text-text mb-3 text-base group-hover:text-primary transition-colors">
|
||||||
|
{skill.name}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
{/* Level Dots */}
|
||||||
|
<div className="flex gap-1.5">
|
||||||
|
{[1, 2, 3, 4, 5].map((dot) => (
|
||||||
|
<div
|
||||||
|
key={dot}
|
||||||
|
className={`w-2.5 h-2.5 rounded-full transition-all duration-300 ${
|
||||||
|
dot <= skill.level
|
||||||
|
? 'bg-primary group-hover:scale-125'
|
||||||
|
: 'bg-gray-300'
|
||||||
|
}`}
|
||||||
|
style={{
|
||||||
|
transitionDelay: `${index * 50 + dot * 30}ms`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Hover Effect - Level Text */}
|
||||||
|
<div className="mt-3 transition-opacity duration-300">
|
||||||
|
<span className="text-xs text-primary font-semibold">
|
||||||
|
{skill.level === 5 ? 'Expertenlevel' : skill.level === 4 ? 'Sehr gut' : 'Gut'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Bottom Info */}
|
||||||
|
<div className="mt-16 bg-gradient-to-r from-primary/5 via-primary/10 to-primary/5 rounded-xl p-8 text-center">
|
||||||
|
<h3 className="text-xl font-bold text-text mb-4">
|
||||||
|
Warum diese Fähigkeiten wichtig sind
|
||||||
|
</h3>
|
||||||
|
<p className="text-text-light leading-relaxed max-w-3xl mx-auto">
|
||||||
|
In über 20 Jahren Berufserfahrung habe ich gelernt, dass technisches Know-how nur die
|
||||||
|
halbe Miete ist. Erfolgreiche Projekte entstehen durch{' '}
|
||||||
|
<strong className="text-primary">klare Kommunikation</strong>,
|
||||||
|
<strong className="text-primary"> Teamarbeit</strong> und die Fähigkeit, auch in
|
||||||
|
stressigen Situationen <strong className="text-primary">lösungsorientiert</strong> zu bleiben.
|
||||||
|
Diese Soft Skills ermöglichen es mir, komplexe technische Anforderungen verständlich zu
|
||||||
|
vermitteln und Teams erfolgreich zu führen.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Script zum Kopieren der Assets aus dem alten Projekt
|
||||||
|
|
||||||
|
echo "🚀 Kopiere Assets aus dem alten beWerbung Projekt..."
|
||||||
|
|
||||||
|
OLD_PROJECT="/Users/sebastianfrohlich/Projekte/bewerbung"
|
||||||
|
NEW_PROJECT="/Users/sebastianfrohlich/Projekte/bewerbung2025/bewerbung/public"
|
||||||
|
|
||||||
|
# Bilder kopieren
|
||||||
|
echo "📸 Kopiere Bilder..."
|
||||||
|
mkdir -p "$NEW_PROJECT/img"
|
||||||
|
cp -r "$OLD_PROJECT/img/"*.jpg "$NEW_PROJECT/img/" 2>/dev/null || true
|
||||||
|
cp -r "$OLD_PROJECT/img/"*.png "$NEW_PROJECT/img/" 2>/dev/null || true
|
||||||
|
cp -r "$OLD_PROJECT/img/"*.svg "$NEW_PROJECT/img/" 2>/dev/null || true
|
||||||
|
|
||||||
|
# Downloads kopieren
|
||||||
|
echo "📄 Kopiere PDFs..."
|
||||||
|
mkdir -p "$NEW_PROJECT/downloads"
|
||||||
|
cp -r "$OLD_PROJECT/downloads/"*.pdf "$NEW_PROJECT/downloads/" 2>/dev/null || true
|
||||||
|
|
||||||
|
# Workspace Hintergrundbild
|
||||||
|
echo "🖼️ Kopiere Workspace Hintergrund..."
|
||||||
|
cp "$OLD_PROJECT/img/Workspace.png" "$NEW_PROJECT/img/workspace-bg.jpg" 2>/dev/null || true
|
||||||
|
cp "$OLD_PROJECT/img/keyboard-bg.jpg" "$NEW_PROJECT/img/" 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "✅ Fertig! Assets wurden kopiert."
|
||||||
|
echo ""
|
||||||
|
echo "📋 Nächste Schritte:"
|
||||||
|
echo "1. npm run dev - Development Server starten"
|
||||||
|
echo "2. Öffne http://localhost:3000"
|
||||||
|
echo "3. Prüfe ob alle Bilder korrekt angezeigt werden"
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
# 📧 E-Mail Bewerbungsvorlage 2025
|
||||||
|
|
||||||
|
Moderne, responsive HTML E-Mail-Vorlage für Bewerbungen - perfekt abgestimmt auf die Webseite apply4jobs.de/bewerbung/
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Was wurde aktualisiert?
|
||||||
|
|
||||||
|
### ✅ **Alle wichtigen Daten auf 2025 aktualisiert:**
|
||||||
|
|
||||||
|
| Kategorie | Alt (2014) | Neu (2025) |
|
||||||
|
|-----------|------------|------------|
|
||||||
|
| **Alter** | 36 Jahre | **46 Jahre** ✅ |
|
||||||
|
| **Position** | Marketing Manager | **Technical Product Owner** ✅ |
|
||||||
|
| **Firma** | Trustec Energy | **Sopra Financial Technology** ✅ |
|
||||||
|
| **Erfahrung** | Webentwicklung, Marketing | **Kubernetes, Cloud, DevOps** ✅ |
|
||||||
|
| **Downloads** | Dropbox 2014 | **apply4jobs.de/bewerbung/** ✅ |
|
||||||
|
| **Webseite** | uberspace.de (alt) | **apply4jobs.de/bewerbung/** ✅ |
|
||||||
|
| **Telefon** | +49 9874 322 429 | **0157 324 699 60** ✅ |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎨 Design-Features:
|
||||||
|
|
||||||
|
✅ **Moderne Farbpalette:**
|
||||||
|
- Primary: `#e63946` (Rot - passend zur Webseite)
|
||||||
|
- Text: `#1d3557` (Dunkelblau)
|
||||||
|
- Gradient Header: `#1d3557` → `#457b9d`
|
||||||
|
|
||||||
|
✅ **Responsive Design:**
|
||||||
|
- Mobile-optimiert (stacked layout auf kleinen Bildschirmen)
|
||||||
|
- Funktioniert in allen gängigen E-Mail-Clients
|
||||||
|
|
||||||
|
✅ **Strukturiert:**
|
||||||
|
1. Header mit Positionsangabe
|
||||||
|
2. Begrüßung + Kurzvorstellung
|
||||||
|
3. Highlight-Box "Warum ich?"
|
||||||
|
4. Aktuelle Position (4 Info-Boxen)
|
||||||
|
5. Download-Buttons (Lebenslauf, Zeugnisse, Referenzen)
|
||||||
|
6. Online-Bewerbung Button
|
||||||
|
7. Kontaktdaten (3-spaltig)
|
||||||
|
8. Abschluss + Footer
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Verwendung:
|
||||||
|
|
||||||
|
### **Schritt 1: Position anpassen**
|
||||||
|
```html
|
||||||
|
<!-- Zeile 44: -->
|
||||||
|
<p style="color: rgba(255, 255, 255, 0.9); margin: 0; font-size: 18px;">
|
||||||
|
[Position einfügen] ← Hier die Stelle eintragen
|
||||||
|
</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Schritt 2: Anrede anpassen**
|
||||||
|
```html
|
||||||
|
<!-- Zeile 52: -->
|
||||||
|
<p style="color: #1d3557; font-size: 16px; line-height: 1.6; margin: 0 0 20px 0;">
|
||||||
|
Sehr geehrte Damen und Herren, ← Bei Bedarf personalisieren
|
||||||
|
</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Schritt 3: E-Mail versenden**
|
||||||
|
|
||||||
|
**Option A: Als HTML-Mail versenden**
|
||||||
|
- Öffne `bewerbung-2025.html` im Browser
|
||||||
|
- Kopiere den kompletten Quelltext
|
||||||
|
- Füge ihn in dein E-Mail-Programm ein (HTML-Modus)
|
||||||
|
|
||||||
|
**Option B: In E-Mail-Client importieren**
|
||||||
|
- Thunderbird: "Einfügen" → "HTML"
|
||||||
|
- Gmail: Erweiterungen wie "Compose" verwenden
|
||||||
|
- Outlook: "Datei" → "HTML einfügen"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📥 Download-Links:
|
||||||
|
|
||||||
|
Die E-Mail enthält Links zu:
|
||||||
|
- ✅ https://apply4jobs.de/bewerbung/downloads/Lebenslauf_2025.pdf
|
||||||
|
- ✅ https://apply4jobs.de/bewerbung/downloads/Zeugnisse_2025.pdf
|
||||||
|
- ✅ https://apply4jobs.de/bewerbung/downloads/Referenzen.pdf
|
||||||
|
- ✅ https://apply4jobs.de/bewerbung/ (Online-Bewerbung)
|
||||||
|
|
||||||
|
**Wichtig:** Stelle sicher, dass diese PDFs auf dem Server liegen!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 Testen:
|
||||||
|
|
||||||
|
### **1. Browser-Test:**
|
||||||
|
```bash
|
||||||
|
# Öffne die Datei im Browser:
|
||||||
|
open email-template/bewerbung-2025.html
|
||||||
|
```
|
||||||
|
|
||||||
|
### **2. E-Mail-Client-Test:**
|
||||||
|
Sende eine Test-E-Mail an dich selbst und prüfe:
|
||||||
|
- ✅ Layout korrekt (Desktop + Mobile)
|
||||||
|
- ✅ Alle Links funktionieren
|
||||||
|
- ✅ Buttons sind klickbar
|
||||||
|
- ✅ Farben werden richtig angezeigt
|
||||||
|
|
||||||
|
### **3. Online-Tools:**
|
||||||
|
- [Litmus](https://litmus.com/) - E-Mail-Preview in 90+ Clients
|
||||||
|
- [Email on Acid](https://www.emailonacid.com/) - E-Mail-Testing
|
||||||
|
- [Mail Tester](https://www.mail-tester.com/) - Spam-Score prüfen
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Highlights der neuen E-Mail:
|
||||||
|
|
||||||
|
### **Inhaltlich:**
|
||||||
|
✅ Alter korrekt (46 statt 36)
|
||||||
|
✅ Aktuelle Position (Technical Product Owner)
|
||||||
|
✅ Moderne Skills (Kubernetes, Cloud, DevOps)
|
||||||
|
✅ Bankenmeldewesen erwähnt
|
||||||
|
✅ Nearshore-Teams erwähnt
|
||||||
|
✅ 20+ Jahre Erfahrung hervorgehoben
|
||||||
|
|
||||||
|
### **Visuell:**
|
||||||
|
✅ Moderne, cleane Optik
|
||||||
|
✅ Gradient-Header
|
||||||
|
✅ Highlight-Box mit rotem Akzent
|
||||||
|
✅ Icon-Boxen (📍 📱 ✉️)
|
||||||
|
✅ Call-to-Action Buttons
|
||||||
|
✅ Responsive für Mobile
|
||||||
|
|
||||||
|
### **Technisch:**
|
||||||
|
✅ Alle Links aktualisiert (2025)
|
||||||
|
✅ Korrekte Telefonnummer
|
||||||
|
✅ Funktionierende Download-Links
|
||||||
|
✅ E-Mail-Client kompatibel
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Personalisierungs-Tipps:
|
||||||
|
|
||||||
|
### **Für verschiedene Bewerbungen:**
|
||||||
|
|
||||||
|
1. **Position anpassen** (Zeile 44)
|
||||||
|
2. **Anrede personalisieren** (Zeile 52)
|
||||||
|
3. **Highlight-Box anpassen** (Zeile 70-79)
|
||||||
|
- Betone Skills, die für die Stelle wichtig sind
|
||||||
|
|
||||||
|
### **Beispiele:**
|
||||||
|
|
||||||
|
**Für DevOps-Position:**
|
||||||
|
```html
|
||||||
|
<li>Kubernetes & Docker Expertise</li>
|
||||||
|
<li>CI/CD Pipelines (GitLab, Jenkins)</li>
|
||||||
|
<li>AWS & Cloud Infrastructure</li>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Für Product Owner Position:**
|
||||||
|
```html
|
||||||
|
<li>Agile Methoden (Scrum, Kanban)</li>
|
||||||
|
<li>Stakeholder Management</li>
|
||||||
|
<li>Technical Background</li>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🆚 Vergleich Alt vs. Neu:
|
||||||
|
|
||||||
|
| Feature | Alt (2014) | Neu (2025) |
|
||||||
|
|---------|------------|------------|
|
||||||
|
| Alter | 36 (falsch!) | 46 ✅ |
|
||||||
|
| Position | Marketing Manager | Technical Product Owner ✅ |
|
||||||
|
| Skills | Newsletter, Print | Kubernetes, Cloud ✅ |
|
||||||
|
| Links | Dropbox, uberspace | apply4jobs.de ✅ |
|
||||||
|
| Design | Template-basiert | Custom, modern ✅ |
|
||||||
|
| Responsive | Ja | Ja, verbessert ✅ |
|
||||||
|
| Farbschema | Grau/Türkis | Blau/Rot (Webseite) ✅ |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📞 Kontakt in der E-Mail:
|
||||||
|
|
||||||
|
```
|
||||||
|
📍 Rosenstraße 4, 91564 Neuendettelsau
|
||||||
|
📱 0157 324 699 60
|
||||||
|
✉️ froehlich.sebastian@gmail.com
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ Wichtige Hinweise:
|
||||||
|
|
||||||
|
1. **Vor dem Versenden:**
|
||||||
|
- [ ] Position eingefügt
|
||||||
|
- [ ] Anrede personalisiert
|
||||||
|
- [ ] Test-Mail versendet
|
||||||
|
- [ ] Links geprüft
|
||||||
|
- [ ] Mobile-Ansicht getestet
|
||||||
|
|
||||||
|
2. **Dateiname beim Versenden:**
|
||||||
|
- Speichere keine Anhänge, alle Dokumente sind verlinkt
|
||||||
|
- Falls doch Anhänge: `Bewerbung_Sebastian_Froehlich_[Position].pdf`
|
||||||
|
|
||||||
|
3. **Betreff-Vorschlag:**
|
||||||
|
- `Bewerbung als [Position] - Sebastian Fröhlich`
|
||||||
|
- `Initiativbewerbung - Technical Product Owner - Sebastian Fröhlich`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎉 Fertig!
|
||||||
|
|
||||||
|
Die E-Mail ist bereit zum Versenden. Viel Erfolg bei deiner Bewerbung! 🚀
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Erstellt:** Oktober 2025
|
||||||
|
**Version:** 1.0
|
||||||
|
**Datei:** `bewerbung-2025.html`
|
||||||
@@ -0,0 +1,312 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<title>Bewerbung von Sebastian Fröhlich - Technical Product Owner</title>
|
||||||
|
<style type="text/css">
|
||||||
|
/* RESET */
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100% !important;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
outline: none;
|
||||||
|
text-decoration: none;
|
||||||
|
border: none;
|
||||||
|
-ms-interpolation-mode: bicubic;
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
mso-table-lspace: 0pt;
|
||||||
|
mso-table-rspace: 0pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media only screen and (max-width: 600px) {
|
||||||
|
.container {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-padding {
|
||||||
|
padding: 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stack {
|
||||||
|
display: block !important;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body style="margin: 0; padding: 0; background-color: #f8f9fa;">
|
||||||
|
<table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #f8f9fa;">
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="padding: 20px 0;">
|
||||||
|
|
||||||
|
<!-- Main Container -->
|
||||||
|
<table class="container" width="600" border="0" cellspacing="0" cellpadding="0" style="background-color: #ffffff; border-radius: 12px; overflow: hidden; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<tr>
|
||||||
|
<td style="background: linear-gradient(135deg, #1d3557 0%, #457b9d 100%); padding: 40px 30px; text-align: center;">
|
||||||
|
<h1 style="color: #ffffff; margin: 0 0 10px 0; font-size: 28px; font-weight: bold;">
|
||||||
|
Bewerbung als
|
||||||
|
</h1>
|
||||||
|
<p style="color: rgba(255, 255, 255, 0.9); margin: 0; font-size: 18px;">
|
||||||
|
[Position einfügen]
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Greeting -->
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 30px 30px 20px 30px;">
|
||||||
|
<p style="color: #1d3557; font-size: 16px; line-height: 1.6; margin: 0 0 20px 0;">
|
||||||
|
Sehr geehrte Damen und Herren,
|
||||||
|
</p>
|
||||||
|
<p style="color: #6c757d; font-size: 16px; line-height: 1.6; margin: 0;">
|
||||||
|
mein Name ist <strong style="color: #1d3557;">Sebastian Fröhlich</strong>, ich bin <strong>46 Jahre</strong> alt und arbeite seit 2021 als <strong style="color: #e63946;">Technical Product Owner</strong> im Bereich Financial Technology. Mit über <strong>20 Jahren IT-Erfahrung</strong> bringe ich umfassende Expertise in modernen Technologien und Projektmanagement mit.
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Highlight Box -->
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 0 30px 30px 30px;">
|
||||||
|
<table width="100%" border="0" cellspacing="0" cellpadding="0" style="background: linear-gradient(135deg, rgba(230, 57, 70, 0.1) 0%, rgba(230, 57, 70, 0.05) 100%); border-left: 4px solid #e63946; border-radius: 8px;">
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 25px;">
|
||||||
|
<h2 style="color: #1d3557; font-size: 20px; margin: 0 0 15px 0;">
|
||||||
|
🎯 Warum ich die richtige Wahl bin
|
||||||
|
</h2>
|
||||||
|
<ul style="color: #6c757d; font-size: 15px; line-height: 1.8; margin: 0; padding-left: 20px;">
|
||||||
|
<li style="margin-bottom: 8px;"><strong style="color: #1d3557;">20+ Jahre IT-Erfahrung</strong> – von der Diskette zur Cloud</li>
|
||||||
|
<li style="margin-bottom: 8px;"><strong style="color: #1d3557;">Technical Product Owner</strong> für 3 Fintech-Produkte im Bankenmeldewesen</li>
|
||||||
|
<li style="margin-bottom: 8px;"><strong style="color: #1d3557;">Kubernetes & Cloud Expertise</strong> – erfolgreiche Migration ohne Ausfallzeiten</li>
|
||||||
|
<li style="margin-bottom: 8px;"><strong style="color: #1d3557;">Team Leadership</strong> – Steuerung internationaler Teams (inkl. Nearshore)</li>
|
||||||
|
<li style="margin-bottom: 8px;"><strong style="color: #1d3557;">Full-Stack Know-how</strong> – PHP/Laravel, Vue.js, DevOps, Systemarchitektur</li>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Divider -->
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 0 30px;">
|
||||||
|
<hr style="border: none; border-top: 2px solid #e9ecef; margin: 0;">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Key Facts Section -->
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 30px;">
|
||||||
|
<h2 style="color: #1d3557; font-size: 20px; margin: 0 0 20px 0; text-align: center;">
|
||||||
|
💼 Meine aktuelle Position
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<!-- Facts Grid -->
|
||||||
|
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||||
|
<tr>
|
||||||
|
<td class="stack" width="50%" style="padding: 10px; vertical-align: top;">
|
||||||
|
<table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #f8f9fa; border-radius: 8px;">
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 20px; text-align: center;">
|
||||||
|
<div style="font-size: 32px; margin-bottom: 10px;">🏢</div>
|
||||||
|
<p style="color: #1d3557; font-weight: bold; margin: 0 0 5px 0; font-size: 14px;">Unternehmen</p>
|
||||||
|
<p style="color: #6c757d; margin: 0; font-size: 13px;">Sopra Financial Technology GmbH</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
<td class="stack" width="50%" style="padding: 10px; vertical-align: top;">
|
||||||
|
<table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #f8f9fa; border-radius: 8px;">
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 20px; text-align: center;">
|
||||||
|
<div style="font-size: 32px; margin-bottom: 10px;">⚙️</div>
|
||||||
|
<p style="color: #1d3557; font-weight: bold; margin: 0 0 5px 0; font-size: 14px;">Position</p>
|
||||||
|
<p style="color: #6c757d; margin: 0; font-size: 13px;">Technical Product Owner</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="stack" width="50%" style="padding: 10px; vertical-align: top;">
|
||||||
|
<table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #f8f9fa; border-radius: 8px;">
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 20px; text-align: center;">
|
||||||
|
<div style="font-size: 32px; margin-bottom: 10px;">📊</div>
|
||||||
|
<p style="color: #1d3557; font-weight: bold; margin: 0 0 5px 0; font-size: 14px;">Verantwortung</p>
|
||||||
|
<p style="color: #6c757d; margin: 0; font-size: 13px;">3 Produkte im Bankenmeldewesen</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
<td class="stack" width="50%" style="padding: 10px; vertical-align: top;">
|
||||||
|
<table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #f8f9fa; border-radius: 8px;">
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 20px; text-align: center;">
|
||||||
|
<div style="font-size: 32px; margin-bottom: 10px;">🚀</div>
|
||||||
|
<p style="color: #1d3557; font-weight: bold; margin: 0 0 5px 0; font-size: 14px;">Highlights</p>
|
||||||
|
<p style="color: #6c757d; margin: 0; font-size: 13px;">K8s-Migration, Code Reviews</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Divider -->
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 0 30px;">
|
||||||
|
<hr style="border: none; border-top: 2px solid #e9ecef; margin: 0;">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Downloads Section -->
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 30px;">
|
||||||
|
<h2 style="color: #1d3557; font-size: 20px; margin: 0 0 20px 0; text-align: center;">
|
||||||
|
📥 Meine Bewerbungsunterlagen
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<!-- Download Buttons -->
|
||||||
|
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 10px; text-align: center;">
|
||||||
|
<a href="https://apply4jobs.de/bewerbung/downloads/Lebenslauf_2025.pdf" style="background-color: #e63946; color: #ffffff; padding: 14px 28px; text-decoration: none; border-radius: 8px; display: inline-block; font-weight: bold; font-size: 15px;">
|
||||||
|
📄 Lebenslauf 2025
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 10px; text-align: center;">
|
||||||
|
<a href="https://apply4jobs.de/bewerbung/downloads/Zeugnisse_2025.pdf" style="background-color: #457b9d; color: #ffffff; padding: 14px 28px; text-decoration: none; border-radius: 8px; display: inline-block; font-weight: bold; font-size: 15px;">
|
||||||
|
📜 Arbeitszeugnisse 2025
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 10px; text-align: center;">
|
||||||
|
<a href="https://apply4jobs.de/bewerbung/downloads/Referenzen.pdf" style="background-color: #457b9d; color: #ffffff; padding: 14px 28px; text-decoration: none; border-radius: 8px; display: inline-block; font-weight: bold; font-size: 15px;">
|
||||||
|
⭐ Referenzen
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 20px 10px 10px 10px; text-align: center;">
|
||||||
|
<a href="https://apply4jobs.de/bewerbung/" style="background: linear-gradient(135deg, #e63946 0%, #d62839 100%); color: #ffffff; padding: 16px 32px; text-decoration: none; border-radius: 8px; display: inline-block; font-weight: bold; font-size: 16px; box-shadow: 0 4px 6px rgba(230, 57, 70, 0.3);">
|
||||||
|
🌐 Vollständige Online-Bewerbung ansehen
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Divider -->
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 0 30px;">
|
||||||
|
<hr style="border: none; border-top: 2px solid #e9ecef; margin: 0;">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Contact Section -->
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 30px;">
|
||||||
|
<h2 style="color: #1d3557; font-size: 20px; margin: 0 0 20px 0; text-align: center;">
|
||||||
|
📞 Kontakt
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||||
|
<tr>
|
||||||
|
<td class="stack" width="33.33%" style="padding: 10px; vertical-align: top;">
|
||||||
|
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||||
|
<tr>
|
||||||
|
<td style="text-align: center;">
|
||||||
|
<div style="font-size: 32px; margin-bottom: 10px;">📍</div>
|
||||||
|
<p style="color: #1d3557; font-weight: bold; margin: 0 0 5px 0; font-size: 13px;">Adresse</p>
|
||||||
|
<p style="color: #6c757d; margin: 0; font-size: 12px; line-height: 1.5;">
|
||||||
|
Rosenstraße 4<br>
|
||||||
|
91564 Neuendettelsau
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
<td class="stack" width="33.33%" style="padding: 10px; vertical-align: top;">
|
||||||
|
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||||
|
<tr>
|
||||||
|
<td style="text-align: center;">
|
||||||
|
<div style="font-size: 32px; margin-bottom: 10px;">📱</div>
|
||||||
|
<p style="color: #1d3557; font-weight: bold; margin: 0 0 5px 0; font-size: 13px;">Telefon</p>
|
||||||
|
<p style="color: #6c757d; margin: 0; font-size: 12px;">
|
||||||
|
<a href="tel:+4915732469960" style="color: #e63946; text-decoration: none;">0157 324 699 60</a>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
<td class="stack" width="33.33%" style="padding: 10px; vertical-align: top;">
|
||||||
|
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||||
|
<tr>
|
||||||
|
<td style="text-align: center;">
|
||||||
|
<div style="font-size: 32px; margin-bottom: 10px;">✉️</div>
|
||||||
|
<p style="color: #1d3557; font-weight: bold; margin: 0 0 5px 0; font-size: 13px;">E-Mail</p>
|
||||||
|
<p style="color: #6c757d; margin: 0; font-size: 12px;">
|
||||||
|
<a href="mailto:froehlich.sebastian@gmail.com" style="color: #e63946; text-decoration: none;">froehlich.sebastian@gmail.com</a>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Closing -->
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 0 30px 30px 30px;">
|
||||||
|
<p style="color: #6c757d; font-size: 15px; line-height: 1.6; margin: 0;">
|
||||||
|
Ich freue mich darauf, Sie in einem persönlichen Gespräch von meinen Fähigkeiten zu überzeugen und mehr über die Position zu erfahren.
|
||||||
|
</p>
|
||||||
|
<p style="color: #6c757d; font-size: 15px; line-height: 1.6; margin: 15px 0 0 0;">
|
||||||
|
Mit freundlichen Grüßen<br>
|
||||||
|
<strong style="color: #1d3557;">Sebastian Fröhlich</strong>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<tr>
|
||||||
|
<td style="background-color: #f8f9fa; padding: 20px 30px; text-align: center; border-top: 1px solid #e9ecef;">
|
||||||
|
<p style="color: #6c757d; font-size: 11px; line-height: 1.5; margin: 0;">
|
||||||
|
Diese E-Mail wurde als responsive HTML-Mail erstellt.<br>
|
||||||
|
Falls die Darstellung nicht korrekt ist, können Sie die
|
||||||
|
<a href="https://apply4jobs.de/bewerbung/" style="color: #e63946; text-decoration: underline;">Online-Version</a> aufrufen.
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { dirname } from "path";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
import { FlatCompat } from "@eslint/eslintrc";
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
|
const compat = new FlatCompat({
|
||||||
|
baseDirectory: __dirname,
|
||||||
|
});
|
||||||
|
|
||||||
|
const eslintConfig = [
|
||||||
|
...compat.extends("next/core-web-vitals", "next/typescript"),
|
||||||
|
{
|
||||||
|
ignores: [
|
||||||
|
"node_modules/**",
|
||||||
|
".next/**",
|
||||||
|
"out/**",
|
||||||
|
"build/**",
|
||||||
|
"next-env.d.ts",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default eslintConfig;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import type { NextConfig } from "next";
|
||||||
|
|
||||||
|
const nextConfig: NextConfig = {
|
||||||
|
output: 'export', // Statischer Export aktivieren
|
||||||
|
images: {
|
||||||
|
unoptimized: true, // Next.js Image Optimierung deaktivieren (für statischen Export nötig)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default nextConfig;
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"name": "bewerbung",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next dev --turbopack",
|
||||||
|
"build": "next build --turbopack",
|
||||||
|
"start": "next start",
|
||||||
|
"lint": "eslint",
|
||||||
|
"copy-assets": "bash copy-assets.sh"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"react": "19.1.0",
|
||||||
|
"react-dom": "19.1.0",
|
||||||
|
"next": "15.5.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5",
|
||||||
|
"@types/node": "^20",
|
||||||
|
"@types/react": "^19",
|
||||||
|
"@types/react-dom": "^19",
|
||||||
|
"@tailwindcss/postcss": "^4",
|
||||||
|
"tailwindcss": "^4",
|
||||||
|
"eslint": "^9",
|
||||||
|
"eslint-config-next": "15.5.4",
|
||||||
|
"@eslint/eslintrc": "^3"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
const config = {
|
||||||
|
plugins: ["@tailwindcss/postcss"],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
|
||||||
|
After Width: | Height: | Size: 391 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 91 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 306 KiB |
|
After Width: | Height: | Size: 204 KiB |
|
After Width: | Height: | Size: 72 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
|
||||||
|
After Width: | Height: | Size: 128 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
|
||||||
|
After Width: | Height: | Size: 385 B |
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2017",
|
||||||
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"incremental": true,
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "next"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
||||||