fix(ui): improve header navigation contrast on dark theme and add frontend not-found route
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-[60vh] text-center px-4">
|
||||
<h1 className="font-heading text-6xl font-bold text-foreground mb-4">404</h1>
|
||||
<h2 className="text-2xl font-semibold text-foreground/80 mb-6">
|
||||
Strona nie została znaleziona
|
||||
</h2>
|
||||
<p className="text-foreground/60 max-w-md mb-8">
|
||||
Przepraszamy, ale strona, której szukasz nie istnieje, została usunięta lub zmieniono jej adres.
|
||||
</p>
|
||||
<Link
|
||||
href="/"
|
||||
className="inline-flex items-center justify-center bg-accent hover:bg-accent-hover text-white font-medium px-6 py-3 rounded-[var(--radius-button)] transition-colors"
|
||||
>
|
||||
Wróć na stronę główną
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -28,11 +28,7 @@ export const EligibilityBlock: React.FC<EligibilityProps> = ({ eyebrow, title,
|
||||
<section className="py-12 md:py-20 bg-card/60 border-y border-border">
|
||||
<div className="container-premium">
|
||||
<div className="max-w-3xl mb-12">
|
||||
{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">
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
@@ -1,41 +1,68 @@
|
||||
'use client'
|
||||
import React from 'react'
|
||||
|
||||
import Link from 'next/link'
|
||||
import React, { useState } from 'react'
|
||||
import { motion, AnimatePresence } from 'framer-motion'
|
||||
import { ChevronDown } from 'lucide-react'
|
||||
import type { Page } from '../../payload-types'
|
||||
|
||||
type Props = Extract<NonNullable<Page['layout']>[0], { blockType: 'faqTeaser' }>
|
||||
|
||||
export const FAQTeaserBlock: React.FC<Props> = ({ eyebrow, title, questions, linkText }) => {
|
||||
return (
|
||||
<section className="py-20 md:py-32 bg-card/40 border-t border-border">
|
||||
<div className="container-premium">
|
||||
<div className="max-w-3xl mb-16 md:mb-24">
|
||||
export const FAQTeaserBlock: React.FC<Props> = ({ title, questions }) => {
|
||||
const [openIndex, setOpenIndex] = useState<number | null>(0)
|
||||
|
||||
const toggleQuestion = (index: number) => {
|
||||
setOpenIndex(openIndex === index ? null : index)
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="py-20 md:py-32 bg-card/40 border-t border-border" id="faq">
|
||||
<div className="container-premium max-w-4xl">
|
||||
<div className="mb-12 md:mb-16 text-center">
|
||||
<h2 className="font-heading text-3xl sm:text-4xl md:text-5xl font-extrabold text-foreground tracking-tight text-balance">
|
||||
{title}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6 mb-12">
|
||||
{questions?.map((q: NonNullable<Props['questions']>[0], index: number) => (
|
||||
<div
|
||||
key={q.id || index}
|
||||
className="py-6 border-b border-border/50 first:border-t"
|
||||
>
|
||||
<h3 className="font-heading text-xl sm:text-2xl font-bold text-foreground mb-3">{q.question}</h3>
|
||||
<p className="text-foreground/75 leading-relaxed">{q.answer}</p>
|
||||
</div>
|
||||
))}
|
||||
<div className="space-y-4">
|
||||
{questions?.map((q: NonNullable<Props['questions']>[0], index: number) => {
|
||||
const isOpen = openIndex === index
|
||||
|
||||
return (
|
||||
<div
|
||||
key={q.id || index}
|
||||
className="bg-background border border-border overflow-hidden shadow-sm hover:shadow-md transition-shadow"
|
||||
>
|
||||
<button
|
||||
onClick={() => toggleQuestion(index)}
|
||||
className="w-full flex items-center justify-between p-6 text-left hover:bg-card/50 transition-colors focus:outline-none"
|
||||
aria-expanded={isOpen}
|
||||
>
|
||||
<h3 className="font-heading text-lg sm:text-xl font-bold text-foreground pr-8">
|
||||
{q.question}
|
||||
</h3>
|
||||
<div className="w-8 h-8 rounded-full bg-accent/10 flex items-center justify-center shrink-0">
|
||||
<ChevronDown
|
||||
className={`w-5 h-5 text-accent transition-transform duration-300 ${isOpen ? 'rotate-180' : ''}`}
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
<AnimatePresence initial={false}>
|
||||
{isOpen && (
|
||||
<motion.div
|
||||
initial={{ height: 0, opacity: 0 }}
|
||||
animate={{ height: 'auto', opacity: 1 }}
|
||||
exit={{ height: 0, opacity: 0 }}
|
||||
transition={{ duration: 0.3, ease: 'easeInOut' }}
|
||||
>
|
||||
<div className="p-6 pt-0 text-foreground/75 leading-relaxed border-t border-border/10">
|
||||
{q.answer}
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
{linkText && (
|
||||
<div className="mt-12">
|
||||
<Link href="/faq" className="inline-block text-accent font-semibold hover:text-accent-hover underline underline-offset-4">
|
||||
{linkText}
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
|
||||
@@ -3,7 +3,6 @@ import type { Block } from 'payload'
|
||||
export const FAQTeaser: Block = {
|
||||
slug: 'faqTeaser',
|
||||
fields: [
|
||||
{ name: 'eyebrow', type: 'text', localized: true },
|
||||
{ name: 'title', type: 'text', required: true, localized: true },
|
||||
{
|
||||
name: 'questions',
|
||||
@@ -15,6 +14,5 @@ export const FAQTeaser: Block = {
|
||||
{ name: 'answer', type: 'textarea', required: true },
|
||||
],
|
||||
},
|
||||
{ name: 'linkText', type: 'text', localized: true },
|
||||
],
|
||||
}
|
||||
|
||||
@@ -74,14 +74,14 @@ export const ServicesDetailedBlock: React.FC<Props> = ({
|
||||
isFirst
|
||||
? 'bg-foreground text-background border-0 shadow-md p-8 md:p-10'
|
||||
: 'bg-card text-foreground border border-border shadow-xs p-6 md:p-8'
|
||||
} rounded-none min-h-[240px] flex flex-col justify-between`}
|
||||
} rounded-none min-h-[240px] flex flex-col justify-between overflow-hidden`}
|
||||
>
|
||||
<div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="text-accent mb-6">
|
||||
<Icon size={isFirst ? 32 : 28} />
|
||||
</div>
|
||||
<h3
|
||||
className={`font-heading font-bold mb-3 leading-snug ${
|
||||
className={`font-heading font-bold mb-3 leading-snug break-words hyphens-auto ${
|
||||
isFirst
|
||||
? 'text-2xl sm:text-3xl text-background'
|
||||
: 'text-xl sm:text-2xl text-foreground'
|
||||
|
||||
@@ -44,7 +44,7 @@ export function Header({ navItems = [] }: { navItems?: any[] }) {
|
||||
<span className="font-heading font-bold text-lg leading-tight tracking-tight text-foreground">
|
||||
Finanz- & Lohnbuchhaltung
|
||||
</span>
|
||||
<span className="text-xs text-foreground/60 uppercase tracking-widest font-medium">
|
||||
<span className="text-xs text-foreground/75 uppercase tracking-widest font-medium">
|
||||
Dipl.-Ing. Janusz Kędzierski
|
||||
</span>
|
||||
</div>
|
||||
@@ -57,7 +57,7 @@ export function Header({ navItems = [] }: { navItems?: any[] }) {
|
||||
key={index}
|
||||
page={page}
|
||||
currentLocaleCode={currentLocale.code}
|
||||
className="text-sm font-medium text-foreground/80 hover:text-accent transition-colors"
|
||||
className="text-sm font-medium text-foreground/90 hover:text-accent transition-colors"
|
||||
/>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
@@ -413,7 +413,6 @@ export interface Page {
|
||||
blockType: 'testimonialsGrid';
|
||||
}
|
||||
| {
|
||||
eyebrow?: string | null;
|
||||
title: string;
|
||||
questions?:
|
||||
| {
|
||||
@@ -422,7 +421,6 @@ export interface Page {
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
linkText?: string | null;
|
||||
id?: string | null;
|
||||
blockName?: string | null;
|
||||
blockType: 'faqTeaser';
|
||||
@@ -848,7 +846,6 @@ export interface PagesSelect<T extends boolean = true> {
|
||||
faqTeaser?:
|
||||
| T
|
||||
| {
|
||||
eyebrow?: T;
|
||||
title?: T;
|
||||
questions?:
|
||||
| T
|
||||
@@ -857,7 +854,6 @@ export interface PagesSelect<T extends boolean = true> {
|
||||
answer?: T;
|
||||
id?: T;
|
||||
};
|
||||
linkText?: T;
|
||||
id?: T;
|
||||
blockName?: T;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user