changes
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import Link from "next/link";
|
||||
import { ArrowRight, Home } from "lucide-react";
|
||||
import { buttonClasses } from "@/components/ui/Button";
|
||||
|
||||
export function CalculatorTeaser() {
|
||||
return (
|
||||
<section className="py-16 md:py-24 bg-white border-b border-border">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="bg-slate-50 p-8 md:p-12 lg:p-16 border-y border-border flex flex-col lg:grid lg:grid-cols-[45%_55%] items-center gap-12 lg:gap-16">
|
||||
|
||||
<div className="flex flex-col gap-6 w-full">
|
||||
<h2 className="text-3xl md:text-4xl lg:text-5xl font-extrabold text-primary font-heading leading-tight">
|
||||
Nie wiesz, jakiej mocy potrzebujesz?
|
||||
</h2>
|
||||
<p className="text-base md:text-lg text-text-muted leading-relaxed max-w-xl">
|
||||
Skorzystaj z naszego inteligentnego kalkulatora. Wystarczy podać metraż pomieszczenia, a my wskażemy optymalną moc klimatyzatora i przybliżony koszt instalacji.
|
||||
</p>
|
||||
|
||||
<div className="mt-4">
|
||||
<Link href="/kalkulator" className={buttonClasses({ variant: 'primary', size: 'lg', className: 'group w-fit' })}>
|
||||
<span>Uruchom kalkulator</span>
|
||||
<ArrowRight className="size-5 group-hover:translate-x-1 transition-transform" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-full">
|
||||
<div className="bg-white rounded-xl p-8 border border-border shadow-md">
|
||||
<div className="flex flex-col gap-8">
|
||||
<div className="flex justify-between items-end border-b border-border pb-4">
|
||||
<div>
|
||||
<p className="text-sm font-semibold text-text-muted mb-1">Powierzchnia</p>
|
||||
<p className="text-3xl font-bold text-primary font-heading">35 <span className="text-xl text-text-muted">m²</span></p>
|
||||
</div>
|
||||
<Home className="size-8 text-accent opacity-50" />
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="h-2 w-full bg-slate-100 rounded-full overflow-hidden">
|
||||
<div className="h-full bg-accent rounded-full w-1/2"></div>
|
||||
</div>
|
||||
<div className="flex justify-between text-xs font-semibold text-text-muted">
|
||||
<span>10 m²</span>
|
||||
<span>100 m²</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-accent/5 rounded-xl p-6 border border-accent/10 flex flex-col items-center text-center">
|
||||
<p className="text-sm font-semibold text-primary mb-1">Sugerowana moc</p>
|
||||
<p className="text-4xl font-extrabold text-accent font-heading">3.5 <span className="text-2xl text-accent/70">kW</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import Link from "next/link";
|
||||
import { Phone, ArrowRight } from "lucide-react";
|
||||
import { companyDetails } from "@/content/company";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { buttonClasses } from "@/components/ui/Button";
|
||||
|
||||
interface CtaBannerProps {
|
||||
title?: string;
|
||||
@@ -56,26 +57,15 @@ export function CtaBanner({
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col sm:flex-row items-center gap-4 mt-8 w-full sm:w-auto shrink-0 justify-center">
|
||||
<Link href={ctaLink} className="w-fit sm:w-auto btn btn-primary font-bold text-white px-6">
|
||||
<span>{ctaText}</span>
|
||||
<ArrowRight className="size-5" />
|
||||
<Link href={ctaLink} className={buttonClasses({ variant: 'primary', size: 'md', className: 'w-fit sm:w-auto' })}>
|
||||
{ctaText} <ArrowRight className="size-4" />
|
||||
</Link>
|
||||
|
||||
<a
|
||||
href={`tel:${companyDetails.phoneRaw}`}
|
||||
className="w-fit sm:w-auto"
|
||||
className={buttonClasses({ variant: isPrimary ? 'outline-light' : 'outline', size: 'md', className: 'w-fit sm:w-auto' })}
|
||||
>
|
||||
<button
|
||||
className={cn(
|
||||
"btn btn-outline btn-primary bg-white w-fit sm:w-auto font-bold flex items-center gap-2 px-6",
|
||||
isPrimary
|
||||
? "text-white hover:bg-white/20 hover:text-white border-white/30"
|
||||
: "text-primary hover:bg-primary/10 border-primary/20"
|
||||
)}
|
||||
>
|
||||
<Phone className="size-5" />
|
||||
<span>{companyDetails.phone}</span>
|
||||
</button>
|
||||
<Phone className="size-4" /> {companyDetails.phone}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { ArrowRight, Star } from "lucide-react";
|
||||
import { buttonClasses } from "@/components/ui/Button";
|
||||
import { Outfit } from "next/font/google";
|
||||
|
||||
const outfit = Outfit({ subsets: ["latin"], weight: ["500", "700", "800"] });
|
||||
|
||||
export interface HeroSectionProps {
|
||||
title?: React.ReactNode;
|
||||
@@ -10,73 +11,88 @@ export interface HeroSectionProps {
|
||||
ctaLink?: string;
|
||||
secondaryCtaText?: string;
|
||||
secondaryCtaLink?: string;
|
||||
backgroundImage?: string;
|
||||
features?: string[];
|
||||
}
|
||||
|
||||
export function HeroSection({
|
||||
title = (
|
||||
<>
|
||||
<span className="text-white">Klimatyzacja</span><br />
|
||||
<span className="text-primary">Klimatyzacja</span><br />
|
||||
<span className="text-accent">we Wrocławiu</span>
|
||||
</>
|
||||
),
|
||||
subtitle = "Montaż, serwis i naprawa — przyjeżdżamy do Ciebie.",
|
||||
subtitle = "Montaż, serwis i naprawa — przyjeżdżamy do Ciebie. Zapewniamy najwyższą jakość instalacji oraz pełne wsparcie pogwarancyjne.",
|
||||
ctaText = "Darmowa wycena",
|
||||
ctaLink = "/kontakt",
|
||||
secondaryCtaText = "Zobacz ofertę",
|
||||
secondaryCtaLink = "/sklep",
|
||||
backgroundImage = "/images/hero/home_page_hero.webp",
|
||||
features
|
||||
secondaryCtaLink = "/sklep"
|
||||
}: HeroSectionProps = {}) {
|
||||
return (
|
||||
<section className="relative bg-primary min-h-[480px] md:min-h-[600px] flex items-center overflow-hidden w-full">
|
||||
{/* TODO ZDJĘCIE HERO: realne zdjęcie firmy/montażu, format poziomy min. 1920×1080, plik public/hero.jpg */}
|
||||
<Image
|
||||
src={backgroundImage}
|
||||
alt="Montaż klimatyzacji i pomp ciepła"
|
||||
fill
|
||||
priority
|
||||
sizes="100vw"
|
||||
className="object-cover"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-black/50" />
|
||||
|
||||
<div className="relative z-10 w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16 md:py-24">
|
||||
<div className="flex flex-col items-start text-left max-w-3xl">
|
||||
<h1 className="text-3xl md:text-5xl lg:text-6xl font-extrabold tracking-tight font-heading leading-[1.1] text-white">
|
||||
{title}
|
||||
</h1>
|
||||
<p className="mt-6 text-base md:text-lg lg:text-xl text-white/90 max-w-2xl leading-relaxed">
|
||||
{subtitle}
|
||||
</p>
|
||||
{features && features.length > 0 && (
|
||||
<ul className="mt-6 grid grid-cols-2 gap-3 text-white/90 font-medium">
|
||||
{features.map((feature, idx) => (
|
||||
<li key={idx} className="flex items-center gap-2">
|
||||
<Star className="size-4 text-yellow-400 fill-yellow-400" />
|
||||
{feature}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<section className="relative w-full bg-slate-50 flex flex-col lg:flex-row min-h-[85vh] border-b border-border">
|
||||
|
||||
{/* Lewa kolumna: Typografia i CTA */}
|
||||
<div className="w-full lg:w-[55%] flex flex-col justify-center px-6 sm:px-12 lg:px-16 xl:px-24 py-16 lg:py-24 z-10">
|
||||
|
||||
<h1 className={`${outfit.className} text-5xl sm:text-6xl xl:text-7xl font-extrabold tracking-tight leading-[1.05] uppercase`}>
|
||||
{title}
|
||||
</h1>
|
||||
|
||||
<p className="mt-8 text-lg sm:text-xl text-text-muted max-w-xl leading-relaxed">
|
||||
{subtitle}
|
||||
</p>
|
||||
|
||||
<div className="mt-12 flex flex-col sm:flex-row gap-4">
|
||||
{ctaText && ctaLink && (
|
||||
<Link
|
||||
href={ctaLink}
|
||||
className="inline-flex items-center justify-center bg-primary text-white font-bold uppercase tracking-wider px-10 py-5 rounded-none hover:bg-primary/90 transition-colors border-2 border-primary"
|
||||
>
|
||||
{ctaText}
|
||||
</Link>
|
||||
)}
|
||||
{secondaryCtaText && secondaryCtaLink && (
|
||||
<Link
|
||||
href={secondaryCtaLink}
|
||||
className="inline-flex items-center justify-center bg-transparent text-primary font-bold uppercase tracking-wider px-10 py-5 rounded-none border-2 border-primary hover:bg-primary/5 transition-colors"
|
||||
>
|
||||
{secondaryCtaText}
|
||||
</Link>
|
||||
)}
|
||||
<div className="mt-10 flex flex-col sm:flex-row items-start sm:items-center gap-4 w-full sm:w-auto">
|
||||
{ctaText && ctaLink && (
|
||||
<Link href={ctaLink} className={buttonClasses({ variant: 'primary', size: 'md', className: 'w-fit sm:w-auto group' })}>
|
||||
<span>{ctaText}</span>
|
||||
<ArrowRight className="size-5 group-hover:translate-x-1 transition-transform" />
|
||||
</Link>
|
||||
)}
|
||||
{secondaryCtaText && secondaryCtaLink && (
|
||||
<Link href={secondaryCtaLink} className={buttonClasses({ variant: 'outline', size: 'md', className: 'w-fit sm:w-auto' })}>
|
||||
<span>{secondaryCtaText}</span>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{/* Trust Signals: Minimalistyczne dane typograficzne */}
|
||||
<div className="mt-16 sm:mt-24 pt-8 border-t border-border flex flex-wrap gap-10">
|
||||
<div>
|
||||
<p className={`${outfit.className} text-4xl font-extrabold text-primary`}>15+</p>
|
||||
<p className="text-xs font-semibold uppercase tracking-widest text-text-muted mt-2">Lat doświadczenia</p>
|
||||
</div>
|
||||
<div className="hidden sm:block w-px bg-border self-stretch" />
|
||||
<div>
|
||||
<p className={`${outfit.className} text-4xl font-extrabold text-primary`}>5</p>
|
||||
<p className="text-xs font-semibold uppercase tracking-widest text-text-muted mt-2">Lat gwarancji</p>
|
||||
</div>
|
||||
<div className="hidden sm:block w-px bg-border self-stretch" />
|
||||
<div>
|
||||
<p className={`${outfit.className} text-4xl font-extrabold text-primary`}>100%</p>
|
||||
<p className="text-xs font-semibold uppercase tracking-widest text-text-muted mt-2">Pokrycia w regionie</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Prawa kolumna: Jedno wielkie, surowe zdjęcie */}
|
||||
<div className="w-full lg:w-[45%] h-[500px] lg:h-auto relative bg-slate-200">
|
||||
<Image
|
||||
src="/images/services/montaz.webp"
|
||||
alt="Profesjonalny montaż klimatyzacji"
|
||||
fill
|
||||
priority
|
||||
sizes="(max-width: 1024px) 100vw, 45vw"
|
||||
className="object-cover object-center"
|
||||
/>
|
||||
{/* Subtelny overlay dla kontrastu jeśli zajdzie potrzeba (opcjonalnie) */}
|
||||
<div className="absolute inset-0 bg-black/5 lg:bg-transparent" />
|
||||
</div>
|
||||
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { SectionHeading } from "../common/SectionHeading";
|
||||
import { IconCard } from "../common/IconCard";
|
||||
import { services as defaultServices } from "@/content/services";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { buttonClasses } from "@/components/ui/Button";
|
||||
import { ArrowRight } from "lucide-react";
|
||||
|
||||
interface ServicesGridProps {
|
||||
services?: {
|
||||
@@ -16,12 +22,14 @@ interface ServicesGridProps {
|
||||
|
||||
export function ServicesGrid({
|
||||
services = defaultServices,
|
||||
title = "Kompleksowe usługi dla Twojego domu",
|
||||
subtitle = "Zapewniamy profesjonalne wsparcie w zakresie instalacji sanitarnych, grzewczych, chłodniczych oraz prac wykończeniowych.",
|
||||
eyebrow = "Pełna Oferta"
|
||||
title = "Rozwiązania dla Twojego domu i biznesu",
|
||||
subtitle = "Wybierz kategorię usług, aby poznać szczegóły. Oferujemy kompleksowe doradztwo, montaż oraz serwis.",
|
||||
eyebrow = "Nasze Usługi"
|
||||
}: ServicesGridProps) {
|
||||
const [activeTab, setActiveTab] = useState(0);
|
||||
|
||||
return (
|
||||
<section className="py-16 md:py-24 bg-slate-50 border-t border-b border-border">
|
||||
<section className="py-16 md:py-24 bg-white border-b border-border">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<SectionHeading
|
||||
eyebrow={eyebrow}
|
||||
@@ -30,16 +38,60 @@ export function ServicesGrid({
|
||||
align="center"
|
||||
/>
|
||||
|
||||
<div className={`grid grid-cols-1 sm:grid-cols-2 gap-6 md:gap-8 mt-10 ${services.length === 2 ? 'max-w-4xl mx-auto' : 'lg:grid-cols-3'}`}>
|
||||
{services.map((service, idx) => (
|
||||
<IconCard
|
||||
key={idx}
|
||||
title={service.title}
|
||||
description={service.description}
|
||||
iconName={service.icon}
|
||||
href={service.href}
|
||||
/>
|
||||
))}
|
||||
<div className="mt-12 flex flex-col items-center">
|
||||
{/* Zakładki */}
|
||||
<div className="flex flex-wrap justify-center gap-2 md:gap-4 mb-10 bg-slate-50 p-2 rounded-2xl border border-border">
|
||||
{services.map((service, idx) => (
|
||||
<button
|
||||
key={idx}
|
||||
onClick={() => setActiveTab(idx)}
|
||||
className={`px-4 py-2.5 md:px-6 md:py-3 rounded-xl text-sm md:text-base font-bold transition-all ${
|
||||
activeTab === idx
|
||||
? "bg-white text-primary shadow-sm border border-border"
|
||||
: "text-text-muted hover:text-primary hover:bg-slate-100"
|
||||
}`}
|
||||
>
|
||||
{service.title}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Zawartość aktywnej zakładki */}
|
||||
<div className="w-full max-w-4xl bg-slate-50 rounded-3xl p-8 md:p-12 border border-border shadow-sm">
|
||||
{services.map((service, idx) => {
|
||||
if (idx !== activeTab) return null;
|
||||
|
||||
return (
|
||||
<div key={idx} className="flex flex-col md:grid md:grid-cols-[2fr_3fr] gap-8 lg:gap-12 items-center animate-fade-in-up">
|
||||
|
||||
{/* Zastąpiono sztuczną ikonę w kółku realnym zdjęciem */}
|
||||
<div className="w-full aspect-[4/3] relative rounded-xl overflow-hidden border border-border shadow-sm">
|
||||
<Image
|
||||
src={`/images/services/montaz.webp`} // Placeholder obrazka z usług (można podpiąć z contentu jeśli jest)
|
||||
alt={service.title}
|
||||
fill
|
||||
className="object-cover"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex-1">
|
||||
<h3 className="text-2xl md:text-3xl font-bold text-primary font-heading mb-4">
|
||||
{service.title}
|
||||
</h3>
|
||||
<p className="text-base md:text-lg text-text-muted leading-relaxed mb-6">
|
||||
{service.description}
|
||||
</p>
|
||||
|
||||
{service.href && (
|
||||
<Link href={service.href} className={buttonClasses({ variant: 'outline', size: 'sm' })}>
|
||||
Więcej szczegółów <ArrowRight className="size-4" />
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user