feat: redesign Hero block, update global design tokens and fonts to new editorial direction
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Inter, Outfit } from 'next/font/google'
|
import { Public_Sans, Fraunces } from 'next/font/google'
|
||||||
import { Providers } from '../../components/Providers'
|
import { Providers } from '../../components/Providers'
|
||||||
import { LanguageSlugsProvider } from '../../components/LanguageSlugsProvider'
|
import { LanguageSlugsProvider } from '../../components/LanguageSlugsProvider'
|
||||||
import { Header } from '../../components/Header'
|
import { Header } from '../../components/Header'
|
||||||
@@ -8,8 +8,13 @@ import { getPayload } from 'payload'
|
|||||||
import configPromise from '@payload-config'
|
import configPromise from '@payload-config'
|
||||||
import '../globals.css'
|
import '../globals.css'
|
||||||
|
|
||||||
const inter = Inter({ subsets: ['latin'], variable: '--font-sans' })
|
const publicSans = Public_Sans({ subsets: ['latin'], variable: '--font-sans' })
|
||||||
const outfit = Outfit({ subsets: ['latin'], variable: '--font-heading' })
|
const fraunces = Fraunces({
|
||||||
|
subsets: ['latin'],
|
||||||
|
variable: '--font-heading',
|
||||||
|
axes: ['opsz'],
|
||||||
|
weight: 'variable',
|
||||||
|
})
|
||||||
|
|
||||||
export const metadata = {
|
export const metadata = {
|
||||||
title: 'Finanz- & Lohnbuchhaltung Dipl.-Ing. Janusz Kędzierski',
|
title: 'Finanz- & Lohnbuchhaltung Dipl.-Ing. Janusz Kędzierski',
|
||||||
@@ -50,7 +55,7 @@ export default async function RootLayout({
|
|||||||
const footerNavItems = (footerData.navigation || []).map((item: any) => item.page).filter((page: any) => typeof page === 'object' && page !== null);
|
const footerNavItems = (footerData.navigation || []).map((item: any) => item.page).filter((page: any) => typeof page === 'object' && page !== null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang="pl" suppressHydrationWarning className={`${inter.variable} ${outfit.variable}`}>
|
<html lang="pl" suppressHydrationWarning className={`${publicSans.variable} ${fraunces.variable}`}>
|
||||||
<body>
|
<body>
|
||||||
<Providers>
|
<Providers>
|
||||||
<LanguageSlugsProvider>
|
<LanguageSlugsProvider>
|
||||||
|
|||||||
+16
-18
@@ -10,35 +10,33 @@
|
|||||||
--color-card: var(--card-color);
|
--color-card: var(--card-color);
|
||||||
--color-border: var(--border-color);
|
--color-border: var(--border-color);
|
||||||
|
|
||||||
--font-sans: 'Inter', sans-serif;
|
--font-sans: 'Public Sans', sans-serif;
|
||||||
--font-heading: 'Outfit', sans-serif;
|
--font-heading: 'Fraunces', serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
/* Jasny motyw */
|
/* Jasny motyw */
|
||||||
--bg-color: #FAFAFA;
|
--bg-color: #F7F5F1;
|
||||||
--fg-color: #18181B;
|
--fg-color: #1C1B1A;
|
||||||
--card-color: #FFFFFF;
|
--card-color: #FFFFFF;
|
||||||
--border-color: #E4E4E7;
|
--border-color: #E2DDD3;
|
||||||
|
|
||||||
/* Ciemniejszy złoty/ochra dla zachowania kontrastu na jasnym tle */
|
--accent-color: #A13D2C;
|
||||||
--accent-color: #7B5C35;
|
--accent-hover-color: #8A3324;
|
||||||
--accent-hover-color: #614828;
|
|
||||||
|
|
||||||
/* Globalny token dla przycisków prostokątnych (umiarkowane zaokrąglenie, nie pill) */
|
/* Globalny token dla przycisków prostokątnych (umiarkowane zaokrąglenie, nie pill) */
|
||||||
--radius-button: 6px;
|
--radius-button: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="dark"] {
|
[data-theme="dark"] {
|
||||||
/* Ciemny motyw: czysty, głęboki antracyt (bez niebieskiego odcienia) */
|
/* Ciemny motyw */
|
||||||
--bg-color: #121212;
|
--bg-color: #17140F;
|
||||||
--fg-color: #F8FAFC;
|
--fg-color: #F5F1E8;
|
||||||
--card-color: #18181B;
|
--card-color: #1F1B14;
|
||||||
--border-color: #27272A;
|
--border-color: #332C21;
|
||||||
|
|
||||||
/* Jasny złoty/ochra dla zachowania kontrastu na ciemnym tle */
|
--accent-color: #D4634A;
|
||||||
--accent-color: #C5A880;
|
--accent-hover-color: #E17B62;
|
||||||
--accent-hover-color: #D4B995;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Globalne style dla HTML i Body */
|
/* Globalne style dla HTML i Body */
|
||||||
@@ -57,7 +55,7 @@ body {
|
|||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
h1, h2, h3, h4, h5, h6 {
|
||||||
font-family: var(--font-heading);
|
font-family: var(--font-heading);
|
||||||
font-weight: 600;
|
font-weight: 500;
|
||||||
letter-spacing: -0.02em;
|
letter-spacing: -0.02em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +66,7 @@ h1, h2, h3, h4, h5, h6 {
|
|||||||
}
|
}
|
||||||
.btn-primary:hover {
|
.btn-primary:hover {
|
||||||
background-color: var(--accent-hover-color);
|
background-color: var(--accent-hover-color);
|
||||||
@apply shadow-lg transform -translate-y-0.5;
|
@apply shadow-lg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Utility dla szerokich kontenerów i dużego oddechu (whitespace) */
|
/* Utility dla szerokich kontenerów i dużego oddechu (whitespace) */
|
||||||
|
|||||||
@@ -1,100 +1,65 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import React, { useState, useEffect } from 'react'
|
import React from 'react'
|
||||||
import type { Page } from '../../payload-types'
|
import type { Page, Media } from '../../payload-types'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import { ArrowRight } from 'lucide-react'
|
|
||||||
|
|
||||||
type Props = Extract<NonNullable<Page['layout']>[0], { blockType: 'hero' }>
|
type Props = Extract<NonNullable<Page['layout']>[0], { blockType: 'hero' }>
|
||||||
|
|
||||||
/* PLACEHOLDER - do podmiany na realne zdjęcia klienta */
|
export const HeroBlock: React.FC<Props> = ({ title, subtitle, primaryCta, secondaryCta, image }) => {
|
||||||
const heroImages = [
|
// Sprawdzamy czy obrazek jest obiektem Media czy tylko ID
|
||||||
{
|
const heroMedia = typeof image === 'object' && image !== null ? (image as Media) : null;
|
||||||
url: 'https://images.unsplash.com/photo-1554224155-8d04cb21cd6c?auto=format&fit=crop&w=2000&q=80',
|
// PLACEHOLDER - do podmiany na zdjęcie klienta jeśli brak w CMS
|
||||||
alt: 'Dokumenty podatkowe i praca biurowa',
|
const imageUrl = heroMedia?.url || 'https://images.unsplash.com/photo-1554224155-8d04cb21cd6c?auto=format&fit=crop&w=1200&q=80';
|
||||||
},
|
const imageAlt = heroMedia?.alt || 'Doradztwo podatkowe - biuro';
|
||||||
{
|
|
||||||
url: 'https://images.unsplash.com/photo-1497366216548-37526070297c?auto=format&fit=crop&w=2000&q=80',
|
|
||||||
alt: 'Profesjonalne biuro doradztwa podatkowego',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: 'https://images.unsplash.com/photo-1486312338219-ce68d2c6f44d?auto=format&fit=crop&w=2000&q=80',
|
|
||||||
alt: 'Praca z rozliczeniami podatkowymi',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
export const HeroBlock: React.FC<Props> = ({ title, subtitle, primaryCta, secondaryCta, yearsOfExperience }) => {
|
|
||||||
const [currentSlide, setCurrentSlide] = useState(0)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const timer = setInterval(() => {
|
|
||||||
setCurrentSlide((prev) => (prev + 1) % heroImages.length)
|
|
||||||
}, 6000)
|
|
||||||
return () => clearInterval(timer)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="relative w-full min-h-[90vh] flex items-end bg-background text-foreground pb-20 md:pb-32 pt-40">
|
<section className="w-full bg-background text-foreground pt-32 pb-16 md:pt-48 md:pb-24">
|
||||||
{/* Pełnoekranowe tło ze sliderem */}
|
<div className="container-premium">
|
||||||
<div className="absolute inset-0 z-0 overflow-hidden">
|
<div className="flex flex-col-reverse md:flex-row items-center justify-between gap-12 lg:gap-24">
|
||||||
{heroImages.map((img, idx) => (
|
|
||||||
<div
|
|
||||||
key={idx}
|
|
||||||
className={`absolute inset-0 transition-opacity duration-1000 ease-in-out ${
|
|
||||||
idx === currentSlide ? 'opacity-100' : 'opacity-0 pointer-events-none'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{/* PLACEHOLDER - do podmiany na realne zdjęcia klienta */}
|
|
||||||
<Image
|
|
||||||
src={img.url}
|
|
||||||
alt={img.alt}
|
|
||||||
fill
|
|
||||||
priority={idx === 0}
|
|
||||||
sizes="100vw"
|
|
||||||
className="object-cover object-center"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
{/* Potężny, gładki overlay z koloru tła aplikacji od dołu i od lewej, dla idealnej czytelności */}
|
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-background via-background/80 to-transparent" />
|
|
||||||
<div className="absolute inset-0 bg-gradient-to-r from-background via-background/40 to-transparent" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="container-premium relative z-10">
|
<div className="w-full md:w-1/2 max-w-xl flex flex-col">
|
||||||
<div className="max-w-4xl">
|
<h1 className="font-heading text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold leading-[1.05] text-foreground mb-8 text-balance">
|
||||||
{yearsOfExperience && (
|
{title}
|
||||||
<div className="font-mono text-sm md:text-base font-bold text-accent tracking-widest uppercase mb-4">
|
</h1>
|
||||||
// {yearsOfExperience}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<h1 className="font-heading text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-extrabold tracking-tight leading-[1.05] text-foreground mb-8 text-balance">
|
<p className="text-xl sm:text-2xl text-foreground/80 mb-12 leading-relaxed font-light">
|
||||||
{title}
|
{subtitle}
|
||||||
</h1>
|
</p>
|
||||||
|
|
||||||
<p className="text-xl sm:text-2xl text-foreground/80 mb-12 leading-relaxed max-w-2xl font-light">
|
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-8">
|
||||||
{subtitle}
|
<a
|
||||||
</p>
|
href={process.env.NEXT_PUBLIC_WHATSAPP_LINK || '#'}
|
||||||
|
target="_blank"
|
||||||
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-8">
|
rel="noopener noreferrer"
|
||||||
<a
|
className="btn-primary"
|
||||||
href={process.env.NEXT_PUBLIC_WHATSAPP_LINK || '#'}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="px-8 py-4 bg-accent hover:bg-accent/90 text-background font-bold text-base sm:text-lg transition-colors flex items-center justify-center rounded-[var(--radius-button)]"
|
|
||||||
>
|
|
||||||
{primaryCta}
|
|
||||||
</a>
|
|
||||||
{secondaryCta?.text && secondaryCta?.url && (
|
|
||||||
<Link
|
|
||||||
href={secondaryCta.url}
|
|
||||||
className="group flex items-center gap-3 text-foreground font-semibold text-lg hover:text-accent transition-colors"
|
|
||||||
>
|
>
|
||||||
<span>{secondaryCta.text}</span>
|
{primaryCta}
|
||||||
<ArrowRight className="w-5 h-5 group-hover:translate-x-1 transition-transform" />
|
</a>
|
||||||
</Link>
|
{secondaryCta?.text && secondaryCta?.url && (
|
||||||
)}
|
<Link
|
||||||
|
href={secondaryCta.url}
|
||||||
|
className="text-foreground font-semibold text-lg hover:text-accent hover:underline underline-offset-4 transition-colors"
|
||||||
|
>
|
||||||
|
{secondaryCta.text}
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="w-full md:w-1/2 flex justify-center md:justify-end">
|
||||||
|
<div className="relative w-full aspect-[4/5] max-w-md">
|
||||||
|
<Image
|
||||||
|
src={imageUrl}
|
||||||
|
alt={imageAlt}
|
||||||
|
fill
|
||||||
|
priority
|
||||||
|
sizes="(max-width: 768px) 100vw, 50vw"
|
||||||
|
className="object-cover object-center"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -14,6 +14,6 @@ export const Hero: Block = {
|
|||||||
{ name: 'url', type: 'text' },
|
{ name: 'url', type: 'text' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{ name: 'yearsOfExperience', type: 'text', localized: true },
|
{ name: 'image', type: 'upload', relationTo: 'media', required: true },
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ export interface Page {
|
|||||||
text?: string | null;
|
text?: string | null;
|
||||||
url?: string | null;
|
url?: string | null;
|
||||||
};
|
};
|
||||||
yearsOfExperience?: string | null;
|
image: number | Media;
|
||||||
id?: string | null;
|
id?: string | null;
|
||||||
blockName?: string | null;
|
blockName?: string | null;
|
||||||
blockType: 'hero';
|
blockType: 'hero';
|
||||||
@@ -624,7 +624,7 @@ export interface PagesSelect<T extends boolean = true> {
|
|||||||
text?: T;
|
text?: T;
|
||||||
url?: T;
|
url?: T;
|
||||||
};
|
};
|
||||||
yearsOfExperience?: T;
|
image?: T;
|
||||||
id?: T;
|
id?: T;
|
||||||
blockName?: T;
|
blockName?: T;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user