Merge branch 'homepage-refactoring' into 'dev'
Homepage Refactoring - Pt. 1 See merge request rheinsw/website!25
This commit is contained in:
@@ -1,24 +1,29 @@
|
|||||||
import type {Metadata} from "next";
|
import type {Metadata} from "next";
|
||||||
import "./globals.css";
|
import "../globals.css";
|
||||||
|
|
||||||
import Nav from "@/components/Home/Navbar/Nav";
|
import Nav from "@/components/Navbar/Nav";
|
||||||
import Footer from "@/components/Home/Footer/Footer";
|
import Footer from "@/components/Home/Footer/Footer";
|
||||||
import {ThemeProvider} from "@/components/provider/ThemeProvider";
|
import {ThemeProvider} from "@/components/provider/ThemeProvider";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import {cookies} from "next/headers";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Rhein Software",
|
title: "Rhein Software",
|
||||||
description: "Rhein Software Development",
|
description: "Rhein Software Development",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function RootLayout({
|
export default async function RootLayout({
|
||||||
children,
|
children,
|
||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}>) {
|
}>) {
|
||||||
|
const cookieStore = await cookies();
|
||||||
|
const theme = cookieStore.get("theme")?.value === "dark" ? "dark" : "light";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang="de">
|
<html lang="de" data-theme={theme}>
|
||||||
<body className={'${font.className} antialiased'} style={{backgroundColor: "var(--primary-bg)"}}>
|
<head/>
|
||||||
|
<body className="antialiased" style={{backgroundColor: "var(--primary-bg)"}}>
|
||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
<Nav/>
|
<Nav/>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,24 +1,29 @@
|
|||||||
import type {Metadata} from "next";
|
import type {Metadata} from "next";
|
||||||
import '../(root)/globals.css';
|
import "../globals.css";
|
||||||
|
|
||||||
import Nav from "@/components/Home/Navbar/Nav";
|
import Nav from "@/components/Navbar/Nav";
|
||||||
import Footer from "@/components/Home/Footer/Footer";
|
import Footer from "@/components/Home/Footer/Footer";
|
||||||
import {ThemeProvider} from "@/components/provider/ThemeProvider";
|
import {ThemeProvider} from "@/components/provider/ThemeProvider";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import {cookies} from "next/headers";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Rhein Software",
|
title: "Rhein Software",
|
||||||
description: "Rhein Software Development",
|
description: "Rhein Software Development",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function RootLayout({
|
export default async function RootLayout({
|
||||||
children,
|
children,
|
||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}>) {
|
}>) {
|
||||||
|
const cookieStore = await cookies();
|
||||||
|
const theme = cookieStore.get("theme")?.value === "dark" ? "dark" : "light";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang="de">
|
<html lang="de" data-theme={theme}>
|
||||||
<body className={'${font.className} antialiased'} style={{backgroundColor: "var(--primary-bg)"}}>
|
<head/>
|
||||||
|
<body className="antialiased" style={{backgroundColor: "var(--primary-bg)"}}>
|
||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
<Nav/>
|
<Nav/>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -34,5 +34,15 @@
|
|||||||
--footer-bg: #242424; /* Deep grey footer to add visual depth */
|
--footer-bg: #242424; /* Deep grey footer to add visual depth */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes float {
|
||||||
|
0%, 100% {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translateY(-6px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-float {
|
||||||
|
animation: float 3.5s ease-in-out infinite;
|
||||||
|
}
|
||||||
@@ -1,29 +1,34 @@
|
|||||||
import type {Metadata} from "next";
|
import type {Metadata} from "next";
|
||||||
import '../(root)/globals.css';
|
import "../globals.css";
|
||||||
|
|
||||||
import Nav from "@/components/Home/Navbar/Nav";
|
import Nav from "@/components/Navbar/Nav";
|
||||||
import Footer from "@/components/Home/Footer/Footer";
|
import Footer from "@/components/Home/Footer/Footer";
|
||||||
import {ThemeProvider} from "@/components/provider/ThemeProvider";
|
import {ThemeProvider} from "@/components/provider/ThemeProvider";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import {cookies} from "next/headers";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Rhein Software",
|
title: "Rhein Software",
|
||||||
description: "Rhein Software Development",
|
description: "Rhein Software Development",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function RootLayout({
|
export default async function RootLayout({
|
||||||
children,
|
children,
|
||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}>) {
|
}>) {
|
||||||
|
const cookieStore = await cookies();
|
||||||
|
const theme = cookieStore.get("theme")?.value === "dark" ? "dark" : "light";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang="de">
|
<html lang="de" data-theme={theme}>
|
||||||
<body className={'${font.className} antialiased'} style={{backgroundColor: "var(--primary-bg)"}}>
|
<head/>
|
||||||
<ThemeProvider>
|
<body className="antialiased" style={{backgroundColor: "var(--primary-bg)"}}>
|
||||||
<Nav/>
|
<ThemeProvider>
|
||||||
{children}
|
<Nav/>
|
||||||
<Footer/>
|
{children}
|
||||||
</ThemeProvider>
|
<Footer/>
|
||||||
|
</ThemeProvider>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
|
|||||||
35
app/services/layout.tsx
Normal file
35
app/services/layout.tsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import type {Metadata} from "next";
|
||||||
|
import "../globals.css";
|
||||||
|
|
||||||
|
import Nav from "@/components/Navbar/Nav";
|
||||||
|
import Footer from "@/components/Home/Footer/Footer";
|
||||||
|
import {ThemeProvider} from "@/components/provider/ThemeProvider";
|
||||||
|
import React from "react";
|
||||||
|
import {cookies} from "next/headers";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Rhein Software",
|
||||||
|
description: "Rhein Software Development",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function RootLayout({
|
||||||
|
children,
|
||||||
|
}: Readonly<{
|
||||||
|
children: React.ReactNode;
|
||||||
|
}>) {
|
||||||
|
const cookieStore = await cookies();
|
||||||
|
const theme = cookieStore.get("theme")?.value === "dark" ? "dark" : "light";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<html lang="de" data-theme={theme}>
|
||||||
|
<head/>
|
||||||
|
<body className="antialiased" style={{backgroundColor: "var(--primary-bg)"}}>
|
||||||
|
<ThemeProvider>
|
||||||
|
<Nav/>
|
||||||
|
{children}
|
||||||
|
<Footer/>
|
||||||
|
</ThemeProvider>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
12
app/services/page.tsx
Normal file
12
app/services/page.tsx
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Contact from "@/components/Contact/Contact";
|
||||||
|
|
||||||
|
const ContactPage = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Contact/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ContactPage;
|
||||||
@@ -1,43 +1,82 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
import {Typewriter} from "react-simple-typewriter";
|
||||||
|
|
||||||
const Hero = () => {
|
const Hero = () => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="relative w-full pt-[4vh] md:pt-[12vh] h-screen flex flex-col"
|
className="relative w-full pt-[4vh] md:pt-[12vh] h-screen flex flex-col overflow-hidden"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "var(--primary-bg)",
|
backgroundColor: "var(--primary-bg)",
|
||||||
color: "var(--primary-text)",
|
color: "white",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex justify-center flex-col w-[90%] sm:w-[80%] h-full mx-auto">
|
{/* Background Image */}
|
||||||
|
<div className="absolute inset-0 z-0">
|
||||||
|
<Image
|
||||||
|
src="/images/home_hero.jpg"
|
||||||
|
alt="Rhein river aerial view"
|
||||||
|
layout="fill"
|
||||||
|
objectFit="cover"
|
||||||
|
className="blur-md scale-105"
|
||||||
|
priority
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-0 bg-black/40"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Main Content */}
|
||||||
|
<div className="relative z-10 flex justify-center flex-col w-[90%] sm:w-[80%] h-full mx-auto">
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 items-center gap-12">
|
<div className="grid grid-cols-1 lg:grid-cols-2 items-center gap-12">
|
||||||
{/* Text Content */}
|
{/* Text Content */}
|
||||||
<div>
|
<div>
|
||||||
<h1
|
<h1
|
||||||
data-aos="fade-up"
|
data-aos="fade-up"
|
||||||
className="text-2xl sm:text-4xl md:text-5xl mt-6 mb-6 font-bold md:leading-[3rem] lg:leading-[3.5rem]"
|
className="text-3xl sm:text-4xl md:text-5xl mt-6 mb-6 font-bold text-white"
|
||||||
>
|
>
|
||||||
Rhein Software Development
|
Rhein-Software Development
|
||||||
</h1>
|
</h1>
|
||||||
<p data-aos="fade-up" data-aos-delay="200">
|
|
||||||
Wir entwickeln performante und zukunftssichere Software für deine Vision.
|
<p
|
||||||
|
data-aos="fade-up"
|
||||||
|
data-aos-delay="200"
|
||||||
|
className="text-lg md:text-xl text-gray-400"
|
||||||
|
>
|
||||||
|
Digitale Lösungen für dein Unternehmen.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p
|
||||||
|
data-aos="fade-up"
|
||||||
|
data-aos-delay="400"
|
||||||
|
className="mt-4 text-lg md:text-xl font-semibold text-white"
|
||||||
|
>
|
||||||
|
<Typewriter
|
||||||
|
words={["Beratung", "Entwicklung", "Wartung", "Fehlerbehebung"]}
|
||||||
|
loop={true}
|
||||||
|
cursor
|
||||||
|
cursorStyle="_"
|
||||||
|
typeSpeed={60}
|
||||||
|
deleteSpeed={40}
|
||||||
|
delaySpeed={1500} // ⬅️ Delay before it starts typing the FIRST word
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{/* Image Content */}
|
|
||||||
|
{/* Floating Image */}
|
||||||
<div
|
<div
|
||||||
data-aos="fade-up"
|
data-aos="fade-up"
|
||||||
data-aos-delay="400"
|
data-aos-delay="400"
|
||||||
className="hidden lg:block"
|
className="hidden lg:block animate-float"
|
||||||
>
|
>
|
||||||
<Image src="/images/hero.png" alt="hero" width={700} height={700}/>
|
<Image
|
||||||
|
src="/images/hero.png"
|
||||||
|
alt="hero graphic"
|
||||||
|
width={700}
|
||||||
|
height={700}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Farbverlauf zum nächsten Bereich */}
|
|
||||||
{/*<div*/}
|
|
||||||
{/* className="absolute bottom-0 left-0 w-full h-20 bg-gradient-to-b from-[var(--primary-bg)] to-[var(--secondary-bg)]"*/}
|
|
||||||
{/*/>*/}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
import {navLinks} from "@/constant/Constant";
|
|
||||||
import Link from "next/link";
|
|
||||||
import React from "react";
|
|
||||||
import {CgClose} from "react-icons/cg";
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
showNav: boolean;
|
|
||||||
closeNav: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
const MobileNav = ({closeNav, showNav}: Props) => {
|
|
||||||
const navOpen = showNav ? "translate-x-0" : "translate-x-[-100%]";
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{/* overlay */}
|
|
||||||
<div
|
|
||||||
className={`fixed ${navOpen} inset-0 transform transition-all duration-500 z-[10000] bg-black opacity-70 w-full h-screen`}
|
|
||||||
></div>
|
|
||||||
{/* Navlinks */}
|
|
||||||
<div
|
|
||||||
className={`text-white ${navOpen} fixed justify-center flex flex-col h-full transform transition-all duration-500 delay-300 w-[80%] sm:w-[60%] bg-indigo-900 space-y-6 z-[10006]`}
|
|
||||||
>
|
|
||||||
{navLinks.map((link) => {
|
|
||||||
return (
|
|
||||||
<Link href={link.url} key={link.id}>
|
|
||||||
<p className="nav__link text-white text-[20px] ml-12 border-b-[1.5px] pb-1 border-white sm:text-[30px]">
|
|
||||||
{link.label}
|
|
||||||
</p>
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
{/* Close icon */}
|
|
||||||
<CgClose
|
|
||||||
onClick={closeNav}
|
|
||||||
className="absolute top-[0.7rem] right-[1.4rem] sm:w-8 sm:h-8 w-6 h-6"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default MobileNav;
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import {usePathname} from "next/navigation";
|
||||||
import {navLinks} from "@/constant/Constant";
|
import {navLinks} from "@/constant/Constant";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import React, {useContext, useEffect, useState} from "react";
|
import React, {useContext, useEffect, useState} from "react";
|
||||||
@@ -18,6 +19,9 @@ const Nav = ({openNav}: Props) => {
|
|||||||
const [buttonSize, setButtonSize] = useState("md:px-6 md:py-2 px-4 py-1 text-sm");
|
const [buttonSize, setButtonSize] = useState("md:px-6 md:py-2 px-4 py-1 text-sm");
|
||||||
const {theme, toggleTheme} = useContext(ThemeContext);
|
const {theme, toggleTheme} = useContext(ThemeContext);
|
||||||
const colors = themeColors[theme];
|
const colors = themeColors[theme];
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
const navColorClass = theme === "dark" || !navBg ? "text-white" : "text-black";
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handler = () => {
|
const handler = () => {
|
||||||
@@ -40,17 +44,17 @@ const Nav = ({openNav}: Props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`fixed ${navBg ? "shadow-md" : "fixed"} w-full transition-all duration-300 ease-in-out ${navHeight} z-[1000]`}
|
className={`fixed w-full transition-all duration-300 ease-in-out ${navHeight} z-[1000] ${
|
||||||
|
navBg ? "shadow-md" : ""
|
||||||
|
}`}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: navBg ? "var(--nav-bg)" : "var(--primary-bg)",
|
backgroundColor: navBg ? "var(--nav-bg)" : "transparent",
|
||||||
color: "var(--primary-text)",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="flex items-center h-full justify-between w-[90%] xl:w-[80%] mx-auto transition-all duration-300 ease-in-out">
|
className="flex items-center h-full justify-between w-[90%] xl:w-[80%] mx-auto transition-all duration-300 ease-in-out">
|
||||||
{/* LOGO */}
|
{/* LOGO */}
|
||||||
<h1 className={`${contentSize} font-bold transition-all duration-300 ease-in-out`}
|
<h1 className={`${contentSize} font-bold transition-all duration-300 ease-in-out ${navColorClass}`}>
|
||||||
style={{color: colors.primaryText}}>
|
|
||||||
<span className="text-lg md:text-xl text-pink-700">R</span>hein Software
|
<span className="text-lg md:text-xl text-pink-700">R</span>hein Software
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@@ -58,26 +62,34 @@ const Nav = ({openNav}: Props) => {
|
|||||||
<div className="hidden lg:flex items-center space-x-6 transition-all duration-300 ease-in-out">
|
<div className="hidden lg:flex items-center space-x-6 transition-all duration-300 ease-in-out">
|
||||||
{navLinks.map((link) => (
|
{navLinks.map((link) => (
|
||||||
<Link href={link.url} key={link.id}>
|
<Link href={link.url} key={link.id}>
|
||||||
<p className={`nav_link ${contentSize} transition-all duration-300 ease-in-out`}
|
<p
|
||||||
style={{color: colors.primaryText}}>{link.label}</p>
|
className={`nav_link ${contentSize} uppercase transition-all duration-300 ease-in-out ${
|
||||||
|
pathname === link.url
|
||||||
|
? "text-white font-bold"
|
||||||
|
: "text-gray-300 font-medium"
|
||||||
|
}`}>
|
||||||
|
{link.label}
|
||||||
|
</p>
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right Side Buttons */}
|
{/* Right Side Buttons */}
|
||||||
<div className="flex items-center space-x-3 transition-all duration-300 ease-in-out">
|
<div className="flex items-center space-x-3 transition-all duration-300 ease-in-out">
|
||||||
{/* Portal Button */}
|
{/* Contact Button */}
|
||||||
<button
|
<Link href="/contact">
|
||||||
className={`${buttonSize} text-white font-semibold bg-blue-700 hover:bg-blue-900 transition-all duration-300 ease-in-out rounded-full`}
|
<button
|
||||||
>
|
className={`${buttonSize} text-white font-semibold bg-blue-700 hover:bg-blue-900 transition-all duration-300 ease-in-out rounded-full`}
|
||||||
Portal
|
>
|
||||||
</button>
|
Kontakt
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
|
||||||
{/* Theme Toggle Button */}
|
{/* Theme Toggle Button */}
|
||||||
<button
|
<button
|
||||||
onClick={toggleTheme}
|
onClick={toggleTheme}
|
||||||
className="w-7 h-7 flex items-center justify-center rounded-full transition-all duration-300 ease-in-out"
|
className={`w-7 h-7 flex items-center justify-center rounded-full transition-all duration-300 ease-in-out ${navColorClass}`}
|
||||||
style={{backgroundColor: colors.secondaryBg, color: colors.primaryText}}
|
style={{backgroundColor: colors.secondaryBg}}
|
||||||
>
|
>
|
||||||
{theme === "dark" ? "🌙" : "☀️"}
|
{theme === "dark" ? "🌙" : "☀️"}
|
||||||
</button>
|
</button>
|
||||||
@@ -85,7 +97,7 @@ const Nav = ({openNav}: Props) => {
|
|||||||
{/* Burger Menu (for mobile) */}
|
{/* Burger Menu (for mobile) */}
|
||||||
<HiBars3BottomRight
|
<HiBars3BottomRight
|
||||||
onClick={openNav}
|
onClick={openNav}
|
||||||
className="w-6 h-6 cursor-pointer text-black lg:hidden transition-all duration-300 ease-in-out"
|
className={`w-6 h-6 cursor-pointer lg:hidden transition-all duration-300 ease-in-out ${navColorClass}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
62
components/Navbar/MobileNav.tsx
Normal file
62
components/Navbar/MobileNav.tsx
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import { navLinks } from "@/constant/Constant";
|
||||||
|
import Link from "next/link";
|
||||||
|
import React, { useContext } from "react";
|
||||||
|
import { CgClose } from "react-icons/cg";
|
||||||
|
import { ThemeContext } from "@/components/provider/ThemeProvider";
|
||||||
|
import { themeColors } from "@/components/Helper/ThemeColors";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
showNav: boolean;
|
||||||
|
closeNav: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const MobileNav = ({ closeNav, showNav }: Props) => {
|
||||||
|
const navOpen = showNav ? "translate-y-0 opacity-100" : "-translate-y-20 opacity-0 pointer-events-none";
|
||||||
|
const { theme, toggleTheme } = useContext(ThemeContext);
|
||||||
|
const colors = themeColors[theme];
|
||||||
|
return (
|
||||||
|
<div className="lg:hidden">
|
||||||
|
{/* overlay background */}
|
||||||
|
<div
|
||||||
|
className={`fixed inset-0 z-[10000] transition-opacity duration-500 ${
|
||||||
|
showNav ? "opacity-60 bg-black" : "opacity-0 pointer-events-none"
|
||||||
|
}`}
|
||||||
|
onClick={closeNav}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* nav menu */}
|
||||||
|
<div
|
||||||
|
className={`fixed top-0 left-0 w-full z-[10006] transform ${navOpen} transition-all duration-500 ease-in-out text-[var(--primary-text)] shadow-md rounded-b-2xl`}
|
||||||
|
style={{ backgroundColor: theme === "dark" ? "#2A2A2A" : "#ffffff", color: theme === "dark" ? "#f5f5f5" : "#1a1a1a" }}
|
||||||
|
>
|
||||||
|
<div className="flex flex-col items-center justify-center py-8 space-y-4 px-4 relative">
|
||||||
|
{/* Close icon */}
|
||||||
|
<CgClose
|
||||||
|
onClick={closeNav}
|
||||||
|
className="absolute top-4 right-6 sm:right-8 sm:w-7 sm:h-7 w-6 h-6 cursor-pointer p-1"
|
||||||
|
style={{ color: colors.primaryText }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{navLinks.map((link) => (
|
||||||
|
<Link href={link.url} key={link.id}>
|
||||||
|
<p className="nav__link uppercase text-[14px] sm:text-[16px] border-b pb-1 border-gray-400 transition-all duration-300 ease-in-out hover:scale-105">
|
||||||
|
{link.label}
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{/* Theme toggle button */}
|
||||||
|
<button
|
||||||
|
onClick={toggleTheme}
|
||||||
|
className="mt-4 w-8 h-8 flex items-center justify-center rounded-full border border-gray-400 transition-all duration-300"
|
||||||
|
style={{ backgroundColor: colors.secondaryBg, color: colors.primaryText }}
|
||||||
|
>
|
||||||
|
{theme === "dark" ? "🌙" : "☀️"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MobileNav;
|
||||||
@@ -11,7 +11,7 @@ export const navLinks = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
url: 'contact',
|
url: '/services',
|
||||||
label: 'Kontakt',
|
label: 'Leistungen',
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
16
package-lock.json
generated
16
package-lock.json
generated
@@ -13,7 +13,8 @@
|
|||||||
"next": "15.1.7",
|
"next": "15.1.7",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-icons": "^5.4.0"
|
"react-icons": "^5.4.0",
|
||||||
|
"react-simple-typewriter": "^5.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3",
|
"@eslint/eslintrc": "^3",
|
||||||
@@ -5530,6 +5531,19 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/react-simple-typewriter": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-simple-typewriter/-/react-simple-typewriter-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-vA5HkABwJKL/DJ4RshSlY/igdr+FiVY4MLsSQYJX6FZG/f1/VwN4y1i3mPXRyfaswrvI8xii1kOVe1dYtO2Row==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18.0.0",
|
||||||
|
"react-dom": ">=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/read-cache": {
|
"node_modules/read-cache": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||||
|
|||||||
@@ -14,7 +14,8 @@
|
|||||||
"next": "15.1.7",
|
"next": "15.1.7",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-icons": "^5.4.0"
|
"react-icons": "^5.4.0",
|
||||||
|
"react-simple-typewriter": "^5.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3",
|
"@eslint/eslintrc": "^3",
|
||||||
|
|||||||
BIN
public/images/home_hero.jpg
Normal file
BIN
public/images/home_hero.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 MiB |
Reference in New Issue
Block a user