Refactor website to use shadcn components

This commit is contained in:
2025-06-28 12:01:43 +00:00
parent 1648e376bf
commit 8c05ad29cb
78 changed files with 3858 additions and 2722 deletions

View File

@@ -0,0 +1,86 @@
'use client';
import {motion} from 'framer-motion';
const About = () => {
return (
<section
id="about"
className="relative w-full py-24 bg-background text-foreground transition-colors duration-700 ease-in-out">
<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"
initial={{opacity: 0, y: 10}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.4}}
>
Ü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 max-w-4xl">
<motion.p
className="text-base md:text-lg leading-relaxed text-muted-foreground"
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 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-muted-foreground"
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. Gemeinsam
realisieren wir digitale Produkte, die wirklich passen.
</motion.p>
<motion.p
className="mt-6 text-base md:text-lg leading-relaxed text-muted-foreground"
initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.5, delay: 0.4}}
>
Egal ob App-Entwicklung, interne Tools, Web-Plattformen oder komplexe Schnittstellen wir
entwickeln Softwarelösungen, die intuitiv, effizient und exakt auf deine Anforderungen
zugeschnitten sind.
</motion.p>
</div>
{/* CTA Placeholder */}
<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}}
>
{/* CTA button can go here */}
</motion.div>
</div>
</div>
</section>
);
};
export default About;

View File

@@ -0,0 +1,109 @@
'use client'
import {Accordion, AccordionContent, AccordionItem, AccordionTrigger,} from "@/components/ui/accordion"
import {motion} from "framer-motion"
const faqItems = [
{
id: "dauer",
question: "Wie lange dauert es, bis meine Website oder App online ist?",
answers: [
"Das hängt vom Umfang des Projekts ab einfache Websites oder MVPs sind meist innerhalb von 46 Wochen realisierbar.",
"Komplexere Anwendungen oder individuelle Features benötigen entsprechend mehr Zeit. Wir geben dir zu Beginn eine realistische Einschätzung.",
],
},
{
id: "inhalte",
question: "Muss ich Texte und Bilder selbst liefern?",
answers: [
"Wenn du Inhalte hast, bauen wir diese gerne ein. Falls nicht, unterstützen wir dich mit Textvorschlägen, Icons oder lizenzfreien Bildern.",
"Bei Apps helfen wir dir auch bei der Strukturierung und Formulierung von App-Inhalten, z.B. Onboarding-Texte oder UI-Texte.",
],
},
{
id: "technik",
question: "Ich habe keine Ahnung von Technik funktioniert das trotzdem?",
answers: [
"Auf jeden Fall. Wir begleiten dich Schritt für Schritt und erklären alles verständlich ganz ohne Fachkenntnisse..",
"Du bekommst eine Lösung, die für dich funktioniert egal ob Website, App oder Backend.",
],
},
{
id: "änderungen",
question: "Was ist, wenn ich im Nachhinein etwas ändern möchte?",
answers: [
"Kein Problem. Du kannst jederzeit neue Inhalte, Features oder Anpassungen beauftragen.",
"Auf Wunsch übernehmen wir auch die laufende Wartung oder stellen dir ein CMS bzw. Admin-Interface bereit.",
],
},
{
id: "seo",
question: "Wird meine Website oder App auch für Suchmaschinen optimiert?",
answers: [
"Ja. Jede Website wird suchmaschinenfreundlich aufgebaut inkl. technischer SEO-Basics wie saubere Struktur, schnelle Ladezeit und mobile Optimierung.",
"Bei Apps unterstützen wir dich z.B. auch mit App Store Optimierung (ASO), damit du besser gefunden wirst.",
],
},
]
export default function Faq() {
return (
<section id="faq" className="py-24 px-4 bg-background text-foreground">
<div className="max-w-3xl mx-auto">
<motion.h2
className="text-3xl md:text-4xl font-bold mb-2 text-center"
initial={{opacity: 0, y: 10}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.4}}
>
Fragen? Antworten.
</motion.h2>
<motion.div
className="w-12 h-[2px] mt-2 mb-6 bg-amber-500 mx-auto"
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-muted-foreground text-center"
initial={{opacity: 0, y: 10}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.4, delay: 0.2}}
>
Hier beantworten wir häufige Fragen rund um Web- und App-Projekte klar gegliedert nach Themen.
Wenn du darüber hinaus etwas wissen möchtest, melde dich gerne persönlich bei uns.
</motion.p>
<motion.div
className="text-sm md:text-base mb-10 text-muted-foreground text-center"
initial={{opacity: 0, y: 10}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.4, delay: 0.4}}
>
<Accordion
type="single"
collapsible
className="w-full"
>
{faqItems.map((item, index) => (
<AccordionItem key={index} value={`faq-${index}`}>
<AccordionTrigger>{item.question}</AccordionTrigger>
<AccordionContent className="flex flex-col gap-4 text-left">
{item.answers.map((text, idx) => (
<p key={idx}>{text}</p>
))}
</AccordionContent>
</AccordionItem>
))}
</Accordion>
</motion.div>
</div>
</section>
)
}

