Compare commits

..

2 Commits

13 changed files with 918 additions and 1072 deletions

View File

@ -1,383 +1,123 @@
[ {
{ "layout": [
"Header": { {
"config": { "Header": {
"sticky": true, "config": {
"variant": "ticker" "sticky": true,
}, "variant": "ticker"
"children": [ },
{ "children": [
"Banner": { {
"config": { "Banner": {
"variant": "ticker", "config": {
"className": "h-12 bg-[#009b93] text-[#fff] gap-12", "variant": "ticker",
"speed": 24, "className": "h-12 bg-[#009b93] text-[#fff] gap-12",
"items": [ "speed": 24,
{ "items": [
"Link": { { "Link": { "config": { "label": "NEU: Overnight Oats Sallys Nussecke 😍", "href": "/" } } },
"config": { { "Link": { "config": { "label": "Versandkostenfrei ab 45 € 💛", "href": "/" } } },
"label": "NEU: Overnight Oats Sallys Nussecke 😍", { "Link": { "config": { "label": "Gratis Geschenk ab 60 € Warenkorbwert 🎁", "href": "/" } } }
"href": "/" ]
} }
} }
}, },
{ {
"Link": { "Nav": {
"config": { "config": {
"label": "Versandkostenfrei ab 45 € 💛", "className": "h-24 bg-white text-[#003F31] gap-12",
"href": "/" "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": { { "Link": { "config": { "label": "Rezepte", "href": "/", "className": "font-bold text-[1rem] text-[#003F31] flex items-center mr-8 gap-1 hover:text-[#009b93]" } } },
"config": { { "Link": { "config": { "label": "Triff Harry Kane", "href": "/", "className": "font-bold text-[1rem] text-[#003F31] flex items-center gap-1 hover:text-[#009b93]" } } }
"label": "Gratis Geschenk ab 60 € Warenkorbwert 🎁", ],
"href": "/" "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": { { "PropsChildren": {} },
"className": "h-24 bg-white text-[#003F31] gap-12", {
"left": [ "Footer": {
{ "config": {
"Logo": { "className": "content-container border-none flex w-full bg-[#003f31] text-white border justify-between pb-8 pt-14",
"config": { "leftClassName": "flex-col ml-3",
"src": "/3bear-logo.png", "centerClassName": "",
"alt": "MyShop", "rightClassName": "flex gap-[10rem] mr-[80px]",
"className": "h-[150px] w-[180px]", "left": [
"objectFit": "contain" { "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" } ] } } },
"VtMegaMenu": { { "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" } ] } } },
"config": { { "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" } ] } } }
"navLabel": { ]
"text": "Shop", }
"className": "font-bold text-[1rem] text-[#003F31] flex items-center mr-8 gap-1 hover:text-[#009b93]", }
"isShowArrow": true },
} {
} "Footer": {
} "config": {
}, "className": "content-container bg-[#003f31] w-full text text-[#11314E] flex items-center justify-between",
{ "leftClassName": "w-full",
"Dropdown": { "left": [],
"config": { "center": [],
"trigger": { "right": [
"text": "Über Uns", { "VtFooterBottom": { "config": { "className": " mr-[80px]", "icons": [ "Mastercard", "PayPal", "Visa", "Mastercard", "Mastercard", "Mastercard", "Mastercard" ] } } }
"className": "font-bold text-[1rem] text-[#003F31] flex items-center mr-8 gap-1 hover:text-[#009b93]", ]
"isShowArrow": true }
}, }
"items": [ }
{ ],
"text": "Unser Unternehmen", "pages": {
"href": "/" "Home": [
}, {
{ "Hero": {
"text": "Loren ipsum", "config": {
"href": "/" "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" } } } ],
"text": "Not a Link" "center": [],
} "right": []
] }
} }
} },
}, {
{ "VtFeaturedProducts": {
"Dropdown": { "config": {
"config": { "title": "best-seller",
"trigger": { "styles": {
"text": "Über unsere Produkte", "container": "content-container py-12 small:py-20",
"className": "font-bold text-[1rem] text-[#003F31] flex items-center mr-8 gap-1 hover:text-[#009b93]", "header": { "container": "hidden", "title": "hidden", "isShowViewAll": false },
"isShowArrow": true "list": "grid grid-cols-2 small:grid-cols-3 gap-x-6 gap-y-24 small:gap-y-36",
}, "productCard": {
"items": [ "badgeText": "Bestseller",
{ "card": "relative flex flex-col items-center bg-transparent shadow-none border-none p-0",
"text": "Unser Unternehmen", "badge": { "container": "absolute top-4 left-4", "text": "px-3 py-1 rounded-full bg-[#009b93] text-white text-[12px] font-semibold" },
"href": "/" "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",
"text": "Loren ipsum", "description": "order-3 text-[#003f31b3]",
"href": "/" "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 }
"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]"
}
}
}
]
} }
} }
} }
] },
} { "CartMismatchBanner": { "config": { "show": true } } },
}, { "FreeShippingPriceNudge": { "config": { "variant": "popup" } } }
{ ]
"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"
]
}
}
}
]
}
}
} }
] }

