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) => ( +
+ {image.alt +
+ ))} +
+
+
+ )} + + {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 ( +