View File

@@ -0,0 +1,76 @@
'use client';
import {motion} from 'framer-motion';
import Image from 'next/image';
import {Typewriter} from 'react-simple-typewriter';
import PulsatingButton from "@/components/PulsatingButton";
const Hero = () => {
return (
<section id="start" className="relative w-full h-screen overflow-hidden">
{/* Background */}
<div className="absolute inset-0 z-0">
<Image
src="/images/home_hero.jpg"
alt="Rhein river aerial view"
fill
className="object-cover scale-105 blur-sm"
priority
/>
<div className="absolute inset-0 bg-black/60"/>
</div>
{/* Content */}
<div
className="relative z-10 flex flex-col justify-center items-start h-full w-[90%] sm:w-[80%] max-w-6xl mx-auto text-white">
<motion.h1
className="text-3xl sm:text-5xl font-bold mb-6 leading-tight"
initial={{opacity: 0, y: 40}}
animate={{opacity: 1, y: 0}}
transition={{duration: 0.6}}
>
Digitale Lösungen, <br/> die wirklich passen.
</motion.h1>
<motion.p
className="text-lg sm:text-xl text-gray-300 mb-6 max-w-2xl"
initial={{opacity: 0, y: 20}}
animate={{opacity: 1, y: 0}}
transition={{duration: 0.6, delay: 0.2}}
>
Wir entwickeln individuelle Softwarelösungen für Unternehmen und Startups.
</motion.p>
<motion.div
className="text-xl font-semibold text-white"
initial={{opacity: 0}}
animate={{opacity: 1}}
transition={{delay: 0.6}}
>
<Typewriter
words={['Webdesign', 'App-Entwicklung', 'Interne Tools']}
loop={true}
cursor
cursorStyle="_"
typeSpeed={60}
deleteSpeed={40}
delaySpeed={2000}
/>
</motion.div>
<div className="mt-10 relative flex items-center justify-center">
<PulsatingButton
label="Jetzt Kontakt aufnehmen"
href="/contact"
color="#2563eb" // Tailwind blue-600
width={256}
pulse
/>
</div>
</div>
</section>
);
};
export default Hero;

View File

@@ -0,0 +1,115 @@
'use client';
import {motion} from 'framer-motion';
import {ChevronRight} from 'lucide-react';
import Link from 'next/link';
const services = [
{
title: 'Webdesign',
description: 'Moderne Websites, die Vertrauen schaffen und verkaufen.',
bullets: [
'Maßgeschneidertes Design',
'Klare Struktur & überzeugende Inhalte',
'Nutzerführung mit System & Strategie',
'Für alle Geräte optimiert',
],
},
{
title: 'App-Entwicklung',
description: 'Skalierbare Apps für Web und Mobile von der Idee bis zum Launch.',
bullets: [
'Plattformübergreifend mit modernen Technologien',
'Backend & API-Entwicklung inklusive',
'Individuelle Funktionen & Logik',
'Stabil, performant & wartbar',
],
},
{
title: 'Interne Tools',
description: 'Digitale Werkzeuge, die Prozesse vereinfachen und Zeit sparen.',
bullets: [
'Prozessdigitalisierung & Automatisierung',
'Zugeschnitten auf eure Workflows',
'Skalierbar & zukunftssicher',
'Intuitiv & effizient bedienbar',
],
},
];
const HomeServices = () => {
return (
<section id="services"
className="w-full py-24 bg-background text-foreground">
<div className="w-full max-w-6xl px-6 md:px-10 mx-auto">
<motion.h2
className="text-3xl md:text-4xl font-bold mb-1 text-left"
initial={{opacity: 0, y: 10}}
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}}
/>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{services.map((service, index) => (
<motion.div
key={service.title}
className="flex flex-col justify-between h-full p-6 rounded-3xl border bg-muted text-foreground"
initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.4, delay: index * 0.1}}
whileHover={{
scale: 1.03,
boxShadow: '0px 12px 30px rgba(0, 0, 0, 0.08)',
}}
>
<div>
<h3 className="text-xl font-semibold mb-2">{service.title}</h3>
<p className="text-muted-foreground mb-4">{service.description}</p>
<ul className="space-y-3">
{service.bullets.map((point, i) => (
<li key={i} className="flex items-start gap-2">
<ChevronRight className="w-4 h-4 text-primary mt-1"/>
<span className="text-sm text-foreground">{point}</span>
</li>
))}
</ul>
</div>
</motion.div>
))}
</div>
<motion.div
className="mt-12 text-center"
initial={{opacity: 0}}
whileInView={{opacity: 1}}
viewport={{once: true}}
transition={{duration: 0.4, delay: 0.3}}
>
<p className="text-muted-foreground mb-4 text-base md:text-lg">
Du möchtest mehr über unsere Leistungen erfahren oder hast ein konkretes Projekt im Kopf?
</p>
<Link
href="/contact"
className="text-sm font-semibold text-primary hover:underline"
>
Jetzt Kontakt aufnehmen
</Link>
</motion.div>
</div>
</section>
);
};
export default HomeServices;

