diff --git a/config/nam.3bear.design.json b/config/nam.3bear.design.json index e9c9da9..496fa98 100644 --- a/config/nam.3bear.design.json +++ b/config/nam.3bear.design.json @@ -177,6 +177,36 @@ ] } }, + { + "Hero": { + "config": { + "className": "h-[35rem]", + "ImageDisplayer": { + "config": { + "duration": 0, + "images": ["./banner-hero.webp"], + "links": ["/account"] + } + }, + "left": [ + { + "VtCtaBanner": { + "config": { + "className": "left-[120px] top-[80px] relative w-full p-12 flex flex-col items-start justify-center text-left bg-transperant border-none shadow-none", + "buttonTextClassName": "inline-flex items-center justify-center bg-[#FCEE56] hover:bg-[#FCEE56]/90 text-[#0D382E] px-8 py-3 rounded-full font-bold text-lg shadow-none border-none", + "tagTextClassName": "text-[#0D382E] text-lg font-medium mb-2 bg-transparent", + "tagText": "So einfach kann Frühstück sein – mit unseren leckeren Overnight Oats.", + "titleText": "breakfast made easy.", + "buttonText": "Jetzt entdecken" + } + } + } + ], + "center": [], + "right": [] + } + } + }, { "CartMismatchBanner": { "config": { @@ -213,10 +243,26 @@ "emailInputClassName": "w-[300px] ml-8" }, "socials": [ - { "icon": "Twitter", "href": "/", "className": "w-5 h-5 text-white" }, - { "icon": "Twitter", "href": "/", "className": "w-5 h-5 text-white" }, - { "icon": "Twitter", "href": "/", "className": "w-5 h-5 text-white" }, - { "icon": "Twitter", "href": "/", "className": "w-5 h-5 text-white" } + { + "icon": "Twitter", + "href": "/", + "className": "w-5 h-5 text-white" + }, + { + "icon": "Twitter", + "href": "/", + "className": "w-5 h-5 text-white" + }, + { + "icon": "Twitter", + "href": "/", + "className": "w-5 h-5 text-white" + }, + { + "icon": "Twitter", + "href": "/", + "className": "w-5 h-5 text-white" + } ], "socialsClassName": "ml-8 mt-10", "className": "", @@ -311,15 +357,22 @@ "config": { "className": "content-container bg-[#003f31] w-full text text-[#11314E] flex items-center justify-between", "leftClassName": "w-full", - "left": [ - ], + "left": [], "center": [], "right": [ { "VtFooterBottom": { "config": { "className": " mr-[80px]", - "icons": ["Mastercard", "PayPal", "Visa", "Mastercard","Mastercard","Mastercard","Mastercard"] + "icons": [ + "Mastercard", + "PayPal", + "Visa", + "Mastercard", + "Mastercard", + "Mastercard", + "Mastercard" + ] } } } diff --git a/config/nam.drsquatch.design.json b/config/nam.drsquatch.design.json index bcc4e8f..9338061 100644 --- a/config/nam.drsquatch.design.json +++ b/config/nam.drsquatch.design.json @@ -130,6 +130,44 @@ ] } }, + { + "Hero": { + "config": { + "className": "h-[35rem]", + "ImageDisplayer": { + "config": { + "duration": 0, + "images": [ + "./drsquatch-banner.jpg" + ], + "links": [ + "/account" + ] + } + }, + "left": [ + { + "VtCtaBanner": { + "config": { + "variant": "default", + "className": "left-[120px] top-[120px] bg-transparent border-none text-white text-center", + "tagTextClassName": "text-white bg-transparent", + "titleTextClassName": "text-white font-bold leading-normal text-[30px]", + "descriptionTextClassName": "text-white text-[1rem] w-[300px] ml-[6.6rem]", + "buttonTextClassName": "text-white bg-orange-500 w-[300px]", + "tagText": "ALL NEW!", + "titleText": "LUMBERJACK LODGE", + "descriptionText": "Step into the lodge with the warm, sweet scent of maple and vanilla.", + "buttonText": "SHOP NOW" + } + } + } + ], + "center": [], + "right": [] + } + } + }, { "CartMismatchBanner": { "config": { @@ -277,14 +315,30 @@ "buttonClassName": "bg-[#C4622C] w-[90px]", "socialsClassName": "mt-4 gap-8", "socials": [ - { "icon": "Twitter", "href": "/", "className": "w-5 h-5 text-white" }, - { "icon": "Twitter", "href": "/", "className": "w-5 h-5 text-white" }, - { "icon": "Twitter", "href": "/", "className": "w-5 h-5 text-white" }, - { "icon": "Twitter", "href": "/", "className": "w-5 h-5 text-white" } + { + "icon": "Twitter", + "href": "/", + "className": "w-5 h-5 text-white" + }, + { + "icon": "Twitter", + "href": "/", + "className": "w-5 h-5 text-white" + }, + { + "icon": "Twitter", + "href": "/", + "className": "w-5 h-5 text-white" + }, + { + "icon": "Twitter", + "href": "/", + "className": "w-5 h-5 text-white" + } ] } } - } + } ] } } diff --git a/config/nam.mds-starter-design.json b/config/nam.mds-starter-design.json index 292b7ab..9994c23 100644 --- a/config/nam.mds-starter-design.json +++ b/config/nam.mds-starter-design.json @@ -134,6 +134,14 @@ ] } }, + { + "Hero": { + "config": { + "variant": "default", + "className": "bg-custom-gradient" + } + } + }, { "CartMismatchBanner": { "config": { diff --git a/config/nam.vibentec.design.json b/config/nam.vibentec.design.json index 22917f8..f5b610a 100644 --- a/config/nam.vibentec.design.json +++ b/config/nam.vibentec.design.json @@ -176,6 +176,41 @@ ] } }, + { + "Hero": { + "config": { + "className": "h-[35rem]", + "ImageDisplayer": { + "config": { + "duration": 5, + "images": [ + "./banner-hero.webp", + "./banner-hero-1.webp", + "./banner-hero-2.webp" + ], + "links": ["/", "/account", "/product"] + } + }, + "left": [ + { + "VtCtaBanner": { + "config": { + "variant": "default", + "className": "left-[120px] top-[80px]", + "titleTextClassName": "leading-normal", + "tagText": "Besonders Aktion", + "titleText": "Willkommen in Vibentec IT Shop", + "descriptionText": "Insert the accordion description here. It would look better as two lines of text or more.", + "buttonText": "Zum Einkaufen" + } + } + } + ], + "center": [], + "right": [] + } + } + }, { "CartMismatchBanner": { "config": { @@ -209,7 +244,10 @@ "logoAlt": "Vibentec IT", "title": "Der Wegbereiter für innovative IT-Lösungen", "description": "Tauchen Sie ein in eine Welt modernster Technologien, zuverlässiger Support und proaktiver Innovation – gemeinsam gestalten wir die digitale Zukunft Ihres Unternehmens.", - "cta": { "label": "Kontaktieren Sie uns", "href": "/" }, + "cta": { + "label": "Kontaktieren Sie uns", + "href": "/" + }, "className": "", "ctaClassName": "ml-8", "titleClassName": "ml-8", @@ -329,7 +367,11 @@ "VtFooterBottom": { "config": { "text": "©2025 Vibentec IT. All rights reserved", - "icons": ["Mastercard", "PayPal", "Visa"] + "icons": [ + "Mastercard", + "PayPal", + "Visa" + ] } } } diff --git a/package.json b/package.json index 8777bbc..49610ca 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,8 @@ "@radix-ui/react-accordion": "^1.2.1", "@stripe/react-stripe-js": "^1.7.2", "@stripe/stripe-js": "^1.29.0", + "embla-carousel-autoplay": "^8.6.0", + "embla-carousel-react": "^8.6.0", "lodash": "^4.17.21", "next": "^15.3.1", "pg": "^8.11.3", diff --git a/public/banner-hero.webp b/public/banner-hero.webp new file mode 100644 index 0000000..d20c685 Binary files /dev/null and b/public/banner-hero.webp differ diff --git a/public/drsquatch-banner.jpg b/public/drsquatch-banner.jpg new file mode 100644 index 0000000..dae4892 Binary files /dev/null and b/public/drsquatch-banner.jpg differ diff --git a/src/app/[countryCode]/(main)/page.tsx b/src/app/[countryCode]/(main)/page.tsx index 16cc61e..7598b51 100644 --- a/src/app/[countryCode]/(main)/page.tsx +++ b/src/app/[countryCode]/(main)/page.tsx @@ -23,14 +23,17 @@ export default async function Home(props: { const { collections } = await listCollections({ fields: "id, handle, title", }) + const res = await listCollections({ + fields: "id, handle, title", + }) if (!collections || !region) { return null } - + console.log(res, '--------------') return ( <> - + {/* */}
    diff --git a/src/modules/layout/templates/hero/banner-hero.tsx b/src/modules/layout/templates/hero/banner-hero.tsx new file mode 100644 index 0000000..cd9cc14 --- /dev/null +++ b/src/modules/layout/templates/hero/banner-hero.tsx @@ -0,0 +1,45 @@ +import { Github } from "@medusajs/icons" +import { Button, Heading } from "@medusajs/ui" +import { VtCarousel } from "../vt-carousel" +import { LayoutComponentDefinition, LayoutContext } from "vibentec/component-map" + +export default function HeroDefault({ node, context }: { node: LayoutComponentDefinition; context: LayoutContext }) { + const props = node.config ?? {} + const imageDisplayer = props.ImageDisplayer + + if (imageDisplayer) { + return ( +
    + +
    + ) + } + + return ( +
    + + + Ecommerce Starter Template + + + Powered by Medusa and Next.js + + + + + +
    + ) +} diff --git a/src/modules/layout/templates/hero/index.tsx b/src/modules/layout/templates/hero/index.tsx new file mode 100644 index 0000000..3c128e6 --- /dev/null +++ b/src/modules/layout/templates/hero/index.tsx @@ -0,0 +1,45 @@ +import { + LayoutComponentDefinition, + LayoutContext, +} from "vibentec/component-map" +import { clx } from "@medusajs/ui" +import BannerHero from "./banner-hero" +import { DynamicLayoutRenderer } from "vibentec/renderer" + +export default async function Hero({ + nodes, + context, +}: { + nodes: LayoutComponentDefinition + context: LayoutContext +}) { + const props = nodes.config ?? {} + const left = nodes.config?.left ?? [] + const center = nodes.config?.center ?? [] + const right = nodes.config?.right ?? [] + const heroClassName = clx( + "min-h-[30rem] w-full border-b border-ui-border-base relative", + props.className + ) + + return ( +
    + +
    + +
    +
    + ) +} diff --git a/src/modules/layout/templates/vt-carousel/carousel-arrow-button.tsx b/src/modules/layout/templates/vt-carousel/carousel-arrow-button.tsx new file mode 100644 index 0000000..ffb2f1f --- /dev/null +++ b/src/modules/layout/templates/vt-carousel/carousel-arrow-button.tsx @@ -0,0 +1,75 @@ +import React, { useCallback, useEffect, useState } from 'react' +import style from './index.module.css' +export const usePrevNextButtons = (emblaApi: any) => { + const [prevBtnDisabled, setPrevBtnDisabled] = useState(true) + const [nextBtnDisabled, setNextBtnDisabled] = useState(true) + + const onPrevButtonClick = useCallback(() => { + if (!emblaApi) return + emblaApi.scrollPrev() + }, [emblaApi]) + + const onNextButtonClick = useCallback(() => { + if (!emblaApi) return + emblaApi.scrollNext() + }, [emblaApi]) + + const onSelect = useCallback((emblaApi: any) => { + setPrevBtnDisabled(!emblaApi.canScrollPrev()) + setNextBtnDisabled(!emblaApi.canScrollNext()) + }, []) + + useEffect(() => { + if (!emblaApi) return + + onSelect(emblaApi) + emblaApi.on('reInit', onSelect).on('select', onSelect) + }, [emblaApi, onSelect]) + + return { + prevBtnDisabled, + nextBtnDisabled, + onPrevButtonClick, + onNextButtonClick + } +} + +export const PrevButton = (props: any) => { + const { children, ...restProps } = props + + return ( + + ) +} + +export const NextButton = (props: any) => { + const { children, ...restProps } = props + + return ( + + ) +} diff --git a/src/modules/layout/templates/vt-carousel/carousel-dot-button.tsx b/src/modules/layout/templates/vt-carousel/carousel-dot-button.tsx new file mode 100644 index 0000000..271767e --- /dev/null +++ b/src/modules/layout/templates/vt-carousel/carousel-dot-button.tsx @@ -0,0 +1,46 @@ +import React, { useCallback, useEffect, useState } from 'react' + +export const useDotButton = (emblaApi: any) => { + const [selectedIndex, setSelectedIndex] = useState(0) + const [scrollSnaps, setScrollSnaps] = useState([]) + + const onDotButtonClick = useCallback( + (index: number) => { + if (!emblaApi) return + emblaApi.scrollTo(index) + }, + [emblaApi] + ) + + const onInit = useCallback((emblaApi: any) => { + setScrollSnaps(emblaApi.scrollSnapList()) + }, []) + + const onSelect = useCallback((emblaApi: any) => { + setSelectedIndex(emblaApi.selectedScrollSnap()) + }, []) + + useEffect(() => { + if (!emblaApi) return + + onInit(emblaApi) + onSelect(emblaApi) + emblaApi.on('reInit', onInit).on('reInit', onSelect).on('select', onSelect) + }, [emblaApi, onInit, onSelect]) + + return { + selectedIndex, + scrollSnaps, + onDotButtonClick + } +} + +export const DotButton = (props: any) => { + const { children, ...restProps } = props + + return ( + + ) +} diff --git a/src/modules/layout/templates/vt-carousel/index.module.css b/src/modules/layout/templates/vt-carousel/index.module.css new file mode 100644 index 0000000..2dfa1ce --- /dev/null +++ b/src/modules/layout/templates/vt-carousel/index.module.css @@ -0,0 +1,139 @@ +.embla { + width: 100%; + height: 100%; + position: relative; + margin: auto; + --slide-height: 19rem; + --slide-spacing: 1rem; + --slide-size: 100%; +} +.embla__viewport { + height: 100%; + overflow: hidden; +} +.embla__container { + display: flex; + height: 100%; + touch-action: pan-y pinch-zoom; + margin-left: calc(var(--slide-spacing) * -1); + --slide-spacing: 1rem; +} +.embla__slide { + --slide-size: 100%; + --slide-spacing: 1rem; + transform: translate3d(0, 0, 0); + flex: 0 0 var(--slide-size); + min-width: 0; + padding-left: var(--slide-spacing); +} +.embla__slide__number { + height: 100%; + font-size: 4rem; + font-weight: 600; + display: flex; + align-items: center; + justify-content: center; + user-select: none; +} +.embla__slide__image { + width: 100%; + height: 100%; + object-fit: cover; +} +.embla__controls { + display: grid; + position: absolute; + top: 0; + z-index: 1000; + width: 100%; + height: 100%; + grid-template-columns: auto 1fr; + justify-content: space-between; + gap: 1.2rem; +} +.embla__buttons { + position: absolute; + top: 45%; + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + z-index: 1000; +} +.embla__button { + --text-high-contrast-rgb-value: 49, 49, 49; + --detail-high-contrast: rgb(192, 192, 192); + --text-body: rgb(54, 49, 61); + -webkit-tap-highlight-color: rgba(var(--text-high-contrast-rgb-value), 0.5); + -webkit-appearance: none; + appearance: none; + background-color: transparent; + touch-action: manipulation; + text-decoration: none; + cursor: pointer; + border: 0; + padding: 0; + margin: 0; + width: 3.6rem; + height: 3.6rem; + z-index: 1001; + border-radius: 50%; + color: var(--text-body); + display: flex; + align-items: center; + justify-content: center; +} + +.embla__button:disabled { + --detail-high-contrast: rgb(192, 192, 192); + color: var(--detail-high-contrast); +} +.embla__button__svg { + width: 35%; + height: 35%; +} +.embla__dots { + display: flex; + position: absolute; + bottom: 0; + left: 48%; + flex-wrap: wrap; + justify-content: flex-end; + align-items: center; + z-index: 1000; +} +.embla__dot { + --text-high-contrast-rgb-value: 49, 49, 49; + --text-body: rgb(54, 49, 61); + -webkit-tap-highlight-color: rgba(var(--text-high-contrast-rgb-value), 0.5); + -webkit-appearance: none; + appearance: none; + background-color: transparent; + touch-action: manipulation; + text-decoration: none; + cursor: pointer; + border: 0; + padding: 0; + margin: 0; + width: 1.6rem; + height: 1.6rem; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; +} +.embla__dot:after { + --detail-medium-contrast: rgb(234, 234, 234); + --detail-medium-contrast-rgb-value: 234, 234, 234; + box-shadow: inset 0 0 0 0.2rem var(--detail-medium-contrast); + width: 0.42rem; + height: 0.42rem; + border-radius: 50%; + display: flex; + align-items: center; + content: ""; +} +.embla__dot--selected:after { + --text-body: black; + box-shadow: inset 0 0 0 0.2rem var(--text-body); +} diff --git a/src/modules/layout/templates/vt-carousel/index.tsx b/src/modules/layout/templates/vt-carousel/index.tsx new file mode 100644 index 0000000..6744cc3 --- /dev/null +++ b/src/modules/layout/templates/vt-carousel/index.tsx @@ -0,0 +1,92 @@ +"use client" +import { + LayoutComponentDefinition, + LayoutContext, +} from "@vibentec/component-map" +import styles from "./index.module.css" +import useEmblaCarousel from "embla-carousel-react" +import Autoplay from "embla-carousel-autoplay" +import { useMemo } from "react" +import { DotButton, useDotButton } from "./carousel-dot-button" +import { NextButton, PrevButton, usePrevNextButtons } from "./carousel-arrow-button" +import LocalizedClientLink from "@modules/common/components/localized-client-link" + +export function VtCarousel({ + nodes, + context, +}: { + nodes: LayoutComponentDefinition + context: LayoutContext +}) { + const props = nodes.config ?? {} + const { options } = props as any + const images: string[] = props.images ?? props.slides ?? [] + const links: (string | undefined)[] = props.links ?? [] + const durationSeconds: number = props.duration ?? 4 + const showControls = images.length > 1 + + const plugins = useMemo(() => { + if (!durationSeconds || durationSeconds <= 0) return [] + return [ + Autoplay({ + delay: durationSeconds * 1000, + stopOnInteraction: false, + stopOnMouseEnter: true, + }), + ] + }, [durationSeconds]) + + const [emblaRef, emblaApi] = useEmblaCarousel(options, plugins) + const { selectedIndex, scrollSnaps, onDotButtonClick } = + useDotButton(emblaApi) + + const { + prevBtnDisabled, + nextBtnDisabled, + onPrevButtonClick, + onNextButtonClick, + } = usePrevNextButtons(emblaApi) + return ( +
    +
    +
    + {images && images.map((src: string, index: number) => ( +
    +
    + {links[index] ? ( + + {`slide-${index + + ) : ( + {`slide-${index + )} +
    +
    + ))} +
    +
    + + {showControls && ( +
    +
    + + +
    + +
    + {scrollSnaps.map((_, index) => ( + onDotButtonClick(index)} + className={[ + styles["embla__dot"], + index === selectedIndex ? styles["embla__dot--selected"] : "", + ].filter(Boolean).join(" ")} + /> + ))} +
    +
    + )} +
    + ) +} diff --git a/src/modules/layout/templates/vt-country-select/index.tsx b/src/modules/layout/templates/vt-country-select/index.tsx index e492c00..625f6e6 100644 --- a/src/modules/layout/templates/vt-country-select/index.tsx +++ b/src/modules/layout/templates/vt-country-select/index.tsx @@ -23,7 +23,6 @@ export default function VtCountrySelectClient({ const triggerText = props?.trigger?.text const [items, setItems] = useState<{ text: string; label?: string }[]>([]) const { countryCode } = useParams() - console.log(regions) useEffect(() => { if (!regions || regions.length === 0) { setItems([]) @@ -39,7 +38,6 @@ export default function VtCountrySelectClient({ .flat() .filter((o) => o.text) .sort((a, b) => (a.label ?? "").localeCompare(b.label ?? "")) - console.log(opts) setItems(opts) }, [regions]) diff --git a/src/modules/layout/templates/vt-cta-banner/default-cta.tsx b/src/modules/layout/templates/vt-cta-banner/default-cta.tsx new file mode 100644 index 0000000..34e753a --- /dev/null +++ b/src/modules/layout/templates/vt-cta-banner/default-cta.tsx @@ -0,0 +1,68 @@ +"use client" +import { Button, clx } from "@medusajs/ui" +import { ChevronRightMini } from "@medusajs/icons" +import { + LayoutComponentDefinition, + LayoutContext, +} from "@vibentec/component-map" + +export function DefaultCtaBanner({ + nodes, + context, +}: { + nodes: LayoutComponentDefinition + context: LayoutContext +}) { + const props = nodes.config ?? {} + return ( +
    + {props.tagText && ( +
    + {props.tagText} +
    + )} + + {props.titleText && ( +

    + {props.titleText} +

    + )} + + {props.descriptionText && ( +

    + {props.descriptionText} +

    + )} + + +
    + ) +} diff --git a/src/modules/layout/templates/vt-cta-banner/index.tsx b/src/modules/layout/templates/vt-cta-banner/index.tsx new file mode 100644 index 0000000..b9c78cf --- /dev/null +++ b/src/modules/layout/templates/vt-cta-banner/index.tsx @@ -0,0 +1,25 @@ +"use client" +import { + LayoutComponentDefinition, + LayoutContext, +} from "@vibentec/component-map" +import { DefaultCtaBanner } from "./default-cta" + +export function VtCtaBanner({ + nodes, + context, +}: { + nodes: LayoutComponentDefinition + context: LayoutContext +}) { + const props = nodes.config ?? {} + const variant = props.variant ?? "default" + + const variants: Record = { + default: DefaultCtaBanner, + } + + const Component = variants[variant] || DefaultCtaBanner + + return +} diff --git a/src/styles/globals.css b/src/styles/globals.css index 35c79e3..706603e 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -113,4 +113,4 @@ } [data-radix-popper-content-wrapper]{ z-index: 51 !important; -} \ No newline at end of file +} diff --git a/src/vibentec/component-map.tsx b/src/vibentec/component-map.tsx index 4ec8f7e..b1c1dcd 100644 --- a/src/vibentec/component-map.tsx +++ b/src/vibentec/component-map.tsx @@ -22,42 +22,56 @@ import VtFooterHero from "@modules/layout/templates/vt-footer/vt-footer-hero" import VtFooterBottom from "@modules/layout/templates/vt-footer/vt-footer-bottom" import VtLogo from "@modules/layout/templates/vt-logo" import VtFooterSignUp from "@modules/layout/templates/vt-footer/vt-footer-signup" +import Hero from "@modules/layout/templates/hero" +import { VtCarousel } from "@modules/layout/templates/vt-carousel" +import { VtCtaBanner } from "@modules/layout/templates/vt-cta-banner" -type ComponentConfig = Record; +type ComponentConfig = Record export interface LayoutComponentDefinition { config?: ComponentConfig children?: LayoutComponentNode[] } -export interface LayoutContext { - customer: any; - cart: any; - shippingOptions: any[]; - contentChildren: React.ReactNode; +export interface LayoutContext { + customer: any + cart: any + shippingOptions: any[] + contentChildren: React.ReactNode } export type ComponentRenderer = { - render: (entry: LayoutComponentDefinition, ctx: LayoutContext) => React.ReactNode + render: ( + entry: LayoutComponentDefinition, + ctx: LayoutContext + ) => React.ReactNode } // Utility methods -const configOnly = (Component: React.ComponentType): ComponentRenderer => ({ - render: (entry) => +const configOnly = ( + Component: React.ComponentType +): ComponentRenderer => ({ + render: (entry) => , }) -const nodesContextRenderer = (Component: React.ComponentType): ComponentRenderer => ({ - render: (entry: any, ctx: LayoutContext) => -}); +const nodesContextRenderer = ( + Component: React.ComponentType +): ComponentRenderer => ({ + render: (entry: any, ctx: LayoutContext) => ( + + ), +}) const renderChildren = (entry: LayoutComponentDefinition, ctx: LayoutContext) => - entry.children ? : null - + entry.children ? ( + + ) : null // Component Map export const componentMap: Record = { - Header: nodesContextRenderer(VtHeader), + Header: nodesContextRenderer(VtHeader), Nav: nodesContextRenderer(VtNav), + Hero: nodesContextRenderer(Hero), VtMegaMenu: nodesContextRenderer(VtMegaMenu), VtSideMenu: nodesContextRenderer(VtSideMenu), Banner: nodesContextRenderer(Banner), @@ -75,17 +89,20 @@ export const componentMap: Record = { CartMismatchBanner: configOnly(CartMismatchBanner), FreeShippingPriceNudge: configOnly(FreeShippingPriceNudge), PropsChildren: { - render: (_props, ctx) => ctx.contentChildren, // PageLayout's props.children + render: (_props, ctx) => ctx.contentChildren, // PageLayout's props.children }, + VtCtaBanner: nodesContextRenderer(VtCtaBanner), VtFooterHero: nodesContextRenderer(VtFooterHero), VtFooterBottom: nodesContextRenderer(VtFooterBottom), VtFooterSignUp: nodesContextRenderer(VtFooterSignUp), - Footer: nodesContextRenderer(VtFooter) + Footer: nodesContextRenderer(VtFooter), + ImageDisplayer: nodesContextRenderer(VtCarousel), } - export type ComponentName = keyof typeof componentMap // //maps key = componentName to value = props + children // export type LayoutComponentNode = Record -export type LayoutComponentNode = { [K in ComponentName]: LayoutComponentDefinition }[ComponentName] \ No newline at end of file +export type LayoutComponentNode = { + [K in ComponentName]: LayoutComponentDefinition +}[ComponentName] diff --git a/src/vibentec/configloader.ts b/src/vibentec/configloader.ts index 1c18fc4..dd5fbef 100644 --- a/src/vibentec/configloader.ts +++ b/src/vibentec/configloader.ts @@ -2,7 +2,7 @@ import fs from "fs" import path from "path" import { jsonFileNames } from "./devJsonFileNames"; -const fileName = jsonFileNames.nam3Bear; +const fileName = jsonFileNames.namStarter; export async function loadDesignConfig() { const filePath = path.join(process.cwd(), "config", fileName)