Merge branch 'dev' into 'production'

Merge dev into production

See merge request rheinsw/website!27
This commit is contained in:
2025-04-13 20:12:11 +00:00
parent f9d2552b90
commit 40f266f8da
79 changed files with 3477 additions and 288 deletions

View File

@@ -0,0 +1,82 @@
'use client';
import Link from 'next/link';
import {FiArrowRight} from 'react-icons/fi';
import {motion} from 'framer-motion';
const About = () => {
return (
<section className="relative w-full py-24 bg-[var(--secondary-bg)] transition-theme">
<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}}
>
Über uns
</motion.h2>
<motion.div
className="w-12 h-[2px] mt-2 mb-6 bg-amber-500"
initial={{opacity: 0, x: -20}}
whileInView={{opacity: 1, x: 0}}
viewport={{once: true}}
transition={{duration: 0.4, delay: 0.1}}
/>
{/* Text */}
<div className="p-0">
<motion.p
className="text-base md:text-lg leading-relaxed text-[var(--secondary-text)] max-w-4xl"
initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.5, delay: 0.2}}
>
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.
</motion.p>
<motion.p
className="mt-6 text-base md:text-lg leading-relaxed text-[var(--secondary-text)] max-w-4xl"
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.
</motion.p>
</div>
{/* CTA Button */}
<motion.div
className="mt-10 flex justify-end"
initial={{opacity: 0, y: 10}}
whileInView={{opacity: 1, y: 0}}
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>
</motion.div>
</div>
</div>
</section>
);
};
export default About;

View File

@@ -0,0 +1,57 @@
'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

@@ -0,0 +1,100 @@
'use client';
import Image from 'next/image';
import {Typewriter} from 'react-simple-typewriter';
import {motion} from 'framer-motion';
const Hero = () => {
return (
<div
className="relative w-full pt-[4vh] md:pt-[12vh] h-screen flex flex-col overflow-hidden"
style={{
backgroundColor: 'var(--primary-bg)',
color: 'white',
}}
>
{/* 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">
{/* Text Content */}
<div>
<motion.h1
className="text-3xl sm:text-4xl md:text-5xl mt-6 mb-6 font-bold text-white"
initial={{opacity: 0, y: 30}}
animate={{opacity: 1, y: 0}}
transition={{duration: 0.6, ease: 'easeOut'}}
>
Rhein-Software Development
</motion.h1>
<motion.p
className="text-lg md:text-xl text-gray-400"
initial={{opacity: 0, y: 30}}
animate={{opacity: 1, y: 0}}
transition={{duration: 0.6, delay: 0.2, ease: 'easeOut'}}
>
Digitale Lösungen für dein Unternehmen.
</motion.p>
<motion.p
className="mt-4 text-lg md:text-xl font-semibold text-white"
initial={{opacity: 0}}
animate={{opacity: 1}}
transition={{delay: 0.9, duration: 0.6}}
>
<Typewriter
words={['Beratung', 'Entwicklung', 'Wartung', 'Fehlerbehebung']}
loop={true}
cursor
cursorStyle="_"
typeSpeed={60}
deleteSpeed={40}
delaySpeed={1500}
/>
</motion.p>
</div>
{/* Floating Image */}
<motion.div
className="hidden lg:block"
initial={{opacity: 0, y: 30}}
animate={{opacity: 1, y: 0}}
transition={{duration: 0.8, ease: 'easeOut', delay: 0.3}}
>
<motion.div
animate={{y: [0, -10, 0]}}
transition={{
duration: 4,
repeat: Infinity,
ease: 'easeInOut',
}}
className="animate-float"
>
<Image
src="/images/hero.png"
alt="hero graphic"
width={700}
height={700}
/>
</motion.div>
</motion.div>
</div>
</div>
</div>
);
};
export default Hero;

27
components/Home/Home.tsx Normal file
View File

@@ -0,0 +1,27 @@
'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";
const Home = () => {
return (
<div className="overflow-hidden">
<Hero/>
<SectionDivider1/>
<About/>
<SectionDivider2/>
<HomeServices/>
<SectionDivider1/>
<TechStack/>
<SectionDivider2/>
<ContactCTA/>
</div>
);
};
export default Home;

View File