View File

@ -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": { "CartMismatchBanner": {
"config": { "config": {

View File

@ -1,236 +1,236 @@
[ {
{ "layout": [
"Header": { {
"config": { "Header": {
"sticky": true "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
}
}
}
}
]
}
}
}, },
{ "children": [
"Nav": { {
"config": { "Banner": {
"left": [ "config": {
{ "variant": "nav",
"VtSideMenu": {} "className": "h-12 bg-[#E6EFFC] text-[#11314E] gap-12 pl-16",
}, "left": [
{ {
"VtMegaMenu": { "Link": {
"config": { "config": {
"navLabel": { "label": "Über Uns",
"text": "Sale", "href": "/",
"className": "text-[13px] text-[#11314E] flex items-center mr-8 gap-1 hover:bg-transparent hover:underline hover:text-[#009b93]" "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": [
"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"
}
}
},
{
"VtFeaturedProducts": {
"config": {
"title": "best-seller"
}
}
},
{
"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": [
{ {
"text": "Clothing", "Link": {
"href": "/" "config": {
"label": "Einsparung durch Digitalisierung in der Arztpraxis",
"href": "/",
"className": "text-[13px] flex items-center gap-1 "
}
}
}, },
{ {
"text": "Shoes", "Button": {
"href": "/categories/shoes" "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", "VtCountryCodeSelect": {
"href": "/categories/accessories" "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": { "config": {
"title": "category", "left": [
"className": "flex flex-col gap-y-2",
"itemClassName": "text-ui-fg-subtle txt-small ml-3",
"items": [
{ {
"text": "Clothing", "VtSideMenu": {}
"href": "/"
}, },
{ {
"text": "Shoes", "VtMegaMenu": {
"href": "/categories/shoes" "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", "VtCartButton": {
"href": "/categories/accessories" "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"
}
}
}
]
} }
] }

View File

@ -1,416 +1,359 @@
[ {
{ "layout": [
"Header": { {
"config": { "Header": {
"sticky": true "config": {
}, "sticky": true
"children": [ },
{ "children": [
"Banner": { {
"config": { "Banner": {
"variant": "nav", "config": {
"className": "h-12 bg-[#E6EFFC] text-[#11314E] gap-12 pl-16", "variant": "nav",
"left": [ "className": "h-12 bg-[#E6EFFC] text-[#11314E] gap-12 pl-16",
{ "left": [
"Link": { {
"config": { "Link": {
"label": "Über Uns", "config": {
"href": "/", "label": "Über Uns",
"className": "text-[13px] flex items-center gap-1 cursor-pointer" "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": { "Link": {
"label": "Kontaktieren Uns", "config": {
"href": "/", "label": "Einsparung durch Digitalisierung in der Arztpraxis",
"className": "text-[13px] flex items-center gap-1" "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": [
"center": [ {
{ "Dropdown": {
"Link": { "config": {
"config": { "trigger": {
"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", "text": "EURO",
"href": "/" "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
} }
]
}
}
},
{
"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": { { "PropsChildren": {} },
"className": "h-24 bg-[white] text-[#11314E] gap-12 pl-16", {
"left": [ "Footer": {
{ "config": {
"Logo": { "className": "content-container flex w-full border justify-between pb-8",
"config": { "leftClassName": "flex-col ml-6",
"src": "/VibentecIT-logo.svg", "centerClassName": "flex mt-[130px] gap-24",
"alt": "MyShop", "rightClassName": "flex mt-[160px]",
"className": "h-full w-[180px] mr-4", "left": [
"objectFit": "contain" {
} "VtFooterHero": {
} "config": {
}, "logoClassName": "h-[100px] w-[255px]",
{ "logoSrc": "/VibentecIT-logo.svg",
"Link": { "logoAlt": "Vibentec IT",
"config": { "title": "Der Wegbereiter für innovative IT-Lösungen",
"label": "Home", "description": "Tauchen Sie ein in eine Welt modernster Technologien, zuverlässiger Support und proaktiver Innovation gemeinsam gestalten wir die digitale Zukunft Ihres Unternehmens.",
"href": "/", "cta": {
"className": "text-[13px] text-[#11314E] flex items-center mr-8 gap-1 hover:underline hover:text-[#009b93]" "label": "Kontaktieren Sie uns",
} "href": "/"
} },
}, "className": "",
{ "ctaClassName": "ml-8",
"Link": { "titleClassName": "ml-8",
"config": { "descriptionClassName": "ml-8 w-[320px]"
"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]"
}
}
}
]
} }
} ],
"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": {
"Hero": { "Home": [
"config": { {
"className": "h-[35rem]", "Hero": {
"ImageDisplayer": {
"config": { "config": {
"duration": 5, "className": "h-[35rem]",
"images": [ "ImageDisplayer": {
"./banner-hero.webp",
"./banner-hero-1.webp",
"./banner-hero-2.webp"
],
"links": ["/", "/account", "/product"]
}
},
"left": [
{
"VtCtaBanner": {
"config": { "config": {
"variant": "default", "duration": 5,
"className": "left-[120px] top-[80px]", "images": ["./banner-hero.webp", "./banner-hero-1.webp", "./banner-hero-2.webp"],
"titleTextClassName": "leading-normal", "links": ["/", "/account", "/product"]
"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"
} }
} },
"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": []
} }
], }
"center": [], },
"right": [] {
} "VtFeaturedProducts": {
} "config": {
}, "title": "best-seller",
{ "styles": {
"VtFeaturedProducts": { "container": "content-container py-12 px-[100px] small:py-24",
"config": { "header": {
"title": "best-seller", "container": "flex justify-between mb-8",
"styles": { "title": "text-[56px] text-[#11314E]",
"container": "content-container py-12 px-[100px] small:py-24", "isShowViewAll": false
"header": { },
"container": "flex justify-between mb-8", "list": "grid grid-cols-2 small:grid-cols-3 gap-x-6 gap-y-24 small:gap-y-36",
"title": "txt-xlarge", "productCard": {
"link": "" "card": "relative overflow-hidden rounded-2xl border border-[#285A86] bg-ui-bg-base shadow-elevation-card-rest h-full flex flex-col",
}, "badge": {
"list": "grid grid-cols-2 small:grid-cols-3 gap-x-6 gap-y-24 small:gap-y-36", "container": "p-4",
"productCard": { "text": "z-20 px-3 py-1 border-[0.5px] rounded bg-[#c9e0f5] txt-compact-small-plus shadow-borders-base text-[#285A86]"
"className": "relative overflow-hidden rounded-2xl border border-[#285A86] bg-ui-bg-base shadow-elevation-card-rest h-full flex flex-col", },
"badge": { "thumbnail": { "className": "rounded-none h-[240px]", "size": "full" },
"container": "p-4", "subtitle": "text-ui-fg-subtle text-[14px]",
"text": "z-20 px-3 py-1 border-[0.5px] rounded bg-[#c9e0f5] txt-compact-small-plus shadow-borders-base text-[#285A86]" "content": "flex flex-col flex-1 justify-between p-4",
}, "title": "text-ui-fg-subtle text-[18px]",
"thumbnail": { "price": "flex items-center gap-x-1 text-[#285A86] font-bold border-b pb-4",
"className": "rounded-none h-[240px]", "button": {
"size": "full" "addToCart": "w-fit h-[40px] bg-black text-white rounded-md",
}, "moreInfo": "w-fit h-[40px] border border-[#285A86] text-[#285A86] rounded-md"
"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",
"button": {
"addToCart": "w-fit h-[40px] bg-black text-white rounded-md",
"moreInfo": "w-fit h-[40px] border border-[#285A86] text-[#285A86] rounded-md"
} }
} }
} }
} },
} { "CartMismatchBanner": { "config": { "show": true } } },
}, { "FreeShippingPriceNudge": { "config": { "variant": "popup" } } }
{ ]
"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"
]
}
}
}
]
}
}
} }
] }

View File

@ -5,8 +5,8 @@ import { retrieveCustomer } from "@lib/data/customer"
import { getBaseURL } from "@lib/util/env" import { getBaseURL } from "@lib/util/env"
import { StoreCartShippingOption } from "@medusajs/types" import { StoreCartShippingOption } from "@medusajs/types"
import { DynamicLayoutRenderer } from "../../../vibentec/renderer" import { DynamicLayoutRenderer } from "../../../vibentec/renderer"
import { LayoutContext, LayoutComponentNode, } from "../../../vibentec/component-map" import { LayoutContext, LayoutComponentNode } from "../../../vibentec/component-map"
import { loadDesignConfig } from "vibentec/configloader" import { loadLayoutConfig } from "vibentec/configloader"
import { getRegion } from "@lib/data/regions" import { getRegion } from "@lib/data/regions"
@ -31,7 +31,7 @@ export default async function PageLayout(props: {
shippingOptions = shipping_options shippingOptions = shipping_options
} }
const nodes: LayoutComponentNode[] = await loadDesignConfig() const nodes: LayoutComponentNode[] = await loadLayoutConfig()
const context: LayoutContext = { const context: LayoutContext = {
customer, customer,
cart, cart,

View File

@ -5,6 +5,9 @@ import Hero from "@modules/home/components/hero"
import { listCollections } from "@lib/data/collections" import { listCollections } from "@lib/data/collections"
import { getRegion } from "@lib/data/regions" import { getRegion } from "@lib/data/regions"
import VtFeaturedProducts from "@modules/home/components/vt-featured-products" 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 = { export const metadata: Metadata = {
title: "Medusa Next.js Starter Template", title: "Medusa Next.js Starter Template",
@ -30,14 +33,20 @@ export default async function Home(props: {
if (!collections || !region) { if (!collections || !region) {
return null return null
} }
return ( const nodes: LayoutComponentNode[] = await loadPageConfig("Home")
<>
{/* <Hero /> */} if (!region) {
{/* <div className="py-12"> return null
<ul className="flex flex-col gap-x-6"> }
<VtFeaturedProducts collections={collections} region={region} countryCode={countryCode} />
</ul> const context: LayoutContext = {
</div> */} customer: null,
</> cart: null,
) shippingOptions: [],
contentChildren: null,
countryCode,
region,
}
return <DynamicLayoutRenderer nodes={nodes} context={context} />
} }

View File

@ -3,6 +3,9 @@ import { notFound } from "next/navigation"
import { listProducts } from "@lib/data/products" import { listProducts } from "@lib/data/products"
import { getRegion, listRegions } from "@lib/data/regions" import { getRegion, listRegions } from "@lib/data/regions"
import ProductTemplate from "@modules/products/templates" 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 = { type Props = {
params: Promise<{ countryCode: string; handle: string }> params: Promise<{ countryCode: string; handle: string }>
@ -96,11 +99,25 @@ export default async function ProductPage(props: Props) {
notFound() notFound()
} }
const nodes: LayoutComponentNode[] = await loadPageConfig("Product")
const context: LayoutContext = {
customer: null,
cart: null,
shippingOptions: [],
contentChildren: null,
countryCode: params.countryCode,
region,
}
return ( return (
<ProductTemplate <>
product={pricedProduct} <ProductTemplate
region={region} product={pricedProduct}
countryCode={params.countryCode} region={region}
/> countryCode={params.countryCode}
/>
<DynamicLayoutRenderer nodes={nodes} context={context} />
</>
) )
} }

View File

@ -2,6 +2,10 @@ import { Metadata } from "next"
import { SortOptions } from "@modules/store/components/refinement-list/sort-products" import { SortOptions } from "@modules/store/components/refinement-list/sort-products"
import StoreTemplate from "@modules/store/templates" 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 = { export const metadata: Metadata = {
title: "Store", title: "Store",
@ -19,15 +23,28 @@ type Params = {
} }
export default async function StorePage(props: Params) { export default async function StorePage(props: Params) {
const params = await props.params; const params = await props.params
const searchParams = await props.searchParams; const searchParams = await props.searchParams
const region = await getRegion(params.countryCode)
const { sortBy, page } = searchParams 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 ( return (
<StoreTemplate <>
sortBy={sortBy} <StoreTemplate
page={page} sortBy={sortBy}
countryCode={params.countryCode} page={page}
/> countryCode={params.countryCode}
/>
<DynamicLayoutRenderer nodes={nodes} context={context} />
</>
) )
} }

View File

@ -63,7 +63,7 @@ export const listProducts = async ({
offset, offset,
region_id: region?.id, region_id: region?.id,
fields: fields:
"*variants.calculated_price,+variants.inventory_quantity,+metadata,+tags", "*variants.calculated_price,+variants.inventory_quantity,*metadata,+tags",
...queryParams, ...queryParams,
}, },
headers, headers,

View File

@ -31,21 +31,24 @@ export default async function ProductRail({
} }
const classes = { const classes = {
container: styles?.container || "content-container py-12 px-[100px] small:py-24", container: styles?.container ?? "content-container py-12 px-[100px] small:py-24",
header: { header: {
container: styles?.header?.container || "flex justify-between mb-8", container: styles?.header?.container ?? "flex justify-between mb-8",
title: styles?.header?.title || "txt-xlarge", 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", list: styles?.list ?? "grid grid-cols-2 small:grid-cols-3 gap-x-6 gap-y-24 small:gap-y-36",
} }
return ( return (
<div className={classes.container}> <div className={classes.container}>
<div className={classes.header.container}> <div className={classes.header.container}>
<Text className={classes.header.title}>{collection.title}</Text> <Text className={classes.header.title}>{collection.title}</Text>
<InteractiveLink href={`/collections/${collection.handle}`}> {classes.header.isShowViewAll && (
View all <InteractiveLink href={`/collections/${collection.handle}`}>
</InteractiveLink> View all
</InteractiveLink>
)}
</div> </div>
<ul className={classes.list}> <ul className={classes.list}>
{pricedProducts && {pricedProducts &&
@ -55,6 +58,7 @@ export default async function ProductRail({
product={product} product={product}
countryCode={countryCode} countryCode={countryCode}
styles={styles?.productCard} styles={styles?.productCard}
badgeText={styles?.productCard?.badgeText}
/> />
</li> </li>
))} ))}

View File

@ -18,7 +18,7 @@ export default async function PreviewPrice({ price }: { price: VariantPrice }) {
)} )}
<Text <Text
className={clx("text-ui-fg-muted", { className={clx("text-ui-fg-muted", {
"text-ui-fg-interactive": price.price_type === "sale", "text-green-700": price.price_type === "sale",
})} })}
data-testid="price" data-testid="price"
> >

View File

@ -32,7 +32,7 @@ export default function ProductCard({
if (firstVariant.allow_backorder) return true if (firstVariant.allow_backorder) return true
return (firstVariant.inventory_quantity || 0) > 0 return (firstVariant.inventory_quantity || 0) > 0
})() })()
console.dir(product, { depth: null })
const { cheapestPrice } = getProductPrice({ product }) const { cheapestPrice } = getProductPrice({ product })
async function handleAddToCart() { async function handleAddToCart() {
@ -46,87 +46,143 @@ export default function ProductCard({
} }
const description = (() => { const description = (() => {
const description = product.description || "" const prodDescription = product.description || ""
const textSlice = description.length > 120 ? description.slice(0, 117) + "…" : description const textSlice =
prodDescription.length > 120
? prodDescription.slice(0, 117) + "…"
: prodDescription
return textSlice return textSlice
})() })()
const classes = { const classes = {
card: styles?.className || className || "relative overflow-hidden rounded-2xl border border-[#285A86] bg-ui-bg-base shadow-elevation-card-rest h-full flex flex-col", card: styles?.card ?? className ?? "",
badge: { badge: {
container: styles?.badge?.container || "p-4", 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] ", 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: { thumbnail: {
className: styles?.thumbnail?.className || "rounded-none h-[240px]", className: styles?.thumbnail?.className ?? "rounded-none h-[240px]",
size: styles?.thumbnail?.size || "full", 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,
}, },
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",
button: { button: {
addToCart: styles?.button?.addToCart || "flex-1", addToCart: styles?.button?.addToCart ?? "flex-1",
moreInfo: styles?.button?.moreInfo || "w-full", moreInfo: styles?.button?.moreInfo ?? "w-full",
isShowIcon: styles?.button?.isShowIcon || true, isShowIcon: styles?.button?.isShowIcon ?? true,
}, },
} }
return ( return (
<div <div className={clx(classes.card)}>
className={clx( <LocalizedClientLink href={`/products/${product.handle}`} className="block">
classes.card <div className="relative">
)} {badgeText && (
> <div className={classes.badge.container}>
<div className="relative"> <span className={classes.badge.text}>{badgeText}</span>
{badgeText && ( </div>
<div className={classes.badge.container}> )}
<span className={classes.badge.text}> <VtThumbnail
{badgeText} thumbnail={product.thumbnail}
</span> className={classes.thumbnail.className}
</div> images={product.images}
)} size={classes.thumbnail.size}
<VtThumbnail isFeatured
thumbnail={product.thumbnail} />
className={classes.thumbnail.className} </div>
images={product.images} </LocalizedClientLink>
size={classes.thumbnail.size}
isFeatured
/>
</div>
<div className={classes.content}> <div className={classes.content}>
{product.collection && ( {classes.subtitle && product.collection && (
<LocalizedClientLink <LocalizedClientLink
href={`/collections/${product.collection.handle}`} href={`/collections/${product.collection.handle}`}
className="txt-small text-ui-fg-muted hover:text-ui-fg-subtle" className="txt-small text-ui-fg-muted hover:text-ui-fg-subtle"
> >
{product.collection.title} {product.subtitle}
</LocalizedClientLink> </LocalizedClientLink>
)} )}
<Heading <LocalizedClientLink href={`/products/${product.handle}`} className="block">
level="h3" <Heading
className={classes.title} level="h3"
data-testid="product-card-title" className={classes.title}
> data-testid="product-card-title"
{product.title} >
</Heading> {product.title}
</Heading>
</LocalizedClientLink>
<div className={classes.price}> <div className={classes.price}>
{cheapestPrice && <PreviewPrice price={cheapestPrice} />} {cheapestPrice && <PreviewPrice price={cheapestPrice} />}
</div> </div>
<Text className="mt-1 txt-compact-small text-ui-fg-muted">
inkl. MwSt. zzgl. Versandkosten
</Text>
<div className="my-4"> {(classes.reviews.rating !== undefined ||
<Divider /> classes.reviews.count !== undefined) && (
</div> <div
className={
classes.reviews.container || "mt-2 flex items-center gap-3"
}
>
<div className="relative inline-block">
<div className={classes.reviews.stars}>
{Array.from({ length: 5 }).map((_, i) => (
<span
key={`star-empty-${i}`}
className={classes.reviews.emptyStar}
>
</span>
))}
</div>
<div
className="absolute inset-0 overflow-hidden"
style={{
width: `${Math.max(
0,
Math.min(
100,
(((classes.reviews.rating as number) ?? 0) / 5) * 100
)
)}%`,
}}
>
<div className={classes.reviews.stars}>
{Array.from({ length: 5 }).map((_, i) => (
<span
key={`star-fills-${i}`}
className={classes.reviews.star}
>
</span>
))}
</div>
</div>
</div>
{typeof classes.reviews.count === "number" && (
<span className={classes.reviews.text}>
{classes.reviews.count} Reviews
</span>
)}
</div>
)}
<Text className="txt-small text-ui-fg-subtle">{description}</Text> <Text className={clx(classes.description, "txt-small my-4")}>{description}</Text>
<Text className="my-3 txt-small text-ui-fg-muted">
Lieferzeit: {deliveryTime}
</Text>
<div className="flex gap-3 mt-auto"> <div className="flex gap-3 mt-auto">
<Button <Button
@ -141,10 +197,7 @@ export default function ProductCard({
href={`/products/${product.handle}`} href={`/products/${product.handle}`}
className="flex-1" className="flex-1"
> >
<Button <Button variant="secondary" className={classes.button.moreInfo}>
variant="secondary"
className={classes.button.moreInfo}
>
More Info {classes.button.isShowIcon && <ChevronRight />} More Info {classes.button.isShowIcon && <ChevronRight />}
</Button> </Button>
</LocalizedClientLink> </LocalizedClientLink>

View File

@ -1,11 +1,28 @@
import fs from "fs" import fs from "fs"
import path from "path" import path from "path"
import { jsonFileNames } from "./devJsonFileNames"; import { jsonFileNames } from "./devJsonFileNames"
const fileName = jsonFileNames.namVibentec; const fileName = jsonFileNames.nam3Bear
export async function loadDesignConfig() { async function readDesignFile() {
const filePath = path.join(process.cwd(), "config", fileName) const filePath = path.join(process.cwd(), "config", fileName)
const fileData = await fs.promises.readFile(filePath, "utf-8") const fileData = await fs.promises.readFile(filePath, "utf-8")
return JSON.parse(fileData) 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()
}