diff --git a/package.json b/package.json index be0b5d0..a3d5b2b 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "test": "jest", "chromatic": "npx chromatic --project-token=chpt_219e0bf9f15c669", "postbuild": "find dist -name '*.js' -exec sed -i 's/\\.css\\.js/\\.css/g' {} +" - }, + }, "dependencies": { "@babel/cli": "7.23.9", "@babel/core": "7.24.0", @@ -48,6 +48,7 @@ "@fortawesome/free-solid-svg-icons": "^6.7.2", "@fortawesome/react-fontawesome": "^0.2.2", "@portabletext/react": "^3.0.0", + "@portabletext/to-html": "^2.0.14", "@radix-ui/colors": "^0.1.8", "@radix-ui/react-accessible-icon": "^1.1.0", "@radix-ui/react-accordion": "^1.2.0", diff --git a/src/theme/conversion/components/cdfaqs/classification.ts b/src/theme/conversion/components/cdfaqs/classification.ts new file mode 100644 index 0000000..7ae186a --- /dev/null +++ b/src/theme/conversion/components/cdfaqs/classification.ts @@ -0,0 +1 @@ +export default ["cdfaqs", "faqs", "cdfaqs"] diff --git a/src/theme/conversion/components/cdfaqs/components/index.tsx b/src/theme/conversion/components/cdfaqs/components/index.tsx new file mode 100644 index 0000000..87a2fb0 --- /dev/null +++ b/src/theme/conversion/components/cdfaqs/components/index.tsx @@ -0,0 +1,49 @@ +import React from "react"; +import { componentBoilerPlate } from "@conversiondigital/headless-basics-data/src/component-tools/componentBoilerPlate"; +import { ViewComponentProps } from "@conversiondigital/headless-basics-data/src/interfaces"; +import { getLogger, logPrefix } from "@conversiondigital/headless-basics-data/src"; +import CdFaqsDefaultVariant from "./variants/CdFaqsDefaultVariant"; + +export const log = getLogger("conversion.components.cdfaqs"); + +// Interface for individual FAQ item +export interface FaqItem { + title: string; + richtextRaw: any[]; +} + +// Interface for global component source +interface GlobalComponentSource { + __typename: string; + _key: string; + _type: string; + title: string; + description: string; + items: FaqItem[]; +} + +// Interface for CdFaqs component data +export interface CdFaqsData { + __typename: string; + _key: string; + _type: string; + selectableVariant: string; + title: string; + description: string; + items: FaqItem[]; + sortOrder: number; + globalComponentSource?: GlobalComponentSource; +} + +export default function CdFaqsUI(dynamicComponent: ViewComponentProps) { + const { variant, matchingData } = componentBoilerPlate(dynamicComponent); + if (!matchingData) return null; + + log.trace(`${logPrefix()} CdFaqsUI started, matchingData: ${JSON.stringify(matchingData)}`); + + switch (variant) { + case "default": + default: + return ; + } +} \ No newline at end of file diff --git a/src/theme/conversion/components/cdfaqs/components/variants/CdFaqsDefaultVariant.tsx b/src/theme/conversion/components/cdfaqs/components/variants/CdFaqsDefaultVariant.tsx new file mode 100644 index 0000000..f1eda5f --- /dev/null +++ b/src/theme/conversion/components/cdfaqs/components/variants/CdFaqsDefaultVariant.tsx @@ -0,0 +1,79 @@ +"use client"; +import { StandardComponentProps } from "@conversiondigital/headless-basics-components/src/interfaces/standardComponentProps"; +import { CdFaqsData, FaqItem } from "../index"; +import { toHTML } from "@portabletext/to-html"; +import React, { useState } from "react"; + +interface CdFaqsDefaultVariantProps extends StandardComponentProps { + matchingData: CdFaqsData; +} + +const CdFaqsDefaultVariant: React.FC = ({ matchingData }) => { + const [indexActive, setIndexActive] = useState(0); + + const title = matchingData?.title || ""; + const description = matchingData?.description || ""; + const items = matchingData?.items || []; + const uniqueId = matchingData?._key || ""; + + return ( +
+
+
+
+

{title}

+

{description}

+
+
+
+ {items.map((item: FaqItem, index: number) => { + return ( +
setIndexActive(index)} + role="button" + tabIndex={0} + aria-pressed={index === indexActive} + > +

+ {item.title} +

+ + + +
+ ); + })} +
+
+ {items.map((item: FaqItem, index: number) => { + return ( +
+
+
+ ); + })} +
+
+
+
+
+ ); +}; + +export default CdFaqsDefaultVariant; diff --git a/src/theme/conversion/components/cdservicestats/index.ts b/src/theme/conversion/components/cdfaqs/index.ts similarity index 76% rename from src/theme/conversion/components/cdservicestats/index.ts rename to src/theme/conversion/components/cdfaqs/index.ts index e14148a..0d09c5d 100644 --- a/src/theme/conversion/components/cdservicestats/index.ts +++ b/src/theme/conversion/components/cdfaqs/index.ts @@ -2,10 +2,10 @@ import { getLogger, getThemeConfig } from "@conversiondigital/headless-basics-da import { View } from "./view"; import { ThemeConfig } from "@conversiondigital/headless-basics-data/src/interfaces" -getLogger("theme.components.cdservicestats") +getLogger("theme.components.cdfaqs") async function getConfig(): Promise { - const config = await getThemeConfig('cdservicestats'); + const config = await getThemeConfig('cdfaqs'); config.view = View; return config; } diff --git a/src/theme/conversion/components/cdserviceofferings/sanity-mapping.ts b/src/theme/conversion/components/cdfaqs/sanity-mapping.ts similarity index 86% rename from src/theme/conversion/components/cdserviceofferings/sanity-mapping.ts rename to src/theme/conversion/components/cdfaqs/sanity-mapping.ts index f32e369..75f5ebc 100644 --- a/src/theme/conversion/components/cdserviceofferings/sanity-mapping.ts +++ b/src/theme/conversion/components/cdfaqs/sanity-mapping.ts @@ -1,7 +1,7 @@ import { getLogger, logPrefix, PageAndSingleComponentDetails } from "@conversiondigital/headless-basics-data/src" import { extractComponentsFromSanityData } from "@conversiondigital/headless-basics-data/src/cms/sanity/sanityMappingUtils" -export const log = getLogger("conversion.components.sanity.cdserviceofferings.mapping") +export const log = getLogger("conversion.components.sanity.cdfaqs.mapping") export async function mapIdentifierData(pageAndComponentCombo: PageAndSingleComponentDetails) { log.trace( @@ -10,7 +10,7 @@ export async function mapIdentifierData(pageAndComponentCombo: PageAndSingleComp const content = pageAndComponentCombo?.component?.data - const matchingData = extractComponentsFromSanityData(content, "cdserviceofferings", log); + const matchingData = extractComponentsFromSanityData(content, "cdfaqs", log); return matchingData } diff --git a/src/theme/conversion/components/cdserviceofferings/sanity-query.ts b/src/theme/conversion/components/cdfaqs/sanity-query.ts similarity index 50% rename from src/theme/conversion/components/cdserviceofferings/sanity-query.ts rename to src/theme/conversion/components/cdfaqs/sanity-query.ts index e77ef55..efd2251 100644 --- a/src/theme/conversion/components/cdserviceofferings/sanity-query.ts +++ b/src/theme/conversion/components/cdfaqs/sanity-query.ts @@ -2,28 +2,20 @@ import { PageAndSingleComponentDetails } from "@conversiondigital/headless-basic export function query(pageAndComponentCombo: PageAndSingleComponentDetails): string { return ` - query GetCdserviceofferingsBySlug($slug: String!) { + query GetCdFaqsBySlug($slug: String!) { allPage(where: { slug: { current: { eq: $slug } } }) { components { __typename - ... on Cdserviceofferings { + ... on Cdfaqs { __typename _key _type selectableVariant title - intro - offerings { + description + items { title - icon - id { - current - } - } - services { - id - title - content + richtextRaw } sortOrder globalComponentSource { @@ -31,44 +23,28 @@ export function query(pageAndComponentCombo: PageAndSingleComponentDetails): str _key _type title - intro - offerings { - title - icon - id { - current - } - } - services { - id + description + items { title - content + richtextRaw } } } } } - allServicePage { + allHomepage { components { __typename - ... on Cdserviceofferings { + ... on Cdfaqs { __typename _key _type selectableVariant title - intro - offerings { + description + items { title - icon - id { - current - } - } - services { - id - title - content + richtextRaw } sortOrder globalComponentSource { @@ -76,18 +52,10 @@ export function query(pageAndComponentCombo: PageAndSingleComponentDetails): str _key _type title - intro - offerings { - title - icon - id { - current - } - } - services { - id + description + items { title - content + richtextRaw } } } diff --git a/src/theme/conversion/components/cdfaqs/sanity-schema.ts b/src/theme/conversion/components/cdfaqs/sanity-schema.ts new file mode 100644 index 0000000..158df17 --- /dev/null +++ b/src/theme/conversion/components/cdfaqs/sanity-schema.ts @@ -0,0 +1,127 @@ +import { defineField, defineType } from 'sanity' +import { EyeOpenIcon } from '@sanity/icons' + +// Define a separate type for the FAQ item object +export const cdFaqItem = defineType({ + name: 'cdFaqItem', + title: 'FAQ Item', + type: 'object', + fields: [ + defineField({ + name: 'title', + title: 'Title', + type: 'string', + description: 'The title of the FAQ item' + }), + defineField({ + name: 'richtext', + title: 'Description', + type: 'array', + of: [ + { + type: 'block', + styles: [ + {title: 'Normal', value: 'normal'}, + {title: 'H2', value: 'h2'}, + {title: 'H3', value: 'h3'}, + {title: 'H4', value: 'h4'}, + {title: 'Quote', value: 'blockquote'} + ], + lists: [ + {title: 'Bullet', value: 'bullet'}, + {title: 'Numbered', value: 'number'} + ], + marks: { + decorators: [ + {title: 'Strong', value: 'strong'}, + {title: 'Emphasis', value: 'em'}, + {title: 'Underline', value: 'underline'} + ], + annotations: [ + { + name: 'link', + type: 'object', + title: 'Link', + fields: [ + { + name: 'href', + type: 'string', + title: 'URL' + }, + { + name: 'blank', + type: 'boolean', + title: 'Open in new tab', + initialValue: false + } + ] + } + ] + } + } + ], + description: 'The rich text content for the FAQ item' + }) + ], + preview: { + select: { + title: 'title' + } + } +}) + +export default defineType({ + name: 'cdfaqs', + title: 'FAQs (CD)', + type: 'object', + icon: EyeOpenIcon, + fields: [ + defineField({ + name: 'selectableVariant', + title: 'Selectable Variant', + type: 'string', + options: { + list: [ + { title: 'Default', value: 'default' } + ] + } + }), + defineField({ + name: 'title', + title: 'Title', + type: 'string', + description: 'The main title for the FAQs section (e.g., "Frequently Asked Questions")' + }), + defineField({ + name: 'description', + title: 'Introduction Text', + type: 'text', + description: 'A brief description of the FAQs' + }), + defineField({ + name: 'items', + title: 'FAQ Items', + type: 'array', + of: [ + { type: 'cdFaqItem' } + ], + }), + defineField({ + name: 'sortOrder', + title: 'Sort Order', + type: 'number' + }), + defineField({ + name: 'globalComponentSource', + title: 'Global Component Source', + type: 'reference', + to: [{ type: 'cdfaqs' }], + description: 'Select a global re-usable FAQs component.' + }) + ], + preview: { + select: { + title: 'title' + } + } +}) \ No newline at end of file diff --git a/src/theme/conversion/components/cdservicestats/view.tsx b/src/theme/conversion/components/cdfaqs/view.tsx similarity index 67% rename from src/theme/conversion/components/cdservicestats/view.tsx rename to src/theme/conversion/components/cdfaqs/view.tsx index 39aaf49..54cae12 100644 --- a/src/theme/conversion/components/cdservicestats/view.tsx +++ b/src/theme/conversion/components/cdfaqs/view.tsx @@ -2,10 +2,10 @@ import { ViewComponentProps } from "@conversiondigital/headless-basics-data/src"; import dynamic from "next/dynamic" -const CdservicestatsUI = dynamic(() => import("./components"), { +const CdFaqsUI = dynamic(() => import("./components"), { loading: () => (

Loading...

) }); export async function View(dynamicComponent: ViewComponentProps) { - return + return } diff --git a/src/theme/conversion/components/cdintroduction/classification.ts b/src/theme/conversion/components/cdintroduction/classification.ts new file mode 100644 index 0000000..f479165 --- /dev/null +++ b/src/theme/conversion/components/cdintroduction/classification.ts @@ -0,0 +1 @@ +export default ["cdintroduction", "introduction", "introduction-cd"] \ No newline at end of file diff --git a/src/theme/conversion/components/cdintroduction/components/index.tsx b/src/theme/conversion/components/cdintroduction/components/index.tsx new file mode 100644 index 0000000..3b0f8d4 --- /dev/null +++ b/src/theme/conversion/components/cdintroduction/components/index.tsx @@ -0,0 +1,41 @@ +import React from "react"; +import { componentBoilerPlate } from "@conversiondigital/headless-basics-data/src/component-tools/componentBoilerPlate"; +import { ViewComponentProps } from "@conversiondigital/headless-basics-data/src/interfaces"; +import { getLogger, logPrefix } from "@conversiondigital/headless-basics-data/src"; +import CdIntroductionDefaultVariant from "./variants/CdIntroductionDefaultVariant"; + +export const log = getLogger("conversion.components.cdintroduction"); + +// Interface for global component source +interface GlobalComponentSource { + __typename: string; + _key: string; + _type: string; + title: string; + richtextRaw: any; +} + +// Interface for CdIntroduction component data +export interface CdIntroductionData { + __typename: string; + _key: string; + _type: string; + selectableVariant: string; + title: string; + richtextRaw: any; + sortOrder: number; + globalComponentSource?: GlobalComponentSource; +} + +export default function CdIntroductionUI(dynamicComponent: ViewComponentProps) { + const { variant, matchingData } = componentBoilerPlate(dynamicComponent); + if (!matchingData) return null; + + log.trace(`${logPrefix()} CdIntroductionUI started, matchingData: ${JSON.stringify(matchingData)}`); + + switch (variant) { + case "default": + default: + return ; + } +} diff --git a/src/theme/conversion/components/cdintroduction/components/variants/CdIntroductionDefaultVariant.tsx b/src/theme/conversion/components/cdintroduction/components/variants/CdIntroductionDefaultVariant.tsx new file mode 100644 index 0000000..6a176db --- /dev/null +++ b/src/theme/conversion/components/cdintroduction/components/variants/CdIntroductionDefaultVariant.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { StandardComponentProps } from "@conversiondigital/headless-basics-components/src/interfaces/standardComponentProps"; +import { CdIntroductionData } from '../index'; +import {toHTML} from '@portabletext/to-html' + +interface CdIntroductionDefaultVariantProps extends StandardComponentProps { + matchingData: CdIntroductionData; +} + +const CdIntroductionDefaultVariant: React.FC = ({ matchingData }) => { + const title = matchingData?.title || ''; + const content = matchingData?.richtextRaw || ''; + + return ( +
+
+
+

{title}

+
+
+
+
+ ); +}; + +export default CdIntroductionDefaultVariant; \ No newline at end of file diff --git a/src/theme/conversion/components/cdserviceintro/index.ts b/src/theme/conversion/components/cdintroduction/index.ts similarity index 76% rename from src/theme/conversion/components/cdserviceintro/index.ts rename to src/theme/conversion/components/cdintroduction/index.ts index 8cf23bb..393a44c 100644 --- a/src/theme/conversion/components/cdserviceintro/index.ts +++ b/src/theme/conversion/components/cdintroduction/index.ts @@ -2,10 +2,10 @@ import { getLogger, getThemeConfig } from "@conversiondigital/headless-basics-da import { View } from "./view"; import { ThemeConfig } from "@conversiondigital/headless-basics-data/src/interfaces" -getLogger("theme.components.cdserviceintro") +getLogger("theme.components.cdintroduction") async function getConfig(): Promise { - const config = await getThemeConfig('cdserviceintro'); + const config = await getThemeConfig('cdintroduction'); config.view = View; return config; } diff --git a/src/theme/conversion/components/cdserviceintro/sanity-mapping.ts b/src/theme/conversion/components/cdintroduction/sanity-mapping.ts similarity index 87% rename from src/theme/conversion/components/cdserviceintro/sanity-mapping.ts rename to src/theme/conversion/components/cdintroduction/sanity-mapping.ts index e7b9f29..240dbb8 100644 --- a/src/theme/conversion/components/cdserviceintro/sanity-mapping.ts +++ b/src/theme/conversion/components/cdintroduction/sanity-mapping.ts @@ -1,14 +1,14 @@ import { getLogger, logPrefix, PageAndSingleComponentDetails } from "@conversiondigital/headless-basics-data/src" import { extractComponentsFromSanityData } from "@conversiondigital/headless-basics-data/src/cms/sanity/sanityMappingUtils" -export const log = getLogger("conversion.components.sanity.cdserviceintro.mapping") +export const log = getLogger("conversion.components.sanity.cdintroduction.mapping") export async function mapIdentifierData(pageAndComponentCombo: PageAndSingleComponentDetails) { log.trace( `${logPrefix()}[${pageAndComponentCombo.component.identifier}][${pageAndComponentCombo.page.source}][${pageAndComponentCombo.page.preliminarySlug}] mapIdentifierData started, ${JSON.stringify(pageAndComponentCombo?.component?.data)}` ); const content = pageAndComponentCombo?.component?.data - const matchingData = extractComponentsFromSanityData(content, "cdserviceintro", log); + const matchingData = extractComponentsFromSanityData(content, "cdintroduction", log); return matchingData } \ No newline at end of file diff --git a/src/theme/conversion/components/cdserviceintro/sanity-query.ts b/src/theme/conversion/components/cdintroduction/sanity-query.ts similarity index 75% rename from src/theme/conversion/components/cdserviceintro/sanity-query.ts rename to src/theme/conversion/components/cdintroduction/sanity-query.ts index 260b921..3f2a4bd 100644 --- a/src/theme/conversion/components/cdserviceintro/sanity-query.ts +++ b/src/theme/conversion/components/cdintroduction/sanity-query.ts @@ -2,49 +2,45 @@ import { PageAndSingleComponentDetails } from "@conversiondigital/headless-basic export function query(pageAndComponentCombo: PageAndSingleComponentDetails): string { return ` - query GetCdserviceintroBySlug($slug: String!) { + query GetCdIntroductionBySlug($slug: String!) { allPage(where: { slug: { current: { eq: $slug } } }) { components { __typename - ... on Cdserviceintro { + ... on Cdintroduction { __typename _key _type selectableVariant - heading title - content + richtextRaw sortOrder globalComponentSource { __typename _key _type - heading title - content + richtextRaw } } } } - allServicePage { + allHomepage { components { __typename - ... on Cdserviceintro { + ... on Cdintroduction { __typename _key _type selectableVariant - heading title - content + richtextRaw sortOrder globalComponentSource { __typename _key _type - heading title - content + richtextRaw } } } diff --git a/src/theme/conversion/components/cdserviceintro/sanity-schema.ts b/src/theme/conversion/components/cdintroduction/sanity-schema.ts similarity index 72% rename from src/theme/conversion/components/cdserviceintro/sanity-schema.ts rename to src/theme/conversion/components/cdintroduction/sanity-schema.ts index 419c1a6..6842609 100644 --- a/src/theme/conversion/components/cdserviceintro/sanity-schema.ts +++ b/src/theme/conversion/components/cdintroduction/sanity-schema.ts @@ -1,10 +1,11 @@ import { defineField, defineType } from 'sanity' import { DocumentTextIcon } from '@sanity/icons' +// Define a separate document type for cdintroduction export default defineType({ - name: 'cdserviceintro', - title: 'Service Introduction (CD)', - type: 'object', + name: 'cdintroduction', + title: 'Introduction (CD)', + type: 'document', icon: DocumentTextIcon, fields: [ defineField({ @@ -17,21 +18,15 @@ export default defineType({ ] } }), - defineField({ - name: 'heading', - title: 'Heading', - type: 'string', - description: 'The main heading for the service introduction section' - }), defineField({ name: 'title', title: 'Title', type: 'string', - description: 'The secondary title for the service introduction section' + description: 'The secondary title for the introduction section' }), defineField({ - name: 'content', - title: 'Content', + name: 'richtext', + title: 'Rich Text', type: 'array', of: [ { @@ -61,8 +56,14 @@ export default defineType({ fields: [ { name: 'href', - type: 'url', + type: 'string', title: 'URL' + }, + { + name: 'blank', + type: 'boolean', + title: 'Open in new tab', + initialValue: false } ] } @@ -70,7 +71,7 @@ export default defineType({ } } ], - description: 'The rich text content for the service introduction' + description: 'The rich text content for the introduction' }), defineField({ name: 'sortOrder', @@ -81,14 +82,13 @@ export default defineType({ name: 'globalComponentSource', title: 'Global Component Source', type: 'reference', - to: [{ type: 'cdserviceintro' }], - description: 'Select a global re-usable service introduction.' - }) + to: [{ type: 'cdintroduction' }], + description: 'Select a global re-usable introduction.' + }), ], preview: { select: { - title: 'heading', - subtitle: 'title' + title: 'title', } } }) \ No newline at end of file diff --git a/src/theme/conversion/components/cdserviceintro/view.tsx b/src/theme/conversion/components/cdintroduction/view.tsx similarity index 67% rename from src/theme/conversion/components/cdserviceintro/view.tsx rename to src/theme/conversion/components/cdintroduction/view.tsx index 5fc6404..13c3448 100644 --- a/src/theme/conversion/components/cdserviceintro/view.tsx +++ b/src/theme/conversion/components/cdintroduction/view.tsx @@ -2,10 +2,10 @@ import { ViewComponentProps } from "@conversiondigital/headless-basics-data/src"; import dynamic from "next/dynamic" -const CdserviceintroUI = dynamic(() => import("./components"), { +const CdIntroductionUI = dynamic(() => import("./components"), { loading: () => (

Loading...

) }); export async function View(dynamicComponent: ViewComponentProps) { - return + return } \ No newline at end of file diff --git a/src/theme/conversion/components/cdnav/sanity-schema.ts b/src/theme/conversion/components/cdnav/sanity-schema.ts index 38e554e..6381457 100644 --- a/src/theme/conversion/components/cdnav/sanity-schema.ts +++ b/src/theme/conversion/components/cdnav/sanity-schema.ts @@ -1,6 +1,5 @@ import { defineField, defineType } from 'sanity' import { EyeOpenIcon } from '@sanity/icons' -import { linkItem } from '@conversiondigital/headless-basics-data/src/cms/sanity/sanityCommonSchema' // Define the dropdown menu type export const dropdownMenu = defineType({ @@ -22,6 +21,26 @@ export const dropdownMenu = defineType({ ] }) +export const linkItem = defineType({ + name: 'linkItem', + title: 'Link Item', + type: 'object', + fields: [ + defineField({ + name: 'label', + title: 'Label', + type: 'string', + validation: Rule => Rule.required() + }), + defineField({ + name: 'url', + title: 'URL', + type: 'url', + validation: Rule => Rule.required() + }) + ] +}) + export default defineType({ name: 'cdnav', title: 'Navigation (CD)', diff --git a/src/theme/conversion/components/cdserviceintro/classification.ts b/src/theme/conversion/components/cdserviceintro/classification.ts deleted file mode 100644 index 2d7f277..0000000 --- a/src/theme/conversion/components/cdserviceintro/classification.ts +++ /dev/null @@ -1 +0,0 @@ -export default ["cdserviceintro", "serviceintro", "service-intro"] \ No newline at end of file diff --git a/src/theme/conversion/components/cdserviceintro/components/index.tsx b/src/theme/conversion/components/cdserviceintro/components/index.tsx deleted file mode 100644 index 7223819..0000000 --- a/src/theme/conversion/components/cdserviceintro/components/index.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import { componentBoilerPlate } from "@conversiondigital/headless-basics-data/src/component-tools/componentBoilerPlate"; -import { ViewComponentProps } from "@conversiondigital/headless-basics-data/src/interfaces"; -import { getLogger, logPrefix } from "@conversiondigital/headless-basics-data/src"; -import CdserviceintroDefaultVariant from './variants/cdserviceintroDefaultVariant'; - -export const log = getLogger("conversion.components.cdserviceintro"); - -export default function CdserviceintroUI(dynamicComponent: ViewComponentProps) { - const { variant, matchingData } = componentBoilerPlate(dynamicComponent); - if (!matchingData) return null; - - log.trace(`${logPrefix()} cdserviceintroUI started, matchingData: ${JSON.stringify(matchingData)}`); - - switch (variant) { - case 'default': - default: - return ; - } -} \ No newline at end of file diff --git a/src/theme/conversion/components/cdserviceintro/components/variants/cdserviceintroDefaultVariant.tsx b/src/theme/conversion/components/cdserviceintro/components/variants/cdserviceintroDefaultVariant.tsx deleted file mode 100644 index 8139c8c..0000000 --- a/src/theme/conversion/components/cdserviceintro/components/variants/cdserviceintroDefaultVariant.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import { StandardComponentProps } from "@conversiondigital/headless-basics-components/src/interfaces/standardComponentProps"; - -const CdserviceintroDefaultVariant: React.FC = ({ matchingData }) => { - const heading = matchingData?.heading || ''; - const title = matchingData?.title || ''; - const content = matchingData?.content || ''; - - return ( -
-
-
-

{heading}

-
-
-

{title}

-
-
-
-
- ); -}; - -export default CdserviceintroDefaultVariant; \ No newline at end of file diff --git a/src/theme/conversion/components/cdserviceofferings/classification.ts b/src/theme/conversion/components/cdserviceofferings/classification.ts deleted file mode 100644 index d1209af..0000000 --- a/src/theme/conversion/components/cdserviceofferings/classification.ts +++ /dev/null @@ -1 +0,0 @@ -export default ["cdserviceofferings", "serviceofferings", "cdserviceofferings"] diff --git a/src/theme/conversion/components/cdserviceofferings/components/index.tsx b/src/theme/conversion/components/cdserviceofferings/components/index.tsx deleted file mode 100644 index 71b0175..0000000 --- a/src/theme/conversion/components/cdserviceofferings/components/index.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import { componentBoilerPlate } from "@conversiondigital/headless-basics-data/src/component-tools/componentBoilerPlate"; -import { ViewComponentProps } from "@conversiondigital/headless-basics-data/src/interfaces"; -import { getLogger, logPrefix } from "@conversiondigital/headless-basics-data/src"; -import CdserviceofferingsDefaultVariant from './variants/cdserviceofferingsDefaultVariant'; - -export const log = getLogger("conversion.components.cdserviceofferings"); - -export default function CdserviceofferingsUI(dynamicComponent: ViewComponentProps) { - const { variant, matchingData } = componentBoilerPlate(dynamicComponent); - if (!matchingData) return null; - - log.trace(`${logPrefix()} cdserviceofferingsUI started, matchingData: ${JSON.stringify(matchingData)}`); - - switch (variant) { - case 'default': - default: - return ; - } -} \ No newline at end of file diff --git a/src/theme/conversion/components/cdserviceofferings/components/variants/cdserviceofferingsDefaultVariant.tsx b/src/theme/conversion/components/cdserviceofferings/components/variants/cdserviceofferingsDefaultVariant.tsx deleted file mode 100644 index 5d70cac..0000000 --- a/src/theme/conversion/components/cdserviceofferings/components/variants/cdserviceofferingsDefaultVariant.tsx +++ /dev/null @@ -1,102 +0,0 @@ -"use client" -import React, { useState, useEffect } from 'react'; -import { StandardComponentProps } from "@conversiondigital/headless-basics-components/src/interfaces/standardComponentProps"; - -interface Offering { - title: string; - icon: string; - id: { - current: string; - }; -} - -interface Service { - id: string; - title: string; - content: string; -} - -const CdserviceofferingsDefaultVariant: React.FC = ({ matchingData }) => { - const title = matchingData?.title || ''; - const intro = matchingData?.intro || ''; - const offerings = matchingData?.offerings || []; - const services = matchingData?.services || []; - - const [activeServiceId, setActiveServiceId] = useState(undefined); - const [isVisible, setIsVisible] = useState(true); - - const getIdValue = (offering: Offering) => offering.id?.current || ''; - - const currentService = services.find((service: Service) => service.id === activeServiceId); - - useEffect(() => { - if (!activeServiceId && offerings.length > 0) { - setActiveServiceId(getIdValue(offerings[0]) || '1'); - } - }, [offerings, activeServiceId]); - - const handleServiceClick = (serviceId: string, index: number) => { - if (serviceId === activeServiceId) return; - - setIsVisible(false); - - setTimeout(() => { - setActiveServiceId(serviceId || index.toString()); - setIsVisible(true); - }, 300); - }; - - return ( -
-
-
-
-

{title}

-

{intro}

-
-
-
- {offerings.map((offering: Offering, index: number) => { - const id = getIdValue(offering); - return ( -
handleServiceClick(id, index + 1)} - role="button" - tabIndex={0} - aria-pressed={id === activeServiceId} - onKeyDown={(e) => { - if (e.key === 'Enter' || e.key === ' ') { - handleServiceClick(id, index + 1); - } - }} - > -

{offering.title}

- - - -
- ); - })} -
-
-
-
-
-
-
-
-
-
-
-
- ); -}; - -export default CdserviceofferingsDefaultVariant; \ No newline at end of file diff --git a/src/theme/conversion/components/cdserviceofferings/sanity-schema.ts b/src/theme/conversion/components/cdserviceofferings/sanity-schema.ts deleted file mode 100644 index a94a148..0000000 --- a/src/theme/conversion/components/cdserviceofferings/sanity-schema.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { defineField, defineType } from 'sanity' -import { TagIcon } from '@sanity/icons' - -export default defineType({ - name: 'cdserviceofferings', - title: 'Service Offerings (CD)', - type: 'object', - icon: TagIcon, - fields: [ - defineField({ - name: 'selectableVariant', - title: 'Selectable Variant', - type: 'string', - options: { - list: [ - { title: 'Default', value: 'default' } - ] - } - }), - defineField({ - name: 'title', - title: 'Title', - type: 'string', - description: 'The main title for the service offerings section (e.g., "What We Offer")' - }), - defineField({ - name: 'intro', - title: 'Introduction Text', - type: 'text', - description: 'A brief introduction to the service offerings' - }), - defineField({ - name: 'offerings', - title: 'Service Offerings', - type: 'array', - of: [ - { - type: 'object', - title: 'Offering', - fields: [ - { - name: 'title', - title: 'Title', - type: 'string', - description: 'The name of the service offering' - }, - { - name: 'icon', - title: 'Icon', - type: 'string', - description: 'The icon name to display for this offering' - }, - { - name: 'id', - title: 'ID', - type: 'slug', - description: 'A unique identifier for this service offering', - } - ] - } - ], - }), - defineField({ - name: 'services', - title: 'Service Details', - type: 'array', - of: [ - { - type: 'object', - title: 'Service Detail', - fields: [ - { - name: 'id', - title: 'ID', - type: 'string', - description: 'A unique identifier for this service detail (should match an offering ID)' - }, - { - name: 'title', - title: 'Title', - type: 'string', - description: 'The title of the service detail' - }, - { - name: 'content', - title: 'Content', - type: 'array', - of: [{ type: 'block' }], - description: 'The rich text content for this service detail' - } - ] - } - ], - description: 'The detailed content for each service offering' - }), - defineField({ - name: 'sortOrder', - title: 'Sort Order', - type: 'number' - }), - defineField({ - name: 'globalComponentSource', - title: 'Global Component Source', - type: 'reference', - to: [{ type: 'cdserviceofferings' }], - description: 'Select a global re-usable service offerings component.' - }) - ], - preview: { - select: { - title: 'title' - } - } -}) \ No newline at end of file diff --git a/src/theme/conversion/components/cdservices/components/index.tsx b/src/theme/conversion/components/cdservices/components/index.tsx index 94047ad..972a2a4 100644 --- a/src/theme/conversion/components/cdservices/components/index.tsx +++ b/src/theme/conversion/components/cdservices/components/index.tsx @@ -4,6 +4,7 @@ import type { ViewComponentProps } from "@conversiondigital/headless-basics-data import { getLogger, logPrefix } from "@conversiondigital/headless-basics-data/src"; import DemoVariant from "./variants/demoVariant"; import DefaultVariant from "./variants/cdservicesDefaultVariant"; +import CdServiceFeatureBlocksVariant from "./variants/CdServiceFeatureBlocksVariant"; export const log = getLogger("conversion.components.cdservices"); @@ -16,6 +17,8 @@ export default function TemplateUI(dynamicComponent: ViewComponentProps) { switch (variant) { case "xDemo": return ; + case "featureBlocks": + return ; default: return ; } diff --git a/src/theme/conversion/components/cdservices/components/variants/CdServiceFeatureBlocksVariant.tsx b/src/theme/conversion/components/cdservices/components/variants/CdServiceFeatureBlocksVariant.tsx new file mode 100644 index 0000000..0d37d16 --- /dev/null +++ b/src/theme/conversion/components/cdservices/components/variants/CdServiceFeatureBlocksVariant.tsx @@ -0,0 +1,120 @@ +import { StandardComponentProps } from "@conversiondigital/headless-basics-components/src/interfaces/standardComponentProps"; +import { cn } from "@conversiondigital/headless-basics-data"; +import { ChevronRight } from "lucide-react"; +import Image from "next/image"; +import Link from "next/link"; + +interface ServiceLink { + name: string; +} + +interface ServiceImage { + asset: { + url: string; + }; +} + +interface ServiceItem { + title: string; + description: string; + image: ServiceImage; + serviceLinks: ServiceLink[]; + category: string; + imageTitle: string; + buttonText: string; + buttonUrl: string; +} + +interface CdServicesData { + _key: string; + _type: string; + selectableVariant: string; + sortOrder: number; + title: string; + subtitle: string; + image?: ServiceImage; + servicesList: ServiceItem[]; + globalComponentSource?: CdServicesData; +} + +export default function CdServiceFeatureBlocksVariant(props: StandardComponentProps) { + const { matchingData } = props; + const data = matchingData as CdServicesData; + const services = data?.servicesList || []; + + const padStart = (number: number) => String(number).padStart(2, "0"); + + return ( +
+
+ {services.map((service: ServiceItem, idx: number) => ( +
+
+
+ + {padStart(idx + 1)} + +

+ {service.title} +

+

+ {service.description} +

+ {!!service.serviceLinks?.length && ( +
+
    + {service.serviceLinks.map((link, linkIdx) => ( +
  • 3 ? "md:w-1/2" : "md:w-full", + )} + > + {link.name} +
  • + ))} +
+
+ )} + + {service.buttonText ?? "Learn More"} + +
+
+ + {service.imageTitle +
+ {service.category} +

+ {service.imageTitle || service.title} +

+
+
+ +
+
+
+ ))} +
+
+ ); +} diff --git a/src/theme/conversion/components/cdservices/sanity-query.ts b/src/theme/conversion/components/cdservices/sanity-query.ts index 1924fae..d34753b 100644 --- a/src/theme/conversion/components/cdservices/sanity-query.ts +++ b/src/theme/conversion/components/cdservices/sanity-query.ts @@ -27,6 +27,13 @@ export function query(pageAndComponentCombo: PageAndSingleComponentDetails): str url } } + serviceLinks { + name + } + category + imageTitle + buttonText + buttonUrl } globalComponentSource { __typename @@ -77,6 +84,13 @@ export function query(pageAndComponentCombo: PageAndSingleComponentDetails): str url } } + serviceLinks { + name + } + category + imageTitle + buttonText + buttonUrl } globalComponentSource { __typename diff --git a/src/theme/conversion/components/cdservices/sanity-schema.ts b/src/theme/conversion/components/cdservices/sanity-schema.ts index 29a873c..19a7b1a 100644 --- a/src/theme/conversion/components/cdservices/sanity-schema.ts +++ b/src/theme/conversion/components/cdservices/sanity-schema.ts @@ -1,6 +1,19 @@ import { defineField, defineType } from 'sanity' import { EyeOpenIcon } from '@sanity/icons' +export const serviceLink = defineType({ + name: 'serviceLink', + title: 'Service Link', + type: 'object', + fields: [ + defineField({ + name: 'name', + title: 'Name', + type: 'string' + }) + ] +}) + export const serviceItem = defineType({ name: 'serviceItem', title: 'Service Item', @@ -25,9 +38,37 @@ export const serviceItem = defineType({ } }), defineField({ - name: 'link', - title: 'Link', - type: 'url' + name: 'serviceLinks', + title: 'Service Links', + type: 'array', + of: [ + { + type: 'serviceLink' + } + ] + }), + defineField({ + name: 'category', + title: 'Category', + type: 'string', + description: 'e.g: Featured case study' + }), + defineField({ + name: 'imageTitle', + title: 'Image Title', + type: 'string' + }), + defineField({ + name: 'buttonText', + title: 'Button Text', + type: 'string', + initialValue: 'Learn more' + }), + defineField({ + name: 'buttonUrl', + title: 'Button URL', + type: 'string', + description: 'URL for the button', }) ] }) @@ -46,6 +87,7 @@ export default defineType({ list: [ { title: 'Default', value: 'default' }, { title: 'Demo', value: 'xDemo' }, + { title: 'Feature Blocks', value: 'featureBlocks' }, ] } }), diff --git a/src/theme/conversion/components/cdservicestats/classification.ts b/src/theme/conversion/components/cdservicestats/classification.ts deleted file mode 100644 index f1f4872..0000000 --- a/src/theme/conversion/components/cdservicestats/classification.ts +++ /dev/null @@ -1 +0,0 @@ -export default ["cdservicestats", "servicestats", "cdservicestats"] diff --git a/src/theme/conversion/components/cdservicestats/components/index.tsx b/src/theme/conversion/components/cdservicestats/components/index.tsx deleted file mode 100644 index 4dd3aca..0000000 --- a/src/theme/conversion/components/cdservicestats/components/index.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import { componentBoilerPlate } from "@conversiondigital/headless-basics-data/src/component-tools/componentBoilerPlate"; -import { ViewComponentProps } from "@conversiondigital/headless-basics-data/src/interfaces"; -import { getLogger, logPrefix } from "@conversiondigital/headless-basics-data/src"; -import CdservicestatsDefaultVariant from './variants/cdservicestatsDefaultVariant'; - -export const log = getLogger("conversion.components.cdservicestats"); - -export default function CdservicestatsUI(dynamicComponent: ViewComponentProps) { - const { variant, matchingData } = componentBoilerPlate(dynamicComponent); - if (!matchingData) return null; - - log.trace(`${logPrefix()} cdservicestatsUI started, matchingData: ${JSON.stringify(matchingData)}`); - - switch (variant) { - case 'default': - default: - return ; - } -} \ No newline at end of file diff --git a/src/theme/conversion/components/cdservicestats/sanity-schema.ts b/src/theme/conversion/components/cdservicestats/sanity-schema.ts deleted file mode 100644 index 62ccd54..0000000 --- a/src/theme/conversion/components/cdservicestats/sanity-schema.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { defineField, defineType } from 'sanity' -import { BarChartIcon } from '@sanity/icons' - -export default defineType({ - name: 'cdservicestats', - title: 'Service Statistics (CD)', - type: 'object', - icon: BarChartIcon, - fields: [ - defineField({ - name: 'selectableVariant', - title: 'Selectable Variant', - type: 'string', - options: { - list: [ - { title: 'Default', value: 'default' } - ] - } - }), - defineField({ - name: 'stats', - title: 'Statistics', - type: 'array', - of: [ - { - type: 'object', - title: 'Statistic', - fields: [ - { - name: 'value', - title: 'Value', - type: 'string', - description: 'The statistical value to display (e.g., "93%", "5.14")' - }, - { - name: 'description', - title: 'Description', - type: 'string', - description: 'The description of what the statistic represents' - } - ] - } - ], - }), - defineField({ - name: 'sortOrder', - title: 'Sort Order', - type: 'number' - }), - defineField({ - name: 'globalComponentSource', - title: 'Global Component Source', - type: 'reference', - to: [{ type: 'cdservicestats' }], - description: 'Select a global re-usable service statistics component.' - }) - ], -}) \ No newline at end of file diff --git a/src/theme/conversion/components/cdstatistics/classification.ts b/src/theme/conversion/components/cdstatistics/classification.ts new file mode 100644 index 0000000..e4e1dc7 --- /dev/null +++ b/src/theme/conversion/components/cdstatistics/classification.ts @@ -0,0 +1 @@ +export default ["cdstatistics", "statistics"] diff --git a/src/theme/conversion/components/cdstatistics/components/index.tsx b/src/theme/conversion/components/cdstatistics/components/index.tsx new file mode 100644 index 0000000..93a160b --- /dev/null +++ b/src/theme/conversion/components/cdstatistics/components/index.tsx @@ -0,0 +1,46 @@ +import React from "react"; +import { componentBoilerPlate } from "@conversiondigital/headless-basics-data/src/component-tools/componentBoilerPlate"; +import { ViewComponentProps } from "@conversiondigital/headless-basics-data/src/interfaces"; +import { getLogger, logPrefix } from "@conversiondigital/headless-basics-data/src"; +import CdStatisticsDefaultVariant from "./variants/CdStatisticsDefaultVariant"; + +export const log = getLogger("conversion.components.cdstatistics"); + +// Interface for individual statistic item +export interface StatisticItem { + value: string; + description: string; +} + +// Interface for global component source +interface GlobalComponentSource { + __typename: string; + _key: string; + _type: string; + stats: StatisticItem[]; +} + +// Interface for CdStatistics component data +export interface CdStatisticsData { + __typename: string; + _key: string; + _type: string; + selectableVariant: string; + title?: string; + stats: StatisticItem[]; + sortOrder: number; + globalComponentSource?: GlobalComponentSource; +} + +export default function CdStatisticsUI(dynamicComponent: ViewComponentProps) { + const { variant, matchingData } = componentBoilerPlate(dynamicComponent); + if (!matchingData) return null; + + log.trace(`${logPrefix()} CdStatisticsUI started, matchingData: ${JSON.stringify(matchingData)}`); + + switch (variant) { + case "default": + default: + return ; + } +} \ No newline at end of file diff --git a/src/theme/conversion/components/cdservicestats/components/variants/cdservicestatsDefaultVariant.tsx b/src/theme/conversion/components/cdstatistics/components/variants/CdStatisticsDefaultVariant.tsx similarity index 52% rename from src/theme/conversion/components/cdservicestats/components/variants/cdservicestatsDefaultVariant.tsx rename to src/theme/conversion/components/cdstatistics/components/variants/CdStatisticsDefaultVariant.tsx index 47fa4a5..5033835 100644 --- a/src/theme/conversion/components/cdservicestats/components/variants/cdservicestatsDefaultVariant.tsx +++ b/src/theme/conversion/components/cdstatistics/components/variants/CdStatisticsDefaultVariant.tsx @@ -1,22 +1,22 @@ -import React from 'react'; +import React from "react"; import { StandardComponentProps } from "@conversiondigital/headless-basics-components/src/interfaces/standardComponentProps"; +import { CdStatisticsData, StatisticItem } from "../index"; -interface Stat { - value: string; - description: string; +interface CdStatisticsDefaultVariantProps extends StandardComponentProps { + matchingData: CdStatisticsData; } -const CdservicestatsDefaultVariant: React.FC = ({ matchingData }) => { +const CdStatisticsDefaultVariant: React.FC = ({ matchingData }) => { const stats = matchingData?.stats || []; return ( -
+
- {stats.map((stat: Stat, index: number) => ( + {stats.map((stat: StatisticItem, index: number) => (
-
{stat.value}
-
{stat.description}
+
{stat.value}
+
{stat.description}
))}
@@ -25,4 +25,4 @@ const CdservicestatsDefaultVariant: React.FC = ({ matchi ); }; -export default CdservicestatsDefaultVariant; \ No newline at end of file +export default CdStatisticsDefaultVariant; \ No newline at end of file diff --git a/src/theme/conversion/components/cdserviceofferings/index.ts b/src/theme/conversion/components/cdstatistics/index.ts similarity index 74% rename from src/theme/conversion/components/cdserviceofferings/index.ts rename to src/theme/conversion/components/cdstatistics/index.ts index 53eb50b..e116827 100644 --- a/src/theme/conversion/components/cdserviceofferings/index.ts +++ b/src/theme/conversion/components/cdstatistics/index.ts @@ -2,10 +2,10 @@ import { getLogger, getThemeConfig } from "@conversiondigital/headless-basics-da import { View } from "./view"; import { ThemeConfig } from "@conversiondigital/headless-basics-data/src/interfaces" -getLogger("theme.components.cdserviceofferings") +getLogger("theme.components.cdstatistics") async function getConfig(): Promise { - const config = await getThemeConfig('cdserviceofferings'); + const config = await getThemeConfig('cdstatistics'); config.view = View; return config; } diff --git a/src/theme/conversion/components/cdservicestats/sanity-mapping.ts b/src/theme/conversion/components/cdstatistics/sanity-mapping.ts similarity index 78% rename from src/theme/conversion/components/cdservicestats/sanity-mapping.ts rename to src/theme/conversion/components/cdstatistics/sanity-mapping.ts index 34a4002..4f87e81 100644 --- a/src/theme/conversion/components/cdservicestats/sanity-mapping.ts +++ b/src/theme/conversion/components/cdstatistics/sanity-mapping.ts @@ -1,7 +1,7 @@ import { getLogger, logPrefix, PageAndSingleComponentDetails } from "@conversiondigital/headless-basics-data/src" import { extractComponentsFromSanityData } from "@conversiondigital/headless-basics-data/src/cms/sanity/sanityMappingUtils" -export const log = getLogger("conversion.components.sanity.cdservicestats.mapping") +export const log = getLogger("conversion.components.sanity.cdstatistics.mapping") export async function mapIdentifierData(pageAndComponentCombo: PageAndSingleComponentDetails) { log.trace( @@ -9,8 +9,8 @@ export async function mapIdentifierData(pageAndComponentCombo: PageAndSingleComp ); const content = pageAndComponentCombo?.component?.data - // The second arg 'cdservicestats' must match the name in cdservicestats's sanity-schema - const matchingData = extractComponentsFromSanityData(content, "cdservicestats", log); + // The second arg 'cdstatistics' must match the name in cdstatistics's sanity-schema + const matchingData = extractComponentsFromSanityData(content, "cdstatistics", log); return matchingData } diff --git a/src/theme/conversion/components/cdservicestats/sanity-query.ts b/src/theme/conversion/components/cdstatistics/sanity-query.ts similarity index 89% rename from src/theme/conversion/components/cdservicestats/sanity-query.ts rename to src/theme/conversion/components/cdstatistics/sanity-query.ts index 8e2501c..2ecb493 100644 --- a/src/theme/conversion/components/cdservicestats/sanity-query.ts +++ b/src/theme/conversion/components/cdstatistics/sanity-query.ts @@ -2,11 +2,11 @@ import { PageAndSingleComponentDetails } from "@conversiondigital/headless-basic export function query(pageAndComponentCombo: PageAndSingleComponentDetails): string { return ` - query GetCdservicestatsBySlug($slug: String!) { + query GetCdStatisticsBySlug($slug: String!) { allPage(where: { slug: { current: { eq: $slug } } }) { components { __typename - ... on Cdservicestats { + ... on Cdstatistics { __typename _key _type @@ -28,10 +28,10 @@ export function query(pageAndComponentCombo: PageAndSingleComponentDetails): str } } } - allServicePage { + allHomepage { components { __typename - ... on Cdservicestats { + ... on Cdstatistics { __typename _key _type diff --git a/src/theme/conversion/components/cdstatistics/sanity-schema.ts b/src/theme/conversion/components/cdstatistics/sanity-schema.ts new file mode 100644 index 0000000..b20816e --- /dev/null +++ b/src/theme/conversion/components/cdstatistics/sanity-schema.ts @@ -0,0 +1,79 @@ +import { defineField, defineType } from 'sanity' +import { BarChartIcon } from '@sanity/icons' + +// Define a separate type for the statistic object +export const cdStatisticItem = defineType({ + name: 'cdStatisticItem', + title: 'Statistic Item', + type: 'object', + fields: [ + defineField({ + name: 'value', + title: 'Value', + type: 'string', + description: 'The statistical value to display (e.g., "93%", "5.14")' + }), + defineField({ + name: 'description', + title: 'Description', + type: 'string', + description: 'The description of what the statistic represents' + }) + ], + preview: { + select: { + title: 'value', + subtitle: 'description' + } + } +}) + +export default defineType({ + name: 'cdstatistics', + title: 'Statistics (CD)', + type: 'object', + icon: BarChartIcon, + fields: [ + defineField({ + name: 'selectableVariant', + title: 'Selectable Variant', + type: 'string', + options: { + list: [ + { title: 'Default', value: 'default' } + ] + } + }), + defineField({ + name: 'title', + title: 'Title', + type: 'string', + description: 'The title of the statistics component' + }), + defineField({ + name: 'stats', + title: 'Statistics', + type: 'array', + of: [ + { type: 'cdStatisticItem' } + ], + }), + defineField({ + name: 'sortOrder', + title: 'Sort Order', + type: 'number' + }), + defineField({ + name: 'globalComponentSource', + title: 'Global Component Source', + type: 'reference', + to: [{ type: 'cdstatistics' }], + description: 'Select a global re-usable service statistics component.' + }) + ], + preview: { + select: { + title: 'title', + } + } +}) \ No newline at end of file diff --git a/src/theme/conversion/components/cdserviceofferings/view.tsx b/src/theme/conversion/components/cdstatistics/view.tsx similarity index 65% rename from src/theme/conversion/components/cdserviceofferings/view.tsx rename to src/theme/conversion/components/cdstatistics/view.tsx index 7fcc2c2..fa048e0 100644 --- a/src/theme/conversion/components/cdserviceofferings/view.tsx +++ b/src/theme/conversion/components/cdstatistics/view.tsx @@ -2,10 +2,10 @@ import { ViewComponentProps } from "@conversiondigital/headless-basics-data/src"; import dynamic from "next/dynamic" -const CdserviceofferingsUI = dynamic(() => import("./components"), { +const CdStatisticsUI = dynamic(() => import("./components"), { loading: () => (

Loading...

) }); export async function View(dynamicComponent: ViewComponentProps) { - return + return } diff --git a/src/theme/conversion/components/herobanner/components/index.tsx b/src/theme/conversion/components/herobanner/components/index.tsx index af66077..bb1701a 100644 --- a/src/theme/conversion/components/herobanner/components/index.tsx +++ b/src/theme/conversion/components/herobanner/components/index.tsx @@ -4,16 +4,23 @@ import type { ViewComponentProps } from "@conversiondigital/headless-basics-data import { getLogger, logPrefix } from "@conversiondigital/headless-basics-data/src" import DemoVariant from "./variants/demoVariant" import DefaultVariant from "./variants/defaultVariant" +import IntroductionVariant from "./variants/IntroductionVariant" +import TitleOnlyVariant from "./variants/TitleOnlyVariant" export const log = getLogger("default.components.heartcore.template.variants"); export default function TemplateUI(dynamicComponent: ViewComponentProps) { const { variant, matchingData } = componentBoilerPlate(dynamicComponent); + if (!matchingData) return null; log.trace(`${logPrefix} TemplateUI started, matchingData: ${JSON.stringify(matchingData)}`); switch (variant) { case "xDemo": return ; + case "title-only": + return ; + case "introduction": + return ; default: return ; } diff --git a/src/theme/conversion/components/herobanner/components/variants/IntroductionVariant.tsx b/src/theme/conversion/components/herobanner/components/variants/IntroductionVariant.tsx new file mode 100644 index 0000000..49d7e3c --- /dev/null +++ b/src/theme/conversion/components/herobanner/components/variants/IntroductionVariant.tsx @@ -0,0 +1,18 @@ +import { StandardComponentProps } from "@conversiondigital/headless-basics-components/src/interfaces/standardComponentProps"; + +export default function IntroductionVariant(props: StandardComponentProps) { + const { matchingData } = props; + const { title, subtitle, category } = matchingData; + + return ( +
+
+
+ {category} +

{title}

+

{subtitle}

+
+
+
+ ); +} diff --git a/src/theme/conversion/components/herobanner/components/variants/TitleOnlyVariant.tsx b/src/theme/conversion/components/herobanner/components/variants/TitleOnlyVariant.tsx new file mode 100644 index 0000000..438f241 --- /dev/null +++ b/src/theme/conversion/components/herobanner/components/variants/TitleOnlyVariant.tsx @@ -0,0 +1,15 @@ +import { StandardComponentProps } from "@conversiondigital/headless-basics-components/src/interfaces/standardComponentProps"; + +export default function TitleOnlyVariant(props: StandardComponentProps) { + const { matchingData } = props; + const title = matchingData?.title; + return ( +
+
+
+

{title}

+
+
+
+ ); +} diff --git a/src/theme/conversion/components/herobanner/sanity-mapping.ts b/src/theme/conversion/components/herobanner/sanity-mapping.ts index f3c1273..33380fd 100644 --- a/src/theme/conversion/components/herobanner/sanity-mapping.ts +++ b/src/theme/conversion/components/herobanner/sanity-mapping.ts @@ -11,6 +11,6 @@ export async function mapIdentifierData(pageAndComponentCombo: PageAndSingleComp const content = pageAndComponentCombo?.component?.data; const thisComponentsOrder = pageAndComponentCombo?.component?.sortOrder ?? 0; log.trace(`${logPrefix()} thisComponentsOrder: ${thisComponentsOrder}`); - const matchingData = extractComponentsFromSanityData(content, "herobanner", log, true, '', thisComponentsOrder); + const matchingData = extractComponentsFromSanityData(content, "herobanner", log); return matchingData; } \ No newline at end of file diff --git a/src/theme/conversion/components/herobanner/sanity-query.ts b/src/theme/conversion/components/herobanner/sanity-query.ts index 8f1a37c..61ab47b 100644 --- a/src/theme/conversion/components/herobanner/sanity-query.ts +++ b/src/theme/conversion/components/herobanner/sanity-query.ts @@ -14,6 +14,7 @@ export function query(pageAndComponentCombo: PageAndSingleComponentDetails): str selectableVariant title subtitle + category image { asset { url @@ -31,6 +32,7 @@ export function query(pageAndComponentCombo: PageAndSingleComponentDetails): str _type title subtitle + category image { asset { url @@ -55,6 +57,7 @@ export function query(pageAndComponentCombo: PageAndSingleComponentDetails): str selectableVariant title subtitle + category image { asset { url @@ -72,6 +75,7 @@ export function query(pageAndComponentCombo: PageAndSingleComponentDetails): str _type title subtitle + category image { asset { url diff --git a/src/theme/conversion/components/herobanner/sanity-schema.ts b/src/theme/conversion/components/herobanner/sanity-schema.ts index 0955911..76211b8 100644 --- a/src/theme/conversion/components/herobanner/sanity-schema.ts +++ b/src/theme/conversion/components/herobanner/sanity-schema.ts @@ -13,6 +13,8 @@ export default defineType({ type: 'string', options: { list: [ + { title: 'Title Only', value: 'title-only' }, + { title: 'Introduction', value: 'introduction' }, { title: 'Default', value: 'default' }, { title: 'Demo', value: 'xDemo' }, ] @@ -28,6 +30,12 @@ export default defineType({ title: 'Subtitle', type: 'string', }), + defineField({ + name: 'category', + title: 'Category', + description: 'e.g: Services, About Us, etc.', + type: 'string', + }), defineField({ name: 'image', title: 'Image', diff --git a/src/theme/conversion/index.ts b/src/theme/conversion/index.ts index 98908ef..7ec25c3 100644 --- a/src/theme/conversion/index.ts +++ b/src/theme/conversion/index.ts @@ -14,6 +14,6 @@ export { default as cdclients } from "./components/cdclients/index"; // Insert cdcta export { default as cdcta } from "./components/cdcta/index"; // New service page components -export { default as cdserviceintro } from "./components/cdserviceintro/index"; -export { default as cdservicestats } from "./components/cdservicestats/index"; -export { default as cdserviceofferings } from "./components/cdserviceofferings/index"; \ No newline at end of file +export { default as cdintroduction } from "./components/cdintroduction/index"; +export { default as cdstatistics } from "./components/cdstatistics/index"; +export { default as cdfaqs } from "./components/cdfaqs/index"; \ No newline at end of file diff --git a/src/theme/conversion/structures/servicepage/sanity-mapping.ts b/src/theme/conversion/structures/servicepage/sanity-mapping.ts deleted file mode 100644 index ad50988..0000000 --- a/src/theme/conversion/structures/servicepage/sanity-mapping.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { getLogger, logPrefix, PageAndSingleComponentDetails } from "@conversiondigital/headless-basics-data/src"; -import { extractComponentsFromSanityData } from "@conversiondigital/headless-basics-data/src/cms/sanity/sanityMappingUtils"; - -export const log = getLogger("conversion.structures.sanity.servicepage.mapping"); - -export async function mapIdentifierData(pageAndComponentCombo: PageAndSingleComponentDetails) { - log.trace( - `${logPrefix()}[${pageAndComponentCombo.component.identifier}][${pageAndComponentCombo.page.source}][${pageAndComponentCombo.page.preliminarySlug}] mapIdentifierData started` - ); - - const content = pageAndComponentCombo?.component?.data; - const servicePage = content?.allServicePage && Array.isArray(content.allServicePage) ? content.allServicePage[0] : null; - - if (!servicePage) { - log.warn(`${logPrefix()} No ServicePage data found`); - return null; - } - - // Find the components by type - const serviceIntroComponent = servicePage.components?.find((comp: any) => comp.__typename === 'Cdserviceintro'); - const serviceStatsComponent = servicePage.components?.find((comp: any) => comp.__typename === 'Cdservicestats'); - const serviceOfferingsComponent = servicePage.components?.find((comp: any) => comp.__typename === 'Cdserviceofferings'); - const serviceDetailComponent = servicePage.components?.find((comp: any) => comp.__typename === 'Cdservicedetail'); - - // Process the service intro component - let serviceIntroData = null; - if (serviceIntroComponent) { - const hasGlobal = serviceIntroComponent.globalComponentSource; - serviceIntroData = { - title: serviceIntroComponent.title || (hasGlobal?.title || ''), - content: serviceIntroComponent.content || (hasGlobal?.content || ''), - selectableVariant: serviceIntroComponent.selectableVariant || (hasGlobal?.selectableVariant || 'default') - }; - } - - // Process the service stats component - let serviceStatsData = null; - if (serviceStatsComponent) { - const hasGlobal = serviceStatsComponent.globalComponentSource; - serviceStatsData = { - stats: serviceStatsComponent.stats && serviceStatsComponent.stats.length > 0 - ? serviceStatsComponent.stats - : (hasGlobal?.stats || []), - selectableVariant: serviceStatsComponent.selectableVariant || (hasGlobal?.selectableVariant || 'default') - }; - } - - // Process the service offerings component - let serviceOfferingsData = null; - if (serviceOfferingsComponent) { - const hasGlobal = serviceOfferingsComponent.globalComponentSource; - serviceOfferingsData = { - title: serviceOfferingsComponent.title || (hasGlobal?.title || ''), - intro: serviceOfferingsComponent.intro || (hasGlobal?.intro || ''), - offerings: serviceOfferingsComponent.offerings && serviceOfferingsComponent.offerings.length > 0 - ? serviceOfferingsComponent.offerings.map((offering: any) => ({ - title: offering.title, - icon: offering.icon, - id: offering.id?.current - })) - : (hasGlobal?.offerings?.map((offering: any) => ({ - title: offering.title, - icon: offering.icon, - id: offering.id?.current - })) || []), - selectableVariant: serviceOfferingsComponent.selectableVariant || (hasGlobal?.selectableVariant || 'default') - }; - } - - // Process the service detail component - let serviceDetailData = null; - if (serviceDetailComponent) { - const hasGlobal = serviceDetailComponent.globalComponentSource; - serviceDetailData = { - services: serviceDetailComponent.services && serviceDetailComponent.services.length > 0 - ? serviceDetailComponent.services.map((service: any) => ({ - title: service.title, - id: service.id?.current, - content: service.content - })) - : (hasGlobal?.services?.map((service: any) => ({ - title: service.title, - id: service.id?.current, - content: service.content - })) || []), - selectableVariant: serviceDetailComponent.selectableVariant || (hasGlobal?.selectableVariant || 'default') - }; - } - - return { - serviceIntroData, - serviceStatsData, - serviceOfferingsData, - serviceDetailData, - defaultActiveServiceId: serviceOfferingsData?.offerings?.[0]?.id - }; -} \ No newline at end of file diff --git a/src/theme/conversion/structures/servicepage/sanity-query.ts b/src/theme/conversion/structures/servicepage/sanity-query.ts deleted file mode 100644 index 8631c23..0000000 --- a/src/theme/conversion/structures/servicepage/sanity-query.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { getLogger, logPrefix, PageAndSingleComponentDetails } from "@conversiondigital/headless-basics-data/src"; - -export const log = getLogger("conversion.structures.sanity.servicepage.query"); - -export function query(pageAndComponentCombo: PageAndSingleComponentDetails) { - log.info(`${logPrefix()}[servicepage][sanity-query][query] called for slug: ${pageAndComponentCombo?.page?.preliminarySlug}`); - - return ` - query GetServicePageBySlug($slug: String!) { - allServicePage(where: { slug: { current: { eq: $slug } } }) { - title - slug { - current - } - components { - __typename - ... on Cdserviceintro { - __typename - _key - _type - selectableVariant - title - content - sortOrder - globalComponentSource { - __typename - _key - _type - title - content - } - } - ... on Cdservicestats { - __typename - _key - _type - selectableVariant - stats { - value - description - } - sortOrder - globalComponentSource { - __typename - _key - _type - stats { - value - description - } - } - } - ... on Cdserviceofferings { - __typename - _key - _type - selectableVariant - title - intro - offerings { - title - icon - id { - current - } - } - sortOrder - globalComponentSource { - __typename - _key - _type - title - intro - offerings { - title - icon - id { - current - } - } - } - } - ... on Cdservicedetail { - __typename - _key - _type - selectableVariant - services { - title - id { - current - } - content - } - sortOrder - globalComponentSource { - __typename - _key - _type - services { - title - id { - current - } - content - } - } - } - } - } - } - `; -} - -export function getQuery() { - return query; -} \ No newline at end of file diff --git a/src/theme/conversion/styles/globals.css b/src/theme/conversion/styles/globals.css index f957ed0..06f7e53 100644 --- a/src/theme/conversion/styles/globals.css +++ b/src/theme/conversion/styles/globals.css @@ -35,6 +35,13 @@ background-color: var(--off-white); } +@theme { + --color-primary-bg: #0d0e47; + --color-accent: #800928; + --font-staatliches: var(--font-staatliches); + --font-figtree: var(--font-figtree); +} + :root { --color-primary-bg: #0D0E47; --color-primary-text: white; @@ -329,20 +336,20 @@ nav { } -.contentServiceIntroWrapper { +.contentIntroductionWrapper { color: #0d0e47; } -.contentServiceIntroWrapper p{ +.contentIntroductionWrapper p{ margin-top: 30px; color: #0d0e47; font-family: var(--font-figtree); } -.contentServiceIntroWrapper p:first-child, .contentServiceIntroWrapper h3:first-child{ +.contentIntroductionWrapper p:first-child, .contentIntroductionWrapper h3:first-child{ margin-top: 0; } -.contentServiceIntroWrapper h3{ +.contentIntroductionWrapper h3{ margin-top: 53px; margin-bottom: 22px; font-size: 30px; @@ -351,7 +358,7 @@ nav { color: #0d0e47; } -.contentServiceOfferingsWrapper { +.contentFaqsWrapper { color: white; font-family: var(--font-figtree); font-size: 18px; @@ -359,7 +366,7 @@ nav { font-weight: 500; } -.contentServiceOfferingsWrapper p{ +.contentFaqsWrapper p{ margin-top: 30px; color: white; font-family: var(--font-figtree); @@ -368,7 +375,7 @@ nav { font-weight: 500; } -.contentServiceOfferingsWrapper ul { +.contentFaqsWrapper ul { list-style: initial; font-size: 18px; line-height: 36px; @@ -376,11 +383,11 @@ nav { margin-left: 30px; } -.contentServiceOfferingsWrapper p:first-child, .contentServiceOfferingsWrapper h3:first-child{ +.contentFaqsWrapper p:first-child, .contentFaqsWrapper h3:first-child{ margin-top: 0; } -.contentServiceOfferingsWrapper h3, .contentServiceOfferingsWrapper h2{ +.contentFaqsWrapper h3, .contentFaqsWrapper h2{ margin-top: 53px; margin-bottom: 22px; font-size: 30px; diff --git a/src/theme/conversion/tailwind.config.js b/src/theme/conversion/tailwind.config.js index f5efe47..89c17c8 100644 --- a/src/theme/conversion/tailwind.config.js +++ b/src/theme/conversion/tailwind.config.js @@ -6,22 +6,22 @@ module.exports = { "pages/**/*.{ts,tsx}", "theme/**/*.{ts,tsx}", "./app/**/*.{ts,tsx}", - + "./node_modules/@conversiondigital/headless-basics-components/src/components/**/*.{ts,tsx}", "./../headless-basics-components/src/components/**/*.{ts,tsx}", "../../node_modules/@conversiondigital/headless-basics-components/src/components/**/*.{ts,tsx}", "./../../../headless-basics-components/src/components/**/*.{ts,tsx}", - + "./node_modules/@conversiondigital/headless-basics-components/src/theme/default/**/*.{ts,tsx}", "./../headless-basics-components/src/theme/default/**/*.{ts,tsx}", "../../node_modules/@conversiondigital/headless-basics-components/src/theme/default/**/*.{ts,tsx}", "./../../../headless-basics-components/src/theme/default/**/*.{ts,tsx}", - + "./node_modules/@conversiondigital/headless-basics-components/src/theme/conversion/**/*.{ts,tsx}", "./../headless-basics-components/src/theme/conversion/**/*.{ts,tsx}", "../../node_modules/@conversiondigital/headless-basics-components/src/theme/conversion/**/*.{ts,tsx}", "./../../../headless-basics-components/src/theme/conversion/**/*.{ts,tsx}", - './src/**/*.{js,jsx,ts,tsx}' + "./src/**/*.{js,jsx,ts,tsx}", ], colors: { black45: "var(--black-45)", @@ -71,13 +71,17 @@ module.exports = { DEFAULT: "#FACF41", light: "#FFE799", }, - "body-color": "#0d0e47", + "body-color": "var(--body-color)", + "primary-bg": "var(--color-primary-bg)", + accent: "var(--color-accent)", }, backgroundImage: { "gradient-dark": "linear-gradient(277deg, #171717 55.29%, #3D3D3D 98.19%)", }, fontFamily: { helvetica: ["var(--font-helvetica)", ...fontFamily.sans], + staatliches: ["var(--font-staatliches)", ...fontFamily.sans], + figtree: ["var(--font-figtree)", ...fontFamily.sans], }, fontSize: { h1: "60px",