diff --git a/config/nam.3bear.design.json b/config/nam.3bear.design.json index 496fa98..ec41a35 100644 --- a/config/nam.3bear.design.json +++ b/config/nam.3bear.design.json @@ -1,383 +1,123 @@ -[ - { - "Header": { - "config": { - "sticky": true, - "variant": "ticker" - }, - "children": [ - { - "Banner": { - "config": { - "variant": "ticker", - "className": "h-12 bg-[#009b93] text-[#fff] gap-12", - "speed": 24, - "items": [ - { - "Link": { - "config": { - "label": "NEU: Overnight Oats – Sallys Nussecke 😍", - "href": "/" - } - } - }, - { - "Link": { - "config": { - "label": "Versandkostenfrei ab 45 € 💛", - "href": "/" - } - } - }, - { - "Link": { - "config": { - "label": "Gratis Geschenk ab 60 € Warenkorbwert 🎁", - "href": "/" - } - } - } - ] +{ + "layout": [ + { + "Header": { + "config": { + "sticky": true, + "variant": "ticker" + }, + "children": [ + { + "Banner": { + "config": { + "variant": "ticker", + "className": "h-12 bg-[#009b93] text-[#fff] gap-12", + "speed": 24, + "items": [ + { "Link": { "config": { "label": "NEU: Overnight Oats – Sallys Nussecke 😍", "href": "/" } } }, + { "Link": { "config": { "label": "Versandkostenfrei ab 45 € 💛", "href": "/" } } }, + { "Link": { "config": { "label": "Gratis Geschenk ab 60 € Warenkorbwert 🎁", "href": "/" } } } + ] + } + } + }, + { + "Nav": { + "config": { + "className": "h-24 bg-white text-[#003F31] gap-12", + "left": [ + { "Logo": { "config": { "src": "/3bear-logo.png", "alt": "MyShop", "className": "h-[150px] w-[180px]", "objectFit": "contain" } } }, + { "VtMegaMenu": { "config": { "navLabel": { "text": "Shop", "className": "font-bold text-[1rem] text-[#003F31] flex items-center mr-8 gap-1 hover:text-[#009b93]", "isShowArrow": true } } } }, + { "Dropdown": { "config": { "trigger": { "text": "Über Uns", "className": "font-bold text-[1rem] text-[#003F31] flex items-center mr-8 gap-1 hover:text-[#009b93]", "isShowArrow": true }, "items": [ { "text": "Unser Unternehmen", "href": "/" }, { "text": "Loren ipsum", "href": "/" }, { "text": "Not a Link" } ] } } }, + { "Dropdown": { "config": { "trigger": { "text": "Über unsere Produkte", "className": "font-bold text-[1rem] text-[#003F31] flex items-center mr-8 gap-1 hover:text-[#009b93]", "isShowArrow": true }, "items": [ { "text": "Unser Unternehmen", "href": "/" }, { "text": "Loren ipsum", "href": "/" }, { "text": "Not a Link" } ] } } }, + { "Link": { "config": { "label": "Rezepte", "href": "/", "className": "font-bold text-[1rem] text-[#003F31] flex items-center mr-8 gap-1 hover:text-[#009b93]" } } }, + { "Link": { "config": { "label": "Triff Harry Kane", "href": "/", "className": "font-bold text-[1rem] text-[#003F31] flex items-center gap-1 hover:text-[#009b93]" } } } + ], + "right": [ + { "VtCountryCodeSelect": { "config": { "trigger": { "className": "w-auto font-bold text-[13px] text-[#11314E] flex justify-start items-center gap-1 hover:text-[#009b93] bg-transparent shadow-none hover:bg-transparent", "isFlag": true, "isDisplayFullname": true } } } }, + { "Button": { "config": { "icon": "MagnifyingGlass", "className": "shadow-none" } } }, + { "AccountButton": { "config": { "icon": "User", "className": " flex items-center gap-1 shadow-none" } } }, + { "VtCartButton": { "config": { "icon": "ShoppingBag", "className": "shadow-none bg-transparent text-black w-[50px]" } } } + ] + } } } - }, - { - "Nav": { - "config": { - "className": "h-24 bg-white text-[#003F31] gap-12", - "left": [ - { - "Logo": { - "config": { - "src": "/3bear-logo.png", - "alt": "MyShop", - "className": "h-[150px] w-[180px]", - "objectFit": "contain" - } - } - }, - { - "VtMegaMenu": { - "config": { - "navLabel": { - "text": "Shop", - "className": "font-bold text-[1rem] text-[#003F31] flex items-center mr-8 gap-1 hover:text-[#009b93]", - "isShowArrow": true - } - } - } - }, - { - "Dropdown": { - "config": { - "trigger": { - "text": "Über Uns", - "className": "font-bold text-[1rem] text-[#003F31] flex items-center mr-8 gap-1 hover:text-[#009b93]", - "isShowArrow": true - }, - "items": [ - { - "text": "Unser Unternehmen", - "href": "/" - }, - { - "text": "Loren ipsum", - "href": "/" - }, - { - "text": "Not a Link" - } - ] - } - } - }, - { - "Dropdown": { - "config": { - "trigger": { - "text": "Über unsere Produkte", - "className": "font-bold text-[1rem] text-[#003F31] flex items-center mr-8 gap-1 hover:text-[#009b93]", - "isShowArrow": true - }, - "items": [ - { - "text": "Unser Unternehmen", - "href": "/" - }, - { - "text": "Loren ipsum", - "href": "/" - }, - { - "text": "Not a Link" - } - ] - } - } - }, - { - "Link": { - "config": { - "label": "Rezepte", - "href": "/", - "className": "font-bold text-[1rem] text-[#003F31] flex items-center mr-8 gap-1 hover:text-[#009b93]" - } - } - }, - { - "Link": { - "config": { - "label": "Triff Harry Kane", - "href": "/", - "className": "font-bold text-[1rem] text-[#003F31] flex items-center gap-1 hover:text-[#009b93]" - } - } - } - ], - "right": [ - { - "VtCountryCodeSelect": { - "config": { - "trigger": { - "className": "w-auto font-bold text-[13px] text-[#11314E] flex justify-start items-center gap-1 hover:text-[#009b93] bg-transparent shadow-none hover:bg-transparent", - "isFlag": true, - "isDisplayFullname": true - } - } - } - }, - { - "Button": { - "config": { - "icon": "MagnifyingGlass", - "className": "shadow-none" - } - } - }, - { - "AccountButton": { - "config": { - "icon": "User", - "className": " flex items-center gap-1 shadow-none" - } - } - }, - { - "VtCartButton": { - "config": { - "icon": "ShoppingBag", - "className": "shadow-none bg-transparent text-black w-[50px]" - } - } - } - ] + ] + } + }, + { "PropsChildren": {} }, + { + "Footer": { + "config": { + "className": "content-container border-none flex w-full bg-[#003f31] text-white border justify-between pb-8 pt-14", + "leftClassName": "flex-col ml-3", + "centerClassName": "", + "rightClassName": "flex gap-[10rem] mr-[80px]", + "left": [ + { "VtFooterHero": { "config": { "logoClassName": "h-[100px] w-[200px]", "logoSrc": "/3bear-white-logo.avif", "logoAlt": "3Bear", "title": "Melde dich für unsere Oatnews an 💛", "email": { "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" } ], "socialsClassName": "ml-8 mt-10", "className": "", "ctaClassName": "ml-8", "titleClassName": "ml-8 text-white w-full", "descriptionClassName": "ml-8" } } } + ], + "center": [], + "right": [ + { "VtMenuItem": { "config": { "title": "Information", "className": "flex flex-col gap-y-2 text-[24px] font-semibold text-white hover:text-white", "itemClassName": "text-[1rem] font-[400] opacity-70 hover:text-white", "items": [ { "text": "Über Uns", "href": "/" }, { "text": "Placeholder", "href": "/categories/shoes" }, { "text": "Placeholder", "href": "/categories/accessories" } ] } } }, + { "VtMenuItem": { "config": { "title": "Kundendienst", "className": "flex flex-col gap-y-2 text-[24px] font-semibold text-white hover:text-white", "itemClassName": "text-[1rem] font-[400] flex items-center opacity-70 hover:text-white", "items": [ { "text": "Twitter", "href": "/" }, { "text": "Facebook", "href": "/categories/shoes" }, { "text": "Pinterest", "href": "/categories/accessories" } ] } } }, + { "VtMenuItem": { "config": { "title": "Weiteres", "className": "flex flex-col gap-y-2 text-[24px] font-semibold text-white", "itemClassName": "text-[1rem] font-[400] w-[150px] opacity-70 hover:text-white", "items": [ { "text": "Karriere", "href": "/" }, { "text": "Unser Team", "href": "/categories/shoes" }, { "text": "B2B", "href": "/categories/accessories" }, { "text": "Presse", "href": "/categories/accessories" } ] } } } + ] + } + } + }, + { + "Footer": { + "config": { + "className": "content-container bg-[#003f31] w-full text text-[#11314E] flex items-center justify-between", + "leftClassName": "w-full", + "left": [], + "center": [], + "right": [ + { "VtFooterBottom": { "config": { "className": " mr-[80px]", "icons": [ "Mastercard", "PayPal", "Visa", "Mastercard", "Mastercard", "Mastercard", "Mastercard" ] } } } + ] + } + } + } + ], + "pages": { + "Home": [ + { + "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": [] + } + } + }, + { + "VtFeaturedProducts": { + "config": { + "title": "best-seller", + "styles": { + "container": "content-container py-12 small:py-20", + "header": { "container": "hidden", "title": "hidden", "isShowViewAll": false }, + "list": "grid grid-cols-2 small:grid-cols-3 gap-x-6 gap-y-24 small:gap-y-36", + "productCard": { + "badgeText": "Bestseller", + "card": "relative flex flex-col items-center bg-transparent shadow-none border-none p-0", + "badge": { "container": "absolute top-4 left-4", "text": "px-3 py-1 rounded-full bg-[#009b93] text-white text-[12px] font-semibold" }, + "thumbnail": { "className": "rounded-2xl bg-white h-[320px] object-contain", "size": "full" }, + "content": "flex flex-col items-center justify-start text-center p-0 mt-6", + "title": "text-[#003F31] text-[28px] font-semibold", + "description": "order-3 text-[#003f31b3]", + "price": "mt-2 text-[#0D382E] text-[24px] font-bold order-2 flex gap-2", + "reviews": { "container": "mt-3 flex items-center gap-2 order-1", "stars": "flex gap-1", "star": "text-[#F59E0B] text-xl leading-none", "emptyStar": "text-[#F59E0B] text-xl opacity-30 leading-none", "text": "text-[#003F31] text-[14px]", "rating": 4.5, "count": 38 }, + "button": { "addToCart": "hidden", "moreInfo": "hidden", "isShowIcon": false } + } } } } - ] - } - }, - { - "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": { - "show": true - } - } - }, - { - "FreeShippingPriceNudge": { - "config": { - "variant": "popup" - } - } - }, - { - "PropsChildren": {} - }, - { - "Footer": { - "config": { - "className": "content-container border-none flex w-full bg-[#003f31] text-white border justify-between pb-8 pt-14", - "leftClassName": "flex-col ml-3", - "centerClassName": "", - "rightClassName": "flex gap-[10rem] mr-[80px]", - "left": [ - { - "VtFooterHero": { - "config": { - "logoClassName": "h-[100px] w-[200px]", - "logoSrc": "/3bear-white-logo.avif", - "logoAlt": "3Bear", - "title": "Melde dich für unsere Oatnews an 💛", - "email": { - "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" - } - ], - "socialsClassName": "ml-8 mt-10", - "className": "", - "ctaClassName": "ml-8", - "titleClassName": "ml-8 text-white w-full", - "descriptionClassName": "ml-8" - } - } - } - ], - "center": [], - "right": [ - { - "VtMenuItem": { - "config": { - "title": "Information", - "className": "flex flex-col gap-y-2 text-[24px] font-semibold text-white hover:text-white", - "itemClassName": "text-[1rem] font-[400] opacity-70 hover:text-white", - "items": [ - { - "text": "Über Uns", - "href": "/" - }, - { - "text": "Placeholder", - "href": "/categories/shoes" - }, - { - "text": "Placeholder", - "href": "/categories/accessories" - } - ] - } - } - }, - { - "VtMenuItem": { - "config": { - "title": "Kundendienst", - "className": "flex flex-col gap-y-2 text-[24px] font-semibold text-white hover:text-white", - "itemClassName": "text-[1rem] font-[400] flex items-center opacity-70 hover:text-white", - "items": [ - { - "text": "Twitter", - "href": "/" - }, - { - "text": "Facebook", - "href": "/categories/shoes" - }, - { - "text": "Pinterest", - "href": "/categories/accessories" - } - ] - } - } - }, - { - "VtMenuItem": { - "config": { - "title": "Weiteres", - "className": "flex flex-col gap-y-2 text-[24px] font-semibold text-white", - "itemClassName": "text-[1rem] font-[400] w-[150px] opacity-70 hover:text-white", - "items": [ - { - "text": "Karriere", - "href": "/" - }, - { - "text": "Unser Team", - "href": "/categories/shoes" - }, - { - "text": "B2B", - "href": "/categories/accessories" - }, - { - "text": "Presse", - "href": "/categories/accessories" - } - ] - } - } - } - ] - } - } - }, - { - "Footer": { - "config": { - "className": "content-container bg-[#003f31] w-full text text-[#11314E] flex items-center justify-between", - "leftClassName": "w-full", - "left": [], - "center": [], - "right": [ - { - "VtFooterBottom": { - "config": { - "className": " mr-[80px]", - "icons": [ - "Mastercard", - "PayPal", - "Visa", - "Mastercard", - "Mastercard", - "Mastercard", - "Mastercard" - ] - } - } - } - ] - } - } + }, + { "CartMismatchBanner": { "config": { "show": true } } }, + { "FreeShippingPriceNudge": { "config": { "variant": "popup" } } } + ] } -] +} diff --git a/config/nam.drsquatch.design.json b/config/nam.drsquatch.design.json index 9338061..7722e5b 100644 --- a/config/nam.drsquatch.design.json +++ b/config/nam.drsquatch.design.json @@ -168,6 +168,52 @@ } } }, + { + "VtFeaturedProducts": { + "config": { + "title": "drsquatch-best-seller", + "styles": { + "container": "content-container py-12 px-[100px] small:py-24", + + "header": { + "container": "flex justify-center mb-8", + "title": "text-[28px] font-bold text-[#1f3521]", + "isShowViewAll": false + }, + "list": "grid grid-cols-2 small:grid-cols-3 gap-x-6 gap-y-24 small:gap-y-36", + "productCard": { + "card": "shadow-none border-none", + "className": "relative overflow-hidden rounded-2xl bg-white shadow-elevation-card-rest h-full flex flex-col", + "badgeText": "LIMITED EDITION", + "badge": { + "container": "absolute z-[1] top-0 left-0 pt-4", + "text": "uppercase px-4 py-2 bg-[#3B6F47] text-white" + }, + "thumbnail": { + "className": "rounded-none h-[300px] shadow-none", + "size": "full" + }, + "content": " flex flex-col flex-1", + "title": "mt-2 text-[#1f3521] text-[22px] font-bold", + "price": "mt-2 text-[#3B6F47] font-bold text-[20px] flex gap-3 flex-row-reverse justify-end", + "reviews": { + "container": "mt-3 flex items-center gap-2", + "stars": "flex gap-1", + "star": "text-[#C4622C] text-xl leading-none", + "emptyStar": "text-[#C4622C] text-xl opacity-30 leading-none", + "text": "text-[#1f3521]", + "rating": 3.6, + "count": 59 + }, + "button": { + "addToCart": "mt-6 w-full bg-[#C4622C] hover:bg-[#C4622C]/90 shadow-none text-white rounded-none h-fit font-bold", + "moreInfo": "hidden" + } + } + } + } + } + }, { "CartMismatchBanner": { "config": { diff --git a/config/nam.mds-starter-design.json b/config/nam.mds-starter-design.json index 9994c23..d402af5 100644 --- a/config/nam.mds-starter-design.json +++ b/config/nam.mds-starter-design.json @@ -1,229 +1,236 @@ -[ - { - "Header": { - "config": { - "sticky": true - }, - "children": [ - { - "Banner": { - "config": { - "variant": "nav", - "className": "h-12 bg-[#E6EFFC] text-[#11314E] gap-12 pl-16", - "left": [ - { - "Link": { - "config": { - "label": "Über Uns", - "href": "/", - "className": "text-[13px] flex items-center gap-1 cursor-pointer" - } - } - }, - { - "Link": { - "config": { - "label": "Kontaktieren Uns", - "href": "/", - "className": "text-[13px] flex items-center gap-1" - } - } - } - ], - "center": [ - { - "Link": { - "config": { - "label": "Einsparung durch Digitalisierung in der Arztpraxis", - "href": "/", - "className": "text-[13px] flex items-center gap-1 " - } - } - }, - { - "Button": { - "config": { - "label": "Mehr Info", - "href": "/", - "className": "text-[13px] flex items-center bg-[#112638] gap-1 " - } - } - } - ], - "right": [ - { - "Dropdown": { - "config": { - "trigger": { - "text": "EURO", - "className": "font-bold text-[13px] text-[#11314E] flex items-center gap-1 hover:text-[#009b93]", - "isShowArrow": true - }, - "items": [ - { - "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_Germany.svg/1200px-Flag_of_Germany.svg.png", - "text": "EURO", - "href": "/" - } - ] - } - } - }, - { - "VtCountryCodeSelect": { - "config": { - "trigger": { - "className": "w-auto font-bold text-[13px] text-[#11314E] flex justify-start items-center gap-1 hover:text-[#009b93] bg-transparent shadow-none hover:bg-transparent", - "isFlag": false - } - } - } - } - ] - } - } +{ + "layout": [ + { + "Header": { + "config": { + "sticky": true }, - { - "Nav": { - "config": { - "left": [ - { - "VtSideMenu": {} - }, - { - "VtMegaMenu": { - "config": { - "navLabel": { - "text": "Sale", - "className": "text-[13px] text-[#11314E] flex items-center mr-8 gap-1 hover:bg-transparent hover:underline hover:text-[#009b93]" + "children": [ + { + "Banner": { + "config": { + "variant": "nav", + "className": "h-12 bg-[#E6EFFC] text-[#11314E] gap-12 pl-16", + "left": [ + { + "Link": { + "config": { + "label": "Über Uns", + "href": "/", + "className": "text-[13px] flex items-center gap-1 cursor-pointer" + } + } + }, + { + "Link": { + "config": { + "label": "Kontaktieren Uns", + "href": "/", + "className": "text-[13px] flex items-center gap-1" } } } - } - ], - "center": [ - { - "HomeButton": { - "config": { - "label": "Medusa Store" - } - } - } - ], - "right": [ - { - "AccountButton": { - "config": { - "label": "Account", - "className": "hover:text-ui-fg-base" - } - } - }, - { - "VtCartButton": { - "config": { - "variant": "link", - "className": "hover:text-ui-fg-base" - } - } - } - ] - } - } - } - ] - } - }, - { - "Hero": { - "config": { - "variant": "default", - "className": "bg-custom-gradient" - } - } - }, - { - "CartMismatchBanner": { - "config": { - "show": true - } - } - }, - { - "FreeShippingPriceNudge": { - "config": { - "variant": "popup" - } - } - }, - { - "PropsChildren": {} - }, - { - "Footer": { - "config": { - "className": "content-container flex w-full border h-[300px] justify-between", - "left": [ - { - "VtMenuItem": { - "config": { - "title": "category", - "className": "flex flex-col gap-y-2", - "itemClassName": "text-ui-fg-subtle txt-small ml-3", - "items": [ + ], + "center": [ { - "text": "Clothing", - "href": "/" + "Link": { + "config": { + "label": "Einsparung durch Digitalisierung in der Arztpraxis", + "href": "/", + "className": "text-[13px] flex items-center gap-1 " + } + } }, { - "text": "Shoes", - "href": "/categories/shoes" + "Button": { + "config": { + "label": "Mehr Info", + "href": "/", + "className": "text-[13px] flex items-center bg-[#112638] gap-1 " + } + } + } + ], + "right": [ + { + "Dropdown": { + "config": { + "trigger": { + "text": "EURO", + "className": "font-bold text-[13px] text-[#11314E] flex items-center gap-1 hover:text-[#009b93]", + "isShowArrow": true + }, + "items": [ + { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_Germany.svg/1200px-Flag_of_Germany.svg.png", + "text": "EURO", + "href": "/" + } + ] + } + } }, { - "text": "Accessories", - "href": "/categories/accessories" + "VtCountryCodeSelect": { + "config": { + "trigger": { + "className": "w-auto font-bold text-[13px] text-[#11314E] flex justify-start items-center gap-1 hover:text-[#009b93] bg-transparent shadow-none hover:bg-transparent", + "isFlag": false + } + } + } } ] } } - } - ], - "center": [ + }, { - "VtMenuItem": { + "Nav": { "config": { - "title": "category", - "className": "flex flex-col gap-y-2", - "itemClassName": "text-ui-fg-subtle txt-small ml-3", - "items": [ + "left": [ { - "text": "Clothing", - "href": "/" + "VtSideMenu": {} }, { - "text": "Shoes", - "href": "/categories/shoes" + "VtMegaMenu": { + "config": { + "navLabel": { + "text": "Sale", + "className": "text-[13px] text-[#11314E] flex items-center mr-8 gap-1 hover:bg-transparent hover:underline hover:text-[#009b93]" + } + } + } + } + ], + "center": [ + { + "HomeButton": { + "config": { + "label": "Medusa Store" + } + } + } + ], + "right": [ + { + "AccountButton": { + "config": { + "label": "Account", + "className": "hover:text-ui-fg-base" + } + } }, { - "text": "Accessories", - "href": "/categories/accessories" + "VtCartButton": { + "config": { + "variant": "link", + "className": "hover:text-ui-fg-base" + } + } } ] } } } - ], - "right": [ - { - "Text": { - "config": { - "label": "Medusa Check", - "className": "text-[13px] text-[#A6A6A6]" - } - } - } ] } + }, + { "PropsChildren": {} }, + { + "Footer": { + "config": { + "className": "content-container flex w-full border h-[300px] justify-between", + "left": [ + { + "VtMenuItem": { + "config": { + "title": "category", + "className": "flex flex-col gap-y-2", + "itemClassName": "text-ui-fg-subtle txt-small ml-3", + "items": [ + { "text": "Clothing", "href": "/" }, + { "text": "Shoes", "href": "/categories/shoes" }, + { "text": "Accessories", "href": "/categories/accessories" } + ] + } + } + } + ], + "center": [ + { + "VtMenuItem": { + "config": { + "title": "category", + "className": "flex flex-col gap-y-2", + "itemClassName": "text-ui-fg-subtle txt-small ml-3", + "items": [ + { "text": "Clothing", "href": "/" }, + { "text": "Shoes", "href": "/categories/shoes" }, + { "text": "Accessories", "href": "/categories/accessories" } + ] + } + } + } + ], + "right": [ + { + "Text": { + "config": { + "label": "Medusa Check", + "className": "text-[13px] text-[#A6A6A6]" + } + } + } + ] + } + } } + ], + "pages": { + "Home": [ + { + "Hero": { + "config": { + "variant": "default", + "className": "bg-custom-gradient" + } + } + }, + { + "VtFeaturedProducts": { + "config": { + "title": "best-seller" + } + } + }, + { + "CartMismatchBanner": { + "config": { "show": true } + } + }, + { + "FreeShippingPriceNudge": { + "config": { "variant": "popup" } + } + } + ], + "Product": [ + { + "VtFeaturedProducts": { + "config": { + "title": "best-seller" + } + } + } + ], + "StorePage": [ + { + "VtFeaturedProducts": { + "config": { + "title": "best-seller" + } + } + } + ] } -] +} diff --git a/config/nam.vibentec.design.json b/config/nam.vibentec.design.json index f5b610a..c604faf 100644 --- a/config/nam.vibentec.design.json +++ b/config/nam.vibentec.design.json @@ -1,382 +1,359 @@ -[ - { - "Header": { - "config": { - "sticky": true - }, - "children": [ - { - "Banner": { - "config": { - "variant": "nav", - "className": "h-12 bg-[#E6EFFC] text-[#11314E] gap-12 pl-16", - "left": [ - { - "Link": { - "config": { - "label": "Über Uns", - "href": "/", - "className": "text-[13px] flex items-center gap-1 cursor-pointer" +{ + "layout": [ + { + "Header": { + "config": { + "sticky": true + }, + "children": [ + { + "Banner": { + "config": { + "variant": "nav", + "className": "h-12 bg-[#E6EFFC] text-[#11314E] gap-12 pl-16", + "left": [ + { + "Link": { + "config": { + "label": "Über Uns", + "href": "/", + "className": "text-[13px] flex items-center gap-1 cursor-pointer" + } } - } - }, - { - "Link": { - "config": { - "label": "Kontaktieren Uns", - "href": "/", - "className": "text-[13px] flex items-center gap-1" - } - } - } - ], - "center": [ - { - "Link": { - "config": { - "label": "Einsparung durch Digitalisierung in der Arztpraxis", - "href": "/", - "className": "text-[13px] flex items-center gap-1 " - } - } - }, - { - "Link": { - "config": { - "label": "Mehr Info", - "href": "/", - "className": "text-[13px] rounded-md hover:text-white w-[80px] text-white text-center flex items-center bg-[#112638] flex justify-center h-[28px] " - } - } - } - ], - "right": [ - { - "Dropdown": { - "config": { - "trigger": { - "text": "EURO", - "className": "font-bold text-[13px] text-[#11314E] flex items-center gap-1 hover:text-[#009b93]", - "isShowArrow": true - }, - "items": [ - { - "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_Germany.svg/1200px-Flag_of_Germany.svg.png", - "text": "EURO", - "href": "/" - } - ] - } - } - }, - { - "VtCountryCodeSelect": { - "config": { - "trigger": { - "className": "w-auto font-bold text-[13px] text-[#11314E] flex justify-start items-center gap-1 hover:text-[#009b93] bg-transparent shadow-none hover:bg-transparent", - "isFlag": false + }, + { + "Link": { + "config": { + "label": "Kontaktieren Uns", + "href": "/", + "className": "text-[13px] flex items-center gap-1" } } } - } - ] + ], + "center": [ + { + "Link": { + "config": { + "label": "Einsparung durch Digitalisierung in der Arztpraxis", + "href": "/", + "className": "text-[13px] flex items-center gap-1 " + } + } + }, + { + "Link": { + "config": { + "label": "Mehr Info", + "href": "/", + "className": "text-[13px] rounded-md hover:text-white w-[80px] text-white text-center flex items-center bg-[#112638] flex justify-center h-[28px] " + } + } + } + ], + "right": [ + { + "Dropdown": { + "config": { + "trigger": { + "text": "EURO", + "className": "font-bold text-[13px] text-[#11314E] flex items-center gap-1 hover:text-[#009b93]", + "isShowArrow": true + }, + "items": [ + { + "icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_Germany.svg/1200px-Flag_of_Germany.svg.png", + "text": "EURO", + "href": "/" + } + ] + } + } + }, + { + "VtCountryCodeSelect": { + "config": { + "trigger": { + "className": "w-auto font-bold text-[13px] text-[#11314E] flex justify-start items-center gap-1 hover:text-[#009b93] bg-transparent shadow-none hover:bg-transparent", + "isFlag": false + } + } + } + } + ] + } + } + }, + { + "Nav": { + "config": { + "className": "h-24 bg-[white] text-[#11314E] gap-12 pl-16", + "left": [ + { + "Logo": { + "config": { + "src": "/VibentecIT-logo.svg", + "alt": "MyShop", + "className": "h-full w-[180px] mr-4", + "objectFit": "contain" + } + } + }, + { + "Link": { + "config": { + "label": "Home", + "href": "/", + "className": "text-[13px] text-[#11314E] flex items-center mr-8 gap-1 hover:underline hover:text-[#009b93]" + } + } + }, + { + "Link": { + "config": { + "label": "Shop", + "href": "/", + "className": "text-[13px] text-[#11314E] flex items-center mr-6 gap-1 hover:underline hover:text-[#009b93]" + } + } + }, + { + "VtMegaMenu": { + "config": { + "navLabel": { + "text": "Sale", + "className": "text-[13px] text-[#11314E] flex items-center mr-8 gap-1 hover:bg-transparent hover:underline hover:text-[#009b93]" + } + } + } + }, + { + "VtMegaMenu": { + "config": { + "navLabel": { + "text": "OUR STORY", + "className": "font-bold text-[1rem] text-white flex items-center mr-8 gap-1 hover:bg-transparent hover:underline hover:text-white" + } + } + } + } + ], + "right": [ + { + "SearchInput": { + "config": { + "placeholder": "Search" + } + } + }, + { + "AccountButton": { + "config": { + "icon": "User", + "className": " flex items-center gap-1 shadow-none" + } + } + }, + { + "Button": { + "config": { + "icon": "Heart", + "className": " flex items-center gap-1 shadow-none w-[50px]" + } + } + }, + { + "VtCartButton": { + "config": { + "icon": "ShoppingCart", + "className": "shadow-none bg-transparent text-black w-[50px]" + } + } + } + ] + } } } - }, - { - "Nav": { - "config": { - "className": "h-24 bg-[white] text-[#11314E] gap-12 pl-16", - "left": [ - { - "Logo": { - "config": { - "src": "/VibentecIT-logo.svg", - "alt": "MyShop", - "className": "h-full w-[180px] mr-4", - "objectFit": "contain" - } - } - }, - { - "Link": { - "config": { - "label": "Home", - "href": "/", - "className": "text-[13px] text-[#11314E] flex items-center mr-8 gap-1 hover:underline hover:text-[#009b93]" - } - } - }, - { - "Link": { - "config": { - "label": "Shop", - "href": "/", - "className": "text-[13px] text-[#11314E] flex items-center mr-6 gap-1 hover:underline hover:text-[#009b93]" - } - } - }, - { - "VtMegaMenu": { - "config": { - "navLabel": { - "text": "Sale", - "className": "text-[13px] text-[#11314E] flex items-center mr-8 gap-1 hover:bg-transparent hover:underline hover:text-[#009b93]" - } - } - } - }, - { - "VtMegaMenu": { - "config": { - "navLabel": { - "text": "OUR STORY", - "className": "font-bold text-[1rem] text-white flex items-center mr-8 gap-1 hover:bg-transparent hover:underline hover:text-white" - } - } + ] + } + }, + { "PropsChildren": {} }, + { + "Footer": { + "config": { + "className": "content-container flex w-full border justify-between pb-8", + "leftClassName": "flex-col ml-6", + "centerClassName": "flex mt-[130px] gap-24", + "rightClassName": "flex mt-[160px]", + "left": [ + { + "VtFooterHero": { + "config": { + "logoClassName": "h-[100px] w-[255px]", + "logoSrc": "/VibentecIT-logo.svg", + "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": "/" + }, + "className": "", + "ctaClassName": "ml-8", + "titleClassName": "ml-8", + "descriptionClassName": "ml-8 w-[320px]" + } + } + } + ], + "center": [ + { + "VtMenuItem": { + "config": { + "title": "Unternehmen", + "className": "flex flex-col gap-y-2 text-[24px] font-semibold text-[#11314E]", + "itemClassName": "text-[1rem] font-[400]", + "items": [ + { "text": "Über Uns", "href": "/" }, + { "text": "Placeholder", "href": "/categories/shoes" }, + { "text": "Placeholder", "href": "/categories/accessories" } + ] + } + } + }, + { + "VtMenuItem": { + "config": { + "title": "Social Media", + "className": "flex flex-col gap-y-2 text-[24px] font-semibold text-[#11314E]", + "itemClassName": "text-[1rem] font-[400] flex items-center", + "items": [ + { "text": "Twitter", "href": "/", "icon": "X" }, + { "text": "Facebook", "href": "/categories/shoes", "icon": "X" }, + { "text": "Pinterest", "href": "/categories/accessories", "icon": "X" } + ] + } + } + }, + { + "VtMenuItem": { + "config": { + "title": "Addresse", + "className": "flex flex-col gap-y-2 text-[24px] font-semibold text-[#11314E]", + "itemClassName": "text-[1rem] font-[400] w-[150px]", + "items": [ + { "text": "Hopfenstr. 10c76185 Karlsruhe Deutschland", "href": "/" }, + { "text": "+497271 5970098", "href": "/categories/shoes" }, + { "text": "info@vibentec-it.io", "href": "/categories/accessories" } + ] + } + } + } + ], + "right": [ + { + "VtMenuItem": { + "config": { + "className": "flex flex-col gap-y-2 text-[24px] font-semibold text-[#11314E]", + "itemClassName": "text-[1rem] font-[400] w-[150px]", + "items": [ + { "text": "Datenschutz", "href": "/" }, + { "text": "Impressum", "href": "/categories/shoes" }, + { "text": "Installation Info", "href": "/categories/accessories" } + ] + } + } + } + ] + } + } + }, + { + "Footer": { + "config": { + "className": "content-container h-[128px] w-full text text-[#11314E] flex items-center justify-between px-20 mt-2", + "leftClassName": "w-full", + "left": [ + { + "VtFooterBottom": { + "config": { + "text": "©2025 Vibentec IT. All rights reserved", + "icons": ["Mastercard", "PayPal", "Visa"] + } + } + } + ] + } + } + } + ], + "pages": { + "Home": [ + { + "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" } } - ], - "right": [ - { - "SearchInput": { - "config": { - "placeholder": "Search" - } - } + } + ], + "center": [], + "right": [] + } + } + }, + { + "VtFeaturedProducts": { + "config": { + "title": "best-seller", + "styles": { + "container": "content-container py-12 px-[100px] small:py-24", + "header": { + "container": "flex justify-between mb-8", + "title": "text-[56px] text-[#11314E]", + "isShowViewAll": false + }, + "list": "grid grid-cols-2 small:grid-cols-3 gap-x-6 gap-y-24 small:gap-y-36", + "productCard": { + "card": "relative overflow-hidden rounded-2xl border border-[#285A86] bg-ui-bg-base shadow-elevation-card-rest h-full flex flex-col", + "badge": { + "container": "p-4", + "text": "z-20 px-3 py-1 border-[0.5px] rounded bg-[#c9e0f5] txt-compact-small-plus shadow-borders-base text-[#285A86]" }, - { - "AccountButton": { - "config": { - "icon": "User", - "className": " flex items-center gap-1 shadow-none" - } - } - }, - { - "Button": { - "config": { - "icon": "Heart", - "className": " flex items-center gap-1 shadow-none w-[50px]" - } - } - }, - { - "VtCartButton": { - "config": { - "icon": "ShoppingCart", - "className": "shadow-none bg-transparent text-black w-[50px]" - } - } + "thumbnail": { "className": "rounded-none h-[240px]", "size": "full" }, + "subtitle": "text-ui-fg-subtle text-[14px]", + "content": "flex flex-col flex-1 justify-between p-4", + "title": "text-ui-fg-subtle text-[18px]", + "price": "flex items-center gap-x-1 text-[#285A86] font-bold border-b pb-4", + "button": { + "addToCart": "w-fit h-[40px] bg-black text-white rounded-md", + "moreInfo": "w-fit h-[40px] border border-[#285A86] text-[#285A86] rounded-md" } - ] + } } } } - ] - } - }, - { - "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": { - "show": true - } - } - }, - { - "FreeShippingPriceNudge": { - "config": { - "variant": "popup" - } - } - }, - { - "PropsChildren": {} - }, - { - "Footer": { - "config": { - "className": "content-container flex w-full border justify-between pb-8", - "leftClassName": "flex-col ml-6", - "centerClassName": "flex mt-[130px] gap-24", - "rightClassName": "flex mt-[160px]", - "left": [ - { - "VtFooterHero": { - "config": { - "logoClassName": "h-[100px] w-[255px]", - "logoSrc": "/VibentecIT-logo.svg", - "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": "/" - }, - "className": "", - "ctaClassName": "ml-8", - "titleClassName": "ml-8", - "descriptionClassName": "ml-8 w-[320px]" - } - } - } - ], - "center": [ - { - "VtMenuItem": { - "config": { - "title": "Unternehmen", - "className": "flex flex-col gap-y-2 text-[24px] font-semibold text-[#11314E]", - "itemClassName": "text-[1rem] font-[400]", - "items": [ - { - "text": "Über Uns", - "href": "/" - }, - { - "text": "Placeholder", - "href": "/categories/shoes" - }, - { - "text": "Placeholder", - "href": "/categories/accessories" - } - ] - } - } - }, - { - "VtMenuItem": { - "config": { - "title": "Social Media", - "className": "flex flex-col gap-y-2 text-[24px] font-semibold text-[#11314E]", - "itemClassName": "text-[1rem] font-[400] flex items-center", - "items": [ - { - "text": "Twitter", - "href": "/", - "icon": "X" - }, - { - "text": "Facebook", - "href": "/categories/shoes", - "icon": "X" - }, - { - "text": "Pinterest", - "href": "/categories/accessories", - "icon": "X" - } - ] - } - } - }, - { - "VtMenuItem": { - "config": { - "title": "Addresse", - "className": "flex flex-col gap-y-2 text-[24px] font-semibold text-[#11314E]", - "itemClassName": "text-[1rem] font-[400] w-[150px]", - "items": [ - { - "text": "Hopfenstr. 10c76185 Karlsruhe Deutschland", - "href": "/" - }, - { - "text": "+497271 5970098", - "href": "/categories/shoes" - }, - { - "text": "info@vibentec-it.io", - "href": "/categories/accessories" - } - ] - } - } - } - ], - "right": [ - { - "VtMenuItem": { - "config": { - "className": "flex flex-col gap-y-2 text-[24px] font-semibold text-[#11314E]", - "itemClassName": "text-[1rem] font-[400] w-[150px]", - "items": [ - { - "text": "Datenschutz", - "href": "/" - }, - { - "text": "Impressum", - "href": "/categories/shoes" - }, - { - "text": "Installation Info", - "href": "/categories/accessories" - } - ] - } - } - } - ] - } - } - }, - { - "Footer": { - "config": { - "className": "content-container h-[128px] w-full text text-[#11314E] flex items-center justify-between px-20 mt-2", - "leftClassName": "w-full", - "left": [ - { - "VtFooterBottom": { - "config": { - "text": "©2025 Vibentec IT. All rights reserved", - "icons": [ - "Mastercard", - "PayPal", - "Visa" - ] - } - } - } - ] - } - } + }, + { "CartMismatchBanner": { "config": { "show": true } } }, + { "FreeShippingPriceNudge": { "config": { "variant": "popup" } } } + ] } -] +} diff --git a/src/app/[countryCode]/(main)/layout.tsx b/src/app/[countryCode]/(main)/layout.tsx index 6036614..77562db 100644 --- a/src/app/[countryCode]/(main)/layout.tsx +++ b/src/app/[countryCode]/(main)/layout.tsx @@ -5,14 +5,22 @@ import { retrieveCustomer } from "@lib/data/customer" import { getBaseURL } from "@lib/util/env" import { StoreCartShippingOption } from "@medusajs/types" import { DynamicLayoutRenderer } from "../../../vibentec/renderer" -import { LayoutContext, LayoutComponentNode, } from "../../../vibentec/component-map" -import { loadDesignConfig } from "vibentec/configloader" +import { LayoutContext, LayoutComponentNode } from "../../../vibentec/component-map" +import { loadLayoutConfig } from "vibentec/configloader" + +import { getRegion } from "@lib/data/regions" export const metadata: Metadata = { metadataBase: new URL(getBaseURL()), } -export default async function PageLayout(props: { children: React.ReactNode }) { +export default async function PageLayout(props: { + children: React.ReactNode + params: Promise<{ countryCode: string }> +}) { + const params = await props.params + const { countryCode } = params + const region = await getRegion(countryCode) const customer = await retrieveCustomer() const cart = await retrieveCart() let shippingOptions: StoreCartShippingOption[] = [] @@ -23,12 +31,14 @@ export default async function PageLayout(props: { children: React.ReactNode }) { shippingOptions = shipping_options } - const nodes: LayoutComponentNode[] = await loadDesignConfig() + const nodes: LayoutComponentNode[] = await loadLayoutConfig() const context: LayoutContext = { customer, cart, shippingOptions, contentChildren: props.children, + countryCode, + region, } diff --git a/src/app/[countryCode]/(main)/page.tsx b/src/app/[countryCode]/(main)/page.tsx index 7598b51..d5de945 100644 --- a/src/app/[countryCode]/(main)/page.tsx +++ b/src/app/[countryCode]/(main)/page.tsx @@ -4,6 +4,10 @@ import FeaturedProducts from "@modules/home/components/featured-products" import Hero from "@modules/home/components/hero" import { listCollections } from "@lib/data/collections" import { getRegion } from "@lib/data/regions" +import VtFeaturedProducts from "@modules/home/components/vt-featured-products" +import { DynamicLayoutRenderer } from "@vibentec/renderer" +import { LayoutContext, LayoutComponentNode } from "@vibentec/component-map" +import { loadPageConfig } from "@vibentec/configloader" export const metadata: Metadata = { title: "Medusa Next.js Starter Template", @@ -23,22 +27,26 @@ export default async function Home(props: { const { collections } = await listCollections({ fields: "id, handle, title", }) - const res = await listCollections({ - fields: "id, handle, title", - }) + + console.log('collections:',collections) if (!collections || !region) { return null } - console.log(res, '--------------') - return ( - <> - {/* */} -
- -
- - ) + const nodes: LayoutComponentNode[] = await loadPageConfig("Home") + + if (!region) { + return null + } + + const context: LayoutContext = { + customer: null, + cart: null, + shippingOptions: [], + contentChildren: null, + countryCode, + region, + } + + return } diff --git a/src/app/[countryCode]/(main)/products/[handle]/page.tsx b/src/app/[countryCode]/(main)/products/[handle]/page.tsx index cc03faf..c2a3394 100644 --- a/src/app/[countryCode]/(main)/products/[handle]/page.tsx +++ b/src/app/[countryCode]/(main)/products/[handle]/page.tsx @@ -3,6 +3,9 @@ import { notFound } from "next/navigation" import { listProducts } from "@lib/data/products" import { getRegion, listRegions } from "@lib/data/regions" import ProductTemplate from "@modules/products/templates" +import { DynamicLayoutRenderer } from "@vibentec/renderer" +import { LayoutContext, LayoutComponentNode } from "@vibentec/component-map" +import { loadPageConfig } from "@vibentec/configloader" type Props = { params: Promise<{ countryCode: string; handle: string }> @@ -96,11 +99,25 @@ export default async function ProductPage(props: Props) { notFound() } + const nodes: LayoutComponentNode[] = await loadPageConfig("Product") + + const context: LayoutContext = { + customer: null, + cart: null, + shippingOptions: [], + contentChildren: null, + countryCode: params.countryCode, + region, + } + return ( - + <> + + + ) } diff --git a/src/app/[countryCode]/(main)/store/page.tsx b/src/app/[countryCode]/(main)/store/page.tsx index 2d256d3..31443fa 100644 --- a/src/app/[countryCode]/(main)/store/page.tsx +++ b/src/app/[countryCode]/(main)/store/page.tsx @@ -2,6 +2,10 @@ import { Metadata } from "next" import { SortOptions } from "@modules/store/components/refinement-list/sort-products" import StoreTemplate from "@modules/store/templates" +import { LayoutComponentNode, LayoutContext } from "@vibentec/component-map" +import { getRegion } from "@lib/data/regions" +import { loadPageConfig } from "@vibentec/configloader" +import { DynamicLayoutRenderer } from "@vibentec/renderer" export const metadata: Metadata = { title: "Store", @@ -19,15 +23,28 @@ type Params = { } export default async function StorePage(props: Params) { - const params = await props.params; - const searchParams = await props.searchParams; + const params = await props.params + const searchParams = await props.searchParams + const region = await getRegion(params.countryCode) const { sortBy, page } = searchParams + const nodes: LayoutComponentNode[] = await loadPageConfig("Store") + const context: LayoutContext = { + customer: null, + cart: null, + shippingOptions: [], + contentChildren: null, + countryCode: params.countryCode, + region, + } return ( - + <> + + + ) } diff --git a/src/lib/data/collections.ts b/src/lib/data/collections.ts index cb403ee..134462f 100644 --- a/src/lib/data/collections.ts +++ b/src/lib/data/collections.ts @@ -36,7 +36,6 @@ export const listCollections = async ( { query: queryParams, next, - cache: "force-cache", } ) .then(({ collections }) => ({ collections, count: collections.length })) diff --git a/src/lib/data/products.ts b/src/lib/data/products.ts index 680a0d9..28a429f 100644 --- a/src/lib/data/products.ts +++ b/src/lib/data/products.ts @@ -63,12 +63,11 @@ export const listProducts = async ({ offset, region_id: region?.id, fields: - "*variants.calculated_price,+variants.inventory_quantity,+metadata,+tags", + "*variants.calculated_price,+variants.inventory_quantity,*metadata,+tags", ...queryParams, }, headers, next, - cache: "force-cache", } ) .then(({ products, count }) => { diff --git a/src/modules/home/components/vt-featured-products/index.tsx b/src/modules/home/components/vt-featured-products/index.tsx new file mode 100644 index 0000000..169c41e --- /dev/null +++ b/src/modules/home/components/vt-featured-products/index.tsx @@ -0,0 +1,52 @@ +import { HttpTypes } from "@medusajs/types" +import ProductRail from "./product-rail" +import { listCollections } from "@lib/data/collections" +import { LayoutComponentDefinition, LayoutContext } from "@vibentec/component-map" + +export default async function VtFeaturedProducts(props: { + collections?: HttpTypes.StoreCollection[] + region?: HttpTypes.StoreRegion + countryCode?: string + nodes?: LayoutComponentDefinition + context?: LayoutContext +}) { + let { collections, region, countryCode } = props + const { nodes, context } = props + + if (context) { + if (!region) region = context.region + if (!countryCode) countryCode = context.countryCode + } + + if (!collections && region) { + const result = await listCollections({ + fields: "id, handle, title", + }) + collections = result.collections + } + + if (!collections || !region || !countryCode) { + return null + } + + const configTitle = nodes?.config?.title + const styles = nodes?.config?.styles + + let displayCollections = collections + if (configTitle) { + displayCollections = collections.filter( + (c) => c.handle === configTitle || c.title === configTitle + ) + } + + return displayCollections.map((collection) => ( +
  • + +
  • + )) +} diff --git a/src/modules/home/components/vt-featured-products/product-rail/index.tsx b/src/modules/home/components/vt-featured-products/product-rail/index.tsx new file mode 100644 index 0000000..db350a5 --- /dev/null +++ b/src/modules/home/components/vt-featured-products/product-rail/index.tsx @@ -0,0 +1,68 @@ +import { listProducts } from "@lib/data/products" +import { HttpTypes } from "@medusajs/types" +import { Text, clx } from "@medusajs/ui" + +import InteractiveLink from "@modules/common/components/interactive-link" +import ProductCard from "@modules/products/components/vt-product-card" + +export default async function ProductRail({ + collection, + region, + countryCode, + styles, +}: { + collection: HttpTypes.StoreCollection + region: HttpTypes.StoreRegion + countryCode: string + styles?: any +}) { + const { + response: { products: pricedProducts }, + } = await listProducts({ + regionId: region.id, + queryParams: { + collection_id: collection.id, + fields: "*variants.calculated_price", + }, + }) + + if (!pricedProducts) { + return null + } + + const classes = { + container: styles?.container ?? "content-container py-12 px-[100px] small:py-24", + header: { + container: styles?.header?.container ?? "flex justify-between mb-8", + title: styles?.header?.title ?? "txt-xlarge", + isShowViewAll: styles?.header.isShowViewAll ?? true, + }, + list: styles?.list ?? "grid grid-cols-2 small:grid-cols-3 gap-x-6 gap-y-24 small:gap-y-36", + } + + return ( +
    +
    + {collection.title} + {classes.header.isShowViewAll && ( + + View all + + )} +
    +
      + {pricedProducts && + pricedProducts.map((product) => ( +
    • + +
    • + ))} +
    +
    + ) +} diff --git a/src/modules/products/components/product-preview/price.tsx b/src/modules/products/components/product-preview/price.tsx index f8fa586..b89351e 100644 --- a/src/modules/products/components/product-preview/price.tsx +++ b/src/modules/products/components/product-preview/price.tsx @@ -18,7 +18,7 @@ export default async function PreviewPrice({ price }: { price: VariantPrice }) { )} diff --git a/src/modules/products/components/vt-product-card/index.tsx b/src/modules/products/components/vt-product-card/index.tsx new file mode 100644 index 0000000..6d58d37 --- /dev/null +++ b/src/modules/products/components/vt-product-card/index.tsx @@ -0,0 +1,208 @@ +import { HttpTypes } from "@medusajs/types" +import { Button, Heading, Text, clx } from "@medusajs/ui" +import LocalizedClientLink from "@modules/common/components/localized-client-link" +import Divider from "@modules/common/components/divider" +import PreviewPrice from "@modules/products/components/product-preview/price" +import { getProductPrice } from "@lib/util/get-product-price" +import { addToCart } from "@lib/data/cart" +import VtThumbnail from "../vt-thumbnail" +import { Plus, ChevronRight } from "@medusajs/icons" +type ProductCardProps = { + product: HttpTypes.StoreProduct + badgeText?: string + deliveryTime?: string + className?: string + countryCode: string + styles?: any +} + +export default function ProductCard({ + product, + badgeText = "Saved up to 20%", + deliveryTime = "2-4 Wochen", + className, + countryCode, + styles, +}: ProductCardProps) { + const firstVariant = product.variants?.[0] + + const inStock = (() => { + if (!firstVariant) return false + if (!firstVariant.manage_inventory) return true + if (firstVariant.allow_backorder) return true + return (firstVariant.inventory_quantity || 0) > 0 + })() + console.dir(product, { depth: null }) + const { cheapestPrice } = getProductPrice({ product }) + + async function handleAddToCart() { + "use server" + if (!firstVariant?.id) return + await addToCart({ + variantId: firstVariant.id, + quantity: 1, + countryCode, + }) + } + + const description = (() => { + const prodDescription = product.description || "" + const textSlice = + prodDescription.length > 120 + ? prodDescription.slice(0, 117) + "…" + : prodDescription + return textSlice + })() + + const classes = { + card: styles?.card ?? className ?? "", + badge: { + container: styles?.badge?.container ?? "p-4", + text: + styles?.badge?.text ?? + "z-20 px-3 py-1 border-[0.5px] rounded bg-[#c9e0f5] txt-compact-small-plus shadow-borders-base text-[#285A86] ", + }, + thumbnail: { + className: styles?.thumbnail?.className ?? "rounded-none h-[240px]", + size: styles?.thumbnail?.size ?? "full", + }, + subtitle: styles?.subtitle ?? "", + content: styles?.content ?? "p-6 flex flex-col flex-1", + title: styles?.title ?? "mt-2 text-ui-fg-base", + price: styles?.price ?? "mt-2 flex items-baseline gap-2", + description: styles?.description ?? "txt-small text-[#285A86] my-4", + reviews: { + container: styles?.reviews?.container ?? undefined, + stars: styles?.reviews?.stars ?? "flex gap-1", + star: styles?.reviews?.star ?? "text-[#C4622C] text-xl leading-none", + emptyStar: + styles?.reviews?.emptyStar ?? + "text-[#C4622C] text-xl opacity-30 leading-none", + text: styles?.reviews?.text ?? "txt-small text-ui-fg-subtle", + rating: styles?.reviews?.rating, + count: styles?.reviews?.count, + }, + button: { + addToCart: styles?.button?.addToCart ?? "flex-1", + moreInfo: styles?.button?.moreInfo ?? "w-full", + isShowIcon: styles?.button?.isShowIcon ?? true, + }, + } + + return ( +
    + +
    + {badgeText && ( +
    + {badgeText} +
    + )} + +
    +
    + +
    + {classes.subtitle && product.collection && ( + + {product.subtitle} + + )} + + + + {product.title} + + + +
    + {cheapestPrice && } +
    + + {(classes.reviews.rating !== undefined || + classes.reviews.count !== undefined) && ( +
    +
    +
    + {Array.from({ length: 5 }).map((_, i) => ( + + ★ + + ))} +
    +
    +
    + {Array.from({ length: 5 }).map((_, i) => ( + + ★ + + ))} +
    +
    +
    + {typeof classes.reviews.count === "number" && ( + + {classes.reviews.count} Reviews + + )} +
    + )} + + {description} + +
    + + + + +
    +
    +
    + ) +} diff --git a/src/modules/products/components/vt-thumbnail/index.tsx b/src/modules/products/components/vt-thumbnail/index.tsx new file mode 100644 index 0000000..728bef3 --- /dev/null +++ b/src/modules/products/components/vt-thumbnail/index.tsx @@ -0,0 +1,70 @@ +import { Container, clx } from "@medusajs/ui" +import Image from "next/image" +import React from "react" + +import PlaceholderImage from "@modules/common/icons/placeholder-image" + +type ThumbnailProps = { + thumbnail?: string | null + // TODO: Fix image typings + images?: any[] | null + size?: "small" | "medium" | "large" | "full" | "square" + isFeatured?: boolean + className?: string + "data-testid"?: string +} + +const VtThumbnail: React.FC = ({ + thumbnail, + images, + size = "small", + isFeatured, + className, + "data-testid": dataTestid, +}) => { + const initialImage = thumbnail || images?.[0]?.url + + return ( + + + + ) +} + +const ImageOrPlaceholder = ({ + image, + size, +}: Pick & { image?: string }) => { + return image ? ( + Thumbnail + ) : ( +
    + +
    + ) +} + +export default VtThumbnail diff --git a/src/vibentec/component-map.tsx b/src/vibentec/component-map.tsx index b1c1dcd..9b196dc 100644 --- a/src/vibentec/component-map.tsx +++ b/src/vibentec/component-map.tsx @@ -25,6 +25,7 @@ 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" +import VtFeaturedProducts from "@modules/home/components/vt-featured-products" type ComponentConfig = Record @@ -38,6 +39,8 @@ export interface LayoutContext { cart: any shippingOptions: any[] contentChildren: React.ReactNode + countryCode?: string + region?: any } export type ComponentRenderer = { @@ -97,6 +100,7 @@ export const componentMap: Record = { VtFooterSignUp: nodesContextRenderer(VtFooterSignUp), Footer: nodesContextRenderer(VtFooter), ImageDisplayer: nodesContextRenderer(VtCarousel), + VtFeaturedProducts: nodesContextRenderer(VtFeaturedProducts), } export type ComponentName = keyof typeof componentMap diff --git a/src/vibentec/configloader.ts b/src/vibentec/configloader.ts index dd5fbef..1759cee 100644 --- a/src/vibentec/configloader.ts +++ b/src/vibentec/configloader.ts @@ -1,11 +1,28 @@ import fs from "fs" import path from "path" -import { jsonFileNames } from "./devJsonFileNames"; +import { jsonFileNames } from "./devJsonFileNames" -const fileName = jsonFileNames.namStarter; +const fileName = jsonFileNames.nam3Bear -export async function loadDesignConfig() { +async function readDesignFile() { const filePath = path.join(process.cwd(), "config", fileName) const fileData = await fs.promises.readFile(filePath, "utf-8") return JSON.parse(fileData) } + +export async function loadLayoutConfig() { + const config = await readDesignFile() + if (Array.isArray(config)) return config + return config.layout ?? [] +} + +export async function loadPageConfig(pageKey: string) { + const config = await readDesignFile() + if (Array.isArray(config)) return [] + const pages = config.pages ?? {} + return pages[pageKey] ?? [] +} + +export async function loadDesignConfig() { + return loadLayoutConfig() +}