style: enhance layout and styling of components with improved animations and responsiveness

This commit is contained in:
2025-02-04 00:38:40 +01:00
parent b1e8775346
commit e7735e8521
10 changed files with 366 additions and 522 deletions

View File

@@ -0,0 +1,32 @@
import Link from "next/link";
export default function Footer() {
return (
<footer
className="p-10 bg-gradient-to-br from-white/60 to-white/30 backdrop-blur-lg rounded-2xl shadow-xl text-center text-gray-800 dark:text-white">
<div className="flex justify-center space-x-4 mt-4">
<Link href="https://github.com/Denshooter" target="_blank">
<svg
className="w-6 h-6 text-gray-700 dark:text-white hover:text-gray-900 dark:hover:text-gray-300 transition"
fill="currentColor"
viewBox="0 0 24 24"
>
<path
d="M12 0C5.37 0 0 5.37 0 12c0 5.3 3.438 9.8 8.205 11.387.6.11.82-.26.82-.577v-2.17c-3.338.726-4.042-1.61-4.042-1.61-.546-1.387-1.333-1.757-1.333-1.757-1.09-.746.083-.73.083-.73 1.205.084 1.84 1.237 1.84 1.237 1.07 1.835 2.807 1.305 3.492.997.108-.774.42-1.305.763-1.605-2.665-.305-5.466-1.332-5.466-5.93 0-1.31.467-2.38 1.235-3.22-.123-.303-.535-1.527.117-3.18 0 0 1.008-.322 3.3 1.23.957-.266 1.98-.4 3-.405 1.02.005 2.043.14 3 .405 2.29-1.552 3.297-1.23 3.297-1.23.653 1.653.24 2.877.118 3.18.77.84 1.233 1.91 1.233 3.22 0 4.61-2.803 5.62-5.475 5.92.43.37.823 1.1.823 2.22v3.293c0 .32.218.694.825.577C20.565 21.8 24 17.3 24 12c0-6.63-5.37-12-12-12z"/>
</svg>
</Link>
<Link href="https://linkedin.com/in/dkonkol" target="_blank">
<svg
className="w-6 h-6 text-gray-700 dark:text-white hover:text-gray-900 dark:hover:text-gray-300 transition"
fill="currentColor"
viewBox="0 0 24 24"
>
<path
d="M19 0h-14c-2.76 0-5 2.24-5 5v14c0 2.76 2.24 5 5 5h14c2.76 0 5-2.24 5-5v-14c0-2.76-2.24-5-5-5zm-11 19h-3v-10h3v10zm-1.5-11.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm13.5 11.5h-3v-5.5c0-1.38-1.12-2.5-2.5-2.5s-2.5 1.12-2.5 2.5v5.5h-3v-10h3v1.5c.83-1.17 2.17-1.5 3.5-1.5 2.48 0 4.5 2.02 4.5 4.5v5.5z"/>
</svg>
</Link>
</div>
<p className="mt-6">© Dennis Konkol 2025</p>
</footer>
);
}

View File

