Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8535731cd7 | ||
|
|
0280389f49 | ||
|
|
07fea547af | ||
|
|
b2a409e6b7 | ||
|
|
8757431c79 | ||
|
|
0b775a938d | ||
|
|
3953cd3976 | ||
|
|
4b43fc8e0a | ||
|
|
86558882f3 | ||
|
|
9df2bd8ce4 |
No files matched your search
@@ -34,7 +34,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-xs);
|
||||||
font-weight: var(--font-weight-semibold);
|
font-weight: var(--font-weight-semibold);
|
||||||
letter-spacing: var(--letter-spacing-wide);
|
letter-spacing: var(--letter-spacing-wide);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
|
|||||||
@@ -19,19 +19,12 @@ html.has-menu-open {
|
|||||||
scrollbar-gutter: stable;
|
scrollbar-gutter: stable;
|
||||||
}
|
}
|
||||||
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
max-width: 100vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
color: var(--font-body-color);
|
color: var(--font-body-color);
|
||||||
background: var(--color-background);
|
background: var(--color-background);
|
||||||
font-family: var(--font-body);
|
font-family: var(--font-body);
|
||||||
font-size: 1rem;
|
font-size: var(--font-size-base);
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
line-height: var(--line-height-body);
|
line-height: var(--line-height-body);
|
||||||
@@ -40,19 +33,10 @@ body {
|
|||||||
|
|
||||||
main {
|
main {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 1280px;
|
|
||||||
margin-inline: auto;
|
|
||||||
padding: 0 var(--space-4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
main {
|
|
||||||
padding: 0 var(--space-4);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 1024px) {
|
@media (min-width: 1024px) {
|
||||||
main {
|
|
||||||
padding: 0 var(--space-6);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import CookieConsentBanner from "@/components/CookieConsent";
|
|
||||||
import type { Metadata, Viewport } from "next";
|
import type { Metadata, Viewport } from "next";
|
||||||
import { Manrope, Nunito_Sans } from "next/font/google";
|
import { Manrope, Nunito_Sans } from "next/font/google";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
|
|
||||||
import Footer from "@/components/Footer";
|
import Footer from "@/components/Footer";
|
||||||
import Header from "@/components/Header";
|
import Header from "@/components/Header";
|
||||||
|
import CookieConsentLoader from "@/components/CookieConsentLoader";
|
||||||
|
|
||||||
const nunitoSans = Nunito_Sans({
|
const nunitoSans = Nunito_Sans({
|
||||||
subsets: ["latin"],
|
subsets: ["latin"],
|
||||||
@@ -94,10 +94,10 @@ export default function RootLayout({
|
|||||||
type="application/ld+json"
|
type="application/ld+json"
|
||||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
|
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
|
||||||
/>
|
/>
|
||||||
|
<CookieConsentLoader />
|
||||||
<Header />
|
<Header />
|
||||||
{children}
|
{children}
|
||||||
<Footer />
|
<Footer />
|
||||||
<CookieConsentBanner />
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-xs);
|
||||||
font-weight: var(--font-weight-semibold);
|
font-weight: var(--font-weight-semibold);
|
||||||
letter-spacing: var(--letter-spacing-wide);
|
letter-spacing: var(--letter-spacing-wide);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
|
|||||||
@@ -1,9 +1,25 @@
|
|||||||
|
import AboutUsSection from "@/components/AboutUsSection";
|
||||||
|
import BenefitsSection from "@/components/benefitsSection";
|
||||||
|
import ContactCtaSection from "@/components/contact/ContactCtaSection";
|
||||||
|
import { homepageFaq } from "@/components/faq/faqData";
|
||||||
|
import FaqSection from "@/components/faq/FaqSection";
|
||||||
import HeroSection from "@/components/HeroSection";
|
import HeroSection from "@/components/HeroSection";
|
||||||
|
import IndustrySolutionsSection from "@/components/IndustrySolutionsSection";
|
||||||
|
import ServiceSection from "@/components/ServiceSection";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
<HeroSection />
|
<HeroSection />
|
||||||
|
<ServiceSection />
|
||||||
|
<BenefitsSection />
|
||||||
|
<IndustrySolutionsSection />
|
||||||
|
<FaqSection
|
||||||
|
title="In drei Schritten zu planbarer Sauberkeit"
|
||||||
|
items={homepageFaq}
|
||||||
|
/>
|
||||||
|
<AboutUsSection />
|
||||||
|
<ContactCtaSection />
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
export type AboutUsMember = {
|
||||||
|
name: string;
|
||||||
|
imageSrc: string;
|
||||||
|
imageAlt: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AboutUsData = {
|
||||||
|
title: string;
|
||||||
|
paragraphs: string[];
|
||||||
|
members: AboutUsMember[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const aboutUsData: AboutUsData = {
|
||||||
|
title: "Ihre Reinigungsfirma für professionelle Ansprüche",
|
||||||
|
paragraphs: [
|
||||||
|
"Basiclean ist ein junges Reinigungsunternehmen mit Fokus auf gewerbliche Kunden in Hannover und der umliegenden Region.",
|
||||||
|
"Unser Ziel ist es, Unternehmen mit planbarer Sauberkeit, klaren Abläufen und zuverlässiger Zusammenarbeit zu entlasten. Statt starrer Standards bieten wir individuelle Reinigungslösungen, abgestimmt auf Ihr Objekt und Ihre Anforderungen.",
|
||||||
|
"Persönlicher Kontakt, transparente Leistungen und geschulte Reinigungskräfte stehen dabei im Mittelpunkt.",
|
||||||
|
],
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: "Abdulkabi Dastan",
|
||||||
|
imageSrc: "/images/portrait/abdulkabi-dastan.jpg",
|
||||||
|
imageAlt: "Porträt von Abdulkabi Dastan",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Gökhan Özsayiner",
|
||||||
|
imageSrc: "/images/portrait/goekhan-oezsayiner.jpg",
|
||||||
|
imageAlt: "Porträt von Gökhan Özsayiner",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
.section {
|
||||||
|
padding-block: var(--space-16);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
width: 100%;
|
||||||
|
max-width: var(--container-width);
|
||||||
|
margin-inline: auto;
|
||||||
|
padding-inline: var(--space-4);
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: var(--space-8);
|
||||||
|
justify-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
max-width: 20ch;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: var(--space-4);
|
||||||
|
max-width: 420px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-3);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.imageWrap {
|
||||||
|
position: relative;
|
||||||
|
aspect-ratio: 4 / 5;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 20px;
|
||||||
|
background: #e9e9e9;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-size: var(----font-size-xs);
|
||||||
|
color: var(--color-text);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textBlock {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-5);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
max-width: 56ch;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
font-size: var(----font-size-xs);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.section {
|
||||||
|
padding-block: var(--space-24);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
column-gap: var(--space-16);
|
||||||
|
row-gap: var(--space-8);
|
||||||
|
align-items: start;
|
||||||
|
justify-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team {
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textBlock {
|
||||||
|
grid-column: 2;
|
||||||
|
grid-row: 2;
|
||||||
|
align-self: center;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
.section {
|
||||||
|
padding-block: var(--space-32);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
padding-inline: var(--space-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.team {
|
||||||
|
max-width: 460px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import Image from "next/image";
|
||||||
|
import styles from "./AboutUsSection.module.css";
|
||||||
|
import { aboutUsData } from "./AboutUsData";
|
||||||
|
|
||||||
|
export default function AboutUsSection() {
|
||||||
|
const { title, paragraphs, members } = aboutUsData;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className={styles.section} aria-labelledby="about-us-heading">
|
||||||
|
<div className={styles.inner}>
|
||||||
|
<h2 id="about-us-heading" className={styles.heading}>
|
||||||
|
{title}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div className={styles.team}>
|
||||||
|
{members.map((member) => (
|
||||||
|
<article key={member.name} className={styles.card}>
|
||||||
|
<div className={styles.imageWrap}>
|
||||||
|
<Image
|
||||||
|
src={member.imageSrc}
|
||||||
|
alt={member.imageAlt}
|
||||||
|
fill
|
||||||
|
className={styles.image}
|
||||||
|
sizes="(max-width: 767px) 42vw, 180px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className={styles.name}>{member.name}</p>
|
||||||
|
</article>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.textBlock}>
|
||||||
|
{paragraphs.map((paragraph, index) => (
|
||||||
|
<p key={index} className={styles.text}>
|
||||||
|
{paragraph}
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -29,5 +29,5 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
:global(#cc-main .cm) {
|
:global(#cc-main .cm) {
|
||||||
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.08) !important;
|
box-shadow: 0 0 8px rgba(0, 0, 0, 0.08) !important;
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,31 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import * as CookieConsent from "vanilla-cookieconsent";
|
|
||||||
import "vanilla-cookieconsent/dist/cookieconsent.css";
|
|
||||||
import "./CookieConsent.module.css";
|
import "./CookieConsent.module.css";
|
||||||
|
|
||||||
export default function CookieConsentBanner() {
|
export default function CookieConsentBanner() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
let mounted = true;
|
||||||
|
let idleId: number | undefined;
|
||||||
|
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
||||||
|
|
||||||
|
const loadConsent = async () => {
|
||||||
|
const [cookieConsentModule] = await Promise.all([
|
||||||
|
import("vanilla-cookieconsent"),
|
||||||
|
import("vanilla-cookieconsent/dist/cookieconsent.css"),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const mod = cookieConsentModule as {
|
||||||
|
run?: (config: unknown) => void;
|
||||||
|
default?: {
|
||||||
|
run?: (config: unknown) => void;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const CookieConsent = mod.run ? mod : mod.default;
|
||||||
|
|
||||||
|
if (!mounted || !CookieConsent?.run) return;
|
||||||
|
|
||||||
CookieConsent.run({
|
CookieConsent.run({
|
||||||
categories: {
|
categories: {
|
||||||
necessary: {
|
necessary: {
|
||||||
@@ -23,10 +42,7 @@ export default function CookieConsentBanner() {
|
|||||||
consentModal: {
|
consentModal: {
|
||||||
title: "Ihre Privatsphäre ist uns wichtig",
|
title: "Ihre Privatsphäre ist uns wichtig",
|
||||||
description:
|
description:
|
||||||
"Wir verwenden Cookies, um Ihnen die bestmögliche Nutzung unserer Website zu ermöglichen. " +
|
"Wir setzen notwendige und optionale Cookies ein. Ihre Auswahl können Sie jederzeit unter <a href='/datenschutz'>Datenschutz</a> ändern.",
|
||||||
"Einige Cookies sind technisch notwendig, andere helfen uns, die Website zu verbessern " +
|
|
||||||
"und Ihnen relevante Inhalte anzuzeigen. Sie können Ihre Auswahl jederzeit unter " +
|
|
||||||
"<a href='/datenschutz'>Datenschutz</a> anpassen oder widerrufen.",
|
|
||||||
acceptAllBtn: "Alle akzeptieren",
|
acceptAllBtn: "Alle akzeptieren",
|
||||||
acceptNecessaryBtn: "Nur notwendige",
|
acceptNecessaryBtn: "Nur notwendige",
|
||||||
showPreferencesBtn: "Einstellungen anpassen",
|
showPreferencesBtn: "Einstellungen anpassen",
|
||||||
@@ -44,44 +60,30 @@ export default function CookieConsentBanner() {
|
|||||||
{
|
{
|
||||||
title: "Ihre Privatsphäre",
|
title: "Ihre Privatsphäre",
|
||||||
description:
|
description:
|
||||||
"Wir setzen Cookies ein, um die Funktionalität unserer Website sicherzustellen " +
|
"Wir setzen Cookies ein, um die Funktionalität unserer Website sicherzustellen und unser Angebot kontinuierlich zu verbessern. Sie entscheiden selbst, welche Kategorien Sie zulassen möchten.",
|
||||||
"und unser Angebot kontinuierlich zu verbessern. Sie entscheiden selbst, " +
|
|
||||||
"welche Kategorien Sie zulassen möchten.",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Technisch notwendig",
|
title: "Technisch notwendig",
|
||||||
description:
|
description:
|
||||||
"Diese Cookies sind für den reibungslosen Betrieb der Website unbedingt erforderlich " +
|
"Diese Cookies sind für den reibungslosen Betrieb der Website unbedingt erforderlich und können nicht deaktiviert werden.",
|
||||||
"und können nicht deaktiviert werden. Sie speichern keine personenbezogenen Daten " +
|
|
||||||
"und werden ausschließlich als Reaktion auf von Ihnen durchgeführte Aktionen gesetzt " +
|
|
||||||
"(z. B. Spracheinstellungen oder Sicherheits-Token).",
|
|
||||||
linkedCategory: "necessary",
|
linkedCategory: "necessary",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Analyse & Statistik",
|
title: "Analyse & Statistik",
|
||||||
description:
|
description:
|
||||||
"Diese Cookies helfen uns zu verstehen, wie Besucher mit unserer Website interagieren. " +
|
"Diese Cookies helfen uns zu verstehen, wie Besucher mit unserer Website interagieren.",
|
||||||
"Alle Daten werden anonymisiert gesammelt und dienen ausschließlich zur Verbesserung " +
|
|
||||||
"unseres Angebots. Wir nutzen Google Analytics (GA4) – Ihre IP-Adresse wird dabei " +
|
|
||||||
"anonymisiert und nicht gespeichert.",
|
|
||||||
linkedCategory: "analytics",
|
linkedCategory: "analytics",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Marketing & externe Medien",
|
title: "Marketing & externe Medien",
|
||||||
description:
|
description:
|
||||||
"Diese Cookies ermöglichen die Einbindung externer Inhalte wie YouTube-Videos, " +
|
"Diese Cookies ermöglichen die Einbindung externer Inhalte wie YouTube-Videos, Google Maps, Instagram-, Facebook- und X-Inhalte.",
|
||||||
"Google Maps, Instagram-, Facebook- und X (Twitter)-Inhalte. " +
|
|
||||||
"Ohne Ihre Zustimmung werden diese Inhalte nicht geladen und keine Daten übertragen. " +
|
|
||||||
"Bitte beachten Sie, dass bei Aktivierung personenbezogene Daten " +
|
|
||||||
"an Drittanbieter (ggf. auch in die USA) übertragen werden können.",
|
|
||||||
linkedCategory: "marketing",
|
linkedCategory: "marketing",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Weitere Informationen",
|
title: "Weitere Informationen",
|
||||||
description:
|
description:
|
||||||
"Bei Fragen zu unserer Cookie-Richtlinie wenden Sie sich bitte an uns über das " +
|
"Bei Fragen wenden Sie sich bitte über das <a href='/kontakt'>Kontaktformular</a> an uns. Mehr Details finden Sie in unserer <a href='/datenschutz'>Datenschutzerklärung</a>.",
|
||||||
"<a href='/kontakt'>Kontaktformular</a>. Mehr Details finden Sie in unserer " +
|
|
||||||
"<a href='/datenschutz'>Datenschutzerklärung</a>.",
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -89,6 +91,32 @@ export default function CookieConsentBanner() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (window.requestIdleCallback) {
|
||||||
|
idleId = window.requestIdleCallback(
|
||||||
|
() => {
|
||||||
|
void loadConsent();
|
||||||
|
},
|
||||||
|
{ timeout: 2000 },
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
timeoutId = setTimeout(() => {
|
||||||
|
void loadConsent();
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
mounted = false;
|
||||||
|
|
||||||
|
if (idleId && window.cancelIdleCallback) {
|
||||||
|
window.cancelIdleCallback(idleId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeoutId) {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
}
|
||||||
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import dynamic from "next/dynamic";
|
||||||
|
|
||||||
|
const CookieConsentBanner = dynamic(() => import("./CookieConsent"), {
|
||||||
|
ssr: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default function CookieConsentLoader() {
|
||||||
|
return <CookieConsentBanner />;
|
||||||
|
}
|
||||||
@@ -1,15 +1,9 @@
|
|||||||
/*
|
|
||||||
FOOTER
|
|
||||||
Datei: components/Footer.module.css
|
|
||||||
*/
|
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--footer-bg: #171717;
|
--footer-bg: #272727;
|
||||||
--footer-text: #a1a1aa;
|
--footer-text: #adadb3;
|
||||||
--footer-text-hover: #ffffff;
|
--footer-text-hover: #ffffff;
|
||||||
--footer-title: #ffffff;
|
--footer-title: #ffffff;
|
||||||
--footer-divider: rgba(255, 255, 255, 0.1);
|
--footer-divider: rgba(255, 255, 255, 0.1);
|
||||||
--footer-padding-y: clamp(3rem, 6vw, 5rem);
|
|
||||||
--footer-gap: clamp(2rem, 5vw, 4rem);
|
--footer-gap: clamp(2rem, 5vw, 4rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,7 +11,6 @@
|
|||||||
.footer {
|
.footer {
|
||||||
background-color: var(--footer-bg);
|
background-color: var(--footer-bg);
|
||||||
color: var(--footer-text);
|
color: var(--footer-text);
|
||||||
font-family: inherit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer a:focus-visible {
|
.footer a:focus-visible {
|
||||||
@@ -26,9 +19,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.footer__inner {
|
.footer__inner {
|
||||||
max-width: 1280px;
|
max-width: var(--container-width);
|
||||||
margin-inline: auto;
|
margin-inline: auto;
|
||||||
padding: var(--footer-padding-y) clamp(1rem, 5vw, 2rem);
|
padding-inline: var(--space-4);
|
||||||
|
padding-block: var(--space-16);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Top */
|
/* Top */
|
||||||
@@ -38,26 +32,16 @@
|
|||||||
gap: var(--footer-gap);
|
gap: var(--footer-gap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
|
||||||
.footer__top {
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 1024px) {
|
|
||||||
.footer__top {
|
|
||||||
grid-template-columns: 1.5fr 1fr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Brand */
|
/* Brand */
|
||||||
|
.footer__brand {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
.footer__logo {
|
.footer__logo {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 1.4rem;
|
width: fit-content;
|
||||||
font-weight: 700;
|
|
||||||
color: var(--footer-title);
|
|
||||||
margin-bottom: 0.75rem;
|
|
||||||
transition: opacity 0.2s ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer__logo:hover {
|
.footer__logo:hover {
|
||||||
@@ -65,8 +49,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.footer__tagline {
|
.footer__tagline {
|
||||||
font-size: 0.9rem;
|
|
||||||
line-height: 1.6;
|
|
||||||
max-width: 32ch;
|
max-width: 32ch;
|
||||||
color: var(--footer-text);
|
color: var(--footer-text);
|
||||||
}
|
}
|
||||||
@@ -74,34 +56,32 @@
|
|||||||
/* Navigation */
|
/* Navigation */
|
||||||
.footer__nav {
|
.footer__nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: var(--footer-gap);
|
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
gap: var(--footer-gap);
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer__nav ul {
|
.footer__nav ul {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer__nav-group ul {
|
.footer__nav-group ul {
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.6rem;
|
gap: var(--space-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer__nav-title {
|
.footer__nav-title {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 0.8rem;
|
margin-bottom: var(--space-4);
|
||||||
font-weight: 700;
|
font-size: var(--font-size-xxs);
|
||||||
text-transform: uppercase;
|
letter-spacing: var(--letter-spacing-wide);
|
||||||
letter-spacing: 0.08em;
|
|
||||||
color: var(--footer-title);
|
color: var(--footer-title);
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer__nav-group a {
|
.footer__nav-group a {
|
||||||
font-size: 0.9rem;
|
font-size: var(--font-size-xs);
|
||||||
color: var(--footer-text);
|
color: var(--footer-text);
|
||||||
transition: color 0.2s ease;
|
transition: color 0.2s ease;
|
||||||
}
|
}
|
||||||
@@ -157,3 +137,31 @@
|
|||||||
border-color: rgba(255, 255, 255, 0.3);
|
border-color: rgba(255, 255, 255, 0.3);
|
||||||
background: rgba(255, 255, 255, 0.05);
|
background: rgba(255, 255, 255, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tablet */
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.footer__top {
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer__nav {
|
||||||
|
justify-self: end;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Desktop */
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
.footer__inner {
|
||||||
|
padding-inline: var(--space-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer__top {
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer__nav {
|
||||||
|
justify-self: end;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
import styles from "./Footer.module.css";
|
import styles from "./Footer.module.css";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import Image from "next/image";
|
||||||
import {
|
import {
|
||||||
InstagramLogoIcon,
|
InstagramLogoIcon,
|
||||||
LinkedinLogoIcon,
|
LinkedinLogoIcon,
|
||||||
XLogoIcon,
|
XLogoIcon,
|
||||||
FacebookLogoIcon,
|
FacebookLogoIcon,
|
||||||
} from "@phosphor-icons/react/dist/ssr";
|
} from "@phosphor-icons/react/dist/ssr";
|
||||||
|
import { companyData } from "@/data/companyData";
|
||||||
|
|
||||||
const currentYear = new Date().getFullYear();
|
const currentYear = new Date().getFullYear();
|
||||||
|
|
||||||
@@ -13,22 +15,24 @@ export default function Footer() {
|
|||||||
return (
|
return (
|
||||||
<footer className={styles.footer}>
|
<footer className={styles.footer}>
|
||||||
<div className={styles.footer__inner}>
|
<div className={styles.footer__inner}>
|
||||||
{/* Top: Brand + Navigation */}
|
|
||||||
<div className={styles.footer__top}>
|
<div className={styles.footer__top}>
|
||||||
{/* Brand */}
|
|
||||||
<div className={styles.footer__brand}>
|
<div className={styles.footer__brand}>
|
||||||
<Link href="/" className={styles.footer__logo}>
|
<Link href="/" className={styles.footer__logo}>
|
||||||
ENVU {/* ← Logo oder Bildkomponente hier */}
|
<Image
|
||||||
|
src="/logo/logo-basiclean-white.svg"
|
||||||
|
alt={companyData.companyName}
|
||||||
|
width={160}
|
||||||
|
height={48}
|
||||||
|
unoptimized
|
||||||
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
<p className={styles.footer__tagline}>
|
|
||||||
Maßgeschneiderte digitale Lösungen für Ihr Unternehmen.
|
<p className={styles.footer__tagline}>{companyData.slogan}</p>
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Navigation Spalten */}
|
|
||||||
<nav className={styles.footer__nav} aria-label="Footer Navigation">
|
<nav className={styles.footer__nav} aria-label="Footer Navigation">
|
||||||
<div className={styles.footer__nav_group}>
|
<div className={styles["footer__nav-group"]}>
|
||||||
<span className={styles.footer__nav_title}>Unternehmen</span>
|
<span className={styles["footer__nav-title"]}>Unternehmen</span>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<Link href="/ueberuns">Über uns</Link>
|
<Link href="/ueberuns">Über uns</Link>
|
||||||
@@ -36,14 +40,17 @@ export default function Footer() {
|
|||||||
<li>
|
<li>
|
||||||
<Link href="/leistungen">Leistungen</Link>
|
<Link href="/leistungen">Leistungen</Link>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link href="/branchenloesungen">Branchenlösungen</Link>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Link href="/kontakt">Kontakt</Link>
|
<Link href="/kontakt">Kontakt</Link>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.footer__nav_group}>
|
<div className={styles["footer__nav-group"]}>
|
||||||
<span className={styles.footer__nav_title}>Rechtliches</span>
|
<span className={styles["footer__nav-title"]}>Rechtliches</span>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<Link href="/impressum">Impressum</Link>
|
<Link href="/impressum">Impressum</Link>
|
||||||
@@ -56,13 +63,12 @@ export default function Footer() {
|
|||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Divider */}
|
|
||||||
<div className={styles.footer__divider} />
|
<div className={styles.footer__divider} />
|
||||||
|
|
||||||
{/* Bottom: Copyright + Social */}
|
|
||||||
<div className={styles.footer__bottom}>
|
<div className={styles.footer__bottom}>
|
||||||
<p className={styles.footer__copy}>
|
<p className={styles.footer__copy}>
|
||||||
© {currentYear} ENVU. Alle Rechte vorbehalten.
|
Copyright © {currentYear} {companyData.companyName}. Alle Rechte
|
||||||
|
vorbehalten.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className={styles.footer__social}>
|
<div className={styles.footer__social}>
|
||||||
@@ -74,6 +80,7 @@ export default function Footer() {
|
|||||||
>
|
>
|
||||||
<InstagramLogoIcon size={20} />
|
<InstagramLogoIcon size={20} />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
href="https://linkedin.com"
|
href="https://linkedin.com"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -82,6 +89,7 @@ export default function Footer() {
|
|||||||
>
|
>
|
||||||
<LinkedinLogoIcon size={20} />
|
<LinkedinLogoIcon size={20} />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
href="https://x.com"
|
href="https://x.com"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -90,6 +98,7 @@ export default function Footer() {
|
|||||||
>
|
>
|
||||||
<XLogoIcon size={20} />
|
<XLogoIcon size={20} />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
href="https://facebook.com"
|
href="https://facebook.com"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
|||||||
@@ -1,59 +1,55 @@
|
|||||||
.hero {
|
.hero {
|
||||||
position: relative;
|
position: relative;
|
||||||
background: linear-gradient(to bottom, #f9f9f9 5%, #ffffff 50%, #f9f9f9 100%);
|
background: var(--color-background-linear);
|
||||||
padding-block: var(--space-16);
|
padding-block: var(--space-16);
|
||||||
width: 100vw;
|
overflow: hidden;
|
||||||
margin-left: calc(50% - 50vw);
|
|
||||||
margin-right: calc(50% - 50vw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.inner {
|
.inner {
|
||||||
width: 100%;
|
z-index: 1;
|
||||||
max-width: 1280px;
|
position: relative;
|
||||||
|
max-width: var(--container-width);
|
||||||
margin-inline: auto;
|
margin-inline: auto;
|
||||||
padding-inline: var(--space-4);
|
padding-inline: var(--space-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.heroDecoration {
|
.heroDecoration {
|
||||||
position: absolute;
|
display: none;
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
right: var(--space-4);
|
|
||||||
width: auto;
|
|
||||||
height: 80%;
|
|
||||||
opacity: 0.12;
|
|
||||||
pointer-events: none;
|
|
||||||
user-select: none;
|
|
||||||
z-index: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: var(--space-5);
|
gap: var(--space-5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.heading {
|
.heading {
|
||||||
max-width: 20ch;
|
max-width: 15ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lead {
|
.lead {
|
||||||
max-width: 56ch;
|
max-width: 40ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
gap: var(--space-3);
|
gap: var(--space-4);
|
||||||
margin-top: var(--space-2);
|
margin-top: var(--space-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions :global(.btn) {
|
.actions :global(.btn) {
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
justify-content: center;
|
font-weight: var(--font-weight-semibold);
|
||||||
min-height: 44px;
|
}
|
||||||
|
|
||||||
|
.actions :global(.btn--tertiary) {
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
color: var(--font-body-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tablet */
|
/* Tablet */
|
||||||
@@ -63,17 +59,33 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.heroDecoration {
|
.heroDecoration {
|
||||||
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
|
left: auto;
|
||||||
|
right: 0;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
height: 90%;
|
width: min(42vw, 420px);
|
||||||
|
height: auto;
|
||||||
|
opacity: 0.06;
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--space-6);
|
gap: var(--space-6);
|
||||||
}
|
}
|
||||||
|
.heading {
|
||||||
|
max-width: 24ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lead {
|
||||||
|
max-width: 48ch;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Desktop */
|
/* Desktop */
|
||||||
@@ -84,4 +96,9 @@
|
|||||||
.inner {
|
.inner {
|
||||||
padding-inline: var(--space-6);
|
padding-inline: var(--space-6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.heroDecoration {
|
||||||
|
width: min(44vw, 560px);
|
||||||
|
opacity: 0.08;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,24 +1,29 @@
|
|||||||
import { ArrowRightIcon, PhoneIcon } from "@phosphor-icons/react/dist/ssr";
|
import { ArrowRightIcon, PhoneIcon } from "@phosphor-icons/react/dist/ssr";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import styles from "./HeroSection.module.css";
|
import styles from "./HeroSection.module.css";
|
||||||
|
import { companyData } from "@/data/companyData";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
export default function HeroSection() {
|
export default function HeroSection() {
|
||||||
return (
|
return (
|
||||||
<section className={styles.hero} aria-labelledby="hero-heading">
|
<section className={styles.hero} aria-labelledby="hero-heading">
|
||||||
<img
|
<div className={styles.inner}>
|
||||||
|
<Image
|
||||||
src="/logo/logo-mininmal-basiclean-grey.svg"
|
src="/logo/logo-mininmal-basiclean-grey.svg"
|
||||||
alt=""
|
alt=""
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
className={styles.heroDecoration}
|
className={styles.heroDecoration}
|
||||||
|
width={620}
|
||||||
|
height={620}
|
||||||
|
unoptimized
|
||||||
/>
|
/>
|
||||||
<div className={styles.inner}>
|
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<h1 id="hero-heading" className={styles.heading}>
|
<h1 id="hero-heading" className={styles.heading}>
|
||||||
Mehr Sauberkeit, weniger Aufwand für ein sauberes Arbeitsumfeld
|
Gebäudereinigung für ein makelloses Arbeitsumfeld
|
||||||
</h1>
|
</h1>
|
||||||
<p className={`lead ${styles.lead}`}>
|
<p className={`lead ${styles.lead}`}>
|
||||||
Professionelle Gebäudereinigung für Büros, Praxen und Gewerbeflächen
|
Mit festen Abläufen und hohen Qualitätsstandards – für ein sauberes,
|
||||||
nach festen Abläufen und höchsten Qualitätsstandards.
|
professionelles Arbeitsumfeld.
|
||||||
</p>
|
</p>
|
||||||
<div className={styles.actions}>
|
<div className={styles.actions}>
|
||||||
<Link href="/kontakt" className="btn btn--filled">
|
<Link href="/kontakt" className="btn btn--filled">
|
||||||
@@ -27,11 +32,19 @@ export default function HeroSection() {
|
|||||||
</span>
|
</span>
|
||||||
Jetzt Angebot anfragen
|
Jetzt Angebot anfragen
|
||||||
</Link>
|
</Link>
|
||||||
<a href="tel:+495112345678" className="btn btn--outline">
|
<Link href="/Leistungen" className="btn btn--outline">
|
||||||
|
Leistungen ansehen
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className={styles.actions}>
|
||||||
|
<a
|
||||||
|
href={`tel:${companyData.contact.phone.value}`}
|
||||||
|
className="btn btn--tertiary"
|
||||||
|
>
|
||||||
<span className="btn-icon" aria-hidden="true">
|
<span className="btn-icon" aria-hidden="true">
|
||||||
<PhoneIcon size={18} weight="bold" />
|
<PhoneIcon size={18} weight="bold" />
|
||||||
</span>
|
</span>
|
||||||
0172 621 0606
|
{companyData.contact.phone.display}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
.section {
|
||||||
|
padding-block: var(--space-16);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
max-width: var(--container-width);
|
||||||
|
margin-inline: auto;
|
||||||
|
padding-inline: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-4);
|
||||||
|
margin-bottom: var(--space-8);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
max-width: 18ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lead {
|
||||||
|
max-width: 58ch;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||||
|
gap: var(--space-4);
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: var(--space-4);
|
||||||
|
background-color: #e2ebe5;
|
||||||
|
color: var(--color-accent);
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
padding: var(--space-6) var(--space-6);
|
||||||
|
text-decoration: none;
|
||||||
|
min-height: 88px;
|
||||||
|
transition:
|
||||||
|
background-color 0.25s ease,
|
||||||
|
color 0.25s ease,
|
||||||
|
box-shadow 0.25s ease;
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover,
|
||||||
|
.card:focus-visible {
|
||||||
|
background-color: var(--color-accent);
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardText {
|
||||||
|
font-size: var(--font-size-body);
|
||||||
|
line-height: 1.2;
|
||||||
|
font-weight: var(--font-weight-semibold);
|
||||||
|
max-width: 18ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconWrap {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 50px;
|
||||||
|
background-color: var(--color-accent);
|
||||||
|
color: #ffffff;
|
||||||
|
transition:
|
||||||
|
background-color 0.25s ease,
|
||||||
|
color 0.25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover .iconWrap,
|
||||||
|
.card:focus-visible .iconWrap {
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.section {
|
||||||
|
padding-block: var(--space-24);
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro {
|
||||||
|
margin-bottom: var(--space-10);
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
max-width: 18ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
min-height: 96px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:nth-child(4),
|
||||||
|
.card:nth-child(5) {
|
||||||
|
grid-column: span 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
.section {
|
||||||
|
padding-block: var(--space-24);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
padding-inline: var(--space-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
max-width: 860px;
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
padding: var(--space-12) var(--space-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:nth-child(4) {
|
||||||
|
grid-column: 1 / 2;
|
||||||
|
justify-self: end;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:nth-child(5) {
|
||||||
|
grid-column: 2 / 3;
|
||||||
|
justify-self: start;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (hover: none) {
|
||||||
|
.card:hover,
|
||||||
|
.card:focus-visible {
|
||||||
|
background-color: #e2ebe5;
|
||||||
|
color: var(--color-accent);
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover .iconWrap,
|
||||||
|
.card:focus-visible .iconWrap {
|
||||||
|
background-color: var(--color-accent);
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
import styles from "./IndustrySolutionsSection.module.css";
|
||||||
|
import {
|
||||||
|
BuildingsIcon,
|
||||||
|
StethoscopeIcon,
|
||||||
|
WarehouseIcon,
|
||||||
|
HouseLineIcon,
|
||||||
|
ArrowRightIcon,
|
||||||
|
} from "@phosphor-icons/react/dist/ssr";
|
||||||
|
|
||||||
|
const industries = [
|
||||||
|
{
|
||||||
|
title: "Büros",
|
||||||
|
href: "/branchen/bueros",
|
||||||
|
icon: BuildingsIcon,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Arztpraxen",
|
||||||
|
href: "/branchen/arztpraxen",
|
||||||
|
icon: StethoscopeIcon,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Hallen und Lagerflächen",
|
||||||
|
href: "/branchen/hallen-lagerflaechen",
|
||||||
|
icon: WarehouseIcon,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Wohn- und Geschäftshäuser",
|
||||||
|
href: "/branchen/wohn-geschaeftshaeuser",
|
||||||
|
icon: HouseLineIcon,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Zum Kontaktformular",
|
||||||
|
href: "/kontakt",
|
||||||
|
icon: ArrowRightIcon,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function IndustrySolutionsSection() {
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
className={styles.section}
|
||||||
|
aria-labelledby="industry-solutions-heading"
|
||||||
|
>
|
||||||
|
<div className={styles.inner}>
|
||||||
|
<div className={styles.intro}>
|
||||||
|
<h2 id="industry-solutions-heading" className={styles.heading}>
|
||||||
|
Reinigungsleistungen für verschiedene Branchen
|
||||||
|
</h2>
|
||||||
|
<p className={styles.lead}>
|
||||||
|
Als Reinigungsfirma betreuen wir Unternehmen aus unterschiedlichen
|
||||||
|
Branchen. Unsere Leistungen passen wir individuell an Nutzung,
|
||||||
|
Objektgröße und branchenspezifische Anforderungen an.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.grid}>
|
||||||
|
{industries.map((industry) => {
|
||||||
|
const Icon = industry.icon;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
key={industry.title}
|
||||||
|
href={industry.href}
|
||||||
|
className={styles.card}
|
||||||
|
>
|
||||||
|
<span className={styles.cardText}>{industry.title}</span>
|
||||||
|
|
||||||
|
<span className={styles.iconWrap} aria-hidden="true">
|
||||||
|
<Icon size={18} weight="bold" className={styles.icon} />
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
font-weight: var(--nav-font-weight);
|
font-weight: var(--nav-font-weight);
|
||||||
background-color: var(--nav-bg);
|
background-color: var(--nav-bg);
|
||||||
color: var(--nav-font-color);
|
color: var(--nav-font-color);
|
||||||
|
letter-spacing: 0.1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav a:focus-visible,
|
.nav a:focus-visible,
|
||||||
@@ -207,10 +208,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.nav-links > li a {
|
.nav-links > li a {
|
||||||
padding: 16px 12px;
|
padding: 24px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links > li:first-child {
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-links > li:first-child,
|
|
||||||
.nav-links > li:last-child {
|
.nav-links > li:last-child {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import { useNavToggleMenu } from "@/hooks/useNavToggleMenu";
|
|||||||
import { useSupportsHover } from "@/hooks/useSupportsHover";
|
import { useSupportsHover } from "@/hooks/useSupportsHover";
|
||||||
import { useToggleBodyOverflow } from "@/hooks/useToggleBodyOverflow";
|
import { useToggleBodyOverflow } from "@/hooks/useToggleBodyOverflow";
|
||||||
import styles from "./Navbar.module.css";
|
import styles from "./Navbar.module.css";
|
||||||
import { NavbarSubMenu } from "./NavbarSubMenu";
|
|
||||||
import { useIsDesktop } from "@/hooks/useIsDesktop";
|
import { useIsDesktop } from "@/hooks/useIsDesktop";
|
||||||
|
import { NavbarSubMenu } from "./NavbarSubMenu";
|
||||||
|
|
||||||
type BasicLink = {
|
type BasicLink = {
|
||||||
label: string;
|
label: string;
|
||||||
|
|||||||
@@ -78,6 +78,7 @@
|
|||||||
font: inherit;
|
font: inherit;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
height: var(--nav-h);
|
height: var(--nav-h);
|
||||||
|
letter-spacing: 0.1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item-with-sub {
|
.nav-item-with-sub {
|
||||||
@@ -103,6 +104,20 @@
|
|||||||
box-shadow: 0 4px 6px -6px rgb(0 0 0 / 30%);
|
box-shadow: 0 4px 6px -6px rgb(0 0 0 / 30%);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateY(-8px);
|
transform: translateY(-8px);
|
||||||
|
transition:
|
||||||
|
max-height 300ms ease,
|
||||||
|
opacity 300ms ease,
|
||||||
|
transform 300ms ease,
|
||||||
|
visibility 0s linear 300ms;
|
||||||
|
background-color: var(--nav-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-submenu.open {
|
||||||
|
transition:
|
||||||
|
max-height 300ms ease,
|
||||||
|
opacity 300ms ease,
|
||||||
|
transform 300ms ease,
|
||||||
|
visibility 0s linear 0s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-submenu-list li a:focus-visible {
|
.nav-submenu-list li a:focus-visible {
|
||||||
|
|||||||
@@ -0,0 +1,137 @@
|
|||||||
|
.services {
|
||||||
|
padding-block: var(--space-16);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
max-width: var(--container-width);
|
||||||
|
margin-inline: auto;
|
||||||
|
padding-inline: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-4);
|
||||||
|
margin-bottom: var(--space-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading,
|
||||||
|
.lead {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||||
|
justify-content: center;
|
||||||
|
gap: var(--space-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100%;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.imageWrap {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
aspect-ratio: 16 / 7;
|
||||||
|
background: var(--color-surface-alt);
|
||||||
|
overflow: hidden;
|
||||||
|
border-bottom: 4px solid var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardBody {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: var(--space-5);
|
||||||
|
padding: var(--space-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardContent {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardTitle {
|
||||||
|
font-size: var(--font-size-s);
|
||||||
|
background-color: var(--color-accent);
|
||||||
|
width: fit-content;
|
||||||
|
padding: 8px;
|
||||||
|
color: #ffffff;
|
||||||
|
letter-spacing: var(--letter-spacing-normal);
|
||||||
|
border-radius: 4px;
|
||||||
|
font-weight: var(--font-weight-regular);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardText {
|
||||||
|
max-width: 34ch;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
font-size: var(--font-size-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardBody :global(.btn) {
|
||||||
|
width: fit-content;
|
||||||
|
padding: 0;
|
||||||
|
color: var(--font-body-color);
|
||||||
|
font-weight: var(--font-weight-semibold);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tablet */
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.services {
|
||||||
|
padding-block: var(--space-24);
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro {
|
||||||
|
margin-bottom: var(--space-10);
|
||||||
|
}
|
||||||
|
.heading {
|
||||||
|
max-width: 22ch;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lead {
|
||||||
|
max-width: 62ch;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* .card {
|
||||||
|
max-width: 100%;
|
||||||
|
} */
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Desktop */
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
.services {
|
||||||
|
padding-block: var(--space-24);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
padding-inline: var(--space-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
import { ArrowRightIcon } from "@phosphor-icons/react/dist/ssr";
|
||||||
|
import Link from "next/link";
|
||||||
|
import styles from "./ServiceSection.module.css";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
|
const services = [
|
||||||
|
{
|
||||||
|
title: "Grundreinigung",
|
||||||
|
description:
|
||||||
|
"Regelmäßige Reinigung von Arbeitsplätzen, Besprechungsräumen und Gemeinschaftsbereichen für einen gepflegten Eindruck im Alltag.",
|
||||||
|
image: "/images/services/grundreinigung.jpg",
|
||||||
|
imageAlt: "Sauberer Büroarbeitsplatz nach der Reinigung",
|
||||||
|
href: "/leistungen/bueroreinigung",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Glas- und Fensterreinigung",
|
||||||
|
description:
|
||||||
|
"Streifenfreie Reinigung von Fenstern, Glaselementen und Eingangsbereichen für einen professionellen ersten Eindruck.",
|
||||||
|
image: "/images/services/Fensterreinigung.jpg",
|
||||||
|
imageAlt: "Große gereinigte Fensterfront eines Geschäftsgebäudes",
|
||||||
|
href: "/leistungen/glasreinigung",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Treppenhausreinigung",
|
||||||
|
description:
|
||||||
|
"Saubere Eingangs- und Treppenbereiche als Visitenkarte für Mitarbeitende, Kundschaft und Besucher.",
|
||||||
|
image: "/images/services/treppenhausreinigung.jpg",
|
||||||
|
imageAlt: "Sauberes Treppenhaus in einem Gewerbeobjekt",
|
||||||
|
href: "/leistungen/treppenhausreinigung",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Unterhaltsreinigung",
|
||||||
|
description:
|
||||||
|
"Individuell abgestimmte Reinigungsintervalle für dauerhaft gepflegte Büro-, Praxis- und Gewerbeflächen.",
|
||||||
|
image: "/images/services/unterhaltsreinigung.jpg",
|
||||||
|
imageAlt: "Reinigungskraft bei der Unterhaltsreinigung in einem Büro",
|
||||||
|
href: "/leistungen/unterhaltsreinigung",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Hausmeisterdienste",
|
||||||
|
description:
|
||||||
|
"Hausmeisterdienste für Kleinreparaturen bis zur Objektbetreuung – für reibungslose Abläufe.",
|
||||||
|
image: "/images/services/Hausmeisterdienste.jpg",
|
||||||
|
imageAlt: "Hausmeisterdienste für Gartenarbeit",
|
||||||
|
href: "/leistungen/Hausmeisterdienste",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function ServiceSection() {
|
||||||
|
return (
|
||||||
|
<section className={styles.services} aria-labelledby="services-heading">
|
||||||
|
<div className={styles.inner}>
|
||||||
|
<div className={styles.intro}>
|
||||||
|
<h2 id="services-heading" className={styles.heading}>
|
||||||
|
Professionelle Reinigung für Büros, Praxen und Geschäftsräume
|
||||||
|
</h2>
|
||||||
|
<p className={`lead ${styles.lead}`}>
|
||||||
|
Individuelle Reinigungskonzepte für Unternehmen – damit Ihre Räume sauber, zuverlässig und professions sorgenfrei bleiben.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.grid}>
|
||||||
|
{services.map((service) => (
|
||||||
|
<article key={service.title} className={styles.card}>
|
||||||
|
<div className={styles.imageWrap}>
|
||||||
|
<Image
|
||||||
|
src={service.image}
|
||||||
|
alt={service.imageAlt}
|
||||||
|
fill
|
||||||
|
sizes="(min-width: 1024px) 400px, (min-width: 768px) 50vw, 100vw"
|
||||||
|
className={styles.image}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.cardBody}>
|
||||||
|
<div className={styles.cardContent}>
|
||||||
|
<h3 className={styles.cardTitle}>{service.title}</h3>
|
||||||
|
<p className={styles.cardText}>{service.description}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Link href={service.href} className="btn btn--tertiary">
|
||||||
|
Mehr
|
||||||
|
<span className="btn-icon animate" aria-hidden="true">
|
||||||
|
<ArrowRightIcon size={16} weight="bold" />
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
.benefits {
|
||||||
|
background: var(--color-background-linear);
|
||||||
|
padding-block: var(--space-16);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
max-width: var(--container-width);
|
||||||
|
margin-inline: auto;
|
||||||
|
padding-inline: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile: Intro oben, Grid unten */
|
||||||
|
.intro {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-4);
|
||||||
|
margin-bottom: var(--space-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading,
|
||||||
|
.lead {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||||
|
gap: var(--space-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: var(--space-4);
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: var(--space-5);
|
||||||
|
box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconWrap {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardContent {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardTitle {
|
||||||
|
font-size: var(--font-size-base);
|
||||||
|
font-weight: var(--font-weight-semibold);
|
||||||
|
color: var(--font-heading-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardText {
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
font-size: var(--font-size-xs);
|
||||||
|
max-width: 34ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tablet */
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.benefits {
|
||||||
|
padding-block: var(--space-24);
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro {
|
||||||
|
margin-bottom: var(--space-10);
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
max-width: 16ch;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lead {
|
||||||
|
max-width: 48ch;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Desktop: Intro links, Grid rechts — nebeneinander */
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
.benefits {
|
||||||
|
padding-block: var(--space-36);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 280px 1fr;
|
||||||
|
gap: var(--space-16);
|
||||||
|
align-items: start;
|
||||||
|
padding-inline: var(--space-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro {
|
||||||
|
position: sticky;
|
||||||
|
top: var(--space-8);
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lead {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
import {
|
||||||
|
UsersThreeIcon,
|
||||||
|
GraduationCapIcon,
|
||||||
|
ClockIcon,
|
||||||
|
SealCheckIcon,
|
||||||
|
LeafIcon,
|
||||||
|
CurrencyCircleDollarIcon,
|
||||||
|
} from "@phosphor-icons/react/dist/ssr";
|
||||||
|
import styles from "./benefitsSection.module.css";
|
||||||
|
|
||||||
|
const benefits = [
|
||||||
|
{
|
||||||
|
icon: UsersThreeIcon,
|
||||||
|
title: "Feste Ansprechpartner",
|
||||||
|
description:
|
||||||
|
"Keine wechselnden Zuständigkeiten – wir sind immer persönlich für Sie da.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: GraduationCapIcon,
|
||||||
|
title: "Geschultes Personal",
|
||||||
|
description:
|
||||||
|
"Unsere Teams werden kontinuierlich in modernen Reinigungstechniken geschult.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: ClockIcon,
|
||||||
|
title: "Flexible Zeiten",
|
||||||
|
description:
|
||||||
|
"Wir reinigen dann, wenn es Ihren Betriebsablauf am wenigsten stört.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: SealCheckIcon,
|
||||||
|
title: "Höchste Qualität",
|
||||||
|
description:
|
||||||
|
"Strenges Qualitätsmanagement durch regelmäßige Objektkontrollen.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: LeafIcon,
|
||||||
|
title: "Umweltfreundlich",
|
||||||
|
description:
|
||||||
|
"Einsatz von biologisch abbaubaren Reinigungsmitteln für die Umwelt.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: CurrencyCircleDollarIcon,
|
||||||
|
title: "Transparente Kosten",
|
||||||
|
description:
|
||||||
|
"Klare Preisgestaltung ohne versteckte Nebenkosten für Ihre Planung.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function BenefitsSection() {
|
||||||
|
return (
|
||||||
|
<section className={styles.benefits} aria-labelledby="benefits-heading">
|
||||||
|
<div className={styles.inner}>
|
||||||
|
<div className={styles.intro}>
|
||||||
|
<h2 id="benefits-heading" className={styles.heading}>
|
||||||
|
Ihre Vorteile mit uns
|
||||||
|
</h2>
|
||||||
|
<p className={`lead ${styles.lead}`}>
|
||||||
|
Wir verstehen die Anforderungen moderner Unternehmen an einen
|
||||||
|
Facility-Partner: Verlässlichkeit, Professionalität und Transparenz.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.grid}>
|
||||||
|
{benefits.map((benefit) => {
|
||||||
|
const Icon = benefit.icon;
|
||||||
|
return (
|
||||||
|
<article key={benefit.title} className={styles.card}>
|
||||||
|
<span className={styles.iconWrap} aria-hidden="true">
|
||||||
|
<Icon size={24} weight="duotone" />
|
||||||
|
</span>
|
||||||
|
<div className={styles.cardContent}>
|
||||||
|
<h3 className={styles.cardTitle}>{benefit.title}</h3>
|
||||||
|
<p className={styles.cardText}>{benefit.description}</p>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import type { ElementType } from "react";
|
||||||
|
import {
|
||||||
|
PhoneIcon,
|
||||||
|
EnvelopeSimpleIcon,
|
||||||
|
ClockIcon,
|
||||||
|
} from "@phosphor-icons/react/dist/ssr";
|
||||||
|
|
||||||
|
export type CompanyContactKey = "phone" | "email" | "openingHours";
|
||||||
|
|
||||||
|
export type CompanyContactItem = {
|
||||||
|
type: "company";
|
||||||
|
contactKey: CompanyContactKey;
|
||||||
|
icon: ElementType;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type StaticContactItem = {
|
||||||
|
type: "static";
|
||||||
|
icon: ElementType;
|
||||||
|
label: string;
|
||||||
|
href?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ContactInfo = CompanyContactItem | StaticContactItem;
|
||||||
|
|
||||||
|
export type ContactCtaData = {
|
||||||
|
heading: string;
|
||||||
|
lead: string;
|
||||||
|
buttonLabel: string;
|
||||||
|
buttonHref: string;
|
||||||
|
contacts: ContactInfo[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const contactCtaData: ContactCtaData = {
|
||||||
|
heading: "Lassen Sie uns über Ihre Anforderungen sprechen",
|
||||||
|
lead: "Wir erstellen ein individuelles Reinigungskonzept für Ihr Unternehmen in Hannover und Umgebung. Unverbindlich, transparent und exakt auf Ihre Anforderung abgestimmt.",
|
||||||
|
buttonLabel: "Angebot anfragen",
|
||||||
|
buttonHref: "/kontakt",
|
||||||
|
contacts: [
|
||||||
|
{
|
||||||
|
type: "company",
|
||||||
|
contactKey: "phone",
|
||||||
|
icon: PhoneIcon,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "company",
|
||||||
|
contactKey: "email",
|
||||||
|
icon: EnvelopeSimpleIcon,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "company",
|
||||||
|
contactKey: "openingHours",
|
||||||
|
icon: ClockIcon,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
.section {
|
||||||
|
background: #ffffff;
|
||||||
|
padding-bottom: var(--space-16);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
max-width: var(--container-width);
|
||||||
|
margin-inline: auto;
|
||||||
|
padding-inline: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background-color: var(--color-accent);
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
padding: var(--space-8) var(--space-6);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.top {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-6);
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top :global(.btn) {
|
||||||
|
font-weight: var(--font-weight-semibold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
color: #ffffff;
|
||||||
|
max-width: 24ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lead {
|
||||||
|
color: rgba(255, 255, 255);
|
||||||
|
font-size: var(--font-size-xs);
|
||||||
|
max-width: 72ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
border: none;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contactRow {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.contactItem {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-2);
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: var(--font-size-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.section {
|
||||||
|
padding-bottom: var(--space-24);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
padding: var(--space-10) var(--space-10);
|
||||||
|
}
|
||||||
|
|
||||||
|
.top {
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: var(--space-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.contactRow {
|
||||||
|
flex-direction: row;
|
||||||
|
gap: var(--space-8);
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
.inner {
|
||||||
|
padding-inline: var(--space-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
padding: var(--space-12) var(--space-12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (hover: none) {
|
||||||
|
.button:hover,
|
||||||
|
.button:focus-visible {
|
||||||
|
background: #ffffff;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
import { ArrowRightIcon } from "@phosphor-icons/react/dist/ssr";
|
||||||
|
import { companyData } from "@/data/companyData";
|
||||||
|
import styles from "./ContactCtaSection.module.css";
|
||||||
|
import { contactCtaData, type ContactInfo } from "./ContactCtaData";
|
||||||
|
|
||||||
|
function resolveCompanyContact(
|
||||||
|
item: Extract<ContactInfo, { type: "company" }>,
|
||||||
|
) {
|
||||||
|
if (item.contactKey === "phone") {
|
||||||
|
return {
|
||||||
|
label: companyData.contact.phone.display,
|
||||||
|
href: `tel:${companyData.contact.phone.value}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.contactKey === "email") {
|
||||||
|
const email = `${companyData.contact.email.user}@${companyData.contact.email.domain}`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
label: email,
|
||||||
|
href: `mailto:${email}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.contactKey === "openingHours") {
|
||||||
|
return {
|
||||||
|
label: companyData.contact.openingHours.display,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ContactCtaSection() {
|
||||||
|
const { heading, lead, buttonLabel, buttonHref, contacts } = contactCtaData;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className={styles.section} aria-labelledby="contact-cta-heading">
|
||||||
|
<div className={styles.inner}>
|
||||||
|
<div className={styles.card}>
|
||||||
|
<div className={styles.top}>
|
||||||
|
<div className={styles.text}>
|
||||||
|
<h2 id="contact-cta-heading" className={styles.heading}>
|
||||||
|
{heading}
|
||||||
|
</h2>
|
||||||
|
<p className={styles.lead}>{lead}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Link href={buttonHref} className="btn btn--filled-inverse">
|
||||||
|
<span className="btn-icon animate" aria-hidden="true">
|
||||||
|
<ArrowRightIcon size={16} weight="bold" />
|
||||||
|
</span>
|
||||||
|
{buttonLabel}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr className={styles.divider} aria-hidden="true" />
|
||||||
|
|
||||||
|
<div className={styles.contactRow}>
|
||||||
|
{contacts.map((item) => {
|
||||||
|
const icon = (
|
||||||
|
<item.icon size={20} weight="regular" aria-hidden="true" />
|
||||||
|
);
|
||||||
|
|
||||||
|
if (item.type === "company") {
|
||||||
|
const resolved = resolveCompanyContact(item);
|
||||||
|
|
||||||
|
if (!resolved) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
key={item.contactKey}
|
||||||
|
href={resolved.href}
|
||||||
|
className={styles.contactItem}
|
||||||
|
aria-label={resolved.label}
|
||||||
|
>
|
||||||
|
{icon}
|
||||||
|
{resolved.label}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.href) {
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
key={item.label}
|
||||||
|
href={item.href}
|
||||||
|
className={styles.contactItem}
|
||||||
|
aria-label={item.label}
|
||||||
|
>
|
||||||
|
{icon}
|
||||||
|
{item.label}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span key={item.label} className={styles.contactItem}>
|
||||||
|
{icon}
|
||||||
|
{item.label}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
.section {
|
||||||
|
background: var(--color-background-linear);
|
||||||
|
padding-block: var(--space-16);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
max-width: var(--container-width);
|
||||||
|
margin-inline: auto;
|
||||||
|
padding-inline: var(--space-4);
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: var(--space-8);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
max-width: 11ch;
|
||||||
|
text-align: left;
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.accordion {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.itemHeading {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: var(--space-4);
|
||||||
|
width: 100%;
|
||||||
|
min-height: 52px;
|
||||||
|
padding: var(--space-3) var(--space-5);
|
||||||
|
background: var(--color-accent);
|
||||||
|
color: #ffffff;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 9999px;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger:hover,
|
||||||
|
.trigger:focus-visible {
|
||||||
|
background: #1f6152;
|
||||||
|
}
|
||||||
|
|
||||||
|
.triggerText {
|
||||||
|
font-size: var(--font-size-s);
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconWrap {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
transition: transform 0.25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger[aria-expanded="true"] .iconWrap {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
max-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: max-height 0.4s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panelInner {
|
||||||
|
padding: var(--space-4) var(--space-5) var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.answer {
|
||||||
|
max-width: 52ch;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
font-size: var(----font-size-xs);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.section {
|
||||||
|
padding-block: var(--space-24);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
grid-template-columns: 280px 1fr;
|
||||||
|
gap: var(--space-16);
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger {
|
||||||
|
min-height: 56px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
.section {
|
||||||
|
padding-block: var(--space-36);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
padding-inline: var(--space-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.accordion {
|
||||||
|
max-width: 560px;
|
||||||
|
justify-self: end;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (hover: none) {
|
||||||
|
.trigger:hover,
|
||||||
|
.trigger:focus-visible {
|
||||||
|
background: var(--color-accent);
|
||||||
|
box-shadow: 0 4px 14px rgba(38, 115, 97, 0.14);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useId, useRef, useState } from "react";
|
||||||
|
import { CaretDownIcon } from "@phosphor-icons/react/dist/ssr";
|
||||||
|
import styles from "./FaqSection.module.css";
|
||||||
|
|
||||||
|
export type FaqItem = {
|
||||||
|
question: string;
|
||||||
|
answer: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type FaqSectionProps = {
|
||||||
|
title: string;
|
||||||
|
items: FaqItem[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type AccordionItemProps = {
|
||||||
|
item: FaqItem;
|
||||||
|
isOpen: boolean;
|
||||||
|
buttonId: string;
|
||||||
|
panelId: string;
|
||||||
|
onToggle: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function AccordionItem({
|
||||||
|
item,
|
||||||
|
isOpen,
|
||||||
|
buttonId,
|
||||||
|
panelId,
|
||||||
|
onToggle,
|
||||||
|
}: AccordionItemProps) {
|
||||||
|
const panelRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
|
const handleToggle = () => {
|
||||||
|
const panel = panelRef.current;
|
||||||
|
if (!panel) return;
|
||||||
|
|
||||||
|
if (panel.style.maxHeight) {
|
||||||
|
panel.style.maxHeight = "";
|
||||||
|
} else {
|
||||||
|
panel.style.maxHeight = panel.scrollHeight + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
onToggle();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.item}>
|
||||||
|
<h3 className={styles.itemHeading}>
|
||||||
|
<button
|
||||||
|
id={buttonId}
|
||||||
|
type="button"
|
||||||
|
className={styles.trigger}
|
||||||
|
aria-expanded={isOpen}
|
||||||
|
aria-controls={panelId}
|
||||||
|
onClick={handleToggle}
|
||||||
|
>
|
||||||
|
<span className={styles.triggerText}>{item.question}</span>
|
||||||
|
|
||||||
|
<span className={styles.iconWrap} aria-hidden="true">
|
||||||
|
<CaretDownIcon size={14} weight="bold" />
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div
|
||||||
|
id={panelId}
|
||||||
|
ref={panelRef}
|
||||||
|
role="region"
|
||||||
|
aria-labelledby={buttonId}
|
||||||
|
className={styles.panel}
|
||||||
|
>
|
||||||
|
<div className={styles.panelInner}>
|
||||||
|
<p className={styles.answer}>{item.answer}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function FaqSection({ title, items }: FaqSectionProps) {
|
||||||
|
const baseId = useId();
|
||||||
|
const [openIndex, setOpenIndex] = useState<number | null>(null);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className={styles.section} aria-labelledby="faq-heading">
|
||||||
|
<div className={styles.inner}>
|
||||||
|
<div className={styles.content}>
|
||||||
|
<h2 id="faq-heading" className={styles.heading}>
|
||||||
|
{title}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.accordion}>
|
||||||
|
{items.map((item, index) => {
|
||||||
|
const isOpen = openIndex === index;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AccordionItem
|
||||||
|
key={item.question}
|
||||||
|
item={item}
|
||||||
|
isOpen={isOpen}
|
||||||
|
buttonId={`${baseId}-btn-${index}`}
|
||||||
|
panelId={`${baseId}-panel-${index}`}
|
||||||
|
onToggle={() => setOpenIndex(isOpen ? null : index)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
export const homepageFaq = [
|
||||||
|
{
|
||||||
|
question: "Kostenlose Beratung und Angebotserstellung",
|
||||||
|
answer:
|
||||||
|
"Wir besprechen Ihr Objekt, den Reinigungsbedarf und die gewünschten Intervalle. Anschließend erhalten Sie ein transparentes Angebot.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Individuelle Reinigungslösungen",
|
||||||
|
answer:
|
||||||
|
"Unsere Leistungen passen wir an Ihre Branche, Objektgröße und Anforderungen an. So entsteht ein Reinigungsplan, der wirklich zu Ihrem Alltag passt.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Zeitverfügbare Umsetzung",
|
||||||
|
answer:
|
||||||
|
"Wir planen flexibel und reinigen dann, wenn es Ihren Betrieb am wenigsten stört. Auf Wunsch auch früh morgens, abends oder am Wochenende.",
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
export const companyData = {
|
||||||
|
name: "Basiclean",
|
||||||
|
companyName: "Basiclean",
|
||||||
|
slogan: "Wo Sauberkeit Standard ist.",
|
||||||
|
contact: {
|
||||||
|
email: {
|
||||||
|
user: "info",
|
||||||
|
domain: "basiclean.de",
|
||||||
|
},
|
||||||
|
phone: {
|
||||||
|
display: "0172 621 0606",
|
||||||
|
value: "+491726210606",
|
||||||
|
},
|
||||||
|
openingHours: {
|
||||||
|
display: "Mo. - Fr. 08:00 - 17:00 Uhr",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { companyData } from "./companyData";
|
||||||
|
|
||||||
|
export function getCompanyEmail() {
|
||||||
|
return `${companyData.contact.email.user}@${companyData.contact.email.domain}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCompanyEmailHref() {
|
||||||
|
return `mailto:${getCompanyEmail()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCompanyPhoneDisplay() {
|
||||||
|
return companyData.contact.phone.display;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCompanyPhoneHref() {
|
||||||
|
return `tel:${companyData.contact.phone.value}`;
|
||||||
|
}
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
import type { NextConfig } from "next";
|
import type { NextConfig } from "next";
|
||||||
|
|
||||||
|
const allowedOrigin = process.env.NEXT_ALLOWED_DEV_ORIGIN;
|
||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
/* config options here */
|
output: "standalone",
|
||||||
trailingSlash: false,
|
trailingSlash: false,
|
||||||
poweredByHeader: false,
|
poweredByHeader: false,
|
||||||
allowedDevOrigins: [
|
|
||||||
"192.168.178.59", // deine PC-IP
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (allowedOrigin) {
|
||||||
|
nextConfig.allowedDevOrigins = [allowedOrigin];
|
||||||
|
}
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig;
|
||||||
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 119 KiB |
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 188 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 120 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 748 167" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><g id="Logo-neben-Schriftzug" serif:id="Logo neben Schriftzug"><path d="M105.008,158.958c-22.419,11.972 -50.938,8.512 -69.831,-10.381c-39.541,-39.541 -35.021,-113.988 -35.021,-113.988c0.167,-2.605 2.243,-4.68 4.848,-4.848c0,0 74.447,-4.52 113.988,35.021c21.914,21.914 23.066,56.779 3.454,80.054c-0.362,-0.185 -0.737,-0.379 -1.127,-0.582c-5.154,-2.691 -5.16,-2.68 -5.604,-2.92c-1.436,-0.776 -1.97,-1.044 -2.742,-1.452c17.744,-19.163 17.304,-49.132 -1.323,-67.759c-30.978,-30.978 -85.143,-32.462 -101.303,-32.17c-0.292,16.16 1.193,70.325 32.17,101.303c13.793,13.793 33.808,17.614 51.047,11.462c0.145,0.095 0.291,0.19 0.439,0.286c2.484,1.615 5.959,3.52 6.376,3.731c1.806,0.917 3.237,1.615 4.628,2.243Z" style="fill:#298972;"/><path d="M189.124,165.924c-3.398,0.229 -16.488,1.214 -32.559,0.216c-2.19,-0.136 -9.695,-0.773 -15.864,-1.809c-10.966,-1.842 -17.633,-3.992 -21.329,-5.221c-7.711,-2.565 -18.01,-6.682 -29.769,-15.316c-4.985,-3.66 -9.537,-7.394 -15.842,-13.667c-0.927,-0.922 -5.602,-5.807 -9.04,-10.007c-4.591,-5.61 -8.504,-11.049 -11.653,-15.709c-3.199,-4.735 -7.124,-11.263 -10.135,-16.633c0.21,0.254 5.761,7.164 14.336,16.223c1.045,1.104 6.617,7.092 15.664,14.982c2.689,2.345 8.097,6.853 13.443,10.683c1.802,1.291 7.343,5.31 15.048,9.761c16.464,9.511 27.83,13.425 29.737,14.138c12.597,4.709 25.101,7.248 26.764,7.609c7.797,1.694 17.199,3.279 31.199,4.751Z" style="fill:#298972;"/><path d="M138.583,150.484c14.876,-8.386 26.33,-25.547 26.33,-43.826c0,-43.809 -37.251,-83.159 -48.884,-94.38c-4.908,4.734 -14.376,14.475 -23.683,27.446c-3.19,-1.426 -6.42,-2.72 -9.664,-3.896c14.593,-20.964 29.92,-34.535 29.92,-34.535c1.96,-1.724 4.895,-1.724 6.856,0c0,0 55.838,49.446 55.838,105.365c0,18.717 -10.095,36.63 -23.662,47.495c-3.502,-0.854 -8.107,-2.077 -13.05,-3.668Z" style="fill:#3166b3;"/></g><g><path d="M230.865,75.544c2.065,-3.614 5.089,-6.565 9.073,-8.851c3.983,-2.287 8.519,-3.43 13.609,-3.43c5.458,0 10.363,1.291 14.715,3.872c4.352,2.582 7.782,6.214 10.29,10.898c2.508,4.684 3.762,10.124 3.762,16.32c0,6.122 -1.254,11.58 -3.762,16.375c-2.508,4.794 -5.956,8.519 -10.345,11.175c-4.389,2.655 -9.275,3.983 -14.66,3.983c-5.237,0 -9.829,-1.143 -13.775,-3.43c-3.946,-2.287 -6.915,-5.2 -8.907,-8.741l0,11.175l-10.068,0l0,-81.875l10.068,0l0,32.529Zm41.159,18.809c0,-4.573 -0.922,-8.556 -2.766,-11.949c-1.844,-3.393 -4.333,-5.975 -7.468,-7.745c-3.135,-1.77 -6.583,-2.655 -10.345,-2.655c-3.688,0 -7.099,0.904 -10.234,2.711c-3.135,1.807 -5.643,4.426 -7.524,7.856c-1.881,3.43 -2.821,7.395 -2.821,11.894c0,4.573 0.94,8.575 2.821,12.005c1.881,3.43 4.389,6.048 7.524,7.856c3.135,1.807 6.546,2.711 10.234,2.711c3.762,0 7.21,-0.904 10.345,-2.711c3.135,-1.807 5.624,-4.426 7.468,-7.856c1.844,-3.43 2.766,-7.468 2.766,-12.115Z" style="fill:#fff;fill-rule:nonzero;"/><path d="M291.829,94.353c0,-6.196 1.254,-11.636 3.762,-16.32c2.508,-4.684 5.956,-8.317 10.345,-10.898c4.389,-2.582 9.275,-3.872 14.66,-3.872c5.311,0 9.921,1.143 13.83,3.43c3.909,2.287 6.823,5.163 8.741,8.63l0,-11.064l10.179,0l0,60.631l-10.179,0l0,-11.285c-1.992,3.541 -4.96,6.473 -8.907,8.796c-3.946,2.323 -8.538,3.485 -13.775,3.485c-5.385,0 -10.253,-1.328 -14.605,-3.983c-4.352,-2.655 -7.782,-6.38 -10.29,-11.175c-2.508,-4.794 -3.762,-10.253 -3.762,-16.375Zm51.338,0.111c0,-4.573 -0.922,-8.556 -2.766,-11.949c-1.844,-3.393 -4.333,-5.993 -7.468,-7.8c-3.135,-1.807 -6.583,-2.711 -10.345,-2.711c-3.762,0 -7.192,0.885 -10.29,2.655c-3.098,1.77 -5.569,4.352 -7.413,7.745c-1.844,3.393 -2.766,7.376 -2.766,11.949c0,4.647 0.922,8.685 2.766,12.115c1.844,3.43 4.315,6.048 7.413,7.856c3.098,1.807 6.528,2.711 10.29,2.711c3.762,0 7.21,-0.904 10.345,-2.711c3.135,-1.807 5.624,-4.426 7.468,-7.856c1.844,-3.43 2.766,-7.431 2.766,-12.005Z" style="fill:#fff;fill-rule:nonzero;"/><path d="M391.686,125.886c-4.658,0 -8.836,-0.793 -12.534,-2.379c-3.696,-1.586 -6.617,-3.799 -8.761,-6.638c-2.144,-2.84 -3.216,-6.104 -3.216,-9.792l10.29,0c0.295,3.024 1.715,5.495 4.26,7.413c2.545,1.918 5.882,2.877 10.013,2.877c3.836,0 6.86,-0.848 9.073,-2.545c2.213,-1.696 3.319,-3.836 3.319,-6.417c0,-2.655 -1.18,-4.628 -3.541,-5.919c-2.36,-1.291 -6.012,-2.563 -10.953,-3.817c-4.499,-1.18 -8.169,-2.379 -11.009,-3.596c-2.84,-1.217 -5.274,-3.024 -7.302,-5.421c-2.028,-2.397 -3.043,-5.551 -3.043,-9.46c0,-3.098 0.922,-5.938 2.766,-8.519c1.844,-2.582 4.463,-4.628 7.856,-6.141c3.393,-1.512 7.265,-2.268 11.617,-2.268c6.712,0 12.134,1.696 16.264,5.089c4.131,3.393 6.343,8.04 6.638,13.941l-10.29,0c0,-3.172 -1.167,-5.716 -3.501,-7.634c-2.334,-1.918 -5.464,-2.877 -9.391,-2.877c-3.63,0 -6.52,0.774 -8.67,2.323c-2.148,1.549 -3.222,3.577 -3.222,6.0Line truncated
|
||||||
|
After Width: | Height: | Size: 8.8 KiB |
@@ -1,13 +1,13 @@
|
|||||||
:root {
|
:root {
|
||||||
/* Colors */
|
/* Colors */
|
||||||
--btn-bg-primary: #267361;
|
--btn-bg-primary: var(--color-accent);
|
||||||
--btn-bg-primary-hover: #267361;
|
--btn-bg-primary-hover: var(--color-accent);
|
||||||
--btn-bg-primary-active: #353030;
|
--btn-bg-primary-active: #353030;
|
||||||
|
|
||||||
--btn-text-light: #fefcfb;
|
--btn-text-light: #fefcfb;
|
||||||
--btn-text-dark: #267361;
|
--btn-text-dark: var(--color-accent);
|
||||||
|
|
||||||
--btn-border-primary: #267361;
|
--btn-border-primary: var(--color-accent);
|
||||||
--btn-border-ghost: #e9e9e9;
|
--btn-border-ghost: #e9e9e9;
|
||||||
--btn-border-ghost-hover: #ececec;
|
--btn-border-ghost-hover: #ececec;
|
||||||
--btn-border-ghost-active: #e1e1e1;
|
--btn-border-ghost-active: #e1e1e1;
|
||||||
@@ -25,20 +25,21 @@
|
|||||||
--btn-focus-offset: 2px;
|
--btn-focus-offset: 2px;
|
||||||
|
|
||||||
/* Layout */
|
/* Layout */
|
||||||
--btn-py: 12px;
|
--btn-py: 8px;
|
||||||
--btn-px: 16px;
|
--btn-px: 12px;
|
||||||
--btn-py-lg: 16px;
|
--btn-py-lg: 16px;
|
||||||
--btn-px-lg: 24px;
|
--btn-px-lg: 20px;
|
||||||
--btn-radius: 50px;
|
--btn-radius: 50px;
|
||||||
--btn-gap: 8px;
|
--btn-gap: 8px;
|
||||||
--btn-max-height: 52px;
|
--btn-max-height: 46px;
|
||||||
|
--btn-min-height: 38px;
|
||||||
--btn-icon-size: 18px;
|
--btn-icon-size: 18px;
|
||||||
--btn-tertiary-px: 4px;
|
--btn-tertiary-px: 4px;
|
||||||
|
|
||||||
/* Typography */
|
/* Typography */
|
||||||
--btn-font-family: var(--font-body);
|
--btn-font-family: var(--font-body);
|
||||||
--btn-font-size: 0.889rem;
|
--btn-font-size: var(--font-size-xs);
|
||||||
--btn-font-weight: var(--font-weight-bold);
|
--btn-font-weight: var(--font-weight-medium);
|
||||||
--btn-line-height: 1;
|
--btn-line-height: 1;
|
||||||
|
|
||||||
/* Shadow */
|
/* Shadow */
|
||||||
@@ -72,6 +73,7 @@
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
transition: var(--btn-transition);
|
transition: var(--btn-transition);
|
||||||
-webkit-tap-highlight-color: transparent;
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
z-index: 999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn:focus {
|
.btn:focus {
|
||||||
@@ -121,12 +123,37 @@
|
|||||||
transition: none;
|
transition: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Filled Inverse */
|
||||||
|
.btn--filled-inverse {
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: var(--color-accent);
|
||||||
|
border-color: #ffffff;
|
||||||
|
box-shadow: var(--btn-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn--filled-inverse .btn-icon {
|
||||||
|
color: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn--filled-inverse:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.9);
|
||||||
|
border-color: rgba(255, 255, 255, 0.9);
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn--filled-inverse:active {
|
||||||
|
background-color: rgba(255, 255, 255, 0.75);
|
||||||
|
border-color: rgba(255, 255, 255, 0.75);
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* Outline */
|
/* Outline */
|
||||||
.btn--outline {
|
.btn--outline {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
color: var(--btn-text-dark);
|
color: var(--btn-text-dark);
|
||||||
border-color: var(--btn-border-primary);
|
border-color: var(--btn-border-primary);
|
||||||
box-shadow: var(--btn-shadow-none);
|
box-shadow: var(--btn-shadow-none);
|
||||||
|
min-height: var(--btn-min-height);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn--outline .btn-icon {
|
.btn--outline .btn-icon {
|
||||||
@@ -217,6 +244,12 @@
|
|||||||
border-color: var(--btn-bg-primary);
|
border-color: var(--btn-bg-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn--filled-inverse:hover {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-color: #ffffff;
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
.btn--outline:hover {
|
.btn--outline:hover {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border-color: var(--btn-border-primary);
|
border-color: var(--btn-border-primary);
|
||||||
@@ -240,6 +273,5 @@
|
|||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
.btn {
|
.btn {
|
||||||
padding: var(--btn-py-lg) var(--btn-px-lg);
|
padding: var(--btn-py-lg) var(--btn-px-lg);
|
||||||
font-size: 1rem;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,10 +47,17 @@
|
|||||||
--color-surface-alt: #f9f9f9;
|
--color-surface-alt: #f9f9f9;
|
||||||
--color-background: #ffffff;
|
--color-background: #ffffff;
|
||||||
--color-background-alt: #f9f9f9;
|
--color-background-alt: #f9f9f9;
|
||||||
|
--color-background-linear: linear-gradient(
|
||||||
|
to bottom,
|
||||||
|
#f9f9f9 5%,
|
||||||
|
#ffffff 50%,
|
||||||
|
#f9f9f9 100%
|
||||||
|
);
|
||||||
--color-text: #171717;
|
--color-text: #171717;
|
||||||
--color-text-muted: #5f5f5f;
|
--color-text-muted: #4a4a4a;
|
||||||
--color-text-soft: #7a7a7a;
|
--color-text-soft: #7a7a7a;
|
||||||
--color-heading: #171717;
|
--color-heading: #171717;
|
||||||
|
--color-accent: #267361;
|
||||||
|
|
||||||
/* Radius */
|
/* Radius */
|
||||||
--radius-none: 0;
|
--radius-none: 0;
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
:root {
|
:root {
|
||||||
/* Font sizes */
|
/* Font sizes */
|
||||||
--font-size-body: 1rem;
|
--font-size-xxs: 0.79rem;
|
||||||
--font-size-small: 0.875rem;
|
--font-size-xs: clamp(0.79rem, 2vw, 0.889rem);
|
||||||
--font-size-lead: 1.125rem;
|
--font-size-s: 0.889rem;
|
||||||
|
--font-size-base: clamp(0.889rem, 2.2vw, 1rem);
|
||||||
|
--font-size-m: clamp(1rem, 2.15vw, 1.125rem);
|
||||||
|
|
||||||
/* Fluid typography (768px to 1024px) */
|
/* Fluid typography (768px to 1024px) */
|
||||||
--font-size-h1: clamp(1.802rem, 5.71vw, 3.247rem);
|
--font-size-h1: clamp(1.802rem, 5.71vw, 3.247rem);
|
||||||
@@ -12,7 +14,8 @@
|
|||||||
--font-size-h5: clamp(1.125rem, 2.82vw, 1.602rem);
|
--font-size-h5: clamp(1.125rem, 2.82vw, 1.602rem);
|
||||||
|
|
||||||
--line-height-body: 1.5;
|
--line-height-body: 1.5;
|
||||||
--line-height-heading: 1.2;
|
--line-height-heading: 1.1;
|
||||||
|
--line-height-lead: 1.2;
|
||||||
|
|
||||||
--letter-spacing-tight: -0.02em;
|
--letter-spacing-tight: -0.02em;
|
||||||
--letter-spacing-normal: 0;
|
--letter-spacing-normal: 0;
|
||||||
@@ -36,20 +39,20 @@ a {
|
|||||||
|
|
||||||
p,
|
p,
|
||||||
li {
|
li {
|
||||||
font-size: var(--font-size-body);
|
font-size: var(--font-size-base);
|
||||||
line-height: var(--line-height-body);
|
line-height: var(--line-height-body);
|
||||||
}
|
}
|
||||||
|
|
||||||
small,
|
.small,
|
||||||
.text-small {
|
.text-small {
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-xs);
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lead,
|
.lead,
|
||||||
.text-lead {
|
.text-lead {
|
||||||
font-size: var(--font-size-lead);
|
font-size: var(--font-size-m);
|
||||||
line-height: 1.4;
|
line-height: var(--line-height-lead);
|
||||||
}
|
}
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
|
|||||||