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,117 @@
"use client";
import {motion} from "framer-motion";
const fadeInUp = {
hidden: {opacity: 0, y: 30},
visible: (i: number) => ({
opacity: 1,
y: 0,
transition: {
duration: 0.6,
delay: i * 0.2,
ease: "easeOut",
},
}),
};
const ImprintComp = () => {
const sections = [
{
title: "Impressum",
content: (
<>
Thatsaphorn Atchariyaphap<br/>
Rhein-Software (Einzelunternehmer)<br/>
Mühlenstrasse 13<br/>
79664 Wehr
</>
),
},
{
title: "Kontakt",
content: (
<>
Telefon: +49 (0) 151 24003632<br/>
E-Mail:{" "}
<a
href="mailto:contact@rhein-software.dev"
className="underline text-primary"
>
contact@rhein-software.dev
</a>
</>
),
},
{
title: "EU-Streitschlichtung",
content: (
<>
Die Europäische Kommission stellt eine Plattform zur
Online-Streitbeilegung (OS) bereit:{" "}
<a
href="https://ec.europa.eu/consumers/odr/"
target="_blank"
rel="noopener noreferrer"
className="underline text-primary"
>
https://ec.europa.eu/consumers/odr/
</a>
.<br/>
Unsere E-Mail-Adresse finden Sie oben im Impressum.
</>
),
},
{
title: "Verbraucherstreitbeilegung / Universalschlichtungsstelle",
content: (
<>
Wir sind nicht bereit oder verpflichtet, an
Streitbeilegungsverfahren vor einer
Verbraucherschlichtungsstelle teilzunehmen.
</>
),
},
];
return (
<div className="overflow-hidden bg-background text-foreground">
<div className="mt-16 w-[90%] sm:w-[80%] mx-auto py-12 space-y-10 text-base leading-relaxed">
{sections.map((section, i) => (
<motion.div
key={section.title}
custom={i}
initial="hidden"
whileInView="visible"
viewport={{once: true, amount: 0.2}}
variants={fadeInUp}
>
<h2 className="text-2xl font-bold mb-4">{section.title}</h2>
<div className="space-y-4">{section.content}</div>
</motion.div>
))}
<motion.p
className="text-sm text-muted-foreground"
custom={4}
initial="hidden"
whileInView="visible"
viewport={{once: true, amount: 0.2}}
variants={fadeInUp}
>
Quelle:{" "}
<a
href="https://www.e-recht24.de"
target="_blank"
rel="noopener noreferrer"
className="underline"
>
www.e-recht24.de
</a>
</motion.p>
</div>
</div>
);
};
export default ImprintComp;

View File

@@ -1,10 +1,17 @@
import React from 'react';
import ImprintComp from "@/components/Legal/Imprint/ImprintComp";
import ImprintComp from "@/app/legal/imprint/ImprintComp";
import type {Metadata} from "next";
export async function generateMetadata(): Promise<Metadata> {
return {
title: "Impressum | Rhein Software",
};
}
const ImprintPage = () => {
return (
<div>
<ImprintComp />
<ImprintComp/>
</div>
);
};

View File

@@ -1,38 +0,0 @@
import type {Metadata} from "next";
import "../globals.css";
import Nav from "@/components/Navbar/Nav";
import Footer from "@/components/Footer/Footer";
import {ThemeProvider} from "@/components/provider/ThemeProvider";
import React from "react";
import {cookies} from "next/headers";
import {themeColors} from "@/components/Helper/ThemeColors";
export const metadata: Metadata = {
title: "Rechtliches | 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";
const bgColor = themeColors[theme].primaryBg;
return (
<html lang="de" data-theme={theme}>
<head/>
<body className="antialiased" style={{backgroundColor: bgColor}}>
<ThemeProvider>
<Nav/>
{children}
<Footer/>
</ThemeProvider>
</body>
</html>
);
}

View File

