Merge branch 'dev' into 'production'

Merge branch 'Homepage Refactoring - Pt .3' into 'production'

See merge request rheinsw/website!30
This commit is contained in:
2025-04-16 17:40:59 +00:00
parent 5336eb327e
commit 37cde33b41
36 changed files with 896 additions and 473 deletions

View File

@@ -1,57 +0,0 @@
'use client';
import Link from 'next/link';
import { motion } from 'framer-motion';
import { FiArrowRight } from 'react-icons/fi';
const ContactCTA = () => {
return (
<section
className="relative w-full py-24 transition-theme overflow-hidden"
style={{
background: 'linear-gradient(135deg, var(--secondary-bg), var(--primary-bg))',
}}
>
<div className="w-full max-w-4xl px-6 md:px-10 mx-auto text-center">
{/* Headline */}
<motion.h2
className="text-3xl md:text-4xl font-bold text-[var(--primary-text)]"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
>
Interesse geweckt?
</motion.h2>
{/* Description */}
<motion.p
className="mt-4 text-sm md:text-base text-[var(--secondary-text)] max-w-xl mx-auto"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.2 }}
>
Lass uns über dein Projekt sprechen. Wir freuen uns darauf, deine Ideen in die Realität umzusetzen.
</motion.p>
{/* CTA Button */}
<motion.div
className="mt-8 flex justify-center"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.3 }}
>
<Link href="/contact">
<button className="inline-flex items-center gap-2 px-6 py-3 text-sm md:text-base font-semibold rounded-full bg-blue-700 hover:bg-blue-900 text-white shadow-md transition-all duration-300">
Jetzt Kontakt aufnehmen <FiArrowRight size={18} />
</button>
</Link>
</motion.div>
</div>
</section>
);
};
export default ContactCTA;

View File

@@ -1,26 +1,45 @@
'use client';
import React from "react";
import Hero from "./Hero/Hero";
import About from "@/components/Home/About/About";
import ContactCTA from "@/components/Home/Contact/ContactCTA";
import {SectionDivider1, SectionDivider2} from "@/components/Helper/SectionDivider";
import HomeServices from "@/components/Home/HomeServices";
import TechStack from "@/components/Home/TechStack";
import About from "@/components/Home/Sections/About";
import ContactCTA from "@/components/Home/Sections/ContactCTA";
import HomeServices from "@/components/Home/Sections/HomeServices";
import TechStack from "@/components/Home/Sections/TechStack";
import Section from "@/components/Section";
import {motion} from "framer-motion";
import {useThemeColors} from "@/utils/useThemeColors";
import Hero from "@/components/Home/Sections/Hero";
const Home = () => {
const colors = useThemeColors();
return (
<div className="overflow-hidden">
<Hero/>
<SectionDivider1/>
<About/>
<SectionDivider2/>
<HomeServices/>
<SectionDivider1/>
<TechStack/>
<SectionDivider2/>
<ContactCTA/>
</div>
<motion.div
initial={{opacity: 0, y: 20}}
animate={{opacity: 1, y: 0}}
transition={{duration: 0.7, ease: "easeOut"}}
className="overflow-hidden"
>
<Section style={{backgroundColor: colors.primaryBg}}>
<Hero/>
</Section>
<Section style={{backgroundColor: colors.secondaryBg}} shadow>
<About/>
</Section>
<Section style={{backgroundColor: colors.primaryBg}} shadow>
<HomeServices/>
</Section>
<Section style={{backgroundColor: colors.secondaryBg}} shadow>
<TechStack/>
</Section>
<Section style={{backgroundColor: colors.primaryBg}} shadow>
<ContactCTA/>
</Section>
</motion.div>
);
};

View File