@@ -1,76 +1,87 @@
"use client"; "use client";
import { useParams, useRouter } from "next/navigation"; import {useParams, useRouter} from "next/navigation";
import { useEffect, useState } from "react"; import {useEffect, useState} from "react";
import Link from "next/link"; import Link from "next/link";
import Image from "next/image"; import Image from "next/image";
import Header from "../../components/Header";
import Footer from "./Footer";
interface Project { interface Project {
id: string; id: string;
title: string; title: string;
slug: string; slug: string;
description: string; description: string;
link: string; link: string;
image: string; image: string;
} }
export default function ProjectDetail() { export default function ProjectDetail() {
const params = useParams(); const params = useParams();
const router = useRouter(); const router = useRouter();
const { slug } = params as { slug: string }; const {slug} = params as { slug: string };
const [project, setProject] = useState<Project | null>(null); const [project, setProject] = useState<Project | null>(null);
useEffect(() => { useEffect(() => {
if (slug) { if (slug) {
fetch("/data/projects.json") fetch("/data/projects.json")
.then((res) => res.json()) .then((res) => res.json())
.then((data: Project[]) => { .then((data: Project[]) => {
const found = data.find((proj) => proj.slug === slug); const found = data.find((proj) => proj.slug === slug);
if (found) { if (found) {
setProject(found); setProject(found);
// Log the project view // Log the project view
fetch("/api/stats", { fetch("/api/stats", {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
body: JSON.stringify({ body: JSON.stringify({
type: "project_view", type: "project_view",
projectId: found.id, projectId: found.id,
}), }),
}).catch((err) => console.error("Failed to log project view", err)); }).catch((err) => console.error("Failed to log project view", err));
} else { } else {
// Redirect to 404 if project not found // Redirect to 404 if project not found
router.replace("/not-found"); router.replace("/not-found");
} }
}); });
}
}, [slug, router]);
if (!project) {
return <div className="p-10 text-center">Loading...</div>;
} }
}, [slug, router]);
if (!project) { return (
return <div className="p-10 text-center">Loading...</div>; <div className="min-h-screen flex flex-col bg-radiant">
} <Header/>
<div className="flex-grow p-10 pt-24">
return ( <div
<div className="p-10 bg-gray-100 dark:bg-gray-800 min-h-screen"> className="flex flex-col items-center p-8 bg-gradient-to-br from-white/60 to-white/30 backdrop-blur-lg rounded-2xl shadow-xl max-w-lg mx-auto">
<h1 className="text-4xl font-bold text-gray-800 dark:text-white"> <h1 className="text-4xl font-bold text-gray-800 dark:text-white">
{project.title} {project.title}
</h1> </h1>
<Image <Image
src={project.image} src={project.image}
alt={project.title} alt={project.title}
className="mt-4 w-full max-w-md rounded shadow" width={400}
/> height={400}
<p className="mt-4 text-gray-600 dark:text-gray-300"> className="mt-4 w-full max-w-md rounded shadow-lg"
{project.description} />
</p> <p className="mt-4 text-gray-600 dark:text-gray-300">
<Link {project.description}
href={`/`} </p>
className="mt-4 inline-block text-blue-500 hover:underline" <Link
> href={`/`}
Go back Home className="mt-4 inline-block text-blue-500 hover:underline"
</Link> >
</div> Go back Home
); </Link>
} </div>
</div>
<Footer/>
</div>
);
}

View File

@@ -22,60 +22,61 @@ export default function Contact() {
setSuccess(true); setSuccess(true);
setForm({name: "", email: "", message: ""}); setForm({name: "", email: "", message: ""});
} catch (err) { } catch (err) {
//use err to avoid unused variable warning
if (err instanceof Error) { if (err instanceof Error) {
setError("Failed to send message. Please try again."); setError("Failed to send message. Please try again.");
} }
} }
}; };
return ( return (
<section id="contact" className="p-10 "> <section id="contact" className="p-10">
<h2 className="text-3xl font-bold text-center text-gray-800 dark:text-white"> <h2 className="text-3xl font-bold text-center text-gray-800 dark:text-white">
Contact Me Contact Me
</h2> </h2>
<form onSubmit={handleSubmit} className="mt-6 max-w-md mx-auto space-y-4"> <div
{success && ( className="flex flex-col items-center p-8 bg-gradient-to-br from-white/60 to-white/30 backdrop-blur-lg rounded-2xl shadow-xl max-w-lg mx-auto mt-6">
<p className="text-green-500"> <form onSubmit={handleSubmit} className="w-full space-y-4">
Your message has been sent successfully! {success && (
</p> <p className="text-green-500">
)} Your message has been sent successfully!
{error && <p className="text-red-500">{error}</p>} </p>
<input )}
type="text" {error && <p className="text-red-500">{error}</p>}
name="name" <input
placeholder="Name" type="text"
className="w-full p-2 border rounded dark:text-white" name="name"
required placeholder="Name"
value={form.name} className="w-full p-2 border rounded dark:text-white"
onChange={handleChange} required
/> value={form.name}
<input onChange={handleChange}
type="email" />
name="email" <input
placeholder="Email" type="email"
className="w-full p-2 border rounded dark:text-white" name="email"
required placeholder="Email"
value={form.email} className="w-full p-2 border rounded dark:text-white"
onChange={handleChange} required
/> value={form.email}
<textarea onChange={handleChange}
name="message" />
placeholder="Message" <textarea
className="w-full p-2 border rounded dark:text-white" name="message"
rows={5} placeholder="Message"
required className="w-full p-2 border rounded dark:text-white"
value={form.message} rows={5}
onChange={handleChange} required
></textarea> value={form.message}
<button onChange={handleChange}
type="submit" ></textarea>
className="w-full p-2 text-white rounded hover:bg-blue-600 transition" <button
> type="submit"
Send className="w-full p-2 text-white bg-gradient-to-r from-blue-500 to-purple-500 rounded hover:from-blue-600 hover:to-purple-600 transition"
</button> >
</form> Send
</button>
</form>
</div>
</section> </section>
); );
} }