@@ -1,10 +1,60 @@
import React from 'react';
'use client'
const LegalPage = () => {
import Link from 'next/link'
import {motion} from 'framer-motion'
import SmallHero from '@/components/Helper/SmallHero'
import {Card, CardContent} from '@/components/ui/card'
const legalLinks = [
{
label: 'Impressum',
href: '/legal/imprint',
},
{
label: 'Datenschutz',
href: '/legal/privacy',
},
{
label: 'Widerrufsrecht',
href: '/legal/revocation',
},
{
label: 'Nutzungsbedingungen',
href: '/legal/terms-of-use',
},
]
export default function LegalOverviewPage() {
return (
<div>
</div>
);
};
<>
<SmallHero
title="Rechtliches"
subtitle="Alle rechtlich relevanten Informationen auf einen Blick."
backgroundImage="/images/contact.png"
blurBackground
/>
export default LegalPage;
<section className="px-6 sm:px-12 py-16 max-w-6xl mx-auto">
<motion.div
className="grid grid-cols-1 sm:grid-cols-2 gap-6"
initial={{opacity: 0, y: 20}}
animate={{opacity: 1, y: 0}}
transition={{duration: 0.5, delay: 0.3}}
>
{legalLinks.map(({label, href}) => (
<Card key={href} className="hover:shadow-md transition-shadow">
<CardContent className="p-6">
<Link
href={href}
className="text-primary font-medium text-lg hover:underline"
>
{label}
</Link>
</CardContent>
</Card>
))}
</motion.div>
</section>
</>
)
}

View File

