Compare commits

..

5 Commits

17 changed files with 896 additions and 690 deletions

View File

@ -136,31 +136,13 @@
], ],
"right": [ "right": [
{ {
"Dropdown": { "VtCountryCodeSelect": {
"config": { "config": {
"trigger": { "trigger": {
"icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_Germany.svg/1200px-Flag_of_Germany.svg.png", "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",
"text": "Germany (EUR)", "isFlag": true,
"className": "font-bold text-[1rem] text-[#003F31] flex items-center gap-1 hover:text-[#009b93]", "isDisplayFullname": true
"isShowArrow": true }
},
"items": [
{
"icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_Germany.svg/1200px-Flag_of_Germany.svg.png",
"text": "Germany (EUR)",
"href": "/"
},
{
"icon": "https://upload.wikimedia.org/wikipedia/commons/2/20/Flag_of_the_Netherlands.svg",
"text": "Netherlands (EUR)",
"href": "/"
},
{
"icon": "https://cdn.shopify.com/s/files/1/0275/7784/3817/files/Australia_Flag.svg?v=1657674627",
"text": "Australia (AUD)",
"href": "/"
}
]
} }
} }
}, },
@ -173,18 +155,18 @@
} }
}, },
{ {
"Button": { "AccountButton": {
"config": { "config": {
"icon": "User", "icon": "User",
"className": "shadow-none" "className": " flex items-center gap-1 shadow-none"
} }
} }
}, },
{ {
"VtCartButton": { "VtCartButton": {
"config": { "config": {
"variant": "shoppingBagbutton", "icon": "ShoppingBag",
"className": "shadow-none" "className": "shadow-none bg-transparent text-black w-[50px]"
} }
} }
} }
@ -215,388 +197,158 @@
{ {
"Footer": { "Footer": {
"config": { "config": {
"className": "content-container flex w-full bg-[#003f31]", "className": "content-container flex w-full bg-[#003f31] text-white border justify-between pb-8 pt-14",
"children": [ "leftClassName": "flex-col ml-3",
"centerClassName": "",
"rightClassName": "flex gap-[12rem] mr-[100px]",
"left": [
{ {
"Section": { "Image": {
"config": { "config": {
"className": "grid grid-cols-2 w-full py-[40px]" "src": "/3bear-white-logo.avif",
"alt": "MyShop",
"className": "h-full w-[150px] ml-10 pb-6",
"objectFit": "contain"
}
}
},
{
"Text": {
"config": {
"label": "Melde dich für unsere Oatnews an 💛",
"className": "flex flex-col gap-y-2 ml-10 w-full text-[24px] font-semibold text-white"
}
}
},
{
"Input": {
"config": {
"placeholder": "E-mail",
"className": "w-[350px] mt-6 border border-gray-200 bg-transparent rounded-md h-[48px] px-[16px] text-[16px] leading-[125%] text-white flex font-bold ml-10"
}
}
},
{
"VtSocialLinks": {
"config": {
"className": "flex items-center gap-1 ml-6 mt-8"
}, },
"children": [ "children": [
{ {
"Section": { "Button": {
"config": { "config": {
"className": "flex mr-8 gap-1 w-full flex-col gap-6" "icon": "Twitter",
}, "iconClassName": "text-white",
"children": [ "className": "w-[48px] h-[48px] shadow-none hover:bg-transparent bg-transparent text-white rounded-md flex items-center justify-center"
{ }
"Image": {
"config": {
"src": "/3bear-white-logo.avif",
"alt": "B Corp Logo",
"className": "w-[150px] h-[108px]"
}
}
},
{
"Text": {
"config": {
"label": "Melde dich für unsere Oatnews an 💛",
"className": "text-[26px] leading-[125%] text-white flex font-bold"
}
}
},
{
"Section": {
"config": {
"className": "flex w-full flex gap-6"
},
"children": [
{
"Input": {
"config": {
"placeholder": "E-mail",
"className": "w-[50%] border border-gray-200 bg-transparent rounded-md h-[48px] px-[16px] text-[16px] leading-[125%] text-white flex font-bold"
}
}
}
]
}
},
{
"Section": {
"config": {
"className": "flex w-full flex"
},
"children": [
{
"Button": {
"config": {
"icon": "Twitter",
"className": "text-white flex justify-start gap-1 shadow-none w-[50px] bg-transparent hover:bg-transparent"
}
}
},
{
"Button": {
"config": {
"icon": "Twitter",
"className": "text-white flex justify-start gap-1 shadow-none w-[50px] bg-transparent hover:bg-transparent"
}
}
},
{
"Button": {
"config": {
"icon": "Twitter",
"className": "text-white flex justify-start gap-1 shadow-none w-[50px] bg-transparent hover:bg-transparent"
}
}
},
{
"Button": {
"config": {
"icon": "Twitter",
"className": "text-white flex justify-start gap-1 shadow-none w-[50px] bg-transparent hover:bg-transparent"
}
}
},
{
"Button": {
"config": {
"icon": "Twitter",
"className": "text-white flex justify-start gap-1 shadow-none w-[50px] bg-transparent hover:bg-transparent"
}
}
}
]
}
}
]
} }
}, },
{ {
"Section": { "Button": {
"config": { "config": {
"className": "flex mr-8 gap-1 w-full gap-6" "icon": "Twitter",
}, "iconClassName": "text-white",
"children": [ "className": "w-[48px] h-[48px] shadow-none hover:bg-transparent bg-transparent text-white rounded-md flex items-center justify-center"
{ }
"Section": { }
"config": { },
"className": "flex mr-8 gap-1 w-full flex-col gap-6" {
}, "Button": {
"children": [ "config": {
{ "icon": "Twitter",
"Link": { "iconClassName": "text-white",
"config": { "className": "w-[48px] h-[48px] shadow-none hover:bg-transparent bg-transparent text-white rounded-md flex items-center justify-center"
"label": "Weiteres", }
"href": "/", }
"className": "text-[16px] leading-[125%] text-white flex hover:text-white font-bold" },
} {
} "Button": {
}, "config": {
{ "icon": "Twitter",
"Link": { "iconClassName": "text-white",
"config": { "className": "w-[48px] h-[48px] shadow-none hover:bg-transparent bg-transparent text-white rounded-md flex items-center justify-center"
"label": "FAQ", }
"href": "/",
"className": "text-[14px] leading-[160%] text-white flex mr-8 gap-1 hover:bg-transparent hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Track My Order",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Store policies",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Contact us",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Placeholder",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Placeholder",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Placeholder",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Placeholder",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
}
]
}
},
{
"Section": {
"config": {
"className": "flex mr-8 gap-1 w-full flex-col gap-6"
},
"children": [
{
"Link": {
"config": {
"label": "Kundendienst",
"href": "/",
"className": "text-[16px] leading-[125%] text-white flex hover:text-white font-bold"
}
}
},
{
"Link": {
"config": {
"label": "FAQ",
"href": "/",
"className": "text-[14px] leading-[160%] text-white flex mr-8 gap-1 hover:bg-transparent hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Track My Order",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Store policies",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Contact us",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Placeholder",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Placeholder",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Placeholder",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Placeholder",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
}
]
}
},
{
"Section": {
"config": {
"className": "flex mr-8 gap-1 w-full flex-col gap-6"
},
"children": [
{
"Link": {
"config": {
"label": "Info",
"href": "/",
"className": "text-[16px] leading-[125%] text-white flex hover:text-white font-bold"
}
}
},
{
"Link": {
"config": {
"label": "FAQ",
"href": "/",
"className": "text-[14px] leading-[160%] text-white flex mr-8 gap-1 hover:bg-transparent hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Track My Order",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Store policies",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Contact us",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Placeholder",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Placeholder",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Placeholder",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
},
{
"Link": {
"config": {
"label": "Placeholder",
"href": "/",
"className": "text-[14px] leading-[125%] text-white flex hover:text-white font-extralight"
}
}
}
]
}
}
]
} }
} }
] ]
} }
} }
],
"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"
}
]
}
}
}
] ]
} }
} }

View File

@ -0,0 +1,221 @@
[
{
"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
}
}
}
}
]
}
}
},
{
"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]"
}
}
}
}
],
"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"
}
}
}
]
}
}
}
]
}
},
{
"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",
"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]"
}
}
}
]
}
}
}
]

