feat(redesign): update UniqueValue, FAQTeaser, Hero two-tone title, and Affiliation trust cards

This commit is contained in:
MichalC
2026-09-03 08:21:32 +02:00
parent 465a8cb0f1
commit 5d3b528cf2
8 changed files with 75 additions and 35 deletions
+24 -17
View File
@@ -1,22 +1,24 @@
'use client' 'use client'
import React from 'react' import React from 'react'
import { motion } from 'framer-motion'
import { Landmark, Scale, ShieldCheck } from 'lucide-react'
import Link from 'next/link' import Link from 'next/link'
import type { Page } from '../../payload-types' import type { Page } from '../../payload-types'
type Props = Extract<NonNullable<Page['layout']>[0], { blockType: 'affiliation' }> type Props = Extract<NonNullable<Page['layout']>[0], { blockType: 'affiliation' }>
export const AffiliationBlock: React.FC<Props> = ({ eyebrow, title, description, logo, linkText }) => { const iconMap = {
shield: ShieldCheck,
scale: Scale,
landmark: Landmark,
}
export const AffiliationBlock: React.FC<Props> = ({ eyebrow, title, description, logo, linkText, trustPoints }) => {
return ( return (
<section className="py-20 md:py-32 bg-background border-t border-border overflow-hidden"> <section className="py-20 md:py-32 bg-background border-t border-border overflow-hidden">
<div className="container-premium"> <div className="container-premium">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 lg:gap-24 items-center"> <div className="flex flex-col gap-16 lg:gap-24">
<div className="max-w-3xl"> <div className="max-w-3xl">
{eyebrow && (
<div className="font-mono text-sm md:text-base font-bold text-accent tracking-widest uppercase mb-4">
// {eyebrow}
</div>
)}
<h2 className="font-heading text-3xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-foreground mb-6 text-balance"> <h2 className="font-heading text-3xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-foreground mb-6 text-balance">
{title} {title}
</h2> </h2>
@@ -38,15 +40,20 @@ export const AffiliationBlock: React.FC<Props> = ({ eyebrow, title, description,
</div> </div>
</div> </div>
<div className="relative aspect-[4/3] lg:aspect-square w-full bg-card overflow-hidden"> {trustPoints && trustPoints.length > 0 && (
{/* PLACEHOLDER - do podmiany na realne zdjęcia klienta */} <div className="grid grid-cols-1 sm:grid-cols-3 gap-6">
<img {trustPoints.map((point: any, index: number) => {
src="https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?auto=format&fit=crop&w=1200&q=80" const Icon = (point.icon && iconMap[point.icon as keyof typeof iconMap]) || ShieldCheck
alt="Budynek urzędu, formalna architektura" return (
className="object-cover w-full h-full grayscale opacity-80 hover:grayscale-0 hover:opacity-100 transition-all duration-700" <div key={point.id || index} className="bg-card border border-border p-6 md:p-8 flex flex-col gap-4">
/> <Icon size={28} className="text-accent" />
<div className="absolute inset-0 bg-gradient-to-t from-background via-background/40 to-transparent pointer-events-none" /> <h3 className="font-heading text-xl font-bold text-foreground">{point.title}</h3>
</div> <p className="text-sm text-foreground/70 leading-relaxed">{point.description}</p>
</div>
)
})}
</div>
)}
</div> </div>
</div> </div>
</section> </section>
+18
View File
@@ -7,6 +7,24 @@ export const Affiliation: Block = {
{ name: 'title', type: 'text', required: true, localized: true }, { name: 'title', type: 'text', required: true, localized: true },
{ name: 'description', type: 'textarea', required: true, localized: true }, { name: 'description', type: 'textarea', required: true, localized: true },
{ name: 'logo', type: 'upload', relationTo: 'media' }, { name: 'logo', type: 'upload', relationTo: 'media' },
{
name: 'trustPoints',
type: 'array',
localized: true,
minRows: 1,
maxRows: 3,
fields: [
{
name: 'icon',
type: 'select',
required: true,
options: ['shield', 'scale', 'landmark'],
defaultValue: 'shield',
},
{ name: 'title', type: 'text', required: true, defaultValue: 'Punkt zaufania' },
{ name: 'description', type: 'textarea', required: true, defaultValue: 'Certyfikacja i uprawnienia potwierdzone urzędowo.' },
],
},
{ name: 'linkText', type: 'text', localized: true }, { name: 'linkText', type: 'text', localized: true },
], ],
} }
+2 -6
View File
@@ -1,6 +1,6 @@
'use client' 'use client'
import React from 'react' import React from 'react'
import { motion } from 'framer-motion'
import Link from 'next/link' import Link from 'next/link'
import type { Page } from '../../payload-types' import type { Page } from '../../payload-types'
@@ -11,11 +11,7 @@ export const FAQTeaserBlock: React.FC<Props> = ({ eyebrow, title, questions, lin
<section className="py-20 md:py-32 bg-card/40 border-t border-border"> <section className="py-20 md:py-32 bg-card/40 border-t border-border">
<div className="container-premium"> <div className="container-premium">
<div className="max-w-3xl mb-16 md:mb-24"> <div className="max-w-3xl mb-16 md:mb-24">
{eyebrow && (
<div className="font-mono text-sm md:text-base font-bold text-accent tracking-widest uppercase mb-4">
// {eyebrow}
</div>
)}
<h2 className="font-heading text-3xl sm:text-4xl md:text-5xl font-extrabold text-foreground tracking-tight text-balance"> <h2 className="font-heading text-3xl sm:text-4xl md:text-5xl font-extrabold text-foreground tracking-tight text-balance">
{title} {title}
</h2> </h2>
+4 -3
View File
@@ -6,7 +6,7 @@ import Image from 'next/image'
type Props = Extract<NonNullable<Page['layout']>[0], { blockType: 'hero' }> type Props = Extract<NonNullable<Page['layout']>[0], { blockType: 'hero' }>
export const HeroBlock: React.FC<Props> = ({ title, subtitle, primaryCta, secondaryCta, image }) => { export const HeroBlock: React.FC<Props> = ({ title, titleAccent, subtitle, primaryCta, secondaryCta, image }) => {
// Sprawdzamy czy obrazek jest obiektem Media czy tylko ID // Sprawdzamy czy obrazek jest obiektem Media czy tylko ID
const heroMedia = typeof image === 'object' && image !== null ? (image as Media) : null; const heroMedia = typeof image === 'object' && image !== null ? (image as Media) : null;
// PLACEHOLDER - do podmiany na zdjęcie klienta jeśli brak w CMS // PLACEHOLDER - do podmiany na zdjęcie klienta jeśli brak w CMS
@@ -19,8 +19,9 @@ export const HeroBlock: React.FC<Props> = ({ title, subtitle, primaryCta, second
<div className="flex flex-col-reverse md:flex-row items-center justify-between gap-12 lg:gap-24"> <div className="flex flex-col-reverse md:flex-row items-center justify-between gap-12 lg:gap-24">
<div className="w-full md:w-1/2 max-w-xl flex flex-col"> <div className="w-full md:w-1/2 max-w-xl flex flex-col">
<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"> <h1 className="font-heading text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold leading-[1.05] mb-8 text-balance">
{title} <span className="block text-foreground">{title}</span>
{titleAccent && <span className="block text-accent">{titleAccent}</span>}
</h1> </h1>
<p className="text-xl sm:text-2xl text-foreground/80 mb-12 leading-relaxed font-light"> <p className="text-xl sm:text-2xl text-foreground/80 mb-12 leading-relaxed font-light">
+2 -1
View File
@@ -3,7 +3,8 @@ import type { Block } from 'payload'
export const Hero: Block = { export const Hero: Block = {
slug: 'hero', slug: 'hero',
fields: [ fields: [
{ name: 'title', type: 'text', required: true, localized: true }, { name: 'title', type: 'text', required: true, localized: true, defaultValue: 'Tytuł strony głównej' },
{ name: 'titleAccent', type: 'text', required: true, localized: true, defaultValue: '— do uzupełnienia' },
{ name: 'subtitle', type: 'text', required: true, localized: true }, { name: 'subtitle', type: 'text', required: true, localized: true },
{ name: 'primaryCta', type: 'text', required: true, localized: true }, { name: 'primaryCta', type: 'text', required: true, localized: true },
{ {
+4 -8
View File
@@ -6,7 +6,7 @@ import { CheckCircle } from 'lucide-react'
type Props = Extract<NonNullable<Page['layout']>[0], { blockType: 'uniqueValue' }> type Props = Extract<NonNullable<Page['layout']>[0], { blockType: 'uniqueValue' }>
export const UniqueValueBlock: React.FC<Props> = ({ eyebrow, features, title, description }) => { export const UniqueValueBlock: React.FC<Props> = ({ eyebrow, features, title, description, image }) => {
return ( return (
<section className="py-20 md:py-32 bg-card/60 border-y border-border"> <section className="py-20 md:py-32 bg-card/60 border-y border-border">
<div className="container-premium"> <div className="container-premium">
@@ -16,8 +16,8 @@ export const UniqueValueBlock: React.FC<Props> = ({ eyebrow, features, title, de
<div className="relative aspect-[4/5] overflow-hidden border border-border"> <div className="relative aspect-[4/5] overflow-hidden border border-border">
{/* PLACEHOLDER - do podmiany na realne zdjęcia klienta */} {/* PLACEHOLDER - do podmiany na realne zdjęcia klienta */}
<Image <Image
src="https://images.unsplash.com/photo-1450133064473-71024230f91b?auto=format&fit=crop&w=1000&q=80" src={image && typeof image === 'object' && image.url ? image.url : "https://images.unsplash.com/photo-1454165804606-c3d57bc86b40?auto=format&fit=crop&w=1000&q=80"}
alt="Dokumenty i profesjonalne doradztwo podatkowe" alt={(image && typeof image === 'object' && image.alt) || "Dokumenty i profesjonalne doradztwo podatkowe"}
fill fill
sizes="(max-width: 1024px) 100vw, 40vw" sizes="(max-width: 1024px) 100vw, 40vw"
className="object-cover grayscale hover:grayscale-0 transition-all duration-700" className="object-cover grayscale hover:grayscale-0 transition-all duration-700"
@@ -27,11 +27,7 @@ export const UniqueValueBlock: React.FC<Props> = ({ eyebrow, features, title, de
{/* Kolumna tekstowa */} {/* Kolumna tekstowa */}
<div className="lg:col-span-7 order-1 lg:order-2 flex flex-col items-start max-w-3xl"> <div className="lg:col-span-7 order-1 lg:order-2 flex flex-col items-start max-w-3xl">
{eyebrow && (
<div className="font-mono text-sm md:text-base font-bold text-accent tracking-widest uppercase mb-4">
// {eyebrow}
</div>
)}
<h2 className="font-heading text-3xl sm:text-4xl md:text-5xl font-extrabold text-foreground tracking-tight mb-6 text-balance"> <h2 className="font-heading text-3xl sm:text-4xl md:text-5xl font-extrabold text-foreground tracking-tight mb-6 text-balance">
{title} {title}
+1
View File
@@ -6,6 +6,7 @@ export const UniqueValue: Block = {
{ name: 'eyebrow', type: 'text', localized: true }, { name: 'eyebrow', type: 'text', localized: true },
{ name: 'title', type: 'text', required: true, localized: true }, { name: 'title', type: 'text', required: true, localized: true },
{ name: 'description', type: 'textarea', required: true, localized: true }, { name: 'description', type: 'textarea', required: true, localized: true },
{ name: 'image', type: 'upload', relationTo: 'media', required: true },
{ {
name: 'features', name: 'features',
type: 'array', type: 'array',
+20
View File
@@ -255,6 +255,7 @@ export interface Page {
} }
| { | {
title: string; title: string;
titleAccent: string;
subtitle: string; subtitle: string;
primaryCta: string; primaryCta: string;
secondaryCta?: { secondaryCta?: {
@@ -295,6 +296,7 @@ export interface Page {
eyebrow?: string | null; eyebrow?: string | null;
title: string; title: string;
description: string; description: string;
image: number | Media;
features?: features?:
| { | {
text: string; text: string;
@@ -342,6 +344,14 @@ export interface Page {
title: string; title: string;
description: string; description: string;
logo?: (number | null) | Media; logo?: (number | null) | Media;
trustPoints?:
| {
icon: 'shield' | 'scale' | 'landmark';
title: string;
description: string;
id?: string | null;
}[]
| null;
linkText?: string | null; linkText?: string | null;
id?: string | null; id?: string | null;
blockName?: string | null; blockName?: string | null;
@@ -617,6 +627,7 @@ export interface PagesSelect<T extends boolean = true> {
| T | T
| { | {
title?: T; title?: T;
titleAccent?: T;
subtitle?: T; subtitle?: T;
primaryCta?: T; primaryCta?: T;
secondaryCta?: secondaryCta?:
@@ -664,6 +675,7 @@ export interface PagesSelect<T extends boolean = true> {
eyebrow?: T; eyebrow?: T;
title?: T; title?: T;
description?: T; description?: T;
image?: T;
features?: features?:
| T | T
| { | {
@@ -714,6 +726,14 @@ export interface PagesSelect<T extends boolean = true> {
title?: T; title?: T;
description?: T; description?: T;
logo?: T; logo?: T;
trustPoints?:
| T
| {
icon?: T;
title?: T;
description?: T;
id?: T;
};
linkText?: T; linkText?: T;
id?: T; id?: T;
blockName?: T; blockName?: T;