View File

@@ -0,0 +1,88 @@
'use client';
import React from 'react';
import {VerticalTimeline, VerticalTimelineElement} from 'react-vertical-timeline-component';
import {FaRocket, FaLightbulb, FaCode, FaPaperPlane} from 'react-icons/fa';
import 'react-vertical-timeline-component/style.min.css';
import {motion} from 'framer-motion';
const steps = [
{
title: 'Kick-Off & Strategie',
description:
'In einem gemeinsamen Auftakt klären wir deine Ziele, Zielgruppen und Herausforderungen. Daraus entsteht ein strukturierter Plan als Basis für alles Weitere.',
icon: <FaRocket/>,
},
{
title: 'Konzept & Inhalte',
description:
'Wir erarbeiten eine klare Struktur und passende Inhalte abgestimmt auf deine Botschaft und deine Nutzer. So entsteht ein roter Faden für Design und Umsetzung.',
icon: <FaLightbulb/>,
},
{
title: 'Design & Entwicklung',
description:
'Wir gestalten ein modernes Design und setzen es technisch um. Durch regelmäßige Feedback-Schleifen bist du jederzeit im Prozess eingebunden.',
icon: <FaCode/>,
},
{
title: 'Go-Live',
description:
'Nach erfolgreichen Tests geht dein Projekt live. Auch danach begleiten wir dich weiter für einen reibungslosen Betrieb und mögliche Weiterentwicklungen.',
icon: <FaPaperPlane/>,
},
];
const ProcessSection = () => {
return (
<section id="process" className="w-full py-24 bg-background text-foreground">
<div className="max-w-6xl px-6 md:px-10 mx-auto">
<motion.h2
className="text-3xl md:text-4xl font-bold mb-1"
initial={{opacity: 0, y: 10}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.4}}
>
Unser Prozess
</motion.h2>
<motion.div
className="w-12 h-[2px] mt-2 mb-12 bg-amber-500"
initial={{opacity: 0, x: -20}}
whileInView={{opacity: 1, x: 0}}
viewport={{once: true}}
transition={{duration: 0.4, delay: 0.1}}
/>
<VerticalTimeline
lineColor="#eab308"
animate={true}
>
{steps.map((step, idx) => (
<VerticalTimelineElement
key={idx}
contentStyle={{
background: 'hsl(var(--muted))',
color: 'hsl(var(--foreground))',
border: '1px solid hsl(var(--border))',
}}
contentArrowStyle={{borderRight: '7px solid hsl(var(--muted))'}}
iconStyle={{
background: '#eab308',
color: '#fff',
}}
icon={step.icon}
>
<h3 className="text-xl font-semibold">{step.title}</h3>
<p className="text-muted-foreground mt-2">{step.description}</p>
</VerticalTimelineElement>
))}
</VerticalTimeline>
</div>
</section>
);
};
export default ProcessSection;

View File