@@ -0,0 +1,115 @@
'use client';
import {
FiServer,
FiTool,
FiMonitor,
FiZap,
FiArrowRight,
} from 'react-icons/fi';
import {motion} from 'framer-motion';
const services = [
{
title: 'Beratung',
icon: <FiMonitor size={24}/>,
description:
'Strategische und technische Beratung rund um digitale Produkte und Prozesse. Wir analysieren bestehende Systeme, identifizieren Potenziale und helfen dir, die passende Architektur für dein Projekt zu finden.',
},
{
title: 'Entwicklung',
icon: <FiZap size={24}/>,
description:
'Individuelle Softwareentwicklung skalierbar, wartbar, zukunftssicher. Ob Web-App, API oder internes Tool: Wir setzen moderne Technologien ein, um genau die Lösung zu bauen, die du brauchst.',
},
{
title: 'Managed Services',
icon: <FiServer size={24}/>,
description:
'Wir betreuen Infrastruktur, Server und Systeme verlässlich und performant. Unser Team kümmert sich um Hosting, Monitoring, Backups und sorgt für einen reibungslosen Betrieb deiner Plattform.',
},
{
title: 'Fehlerbehebung',
icon: <FiTool size={24}/>,
description:
'Schnelle Hilfe bei Bugs, Performance-Problemen oder Sicherheitslücken. Wir analysieren Probleme, beheben sie gezielt und sorgen dafür, dass dein System wieder stabil läuft langfristig und zuverlässig.',
},
];
const HomeServices = () => {
return (
<section
className="w-full py-24 bg-[var(--primary-bg)] transition-theme"
id="leistungen"
>
<div className="w-full max-w-6xl px-6 md:px-10 mx-auto">
{/* Heading */}
<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}}
>
Leistungen
</motion.h2>
<motion.div
className="w-12 h-[2px] mt-2 mb-10 bg-amber-500"
initial={{opacity: 0, x: -20}}
whileInView={{opacity: 1, x: 0}}
viewport={{once: true}}
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"
whileHover={{
scale: 1.03,
boxShadow: '0px 10px 20px rgba(0,0,0,0.1)',
}}
initial={{opacity: 0, y: 30}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{
duration: 0.4,
delay: index * 0.1,
ease: 'easeOut',
}}
>
<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">
{service.description}
</p>
</motion.div>
))}
</div>
{/* Weitere Leistungen */}
<motion.div
className="mt-10 flex justify-end"
initial={{opacity: 0}}
whileInView={{opacity: 1}}
viewport={{once: true}}
transition={{duration: 0.4, delay: 0.3}}
>
<a
href="/services"
className="text-sm font-semibold text-blue-600 hover:underline flex items-center gap-1"
>
Weitere Leistungen <FiArrowRight size={16}/>
</a>
</motion.div>
</div>
</section>
);
};
export default HomeServices;

View File

@@ -0,0 +1,75 @@
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

@@ -0,0 +1,57 @@
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

@@ -0,0 +1,28 @@
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

@@ -0,0 +1,150 @@
'use client';
import Image from 'next/image';
import {motion} from 'framer-motion';
const techStack = {
row1: [
{
category: 'Programmiersprachen & Frameworks Backend',
items: [
{id: 'java', label: 'Java'},
{id: 'dart', label: 'Dart'},
{id: 'kotlin', label: 'Kotlin'},
{id: 'spring', label: 'Spring'},
],
},
{
category: 'Programmiersprachen & Frameworks Frontend',
items: [
{id: 'html', label: 'HTML'},
{id: 'css', label: 'CSS'},
{id: 'bootstrap', label: 'Bootstrap'},
{id: 'nextjs', label: 'Next.js'},
{id: 'typescript', label: 'TypeScript'},
{id: 'flutter', label: 'Flutter'},
],
},
],
row2: [
{
category: 'Betriebssysteme',
items: [
{id: 'macos', label: 'macOS'},
{id: 'debian', label: 'Debian'},
{id: 'ubuntu', label: 'Ubuntu'},
],
},
{
category: 'Version Control & Collaboration',
items: [
{id: 'gitlab', label: 'GitLab'},
{id: 'outline', label: 'Outline'},
],
},
{
category: 'DevOps & Infrastruktur',
items: [
{id: 'gitlab-ci', label: 'GitLab CI'},
{id: 'docker', label: 'Docker'},
{id: 'proxmox', label: 'Proxmox'},
],
},
],
};
const TechStack = () => {
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">
<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}}
>
Technologien
</motion.h2>
<motion.div
className="w-12 h-[2px] mt-2 mb-6 bg-amber-500"
initial={{opacity: 0, x: -20}}
whileInView={{opacity: 1, x: 0}}
viewport={{once: true}}
transition={{duration: 0.4, delay: 0.1}}
/>
<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}}
>
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}/>
))}
</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}
/>
))}
</div>
</div>
</section>
);
};
const TechCard = ({
group,
delay,
}: {
group: { category: string; items: { id: string; label: string }[] };
delay: number;
}) => (
<motion.div
className="p-4 rounded-lg border border-[var(--primary-bg)] bg-[var(--primary-bg)] shadow-md transition-theme"
initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}}
whileHover={{
scale: 1.03,
boxShadow: '0px 10px 20px rgba(0,0,0,0.1)',
}}
viewport={{once: true}}
transition={{duration: 0.4, delay, ease: 'easeOut'}}
>
<h3 className="text-base font-semibold mb-4 text-[var(--primary-text)]">
{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)]">
{label}
</span>
</div>
))}
</div>
</motion.div>
);
export default TechStack;