diff --git a/next.config.js b/next.config.js index bcfc4c1..2e2e655 100644 --- a/next.config.js +++ b/next.config.js @@ -18,6 +18,10 @@ const nextConfig = { protocol: url.protocol.replace(':', ''), } }), + { + protocol: 'https', + hostname: 'images.unsplash.com', + }, ], }, reactStrictMode: true, @@ -25,3 +29,4 @@ const nextConfig = { } export default withPayload(nextConfig, { devBundleServerPackages: false }) + diff --git a/package-lock.json b/package-lock.json index d192f99..35b8975 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "MIT", "dependencies": { + "@heroicons/react": "^2.2.0", "@payloadcms/admin-bar": "3.31.0", "@payloadcms/db-postgres": "3.31.0", "@payloadcms/live-preview-react": "3.31.0", @@ -28,6 +29,7 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cross-env": "^7.0.3", + "framer-motion": "^12.6.3", "geist": "^1.3.0", "graphql": "^16.8.2", "lucide-react": "^0.378.0", @@ -2494,6 +2496,15 @@ "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", "license": "MIT" }, + "node_modules/@heroicons/react": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.2.0.tgz", + "integrity": "sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==", + "license": "MIT", + "peerDependencies": { + "react": ">= 16 || ^19.0.0-rc" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -8521,6 +8532,33 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/framer-motion": { + "version": "12.6.3", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.6.3.tgz", + "integrity": "sha512-2hsqknz23aloK85bzMc9nSR2/JP+fValQ459ZTVElFQ0xgwR2YqNjYSuDZdFBPOwVCt4Q9jgyTt6hg6sVOALzw==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.6.3", + "motion-utils": "^12.6.3", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -10612,6 +10650,21 @@ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "license": "MIT" }, + "node_modules/motion-dom": { + "version": "12.6.3", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.6.3.tgz", + "integrity": "sha512-gRY08RjcnzgFYLemUZ1lo/e9RkBxR+6d4BRvoeZDSeArG4XQXERSPapKl3LNQRu22Sndjf1h+iavgY0O4NrYqA==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.6.3" + } + }, + "node_modules/motion-utils": { + "version": "12.6.3", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.6.3.tgz", + "integrity": "sha512-R/b3Ia2VxtTNZ4LTEO5pKYau1OUNHOuUfxuP0WFCTDYdHkeTBR9UtxR1cc8mDmKr8PEhmmfnTKGz3rSMjNRoRg==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", diff --git a/package.json b/package.json index 39a2766..020caab 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,9 @@ "start": "cross-env NODE_OPTIONS=--no-deprecation next start" }, "dependencies": { + "@heroicons/react": "^2.2.0", "@payloadcms/admin-bar": "3.31.0", + "@payloadcms/db-postgres": "3.31.0", "@payloadcms/live-preview-react": "3.31.0", "@payloadcms/next": "3.31.0", "@payloadcms/payload-cloud": "3.31.0", @@ -37,6 +39,7 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cross-env": "^7.0.3", + "framer-motion": "^12.6.3", "geist": "^1.3.0", "graphql": "^16.8.2", "lucide-react": "^0.378.0", @@ -49,8 +52,7 @@ "react-hook-form": "7.45.4", "sharp": "0.32.6", "tailwind-merge": "^2.3.0", - "tailwindcss-animate": "^1.0.7", - "@payloadcms/db-postgres": "3.31.0" + "tailwindcss-animate": "^1.0.7" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", diff --git a/public/icons/docker-icon.svg b/public/icons/docker-icon.svg new file mode 100644 index 0000000..6808eae --- /dev/null +++ b/public/icons/docker-icon.svg @@ -0,0 +1,7 @@ + + diff --git a/public/icons/git-icon.svg b/public/icons/git-icon.svg new file mode 100644 index 0000000..5785d52 --- /dev/null +++ b/public/icons/git-icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/icons/go-icon.svg b/public/icons/go-icon.svg new file mode 100644 index 0000000..823e818 --- /dev/null +++ b/public/icons/go-icon.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/public/icons/linux-icon.svg b/public/icons/linux-icon.svg new file mode 100644 index 0000000..e978c91 --- /dev/null +++ b/public/icons/linux-icon.svg @@ -0,0 +1,2 @@ + + diff --git a/public/icons/nextjs-icon.svg b/public/icons/nextjs-icon.svg new file mode 100644 index 0000000..9c33956 --- /dev/null +++ b/public/icons/nextjs-icon.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/public/icons/postgres-icon.svg b/public/icons/postgres-icon.svg new file mode 100644 index 0000000..f457799 --- /dev/null +++ b/public/icons/postgres-icon.svg @@ -0,0 +1,2 @@ + + diff --git a/public/images/map.png b/public/images/map.png new file mode 100644 index 0000000..8e477c8 Binary files /dev/null and b/public/images/map.png differ diff --git a/src/Header/Component.client.tsx b/src/Header/Component.client.tsx index a4bd658..1e438c9 100644 --- a/src/Header/Component.client.tsx +++ b/src/Header/Component.client.tsx @@ -8,6 +8,7 @@ import type { Header } from '@/payload-types' import { Logo } from '@/components/Logo/Logo' import { HeaderNav } from './Nav' +import { ChevronRightIcon } from 'lucide-react' interface HeaderClientProps { data: Header @@ -32,9 +33,22 @@ export const HeaderClient: React.FC = ({ data }) => { return ( - - - + + + + + + Beitzah Technology Solutions + + See our FAQ to learn more about our process. + + + + + diff --git a/src/app/(frontend)/[slug]/page.tsx b/src/app/(frontend)/[slug]/page.tsx index 7a8d103..16e441b 100644 --- a/src/app/(frontend)/[slug]/page.tsx +++ b/src/app/(frontend)/[slug]/page.tsx @@ -5,7 +5,6 @@ import configPromise from '@payload-config' import { getPayload, type RequiredDataFromCollectionSlug } from 'payload' import { draftMode } from 'next/headers' import React, { cache } from 'react' -import { homeStatic } from '@/endpoints/seed/home-static' import { RenderBlocks } from '@/blocks/RenderBlocks' import { RenderHero } from '@/heros/RenderHero' @@ -48,16 +47,9 @@ export default async function Page({ params: paramsPromise }: Args) { const { slug = 'home' } = await paramsPromise const url = '/' + slug - let page: RequiredDataFromCollectionSlug<'pages'> | null - - page = await queryPageBySlug({ + const page: RequiredDataFromCollectionSlug<'pages'> | null = await queryPageBySlug({ slug, - }) - - // Remove this code once your website is seeded - if (!page && slug === 'home') { - page = homeStatic - } + }) || null if (!page) { return diff --git a/src/app/(frontend)/globals.css b/src/app/(frontend)/globals.css index 2c785c1..21bf493 100644 --- a/src/app/(frontend)/globals.css +++ b/src/app/(frontend)/globals.css @@ -50,7 +50,7 @@ } [data-theme='dark'] { - --background: 0 0% 0%; + --background: 215 28% 10%; --foreground: 210 40% 98%; --card: 0 0% 4%; diff --git a/src/app/(payload)/admin/importMap.js b/src/app/(payload)/admin/importMap.js index 896ea84..da56321 100644 --- a/src/app/(payload)/admin/importMap.js +++ b/src/app/(payload)/admin/importMap.js @@ -7,14 +7,26 @@ import { ParagraphFeatureClient as ParagraphFeatureClient_e70f5e05f09f93e00b997e 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 { AlignFeatureClient as AlignFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client' +import { BlockquoteFeatureClient as BlockquoteFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client' +import { UnorderedListFeatureClient as UnorderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client' import { LinkFeatureClient as LinkFeatureClient_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 { RelationshipFeatureClient as RelationshipFeatureClient_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 { IndentFeatureClient as IndentFeatureClient_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 { OverviewComponent as OverviewComponent_a8a977ebc872c5d5ea7ee689724c0860 } from '@payloadcms/plugin-seo/client' import { MetaTitleComponent as MetaTitleComponent_a8a977ebc872c5d5ea7ee689724c0860 } from '@payloadcms/plugin-seo/client' import { MetaImageComponent as MetaImageComponent_a8a977ebc872c5d5ea7ee689724c0860 } from '@payloadcms/plugin-seo/client' import { MetaDescriptionComponent as MetaDescriptionComponent_a8a977ebc872c5d5ea7ee689724c0860 } from '@payloadcms/plugin-seo/client' import { PreviewComponent as PreviewComponent_a8a977ebc872c5d5ea7ee689724c0860 } from '@payloadcms/plugin-seo/client' import { SlugComponent as SlugComponent_92cc057d0a2abb4f6cf0307edf59f986 } from '@/fields/slug/SlugComponent' -import { HorizontalRuleFeatureClient as HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client' import { BlocksFeatureClient as BlocksFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client' import { LinkToDoc as LinkToDoc_aead06e4cbf6b2620c5c51c9ab283634 } from '@payloadcms/plugin-search/client' import { ReindexButton as ReindexButton_aead06e4cbf6b2620c5c51c9ab283634 } from '@payloadcms/plugin-search/client' @@ -24,45 +36,40 @@ import { default as default_1a7510af427896d367a49dbf838d2de6 } from '@/component import { default as default_8a7ab0eb7ab5c511aba12e68480bfe5e } from '@/components/BeforeLogin' export const importMap = { - '@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell': - RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e, - '@payloadcms/richtext-lexical/rsc#RscEntryLexicalField': - RscEntryLexicalField_44fe37237e0ebf4470c9990d8cb7b07e, - '@payloadcms/richtext-lexical/client#InlineToolbarFeatureClient': - InlineToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - '@payloadcms/richtext-lexical/client#FixedToolbarFeatureClient': - FixedToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - '@payloadcms/richtext-lexical/client#HeadingFeatureClient': - HeadingFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - '@payloadcms/richtext-lexical/client#ParagraphFeatureClient': - ParagraphFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - '@payloadcms/richtext-lexical/client#UnderlineFeatureClient': - UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - '@payloadcms/richtext-lexical/client#BoldFeatureClient': - BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - '@payloadcms/richtext-lexical/client#ItalicFeatureClient': - ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - '@payloadcms/richtext-lexical/client#LinkFeatureClient': - LinkFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - '@payloadcms/plugin-seo/client#OverviewComponent': - OverviewComponent_a8a977ebc872c5d5ea7ee689724c0860, - '@payloadcms/plugin-seo/client#MetaTitleComponent': - MetaTitleComponent_a8a977ebc872c5d5ea7ee689724c0860, - '@payloadcms/plugin-seo/client#MetaImageComponent': - MetaImageComponent_a8a977ebc872c5d5ea7ee689724c0860, - '@payloadcms/plugin-seo/client#MetaDescriptionComponent': - MetaDescriptionComponent_a8a977ebc872c5d5ea7ee689724c0860, - '@payloadcms/plugin-seo/client#PreviewComponent': - PreviewComponent_a8a977ebc872c5d5ea7ee689724c0860, - '@/fields/slug/SlugComponent#SlugComponent': SlugComponent_92cc057d0a2abb4f6cf0307edf59f986, - '@payloadcms/richtext-lexical/client#HorizontalRuleFeatureClient': - HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - '@payloadcms/richtext-lexical/client#BlocksFeatureClient': - BlocksFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - '@payloadcms/plugin-search/client#LinkToDoc': LinkToDoc_aead06e4cbf6b2620c5c51c9ab283634, - '@payloadcms/plugin-search/client#ReindexButton': ReindexButton_aead06e4cbf6b2620c5c51c9ab283634, - '@/Header/RowLabel#RowLabel': RowLabel_ec255a65fa6fa8d1faeb09cf35284224, - '@/Footer/RowLabel#RowLabel': RowLabel_1f6ff6ff633e3695d348f4f3c58f1466, - '@/components/BeforeDashboard#default': default_1a7510af427896d367a49dbf838d2de6, - '@/components/BeforeLogin#default': default_8a7ab0eb7ab5c511aba12e68480bfe5e, + "@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell": RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e, + "@payloadcms/richtext-lexical/rsc#RscEntryLexicalField": RscEntryLexicalField_44fe37237e0ebf4470c9990d8cb7b07e, + "@payloadcms/richtext-lexical/client#InlineToolbarFeatureClient": InlineToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + "@payloadcms/richtext-lexical/client#FixedToolbarFeatureClient": FixedToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + "@payloadcms/richtext-lexical/client#HeadingFeatureClient": HeadingFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + "@payloadcms/richtext-lexical/client#ParagraphFeatureClient": ParagraphFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + "@payloadcms/richtext-lexical/client#UnderlineFeatureClient": UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + "@payloadcms/richtext-lexical/client#BoldFeatureClient": BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + "@payloadcms/richtext-lexical/client#ItalicFeatureClient": ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + "@payloadcms/richtext-lexical/client#AlignFeatureClient": AlignFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + "@payloadcms/richtext-lexical/client#BlockquoteFeatureClient": BlockquoteFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + "@payloadcms/richtext-lexical/client#UnorderedListFeatureClient": UnorderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + "@payloadcms/richtext-lexical/client#LinkFeatureClient": LinkFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + "@payloadcms/richtext-lexical/client#HorizontalRuleFeatureClient": HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + "@payloadcms/richtext-lexical/client#UploadFeatureClient": UploadFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + "@payloadcms/richtext-lexical/client#RelationshipFeatureClient": RelationshipFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + "@payloadcms/richtext-lexical/client#ChecklistFeatureClient": ChecklistFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + "@payloadcms/richtext-lexical/client#OrderedListFeatureClient": OrderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + "@payloadcms/richtext-lexical/client#IndentFeatureClient": IndentFeatureClient_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/plugin-seo/client#OverviewComponent": OverviewComponent_a8a977ebc872c5d5ea7ee689724c0860, + "@payloadcms/plugin-seo/client#MetaTitleComponent": MetaTitleComponent_a8a977ebc872c5d5ea7ee689724c0860, + "@payloadcms/plugin-seo/client#MetaImageComponent": MetaImageComponent_a8a977ebc872c5d5ea7ee689724c0860, + "@payloadcms/plugin-seo/client#MetaDescriptionComponent": MetaDescriptionComponent_a8a977ebc872c5d5ea7ee689724c0860, + "@payloadcms/plugin-seo/client#PreviewComponent": PreviewComponent_a8a977ebc872c5d5ea7ee689724c0860, + "@/fields/slug/SlugComponent#SlugComponent": SlugComponent_92cc057d0a2abb4f6cf0307edf59f986, + "@payloadcms/richtext-lexical/client#BlocksFeatureClient": BlocksFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + "@payloadcms/plugin-search/client#LinkToDoc": LinkToDoc_aead06e4cbf6b2620c5c51c9ab283634, + "@payloadcms/plugin-search/client#ReindexButton": ReindexButton_aead06e4cbf6b2620c5c51c9ab283634, + "@/Header/RowLabel#RowLabel": RowLabel_ec255a65fa6fa8d1faeb09cf35284224, + "@/Footer/RowLabel#RowLabel": RowLabel_1f6ff6ff633e3695d348f4f3c58f1466, + "@/components/BeforeDashboard#default": default_1a7510af427896d367a49dbf838d2de6, + "@/components/BeforeLogin#default": default_8a7ab0eb7ab5c511aba12e68480bfe5e } diff --git a/src/blocks/ArticleBlock/Component.tsx b/src/blocks/ArticleBlock/Component.tsx new file mode 100644 index 0000000..b249b94 --- /dev/null +++ b/src/blocks/ArticleBlock/Component.tsx @@ -0,0 +1,72 @@ +import { Heading, Subheading } from '@/components/Headings/Headings' + +import type { ArticleBlock as ArticleBlockProps } from '@/payload-types' +import { Container } from '@/components/Container/Container' +import RichText from '@/components/RichText' +import { cn } from '@/utilities/ui' +import { CMSLink } from '@/components/Link' +import Image from 'next/image' +import clsx from 'clsx' + +const colsSpanClasses = { + full: '12', + half: '6', + oneThird: '4', + twoThirds: '8', +} + +export const ArticleBlock: React.FC = (props) => { + const { heading, subheading, brief, columns } = props + return ( + + {subheading} + + {heading} + + + {brief && } + + + {columns && + columns.length > 0 && + columns.map((col) => { + const { enableLink, link, richText, size, imageUrls } = col + + return ( + + {richText && imageUrls?.length && ( + + + + + + + + {imageUrls?.map((image, i) => ( + + + + ))} + + + + )} + + {enableLink && } + + ) + })} + + ) +} diff --git a/src/blocks/ArticleBlock/config.ts b/src/blocks/ArticleBlock/config.ts new file mode 100644 index 0000000..5c74010 --- /dev/null +++ b/src/blocks/ArticleBlock/config.ts @@ -0,0 +1,118 @@ +import { FixedToolbarFeature, HeadingFeature, InlineToolbarFeature, lexicalEditor, UnorderedListFeature } from '@payloadcms/richtext-lexical' +import type { Block, Field } from 'payload' + +import { link } from '@/fields/link' + +const imageUrlFields: Field[] = [ + { + name: 'url', + type: 'text', + }, + { + name: 'alt', + type: 'text', + }, + { + name: 'width', + type: 'number', + }, + { + name: 'height', + type: 'number', + } +] + +const columnFields: Field[] = [ + { + name: 'size', + type: 'select', + defaultValue: 'oneThird', + options: [ + { + label: 'One Third', + value: 'oneThird', + }, + { + label: 'Half', + value: 'half', + }, + { + label: 'Two Thirds', + value: 'twoThirds', + }, + { + label: 'Full', + value: 'full', + }, + ], + }, + { + name: 'richText', + type: 'richText', + editor: lexicalEditor({ + features: ({ defaultFeatures }) => { + return [ + ...defaultFeatures, + FixedToolbarFeature(), + InlineToolbarFeature(), + ] + }, + }), + label: false, + }, + { + name: 'enableLink', + type: 'checkbox', + }, + link({ + overrides: { + admin: { + condition: (_data, siblingData) => { + return Boolean(siblingData?.enableLink) + }, + }, + }, + }), + { + name: 'imageUrls', + type: 'array', + fields: imageUrlFields, + } +] + +export const ArticleBlock: Block = { + slug: 'article', + interfaceName: 'ArticleBlock', + fields: [ + { + name: "heading", + type: "text" + }, + { + name: "subheading", + type: "text" + }, + { + name: 'brief', + type: 'richText', + editor: lexicalEditor({ + features: ({ defaultFeatures }) => { + return [ + ...defaultFeatures, + FixedToolbarFeature(), + InlineToolbarFeature(), + ] + }, + }), + label: false, + }, + { + name: 'columns', + type: 'array', + admin: { + initCollapsed: true, + }, + fields: columnFields, + }, + ], +} diff --git a/src/blocks/Bento/Component.tsx b/src/blocks/Bento/Component.tsx new file mode 100644 index 0000000..738d26c --- /dev/null +++ b/src/blocks/Bento/Component.tsx @@ -0,0 +1,31 @@ +import { BentoCard } from '@/components/BentoCard/BentoCard' +import { Heading, Subheading } from '@/components/Headings/Headings' + +import type { BentoBlock as BentoBlockProps } from '@/payload-types' +import { Container } from '@/components/Container/Container' + +export const BentoBlock: React.FC = (props) => { + const { heading, subheading, graphics } = props + return ( + + {subheading} + + {heading} + + + + {graphics?.map((c) => ( + + ) + )} + + + ) +} diff --git a/src/blocks/Bento/config.ts b/src/blocks/Bento/config.ts new file mode 100644 index 0000000..750a698 --- /dev/null +++ b/src/blocks/Bento/config.ts @@ -0,0 +1,73 @@ +import { Keyboard } from '@/components/Graphics/Keyboard' +import { LogoCluster } from '@/components/Graphics/LogoCluster' +import { Map as MapGraphic } from '@/components/Graphics/Map' +import type { Block, Field } from 'payload' + +export const Graphics = new Map([ + ["animatedMapPins", MapGraphic], + ["animatedLogoCluster", LogoCluster], + ["animatedKeyboard", Keyboard], +]) + + + +const bentoSectionFields: Field[] = [ + { + name: 'graphic', + type: 'select', + options: [ + { + label: 'Animated Map with Pins', + value: 'animatedMapPins', + }, + { + label: 'Animated Logo Cluster', + value: 'animatedLogoCluster', + }, + { + label: 'Animated Keybaord', + value: 'animatedKeyboard', + }, + ], + }, + { + name: 'eyebrow', + type: 'text', + }, + { + name: 'title', + type: 'text', + }, + { + name: 'description', + type: 'text', + }, + { + name: 'className', + type: 'text', + }, + +] + +export const BentoBlock: Block = { + slug: 'bento', + interfaceName: 'BentoBlock', + fields: [ + { + name: "heading", + type: "text" + }, + { + name: "subheading", + type: "text" + }, + { + name: 'graphics', + type: 'array', + admin: { + initCollapsed: true, + }, + fields: bentoSectionFields, + }, + ], +} diff --git a/src/blocks/CallToAction/Component.tsx b/src/blocks/CallToAction/Component.tsx index 6b3771c..3316113 100644 --- a/src/blocks/CallToAction/Component.tsx +++ b/src/blocks/CallToAction/Component.tsx @@ -8,11 +8,11 @@ import { CMSLink } from '@/components/Link' export const CallToActionBlock: React.FC = ({ links, richText }) => { return ( - - - {richText && } + + + {richText && } - + {(links || []).map(({ link }, i) => { return })} diff --git a/src/blocks/Content/Component.tsx b/src/blocks/Content/Component.tsx index 2c2550b..7e11f08 100644 --- a/src/blocks/Content/Component.tsx +++ b/src/blocks/Content/Component.tsx @@ -5,9 +5,10 @@ import RichText from '@/components/RichText' import type { ContentBlock as ContentBlockProps } from '@/payload-types' import { CMSLink } from '../../components/Link' +import Image from 'next/image' export const ContentBlock: React.FC = (props) => { - const { columns } = props + const { columns, isFullscreen, backgroundImage } = props const colsSpanClasses = { full: '12', @@ -16,9 +17,26 @@ export const ContentBlock: React.FC = (props) => { twoThirds: '8', } + console.log(isFullscreen, backgroundImage) + return ( - - + + + {!!backgroundImage && + } + {columns && columns.length > 0 && columns.map((col, index) => { diff --git a/src/blocks/Content/config.ts b/src/blocks/Content/config.ts index 5c2fb07..603f0a6 100644 --- a/src/blocks/Content/config.ts +++ b/src/blocks/Content/config.ts @@ -40,7 +40,7 @@ const columnFields: Field[] = [ features: ({ rootFeatures }) => { return [ ...rootFeatures, - HeadingFeature({ enabledHeadingSizes: ['h2', 'h3', 'h4'] }), + HeadingFeature({ enabledHeadingSizes: ['h1', 'h2', 'h3', 'h4'] }), FixedToolbarFeature(), InlineToolbarFeature(), ] @@ -75,5 +75,13 @@ export const Content: Block = { }, fields: columnFields, }, + { + name: 'backgroundImage', + type: 'text', + }, + { + name: 'isFullscreen', + type: 'checkbox', + }, ], } diff --git a/src/blocks/RenderBlocks.tsx b/src/blocks/RenderBlocks.tsx index c84634a..56e4e26 100644 --- a/src/blocks/RenderBlocks.tsx +++ b/src/blocks/RenderBlocks.tsx @@ -7,6 +7,8 @@ import { CallToActionBlock } from '@/blocks/CallToAction/Component' import { ContentBlock } from '@/blocks/Content/Component' import { FormBlock } from '@/blocks/Form/Component' import { MediaBlock } from '@/blocks/MediaBlock/Component' +import { BentoBlock } from '@/blocks/Bento/Component' +import { ArticleBlock } from './ArticleBlock/Component' const blockComponents = { archive: ArchiveBlock, @@ -14,6 +16,8 @@ const blockComponents = { cta: CallToActionBlock, formBlock: FormBlock, mediaBlock: MediaBlock, + bento: BentoBlock, + article: ArticleBlock, } export const RenderBlocks: React.FC<{ diff --git a/src/collections/Pages/index.ts b/src/collections/Pages/index.ts index c81ffa8..d94104a 100644 --- a/src/collections/Pages/index.ts +++ b/src/collections/Pages/index.ts @@ -7,6 +7,7 @@ import { CallToAction } from '../../blocks/CallToAction/config' import { Content } from '../../blocks/Content/config' import { FormBlock } from '../../blocks/Form/config' import { MediaBlock } from '../../blocks/MediaBlock/config' +import { BentoBlock } from '@/blocks/Bento/config' import { hero } from '@/heros/config' import { slugField } from '@/fields/slug' import { populatePublishedAt } from '../../hooks/populatePublishedAt' @@ -20,6 +21,7 @@ import { OverviewField, PreviewField, } from '@payloadcms/plugin-seo/fields' +import { ArticleBlock } from '@/blocks/ArticleBlock/config' export const Pages: CollectionConfig<'pages'> = { slug: 'pages', @@ -75,7 +77,7 @@ export const Pages: CollectionConfig<'pages'> = { { name: 'layout', type: 'blocks', - blocks: [CallToAction, Content, MediaBlock, Archive, FormBlock], + blocks: [CallToAction, Content, MediaBlock, Archive, FormBlock, BentoBlock, ArticleBlock], required: true, admin: { initCollapsed: true, diff --git a/src/collections/Posts/hooks/populateAuthors.ts b/src/collections/Posts/hooks/populateAuthors.ts index 40b4fe5..67e0ead 100644 --- a/src/collections/Posts/hooks/populateAuthors.ts +++ b/src/collections/Posts/hooks/populateAuthors.ts @@ -5,7 +5,7 @@ import { User } from 'src/payload-types' // This means that we need to populate the authors manually here to protect user privacy // GraphQL will not return mutated user data that differs from the underlying schema // So we use an alternative `populatedAuthors` field to populate the user data, hidden from the admin UI -export const populateAuthors: CollectionAfterReadHook = async ({ doc, req, req: { payload } }) => { +export const populateAuthors: CollectionAfterReadHook = async ({ doc, req: { payload } }) => { if (doc?.authors && doc?.authors?.length > 0) { const authorDocs: User[] = [] diff --git a/src/components/BentoCard/BentoCard.tsx b/src/components/BentoCard/BentoCard.tsx new file mode 100644 index 0000000..ecd13e5 --- /dev/null +++ b/src/components/BentoCard/BentoCard.tsx @@ -0,0 +1,68 @@ +'use client' + +import { clsx } from 'clsx' +import { motion } from 'framer-motion' +import { Subheading } from '../Headings/Headings' +import { Graphics } from '@/blocks/Bento/config' + +const getGraphicElementFromName = (graphicName?: string) => { + const graphicElement = Graphics.get(graphicName || '') + if (graphicElement) return graphicElement() +} + +export function BentoCard({ + dark = false, + className = '', + eyebrow, + title, + description, + graphic, + fade = [], +}: { + dark?: boolean + className?: string + eyebrow: React.ReactNode + title: React.ReactNode + description: React.ReactNode + graphic: string + fade?: ('top' | 'bottom')[] +}) { + return ( + + + { + getGraphicElementFromName(graphic) + } + {fade.includes('top') && ( + + )} + {fade.includes('bottom') && ( + + )} + + + + {eyebrow} + + + {title} + + + {description} + + + + ) +} diff --git a/src/components/Container/Container.tsx b/src/components/Container/Container.tsx new file mode 100644 index 0000000..c39cad5 --- /dev/null +++ b/src/components/Container/Container.tsx @@ -0,0 +1,15 @@ +import { clsx } from 'clsx' + +export function Container({ + className, + children, +}: { + className?: string + children: React.ReactNode +}) { + return ( + + {children} + + ) +} diff --git a/src/components/Graphics/Keyboard.tsx b/src/components/Graphics/Keyboard.tsx new file mode 100644 index 0000000..b606f94 --- /dev/null +++ b/src/components/Graphics/Keyboard.tsx @@ -0,0 +1,1053 @@ +'use client' + +import { clsx } from 'clsx' +import { motion } from 'framer-motion' +import { createContext, useContext } from 'react' + +const KeyboardContext = createContext<{ highlighted: string[] }>({ + highlighted: [], +}) + +function Row(props: { children: React.ReactNode }) { + return +} + +function Key({ + name, + width = 36, + className, + children, +}: { + name: string + width?: number + className?: string + children?: React.ReactNode +}) { + const { highlighted } = useContext(KeyboardContext) + + return ( + + {children} + + ) +} + +function KeyGroup(props: { children: React.ReactNode }) { + return ( + + ) +} + +function EscapeKey() { + return ( + + + + + + ) +} + +function F1Key() { + return ( + + + + + + + + + ) +} + +function F2Key() { + return ( + + + + + + + + + ) +} + +function F3Key() { + return ( + + + + + + + + + ) +} + +function F4Key() { + return ( + + + + + + + + + ) +} + +function F5Key() { + return ( + + + + + + + + + ) +} + +function F6Key() { + return ( + + + + + + + + + ) +} + +function F7Key() { + return ( + + + + + + + + + ) +} + +function F8Key() { + return ( + + + + + + + + + ) +} + +function F9Key() { + return ( + + + + + + + + + ) +} + +function F10Key() { + return ( + + + + + + + + + ) +} + +function F11Key() { + return ( + + + + + + + + + ) +} + +function F12Key() { + return ( + + + + + + + + + ) +} + +function LockKey() { + return ( + + + + + + ) +} + +function BacktickKey() { + return ( + + + + + + + + + ) +} + +function OneKey() { + return ( + + + + + + + + + ) +} + +function TwoKey() { + return ( + + + + + + + + + ) +} + +function ThreeKey() { + return ( + + + + + + + + + ) +} + +function FourKey() { + return ( + + + + + + + + + ) +} + +function FiveKey() { + return ( + + + + + + + + + ) +} + +function SixKey() { + return ( + + + + + + + + + ) +} + +function SevenKey() { + return ( + + + + + + + + + ) +} + +function EightKey() { + return ( + + + + + + + + + ) +} + +function NineKey() { + return ( + + + + + + + + + ) +} + +function ZeroKey() { + return ( + + + + + + + + + ) +} + +function DashKey() { + return ( + + + + + + + + + ) +} + +function EqualsKey() { + return ( + + + + + + + + + ) +} + +function DeleteKey() { + return ( + + + + + + ) +} + +function TabKey() { + return ( + + + + + + ) +} + +function QKey() { + return ( + + + + + + ) +} + +function WKey() { + return ( + + + + + + ) +} + +function EKey() { + return ( + + + + + + ) +} + +function RKey() { + return ( + + + + + + ) +} + +function TKey() { + return ( + + + + + + ) +} + +function YKey() { + return ( + + + + + + ) +} + +function UKey() { + return ( + + + + + + ) +} + +function IKey() { + return ( + + + + + + ) +} + +function OKey() { + return ( + + + + + + ) +} + +function PKey() { + return ( + + + + + + ) +} + +function LeftSquareBracketKey() { + return ( + + + + + + + + + ) +} + +function RightSquareBracketKey() { + return ( + + + + + + + + + ) +} + +function BackSlashKey() { + return ( + + + + + + + + + ) +} + +function CapsLockKey() { + return ( + + + + + + + + + ) +} + +function AKey() { + return ( + + + + + + ) +} + +function SKey() { + return ( + + + + + + ) +} + +function DKey() { + return ( + + + + + + ) +} + +function FKey() { + return ( + + + + + + ) +} + +function GKey() { + return ( + + + + + + ) +} + +function HKey() { + return ( + + + + + + ) +} + +function JKey() { + return ( + + + + + + ) +} + +function KKey() { + return ( + + + + + + ) +} + +function LKey() { + return ( + + + + + + ) +} + +function SemicolonKey() { + return ( + + + + + + + + + ) +} + +function SingleQuoteKey() { + return ( + + + + + + + + + ) +} + +function ReturnKey() { + return ( + + + + + + ) +} + +function ShiftKey({ position }: { position: 'Left' | 'Right' }) { + return ( + + + + + + ) +} + +function ZKey() { + return ( + + + + + + ) +} + +function XKey() { + return ( + + + + + + ) +} + +function CKey() { + return ( + + + + + + ) +} + +function VKey() { + return ( + + + + + + ) +} + +function BKey() { + return ( + + + + + + ) +} + +function NKey() { + return ( + + + + + + ) +} + +function MKey() { + return ( + + + + + + ) +} + +function CommaKey() { + return ( + + + + + + + + + ) +} + +function PeriodKey() { + return ( + + + + + + + + + ) +} + +function ForwardSlashKey() { + return ( + + + + + + + + + ) +} + +function FunctionKey() { + return ( + + + + + + + + + ) +} + +function ControlKey() { + return ( + + + + + + + + + ) +} + +function OptionKey({ position }: { position: 'Left' | 'Right' }) { + return ( + + + + + + + + + ) +} + +function CommandKey({ position }: { position: 'Left' | 'Right' }) { + return ( + + + + + + + + + ) +} + +function SpaceKey() { + return +} + +function LeftKey() { + return ( + + + + + + ) +} + +function UpKey() { + return ( + + + + + + ) +} + +function DownKey() { + return ( + + + + + + ) +} + +function RightKey() { + return ( + + + + + + ) +} + +export function Keyboard() { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/src/components/Graphics/LogoCluster.tsx b/src/components/Graphics/LogoCluster.tsx new file mode 100644 index 0000000..59454b4 --- /dev/null +++ b/src/components/Graphics/LogoCluster.tsx @@ -0,0 +1,135 @@ +'use client' + +import { clsx } from 'clsx' +import { motion } from 'framer-motion' +import { MovingMark } from './Mark' + +function Circle({ size, delay, opacity }: { size: number; delay: number; opacity: string }) { + return ( + + ) +} + +function Circles() { + return ( + + + + + + + + ) +} + +function MainLogo() { + return ( + + + + ) +} + +function Logo({ + src, + left, + top, + hover, +}: { + src: string + left: number + top: number + hover: { x: number; y: number; rotate: number; delay: number } +}) { + return ( + + ) +} + +export function LogoCluster() { + return ( + + + + + + + + + + + + + ) +} diff --git a/src/components/Graphics/Map.tsx b/src/components/Graphics/Map.tsx new file mode 100644 index 0000000..e6845cf --- /dev/null +++ b/src/components/Graphics/Map.tsx @@ -0,0 +1,121 @@ +'use client' + +import { + ServerStackIcon, + CircleStackIcon, + UserGroupIcon, + MagnifyingGlassIcon, + BuildingStorefrontIcon, +} from '@heroicons/react/24/solid' +import { motion } from 'framer-motion' +import Image from 'next/image' +import { ForwardRefExoticComponent, RefAttributes, SVGProps } from 'react' + +type HeroIcon = ForwardRefExoticComponent< + Omit, 'ref'> & { + title?: string | undefined + titleId?: string | undefined + } & RefAttributes +> + +type IconProps = { + icon: HeroIcon + className?: string +} + +function IconWrapper({ icon: Icon, className }: IconProps) { + return +} + +function Marker({ + src, + icon, + iconClassNames, + top, + offset, + delay, +}: { + src?: string + icon?: HeroIcon + iconClassNames?: string + top: number + offset: number + delay: number +}) { + return ( + + + + + + {src && !icon && ( + + )} + {!src && icon && ( + + )} + + ) +} + +export function Map() { + return ( + + + + + + + + + + + ) +} diff --git a/src/components/Graphics/Mark.tsx b/src/components/Graphics/Mark.tsx new file mode 100644 index 0000000..63a30f9 --- /dev/null +++ b/src/components/Graphics/Mark.tsx @@ -0,0 +1,111 @@ +'use client' + +import { clsx } from 'clsx' +import { motion } from 'framer-motion' + +export function MovingMark({ className }: { className?: string }) { + const transition = { + duration: 0.5, + ease: 'easeInOut', + } + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} + +export function Mark({ className }: { className?: string }) { + return ( + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/src/components/Headings/Headings.tsx b/src/components/Headings/Headings.tsx new file mode 100644 index 0000000..6376421 --- /dev/null +++ b/src/components/Headings/Headings.tsx @@ -0,0 +1,41 @@ +import clsx from "clsx" + +export type HeadingProps = { + as?: 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' + dark?: boolean +} & React.ComponentPropsWithoutRef<'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'> + +export function Heading({ className, as: Element = 'h2', dark = false, ...props }: HeadingProps) { + return ( + + ) +} + +export function Subheading({ + className, + as: Element = 'h2', + dark = false, + ...props +}: HeadingProps) { + return ( + + ) +} + +export function Lead({ className, ...props }: React.ComponentPropsWithoutRef<'p'>) { + return +} diff --git a/src/components/Link/index.tsx b/src/components/Link/index.tsx index 0cf220e..3e3c061 100644 --- a/src/components/Link/index.tsx +++ b/src/components/Link/index.tsx @@ -18,6 +18,8 @@ type CMSLinkType = { size?: ButtonProps['size'] | null type?: 'custom' | 'reference' | null url?: string | null + backgroundColor?: string | null + textColor?: string | null } export const CMSLink: React.FC = (props) => { @@ -31,6 +33,8 @@ export const CMSLink: React.FC = (props) => { reference, size: sizeFromProps, url, + backgroundColor, + textColor, } = props const href = @@ -56,8 +60,19 @@ export const CMSLink: React.FC = (props) => { } return ( - - + + {label && label} {children && children} diff --git a/src/components/Logo/Logo.tsx b/src/components/Logo/Logo.tsx index 3efa904..65e8455 100644 --- a/src/components/Logo/Logo.tsx +++ b/src/components/Logo/Logo.tsx @@ -1,4 +1,3 @@ -import clsx from 'clsx' import React from 'react' interface Props { @@ -8,7 +7,7 @@ interface Props { } export const Logo = (props: Props) => { - const { loading: loadingFromProps, priority: priorityFromProps, className } = props + const { loading: loadingFromProps, priority: priorityFromProps } = props const loading = loadingFromProps || 'lazy' const priority = priorityFromProps || 'low' @@ -16,14 +15,14 @@ export const Logo = (props: Props) => { return ( /* eslint-disable @next/next/no-img-element */ ) } diff --git a/src/components/RichText/index.tsx b/src/components/RichText/index.tsx index 1994159..7209b95 100644 --- a/src/components/RichText/index.tsx +++ b/src/components/RichText/index.tsx @@ -35,25 +35,27 @@ const internalDocToHref = ({ linkNode }: { linkNode: SerializedLinkNode }) => { return relationTo === 'posts' ? `/posts/${slug}` : `/${slug}` } -const jsxConverters: JSXConvertersFunction = ({ defaultConverters }) => ({ - ...defaultConverters, - ...LinkJSXConverter({ internalDocToHref }), - blocks: { - banner: ({ node }) => , - mediaBlock: ({ node }) => ( - - ), - code: ({ node }) => , - cta: ({ node }) => , - }, -}) +const jsxConverters: JSXConvertersFunction = ({ defaultConverters }) => { + return { + ...defaultConverters, + ...LinkJSXConverter({ internalDocToHref }), + blocks: { + banner: ({ node }) => , + mediaBlock: ({ node }) => ( + + ), + code: ({ node }) => , + cta: ({ node }) => , + }, + } +} type Props = { data: DefaultTypedEditorState diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index 391a566..7181a5f 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -19,11 +19,13 @@ const buttonVariants = cva( sm: 'h-9 rounded px-3', }, variant: { - default: 'bg-primary text-primary-foreground hover:bg-primary/90', + default: + 'inline-flex items-center justify-center px-4 py-[calc(--spacing(2)-1px)] rounded-full border border-transparent bg-gray-950 shadow-md text-base font-medium whitespace-nowrap text-white data-disabled:bg-gray-950 data-disabled:opacity-40 data-hover:bg-gray-800', destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90', ghost: 'hover:bg-card hover:text-accent-foreground', link: 'text-primary items-start justify-start underline-offset-4 hover:underline', - outline: 'border border-border bg-background hover:bg-card hover:text-accent-foreground', + outline: + 'relative inline-flex items-center justify-center px-4 py-[calc(--spacing(2)-1px)] rounded-full border border-transparent bg-white/15 ring-1 shadow-md ring-[#D15052]/15 after:absolute after:inset-0 after:rounded-full after:shadow-[inset_0_0_2px_1px_#ffffff4d] text-base font-medium whitespace-nowrap text-gray-950 data-disabled:bg-white/15 data-disabled:opacity-40 data-hover:bg-white/20', secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80', }, }, @@ -46,7 +48,7 @@ const Button: React.FC = ({ ...props }) => { const Comp = asChild ? Slot : 'button' - return + return } export { Button, buttonVariants } diff --git a/src/fields/defaultLexical.ts b/src/fields/defaultLexical.ts index 2468d6e..0fc4e4d 100644 --- a/src/fields/defaultLexical.ts +++ b/src/fields/defaultLexical.ts @@ -7,6 +7,9 @@ import { lexicalEditor, UnderlineFeature, type LinkFields, + UnorderedListFeature, + AlignFeature, + BlockquoteFeature, } from '@payloadcms/richtext-lexical' export const defaultLexical = lexicalEditor({ @@ -15,6 +18,9 @@ export const defaultLexical = lexicalEditor({ UnderlineFeature(), BoldFeature(), ItalicFeature(), + AlignFeature(), + BlockquoteFeature(), + UnorderedListFeature(), LinkFeature({ enabledCollections: ['pages', 'posts'], fields: ({ defaultFields }) => { diff --git a/src/fields/link.ts b/src/fields/link.ts index 2834e25..2f2365b 100644 --- a/src/fields/link.ts +++ b/src/fields/link.ts @@ -2,7 +2,7 @@ import type { Field, GroupField } from 'payload' import deepMerge from '@/utilities/deepMerge' -export type LinkAppearances = 'default' | 'outline' +export type LinkAppearances = 'default' | 'outline' | 'destructive' export const appearanceOptions: Record = { default: { @@ -13,6 +13,10 @@ export const appearanceOptions: Record = ({ links, richText }) => { + const { setHeaderTheme } = useHeaderTheme() + + useEffect(() => { + setHeaderTheme('light') + }) + + return ( + + + + {richText && ( + + )} + {Array.isArray(links) && links.length > 0 && ( + + {links.map(({ link }, i) => { + return ( + + + + ) + })} + + )} + + + + ) +} diff --git a/src/heros/RenderHero.tsx b/src/heros/RenderHero.tsx index 00ca702..7b9caf9 100644 --- a/src/heros/RenderHero.tsx +++ b/src/heros/RenderHero.tsx @@ -2,11 +2,13 @@ import React from 'react' import type { Page } from '@/payload-types' +import { GradientImpactHero } from '@/heros/GradientImpact' import { HighImpactHero } from '@/heros/HighImpact' import { LowImpactHero } from '@/heros/LowImpact' import { MediumImpactHero } from '@/heros/MediumImpact' const heroes = { + gradientImpact: GradientImpactHero, highImpact: HighImpactHero, lowImpact: LowImpactHero, mediumImpact: MediumImpactHero, diff --git a/src/heros/config.ts b/src/heros/config.ts index 7bc2f24..bab78c2 100644 --- a/src/heros/config.ts +++ b/src/heros/config.ts @@ -23,6 +23,10 @@ export const hero: Field = { label: 'None', value: 'none', }, + { + label: 'Gradient Impact', + value: 'gradientImpact', + }, { label: 'High Impact', value: 'highImpact', diff --git a/src/payload-types.ts b/src/payload-types.ts index 1dfe387..39ec0ea 100644 --- a/src/payload-types.ts +++ b/src/payload-types.ts @@ -54,6 +54,7 @@ export type SupportedTimezones = | 'Asia/Singapore' | 'Asia/Tokyo' | 'Asia/Seoul' + | 'Australia/Brisbane' | 'Australia/Sydney' | 'Pacific/Guam' | 'Pacific/Noumea' @@ -97,7 +98,7 @@ export interface Config { 'payload-migrations': PayloadMigrationsSelect | PayloadMigrationsSelect; }; db: { - defaultIDType: string; + defaultIDType: number; }; globals: { header: Header; @@ -145,10 +146,10 @@ export interface UserAuthOperations { * via the `definition` "pages". */ export interface Page { - id: string; + id: number; title: string; hero: { - type: 'none' | 'highImpact' | 'mediumImpact' | 'lowImpact'; + type: 'none' | 'gradientImpact' | 'highImpact' | 'mediumImpact' | 'lowImpact'; richText?: { root: { type: string; @@ -169,14 +170,16 @@ export interface Page { link: { type?: ('reference' | 'custom') | null; newTab?: boolean | null; + backgroundColor?: string | null; + textColor?: string | null; reference?: | ({ relationTo: 'pages'; - value: string | Page; + value: number | Page; } | null) | ({ relationTo: 'posts'; - value: string | Post; + value: number | Post; } | null); url?: string | null; label: string; @@ -188,15 +191,15 @@ export interface Page { id?: string | null; }[] | null; - media?: (string | null) | Media; + media?: (number | null) | Media; }; - layout: (CallToActionBlock | ContentBlock | MediaBlock | ArchiveBlock | FormBlock)[]; + layout: (CallToActionBlock | ContentBlock | MediaBlock | ArchiveBlock | FormBlock | BentoBlock | ArticleBlock)[]; meta?: { title?: string | null; /** * Maximum upload file size: 12MB. Recommended file size for images is <500KB. */ - image?: (string | null) | Media; + image?: (number | null) | Media; description?: string | null; }; publishedAt?: string | null; @@ -211,9 +214,9 @@ export interface Page { * via the `definition` "posts". */ export interface Post { - id: string; + id: number; title: string; - heroImage?: (string | null) | Media; + heroImage?: (number | null) | Media; content: { root: { type: string; @@ -229,18 +232,18 @@ export interface Post { }; [k: string]: unknown; }; - relatedPosts?: (string | Post)[] | null; - categories?: (string | Category)[] | null; + relatedPosts?: (number | Post)[] | null; + categories?: (number | Category)[] | null; meta?: { title?: string | null; /** * Maximum upload file size: 12MB. Recommended file size for images is <500KB. */ - image?: (string | null) | Media; + image?: (number | null) | Media; description?: string | null; }; publishedAt?: string | null; - authors?: (string | User)[] | null; + authors?: (number | User)[] | null; populatedAuthors?: | { id?: string | null; @@ -258,7 +261,7 @@ export interface Post { * via the `definition` "media". */ export interface Media { - id: string; + id: number; alt?: string | null; caption?: { root: { @@ -350,14 +353,14 @@ export interface Media { * via the `definition` "categories". */ export interface Category { - id: string; + id: number; title: string; slug?: string | null; slugLock?: boolean | null; - parent?: (string | null) | Category; + parent?: (number | null) | Category; breadcrumbs?: | { - doc?: (string | null) | Category; + doc?: (number | null) | Category; url?: string | null; label?: string | null; id?: string | null; @@ -371,7 +374,7 @@ export interface Category { * via the `definition` "users". */ export interface User { - id: string; + id: number; name?: string | null; updatedAt: string; createdAt: string; @@ -409,14 +412,16 @@ export interface CallToActionBlock { link: { type?: ('reference' | 'custom') | null; newTab?: boolean | null; + backgroundColor?: string | null; + textColor?: string | null; reference?: | ({ relationTo: 'pages'; - value: string | Page; + value: number | Page; } | null) | ({ relationTo: 'posts'; - value: string | Post; + value: number | Post; } | null); url?: string | null; label: string; @@ -459,14 +464,16 @@ export interface ContentBlock { link?: { type?: ('reference' | 'custom') | null; newTab?: boolean | null; + backgroundColor?: string | null; + textColor?: string | null; reference?: | ({ relationTo: 'pages'; - value: string | Page; + value: number | Page; } | null) | ({ relationTo: 'posts'; - value: string | Post; + value: number | Post; } | null); url?: string | null; label: string; @@ -478,6 +485,8 @@ export interface ContentBlock { id?: string | null; }[] | null; + backgroundImage?: string | null; + isFullscreen?: boolean | null; id?: string | null; blockName?: string | null; blockType: 'content'; @@ -487,7 +496,7 @@ export interface ContentBlock { * via the `definition` "MediaBlock". */ export interface MediaBlock { - media: string | Media; + media: number | Media; id?: string | null; blockName?: string | null; blockType: 'mediaBlock'; @@ -514,12 +523,12 @@ export interface ArchiveBlock { } | null; populateBy?: ('collection' | 'selection') | null; relationTo?: 'posts' | null; - categories?: (string | Category)[] | null; + categories?: (number | Category)[] | null; limit?: number | null; selectedDocs?: | { relationTo: 'posts'; - value: string | Post; + value: number | Post; }[] | null; id?: string | null; @@ -531,7 +540,7 @@ export interface ArchiveBlock { * via the `definition` "FormBlock". */ export interface FormBlock { - form: string | Form; + form: number | Form; enableIntro?: boolean | null; introContent?: { root: { @@ -557,7 +566,7 @@ export interface FormBlock { * via the `definition` "forms". */ export interface Form { - id: string; + id: number; title: string; fields?: | ( @@ -624,6 +633,7 @@ export interface Form { label?: string | null; width?: number | null; defaultValue?: string | null; + placeholder?: string | null; options?: | { label: string; @@ -725,12 +735,111 @@ export interface Form { updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "BentoBlock". + */ +export interface BentoBlock { + heading?: string | null; + subheading?: string | null; + graphics?: + | { + graphic?: ('animatedMapPins' | 'animatedLogoCluster' | 'animatedKeyboard') | null; + eyebrow?: string | null; + title?: string | null; + description?: string | null; + className?: string | null; + id?: string | null; + }[] + | null; + id?: string | null; + blockName?: string | null; + blockType: 'bento'; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "ArticleBlock". + */ +export interface ArticleBlock { + heading?: string | null; + subheading?: string | null; + brief?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + columns?: + | { + size?: ('oneThird' | 'half' | 'twoThirds' | 'full') | null; + richText?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + enableLink?: boolean | null; + link?: { + type?: ('reference' | 'custom') | null; + newTab?: boolean | null; + backgroundColor?: string | null; + textColor?: string | null; + reference?: + | ({ + relationTo: 'pages'; + value: number | Page; + } | null) + | ({ + relationTo: 'posts'; + value: number | Post; + } | null); + url?: string | null; + label: string; + /** + * Choose how the link should be rendered. + */ + appearance?: ('default' | 'outline') | null; + }; + imageUrls?: + | { + url?: string | null; + alt?: string | null; + width?: number | null; + height?: number | null; + id?: string | null; + }[] + | null; + id?: string | null; + }[] + | null; + id?: string | null; + blockName?: string | null; + blockType: 'article'; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "redirects". */ export interface Redirect { - id: string; + id: number; /** * You will need to rebuild the website when changing this field. */ @@ -740,11 +849,11 @@ export interface Redirect { reference?: | ({ relationTo: 'pages'; - value: string | Page; + value: number | Page; } | null) | ({ relationTo: 'posts'; - value: string | Post; + value: number | Post; } | null); url?: string | null; }; @@ -756,8 +865,8 @@ export interface Redirect { * via the `definition` "form-submissions". */ export interface FormSubmission { - id: string; - form: string | Form; + id: number; + form: number | Form; submissionData?: | { field: string; @@ -775,18 +884,18 @@ export interface FormSubmission { * via the `definition` "search". */ export interface Search { - id: string; + id: number; title?: string | null; priority?: number | null; doc: { relationTo: 'posts'; - value: string | Post; + value: number | Post; }; slug?: string | null; meta?: { title?: string | null; description?: string | null; - image?: (string | null) | Media; + image?: (number | null) | Media; }; categories?: | { @@ -803,7 +912,7 @@ export interface Search { * via the `definition` "payload-jobs". */ export interface PayloadJob { - id: string; + id: number; /** * Input data provided to the job */ @@ -895,52 +1004,52 @@ export interface PayloadJob { * via the `definition` "payload-locked-documents". */ export interface PayloadLockedDocument { - id: string; + id: number; document?: | ({ relationTo: 'pages'; - value: string | Page; + value: number | Page; } | null) | ({ relationTo: 'posts'; - value: string | Post; + value: number | Post; } | null) | ({ relationTo: 'media'; - value: string | Media; + value: number | Media; } | null) | ({ relationTo: 'categories'; - value: string | Category; + value: number | Category; } | null) | ({ relationTo: 'users'; - value: string | User; + value: number | User; } | null) | ({ relationTo: 'redirects'; - value: string | Redirect; + value: number | Redirect; } | null) | ({ relationTo: 'forms'; - value: string | Form; + value: number | Form; } | null) | ({ relationTo: 'form-submissions'; - value: string | FormSubmission; + value: number | FormSubmission; } | null) | ({ relationTo: 'search'; - value: string | Search; + value: number | Search; } | null) | ({ relationTo: 'payload-jobs'; - value: string | PayloadJob; + value: number | PayloadJob; } | null); globalSlug?: string | null; user: { relationTo: 'users'; - value: string | User; + value: number | User; }; updatedAt: string; createdAt: string; @@ -950,10 +1059,10 @@ export interface PayloadLockedDocument { * via the `definition` "payload-preferences". */ export interface PayloadPreference { - id: string; + id: number; user: { relationTo: 'users'; - value: string | User; + value: number | User; }; key?: string | null; value?: @@ -973,7 +1082,7 @@ export interface PayloadPreference { * via the `definition` "payload-migrations". */ export interface PayloadMigration { - id: string; + id: number; name?: string | null; batch?: number | null; updatedAt: string; @@ -998,6 +1107,8 @@ export interface PagesSelect { | { type?: T; newTab?: T; + backgroundColor?: T; + textColor?: T; reference?: T; url?: T; label?: T; @@ -1015,6 +1126,8 @@ export interface PagesSelect { mediaBlock?: T | MediaBlockSelect; archive?: T | ArchiveBlockSelect; formBlock?: T | FormBlockSelect; + bento?: T | BentoBlockSelect; + article?: T | ArticleBlockSelect; }; meta?: | T @@ -1044,6 +1157,8 @@ export interface CallToActionBlockSelect { | { type?: T; newTab?: T; + backgroundColor?: T; + textColor?: T; reference?: T; url?: T; label?: T; @@ -1070,6 +1185,8 @@ export interface ContentBlockSelect { | { type?: T; newTab?: T; + backgroundColor?: T; + textColor?: T; reference?: T; url?: T; label?: T; @@ -1077,6 +1194,8 @@ export interface ContentBlockSelect { }; id?: T; }; + backgroundImage?: T; + isFullscreen?: T; id?: T; blockName?: T; } @@ -1114,6 +1233,66 @@ export interface FormBlockSelect { id?: T; blockName?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "BentoBlock_select". + */ +export interface BentoBlockSelect { + heading?: T; + subheading?: T; + graphics?: + | T + | { + graphic?: T; + eyebrow?: T; + title?: T; + description?: T; + className?: T; + id?: T; + }; + id?: T; + blockName?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "ArticleBlock_select". + */ +export interface ArticleBlockSelect { + heading?: T; + subheading?: T; + brief?: T; + columns?: + | T + | { + size?: T; + richText?: T; + enableLink?: T; + link?: + | T + | { + type?: T; + newTab?: T; + backgroundColor?: T; + textColor?: T; + reference?: T; + url?: T; + label?: T; + appearance?: T; + }; + imageUrls?: + | T + | { + url?: T; + alt?: T; + width?: T; + height?: T; + id?: T; + }; + id?: T; + }; + id?: T; + blockName?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "posts_select". @@ -1355,6 +1534,7 @@ export interface FormsSelect { label?: T; width?: T; defaultValue?: T; + placeholder?: T; options?: | T | { @@ -1532,20 +1712,22 @@ export interface PayloadMigrationsSelect { * via the `definition` "header". */ export interface Header { - id: string; + id: number; navItems?: | { link: { type?: ('reference' | 'custom') | null; newTab?: boolean | null; + backgroundColor?: string | null; + textColor?: string | null; reference?: | ({ relationTo: 'pages'; - value: string | Page; + value: number | Page; } | null) | ({ relationTo: 'posts'; - value: string | Post; + value: number | Post; } | null); url?: string | null; label: string; @@ -1561,20 +1743,22 @@ export interface Header { * via the `definition` "footer". */ export interface Footer { - id: string; + id: number; navItems?: | { link: { type?: ('reference' | 'custom') | null; newTab?: boolean | null; + backgroundColor?: string | null; + textColor?: string | null; reference?: | ({ relationTo: 'pages'; - value: string | Page; + value: number | Page; } | null) | ({ relationTo: 'posts'; - value: string | Post; + value: number | Post; } | null); url?: string | null; label: string; @@ -1598,6 +1782,8 @@ export interface HeaderSelect { | { type?: T; newTab?: T; + backgroundColor?: T; + textColor?: T; reference?: T; url?: T; label?: T; @@ -1621,6 +1807,8 @@ export interface FooterSelect { | { type?: T; newTab?: T; + backgroundColor?: T; + textColor?: T; reference?: T; url?: T; label?: T; @@ -1642,14 +1830,14 @@ export interface TaskSchedulePublish { doc?: | ({ relationTo: 'pages'; - value: string | Page; + value: number | Page; } | null) | ({ relationTo: 'posts'; - value: string | Post; + value: number | Post; } | null); global?: string | null; - user?: (string | null) | User; + user?: (number | null) | User; }; output?: unknown; } diff --git a/tailwind.config.mjs b/tailwind.config.mjs index 44469ab..80a987a 100644 --- a/tailwind.config.mjs +++ b/tailwind.config.mjs @@ -116,6 +116,11 @@ const config = { h1: { fontWeight: 'normal', marginBottom: '0.25em', + fontSize: '3.5rem', + }, + h3: { + fontSize: '1.25rem', + fontWeight: 400, }, }, ], @@ -124,7 +129,7 @@ const config = { css: [ { h1: { - fontSize: '2.5rem', + fontSize: '3.5rem', }, h2: { fontSize: '1.25rem', @@ -137,7 +142,7 @@ const config = { css: [ { h1: { - fontSize: '3.5rem', + fontSize: '4.5rem', }, h2: { fontSize: '1.5rem',
+ {title} +
+ {description} +