@@ -0,0 +1,60 @@
'use client'
import {motion} from 'framer-motion'
import Link from 'next/link'
export default function ReferralSection() {
return (
<section id="referral" className="py-24 px-4 bg-background/80 text-foreground">
<div className="max-w-3xl mx-auto text-center">
<motion.h2
className="text-3xl md:text-4xl font-bold mb-2"
initial={{opacity: 0, y: 10}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.4}}
>
Weiterempfehlen lohnt sich
</motion.h2>
<motion.div
className="w-12 h-[2px] mt-2 mb-6 bg-amber-500 mx-auto"
initial={{opacity: 0, x: -20}}
whileInView={{opacity: 1, x: 0}}
viewport={{once: true}}
transition={{duration: 0.4, delay: 0.1}}
/>
<motion.div
className="text-sm md:text-base mb-8 text-muted-foreground space-y-4"
initial={{opacity: 0, y: 10}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.4, delay: 0.2}}
>
<p>
Du empfiehlst uns weiter und dein Kontakt wird Kunde?
Als Dank erhältst du <strong>10 % Rabatt</strong> auf dein nächstes Projekt bei uns.
</p>
<p>
Einfach, fair und lohnend ideal für alle, die mit unserer Arbeit zufrieden sind.
</p>
</motion.div>
<motion.div
initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.5, delay: 0.3}}
>
<Link
href="/contact"
className="inline-block bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-full font-semibold transition"
>
Jetzt empfehlen
</Link>
</motion.div>
</div>
</section>
)
}

View File

@@ -0,0 +1,87 @@
'use client';
import Image from 'next/image';
import {motion} from 'framer-motion';
import {techStack} from "@/constant/TechStack";
const TechStack = () => {
return (
<section className="w-full py-20 bg-background text-foreground transition-colors duration-700 ease-in-out">
<div className="w-full max-w-6xl px-6 md:px-10 mx-auto">
<motion.h2
className="text-3xl md:text-4xl font-bold mb-1 text-left"
initial={{opacity: 0, y: 10}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.4}}
>
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-muted-foreground"
initial={{opacity: 0, y: 10}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.3, delay: 0.2}}
>
Mit diesen Technologien realisieren wir moderne, leistungsstarke Softwarelösungen.
</motion.p>
<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>
<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 bg-muted shadow-md text-foreground"
initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}}
whileHover={{scale: 1.03, boxShadow: '0 10px 20px rgba(0,0,0,0.1)'}}
viewport={{once: true}}
transition={{duration: 0.4, delay}}
>
<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-muted-foreground">{label}</span>
</div>
))}
</div>
</motion.div>
);
export default TechStack;

View File

@@ -0,0 +1,69 @@
'use client';
import {CheckCircle} from 'lucide-react';
import {motion} from 'framer-motion';
import Link from 'next/link';
import Image from 'next/image';
const points = [
'Fertigstellung in 48 Wochen',
'Fester Ansprechpartner von Anfang bis Ende',
'Struktur & Klarheit',
'Starkes Alleinstellungsmerkmal',
'Zuverlässiges Team mit Weitblick',
];
export default function WhyUs() {
return (
<section id="whyus" className="py-24 px-4 bg-background text-foreground">
<div className="max-w-xl mx-auto">
<motion.h2
className="text-3xl md:text-4xl font-bold mb-1 text-center"
initial={{opacity: 0, y: 10}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.4}}
>
Warum wir?
</motion.h2>
<motion.div
className="w-12 h-[2px] mt-2 mb-10 bg-amber-500 mx-auto"
initial={{opacity: 0, x: -20}}
whileInView={{opacity: 1, x: 0}}
viewport={{once: true}}
transition={{duration: 0.4, delay: 0.1}}
/>
<motion.div
className="rounded-2xl p-8 md:p-10 bg-gradient-to-br from-[#1e3a8a] to-[#2563eb] text-white shadow-xl relative overflow-hidden"
initial={{opacity: 0, y: 40}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.5}}
>
{/* Logo */}
<div className="mb-6">
<Image src="/logo.svg" alt="Rhein Software Logo" width={120} height={32}/>
</div>
<ul className="space-y-4 mb-8">
{points.map((point, index) => (
<li key={index} className="flex items-start gap-2">
<CheckCircle className="text-white w-5 h-5 flex-shrink-0 mt-0.5"/>
<span>{point}</span>
</li>
))}
</ul>
<Link
href="/contact"
className="inline-block bg-white text-blue-700 font-semibold px-6 py-3 rounded-full text-center shadow-md hover:bg-slate-100 transition"
>
Kostenlose Beratung anfragen
</Link>
</motion.div>
</div>
</section>
);
}