View File

@@ -1,24 +1,42 @@
import Link from "next/link"; import Link from "next/link";
export default function Footer() { export default function Footer() {
return ( const scrollToSection = (id: string) => {
<footer className="text-center p-10 text-white"> const element = document.getElementById(id);
<h1 className="text-3xl font-bold">Thank You for Visiting</h1> if (element) {
<p className="mt-4 text-xl">Connect with me on social platforms:</p> element.scrollIntoView({behavior: "smooth"});
<div className="flex justify-center space-x-4 mt-4"> }
<Link href="https://github.com/yourusername" target="_blank"></Link> };
<Link
href="https://linkedin.com/in/yourusername" return (
target="_blank" <footer
></Link> className="p-10 bg-gradient-to-br from-white/60 to-white/30 backdrop-blur-lg rounded-2xl shadow-xl text-center text-gray-800 dark:text-white">
{/* Add more social links as needed */} <h1 className="text-3xl font-bold">Thank You for Visiting</h1>
</div> <p className="mt-4 text-xl">Connect with me on social platforms:</p>
<p className="mt-6">© Dennis Konkol 2024</p> <div className="flex justify-center space-x-4 mt-4">
<Link href="#hero"> <Link href="https://github.com/Denshooter" target="_blank">
<button className="mt-6 inline-block px-6 py-2 text-white rounded hover:bg-gray-800 dark:bg-white dark:text-black dark:hover:bg-gray-300 transition"> <svg
Back to Top className="w-6 h-6 text-gray-700 dark:text-white hover:text-gray-900 dark:hover:text-gray-300 transition"
</button> fill="currentColor" viewBox="0 0 24 24">
</Link> <path
</footer> d="M12 0C5.37 0 0 5.37 0 12c0 5.3 3.438 9.8 8.205 11.387.6.11.82-.26.82-.577v-2.17c-3.338.726-4.042-1.61-4.042-1.61-.546-1.387-1.333-1.757-1.333-1.757-1.09-.746.083-.73.083-.73 1.205.084 1.84 1.237 1.84 1.237 1.07 1.835 2.807 1.305 3.492.997.108-.774.42-1.305.763-1.605-2.665-.305-5.466-1.332-5.466-5.93 0-1.31.467-2.38 1.235-3.22-.123-.303-.535-1.527.117-3.18 0 0 1.008-.322 3.3 1.23.957-.266 1.98-.4 3-.405 1.02.005 2.043.14 3 .405 2.29-1.552 3.297-1.23 3.297-1.23.653 1.653.24 2.877.118 3.18.77.84 1.233 1.91 1.233 3.22 0 4.61-2.803 5.62-5.475 5.92.43.37.823 1.1.823 2.22v3.293c0 .32.218.694.825.577C20.565 21.8 24 17.3 24 12c0-6.63-5.37-12-12-12z"/>
); </svg>
} </Link>
<Link href="https://linkedin.com/in/dkonkol" target="_blank">
<svg
className="w-6 h-6 text-gray-700 dark:text-white hover:text-gray-900 dark:hover:text-gray-300 transition"
fill="currentColor" viewBox="0 0 24 24">
<path
d="M19 0h-14c-2.76 0-5 2.24-5 5v14c0 2.76 2.24 5 5 5h14c2.76 0 5-2.24 5-5v-14c0-2.76-2.24-5-5-5zm-11 19h-3v-10h3v10zm-1.5-11.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm13.5 11.5h-3v-5.5c0-1.38-1.12-2.5-2.5-2.5s-2.5 1.12-2.5 2.5v5.5h-3v-10h3v1.5c.83-1.17 2.17-1.5 3.5-1.5 2.48 0 4.5 2.02 4.5 4.5v5.5z"/>
</svg>
</Link>
</div>
<p className="mt-6">© Dennis Konkol 2025</p>
<button
onClick={() => scrollToSection("about")}
className="mt-6 inline-block px-6 py-2 text-white bg-gradient-to-r from-blue-500 to-purple-500 rounded hover:from-blue-600 hover:to-purple-600 transition">
Back to Top
</button>
</footer>
);
}

View File