@@ -1,75 +0,0 @@
import React from "react";
import Image from "next/image";
const FullStack = () => {
return (
<div
className="w-[95%] sm:w-[80%] mx-auto items-center grid grid-cols-1 lg:grid-cols-2 gap-6 mt-8 mb-16 transition-theme">
<div className="p-0"
>
<h1 data-aos="fade-up"
className="mt-4 text-xl sm:text-2xl md:text-3xl font-bold"
style={{color: "var(--primary-text)"}} // Dynamic text color
>
💻 Full-Stack Entwicklung
</h1>
<div data-aos="fade-up"
data-aos-delay="200"
>
<p
className="mt-4 text-sm font-medium leading-[2rem]"
style={{color: "var(--secondary-text)"}} // Secondary text color
>
Wir entwickeln skalierbare Backends, performante Frontends und native Apps genau auf deine
Anforderungen zugeschnitten. Dabei setzen wir auf neueste und modernste Technologien, um
flexible
und zukunftssichere Lösungen zu schaffen.
</p>
{/* Technology Logos Section */}
<h2
className="mt-8 text-lg font-semibold"
style={{color: "var(--primary-text)"}}
>
🔧 Tech Stack
</h2>
<span
className="mt-4 text-sm font-medium leading-[2rem]"
style={{color: "var(--secondary-text)"}}
>
Programmiersprachen und Frameworks, die wir für unsere Lösungen einsetzen.
</span>
<div className="mt-6 flex flex-wrap items-center gap-8">
{/* Tech Stack Logos */}
{[
{src: "/images/flutter_logo.png", label: "Flutter", width: 30, height: 30},
{src: "/images/dart_logo.png", label: "Dart", width: 40, height: 40},
{src: "/images/java_logo.png", label: "Java", width: 40, height: 40},
{src: "/images/nextjs_logo.png", label: "NextJS", width: 40, height: 40},
].map(({src, label, width, height}) => (
<div key={label} className="flex flex-col items-center">
<Image src={src} alt={label} width={width} height={height} className="object-contain"/>
<span
className="text-xs mt-2"
style={{color: "var(--secondary-text)"}} // Match theme
>
{label}
</span>
</div>
))}
</div>
</div>
</div>
<div data-aos="fade-up" data-aos-anchor-placement="top-center" className="justify-self-center">
<Image
src="/images/software_dev.jpg"
alt="image"
width={200}
height={200}
className="object-contain"
/>
</div>
</div>
);
};
export default FullStack;

View File

@@ -1,57 +0,0 @@
import React from "react";
import Image from "next/image";
import {TiChevronRightOutline} from "react-icons/ti";
const ManagedServices = () => {
return (
<div
className="w-[95%] sm:w-[80%] mx-auto items-center grid grid-cols-1 lg:grid-cols-2 gap-6 mt-8 mb-16"
data-aos="fade-up"
data-aos-delay="200"
>
{/* Image Section */}
<div
data-aos="fade-up"
data-aos-anchor-placement="top-center"
className="justify-self-center"
>
<Image
src="/images/software_dev.jpg"
alt="image"
width={200}
height={200}
className="object-contain"
/>
</div>
{/* Text Content */}
<div className="p-0">
<h1
className="mt-4 text-xl sm:text-2xl md:text-3xl font-bold transition-theme"
style={{color: "var(--primary-text)"}}>
Managed Services
</h1>
<p
className="mt-4 text-sm font-medium leading-[2rem] transition-theme"
style={{color: "var(--secondary-text)"}}>
Wir übernehmen das Hosting und Management deiner Server, damit du dich auf dein
Business konzentrieren kannst. Egal ob Cloud-Hosting, dedizierte Server oder hybride Lösungen wir
sorgen für eine sichere, performante und skalierbare Infrastruktur.
</p>
<ul className="mt-7 space-y-2">
{[
"Web- & Cloud-Hosting",
"Mailserver-Management",
"Webserver-Administration",
].map((item, index) => (
<li key={index} className="flex items-center font-semibold transition-theme">
<TiChevronRightOutline className="text-blue-500 mr-2"/>
<span style={{color: "var(--primary-text)"}}>{item}</span>
</li>
))}
</ul>
</div>
</div>
);
};
export default ManagedServices;

View File

@@ -1,28 +0,0 @@
import React from "react";
import FullStack from "@/components/Home/Offer/FullStack";
import ManagedServices from "@/components/Home/Offer/ManagedServices";
const Offer = () => {
return (
<div
className="transition-theme"
style={{
backgroundColor: "var(--primary-bg)", // Using CSS variable
color: "var(--primary-text)", // Ensuring text color follows theme
transition: "background-color 0.5s ease, color 0.5s ease", // Smooth transition
}}>
<div className="pt-24 pb-16">
<h1 className="mt-6 text-2xl md:text-3xl capitalize font-bold text-center"
data-aos="fade-up"
style={{color: "var(--primary-text)"}}
>
Was bieten wir?
</h1>
<FullStack/>
<ManagedServices/>
</div>
</div>
);
};
export default Offer;