View File

@ -45,7 +45,7 @@
"config": { "config": {
"label": "Mehr Info", "label": "Mehr Info",
"href": "/", "href": "/",
"className": "text-[13px] flex items-center bg-[#112638] gap-1 " "className": "text-[13px] w-fit text-white px-3 flex items-center bg-[#112638] gap-1 "
} }
} }
} }
@ -70,20 +70,12 @@
} }
}, },
{ {
"Dropdown": { "VtCountryCodeSelect": {
"config": { "config": {
"trigger": { "trigger": {
"text": "DE", "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",
"className": "font-bold text-[13px] text-[#11314E] flex items-center gap-1 hover:text-[#009b93]", "isFlag": false
"isShowArrow": true }
},
"items": [
{
"icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_Germany.svg/1200px-Flag_of_Germany.svg.png",
"text": "DE",
"href": "/"
}
]
} }
} }
} }
@ -154,10 +146,10 @@
} }
}, },
{ {
"Button": { "AccountButton": {
"config": { "config": {
"icon": "User", "icon": "User",
"className": " flex items-center gap-1 shadow-none w-[50px]" "className": " flex items-center gap-1 shadow-none"
} }
} }
}, },
@ -172,7 +164,7 @@
{ {
"VtCartButton": { "VtCartButton": {
"config": { "config": {
"variant": "shoppingBagbutton", "icon": "ShoppingCart",
"className": "shadow-none bg-transparent text-black w-[50px]" "className": "shadow-none bg-transparent text-black w-[50px]"
} }
} }
@ -204,241 +196,189 @@
{ {
"Footer": { "Footer": {
"config": { "config": {
"children": [ "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": [
{ {
"Image": { "Image": {
"config": { "config": {
"src": "/VibentecIT-logo.svg", "src": "/VibentecIT-logo.svg",
"alt": "MyShop", "alt": "MyShop",
"className": "h-[128px] w-[324px] ml-[3rem]", "className": "h-[100px] w-[320px]",
"objectFit": "contain" "objectFit": "contain"
} }
} }
}, },
{ {
"Section": { "VtMenuItem": {
"config": { "config": {
"className": "flex items-start px-[3rem] justify-between" "title": "Der Wegbereiter für innovative IT-Lösungen",
}, "className": "flex flex-col gap-y-2 ml-10 w-[320px] text-[24px] font-semibold text-[#11314E]",
"children": [ "itemClassName": "text-ui-fg-subtle txt-small",
{ "items": [
"Section": { {
"config": { "text": "Tauchen Sie ein in eine Welt modernster Technologien, zuverlässiger Support und proaktiver Innovation gemeinsam gestalten wir die digitale Zukunft Ihres Unternehmens.",
"className": "flex flex-col" "href": "/"
},
"children": [
{
"Link": {
"config": {
"label": "Der Wegbereiter für innovative IT-Lösungen",
"href": "/",
"className": "text-[24px] leading-[125%] text-[#11314E] flex mr-8 gap-1 hover:underline font-bold w-[336px] pl-[2rem] mb-[22px]"
}
}
},
{
"Link": {
"config": {
"label": "Tauchen Sie ein in eine Welt modernster Technologien, zuverlässiger Support und proaktiver Innovation gemeinsam gestalten wir die digitale Zukunft Ihres Unternehmens.",
"href": "/",
"className": "text-[13px] leading-[160%] text-[#11314E] flex items-center mr-8 gap-1 w-[336px] pl-[2rem] hover:no-underline"
}
}
},
{
"Button": {
"config": {
"label": "Kontaktieren Sie Uns",
"labelClassName": "order-[1]",
"iconClassName": "order-[2]",
"icon": "ChevronRight",
"className": "mt-[24px] flex items-center w-fit hover:bg-black gap-1 shadow-none p-[1rem] bg-[#18181B] text-white ml-[2rem]"
}
}
}
]
} }
}, ]
{ }
"Section": {
"config": {
"className": "flex items-start mt-[2rem]"
},
"children": [
{
"Section": {
"config": {
"className": "flex flex-col"
},
"children": [
{
"Link": {
"config": {
"label": "Unternehmen",
"href": "/",
"className": "text-[24px] leading-[125%] text-[#11314E] flex mr-8 gap-1 hover:underline font-bold w-[200px] pl-[2rem] mb-[16px]"
}
}
},
{
"Link": {
"config": {
"label": "Über Uns",
"href": "/",
"className": "text-[13px] leading-[160%] text-[#11314E] flex items-center mr-8 gap-1 w-[200px] pl-[2rem] hover:no-underline"
}
}
},
{
"Link": {
"config": {
"label": "Placeholder",
"href": "/",
"className": "text-[13px] leading-[160%] text-[#11314E] flex items-center mr-8 gap-1 w-[200px] pl-[2rem] hover:no-underline"
}
}
},
{
"Link": {
"config": {
"label": "Placeholder",
"href": "/",
"className": "text-[13px] leading-[160%] text-[#11314E] flex items-center mr-8 gap-1 w-[200px] pl-[2rem] hover:no-underline"
}
}
}
]
}
},
{
"Section": {
"config": {
"className": "flex flex-col gap-[6px]"
},
"children": [
{
"Link": {
"config": {
"label": "Social Media",
"href": "/",
"className": "text-[24px] leading-[125%] text-[#11314E] flex mr-8 mb-[2px] gap-1 hover:underline font-bold w-[200px] pl-[2rem]"
}
}
},
{
"Button": {
"config": {
"label": "Über Uns",
"icon": "Twitter",
"className": "text-[13px] leading-[160%] text-[#11314E] flex justify-start font-semibold mr-8 gap-1 shadow-none w-[200px] pl-[2rem] hover:bg-transparent"
}
}
},
{
"Button": {
"config": {
"label": "Über Uns",
"icon": "Twitter",
"className": "text-[13px] leading-[160%] text-[#11314E] flex justify-start font-semibold mr-8 gap-1 shadow-none w-[200px] pl-[2rem] hover:bg-transparent"
}
}
},
{
"Button": {
"config": {
"label": "Über Uns",
"icon": "Twitter",
"className": "text-[13px] leading-[160%] text-[#11314E] flex justify-start font-semibold mr-8 gap-1 shadow-none w-[200px] pl-[2rem] hover:bg-transparent"
}
}
}
]
}
},
{
"Section": {
"config": {
"className": "flex flex-col"
},
"children": [
{
"Link": {
"config": {
"label": "Addresse",
"href": "/",
"className": "text-[24px] leading-[125%] text-[#11314E] flex mr-8 gap-1 hover:underline font-bold w-[200px] pl-[2rem] mb-[16px]"
}
}
},
{
"Link": {
"config": {
"label": "Über Uns",
"href": "/",
"className": "text-[13px] leading-[160%] text-[#11314E] flex items-center mr-8 gap-1 w-[200px] pl-[2rem] hover:no-underline"
}
}
},
{
"Link": {
"config": {
"label": "Social Media",
"href": "/",
"className": "text-[13px] leading-[160%] text-[#11314E] flex items-center mr-8 gap-1 w-[200px] pl-[2rem] hover:no-underline"
}
}
},
{
"Link": {
"config": {
"label": "Über Uns",
"href": "/",
"className": "text-[13px] leading-[160%] text-[#11314E] flex items-center mr-8 gap-1 w-[200px] pl-[2rem] hover:no-underline"
}
}
}
]
}
}
]
}
},
{
"Section": {
"config": {
"className": "flex flex-col mt-[5rem]"
},
"children": [
{
"Link": {
"config": {
"label": "Tauchen Sie ein in eine Welt modernster Technologien, zuverlässiger Support und proaktiver Innovation gemeinsam gestalten wir die digitale Zukunft Ihres Unternehmens.",
"href": "/",
"className": "text-[13px] leading-[160%] text-[#11314E] flex items-center mr-8 gap-1 w-full pl-[2rem] hover:no-underline"
}
}
}
]
}
}
]
} }
}, },
{ {
"Section": { "Button": {
"config": { "config": {
"className": "relative flex px-[3rem] justify-between mt-[29px] pt-[8px] after:content-[''] after:absolute after:left-[4.8rem] after:right-[3rem] after:top-0 after:h-[1px] after:bg-[#285A86] mb-10" "label": "Kontaktieren Sie uns",
}, "className": "bg-black text-white items-center flex gap-2 ml-10 px-4 mt-[24px] py-5 rounded-md w-fit text-[14px]",
"children": [ "icon": "ChevronRightMini",
{ "iconClassName": "order-1"
"Text": { }
"config": { }
"label": "©2025 Vibentec IT. All rights reserved", }
"className": "text-[13px] leading-[160%] text-[#11314E] flex items-center mr-8 gap-1 w-full pl-[2rem]" ],
} "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",
"left": [
{
"Text": {
"config": {
"label": "©2025 Vibentec IT. All rights reserved",
"className": "text-[14px] font-[400] pt-2"
}
}
}
],
"center": [],
"right": [
{
"Button": {
"config": {
"href": "/",
"icon": "Mastercard",
"className": "shadow-none"
}
}
},
{
"Button": {
"config": {
"href": "/",
"icon": "PayPal",
"className": "shadow-none"
}
}
},
{
"Button": {
"config": {
"href": "/",
"icon": "Visa",
"className": "shadow-none"
}
} }
} }
] ]

View File

@ -1,8 +1,8 @@
import { retrieveCart } from "@lib/data/cart" import { retrieveCart } from "@lib/data/cart"
import CartDropdown from "../cart-dropdown" import CartDropdown from "../cart-dropdown"
export default async function CartButton() { export default async function CartButton({ iconName }: { iconName?: string }) {
const cart = await retrieveCart().catch(() => null) const cart = await retrieveCart().catch(() => null)
return <CartDropdown cart={cart} /> return <CartDropdown cart={cart} iconName={iconName} />
} }

View File

@ -9,6 +9,7 @@ import {
import { convertToLocale } from "@lib/util/money" import { convertToLocale } from "@lib/util/money"
import { HttpTypes } from "@medusajs/types" import { HttpTypes } from "@medusajs/types"
import { Button } from "@medusajs/ui" import { Button } from "@medusajs/ui"
import * as MedusaIcons from "@medusajs/icons"
import DeleteButton from "@modules/common/components/delete-button" import DeleteButton from "@modules/common/components/delete-button"
import LineItemOptions from "@modules/common/components/line-item-options" import LineItemOptions from "@modules/common/components/line-item-options"
import LineItemPrice from "@modules/common/components/line-item-price" import LineItemPrice from "@modules/common/components/line-item-price"
@ -19,8 +20,10 @@ import { Fragment, useEffect, useRef, useState } from "react"
const CartDropdown = ({ const CartDropdown = ({
cart: cartState, cart: cartState,
iconName,
}: { }: {
cart?: HttpTypes.StoreCart | null cart?: HttpTypes.StoreCart | null
iconName?: string
}) => { }) => {
const [activeTimer, setActiveTimer] = useState<NodeJS.Timer | undefined>( const [activeTimer, setActiveTimer] = useState<NodeJS.Timer | undefined>(
undefined undefined
@ -73,6 +76,10 @@ const CartDropdown = ({
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [totalItems, itemRef.current]) }, [totalItems, itemRef.current])
const Icon = iconName
? (MedusaIcons as Record<string, React.ComponentType<any>>)[iconName]
: undefined
return ( return (
<div <div
className="h-full z-50" className="h-full z-50"
@ -81,11 +88,15 @@ const CartDropdown = ({
> >
<Popover className="relative h-full"> <Popover className="relative h-full">
<PopoverButton className="h-full"> <PopoverButton className="h-full">
<LocalizedClientLink {Icon ? (
className="hover:text-ui-fg-base" <Icon />
href="/cart" ) : (
data-testid="nav-cart-link" <LocalizedClientLink
>{`Cart (${totalItems})`}</LocalizedClientLink> className="hover:text-ui-fg-base"
href="/cart"
data-testid="nav-cart-link"
>{`Cart (${totalItems})`}</LocalizedClientLink>
)}
</PopoverButton> </PopoverButton>
<Transition <Transition
show={cartDropdownOpen} show={cartDropdownOpen}

View File

@ -1,26 +1,38 @@
import LocalizedClientLink from "@modules/common/components/localized-client-link" import LocalizedClientLink from "@modules/common/components/localized-client-link"
import { LayoutComponentDefinition, LayoutContext } from "vibentec/component-map"; import {
LayoutComponentDefinition,
LayoutContext,
} from "vibentec/component-map"
import { clx } from "@medusajs/ui" import { clx } from "@medusajs/ui"
import * as MedusaIcons from "@medusajs/icons"
export const AccountButton = ({ nodes, context }: { nodes: LayoutComponentDefinition; context: LayoutContext }) => { export const AccountButton = ({
nodes,
context,
}: {
nodes: LayoutComponentDefinition
context: LayoutContext
}) => {
const props = nodes.config ?? {} const props = nodes.config ?? {}
const className = clx("hover:text-ui-fg-base", props.className); const className = clx("hover:text-ui-fg-base", props.className)
const style: React.CSSProperties = {}; const style: React.CSSProperties = {}
if (props.bgColor) style.backgroundColor = props.bgColor; if (props.bgColor) style.backgroundColor = props.bgColor
if (props.textColor) style.color = props.textColor; if (props.textColor) style.color = props.textColor
const href = props.href ?? "/account" const href = props.href ?? "/account"
const label = props.label ?? "Account" const label = props.label ?? "Account"
const iconName = props.icon
const Icon = iconName
? (MedusaIcons as Record<string, React.ComponentType<any>>)[iconName]
: undefined
return ( return (
<div className="flex items-center h-full" style={style}> <div className="flex items-center h-full">
<LocalizedClientLink <LocalizedClientLink
href={href} href={href}
className={className} className={className}
data-testid="nav-account-link" data-testid="nav-account-link"
> >
{label} {Icon ? <Icon /> : label}
</LocalizedClientLink> </LocalizedClientLink>
</div> </div>
) )
} }

View File

@ -3,23 +3,9 @@ import {
LayoutComponentDefinition, LayoutComponentDefinition,
LayoutContext, LayoutContext,
} from "vibentec/component-map" } from "vibentec/component-map"
import { clx, IconButton } from "@medusajs/ui" import { clx } from "@medusajs/ui"
import { Suspense } from "react" import { Suspense } from "react"
import CartButton from "@modules/layout/components/cart-button" import CartButton from "@modules/layout/components/cart-button"
import { ShoppingBag, ShoppingCart } from "@medusajs/icons"
const IconButtonComponent = ({ className, variant }: { className?: string; variant?: "shoppingBag" | "cart" }) => {
const variants = {
shoppingBag: ShoppingBag,
cart: ShoppingCart,
}
const Icon = variants[variant ?? "shoppingBag"]
return (
<IconButton className={className}>
<Icon />
</IconButton>
)
}
export const VtCartButton = ({ export const VtCartButton = ({
nodes, nodes,
@ -30,15 +16,6 @@ export const VtCartButton = ({
}) => { }) => {
const props = nodes.config ?? {} const props = nodes.config ?? {}
const className = clx("hover:text-ui-fg-base flex gap-2", props.className) const className = clx("hover:text-ui-fg-base flex gap-2", props.className)
const variants = {
link: <CartButton />,
shoppingBagbutton: <IconButtonComponent className={className} variant="shoppingBag" />,
cartIconButton: <IconButtonComponent className={className} variant="cart" />,
}
if (!props.variant) return null
const fallBackComp = variants[props.variant as keyof typeof variants]
return ( return (
<Suspense <Suspense
fallback={ fallback={
@ -51,7 +28,7 @@ export const VtCartButton = ({
</LocalizedClientLink> </LocalizedClientLink>
} }
> >
{fallBackComp} <CartButton iconName={props.icon} />
</Suspense> </Suspense>
) )
} }

View File

@ -20,22 +20,13 @@ export default function VtButton({
(CustomIcons as Record<string, any>)[iconName] (CustomIcons as Record<string, any>)[iconName]
: undefined : undefined
return ( return (
<> <IconButton className={props?.className ?? ""}>
{props?.icon && ( {IconComponent && (
<IconButton className={props?.className ?? ""}> <IconComponent className={props?.iconClassName ?? ""} />
{IconComponent && (
<IconComponent className={props?.iconClassName ?? ""} />
)}
{props?.label && (
<span className={props?.labelClassName ?? ""}>{props.label}</span>
)}
</IconButton>
)} )}
{!props?.icon && ( {props?.label && (
<Button className={props?.className ?? ""}> <span className={props?.labelClassName ?? ""}>{props.label}</span>
{props?.label && <span>{props.label}</span>}
</Button>
)} )}
</> </IconButton>
) )
} }

View File

@ -0,0 +1,112 @@
"use client"
import { Select } from "@medusajs/ui"
import ChevronDown from "@modules/common/icons/chevron-down"
import {
LayoutComponentDefinition,
LayoutContext,
} from "@vibentec/component-map"
import { useMemo, useState, useEffect } from "react"
import { useParams, usePathname, useRouter } from "next/navigation"
import ReactCountryFlag from "react-country-flag"
import { HttpTypes } from "@medusajs/types"
export default function VtCountrySelectClient({
nodes,
context,
regions,
}: {
nodes: LayoutComponentDefinition
context: LayoutContext
regions?: HttpTypes.StoreRegion[]
}) {
const props = nodes.config ?? {}
const triggerText = props?.trigger?.text
const [items, setItems] = useState<{ text: string; label?: string }[]>([])
const { countryCode } = useParams()
console.log(regions)
useEffect(() => {
if (!regions || regions.length === 0) {
setItems([])
return
}
const opts = regions
.map((r) =>
(r.countries || []).map((c) => ({
text: c.iso_2 ?? "",
label: c.display_name,
}))
)
.flat()
.filter((o) => o.text)
.sort((a, b) => (a.label ?? "").localeCompare(b.label ?? ""))
console.log(opts)
setItems(opts)
}, [regions])
const initialValue = (countryCode as string) || triggerText || ""
const [value, setValue] = useState(initialValue)
const pathname = usePathname()
const router = useRouter()
const handleChange = (next: string) => {
setValue(next)
if (!pathname || !next) return
const parts = pathname.split("/")
if (parts.length > 1) {
parts[1] = next.toLowerCase()
const newPath = parts.join("/")
router.replace(newPath)
}
}
const selectedItem = useMemo(() => {
return items.find((i) => i.text === value)
}, [items, value])
if (!triggerText && items.length === 0) {
return null
}
return (
<Select value={value} onValueChange={handleChange}>
<Select.Trigger
className={
(props.trigger?.className ?? "") +
"flex items-center gap-1 [&_svg:not(:first-of-type)]:hidden"
}
>
<span className="txt-compact-small flex items-center">
{/* @ts-ignore */}
{props.trigger?.isFlag && (
<ReactCountryFlag
svg
style={{
width: "16px",
height: "16px",
}}
countryCode={value ?? ""}
/>
)}
</span>
{props.trigger?.isDisplayFullname ? (selectedItem?.label || value) : (selectedItem?.text.toUpperCase() || value)} <ChevronDown />
</Select.Trigger>
<Select.Content>
{items.length > 0 &&
items.map((item: { text: string; label?: string }, index: number) => (
<Select.Item value={item.text || ""} key={item.text + index}>
<div className="flex items-center w-full gap-3">
{props.trigger?.isFlag && item.text && (
<ReactCountryFlag
svg
style={{
width: "16px",
height: "16px",
}}
countryCode={item.text ?? ""}
/>
)}
{item.text.toUpperCase()}
</div>
</Select.Item>
))}
</Select.Content>
</Select>
)
}

View File

@ -0,0 +1,22 @@
import { listRegions, getRegion } from "@lib/data/regions"
import { HttpTypes } from "@medusajs/types"
import {
LayoutComponentDefinition,
LayoutContext,
} from "@vibentec/component-map"
import VtCountryCodeSelectClient from "./index"
export default async function VtCountryCodeSelect({
nodes,
context,
}: {
nodes: LayoutComponentDefinition
context: LayoutContext
}) {
const regions = (await listRegions()) as HttpTypes.StoreRegion[]
return (
<VtCountryCodeSelectClient nodes={nodes} context={context} regions={regions} />
)
}

View File

@ -0,0 +1,72 @@
"use client"
import { Select } from "@medusajs/ui"
import LocalizedClientLink from "@modules/common/components/localized-client-link"
import ChevronDown from "@modules/common/icons/chevron-down"
import {
LayoutComponentDefinition,
LayoutContext,
} from "@vibentec/component-map"
export default function VtCurrencySelect({
nodes,
context,
}: {
nodes: LayoutComponentDefinition
context: LayoutContext
}) {
const props = nodes.config ?? {}
if (!props.trigger.text || props.items.length === 0) {
return null
}
return (
<Select>
<Select.Trigger
className={props.trigger.className + " flex items-center gap-1"}
>
{props.trigger.icon && (
<img
src={props.trigger.icon}
alt={props.trigger.text}
className="w-5 h-5 rounded-[50%] mr-3"
/>
)}
{props.trigger.text} {props.trigger.isShowArrow && <ChevronDown />}
</Select.Trigger>
<Select.Content>
{props.items.length > 0 &&
props.items.map(
(
item: {
text: string
className?: string
href?: string
icon?: string
},
index: number
) => (
<Select.Item
value={item.text || ""}
key={item.text + index}
className={item.className || ""}
>
{item.icon && (
<img
src={item.icon}
alt={item.text}
className="w-5 h-5 rounded-[50%] mr-3"
/>
)}
{item.href ? (
<LocalizedClientLink href={item.href}>
{item.text}
</LocalizedClientLink>
) : (
item.text
)}
</Select.Item>
)
)}
</Select.Content>
</Select>
)
}

View File

@ -24,7 +24,21 @@ export default async function VtFooter({
return ( return (
<footer className={props?.className ?? ""}> <footer className={props?.className ?? ""}>
{props.children && <DynamicLayoutRenderer nodes={props.children} context={context} />} <div className={clx("flex gap-x-4 h-full", props?.leftClassName)}>
{props.left && (
<DynamicLayoutRenderer nodes={props.left} context={context} />
)}
</div>
<div className={clx("flex gap-x-4 h-full", props?.centerClassName)}>
{props.center && (
<DynamicLayoutRenderer nodes={props.center} context={context} />
)}
</div>
<div className={clx("flex gap-x-4 h-full", props?.rightClassName)}>
{props.right && (
<DynamicLayoutRenderer nodes={props.right} context={context} />
)}
</div>
</footer> </footer>
) )
} }

View File

@ -21,7 +21,7 @@ export default function VtImage({
const props = (nodes.config as VtImageConfig) ?? {} const props = (nodes.config as VtImageConfig) ?? {}
return ( return (
<div className={clx("relative", props.className)}> <div className={clx("relative", props.className)}>
<Image src={props.src} alt={props.alt} fill objectFit={props.objectFit ?? "contain"} /> <img src={props.src} alt={props.alt} className={clx("w-full h-full object-cover", props.objectFit)} />
</div> </div>
) )
} }

View File

@ -0,0 +1,56 @@
"use client"
import {
LayoutComponentDefinition,
LayoutContext,
} from "@vibentec/component-map"
import LocalizedClientLink from "@modules/common/components/localized-client-link"
import * as MedusaIcons from "@medusajs/icons"
import * as CustomIcons from "@modules/common/icons"
export default function VtMenuItem({
nodes,
context,
}: {
nodes: LayoutComponentDefinition
context: LayoutContext
}) {
const props = nodes.config ?? {}
const title = props.title ?? ""
const items = props.items ?? []
const icon = props.icon ?? ""
const getIconComponent = (icon: string | undefined) => {
return icon
? (MedusaIcons as Record<string, any>)[icon] ??
(CustomIcons as Record<string, any>)[icon]
: undefined
}
return (
<div className={props.className ?? "flex flex-col gap-y-2"}>
<span>{title}</span>
<ul className="grid grid-cols-1 gap-2" data-testid="footer-categories">
{items.map((item: { text: string; href?: string; icon?: string }, index: number) => {
const Icon = getIconComponent(item.icon)
return (
<li
key={`${item.text}-${index}`}
className={props.itemClassName ?? "text-ui-fg-subtle txt-small"}
>
{Icon && <Icon className={props.iconClassName ?? "inline-block mr-2"} />}
{item.href ? (
<LocalizedClientLink
className="hover:text-ui-fg-base"
href={item.href}
data-testid="category-link"
>
{item.text}
</LocalizedClientLink>
) : (
<span className="hover:text-ui-fg-base">{item.text}</span>
)}
</li>
)
})}
</ul>
</div>
)
}

View File

@ -0,0 +1,17 @@
import { LayoutComponentDefinition, LayoutContext } from "@vibentec/component-map"
import { DynamicLayoutRenderer } from "@vibentec/renderer"
export default function VtSocialLinks({
nodes,
context,
}: {
nodes: LayoutComponentDefinition
context: LayoutContext
}) {
const props = nodes.config ?? {}
return (
<div className={props.className ?? ""}>
{nodes.children && <DynamicLayoutRenderer nodes={nodes.children} context={context} />}
</div>
)
}

View File

@ -19,6 +19,10 @@ import VtSearchInput from "@modules/layout/templates/vt-search-input"
import VtSection from "@modules/layout/templates/vt-section" import VtSection from "@modules/layout/templates/vt-section"
import VtText from "@modules/layout/templates/vt-text" import VtText from "@modules/layout/templates/vt-text"
import VtInput from "@modules/layout/templates/vt-input" import VtInput from "@modules/layout/templates/vt-input"
import VtCurrencySelect from "@modules/layout/templates/vt-currency-select"
import VtMenuItem from "@modules/layout/templates/vt-menu-item"
import VtCountryCodeSelect from "@modules/layout/templates/vt-country-select/server"
import VtSocialLinks from "@modules/layout/templates/vt-social-link"
type ComponentConfig = Record<string, any>; type ComponentConfig = Record<string, any>;
@ -64,11 +68,15 @@ export const componentMap: Record<string, ComponentRenderer> = {
Section: nodesContextRenderer(VtSection), Section: nodesContextRenderer(VtSection),
SearchInput: nodesContextRenderer(VtSearchInput), SearchInput: nodesContextRenderer(VtSearchInput),
VtCartButton: nodesContextRenderer(VtCartButton), VtCartButton: nodesContextRenderer(VtCartButton),
VtCurrencySelect: nodesContextRenderer(VtCurrencySelect),
VtCountryCodeSelect: nodesContextRenderer(VtCountryCodeSelect),
VtSocialLinks: nodesContextRenderer(VtSocialLinks),
Link: nodesContextRenderer(VtLink), Link: nodesContextRenderer(VtLink),
Input: nodesContextRenderer(VtInput), Input: nodesContextRenderer(VtInput),
Image: nodesContextRenderer(VtImage), Image: nodesContextRenderer(VtImage),
Text: nodesContextRenderer(VtText), Text: nodesContextRenderer(VtText),
Dropdown: nodesContextRenderer(VtDropdown), Dropdown: nodesContextRenderer(VtDropdown),
VtMenuItem: nodesContextRenderer(VtMenuItem),
CartMismatchBanner: configOnly(CartMismatchBanner), CartMismatchBanner: configOnly(CartMismatchBanner),
FreeShippingPriceNudge: configOnly(FreeShippingPriceNudge), FreeShippingPriceNudge: configOnly(FreeShippingPriceNudge),
PropsChildren: { PropsChildren: {

View File

@ -3,5 +3,6 @@ export const jsonFileNames = {
stePlayGround: "ste.playground.design.json", stePlayGround: "ste.playground.design.json",
nam3Bear: "nam.3bear.design.json", nam3Bear: "nam.3bear.design.json",
namDrsquatch: "nam.drsquatch.design.json", namDrsquatch: "nam.drsquatch.design.json",
namVibentec: "nam.vibentec.design.json" namVibentec: "nam.vibentec.design.json",
namStarter: "nam.mds-starter-design.json",
}; };