@@ -2,9 +2,6 @@
import {useState} from "react"; import {useState} from "react";
import Link from "next/link"; import Link from "next/link";
import {Roboto} from "next/font/google";
const inter = Roboto({weight: '400', subsets: ["latin"]});
export default function Header() { export default function Header() {
const [isSidebarOpen, setIsSidebarOpen] = useState(false); const [isSidebarOpen, setIsSidebarOpen] = useState(false);
@@ -13,15 +10,28 @@ export default function Header() {
setIsSidebarOpen(!isSidebarOpen); setIsSidebarOpen(!isSidebarOpen);
}; };
const scrollToSection = (id: string) => {
const element = document.getElementById(id);
if (element) {
element.scrollIntoView({behavior: "smooth"});
} else {
/*go to main page and scroll*/
window.location.href = `/#${id}`;
}
};
return ( return (
<div className={inter.className}> <div className="p-4">
<div className="p-4"> <div
<header className={`fixed top-4 left-4 right-4 p-4 bg-white/45 text-gray-700 backdrop-blur-md shadow-xl rounded-2xl z-50 ${isSidebarOpen ? 'transform -translate-y-full' : ''}`}>
className={`p-4 bg-white/45 text-gray-700 w-full backdrop-blur-md shadow-xl rounded-2xl transition-transform ${isSidebarOpen ? 'transform -translate-y-full' : ''}`}> <header className="w-full">
<nav className="flex justify-between items-center mx-auto"> <nav className="flex flex-row items-center px-4">
<h1 className="text-xl md:text-2xl">Dennis Konkol</h1> <Link href="/" className="flex justify-start">
<h1 className="text-xl md:text-2xl">Dennis Konkol</h1>
</Link>
<div className="flex-grow"></div>
<button <button
className="md:hidden text-gray-700 hover:text-gray-900" className="text-gray-700 hover:text-gray-900 md:hidden"
onClick={toggleSidebar} onClick={toggleSidebar}
> >
<svg <svg
@@ -40,150 +50,71 @@ export default function Header() {
</svg> </svg>
</button> </button>
<div className="hidden md:flex space-x-4 md:space-x-6"> <div className="hidden md:flex space-x-4 md:space-x-6">
<Link href="#projects"> <button
<button onClick={() => scrollToSection("about")}
className="relative px-4 py-2 text-gray-700 hover:text-gray-900 text-xl md:text-2xl group"> className="relative px-4 py-2 text-gray-700 hover:text-gray-900 text-xl md:text-2xl group">
<span About
className="inline-flex items-center group-hover:transform group-hover:-translate-x-2 transition-transform"> </button>
Projects <button
<svg onClick={() => scrollToSection("projects")}
className="ml-1 w-6 h-6 opacity-0 group-hover:opacity-100 transition-opacity" className="relative px-4 py-2 text-gray-700 hover:text-gray-900 text-xl md:text-2xl group">
xmlns="http://www.w3.org/2000/svg" Projects
fill="none" </button>
viewBox="0 0 24 24" <button
stroke="currentColor" onClick={() => scrollToSection("contact")}
> className="relative pl-4 py-2 text-gray-700 hover:text-gray-900 text-xl md:text-2xl group">
<path Contact
strokeLinecap="round" </button>
strokeLinejoin="round"
strokeWidth={2}
d="M3 8.2c0-1.12 0-1.68.218-2.108a2 2 0 0 1 .874-.874C4.52 5 5.08 5 6.2 5h3.475c.489 0 .733 0 .963.055.204.05.4.13.579.24.201.123.374.296.72.642l.126.126c.346.346.519.519.72.642.18.11.375.19.579.24.23.055.474.055.963.055H17.8c1.12 0 1.68 0 2.108.218a2 2 0 0 1 .874.874C21 8.52 21 9.08 21 10.2v5.6c0 1.12 0 1.68-.218 2.108a2 2 0 0 1-.874.874C19.48 19 18.92 19 17.8 19H6.2c-1.12 0-1.68 0-2.108-.218a2 2 0 0 1-.874-.874C3 17.48 3 16.92 3 15.8V8.2Z"
/>
</svg>
</span>
</button>
</Link>
<Link href="#contact">
<button
className="relative px-4 py-2 text-gray-700 hover:text-gray-900 text-xl md:text-2xl group">
<span
className="inline-flex items-center group-hover:transform group-hover:-translate-x-2 transition-transform">
Contact
<svg
className="ml-1 w-6 h-6 opacity-0 group-hover:opacity-100 transition-opacity"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
d="M22 12.27v4.37a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V7.36a2 2 0 0 1 2-2h6.76"
style={{
strokeLinejoin: "bevel",
fillRule: "evenodd",
fill: "none",
strokeLinecap: "round",
strokeWidth: "1.5px",
}}
/>
<path
d="M19.3 4.25a1 1 0 0 0-1.42 0l-6 6h0l-.1 3a.21.21 0 0 0 .23.22l3-.1h0l6-6A1 1 0 0 0 21 6Z"
style={{
strokeLinejoin: "round",
fill: "none",
strokeLinecap: "round",
strokeWidth: "1.5px",
}}
/>
</svg>
</span>
</button>
</Link>
<Link href="#about">
<button
className="relative px-4 py-2 text-gray-700 hover:text-gray-900 text-xl md:text-2xl group">
<span
className="inline-flex items-center group-hover:transform group-hover:-translate-x-2 transition-transform">
About
<svg
className="ml-1 w-6 h-6 opacity-0 group-hover:opacity-100 transition-opacity"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
fillRule="evenodd"
d="M10 7.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5Z"
clipRule="evenodd"
/>
<path
fillRule="evenodd"
d="M3 7a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v4a2 2 0 0 1-1.052 1.761C18.908 16.611 15.884 19.5 12 19.5c-3.884 0-6.908-2.889-7.948-6.739A2 2 0 0 1 3 11V7Zm2-1h14a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-3.335a1 1 0 0 1-.284-.041l-2.529-.75a2.999 2.999 0 0 0-1.704 0l-2.529.75a1 1 0 0 1-.284.041H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1Zm.166 7C6.23 16.256 8.834 18.5 12 18.5c3.166 0 5.77-2.244 6.834-5.5h-3.169c-.192 0-.384-.028-.568-.082l-2.529-.75c-.37-.11-.765-.11-1.136 0l-2.529.75a2.002 2.002 0 0 1-.568.082H5.166Z"
clipRule="evenodd"
/>
<path
fillRule="evenodd"
d="M10 14.5a.5.5 0 0 1 .5.5v.003l.003.01c.004.009.014.027.036.053a.86.86 0 0 0 .27.194c.28.14.7.24 1.191.24.492 0 .912-.1 1.19-.24a.86.86 0 0 0 .271-.194.214.214 0 0 0 .039-.063V15a.5.5 0 0 1 1 0c0 .568-.447.947-.862 1.154-.445.223-1.025.346-1.638.346s-1.193-.123-1.638-.346C9.947 15.947 9.5 15.568 9.5 15a.5.5 0 0 1 .5-.5Z"
clipRule="evenodd"
/>
</svg>
</span>
</button>
</Link>
</div> </div>
</nav> </nav>
</header> </header>
</div>
<div <div
className={`fixed inset-0 bg-black bg-opacity-50 transition-opacity ${isSidebarOpen ? 'opacity-100' : 'opacity-0 pointer-events-none'}`} className={`fixed inset-0 bg-black bg-opacity-50 transition-opacity ${isSidebarOpen ? 'opacity-100' : 'opacity-0 pointer-events-none'}`}
onClick={toggleSidebar}
></div>
<div
className={`fixed z-10 top-0 right-0 h-full bg-white w-1/3 transform transition-transform flex flex-col ${isSidebarOpen ? 'translate-x-0' : 'translate-x-full'}`}
>
<button
className="absolute top-4 right-4 text-gray-700 hover:text-gray-900"
onClick={toggleSidebar} onClick={toggleSidebar}
></div>
<div
className={`fixed top-0 right-0 h-full bg-white w-1/3 transform transition-transform flex flex-col ${isSidebarOpen ? 'translate-x-0' : 'translate-x-full'}`}
> >
<button <svg
className="absolute top-4 right-4 text-gray-700 hover:text-gray-900" className="w-6 h-6"
onClick={toggleSidebar} fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
> >
<svg <path
className="w-6 h-6" strokeLinecap="round"
fill="none" strokeLinejoin="round"
stroke="currentColor" strokeWidth="2"
viewBox="0 0 24 24" d="M6 18L18 6M6 6l12 12"
xmlns="http://www.w3.org/2000/svg" />
> </svg>
<path </button>
strokeLinecap="round" <div className="pt-8 space-y-4 flex-grow">
strokeLinejoin="round" <button
strokeWidth="2" onClick={() => scrollToSection("about")}
d="M6 18L18 6M6 6l12 12" className="w-full px-4 py-2 pt-8 text-gray-700 hover:text-gray-900 text-xl md:text-2xl group">
/> About
</svg> </button>
<button
onClick={() => scrollToSection("projects")}
className="w-full px-4 py-2 text-gray-700 hover:text-gray-900 text-xl md:text-2xl group">
Projects
</button>
<button
onClick={() => scrollToSection("contact")}
className="w-full px-4 py-2 text-gray-700 hover:text-gray-900 text-xl md:text-2xl group">
Contact
</button> </button>
<div className="pt-8 space-y-4 flex-grow">
<Link href="#projects">
<button
className="w-full px-4 py-2 pt-8 text-gray-700 hover:text-gray-900 text-xl md:text-2xl group">
Projects
</button>
</Link>
<Link href="#contact">
<button
className="w-full px-4 py-2 text-gray-700 hover:text-gray-900 text-xl md:text-2xl group">
Contact
</button>
</Link>
<Link href="#about">
<button
className="w-full px-4 py-2 text-gray-700 hover:text-gray-900 text-xl md:text-2xl group">
About
</button>
</Link>
</div>
<h6 className="text-center text-xs text-gray-500 p-4">© 2025 Dennis</h6>
</div> </div>
<h6 className="text-center text-xs text-gray-500 p-4">© 2025 Dennis</h6>
</div> </div>
</div> </div>
); );

View File

@@ -1,48 +1,43 @@
import Image from "next/image"; import Image from "next/image";
import {Roboto} from "next/font/google";
const roboto = Roboto({weight: "400", subsets: ["latin"]});
export default function Hero() { export default function Hero() {
return ( return (
<div className={roboto.className}> <div id="about"
<div id="hero" className="flex flex-col md:flex-row items-center justify-center pt-16 pb-16 px-6 text-gray-700">
className="flex flex-col md:flex-row items-center justify-center pt-16 pb-16 px-6 text-gray-700">
{/* Left Section: Text */} {/* Left Section: Text */}
<div className="flex flex-col items-center p-8 bg-gradient-to-br from-white/60 to-white/30 <div className="flex flex-col items-center p-8 bg-gradient-to-br from-white/60 to-white/30
backdrop-blur-lg rounded-2xl shadow-xl max-w-lg text-center"> backdrop-blur-lg rounded-2xl shadow-xl max-w-lg text-center">
<h1 className="text-4xl md:text-5xl font-extrabold text-gray-900"> <h1 className="text-4xl md:text-5xl font-extrabold text-gray-900">
Hi, Im Dennis Hi, Im Dennis
</h1> </h1>
<h2 className="mt-2 text-xl md:text-2xl font-semibold text-gray-700"> <h2 className="mt-2 text-xl md:text-2xl font-semibold text-gray-700">
Student & Software Engineer Student & Software Engineer
</h2> </h2>
<h3 className="mt-1 text-lg md:text-xl text-gray-600"> <h3 className="mt-1 text-lg md:text-xl text-gray-600">
Based in Osnabrück, Germany Based in Osnabrück, Germany
</h3> </h3>
<p className="mt-6 text-gray-800 text-lg leading-relaxed"> <p className="mt-6 text-gray-800 text-lg leading-relaxed">
Passionate about technology, coding, and solving real-world problems. Passionate about technology, coding, and solving real-world problems.
I enjoy building innovative solutions and continuously expanding my knowledge. I enjoy building innovative solutions and continuously expanding my knowledge.
</p> </p>
<p className="mt-4 text-gray-700 text-base"> <p className="mt-4 text-gray-700 text-base">
Currently working on exciting projects that merge creativity with functionality. Currently working on exciting projects that merge creativity with functionality.
Always eager to learn and collaborate! Always eager to learn and collaborate!
</p> </p>
</div> </div>
{/* Right Section: Image */} {/* Right Section: Image */}
<div className="flex mt-8 md:mt-0 md:ml-12"> <div className="flex mt-8 md:mt-0 md:ml-12">
<Image <Image
src="/images/me.jpg" src="/images/me.jpg"
alt="Image of Dennis" alt="Image of Dennis"
width={400} width={400}
height={400} height={400}
className="rounded-2xl shadow-lg shadow-gray-700 object-cover" className="rounded-2xl shadow-lg shadow-gray-700 object-cover"
/> />
</div>
</div> </div>
</div> </div>
); );

View File

@@ -22,28 +22,29 @@ export default function Projects() {
return ( return (
<section id="projects" className="p-10"> <section id="projects" className="p-10">
<h2 className="text-3xl font-bold text-center text-gray-800 dark:text-white"> <h2 className="text-3xl font-bold text-center text-gray-800">
Projects Projects
</h2> </h2>
<div className="mt-6 grid grid-cols-1 md:grid-cols-2 gap-6"> <div className="mt-6 grid grid-cols-1 md:grid-cols-2 gap-6">
{projects.map((project) => ( {projects.map((project) => (
<div <Link
key={project.id} key={project.id}
className="p-4 border shadow-lg bg-white/45 rounded-2xl" href={`/Projects/${project.title.toLowerCase().replace(" ", "-")}`}
className="cursor-pointer"
> >
<h3 className="text-2xl font-bold text-gray-800"> <div
{project.title} key={project.id}
</h3> className="p-4 border shadow-lg bg-white/45 rounded-2xl"
<p className="mt-2 text-gray-500">
{project.description}
</p>
<Link
href={`/Projects/${project.title.toLowerCase().replace(" ", "-")}`}
className="mt-4 inline-block text-blue-800 hover:underline"
> >
View Project <h3 className="text-2xl font-bold text-gray-800">
</Link> {project.title}
</div> </h3>
<p className="mt-2 text-gray-500">
{project.description}
</p>
</div>
</Link>
))} ))}
</div> </div>
</section> </section>

View File

@@ -4,195 +4,53 @@
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
/* Custom Global Styles */
body { body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: 0; margin: 0;
padding: 0; padding: 0;
position: relative; position: relative;
min-height: 100vh; min-height: 100vh;
} }
body::before { .bg-radiant-animated {
content: "";
position: fixed;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
z-index: -1;
background: radial-gradient(circle at 20% 20%, #ff8185, transparent 25%), background: radial-gradient(circle at 20% 20%, #ff8185, transparent 25%),
radial-gradient(circle at 80% 80%, #ffaa91, transparent 25%), radial-gradient(circle at 80% 80%, #ffaa91, transparent 25%),
radial-gradient(circle at 50% 50%, #fb7fd9, transparent 25%), radial-gradient(circle at 50% 50%, #fb7fd9, transparent 25%),
radial-gradient(circle at 30% 70%, #9b6fff, transparent 25%), radial-gradient(circle at 30% 70%, #9b6fff, transparent 25%),
radial-gradient(circle at 70% 30%, #ff8edf, transparent 25%); radial-gradient(circle at 70% 30%, #ff8edf, transparent 25%);
background-size: 200% 200%; background-size: 200% 200%;
animation: bubbleAnimation 60s ease infinite; animation: backgroundAnimation 60s ease infinite alternate;
} }
@keyframes bubbleAnimation { .bg-radiant {
background: radial-gradient(circle at 20% 20%, #ff8185, transparent 25%),
radial-gradient(circle at 80% 80%, #ffaa91, transparent 25%),
radial-gradient(circle at 50% 50%, #fb7fd9, transparent 25%),
radial-gradient(circle at 30% 70%, #9b6fff, transparent 25%),
radial-gradient(circle at 70% 30%, #ff8edf, transparent 25%);
background-size: cover;
}
@keyframes backgroundAnimation {
0% { 0% {
background-position: 0 0; background-position: 0 0;
transform: rotate(0deg) scale(1.5);
}
2.5% {
background-position: 5% 5%;
transform: rotate(9deg) scale(1.5);
}
5% {
background-position: 10% 10%;
transform: rotate(18deg) scale(1.5);
}
7.5% {
background-position: 15% 15%;
transform: rotate(27deg) scale(1.5);
}
10% {
background-position: 20% 20%;
transform: rotate(36deg) scale(1.5);
}
12.5% {
background-position: 25% 25%;
transform: rotate(45deg) scale(1.5);
}
15% {
background-position: 30% 30%;
transform: rotate(54deg) scale(1.5);
}
17.5% {
background-position: 35% 35%;
transform: rotate(63deg) scale(1.5);
}
20% {
background-position: 40% 40%;
transform: rotate(72deg) scale(1.5);
}
22.5% {
background-position: 45% 45%;
transform: rotate(81deg) scale(1.5);
}
25% {
background-position: 50% 50%;
transform: rotate(90deg) scale(1.5);
}
27.5% {
background-position: 55% 55%;
transform: rotate(99deg) scale(1.5);
}
30% {
background-position: 60% 60%;
transform: rotate(108deg) scale(1.5);
}
32.5% {
background-position: 65% 65%;
transform: rotate(117deg) scale(1.5);
}
35% {
background-position: 70% 70%;
transform: rotate(126deg) scale(1.5);
}
37.5% {
background-position: 75% 75%;
transform: rotate(135deg) scale(1.5);
}
40% {
background-position: 80% 80%;
transform: rotate(144deg) scale(1.5);
}
42.5% {
background-position: 85% 85%;
transform: rotate(153deg) scale(1.5);
}
45% {
background-position: 90% 90%;
transform: rotate(162deg) scale(1.5);
}
47.5% {
background-position: 95% 95%;
transform: rotate(171deg) scale(1.5);
}
50% {
background-position: 100% 100%;
transform: rotate(180deg) scale(1.5);
}
52.5% {
background-position: 95% 95%;
transform: rotate(189deg) scale(1.5);
}
55% {
background-position: 90% 90%;
transform: rotate(198deg) scale(1.5);
}
57.5% {
background-position: 85% 85%;
transform: rotate(207deg) scale(1.5);
}
60% {
background-position: 80% 80%;
transform: rotate(216deg) scale(1.5);
}
62.5% {
background-position: 75% 75%;
transform: rotate(225deg) scale(1.5);
}
65% {
background-position: 70% 70%;
transform: rotate(234deg) scale(1.5);
}
67.5% {
background-position: 65% 65%;
transform: rotate(243deg) scale(1.5);
}
70% {
background-position: 60% 60%;
transform: rotate(252deg) scale(1.5);
}
72.5% {
background-position: 55% 55%;
transform: rotate(261deg) scale(1.5);
}
75% {
background-position: 50% 50%;
transform: rotate(270deg) scale(1.5);
}
77.5% {
background-position: 45% 45%;
transform: rotate(279deg) scale(1.5);
}
80% {
background-position: 40% 40%;
transform: rotate(288deg) scale(1.5);
}
82.5% {
background-position: 35% 35%;
transform: rotate(297deg) scale(1.5);
}
85% {
background-position: 30% 30%;
transform: rotate(306deg) scale(1.5);
}
87.5% {
background-position: 25% 25%;
transform: rotate(315deg) scale(1.5);
}
90% {
background-position: 20% 20%;
transform: rotate(324deg) scale(1.5);
}
92.5% {
background-position: 15% 15%;
transform: rotate(333deg) scale(1.5);
}
95% {
background-position: 10% 10%;
transform: rotate(342deg) scale(1.5);
}
97.5% {
background-position: 5% 5%;
transform: rotate(351deg) scale(1.5);
} }
100% { 100% {
background-position: 0 0; background-position: 100% 100%;
transform: rotate(360deg) scale(1.5);
} }
}
.min-h-screen {
min-height: 100vh;
}
.flex {
display: flex;
}
.flex-col {
flex-direction: column;
}
.flex-grow {
flex-grow: 1;
} }

View File

@@ -1,36 +1,33 @@
// app/layout.tsx // app/layout.tsx
import type { Metadata } from "next"; import type {Metadata} from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css"; import "./globals.css";
const geistSans = Geist({ import {Roboto} from 'next/font/google'
variable: "--font-geist-sans", import React from "react";
subsets: ["latin"],
}); const roboto = Roboto({
variable: '--font-roboto',
weight: '400',
subsets: ['latin'],
})
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Dennis's Portfolio", title: "Dennis's Portfolio",
description: "A portfolio website showcasing my work and skills.", description: "A portfolio website showcasing my work and skills.",
}; };
export default function RootLayout({ export default function RootLayout({
children, children,
}: { }: {
children: React.ReactNode; children: React.ReactNode;
}) { }) {
return ( return (
<html lang="en" className="dark"> <html lang="en">
<body <body className={roboto.variable}>
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
{children} {children}
</body> </body>
</html> </html>
); );
} }

View File

@@ -8,7 +8,7 @@ import Footer from "./components/Footer";
export default function Home() { export default function Home() {
return ( return (
<> <div className="min-h-screen flex flex-col bg-radiant-animated">
<Header/> <Header/>
<div className="h-10"></div> <div className="h-10"></div>
<main> <main>
@@ -17,6 +17,6 @@ export default function Home() {
<Contact/> <Contact/>
<Footer/> <Footer/>
</main> </main>
</> </div>
); );
} }