@@ -0,0 +1,124 @@
"use client";
import {motion} from "framer-motion";
const fadeInUp = {
hidden: {opacity: 0, y: 30},
visible: (i: number) => ({
opacity: 1,
y: 0,
transition: {
duration: 0.6,
delay: i * 0.2,
ease: "easeOut",
},
}),
};
const PrivacyComp = () => {
const sections = [
{
title: "1. Datenschutz auf einen Blick",
content: (
<>
<p>
Die folgenden Hinweise geben einen einfachen Überblick darüber, was mit Ihren personenbezogenen
Daten passiert, wenn Sie diese Website besuchen. Personenbezogene Daten sind alle Daten, mit
denen Sie persönlich identifiziert werden können.
</p>
<p>
Die Datenverarbeitung auf dieser Website erfolgt durch den Websitebetreiber. Dessen Kontaktdaten
finden Sie im Abschnitt Hinweis zur Verantwortlichen Stelle.
</p>
</>
),
},
{
title: "2. Allgemeine Hinweise und Pflichtinformationen",
content: (
<>
<p>
Wir behandeln Ihre personenbezogenen Daten vertraulich und entsprechend den gesetzlichen
Datenschutzvorschriften sowie dieser Datenschutzerklärung. Wir weisen darauf hin, dass die
Datenübertragung im Internet Sicherheitslücken aufweisen kann.
</p>
<p>
Verantwortlich für die Datenverarbeitung:
<br/>
Rhein-Software Development
<br/>
Mühlenstrasse 13
<br/>
79664 Wehr
<br/>
<br/>
Telefon: +49 (0) 151 24003632
<br/>
E-Mail: <a href="mailto:contact@rhein-software.dev"
className="underline text-primary">contact@rhein-software.dev</a>
</p>
</>
),
},
{
title: "3. Ihre Rechte",
content: (
<p>
Sie haben das Recht auf Auskunft, Berichtigung, Löschung, Einschränkung der Verarbeitung,
Datenübertragbarkeit sowie auf Widerspruch gegen die Verarbeitung Ihrer Daten. Zudem haben Sie
ein Beschwerderecht bei der zuständigen Aufsichtsbehörde.
</p>
),
},
{
title: "4. Analyse-Tools und Cookies",
content: (
<p>
Beim Besuch dieser Website kann Ihr Surfverhalten statistisch ausgewertet werden. Das geschieht
vor allem mit sogenannten Analyseprogrammen und Cookies. Detaillierte Informationen hierzu
entnehmen Sie bitte unserer vollständigen Datenschutzerklärung.
</p>
),
},
{
title: "5. Sicherheit",
content: (
<p>
Diese Seite nutzt eine SSL- bzw. TLS-Verschlüsselung. Eine verschlüsselte Verbindung erkennen
Sie an der Adresszeile des Browsers (https://“) und dem Schloss-Symbol.
</p>
),
},
{
title: "Quelle",
content: (
<p className="text-sm text-muted-foreground">
Quelle: <a href="https://www.e-recht24.de" target="_blank" rel="noopener noreferrer"
className="underline">www.e-recht24.de</a>
</p>
),
},
];
return (
<div className="overflow-hidden bg-background text-foreground">
<div className="mt-16 w-[90%] sm:w-[80%] mx-auto py-12 space-y-10 text-base leading-relaxed">
{sections.map((section, i) => (
<motion.div
key={section.title}
custom={i}
initial="hidden"
whileInView="visible"
viewport={{once: true, amount: 0.2}}
variants={fadeInUp}
>
<h2 className="text-2xl font-bold mb-4">{section.title}</h2>
<div className="space-y-4">{section.content}</div>
</motion.div>
))}
</div>
</div>
);
};
export default PrivacyComp;

View File

@@ -1,5 +1,12 @@
import React from 'react';
import PrivacyComp from "@/components/Legal/Privacy/PrivacyComp";
import PrivacyComp from "@/app/legal/privacy/PrivacyComp";
import type {Metadata} from "next";
export async function generateMetadata(): Promise<Metadata> {
return {
title: "Datenschutz | Rhein Software",
};
}
const PrivacyPage = () => {
return (

View File

@@ -1,12 +0,0 @@
import React from 'react';
import RevocationComp from "@/components/Legal/RevocationComp";
const RevocationPage = () => {
return (
<div>
<RevocationComp />
</div>
);
};
export default RevocationPage;

View File

@@ -0,0 +1,98 @@
'use client';
import SmallHero from '@/components/Helper/SmallHero';
import React from 'react';
import {motion} from 'framer-motion';
const TermsOfUseComp = () => {
return (
<div className="overflow-hidden bg-background text-foreground">
{/* Hero Section */}
<div className="mt-[10vh]">
<SmallHero
title="AGB"
subtitle=""
backgroundImage="/images/contact.png"
/>
</div>
{/* Contact Form */}
<div className="mt-16 w-[90%] sm:w-[80%] mx-auto py-12">
<motion.h2
className="text-2xl md:text-3xl font-bold text-center"
initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.6}}
>
Schreib uns eine Nachricht
</motion.h2>
<motion.p
className="text-center mt-3 text-muted-foreground"
initial={{opacity: 0, y: 10}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.5, delay: 0.2}}
>
Wir melden uns schnellstmöglich bei dir!
</motion.p>
<form className="mt-8 max-w-2xl mx-auto space-y-6">
{/* Name & Email */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{["Dein Name", "Deine E-Mail"].map((label, index) => (
<motion.div
key={index}
initial={{opacity: 0, y: 10}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.5, delay: index * 0.2}}
>
<label className="block font-semibold">{label}</label>
<input
type={index === 0 ? "text" : "email"}
placeholder={index === 0 ? "Max Mustermann" : "max@example.com"}
className="w-full p-3 rounded-lg border border-border bg-card text-foreground focus:outline-none focus:ring-2 focus:ring-blue-500 transition"
/>
</motion.div>
))}
</div>
{/* Message */}
<motion.div
initial={{opacity: 0, y: 10}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.5, delay: 0.5}}
>
<label className="block font-semibold">Deine Nachricht</label>
<textarea
rows={4}
placeholder="Schreibe deine Nachricht..."
className="w-full p-3 rounded-lg border border-border bg-card text-foreground focus:outline-none focus:ring-2 focus:ring-blue-500 transition"
/>
</motion.div>
{/* Submit Button */}
<motion.div
className="text-center"
initial={{opacity: 0, y: 10}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.5, delay: 0.7}}
>
<button
type="submit"
className="px-6 py-3 bg-blue-600 text-white text-lg font-semibold rounded-lg shadow-md hover:bg-blue-700 transition-all"
>
📩 Nachricht senden
</button>
</motion.div>
</form>
</div>
</div>
);
};
export default TermsOfUseComp;

View File

@@ -1,5 +1,12 @@
import React from 'react';
import TermsOfUseComp from "@/components/Legal/TermsOfUseComp";
import TermsOfUseComp from "@/app/legal/terms-of-use/TermsOfUseComp";
import type {Metadata} from "next";
export async function generateMetadata(): Promise<Metadata> {
return {
title: "Nutzungsbedingungen | Rhein Software",
};
}
const TermsOfUsePage = () => {
return (