feat: complete POI Clean House website with Karcher theme, blog, interactive animations and full CMS configuration
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
import { notFound } from 'next/navigation'
|
||||
import type { Metadata } from 'next'
|
||||
import { RenderBlocks } from '@intecion/ipal-kit/rsc'
|
||||
import { createPageMetadata } from '@intecion/ipal-kit'
|
||||
import { i18nConfig } from '@/i18n.config'
|
||||
import { blockRegistry } from '@/blocks/registry'
|
||||
import { getCachedPayload, resolveRoute } from '@/lib/content'
|
||||
|
||||
interface PageProps {
|
||||
params: Promise<{
|
||||
locale: string
|
||||
slug?: string[]
|
||||
}>
|
||||
searchParams: Promise<{
|
||||
page?: string
|
||||
}>
|
||||
}
|
||||
|
||||
const pageMetadata = createPageMetadata({
|
||||
config: i18nConfig,
|
||||
baseUrl: process.env.NEXT_PUBLIC_SERVER_URL || 'http://localhost:3000',
|
||||
})
|
||||
|
||||
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
|
||||
const { locale, slug } = await params
|
||||
return pageMetadata({ payload: await getCachedPayload(), locale, slug: slug ?? [] })
|
||||
}
|
||||
|
||||
export default async function Page({ params, searchParams }: PageProps) {
|
||||
const { locale, slug } = await params
|
||||
const { page } = await searchParams
|
||||
const pageNumber = page ? parseInt(page, 10) : 1
|
||||
const route = await resolveRoute(locale, slug ?? [], isNaN(pageNumber) ? 1 : pageNumber)
|
||||
|
||||
if (!route) {
|
||||
notFound()
|
||||
}
|
||||
|
||||
const blocks = (route.doc as { layout?: unknown[] }).layout || []
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<RenderBlocks blocks={blocks as never} components={blockRegistry} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
import { notFound } from 'next/navigation'
|
||||
import type { ReactNode } from 'react'
|
||||
import {
|
||||
getConsentTexts,
|
||||
getAnalyticsConfig,
|
||||
getSystemPagePath,
|
||||
} from '@intecion/ipal-kit'
|
||||
import {
|
||||
ConsentProvider,
|
||||
CookieBanner,
|
||||
CookieButton,
|
||||
Analytics,
|
||||
} from '@intecion/ipal-kit/client'
|
||||
import { i18nConfig } from '@/i18n.config'
|
||||
import { getCachedPayload, getConfiguredLocales } from '@/lib/content'
|
||||
import { getSettings } from '@/lib/payload'
|
||||
import { Header, type NavItem } from '@/components/Header'
|
||||
import { Footer, type FooterNavItem } from '@/components/Footer'
|
||||
import '../styles.css'
|
||||
|
||||
import type { Company, Navigation, Page } from '@/payload-types'
|
||||
|
||||
interface LayoutProps {
|
||||
children: ReactNode
|
||||
params: Promise<{ locale: string }>
|
||||
}
|
||||
|
||||
function resolveNavItemHref(item: { page?: Page | number | string | null; url?: string | null }): string {
|
||||
if (item.url) return item.url
|
||||
if (item.page && typeof item.page === 'object' && 'slug' in item.page && item.page.slug) {
|
||||
return item.page.slug === 'home' ? '/' : `/${item.page.slug}`
|
||||
}
|
||||
return '#'
|
||||
}
|
||||
|
||||
export default async function LocaleLayout({ children, params }: LayoutProps) {
|
||||
const { locale } = await params
|
||||
const locales = await getConfiguredLocales()
|
||||
if (!locales.includes(locale)) notFound()
|
||||
|
||||
const payload = await getCachedPayload()
|
||||
const settings = await getSettings(locale)
|
||||
const privacyPage = (settings as { privacyPolicy?: unknown })?.privacyPolicy
|
||||
const cookiePage = (settings as { cookiePolicy?: unknown })?.cookiePolicy
|
||||
const homePage = (settings as { homepage?: unknown })?.homepage
|
||||
|
||||
let company: Company | null = null
|
||||
let navigation: Navigation | null = null
|
||||
|
||||
try {
|
||||
const [compDoc, navDoc] = await Promise.all([
|
||||
payload.findGlobal({ slug: 'company', locale: locale as never }),
|
||||
payload.findGlobal({ slug: 'navigation', locale: locale as never, depth: 2 }),
|
||||
])
|
||||
company = compDoc
|
||||
navigation = navDoc
|
||||
} catch {
|
||||
// fallback if globals not yet created
|
||||
}
|
||||
|
||||
const privacyHref = privacyPage
|
||||
? getSystemPagePath({ config: i18nConfig, locale, page: privacyPage })
|
||||
: undefined
|
||||
|
||||
const cookieHref = cookiePage
|
||||
? getSystemPagePath({ config: i18nConfig, locale, page: cookiePage })
|
||||
: undefined
|
||||
|
||||
const homeHref = homePage
|
||||
? getSystemPagePath({ config: i18nConfig, locale, page: homePage }) || '/'
|
||||
: '/'
|
||||
|
||||
const [texts, analytics] = await Promise.all([
|
||||
getConsentTexts({
|
||||
config: i18nConfig,
|
||||
locale,
|
||||
payload,
|
||||
privacyPolicy:
|
||||
privacyPage && typeof privacyPage === 'object'
|
||||
? { page: privacyPage, label: 'Polityka prywatności' }
|
||||
: undefined,
|
||||
}),
|
||||
getAnalyticsConfig(payload),
|
||||
])
|
||||
|
||||
const headerItems: NavItem[] =
|
||||
navigation?.headerItems?.map((item) => ({
|
||||
id: item.id || undefined,
|
||||
label: item.label,
|
||||
href: resolveNavItemHref(item),
|
||||
})) || []
|
||||
|
||||
const footerItems: FooterNavItem[] =
|
||||
navigation?.footerItems?.map((item) => ({
|
||||
id: item.id || undefined,
|
||||
label: item.label,
|
||||
href: resolveNavItemHref(item),
|
||||
})) || []
|
||||
|
||||
return (
|
||||
<html lang={locale}>
|
||||
<body className="min-h-screen flex flex-col bg-slate-950 text-slate-100 antialiased selection:bg-sky-500 selection:text-white">
|
||||
<ConsentProvider texts={texts}>
|
||||
<Header
|
||||
companyName={company?.shortName || company?.name}
|
||||
tagline={navigation?.tagline}
|
||||
items={headerItems}
|
||||
phone={company?.phone}
|
||||
homeHref={homeHref}
|
||||
currentLocale={locale}
|
||||
contactHref={`/${locale}/kontakt`}
|
||||
contactLabel="KONTAKT"
|
||||
/>
|
||||
<main className="flex-1">{children}</main>
|
||||
<Footer
|
||||
companyName={company?.name}
|
||||
footerTagline={navigation?.footerTagline}
|
||||
nip={company?.nip}
|
||||
regon={company?.regon}
|
||||
address={company?.address}
|
||||
city={company?.city}
|
||||
phone={company?.phone}
|
||||
email={company?.email}
|
||||
items={footerItems}
|
||||
privacyHref={privacyHref}
|
||||
cookieHref={cookieHref}
|
||||
/>
|
||||
<CookieBanner
|
||||
classNames={{
|
||||
root: 'fixed bottom-0 inset-x-0 z-50 bg-[#1f1f1f] text-white p-6 border-t-4 border-[#FFED00] shadow-2xl',
|
||||
primaryButton:
|
||||
'bg-[#FFED00] hover:bg-[#fae100] text-[#1f1f1f] border-2 border-[#1f1f1f] px-6 py-2.5 text-xs font-black uppercase tracking-widest transition-all cursor-pointer shadow-xs',
|
||||
secondaryButton:
|
||||
'bg-[#2b2b2b] hover:bg-[#383838] text-white border border-[#444444] px-4 py-2.5 text-xs font-bold uppercase tracking-wider transition-colors cursor-pointer',
|
||||
}}
|
||||
/>
|
||||
<CookieButton className="fixed bottom-4 left-4 z-40 bg-[#1f1f1f] hover:bg-[#FFED00] text-[#FFED00] hover:text-[#1f1f1f] border-2 border-[#FFED00] p-2.5 transition-all shadow-lg cursor-pointer" />
|
||||
<Analytics {...analytics} />
|
||||
</ConsentProvider>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
const locales = await getConfiguredLocales()
|
||||
return locales.map((locale) => ({ locale }))
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
@import "tailwindcss";
|
||||
@source "../../../node_modules/@intecion/ipal-kit/dist/**/*.js";
|
||||
|
||||
@theme {
|
||||
--color-karcher-yellow: #ffed00;
|
||||
--color-karcher-yellow-hover: #fae100;
|
||||
--color-karcher-dark: #1f1f1f;
|
||||
--color-karcher-black: #141414;
|
||||
--color-karcher-gray: #f4f4f4;
|
||||
--color-karcher-border: #e0e0e0;
|
||||
--color-karcher-text: #222222;
|
||||
--color-karcher-muted: #666666;
|
||||
}
|
||||
|
||||
:root {
|
||||
--ipal-primary: #ffed00;
|
||||
--ipal-primary-hover: #fae100;
|
||||
--ipal-radius: 0px;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
scroll-padding-top: 5.5rem;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
||||
background-color: #ffffff;
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, .font-karcher {
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
/* Card hover animation effects */
|
||||
.hover-lift {
|
||||
transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.3s cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
.hover-lift:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 12px 24px -10px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import type { Metadata } from 'next'
|
||||
import config from '@/payload.config'
|
||||
import { RootPage, generatePageMetadata } from '@payloadcms/next/views'
|
||||
import { importMap } from '../importMap'
|
||||
|
||||
type Args = {
|
||||
params: Promise<{
|
||||
segments: string[]
|
||||
}>
|
||||
searchParams: Promise<{
|
||||
[key: string]: string | string[]
|
||||
}>
|
||||
}
|
||||
|
||||
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
|
||||
generatePageMetadata({ config, params, searchParams })
|
||||
|
||||
const Page = ({ params, searchParams }: Args) =>
|
||||
RootPage({ config, params, searchParams, importMap })
|
||||
|
||||
export default Page
|
||||
@@ -0,0 +1,66 @@
|
||||
import { OverviewComponent as OverviewComponent_a8a977ebc872c5d5ea7ee689724c0860 } from '@payloadcms/plugin-seo/client'
|
||||
import { MetaTitleComponent as MetaTitleComponent_a8a977ebc872c5d5ea7ee689724c0860 } from '@payloadcms/plugin-seo/client'
|
||||
import { MetaDescriptionComponent as MetaDescriptionComponent_a8a977ebc872c5d5ea7ee689724c0860 } from '@payloadcms/plugin-seo/client'
|
||||
import { MetaImageComponent as MetaImageComponent_a8a977ebc872c5d5ea7ee689724c0860 } from '@payloadcms/plugin-seo/client'
|
||||
import { PreviewComponent as PreviewComponent_a8a977ebc872c5d5ea7ee689724c0860 } from '@payloadcms/plugin-seo/client'
|
||||
import { RscEntryLexicalCell as RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e } from '@payloadcms/richtext-lexical/rsc'
|
||||
import { RscEntryLexicalField as RscEntryLexicalField_44fe37237e0ebf4470c9990d8cb7b07e } from '@payloadcms/richtext-lexical/rsc'
|
||||
import { LexicalDiffComponent as LexicalDiffComponent_44fe37237e0ebf4470c9990d8cb7b07e } from '@payloadcms/richtext-lexical/rsc'
|
||||
import { InlineToolbarFeatureClient as InlineToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { HorizontalRuleFeatureClient as HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { UploadFeatureClient as UploadFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { BlockquoteFeatureClient as BlockquoteFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { RelationshipFeatureClient as RelationshipFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { LinkFeatureClient as LinkFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { ChecklistFeatureClient as ChecklistFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { OrderedListFeatureClient as OrderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { UnorderedListFeatureClient as UnorderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { IndentFeatureClient as IndentFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { AlignFeatureClient as AlignFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { HeadingFeatureClient as HeadingFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { ParagraphFeatureClient as ParagraphFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { InlineCodeFeatureClient as InlineCodeFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { SuperscriptFeatureClient as SuperscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { SubscriptFeatureClient as SubscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { StrikethroughFeatureClient as StrikethroughFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { UnderlineFeatureClient as UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { BoldFeatureClient as BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { ItalicFeatureClient as ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { MaskedField as MaskedField_630f031911beff97691b963f10a20a86 } from '@intecion/ipal-kit/client'
|
||||
import { TestEmailButton as TestEmailButton_630f031911beff97691b963f10a20a86 } from '@intecion/ipal-kit/client'
|
||||
import { CollectionCards as CollectionCards_f9c02e79a4aed9a3924487c0cd4cafb1 } from '@payloadcms/next/rsc'
|
||||
|
||||
/** @type import('payload').ImportMap */
|
||||
export const importMap = {
|
||||
"@payloadcms/plugin-seo/client#OverviewComponent": OverviewComponent_a8a977ebc872c5d5ea7ee689724c0860,
|
||||
"@payloadcms/plugin-seo/client#MetaTitleComponent": MetaTitleComponent_a8a977ebc872c5d5ea7ee689724c0860,
|
||||
"@payloadcms/plugin-seo/client#MetaDescriptionComponent": MetaDescriptionComponent_a8a977ebc872c5d5ea7ee689724c0860,
|
||||
"@payloadcms/plugin-seo/client#MetaImageComponent": MetaImageComponent_a8a977ebc872c5d5ea7ee689724c0860,
|
||||
"@payloadcms/plugin-seo/client#PreviewComponent": PreviewComponent_a8a977ebc872c5d5ea7ee689724c0860,
|
||||
"@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell": RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e,
|
||||
"@payloadcms/richtext-lexical/rsc#RscEntryLexicalField": RscEntryLexicalField_44fe37237e0ebf4470c9990d8cb7b07e,
|
||||
"@payloadcms/richtext-lexical/rsc#LexicalDiffComponent": LexicalDiffComponent_44fe37237e0ebf4470c9990d8cb7b07e,
|
||||
"@payloadcms/richtext-lexical/client#InlineToolbarFeatureClient": InlineToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#HorizontalRuleFeatureClient": HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#UploadFeatureClient": UploadFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#BlockquoteFeatureClient": BlockquoteFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#RelationshipFeatureClient": RelationshipFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#LinkFeatureClient": LinkFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#ChecklistFeatureClient": ChecklistFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#OrderedListFeatureClient": OrderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#UnorderedListFeatureClient": UnorderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#IndentFeatureClient": IndentFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#AlignFeatureClient": AlignFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#HeadingFeatureClient": HeadingFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#ParagraphFeatureClient": ParagraphFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#InlineCodeFeatureClient": InlineCodeFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#SuperscriptFeatureClient": SuperscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#SubscriptFeatureClient": SubscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#StrikethroughFeatureClient": StrikethroughFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#UnderlineFeatureClient": UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#BoldFeatureClient": BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#ItalicFeatureClient": ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@intecion/ipal-kit/client#MaskedField": MaskedField_630f031911beff97691b963f10a20a86,
|
||||
"@intecion/ipal-kit/client#TestEmailButton": TestEmailButton_630f031911beff97691b963f10a20a86,
|
||||
"@payloadcms/next/rsc#CollectionCards": CollectionCards_f9c02e79a4aed9a3924487c0cd4cafb1
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import config from '@/payload.config'
|
||||
import {
|
||||
REST_DELETE,
|
||||
REST_GET,
|
||||
REST_OPTIONS,
|
||||
REST_PATCH,
|
||||
REST_POST,
|
||||
REST_PUT,
|
||||
} from '@payloadcms/next/routes'
|
||||
|
||||
export const GET = REST_GET(config)
|
||||
export const POST = REST_POST(config)
|
||||
export const DELETE = REST_DELETE(config)
|
||||
export const PATCH = REST_PATCH(config)
|
||||
export const PUT = REST_PUT(config)
|
||||
export const OPTIONS = REST_OPTIONS(config)
|
||||
@@ -0,0 +1,27 @@
|
||||
import config from '@/payload.config'
|
||||
import '@payloadcms/next/css'
|
||||
import type { ServerFunctionClient } from 'payload'
|
||||
import { handleServerFunctions, RootLayout } from '@payloadcms/next/layouts'
|
||||
import React from 'react'
|
||||
import { importMap } from './admin/importMap'
|
||||
|
||||
type Args = {
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
const serverFunction: ServerFunctionClient = async function (args) {
|
||||
'use server'
|
||||
return handleServerFunctions({
|
||||
...args,
|
||||
config,
|
||||
importMap,
|
||||
})
|
||||
}
|
||||
|
||||
const Layout = ({ children }: Args) => (
|
||||
<RootLayout config={config} importMap={importMap} serverFunction={serverFunction}>
|
||||
{children}
|
||||
</RootLayout>
|
||||
)
|
||||
|
||||
export default Layout
|
||||
Reference in New Issue
Block a user