View File

@@ -1,22 +1,23 @@
'use client';
import Link from 'next/link';
import {FiArrowRight} from 'react-icons/fi';
// import Link from 'next/link';
// import {FiArrowRight} from 'react-icons/fi';
import {motion} from 'framer-motion';
import {useThemeColors} from '@/utils/useThemeColors';
const About = () => {
const colors = useThemeColors();
return (
<section className="relative w-full py-24 bg-[var(--secondary-bg)] transition-theme">
<section
className="relative w-full py-24 transition-colors duration-700 ease-in-out"
style={{backgroundColor: colors.secondaryBg, color: colors.primaryText}}
>
<div className="w-full max-w-6xl px-6 md:px-10 mx-auto">
<div className="flex flex-col">
{/* Title */}
<motion.h2
className="text-3xl md:text-4xl font-bold mb-1 text-left"
style={{color: 'var(--primary-text)'}}
initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.5}}
className="text-3xl md:text-4xl font-bold mb-1 text-left transition-colors duration-700 ease-in-out"
>
Über uns
</motion.h2>
@@ -30,9 +31,10 @@ const About = () => {
/>
{/* Text */}
<div className="p-0">
<div className="p-0 max-w-4xl">
<motion.p
className="text-base md:text-lg leading-relaxed text-[var(--secondary-text)] max-w-4xl"
className="text-base md:text-lg leading-relaxed transition-colors duration-700 ease-in-out"
style={{color: colors.secondaryText}}
initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
@@ -40,21 +42,20 @@ const About = () => {
>
Wir sind Rhein-Software ein Team, das sich auf individuelle Softwarelösungen und digitale
Services spezialisiert hat. Unsere Anwendungen sind technisch solide, skalierbar und
durchdacht gebaut für
langfristigen Erfolg.
durchdacht gebaut für langfristigen Erfolg.
</motion.p>
<motion.p
className="mt-6 text-base md:text-lg leading-relaxed text-[var(--secondary-text)] max-w-4xl"
className="mt-6 text-base md:text-lg leading-relaxed transition-colors duration-700 ease-in-out"
style={{color: colors.secondaryText}}
initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.5, delay: 0.3}}
>
Von der ersten Idee bis zum Go-Live begleiten wir Unternehmen und Startups mit einem
flexiblen Netzwerk, klarer Kommunikation und einem hohen Anspruch an Qualität. Unsere
Lösungen sind
intuitiv, effizient und genau auf deine Anforderungen zugeschnitten.
flexiblen Netzwerk, klarer Kommunikation und einem hohen Anspruch an Qualität.
Unsere Lösungen sind intuitiv, effizient und genau auf deine Anforderungen zugeschnitten.
</motion.p>
</div>
@@ -66,12 +67,13 @@ const About = () => {
viewport={{once: true}}
transition={{duration: 0.5, delay: 0.5}}
>
<Link href="/about">
<button
className="flex items-center gap-2 bg-blue-700 hover:bg-blue-900 text-white font-semibold px-5 py-2 rounded-full shadow-lg transition-all">
Mehr über uns <FiArrowRight size={18}/>
</button>
</Link>
{/*<Link href="/about">*/}
{/* <button*/}
{/* className="flex items-center gap-2 bg-blue-700 hover:bg-blue-900 text-white font-semibold px-5 py-2 rounded-full shadow-lg transition-all"*/}
{/* >*/}
{/* Mehr über uns <FiArrowRight size={18}/>*/}
{/* </button>*/}
{/*</Link>*/}
</motion.div>
</div>
</div>

View File

@@ -0,0 +1,57 @@
'use client';
import Link from 'next/link';
import {motion} from 'framer-motion';
import {FiArrowRight} from 'react-icons/fi';
import {useThemeColors} from '@/utils/useThemeColors';
const ContactCTA = () => {
const colors = useThemeColors();
return (
<section
className="relative w-full py-24 overflow-hidden transition-colors duration-700 ease-in-out"
style={{backgroundColor: colors.primaryBg, color: colors.primaryText}}
>
<div className="w-full max-w-4xl px-6 md:px-10 mx-auto text-center">
{/* Headline */}
<motion.h2
className="text-3xl md:text-4xl font-bold transition-colors duration-700 ease-in-out"
>
Interesse geweckt?
</motion.h2>
{/* Description */}
<motion.p
className="mt-4 text-sm md:text-base max-w-xl mx-auto transition-colors duration-700 ease-in-out"
style={{color: colors.secondaryText}}
initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.5, delay: 0.2}}
>
Lass uns über dein Projekt sprechen. Wir freuen uns darauf, deine Ideen in die Realität umzusetzen.
</motion.p>
{/* CTA Button */}
<motion.div
className="mt-8 flex justify-center"
initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.5, delay: 0.3}}
>
<Link href="/contact">
<button
className="inline-flex items-center gap-2 px-6 py-3 text-sm md:text-base font-semibold rounded-full bg-blue-700 hover:bg-blue-900 text-white shadow-md transition-all duration-300"
>
Jetzt Kontakt aufnehmen <FiArrowRight size={18}/>
</button>
</Link>
</motion.div>
</div>
</section>
);
};
export default ContactCTA;

