diff --git a/package-lock.json b/package-lock.json
index 6717e11..714bf56 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,7 +10,8 @@
"dependencies": {
"lucide-react": "^0.539.0",
"react": "^19.1.1",
- "react-dom": "^19.1.1"
+ "react-dom": "^19.1.1",
+ "react-icons": "^5.5.0"
},
"devDependencies": {
"@eslint/js": "^9.32.0",
@@ -3255,6 +3256,15 @@
"react": "^19.1.1"
}
},
+ "node_modules/react-icons": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",
+ "integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
"node_modules/react-refresh": {
"version": "0.17.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
diff --git a/package.json b/package.json
index 4a7e1cb..600a113 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,8 @@
"dependencies": {
"lucide-react": "^0.539.0",
"react": "^19.1.1",
- "react-dom": "^19.1.1"
+ "react-dom": "^19.1.1",
+ "react-icons": "^5.5.0"
},
"devDependencies": {
"@eslint/js": "^9.32.0",
diff --git a/src/app/page.tsx b/src/app/page.tsx
index be41457..ba27db2 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -4,6 +4,11 @@ import Navbar from '../components/layout/Navigation';
import HeroSection from '../components/sections/HeroSection';
import AboutSection from '../components/sections/AboutSection';
import ServicesSection from '../components/sections/ServicesSection';
+import SkillsSection from '../components/sections/SkillsSection';
+import CertificationsSection from '../components/sections/CertificationsSection';
+import ProjectsSection from '../components/sections/ProjectsSection';
+import ContactSection from '../components/sections/ContactSection';
+import Footer from '../components/layout/Footer';
function PortfolioApp() {
const [theme, setTheme] = useState<'light' | 'dark'>('light');
@@ -18,6 +23,11 @@ function PortfolioApp() {
+
+
+
+
+
>
);
}
diff --git a/src/components/layout/Footer.tsx b/src/components/layout/Footer.tsx
new file mode 100644
index 0000000..f998715
--- /dev/null
+++ b/src/components/layout/Footer.tsx
@@ -0,0 +1,50 @@
+import { Github, Linkedin, Mail } from 'lucide-react';
+import { personalConfig, createEmailLink } from '../../config/personal';
+
+export default function Footer() {
+ // Email obfuscation function using config
+ const handleEmailClick = (e: React.MouseEvent) => {
+ e.preventDefault();
+ window.location.href = createEmailLink();
+ };
+
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/layout/Navigation.tsx b/src/components/layout/Navigation.tsx
index 06c46d7..9afe37b 100644
--- a/src/components/layout/Navigation.tsx
+++ b/src/components/layout/Navigation.tsx
@@ -1,6 +1,7 @@
import { useState } from 'react';
import ThemeToggle from '../ThemeToggle';
import MobileMenu from './MobileMenu';
+import { personalConfig } from '../../config/personal';
type Props = {
theme: 'light' | 'dark';
@@ -19,9 +20,8 @@ export default function Navbar({ theme, setTheme }: Props) {
];
return (
- // TODO Centralize strings, create buttons via loops
-
Sascha Bach
+
{personalConfig.name}
{menuItems.map((item) => (