View File

@@ -1,13 +1,8 @@
'use client';
import {
FiServer,
FiTool,
FiMonitor,
FiZap,
FiArrowRight,
} from 'react-icons/fi';
import {FiServer, FiTool, FiMonitor, FiZap, FiArrowRight} from 'react-icons/fi';
import {motion} from 'framer-motion';
import {useThemeColors} from '@/utils/useThemeColors';
const services = [
{
@@ -37,19 +32,16 @@ const services = [
];
const HomeServices = () => {
const colors = useThemeColors();
return (
<section
className="w-full py-24 bg-[var(--primary-bg)] transition-theme"
id="leistungen"
className="w-full py-24 transition-colors duration-700 ease-in-out"
style={{backgroundColor: colors.primaryBg}}
>
<div className="w-full max-w-6xl px-6 md:px-10 mx-auto">
{/* Heading */}
<div className="w-full max-w-6xl px-6 md:px-10 mx-auto" style={{color: colors.primaryText}}>
<motion.h2
className="text-3xl md:text-4xl font-bold mb-1 text-left text-[var(--primary-text)]"
initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.4}}
className="text-3xl md:text-4xl font-bold mb-1 text-left transition-colors duration-700 ease-in-out"
>
Leistungen
</motion.h2>
@@ -62,12 +54,16 @@ const HomeServices = () => {
transition={{duration: 0.4, delay: 0.1}}
/>
{/* Service Cards */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{services.map((service, index) => (
<motion.div
key={service.title}
className="p-6 rounded-xl border border-[var(--secondary-bg)] bg-[var(--secondary-bg)] shadow-md"
className="p-6 rounded-xl border shadow-md transition-colors duration-700 ease-in-out"
style={{
backgroundColor: colors.secondaryBg,
borderColor: colors.secondaryBg,
color: colors.primaryText,
}}
whileHover={{
scale: 1.03,
boxShadow: '0px 10px 20px rgba(0,0,0,0.1)',
@@ -75,24 +71,18 @@ const HomeServices = () => {
initial={{opacity: 0, y: 30}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{
duration: 0.4,
delay: index * 0.1,
ease: 'easeOut',
}}
transition={{duration: 0.4, delay: index * 0.1}}
>
<div className="mb-3 text-blue-600">{service.icon}</div>
<h3 className="text-xl font-semibold mb-2 text-[var(--primary-text)]">
{service.title}
</h3>
<p className="text-sm text-[var(--secondary-text)] leading-relaxed">
<h3 className="text-xl font-semibold mb-2">{service.title}</h3>
<p className="text-sm leading-relaxed transition-colors duration-700 ease-in-out"
style={{color: colors.secondaryText}}>
{service.description}
</p>
</motion.div>
))}
</div>
{/* Weitere Leistungen */}
<motion.div
className="mt-10 flex justify-end"
initial={{opacity: 0}}
@@ -112,4 +102,4 @@ const HomeServices = () => {
);
};
export default HomeServices;
export default HomeServices;

View File

@@ -2,6 +2,7 @@
import Image from 'next/image';
import {motion} from 'framer-motion';
import {useThemeColors} from "@/utils/useThemeColors";
const techStack = {
row1: [
@@ -54,15 +55,16 @@ const techStack = {
};
const TechStack = () => {
const colors = useThemeColors();
return (
<section className="w-full py-20 bg-[var(--secondary-bg)] transition-theme">
<div className="w-full max-w-6xl px-6 md:px-10 mx-auto">
<section
className="w-full py-20 transition-colors duration-700 ease-in-out"
style={{backgroundColor: colors.secondaryBg}}
>
<div className="w-full max-w-6xl px-6 md:px-10 mx-auto" style={{color: colors.primaryText}}>
<motion.h2
className="text-2xl md:text-3xl font-bold mb-1 text-left text-[var(--primary-text)]"
initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.5}}
className="text-3xl md:text-4xl font-bold mb-1 text-left transition-colors duration-700 ease-in-out"
>
Technologien
</motion.h2>
@@ -76,30 +78,20 @@ const TechStack = () => {
/>
<motion.p
className="text-sm md:text-base mb-10 text-[var(--secondary-text)]"
initial={{opacity: 0, y: 10}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.4, delay: 0.2}}
className="text-sm md:text-base mb-10 transition-colors duration-700 ease-in-out"
style={{color: colors.secondaryText}}
>
Mit diesen Technologien realisieren wir moderne, leistungsstarke Softwarelösungen.
</motion.p>
{/* Row 1 */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
{techStack.row1.map((group, index) => (
<TechCard key={group.category} group={group} delay={index * 0.2}/>
<TechCard key={group.category} group={group} delay={index * 0.2} colors={colors}/>
))}
</div>
{/* Row 2 */}
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
{techStack.row2.map((group, index) => (
<TechCard
key={group.category}
group={group}
delay={index * 0.2 + 0.4}
/>
<TechCard key={group.category} group={group} delay={index * 0.2 + 0.4} colors={colors}/>
))}
</div>
</div>
@@ -110,35 +102,32 @@ const TechStack = () => {
const TechCard = ({
group,
delay,
colors,
}: {
group: { category: string; items: { id: string; label: string }[] };
delay: number;
colors: ReturnType<typeof useThemeColors>;
}) => (
<motion.div
className="p-4 rounded-lg border border-[var(--primary-bg)] bg-[var(--primary-bg)] shadow-md transition-theme"
className="p-4 rounded-lg border shadow-md transition-colors duration-700 ease-in-out"
style={{
backgroundColor: colors.primaryBg,
borderColor: colors.primaryBg,
color: colors.primaryText,
}}
initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}}
whileHover={{
scale: 1.03,
boxShadow: '0px 10px 20px rgba(0,0,0,0.1)',
}}
whileHover={{scale: 1.03, boxShadow: '0 10px 20px rgba(0,0,0,0.1)'}}
viewport={{once: true}}
transition={{duration: 0.4, delay, ease: 'easeOut'}}
transition={{duration: 0.4, delay}}
>
<h3 className="text-base font-semibold mb-4 text-[var(--primary-text)]">
{group.category}
</h3>
<h3 className="text-base font-semibold mb-4">{group.category}</h3>
<div className="grid grid-cols-3 gap-3">
{group.items.map(({id, label}) => (
<div key={id} className="flex flex-col items-center text-center">
<Image
src={`/images/svg/${id}.svg`}
alt={label}
width={32}
height={32}
className="object-contain"
/>
<span className="text-[10px] mt-1 text-[var(--secondary-text)]">
<Image src={`/images/svg/${id}.svg`} alt={label} width={32} height={32} className="object-contain"/>
<span className="text-[10px] mt-1 transition-colors duration-700 ease-in-out"
style={{color: colors.secondaryText}}>
{label}
</span>
</div>
@@ -147,4 +136,4 @@ const TechCard = ({
</motion.div>
);
export default TechStack;
export default TechStack;