@xiwebdesign/xicms-core 7.19.1 → 7.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/settings/SettingsPanel.js +8 -1
- package/dist/admin/settings/SettingsPanel.js.map +1 -1
- package/dist/admin/shop/OrdersTab.js +9 -2
- package/dist/admin/shop/OrdersTab.js.map +1 -1
- package/dist/admin/shop/ProductsTab.d.ts +0 -6
- package/dist/admin/shop/ProductsTab.js +26 -0
- package/dist/admin/shop/ProductsTab.js.map +1 -1
- package/dist/admin/shop/ShopSettingsTab.js +57 -2
- package/dist/admin/shop/ShopSettingsTab.js.map +1 -1
- package/dist/admin.css +1 -1
- package/dist/modules/shop/blocks/Cart.js +8 -2
- package/dist/modules/shop/blocks/Cart.js.map +1 -1
- package/dist/modules/shop/blocks/Checkout.js +32 -8
- package/dist/modules/shop/blocks/Checkout.js.map +1 -1
- package/dist/modules/shop/blocks/ProductGrid.js +5 -1
- package/dist/modules/shop/blocks/ProductGrid.js.map +1 -1
- package/dist/modules/shop/settings.d.ts +8 -0
- package/dist/modules/shop/settings.js +21 -1
- package/dist/modules/shop/settings.js.map +1 -1
- package/dist/modules/shop/strings.d.ts +2 -0
- package/dist/modules/shop/strings.js +4 -0
- package/dist/modules/shop/strings.js.map +1 -1
- package/dist/schema/shopGeld.d.ts +30 -3
- package/dist/schema/shopGeld.js +19 -4
- package/dist/schema/shopGeld.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/admin.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
2
|
-
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-200:oklch(88.5% .062 18.334);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-600:oklch(66.6% .179 58.318);--color-amber-700:oklch(55.5% .163 48.998);--color-amber-800:oklch(47.3% .137 46.201);--color-amber-900:oklch(41.4% .112 45.904);--color-emerald-700:oklch(50.8% .118 165.612);--color-blue-600:oklch(54.6% .245 262.881);--color-indigo-500:oklch(58.5% .233 277.117);--color-slate-50:oklch(98.4% .003 247.858);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-700:oklch(37.2% .044 257.287);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--container-sm:24rem;--container-md:28rem;--container-3xl:48rem;--container-4xl:56rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--ease-out:cubic-bezier(0, 0, .2, 1);--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--color-brand:#4f46e5;--color-brand-50:#eef2ff;--color-brand-500:#4f46e5;--color-brand-600:#4f46e5;--color-brand-700:#3730a3}}@scope(.xicms-admin){@layer utilities{.pointer-events-none{pointer-events:none!important}.visible{visibility:visible!important}.sr-only{clip-path:inset(50%)!important;white-space:nowrap!important;border-width:0!important;width:1px!important;height:1px!important;margin:-1px!important;padding:0!important;position:absolute!important;overflow:hidden!important}.absolute{position:absolute!important}.fixed{position:fixed!important}.relative{position:relative!important}.static{position:static!important}.sticky{position:sticky!important}.inset-x-0{inset-inline:0!important}.-top-0\.5{top:calc(var(--spacing) * -.5)!important}.-top-2{top:calc(var(--spacing) * -2)!important}.top-0{top:0!important}.-right-2{right:calc(var(--spacing) * -2)!important}.right-0{right:0!important}.-bottom-2{bottom:calc(var(--spacing) * -2)!important}.bottom-0{bottom:0!important}.-left-2{left:calc(var(--spacing) * -2)!important}.left-1\/2{left:50%!important}.z-10{z-index:10!important}.col-span-2{grid-column:span 2/span 2!important}.col-span-full{grid-column:1/-1!important}.container{width:100%!important}@media (min-width:40rem){.container{max-width:40rem!important}}@media (min-width:48rem){.container{max-width:48rem!important}}@media (min-width:64rem){.container{max-width:64rem!important}}@media (min-width:80rem){.container{max-width:80rem!important}}@media (min-width:96rem){.container{max-width:96rem!important}}.-mx-1{margin-inline:calc(var(--spacing) * -1)!important}.-mx-4{margin-inline:calc(var(--spacing) * -4)!important}.mt-0\.5{margin-top:calc(var(--spacing) * .5)!important}.mt-1{margin-top:var(--spacing)!important}.mt-2{margin-top:calc(var(--spacing) * 2)!important}.mt-3{margin-top:calc(var(--spacing) * 3)!important}.mt-4{margin-top:calc(var(--spacing) * 4)!important}.mt-5{margin-top:calc(var(--spacing) * 5)!important}.mt-6{margin-top:calc(var(--spacing) * 6)!important}.mt-auto{margin-top:auto!important}.mr-1{margin-right:var(--spacing)!important}.mr-2{margin-right:calc(var(--spacing) * 2)!important}.mb-1{margin-bottom:var(--spacing)!important}.mb-2{margin-bottom:calc(var(--spacing) * 2)!important}.mb-3{margin-bottom:calc(var(--spacing) * 3)!important}.mb-4{margin-bottom:calc(var(--spacing) * 4)!important}.ml-1{margin-left:var(--spacing)!important}.ml-1\.5{margin-left:calc(var(--spacing) * 1.5)!important}.ml-auto{margin-left:auto!important}.block{display:block!important}.contents{display:contents!important}.flex{display:flex!important}.grid{display:grid!important}.hidden{display:none!important}.inline{display:inline!important}.inline-block{display:inline-block!important}.inline-flex{display:inline-flex!important}.table{display:table!important}.aspect-square{aspect-ratio:1!important}.h-1\.5{height:calc(var(--spacing) * 1.5)!important}.h-2{height:calc(var(--spacing) * 2)!important}.h-5{height:calc(var(--spacing) * 5)!important}.h-6{height:calc(var(--spacing) * 6)!important}.h-8{height:calc(var(--spacing) * 8)!important}.h-9{height:calc(var(--spacing) * 9)!important}.h-10{height:calc(var(--spacing) * 10)!important}.h-14{height:calc(var(--spacing) * 14)!important}.h-16{height:calc(var(--spacing) * 16)!important}.h-28{height:calc(var(--spacing) * 28)!important}.h-32{height:calc(var(--spacing) * 32)!important}.h-\[70vh\]{height:70vh!important}.h-fit{height:fit-content!important}.h-full{height:100%!important}.max-h-\[55vh\]{max-height:55vh!important}.max-h-\[60vh\]{max-height:60vh!important}.min-h-\[8rem\]{min-height:8rem!important}.min-h-screen{min-height:100vh!important}.w-2{width:calc(var(--spacing) * 2)!important}.w-5{width:calc(var(--spacing) * 5)!important}.w-6{width:calc(var(--spacing) * 6)!important}.w-8{width:calc(var(--spacing) * 8)!important}.w-14{width:calc(var(--spacing) * 14)!important}.w-16{width:calc(var(--spacing) * 16)!important}.w-20{width:calc(var(--spacing) * 20)!important}.w-24{width:calc(var(--spacing) * 24)!important}.w-28{width:calc(var(--spacing) * 28)!important}.w-32{width:calc(var(--spacing) * 32)!important}.w-36{width:calc(var(--spacing) * 36)!important}.w-44{width:calc(var(--spacing) * 44)!important}.w-56{width:calc(var(--spacing) * 56)!important}.w-fit{width:fit-content!important}.w-full{width:100%!important}.max-w-3xl{max-width:var(--container-3xl)!important}.max-w-4xl{max-width:var(--container-4xl)!important}.max-w-md{max-width:var(--container-md)!important}.max-w-sm{max-width:var(--container-sm)!important}.max-w-xs{max-width:var(--container-xs)!important}.min-w-0{min-width:0!important}.min-w-8{min-width:calc(var(--spacing) * 8)!important}.flex-1{flex:1!important}.shrink-0{flex-shrink:0!important}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1)!important;translate:var(--tw-translate-x) var(--tw-translate-y)!important}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1)!important;translate:var(--tw-translate-x) var(--tw-translate-y)!important}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)!important}.cursor-default{cursor:default!important}.cursor-pointer{cursor:pointer!important}.resize{resize:both!important}.list-decimal{list-style-type:decimal!important}.list-disc{list-style-type:disc!important}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))!important}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))!important}.grid-cols-\[1fr_1\.4fr_auto\]{grid-template-columns:1fr 1.4fr auto!important}.grid-cols-\[1fr_150px_70px_auto\]{grid-template-columns:1fr 150px 70px auto!important}.grid-cols-\[120px_1fr\]{grid-template-columns:120px 1fr!important}.grid-cols-\[minmax\(0\,1fr\)_auto\]{grid-template-columns:minmax(0,1fr) auto!important}.flex-col{flex-direction:column!important}.flex-wrap{flex-wrap:wrap!important}.place-items-center{place-items:center!important}.items-baseline{align-items:baseline!important}.items-center{align-items:center!important}.items-end{align-items:flex-end!important}.items-start{align-items:flex-start!important}.justify-between{justify-content:space-between!important}.justify-center{justify-content:center!important}.justify-end{justify-content:flex-end!important}.gap-0\.5{gap:calc(var(--spacing) * .5)!important}.gap-1{gap:var(--spacing)!important}.gap-1\.5{gap:calc(var(--spacing) * 1.5)!important}.gap-2{gap:calc(var(--spacing) * 2)!important}.gap-2\.5{gap:calc(var(--spacing) * 2.5)!important}.gap-3{gap:calc(var(--spacing) * 3)!important}.gap-4{gap:calc(var(--spacing) * 4)!important}.gap-6{gap:calc(var(--spacing) * 6)!important}.gap-x-3{column-gap:calc(var(--spacing) * 3)!important}.gap-x-5{column-gap:calc(var(--spacing) * 5)!important}.gap-y-1{row-gap:var(--spacing)!important}.self-center{align-self:center!important}.self-end{align-self:flex-end!important}.truncate{text-overflow:ellipsis!important;white-space:nowrap!important;overflow:hidden!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-x-auto{overflow-x:auto!important}.overflow-y-auto{overflow-y:auto!important}.rounded{border-radius:.25rem!important}.rounded-full{border-radius:3.40282e38px!important}.rounded-lg{border-radius:var(--radius-lg)!important}.rounded-md{border-radius:var(--radius-md)!important}.rounded-xl{border-radius:var(--radius-xl)!important}.rounded-t-lg{border-top-left-radius:var(--radius-lg)!important;border-top-right-radius:var(--radius-lg)!important}.rounded-b-lg{border-bottom-right-radius:var(--radius-lg)!important;border-bottom-left-radius:var(--radius-lg)!important}.border{border-style:var(--tw-border-style)!important;border-width:1px!important}.border-t{border-top-style:var(--tw-border-style)!important;border-top-width:1px!important}.border-t-0{border-top-style:var(--tw-border-style)!important;border-top-width:0!important}.border-b{border-bottom-style:var(--tw-border-style)!important;border-bottom-width:1px!important}.border-amber-300{border-color:var(--color-amber-300)!important}.border-brand-500{border-color:var(--color-brand-500)!important}.border-red-200{border-color:var(--color-red-200)!important}.border-slate-100{border-color:var(--color-slate-100)!important}.border-slate-200{border-color:var(--color-slate-200)!important}.border-slate-300{border-color:var(--color-slate-300)!important}.bg-amber-50{background-color:var(--color-amber-50)!important}.bg-brand-50{background-color:var(--color-brand-50)!important}.bg-brand-500{background-color:var(--color-brand-500)!important}.bg-red-50{background-color:var(--color-red-50)!important}.bg-slate-50{background-color:var(--color-slate-50)!important}.bg-slate-100{background-color:var(--color-slate-100)!important}.bg-slate-200{background-color:var(--color-slate-200)!important}.bg-slate-700{background-color:var(--color-slate-700)!important}.bg-white{background-color:var(--color-white)!important}.object-cover{object-fit:cover!important}.p-0\.5{padding:calc(var(--spacing) * .5)!important}.p-1{padding:var(--spacing)!important}.p-2{padding:calc(var(--spacing) * 2)!important}.p-3{padding:calc(var(--spacing) * 3)!important}.p-4{padding:calc(var(--spacing) * 4)!important}.p-5{padding:calc(var(--spacing) * 5)!important}.p-6{padding:calc(var(--spacing) * 6)!important}.px-1{padding-inline:var(--spacing)!important}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)!important}.px-2{padding-inline:calc(var(--spacing) * 2)!important}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)!important}.px-3{padding-inline:calc(var(--spacing) * 3)!important}.px-4{padding-inline:calc(var(--spacing) * 4)!important}.py-0\.5{padding-block:calc(var(--spacing) * .5)!important}.py-1{padding-block:var(--spacing)!important}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)!important}.py-2{padding-block:calc(var(--spacing) * 2)!important}.py-3{padding-block:calc(var(--spacing) * 3)!important}.py-8{padding-block:calc(var(--spacing) * 8)!important}.py-16{padding-block:calc(var(--spacing) * 16)!important}.pt-0{padding-top:0!important}.pt-1{padding-top:var(--spacing)!important}.pt-3{padding-top:calc(var(--spacing) * 3)!important}.pt-4{padding-top:calc(var(--spacing) * 4)!important}.pt-5{padding-top:calc(var(--spacing) * 5)!important}.pr-2{padding-right:calc(var(--spacing) * 2)!important}.pl-1{padding-left:var(--spacing)!important}.pl-5{padding-left:calc(var(--spacing) * 5)!important}.text-center{text-align:center!important}.text-left{text-align:left!important}.text-right{text-align:right!important}.align-top{vertical-align:top!important}.font-mono{font-family:var(--font-mono)!important}.text-3xl{font-size:var(--text-3xl)!important;line-height:var(--tw-leading,var(--text-3xl--line-height))!important}.text-base{font-size:var(--text-base)!important;line-height:var(--tw-leading,var(--text-base--line-height))!important}.text-lg{font-size:var(--text-lg)!important;line-height:var(--tw-leading,var(--text-lg--line-height))!important}.text-sm{font-size:var(--text-sm)!important;line-height:var(--tw-leading,var(--text-sm--line-height))!important}.text-xl{font-size:var(--text-xl)!important;line-height:var(--tw-leading,var(--text-xl--line-height))!important}.text-xs{font-size:var(--text-xs)!important;line-height:var(--tw-leading,var(--text-xs--line-height))!important}.text-\[10px\]{font-size:10px!important}.text-\[11px\]{font-size:11px!important}.font-bold{--tw-font-weight:var(--font-weight-bold)!important;font-weight:var(--font-weight-bold)!important}.font-medium{--tw-font-weight:var(--font-weight-medium)!important;font-weight:var(--font-weight-medium)!important}.font-normal{--tw-font-weight:var(--font-weight-normal)!important;font-weight:var(--font-weight-normal)!important}.font-semibold{--tw-font-weight:var(--font-weight-semibold)!important;font-weight:var(--font-weight-semibold)!important}.tracking-wide{--tw-tracking:var(--tracking-wide)!important;letter-spacing:var(--tracking-wide)!important}.whitespace-nowrap{white-space:nowrap!important}.whitespace-pre-wrap{white-space:pre-wrap!important}.text-amber-600{color:var(--color-amber-600)!important}.text-amber-700{color:var(--color-amber-700)!important}.text-amber-800{color:var(--color-amber-800)!important}.text-amber-900{color:var(--color-amber-900)!important}.text-brand-700{color:var(--color-brand-700)!important}.text-brand-700\/70{color:#3730a3b3!important}@supports (color:color-mix(in lab, red, red)){.text-brand-700\/70{color:color-mix(in oklab, var(--color-brand-700) 70%, transparent)!important}}.text-emerald-700{color:var(--color-emerald-700)!important}.text-red-600{color:var(--color-red-600)!important}.text-red-700{color:var(--color-red-700)!important}.text-slate-400{color:var(--color-slate-400)!important}.text-slate-500{color:var(--color-slate-500)!important}.text-slate-600{color:var(--color-slate-600)!important}.text-slate-700{color:var(--color-slate-700)!important}.text-slate-800{color:var(--color-slate-800)!important}.text-slate-900{color:var(--color-slate-900)!important}.text-white{color:var(--color-white)!important}.uppercase{text-transform:uppercase!important}.italic{font-style:italic!important}.tabular-nums{--tw-numeric-spacing:tabular-nums!important;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)!important}.line-through{text-decoration-line:line-through!important}.underline{text-decoration-line:underline!important}.opacity-70{opacity:.7!important}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a)!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a)!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor)!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}.ring-brand-500{--tw-ring-color:var(--color-brand-500)!important}.outline{outline-style:var(--tw-outline-style)!important;outline-width:1px!important}.blur{--tw-blur:blur(8px)!important;filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)!important}.grayscale{--tw-grayscale:grayscale(100%)!important;filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)!important}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)!important}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events!important;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function))!important;transition-duration:var(--tw-duration,var(--default-transition-duration))!important}.transition-\[filter\]{transition-property:filter!important;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function))!important;transition-duration:var(--tw-duration,var(--default-transition-duration))!important}.ease-out{--tw-ease:var(--ease-out)!important;transition-timing-function:var(--ease-out)!important}.outline-none{--tw-outline-style:none!important;outline-style:none!important}@media (hover:hover){.group-hover\:opacity-80:is(:where(.group):hover *){opacity:.8!important}}.last\:border-0:last-child{border-style:var(--tw-border-style)!important;border-width:0!important}@media (hover:hover){.hover\:border-brand-500:hover{border-color:var(--color-brand-500)!important}.hover\:bg-slate-50:hover{background-color:var(--color-slate-50)!important}.hover\:bg-slate-100:hover{background-color:var(--color-slate-100)!important}.hover\:bg-slate-200:hover{background-color:var(--color-slate-200)!important}.hover\:text-slate-600:hover{color:var(--color-slate-600)!important}.hover\:text-slate-700:hover{color:var(--color-slate-700)!important}.hover\:text-slate-900:hover{color:var(--color-slate-900)!important}.hover\:underline:hover{text-decoration-line:underline!important}.hover\:brightness-95:hover{--tw-brightness:brightness(95%)!important;filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)!important}}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor)!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}.focus\:ring-indigo-500:focus{--tw-ring-color:var(--color-indigo-500)!important}.focus\:outline-none:focus{--tw-outline-style:none!important;outline-style:none!important}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor)!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}.focus-visible\:ring-brand-500:focus-visible{--tw-ring-color:var(--color-brand-500)!important}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style)!important;outline-width:2px!important}.focus-visible\:outline-offset-2:focus-visible{outline-offset:2px!important}.focus-visible\:outline-blue-600:focus-visible{outline-color:var(--color-blue-600)!important}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none!important;outline-style:none!important}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed!important}.disabled\:opacity-50:disabled{opacity:.5!important}.aria-\[current\=page\]\:bg-slate-200[aria-current=page]{background-color:var(--color-slate-200)!important}.aria-\[current\=page\]\:text-slate-900[aria-current=page]{color:var(--color-slate-900)!important}.data-\[state\=active\]\:border-b-2[data-state=active]{border-bottom-style:var(--tw-border-style)!important;border-bottom-width:2px!important}.data-\[state\=active\]\:border-brand-600[data-state=active]{border-color:var(--color-brand-600)!important}.data-\[state\=active\]\:bg-slate-100[data-state=active]{background-color:var(--color-slate-100)!important}.data-\[state\=active\]\:text-brand-700[data-state=active]{color:var(--color-brand-700)!important}.data-\[state\=active\]\:text-slate-900[data-state=active]{color:var(--color-slate-900)!important}.data-\[state\=active\]\:shadow-\[inset_2px_0_0_0_var\(--color-brand-500\)\][data-state=active]{--tw-shadow:inset 2px 0 0 0 var(--tw-shadow-color,var(--color-brand-500))!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}@media (min-width:40rem){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))!important}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))!important}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))!important}}@media (min-width:48rem){.md\:sticky{position:sticky!important}.md\:top-0{top:0!important}.md\:col-span-5{grid-column:span 5/span 5!important}.md\:flex{display:flex!important}.md\:grid{display:grid!important}.md\:h-screen{height:100vh!important}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))!important}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))!important}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))!important}.md\:grid-cols-\[1fr_1fr_140px_auto_auto\]{grid-template-columns:1fr 1fr 140px auto auto!important}.md\:grid-cols-\[1fr_110px\]{grid-template-columns:1fr 110px!important}.md\:grid-cols-\[1fr_130px_90px_110px_auto\]{grid-template-columns:1fr 130px 90px 110px auto!important}.md\:grid-cols-\[1fr_140px_1fr_150px\]{grid-template-columns:1fr 140px 1fr 150px!important}.md\:grid-cols-\[248px_1fr\]{grid-template-columns:248px 1fr!important}.md\:grid-cols-\[260px_1fr\]{grid-template-columns:260px 1fr!important}.md\:grid-cols-\[280px_1fr\]{grid-template-columns:280px 1fr!important}.md\:grid-cols-\[300px_1fr\]{grid-template-columns:300px 1fr!important}.md\:grid-cols-\[340px_1fr\]{grid-template-columns:340px 1fr!important}.md\:flex-col{flex-direction:column!important}.md\:overflow-visible{overflow:visible!important}.md\:border-r{border-right-style:var(--tw-border-style)!important;border-right-width:1px!important}.md\:border-b-0{border-bottom-style:var(--tw-border-style)!important;border-bottom-width:0!important}.md\:p-8{padding:calc(var(--spacing) * 8)!important}.md\:px-8{padding-inline:calc(var(--spacing) * 8)!important}}@media (min-width:64rem){.lg\:col-span-2{grid-column:span 2/span 2!important}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))!important}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))!important}}}}.xicms-admin,.xicms-admin *,.xicms-admin :before,.xicms-admin :after{box-sizing:border-box}.xicms-admin{-webkit-font-smoothing:antialiased;--color-white:#fff;--color-slate-50:#faf9f6;--color-slate-100:#f3f1ec;--color-slate-200:#e5e2da;--color-slate-300:#d5d1c7;--color-slate-400:#a8a399;--color-slate-500:#6e6a62;--color-slate-600:#57534b;--color-slate-700:#403c36;--color-slate-900:#1b1a17;--color-brand:var(--xicms-primary,#4f46e5);--color-brand-500:var(--xicms-primary,#4f46e5);--color-brand-600:var(--xicms-primary,#4f46e5);--color-brand-700:var(--xicms-primary,#4f46e5);font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;line-height:1.5}@supports (color:color-mix(in lab, red, red)){.xicms-admin{--color-brand-700:color-mix(in srgb, var(--xicms-primary,#4f46e5) 78%, #1b1a17)}}.xicms-admin{--color-brand-50:var(--xicms-primary,#4f46e5)}@supports (color:color-mix(in lab, red, red)){.xicms-admin{--color-brand-50:color-mix(in srgb, var(--xicms-primary,#4f46e5) 10%, #fff)}}.xicms-admin{--admin-canvas:#f6f5f2;--admin-sidebar:#f0eee9;--color-background-body:var(--color-white);--color-background-surface:var(--color-white);--color-background-card:var(--color-white);--color-background-muted:var(--color-slate-100);--color-text-primary:var(--color-slate-900);--color-text-secondary:var(--color-slate-500);--color-border:var(--color-slate-200);--color-accent:var(--color-brand-500);--color-on-accent:#fff;--color-error:#dc2626;color-scheme:light;color:var(--color-text-primary);background:var(--admin-canvas)}.xicms-admin h1,.xicms-admin h2,.xicms-admin h3,.xicms-admin p,.xicms-admin figure{margin:0}.xicms-admin button{font:inherit;cursor:pointer}.xicms-admin input,.xicms-admin textarea,.xicms-admin select{font:inherit;color:inherit}.xicms-admin .ProseMirror{outline:none;min-height:8rem}.xicms-admin .ProseMirror p{margin:0 0 .6rem}.xicms-admin .ProseMirror:focus{outline:none}@media (prefers-reduced-motion:reduce){.xicms-admin *,.xicms-admin :before,.xicms-admin :after,.xicms-ve *,.xicms-ve :before,.xicms-ve :after{transition-duration:.001ms!important;animation-duration:.001ms!important;animation-iteration-count:1!important}}.xicms-admin__midden,.xicms-admin__raster{min-height:100vh}.xicms-admin--ingebed .xicms-admin__midden{min-height:50vh}.xicms-admin--ingebed .xicms-admin__raster{min-height:60vh;display:block}.xicms-admin--ingebed .xicms-admin__rail{border-bottom-width:1px;border-right:0;flex-flow:wrap;align-items:center;gap:1rem;height:auto;padding:.5rem 1rem;position:static}.xicms-admin--ingebed .xicms-admin__lijst{flex-direction:row;overflow-x:auto}.xicms-admin--ingebed .xicms-admin__voet{border-top:0;flex-direction:row;align-items:center;gap:.75rem;margin-top:0;margin-left:auto;padding-top:0;display:flex}.xicms-admin--ingebed .xicms-admin__kop{position:static}.xicms-admin--ingebed{width:100vw;max-width:100vw;margin-left:calc(50% - 50vw);margin-right:calc(50% - 50vw)}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-200:oklch(88.5% .062 18.334);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-600:oklch(66.6% .179 58.318);--color-amber-700:oklch(55.5% .163 48.998);--color-amber-800:oklch(47.3% .137 46.201);--color-amber-900:oklch(41.4% .112 45.904);--color-emerald-700:oklch(50.8% .118 165.612);--color-blue-600:oklch(54.6% .245 262.881);--color-indigo-500:oklch(58.5% .233 277.117);--color-slate-50:oklch(98.4% .003 247.858);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-700:oklch(37.2% .044 257.287);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--container-sm:24rem;--container-md:28rem;--container-3xl:48rem;--container-4xl:56rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--ease-out:cubic-bezier(0, 0, .2, 1);--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--color-brand:#4f46e5;--color-brand-50:#eef2ff;--color-brand-500:#4f46e5;--color-brand-600:#4f46e5;--color-brand-700:#3730a3}}@scope(.xicms-admin){@layer utilities{.pointer-events-none{pointer-events:none!important}.visible{visibility:visible!important}.sr-only{clip-path:inset(50%)!important;white-space:nowrap!important;border-width:0!important;width:1px!important;height:1px!important;margin:-1px!important;padding:0!important;position:absolute!important;overflow:hidden!important}.absolute{position:absolute!important}.fixed{position:fixed!important}.relative{position:relative!important}.static{position:static!important}.sticky{position:sticky!important}.inset-x-0{inset-inline:0!important}.-top-0\.5{top:calc(var(--spacing) * -.5)!important}.-top-2{top:calc(var(--spacing) * -2)!important}.top-0{top:0!important}.-right-2{right:calc(var(--spacing) * -2)!important}.right-0{right:0!important}.-bottom-2{bottom:calc(var(--spacing) * -2)!important}.bottom-0{bottom:0!important}.-left-2{left:calc(var(--spacing) * -2)!important}.left-1\/2{left:50%!important}.z-10{z-index:10!important}.col-span-2{grid-column:span 2/span 2!important}.col-span-full{grid-column:1/-1!important}.container{width:100%!important}@media (min-width:40rem){.container{max-width:40rem!important}}@media (min-width:48rem){.container{max-width:48rem!important}}@media (min-width:64rem){.container{max-width:64rem!important}}@media (min-width:80rem){.container{max-width:80rem!important}}@media (min-width:96rem){.container{max-width:96rem!important}}.-mx-1{margin-inline:calc(var(--spacing) * -1)!important}.-mx-4{margin-inline:calc(var(--spacing) * -4)!important}.mt-0\.5{margin-top:calc(var(--spacing) * .5)!important}.mt-1{margin-top:var(--spacing)!important}.mt-2{margin-top:calc(var(--spacing) * 2)!important}.mt-3{margin-top:calc(var(--spacing) * 3)!important}.mt-4{margin-top:calc(var(--spacing) * 4)!important}.mt-5{margin-top:calc(var(--spacing) * 5)!important}.mt-6{margin-top:calc(var(--spacing) * 6)!important}.mt-auto{margin-top:auto!important}.mr-1{margin-right:var(--spacing)!important}.mr-2{margin-right:calc(var(--spacing) * 2)!important}.mb-1{margin-bottom:var(--spacing)!important}.mb-2{margin-bottom:calc(var(--spacing) * 2)!important}.mb-3{margin-bottom:calc(var(--spacing) * 3)!important}.mb-4{margin-bottom:calc(var(--spacing) * 4)!important}.ml-1{margin-left:var(--spacing)!important}.ml-1\.5{margin-left:calc(var(--spacing) * 1.5)!important}.ml-auto{margin-left:auto!important}.block{display:block!important}.contents{display:contents!important}.flex{display:flex!important}.grid{display:grid!important}.hidden{display:none!important}.inline{display:inline!important}.inline-block{display:inline-block!important}.inline-flex{display:inline-flex!important}.table{display:table!important}.aspect-square{aspect-ratio:1!important}.h-1\.5{height:calc(var(--spacing) * 1.5)!important}.h-2{height:calc(var(--spacing) * 2)!important}.h-5{height:calc(var(--spacing) * 5)!important}.h-6{height:calc(var(--spacing) * 6)!important}.h-8{height:calc(var(--spacing) * 8)!important}.h-9{height:calc(var(--spacing) * 9)!important}.h-10{height:calc(var(--spacing) * 10)!important}.h-14{height:calc(var(--spacing) * 14)!important}.h-16{height:calc(var(--spacing) * 16)!important}.h-28{height:calc(var(--spacing) * 28)!important}.h-32{height:calc(var(--spacing) * 32)!important}.h-\[70vh\]{height:70vh!important}.h-fit{height:fit-content!important}.h-full{height:100%!important}.max-h-\[55vh\]{max-height:55vh!important}.max-h-\[60vh\]{max-height:60vh!important}.min-h-\[8rem\]{min-height:8rem!important}.min-h-screen{min-height:100vh!important}.w-2{width:calc(var(--spacing) * 2)!important}.w-5{width:calc(var(--spacing) * 5)!important}.w-6{width:calc(var(--spacing) * 6)!important}.w-8{width:calc(var(--spacing) * 8)!important}.w-14{width:calc(var(--spacing) * 14)!important}.w-16{width:calc(var(--spacing) * 16)!important}.w-20{width:calc(var(--spacing) * 20)!important}.w-24{width:calc(var(--spacing) * 24)!important}.w-28{width:calc(var(--spacing) * 28)!important}.w-32{width:calc(var(--spacing) * 32)!important}.w-36{width:calc(var(--spacing) * 36)!important}.w-44{width:calc(var(--spacing) * 44)!important}.w-56{width:calc(var(--spacing) * 56)!important}.w-fit{width:fit-content!important}.w-full{width:100%!important}.max-w-3xl{max-width:var(--container-3xl)!important}.max-w-4xl{max-width:var(--container-4xl)!important}.max-w-md{max-width:var(--container-md)!important}.max-w-sm{max-width:var(--container-sm)!important}.max-w-xs{max-width:var(--container-xs)!important}.min-w-0{min-width:0!important}.min-w-8{min-width:calc(var(--spacing) * 8)!important}.flex-1{flex:1!important}.shrink-0{flex-shrink:0!important}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1)!important;translate:var(--tw-translate-x) var(--tw-translate-y)!important}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1)!important;translate:var(--tw-translate-x) var(--tw-translate-y)!important}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)!important}.cursor-default{cursor:default!important}.cursor-pointer{cursor:pointer!important}.resize{resize:both!important}.list-decimal{list-style-type:decimal!important}.list-disc{list-style-type:disc!important}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))!important}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))!important}.grid-cols-\[1fr_1\.4fr_auto\]{grid-template-columns:1fr 1.4fr auto!important}.grid-cols-\[1fr_1fr_90px_90px_auto\]{grid-template-columns:1fr 1fr 90px 90px auto!important}.grid-cols-\[1fr_150px_70px_auto\]{grid-template-columns:1fr 150px 70px auto!important}.grid-cols-\[120px_1fr\]{grid-template-columns:120px 1fr!important}.grid-cols-\[minmax\(0\,1fr\)_auto\]{grid-template-columns:minmax(0,1fr) auto!important}.flex-col{flex-direction:column!important}.flex-wrap{flex-wrap:wrap!important}.place-items-center{place-items:center!important}.items-baseline{align-items:baseline!important}.items-center{align-items:center!important}.items-end{align-items:flex-end!important}.items-start{align-items:flex-start!important}.justify-between{justify-content:space-between!important}.justify-center{justify-content:center!important}.justify-end{justify-content:flex-end!important}.gap-0\.5{gap:calc(var(--spacing) * .5)!important}.gap-1{gap:var(--spacing)!important}.gap-1\.5{gap:calc(var(--spacing) * 1.5)!important}.gap-2{gap:calc(var(--spacing) * 2)!important}.gap-2\.5{gap:calc(var(--spacing) * 2.5)!important}.gap-3{gap:calc(var(--spacing) * 3)!important}.gap-4{gap:calc(var(--spacing) * 4)!important}.gap-6{gap:calc(var(--spacing) * 6)!important}.gap-x-3{column-gap:calc(var(--spacing) * 3)!important}.gap-x-5{column-gap:calc(var(--spacing) * 5)!important}.gap-y-1{row-gap:var(--spacing)!important}.self-center{align-self:center!important}.self-end{align-self:flex-end!important}.truncate{text-overflow:ellipsis!important;white-space:nowrap!important;overflow:hidden!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-x-auto{overflow-x:auto!important}.overflow-y-auto{overflow-y:auto!important}.rounded{border-radius:.25rem!important}.rounded-full{border-radius:3.40282e38px!important}.rounded-lg{border-radius:var(--radius-lg)!important}.rounded-md{border-radius:var(--radius-md)!important}.rounded-xl{border-radius:var(--radius-xl)!important}.rounded-t-lg{border-top-left-radius:var(--radius-lg)!important;border-top-right-radius:var(--radius-lg)!important}.rounded-b-lg{border-bottom-right-radius:var(--radius-lg)!important;border-bottom-left-radius:var(--radius-lg)!important}.border{border-style:var(--tw-border-style)!important;border-width:1px!important}.border-t{border-top-style:var(--tw-border-style)!important;border-top-width:1px!important}.border-t-0{border-top-style:var(--tw-border-style)!important;border-top-width:0!important}.border-b{border-bottom-style:var(--tw-border-style)!important;border-bottom-width:1px!important}.border-amber-300{border-color:var(--color-amber-300)!important}.border-brand-500{border-color:var(--color-brand-500)!important}.border-red-200{border-color:var(--color-red-200)!important}.border-slate-100{border-color:var(--color-slate-100)!important}.border-slate-200{border-color:var(--color-slate-200)!important}.border-slate-300{border-color:var(--color-slate-300)!important}.bg-amber-50{background-color:var(--color-amber-50)!important}.bg-brand-50{background-color:var(--color-brand-50)!important}.bg-brand-500{background-color:var(--color-brand-500)!important}.bg-red-50{background-color:var(--color-red-50)!important}.bg-slate-50{background-color:var(--color-slate-50)!important}.bg-slate-100{background-color:var(--color-slate-100)!important}.bg-slate-200{background-color:var(--color-slate-200)!important}.bg-slate-700{background-color:var(--color-slate-700)!important}.bg-white{background-color:var(--color-white)!important}.object-cover{object-fit:cover!important}.p-0\.5{padding:calc(var(--spacing) * .5)!important}.p-1{padding:var(--spacing)!important}.p-2{padding:calc(var(--spacing) * 2)!important}.p-3{padding:calc(var(--spacing) * 3)!important}.p-4{padding:calc(var(--spacing) * 4)!important}.p-5{padding:calc(var(--spacing) * 5)!important}.p-6{padding:calc(var(--spacing) * 6)!important}.px-1{padding-inline:var(--spacing)!important}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)!important}.px-2{padding-inline:calc(var(--spacing) * 2)!important}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)!important}.px-3{padding-inline:calc(var(--spacing) * 3)!important}.px-4{padding-inline:calc(var(--spacing) * 4)!important}.py-0\.5{padding-block:calc(var(--spacing) * .5)!important}.py-1{padding-block:var(--spacing)!important}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)!important}.py-2{padding-block:calc(var(--spacing) * 2)!important}.py-3{padding-block:calc(var(--spacing) * 3)!important}.py-8{padding-block:calc(var(--spacing) * 8)!important}.py-16{padding-block:calc(var(--spacing) * 16)!important}.pt-0{padding-top:0!important}.pt-1{padding-top:var(--spacing)!important}.pt-3{padding-top:calc(var(--spacing) * 3)!important}.pt-4{padding-top:calc(var(--spacing) * 4)!important}.pt-5{padding-top:calc(var(--spacing) * 5)!important}.pr-2{padding-right:calc(var(--spacing) * 2)!important}.pl-1{padding-left:var(--spacing)!important}.pl-5{padding-left:calc(var(--spacing) * 5)!important}.text-center{text-align:center!important}.text-left{text-align:left!important}.text-right{text-align:right!important}.align-top{vertical-align:top!important}.font-mono{font-family:var(--font-mono)!important}.text-3xl{font-size:var(--text-3xl)!important;line-height:var(--tw-leading,var(--text-3xl--line-height))!important}.text-base{font-size:var(--text-base)!important;line-height:var(--tw-leading,var(--text-base--line-height))!important}.text-lg{font-size:var(--text-lg)!important;line-height:var(--tw-leading,var(--text-lg--line-height))!important}.text-sm{font-size:var(--text-sm)!important;line-height:var(--tw-leading,var(--text-sm--line-height))!important}.text-xl{font-size:var(--text-xl)!important;line-height:var(--tw-leading,var(--text-xl--line-height))!important}.text-xs{font-size:var(--text-xs)!important;line-height:var(--tw-leading,var(--text-xs--line-height))!important}.text-\[10px\]{font-size:10px!important}.text-\[11px\]{font-size:11px!important}.font-bold{--tw-font-weight:var(--font-weight-bold)!important;font-weight:var(--font-weight-bold)!important}.font-medium{--tw-font-weight:var(--font-weight-medium)!important;font-weight:var(--font-weight-medium)!important}.font-normal{--tw-font-weight:var(--font-weight-normal)!important;font-weight:var(--font-weight-normal)!important}.font-semibold{--tw-font-weight:var(--font-weight-semibold)!important;font-weight:var(--font-weight-semibold)!important}.tracking-wide{--tw-tracking:var(--tracking-wide)!important;letter-spacing:var(--tracking-wide)!important}.whitespace-nowrap{white-space:nowrap!important}.whitespace-pre-wrap{white-space:pre-wrap!important}.text-amber-600{color:var(--color-amber-600)!important}.text-amber-700{color:var(--color-amber-700)!important}.text-amber-800{color:var(--color-amber-800)!important}.text-amber-900{color:var(--color-amber-900)!important}.text-brand-700{color:var(--color-brand-700)!important}.text-brand-700\/70{color:#3730a3b3!important}@supports (color:color-mix(in lab, red, red)){.text-brand-700\/70{color:color-mix(in oklab, var(--color-brand-700) 70%, transparent)!important}}.text-emerald-700{color:var(--color-emerald-700)!important}.text-red-600{color:var(--color-red-600)!important}.text-red-700{color:var(--color-red-700)!important}.text-slate-400{color:var(--color-slate-400)!important}.text-slate-500{color:var(--color-slate-500)!important}.text-slate-600{color:var(--color-slate-600)!important}.text-slate-700{color:var(--color-slate-700)!important}.text-slate-800{color:var(--color-slate-800)!important}.text-slate-900{color:var(--color-slate-900)!important}.text-white{color:var(--color-white)!important}.uppercase{text-transform:uppercase!important}.italic{font-style:italic!important}.tabular-nums{--tw-numeric-spacing:tabular-nums!important;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)!important}.line-through{text-decoration-line:line-through!important}.underline{text-decoration-line:underline!important}.opacity-70{opacity:.7!important}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a)!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a)!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor)!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}.ring-brand-500{--tw-ring-color:var(--color-brand-500)!important}.outline{outline-style:var(--tw-outline-style)!important;outline-width:1px!important}.blur{--tw-blur:blur(8px)!important;filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)!important}.grayscale{--tw-grayscale:grayscale(100%)!important;filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)!important}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)!important}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events!important;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function))!important;transition-duration:var(--tw-duration,var(--default-transition-duration))!important}.transition-\[filter\]{transition-property:filter!important;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function))!important;transition-duration:var(--tw-duration,var(--default-transition-duration))!important}.ease-out{--tw-ease:var(--ease-out)!important;transition-timing-function:var(--ease-out)!important}.outline-none{--tw-outline-style:none!important;outline-style:none!important}@media (hover:hover){.group-hover\:opacity-80:is(:where(.group):hover *){opacity:.8!important}}.last\:border-0:last-child{border-style:var(--tw-border-style)!important;border-width:0!important}@media (hover:hover){.hover\:border-brand-500:hover{border-color:var(--color-brand-500)!important}.hover\:bg-slate-50:hover{background-color:var(--color-slate-50)!important}.hover\:bg-slate-100:hover{background-color:var(--color-slate-100)!important}.hover\:bg-slate-200:hover{background-color:var(--color-slate-200)!important}.hover\:text-slate-600:hover{color:var(--color-slate-600)!important}.hover\:text-slate-700:hover{color:var(--color-slate-700)!important}.hover\:text-slate-900:hover{color:var(--color-slate-900)!important}.hover\:underline:hover{text-decoration-line:underline!important}.hover\:brightness-95:hover{--tw-brightness:brightness(95%)!important;filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)!important}}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor)!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}.focus\:ring-indigo-500:focus{--tw-ring-color:var(--color-indigo-500)!important}.focus\:outline-none:focus{--tw-outline-style:none!important;outline-style:none!important}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor)!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}.focus-visible\:ring-brand-500:focus-visible{--tw-ring-color:var(--color-brand-500)!important}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style)!important;outline-width:2px!important}.focus-visible\:outline-offset-2:focus-visible{outline-offset:2px!important}.focus-visible\:outline-blue-600:focus-visible{outline-color:var(--color-blue-600)!important}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none!important;outline-style:none!important}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed!important}.disabled\:opacity-50:disabled{opacity:.5!important}.aria-\[current\=page\]\:bg-slate-200[aria-current=page]{background-color:var(--color-slate-200)!important}.aria-\[current\=page\]\:text-slate-900[aria-current=page]{color:var(--color-slate-900)!important}.data-\[state\=active\]\:border-b-2[data-state=active]{border-bottom-style:var(--tw-border-style)!important;border-bottom-width:2px!important}.data-\[state\=active\]\:border-brand-600[data-state=active]{border-color:var(--color-brand-600)!important}.data-\[state\=active\]\:bg-slate-100[data-state=active]{background-color:var(--color-slate-100)!important}.data-\[state\=active\]\:text-brand-700[data-state=active]{color:var(--color-brand-700)!important}.data-\[state\=active\]\:text-slate-900[data-state=active]{color:var(--color-slate-900)!important}.data-\[state\=active\]\:shadow-\[inset_2px_0_0_0_var\(--color-brand-500\)\][data-state=active]{--tw-shadow:inset 2px 0 0 0 var(--tw-shadow-color,var(--color-brand-500))!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}@media (min-width:40rem){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))!important}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))!important}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))!important}}@media (min-width:48rem){.md\:sticky{position:sticky!important}.md\:top-0{top:0!important}.md\:col-span-5{grid-column:span 5/span 5!important}.md\:flex{display:flex!important}.md\:grid{display:grid!important}.md\:h-screen{height:100vh!important}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))!important}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))!important}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))!important}.md\:grid-cols-\[1fr_1fr_140px_auto_auto\]{grid-template-columns:1fr 1fr 140px auto auto!important}.md\:grid-cols-\[1fr_110px\]{grid-template-columns:1fr 110px!important}.md\:grid-cols-\[1fr_130px_90px_110px_auto\]{grid-template-columns:1fr 130px 90px 110px auto!important}.md\:grid-cols-\[1fr_140px_1fr_150px\]{grid-template-columns:1fr 140px 1fr 150px!important}.md\:grid-cols-\[248px_1fr\]{grid-template-columns:248px 1fr!important}.md\:grid-cols-\[260px_1fr\]{grid-template-columns:260px 1fr!important}.md\:grid-cols-\[280px_1fr\]{grid-template-columns:280px 1fr!important}.md\:grid-cols-\[300px_1fr\]{grid-template-columns:300px 1fr!important}.md\:grid-cols-\[340px_1fr\]{grid-template-columns:340px 1fr!important}.md\:flex-col{flex-direction:column!important}.md\:overflow-visible{overflow:visible!important}.md\:border-r{border-right-style:var(--tw-border-style)!important;border-right-width:1px!important}.md\:border-b-0{border-bottom-style:var(--tw-border-style)!important;border-bottom-width:0!important}.md\:p-8{padding:calc(var(--spacing) * 8)!important}.md\:px-8{padding-inline:calc(var(--spacing) * 8)!important}}@media (min-width:64rem){.lg\:col-span-2{grid-column:span 2/span 2!important}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))!important}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))!important}}}}.xicms-admin,.xicms-admin *,.xicms-admin :before,.xicms-admin :after{box-sizing:border-box}.xicms-admin{-webkit-font-smoothing:antialiased;--color-white:#fff;--color-slate-50:#faf9f6;--color-slate-100:#f3f1ec;--color-slate-200:#e5e2da;--color-slate-300:#d5d1c7;--color-slate-400:#a8a399;--color-slate-500:#6e6a62;--color-slate-600:#57534b;--color-slate-700:#403c36;--color-slate-900:#1b1a17;--color-brand:var(--xicms-primary,#4f46e5);--color-brand-500:var(--xicms-primary,#4f46e5);--color-brand-600:var(--xicms-primary,#4f46e5);--color-brand-700:var(--xicms-primary,#4f46e5);font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;line-height:1.5}@supports (color:color-mix(in lab, red, red)){.xicms-admin{--color-brand-700:color-mix(in srgb, var(--xicms-primary,#4f46e5) 78%, #1b1a17)}}.xicms-admin{--color-brand-50:var(--xicms-primary,#4f46e5)}@supports (color:color-mix(in lab, red, red)){.xicms-admin{--color-brand-50:color-mix(in srgb, var(--xicms-primary,#4f46e5) 10%, #fff)}}.xicms-admin{--admin-canvas:#f6f5f2;--admin-sidebar:#f0eee9;--color-background-body:var(--color-white);--color-background-surface:var(--color-white);--color-background-card:var(--color-white);--color-background-muted:var(--color-slate-100);--color-text-primary:var(--color-slate-900);--color-text-secondary:var(--color-slate-500);--color-border:var(--color-slate-200);--color-accent:var(--color-brand-500);--color-on-accent:#fff;--color-error:#dc2626;color-scheme:light;color:var(--color-text-primary);background:var(--admin-canvas)}.xicms-admin h1,.xicms-admin h2,.xicms-admin h3,.xicms-admin p,.xicms-admin figure{margin:0}.xicms-admin button{font:inherit;cursor:pointer}.xicms-admin input,.xicms-admin textarea,.xicms-admin select{font:inherit;color:inherit}.xicms-admin .ProseMirror{outline:none;min-height:8rem}.xicms-admin .ProseMirror p{margin:0 0 .6rem}.xicms-admin .ProseMirror:focus{outline:none}@media (prefers-reduced-motion:reduce){.xicms-admin *,.xicms-admin :before,.xicms-admin :after,.xicms-ve *,.xicms-ve :before,.xicms-ve :after{transition-duration:.001ms!important;animation-duration:.001ms!important;animation-iteration-count:1!important}}.xicms-admin__midden,.xicms-admin__raster{min-height:100vh}.xicms-admin--ingebed .xicms-admin__midden{min-height:50vh}.xicms-admin--ingebed .xicms-admin__raster{min-height:60vh;display:block}.xicms-admin--ingebed .xicms-admin__rail{border-bottom-width:1px;border-right:0;flex-flow:wrap;align-items:center;gap:1rem;height:auto;padding:.5rem 1rem;position:static}.xicms-admin--ingebed .xicms-admin__lijst{flex-direction:row;overflow-x:auto}.xicms-admin--ingebed .xicms-admin__voet{border-top:0;flex-direction:row;align-items:center;gap:.75rem;margin-top:0;margin-left:auto;padding-top:0;display:flex}.xicms-admin--ingebed .xicms-admin__kop{position:static}.xicms-admin--ingebed{width:100vw;max-width:100vw;margin-left:calc(50% - 50vw);margin-right:calc(50% - 50vw)}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}
|
|
@@ -12,9 +12,14 @@ function CartRender({ block, siteId }) {
|
|
|
12
12
|
const { lines, itemsCents } = useCart(siteId);
|
|
13
13
|
const shippingCents = shippingCentsFor(
|
|
14
14
|
itemsCents,
|
|
15
|
-
{
|
|
15
|
+
{
|
|
16
|
+
shippingFlatCents: settings.shippingFlatCents,
|
|
17
|
+
shippingFreeFromCents: settings.shippingFreeFromCents || void 0,
|
|
18
|
+
shippingZones: settings.shippingZones
|
|
19
|
+
},
|
|
16
20
|
lines.length > 0
|
|
17
21
|
);
|
|
22
|
+
const meerdereZones = (settings.shippingZones ?? []).length > 1;
|
|
18
23
|
return /* @__PURE__ */ jsxs("div", { className: "xicms-shop-cart", children: [
|
|
19
24
|
block.heading && /* @__PURE__ */ jsx(Heading, { level: 1, "data-xicms-edit": "heading", children: block.heading }),
|
|
20
25
|
lines.length === 0 ? /* @__PURE__ */ jsx(Card, { padding: 4, variant: "muted", style: { marginTop: "1rem" }, children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
@@ -70,7 +75,8 @@ function CartRender({ block, siteId }) {
|
|
|
70
75
|
/* @__PURE__ */ jsxs(Text, { size: "sm", children: [
|
|
71
76
|
t("shippingCosts"),
|
|
72
77
|
": ",
|
|
73
|
-
shippingCents === 0 ? t("free") : formatCents(shippingCents, settings.currency)
|
|
78
|
+
shippingCents === 0 ? t("free") : formatCents(shippingCents, settings.currency),
|
|
79
|
+
meerdereZones ? ` ${t("shippingFromCountry")}` : ""
|
|
74
80
|
] }),
|
|
75
81
|
/* @__PURE__ */ jsxs(Text, { weight: "bold", children: [
|
|
76
82
|
t("total"),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/shop/blocks/Cart.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport { formatCents, shippingCentsFor } from \"../../../schema/shopGeld\";\nimport type { CartBlockSchema } from \"../../../schema/shop\";\nimport { defineBlock, type BlockRenderProps } from \"../../../blocks/registry\";\nimport { Card, Heading, Text } from \"../../../blocks/ui\";\nimport { cartLineKey, cartRemove, cartSetQty, useCart } from \"../cartStore\";\nimport { useShopStrings } from \"../strings\";\nimport { useShopSettings } from \"../lib\";\n\ntype Blk = z.infer<typeof CartBlockSchema>;\n\nfunction CartRender({ block, siteId }: BlockRenderProps<Blk>) {\n const settings = useShopSettings();\n const t = useShopStrings();\n const { lines, itemsCents } = useCart(siteId);\n const shippingCents = shippingCentsFor(\n itemsCents,\n {
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/shop/blocks/Cart.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport { formatCents, shippingCentsFor } from \"../../../schema/shopGeld\";\nimport type { CartBlockSchema } from \"../../../schema/shop\";\nimport { defineBlock, type BlockRenderProps } from \"../../../blocks/registry\";\nimport { Card, Heading, Text } from \"../../../blocks/ui\";\nimport { cartLineKey, cartRemove, cartSetQty, useCart } from \"../cartStore\";\nimport { useShopStrings } from \"../strings\";\nimport { useShopSettings } from \"../lib\";\n\ntype Blk = z.infer<typeof CartBlockSchema>;\n\nfunction CartRender({ block, siteId }: BlockRenderProps<Blk>) {\n const settings = useShopSettings();\n const t = useShopStrings();\n const { lines, itemsCents } = useCart(siteId);\n /**\n * Verzendkosten in de winkelwagen zijn een RICHTBEDRAG voor het standaardland: de klant kiest\n * zijn land (en een eventuele kortingscode) pas bij het afrekenen. Met zones staat dat er nu\n * ook bij, zodat \"€ 7,25\" niet als een belofte leest voor een Belgische bezoeker.\n */\n const shippingCents = shippingCentsFor(\n itemsCents,\n {\n shippingFlatCents: settings.shippingFlatCents,\n shippingFreeFromCents: settings.shippingFreeFromCents || undefined,\n shippingZones: settings.shippingZones,\n },\n lines.length > 0,\n );\n const meerdereZones = (settings.shippingZones ?? []).length > 1;\n\n return (\n <div className=\"xicms-shop-cart\">\n {block.heading && <Heading level={1} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n\n {lines.length === 0 ? (\n <Card padding={4} variant=\"muted\" style={{ marginTop: \"1rem\" }}>\n <Text>\n {t(\"cartEmpty\")} <a href={settings.shopPath}>{t(\"toShop\")}</a>\n </Text>\n </Card>\n ) : (\n <div style={{ display: \"grid\", gap: \"1rem\", marginTop: \"1rem\" }}>\n {lines.map((l) => (\n <Card key={cartLineKey(l)} padding={3}>\n <div style={{ display: \"flex\", gap: \"1rem\", alignItems: \"center\", flexWrap: \"wrap\" }}>\n {l.imageUrl && (\n <img src={l.imageUrl} alt=\"\" style={{ width: 72, height: 72, objectFit: \"cover\", borderRadius: 8 }} />\n )}\n <div style={{ flex: \"1 1 200px\" }}>\n <a href={`${settings.detailPath}?p=${encodeURIComponent(l.slug)}`} style={{ textDecoration: \"none\", color: \"inherit\" }}>\n <Text weight=\"bold\" display=\"block\">{l.name}</Text>\n </a>\n {l.variantLabel && <Text size=\"sm\" display=\"block\" style={{ opacity: 0.75 }}>{l.variantLabel}</Text>}\n {l.personalizationLabel && (\n <Text size=\"sm\" display=\"block\" style={{ opacity: 0.75 }}>{l.personalizationLabel}</Text>\n )}\n <Text size=\"sm\" display=\"block\" style={{ marginTop: 2 }}>\n {formatCents(l.unitPriceCents, settings.currency)} {t(\"perPiece\")}\n </Text>\n </div>\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 8 }}>\n <input\n className=\"xicms-input\"\n type=\"number\"\n min={0}\n max={999}\n value={l.qty}\n aria-label={`${t(\"qty\")} ${l.name}`}\n onChange={(e) => cartSetQty(siteId, l, Math.max(0, Number(e.target.value) || 0))}\n style={{ width: 72 }}\n />\n <Text weight=\"bold\" style={{ minWidth: 80, textAlign: \"right\" }}>\n {formatCents(l.unitPriceCents * l.qty, settings.currency)}\n </Text>\n <button\n type=\"button\"\n aria-label={`Verwijder ${l.name}`}\n onClick={() => cartRemove(siteId, l)}\n style={{ background: \"none\", border: \"none\", cursor: \"pointer\", fontSize: \"1.1rem\", opacity: 0.6 }}\n >\n ✕\n </button>\n </div>\n </div>\n </Card>\n ))}\n\n <Card padding={3} variant=\"muted\">\n <div style={{ display: \"grid\", gap: 4, justifyContent: \"end\", textAlign: \"right\" }}>\n <Text size=\"sm\">{t(\"subtotal\")}: {formatCents(itemsCents, settings.currency)}</Text>\n <Text size=\"sm\">\n {t(\"shippingCosts\")}: {shippingCents === 0 ? t(\"free\") : formatCents(shippingCents, settings.currency)}\n {meerdereZones ? ` ${t(\"shippingFromCountry\")}` : \"\"}\n </Text>\n <Text weight=\"bold\">{t(\"total\")}: {formatCents(itemsCents + shippingCents, settings.currency)}</Text>\n </div>\n </Card>\n\n <div style={{ display: \"flex\", gap: 12, flexWrap: \"wrap\" }}>\n <a className=\"xicms-btn xicms-btn--primary\" href={settings.checkoutPath}>{t(\"checkout\")}</a>\n <a className=\"xicms-btn xicms-btn--secondary\" href={settings.shopPath}>{t(\"continueShopping\")}</a>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const cartBlock = defineBlock({\n type: \"cart\",\n Render: CartRender,\n label: \"Winkelwagen\",\n icon: \"🛒\",\n defaults: () => ({ heading: \"Winkelwagen\" }),\n});\n"],"mappings":"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","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useState } from "react";
|
|
4
|
-
import { formatCents, shippingCentsFor } from "../../../schema/shopGeld.js";
|
|
3
|
+
import { useMemo, useState } from "react";
|
|
4
|
+
import { formatCents, shippingCentsFor, verzendLanden } from "../../../schema/shopGeld.js";
|
|
5
5
|
import { defineBlock } from "../../../blocks/registry.js";
|
|
6
6
|
import { Card, Heading, Text } from "../../../blocks/ui/index.js";
|
|
7
7
|
import { TextInput } from "@astryxdesign/core/TextInput";
|
|
@@ -9,23 +9,32 @@ import { TextArea } from "@astryxdesign/core/TextArea";
|
|
|
9
9
|
import { cartLineKey, useCart } from "../cartStore.js";
|
|
10
10
|
import { useShopStrings } from "../strings.js";
|
|
11
11
|
import { createOrderCall, useShopSettings, validateDiscountCall } from "../lib.js";
|
|
12
|
+
const LANDNAMEN = new Intl.DisplayNames(["nl"], { type: "region" });
|
|
12
13
|
function CheckoutRender({ block, siteId, mode }) {
|
|
13
14
|
const settings = useShopSettings();
|
|
14
15
|
const t = useShopStrings();
|
|
15
16
|
const { lines, itemsCents } = useCart(siteId);
|
|
16
|
-
const [v, setV] = useState({ name: "", email: "", phone: "", address: "", zip: "", city: "", note: "" });
|
|
17
|
+
const [v, setV] = useState({ name: "", email: "", phone: "", address: "", zip: "", city: "", country: "NL", note: "" });
|
|
17
18
|
const [hp, setHp] = useState("");
|
|
19
|
+
const landOpties = useMemo(() => {
|
|
20
|
+
const uit = verzendLanden({ shippingZones: settings.shippingZones });
|
|
21
|
+
return uit.length > 0 ? uit : ["NL"];
|
|
22
|
+
}, [settings.shippingZones]);
|
|
18
23
|
const [busy, setBusy] = useState(false);
|
|
19
24
|
const [error, setError] = useState(null);
|
|
20
25
|
const [codeInput, setCodeInput] = useState("");
|
|
21
26
|
const [codeBusy, setCodeBusy] = useState(false);
|
|
22
27
|
const [discount, setDiscount] = useState(null);
|
|
23
|
-
const
|
|
28
|
+
const shippingCents = shippingCentsFor(
|
|
24
29
|
itemsCents,
|
|
25
|
-
{
|
|
26
|
-
|
|
30
|
+
{
|
|
31
|
+
shippingFlatCents: settings.shippingFlatCents,
|
|
32
|
+
shippingFreeFromCents: settings.shippingFreeFromCents || void 0,
|
|
33
|
+
shippingZones: settings.shippingZones
|
|
34
|
+
},
|
|
35
|
+
lines.length > 0,
|
|
36
|
+
{ land: v.country, freeShipping: discount?.valid && discount.freeShipping }
|
|
27
37
|
);
|
|
28
|
-
const shippingCents = discount?.valid && discount.freeShipping ? 0 : baseShipping;
|
|
29
38
|
const discountCents = discount?.valid ? Math.min(discount.discountCents ?? 0, itemsCents) : 0;
|
|
30
39
|
const totalCents = Math.max(0, itemsCents - discountCents) + shippingCents;
|
|
31
40
|
async function applyCode() {
|
|
@@ -56,7 +65,7 @@ function CheckoutRender({ block, siteId, mode }) {
|
|
|
56
65
|
personalization: l.personalization
|
|
57
66
|
})),
|
|
58
67
|
customer: { email: v.email, name: v.name, phone: v.phone || void 0 },
|
|
59
|
-
shipping: { address: v.address, zip: v.zip, city: v.city, country: "NL" },
|
|
68
|
+
shipping: { address: v.address, zip: v.zip, city: v.city, country: v.country || "NL" },
|
|
60
69
|
note: v.note || void 0,
|
|
61
70
|
discountCode: discount?.valid ? discount.code : void 0,
|
|
62
71
|
successPath: settings.successPath,
|
|
@@ -89,6 +98,21 @@ function CheckoutRender({ block, siteId, mode }) {
|
|
|
89
98
|
/* @__PURE__ */ jsx(TextInput, { label: `${t("fieldZip")} *`, value: v.zip, onChange: (x) => setV((p) => ({ ...p, zip: x })) }),
|
|
90
99
|
/* @__PURE__ */ jsx(TextInput, { label: `${t("fieldCity")} *`, value: v.city, onChange: (x) => setV((p) => ({ ...p, city: x })) })
|
|
91
100
|
] }),
|
|
101
|
+
/* @__PURE__ */ jsx("div", { children: landOpties.length > 1 && /* @__PURE__ */ jsxs("label", { style: { display: "grid", gap: 4 }, children: [
|
|
102
|
+
/* @__PURE__ */ jsxs("span", { style: { fontSize: "0.9rem" }, children: [
|
|
103
|
+
t("fieldCountry"),
|
|
104
|
+
" *"
|
|
105
|
+
] }),
|
|
106
|
+
/* @__PURE__ */ jsx(
|
|
107
|
+
"select",
|
|
108
|
+
{
|
|
109
|
+
className: "xicms-input",
|
|
110
|
+
value: v.country,
|
|
111
|
+
onChange: (e) => setV((p) => ({ ...p, country: e.target.value })),
|
|
112
|
+
children: landOpties.map((c) => /* @__PURE__ */ jsx("option", { value: c, children: LANDNAMEN.of(c) ?? c }, c))
|
|
113
|
+
}
|
|
114
|
+
)
|
|
115
|
+
] }) }),
|
|
92
116
|
/* @__PURE__ */ jsx(TextArea, { label: t("fieldNote"), rows: 3, value: v.note, onChange: (x) => setV((p) => ({ ...p, note: x })) }),
|
|
93
117
|
/* @__PURE__ */ jsx(
|
|
94
118
|
"input",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/shop/blocks/Checkout.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, type FormEvent } from \"react\";\nimport type { z } from \"zod\";\nimport { formatCents, shippingCentsFor } from \"../../../schema/shopGeld\";\nimport type { CheckoutBlockSchema } from \"../../../schema/shop\";\nimport { defineBlock, type BlockRenderProps } from \"../../../blocks/registry\";\nimport { Card, Heading, Text } from \"../../../blocks/ui\";\nimport { TextInput } from \"@astryxdesign/core/TextInput\";\nimport { TextArea } from \"@astryxdesign/core/TextArea\";\nimport { cartLineKey, useCart } from \"../cartStore\";\nimport { useShopStrings } from \"../strings\";\nimport { createOrderCall, useShopSettings, validateDiscountCall, type DiscountPreview } from \"../lib\";\n\ntype Blk = z.infer<typeof CheckoutBlockSchema>;\n\n/**\n * Afrekenen — klantgegevens + overzicht + kortingscode; `createOrder` herrekent server-side\n * (incl. korting en personalisatie-meerprijs) en geeft de Stripe Checkout-URL terug. De cart\n * wordt pas geleegd op de bedankt-pagina, zodat een geannuleerde betaling niets kwijtraakt.\n * NB: verplichte velden dragen een \" *\" in het label (de Engelse Astryx-chip blijft uit).\n */\nfunction CheckoutRender({ block, siteId, mode }: BlockRenderProps<Blk>) {\n const settings = useShopSettings();\n const t = useShopStrings();\n const { lines, itemsCents } = useCart(siteId);\n const [v, setV] = useState({ name: \"\", email: \"\", phone: \"\", address: \"\", zip: \"\", city: \"\", note: \"\" });\n const [hp, setHp] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [codeInput, setCodeInput] = useState(\"\");\n const [codeBusy, setCodeBusy] = useState(false);\n const [discount, setDiscount] = useState<DiscountPreview | null>(null);\n\n const baseShipping = shippingCentsFor(\n itemsCents,\n { shippingFlatCents: settings.shippingFlatCents, shippingFreeFromCents: settings.shippingFreeFromCents || undefined },\n lines.length > 0,\n );\n const shippingCents = discount?.valid && discount.freeShipping ? 0 : baseShipping;\n const discountCents = discount?.valid ? Math.min(discount.discountCents ?? 0, itemsCents) : 0;\n const totalCents = Math.max(0, itemsCents - discountCents) + shippingCents;\n\n async function applyCode() {\n const code = codeInput.trim().toUpperCase();\n if (!code || codeBusy) return;\n setCodeBusy(true);\n try {\n const res = await validateDiscountCall(siteId, code, itemsCents);\n setDiscount(res.valid ? { ...res, code } : { valid: false });\n } catch {\n setDiscount({ valid: false });\n } finally {\n setCodeBusy(false);\n }\n }\n\n async function submit(e: FormEvent) {\n e.preventDefault();\n if (mode === \"preview\" || busy) return;\n setBusy(true);\n setError(null);\n try {\n const { url } = await createOrderCall({\n siteId,\n items: lines.map((l) => ({\n productId: l.productId,\n variantKey: l.variantKey,\n qty: l.qty,\n personalization: l.personalization,\n })),\n customer: { email: v.email, name: v.name, phone: v.phone || undefined },\n shipping: { address: v.address, zip: v.zip, city: v.city, country: \"NL\" },\n note: v.note || undefined,\n discountCode: discount?.valid ? discount.code : undefined,\n successPath: settings.successPath,\n cancelPath: settings.cartPath,\n _hp: hp || undefined,\n });\n window.location.assign(url);\n } catch (err) {\n console.error(\"[xicms] checkout mislukt:\", err);\n setError(t(\"checkoutFailed\"));\n setBusy(false);\n }\n }\n\n if (lines.length === 0) {\n return (\n <Card padding={4} variant=\"muted\">\n <Text>\n {t(\"cartEmpty\")} <a href={settings.shopPath}>{t(\"toShop\")}</a>\n </Text>\n </Card>\n );\n }\n\n return (\n <div className=\"xicms-shop-checkout\" style={{ display: \"grid\", gap: \"2rem\", gridTemplateColumns: \"repeat(auto-fit, minmax(min(320px, 100%), 1fr))\" }}>\n <form onSubmit={submit} style={{ display: \"grid\", gap: \"0.9rem\", alignContent: \"start\" }}>\n {block.heading && <Heading level={1} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n {block.introText && <Text data-xicms-edit=\"introText\">{block.introText}</Text>}\n\n <TextInput label={`${t(\"fieldName\")} *`} value={v.name} onChange={(x) => setV((p) => ({ ...p, name: x }))} />\n <TextInput label={`${t(\"fieldEmail\")} *`} type=\"email\" value={v.email} onChange={(x) => setV((p) => ({ ...p, email: x }))} />\n <TextInput label={t(\"fieldPhone\")} value={v.phone} onChange={(x) => setV((p) => ({ ...p, phone: x }))} />\n <TextInput label={`${t(\"fieldAddress\")} *`} value={v.address} onChange={(x) => setV((p) => ({ ...p, address: x }))} />\n <div style={{ display: \"grid\", gap: \"0.9rem\", gridTemplateColumns: \"140px 1fr\" }}>\n <TextInput label={`${t(\"fieldZip\")} *`} value={v.zip} onChange={(x) => setV((p) => ({ ...p, zip: x }))} />\n <TextInput label={`${t(\"fieldCity\")} *`} value={v.city} onChange={(x) => setV((p) => ({ ...p, city: x }))} />\n </div>\n <TextArea label={t(\"fieldNote\")} rows={3} value={v.note} onChange={(x) => setV((p) => ({ ...p, note: x }))} />\n\n {/* Honeypot — verborgen voor mensen, bots vullen 'm vaak wel in. */}\n <input\n type=\"text\"\n tabIndex={-1}\n autoComplete=\"off\"\n value={hp}\n onChange={(e) => setHp(e.target.value)}\n style={{ position: \"absolute\", left: \"-9999px\", width: 1, height: 1 }}\n aria-hidden\n />\n\n {error && <Text role=\"alert\" style={{ color: \"var(--color-error, #c0392b)\" }}>{error}</Text>}\n\n <button\n type=\"submit\"\n className=\"xicms-btn xicms-btn--primary\"\n disabled={busy}\n style={{ cursor: busy ? \"wait\" : \"pointer\", width: \"fit-content\" }}\n >\n {busy ? t(\"busy\") : t(\"pay\", { bedrag: formatCents(totalCents, settings.currency) })}\n </button>\n <Text size=\"sm\" style={{ opacity: 0.7 }}>{t(\"secureNote\")}</Text>\n </form>\n\n <Card padding={3} variant=\"muted\" style={{ alignSelf: \"start\" }}>\n <Heading level={2}>{t(\"yourOrder\")}</Heading>\n <div style={{ display: \"grid\", gap: 8, marginTop: \"0.75rem\" }}>\n {lines.map((l) => (\n <div key={cartLineKey(l)} style={{ display: \"flex\", justifyContent: \"space-between\", gap: 12 }}>\n <Text size=\"sm\">\n {l.qty}× {l.name}\n {l.variantLabel ? ` (${l.variantLabel})` : \"\"}\n {l.personalizationLabel ? ` — ${l.personalizationLabel}` : \"\"}\n </Text>\n <Text size=\"sm\">{formatCents(l.unitPriceCents * l.qty, settings.currency)}</Text>\n </div>\n ))}\n\n {/* Kortingscode */}\n <div className=\"xicms-shop-checkout__discount\" style={{ display: \"flex\", gap: 8, marginTop: 4 }}>\n <input\n className=\"xicms-input\"\n type=\"text\"\n placeholder={t(\"discountCode\")}\n value={codeInput}\n onChange={(e) => setCodeInput(e.target.value.toUpperCase())}\n style={{ flex: 1, textTransform: \"uppercase\" }}\n />\n <button type=\"button\" className=\"xicms-btn xicms-btn--secondary\" disabled={codeBusy || !codeInput.trim()} onClick={applyCode}>\n {codeBusy ? t(\"busy\") : t(\"discountApply\")}\n </button>\n </div>\n {discount && !discount.valid && (\n <Text size=\"sm\" role=\"alert\" style={{ color: \"var(--color-error, #c0392b)\" }}>{t(\"discountInvalid\")}</Text>\n )}\n {discount?.valid && (\n <Text size=\"sm\" style={{ color: \"var(--xicms-primary, #4d7fb0)\", fontWeight: 600 }}>\n {t(\"discountApplied\", { code: discount.code ?? \"\" })}\n </Text>\n )}\n\n <hr style={{ border: \"none\", borderTop: \"1px solid rgba(0,0,0,0.1)\" }} />\n {discountCents > 0 && (\n <div style={{ display: \"flex\", justifyContent: \"space-between\" }}>\n <Text size=\"sm\">{t(\"discount\")}</Text>\n <Text size=\"sm\">−{formatCents(discountCents, settings.currency)}</Text>\n </div>\n )}\n <div style={{ display: \"flex\", justifyContent: \"space-between\" }}>\n <Text size=\"sm\">{t(\"shippingCosts\")}</Text>\n <Text size=\"sm\">{shippingCents === 0 ? t(\"free\") : formatCents(shippingCents, settings.currency)}</Text>\n </div>\n <div style={{ display: \"flex\", justifyContent: \"space-between\" }}>\n <Text weight=\"bold\">{t(\"total\")}</Text>\n <Text weight=\"bold\">{formatCents(totalCents, settings.currency)}</Text>\n </div>\n </div>\n </Card>\n </div>\n );\n}\n\nexport const checkoutBlock = defineBlock({\n type: \"checkout\",\n Render: CheckoutRender,\n label: \"Afrekenen\",\n icon: \"💳\",\n defaults: () => ({ heading: \"Afrekenen\" }),\n});\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/shop/blocks/Checkout.tsx"],"sourcesContent":["\"use client\";\n\nimport { useMemo, useState, type FormEvent } from \"react\";\nimport type { z } from \"zod\";\nimport { formatCents, shippingCentsFor, verzendLanden } from \"../../../schema/shopGeld\";\nimport type { CheckoutBlockSchema } from \"../../../schema/shop\";\nimport { defineBlock, type BlockRenderProps } from \"../../../blocks/registry\";\nimport { Card, Heading, Text } from \"../../../blocks/ui\";\nimport { TextInput } from \"@astryxdesign/core/TextInput\";\nimport { TextArea } from \"@astryxdesign/core/TextArea\";\nimport { cartLineKey, useCart } from \"../cartStore\";\nimport { useShopStrings } from \"../strings\";\nimport { createOrderCall, useShopSettings, validateDiscountCall, type DiscountPreview } from \"../lib\";\n\ntype Blk = z.infer<typeof CheckoutBlockSchema>;\n\n/**\n * Afrekenen — klantgegevens + overzicht + kortingscode; `createOrder` herrekent server-side\n * (incl. korting en personalisatie-meerprijs) en geeft de Stripe Checkout-URL terug. De cart\n * wordt pas geleegd op de bedankt-pagina, zodat een geannuleerde betaling niets kwijtraakt.\n * NB: verplichte velden dragen een \" *\" in het label (de Engelse Astryx-chip blijft uit).\n */\n/** Landnamen in het Nederlands (\"BE\" → \"België\"); valt terug op de code als de browser hem niet kent. */\nconst LANDNAMEN = new Intl.DisplayNames([\"nl\"], { type: \"region\" });\n\nfunction CheckoutRender({ block, siteId, mode }: BlockRenderProps<Blk>) {\n const settings = useShopSettings();\n const t = useShopStrings();\n const { lines, itemsCents } = useCart(siteId);\n const [v, setV] = useState({ name: \"\", email: \"\", phone: \"\", address: \"\", zip: \"\", city: \"\", country: \"NL\", note: \"\" });\n const [hp, setHp] = useState(\"\");\n // Welke landen bedient deze winkel? Leeg (of geen zones) = alleen het standaardland.\n const landOpties = useMemo(() => {\n const uit = verzendLanden({ shippingZones: settings.shippingZones });\n return uit.length > 0 ? uit : [\"NL\"];\n }, [settings.shippingZones]);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [codeInput, setCodeInput] = useState(\"\");\n const [codeBusy, setCodeBusy] = useState(false);\n const [discount, setDiscount] = useState<DiscountPreview | null>(null);\n\n // Eén rekenfunctie voor winkelwagen, afrekenen en server (zie shopGeld.ts): het land bepaalt de\n // zone, en een kortingscode met gratis verzending zit er nu ín in plaats van eromheen.\n const shippingCents = shippingCentsFor(\n itemsCents,\n {\n shippingFlatCents: settings.shippingFlatCents,\n shippingFreeFromCents: settings.shippingFreeFromCents || undefined,\n shippingZones: settings.shippingZones,\n },\n lines.length > 0,\n { land: v.country, freeShipping: discount?.valid && discount.freeShipping },\n );\n const discountCents = discount?.valid ? Math.min(discount.discountCents ?? 0, itemsCents) : 0;\n const totalCents = Math.max(0, itemsCents - discountCents) + shippingCents;\n\n async function applyCode() {\n const code = codeInput.trim().toUpperCase();\n if (!code || codeBusy) return;\n setCodeBusy(true);\n try {\n const res = await validateDiscountCall(siteId, code, itemsCents);\n setDiscount(res.valid ? { ...res, code } : { valid: false });\n } catch {\n setDiscount({ valid: false });\n } finally {\n setCodeBusy(false);\n }\n }\n\n async function submit(e: FormEvent) {\n e.preventDefault();\n if (mode === \"preview\" || busy) return;\n setBusy(true);\n setError(null);\n try {\n const { url } = await createOrderCall({\n siteId,\n items: lines.map((l) => ({\n productId: l.productId,\n variantKey: l.variantKey,\n qty: l.qty,\n personalization: l.personalization,\n })),\n customer: { email: v.email, name: v.name, phone: v.phone || undefined },\n shipping: { address: v.address, zip: v.zip, city: v.city, country: v.country || \"NL\" },\n note: v.note || undefined,\n discountCode: discount?.valid ? discount.code : undefined,\n successPath: settings.successPath,\n cancelPath: settings.cartPath,\n _hp: hp || undefined,\n });\n window.location.assign(url);\n } catch (err) {\n console.error(\"[xicms] checkout mislukt:\", err);\n setError(t(\"checkoutFailed\"));\n setBusy(false);\n }\n }\n\n if (lines.length === 0) {\n return (\n <Card padding={4} variant=\"muted\">\n <Text>\n {t(\"cartEmpty\")} <a href={settings.shopPath}>{t(\"toShop\")}</a>\n </Text>\n </Card>\n );\n }\n\n return (\n <div className=\"xicms-shop-checkout\" style={{ display: \"grid\", gap: \"2rem\", gridTemplateColumns: \"repeat(auto-fit, minmax(min(320px, 100%), 1fr))\" }}>\n <form onSubmit={submit} style={{ display: \"grid\", gap: \"0.9rem\", alignContent: \"start\" }}>\n {block.heading && <Heading level={1} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n {block.introText && <Text data-xicms-edit=\"introText\">{block.introText}</Text>}\n\n <TextInput label={`${t(\"fieldName\")} *`} value={v.name} onChange={(x) => setV((p) => ({ ...p, name: x }))} />\n <TextInput label={`${t(\"fieldEmail\")} *`} type=\"email\" value={v.email} onChange={(x) => setV((p) => ({ ...p, email: x }))} />\n <TextInput label={t(\"fieldPhone\")} value={v.phone} onChange={(x) => setV((p) => ({ ...p, phone: x }))} />\n <TextInput label={`${t(\"fieldAddress\")} *`} value={v.address} onChange={(x) => setV((p) => ({ ...p, address: x }))} />\n <div style={{ display: \"grid\", gap: \"0.9rem\", gridTemplateColumns: \"140px 1fr\" }}>\n <TextInput label={`${t(\"fieldZip\")} *`} value={v.zip} onChange={(x) => setV((p) => ({ ...p, zip: x }))} />\n <TextInput label={`${t(\"fieldCity\")} *`} value={v.city} onChange={(x) => setV((p) => ({ ...p, city: x }))} />\n </div>\n <div>\n {/* Landkeuze alleen tonen wanneer de winkel meer dan één land bedient — anders is het\n een keuzemenu met één optie, en dat is ruis op een afrekenpagina. */}\n {landOpties.length > 1 && (\n <label style={{ display: \"grid\", gap: 4 }}>\n <span style={{ fontSize: \"0.9rem\" }}>{t(\"fieldCountry\")} *</span>\n <select\n className=\"xicms-input\"\n value={v.country}\n onChange={(e) => setV((p) => ({ ...p, country: e.target.value }))}\n >\n {landOpties.map((c) => (\n <option key={c} value={c}>\n {LANDNAMEN.of(c) ?? c}\n </option>\n ))}\n </select>\n </label>\n )}\n </div>\n <TextArea label={t(\"fieldNote\")} rows={3} value={v.note} onChange={(x) => setV((p) => ({ ...p, note: x }))} />\n\n {/* Honeypot — verborgen voor mensen, bots vullen 'm vaak wel in. */}\n <input\n type=\"text\"\n tabIndex={-1}\n autoComplete=\"off\"\n value={hp}\n onChange={(e) => setHp(e.target.value)}\n style={{ position: \"absolute\", left: \"-9999px\", width: 1, height: 1 }}\n aria-hidden\n />\n\n {error && <Text role=\"alert\" style={{ color: \"var(--color-error, #c0392b)\" }}>{error}</Text>}\n\n <button\n type=\"submit\"\n className=\"xicms-btn xicms-btn--primary\"\n disabled={busy}\n style={{ cursor: busy ? \"wait\" : \"pointer\", width: \"fit-content\" }}\n >\n {busy ? t(\"busy\") : t(\"pay\", { bedrag: formatCents(totalCents, settings.currency) })}\n </button>\n <Text size=\"sm\" style={{ opacity: 0.7 }}>{t(\"secureNote\")}</Text>\n </form>\n\n <Card padding={3} variant=\"muted\" style={{ alignSelf: \"start\" }}>\n <Heading level={2}>{t(\"yourOrder\")}</Heading>\n <div style={{ display: \"grid\", gap: 8, marginTop: \"0.75rem\" }}>\n {lines.map((l) => (\n <div key={cartLineKey(l)} style={{ display: \"flex\", justifyContent: \"space-between\", gap: 12 }}>\n <Text size=\"sm\">\n {l.qty}× {l.name}\n {l.variantLabel ? ` (${l.variantLabel})` : \"\"}\n {l.personalizationLabel ? ` — ${l.personalizationLabel}` : \"\"}\n </Text>\n <Text size=\"sm\">{formatCents(l.unitPriceCents * l.qty, settings.currency)}</Text>\n </div>\n ))}\n\n {/* Kortingscode */}\n <div className=\"xicms-shop-checkout__discount\" style={{ display: \"flex\", gap: 8, marginTop: 4 }}>\n <input\n className=\"xicms-input\"\n type=\"text\"\n placeholder={t(\"discountCode\")}\n value={codeInput}\n onChange={(e) => setCodeInput(e.target.value.toUpperCase())}\n style={{ flex: 1, textTransform: \"uppercase\" }}\n />\n <button type=\"button\" className=\"xicms-btn xicms-btn--secondary\" disabled={codeBusy || !codeInput.trim()} onClick={applyCode}>\n {codeBusy ? t(\"busy\") : t(\"discountApply\")}\n </button>\n </div>\n {discount && !discount.valid && (\n <Text size=\"sm\" role=\"alert\" style={{ color: \"var(--color-error, #c0392b)\" }}>{t(\"discountInvalid\")}</Text>\n )}\n {discount?.valid && (\n <Text size=\"sm\" style={{ color: \"var(--xicms-primary, #4d7fb0)\", fontWeight: 600 }}>\n {t(\"discountApplied\", { code: discount.code ?? \"\" })}\n </Text>\n )}\n\n <hr style={{ border: \"none\", borderTop: \"1px solid rgba(0,0,0,0.1)\" }} />\n {discountCents > 0 && (\n <div style={{ display: \"flex\", justifyContent: \"space-between\" }}>\n <Text size=\"sm\">{t(\"discount\")}</Text>\n <Text size=\"sm\">−{formatCents(discountCents, settings.currency)}</Text>\n </div>\n )}\n <div style={{ display: \"flex\", justifyContent: \"space-between\" }}>\n <Text size=\"sm\">{t(\"shippingCosts\")}</Text>\n <Text size=\"sm\">{shippingCents === 0 ? t(\"free\") : formatCents(shippingCents, settings.currency)}</Text>\n </div>\n <div style={{ display: \"flex\", justifyContent: \"space-between\" }}>\n <Text weight=\"bold\">{t(\"total\")}</Text>\n <Text weight=\"bold\">{formatCents(totalCents, settings.currency)}</Text>\n </div>\n </div>\n </Card>\n </div>\n );\n}\n\nexport const checkoutBlock = defineBlock({\n type: \"checkout\",\n Render: CheckoutRender,\n label: \"Afrekenen\",\n icon: \"💳\",\n defaults: () => ({ heading: \"Afrekenen\" }),\n});\n"],"mappings":"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","names":[]}
|
|
@@ -25,7 +25,10 @@ function PriceLine({ product, currency }) {
|
|
|
25
25
|
] });
|
|
26
26
|
}
|
|
27
27
|
function isSoldOut(p) {
|
|
28
|
-
|
|
28
|
+
if (p.trackStock !== true) return false;
|
|
29
|
+
if ((p.options ?? []).length === 0) return p.stock !== void 0 && p.stock <= 0;
|
|
30
|
+
const metVoorraad = (p.variants ?? []).filter((v) => v.stock !== void 0 && v.active !== false);
|
|
31
|
+
return metVoorraad.length > 0 && metVoorraad.every((v) => v.stock <= 0);
|
|
29
32
|
}
|
|
30
33
|
function ColorSwatches({ product, onHover }) {
|
|
31
34
|
const optie = kleurOptie(product);
|
|
@@ -165,6 +168,7 @@ function ProductGridRender({ block, siteId }) {
|
|
|
165
168
|
else if (sort === "priceAsc") sorted.sort((a, b) => a.priceCents - b.priceCents);
|
|
166
169
|
else if (sort === "priceDesc") sorted.sort((a, b) => b.priceCents - a.priceCents);
|
|
167
170
|
else sorted.sort((a, b) => (a.order ?? 0) - (b.order ?? 0) || a.name.localeCompare(b.name, "nl"));
|
|
171
|
+
sorted.sort((a, b) => Number(isSoldOut(a)) - Number(isSoldOut(b)));
|
|
168
172
|
return sorted.slice(0, block.limit);
|
|
169
173
|
}, [products, activeCat, block.featuredOnly, block.limit, sort, filterColor, filterSize]);
|
|
170
174
|
if (products === null) return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/shop/blocks/ProductGrid.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport type { z } from \"zod\";\nimport { formatCents } from \"../../../schema/shopGeld\";\nimport type { ProductGridBlockSchema } from \"../../../schema/shop\";\nimport { defineBlock, type BlockRenderProps } from \"../../../blocks/registry\";\nimport { useBlockData } from \"../../../blocks/context\";\nimport { Card, Heading, Text } from \"../../../blocks/ui\";\nimport { cartAdd } from \"../cartStore\";\nimport { useShopStrings, type ShopT } from \"../strings\";\nimport {\n fetchActiveProducts,\n fetchShopCategories,\n kleurNaarCss,\n kleurOptie,\n readQueryParam,\n useShopSettings,\n type StoredProduct,\n type StoredShopCategory,\n} from \"../lib\";\nimport type { ShopPageData } from \"../types\";\n\ntype Blk = z.infer<typeof ProductGridBlockSchema>;\n\n/** Prijsregel met optionele doorgestreepte \"van\"-prijs en \"vanaf\" bij variant-prijzen. */\nexport function PriceLine({ product, currency }: { product: StoredProduct; currency: string }) {\n const variantPrices = (product.variants ?? [])\n .filter((v) => v.priceCents !== undefined)\n .map((v) => v.priceCents as number);\n const min = Math.min(product.priceCents, ...variantPrices);\n const hasRange = variantPrices.some((p) => p !== product.priceCents);\n return (\n <span className=\"xicms-shop-price\">\n {product.compareAtCents !== undefined && product.compareAtCents > min && (\n <s style={{ opacity: 0.6, marginRight: 6 }}>{formatCents(product.compareAtCents, currency)}</s>\n )}\n {hasRange ? `vanaf ${formatCents(min, currency)}` : formatCents(min, currency)}\n </span>\n );\n}\n\n/** Uitverkocht (alleen betrouwbaar vast te stellen zonder opties: expliciete voorraad 0). */\nfunction isSoldOut(p: StoredProduct): boolean {\n return p.trackStock === true && (p.options ?? []).length === 0 && p.stock !== undefined && p.stock <= 0;\n}\n\n/** Stof-stipjes; hover wisselt de kaartfoto naar de per-kleur-afbeelding (als die er is). */\nfunction ColorSwatches({ product, onHover }: { product: StoredProduct; onHover?: (url: string | null) => void }) {\n const optie = kleurOptie(product);\n if (!optie) return null;\n const dots = optie.values\n .map((v) => ({ v, css: kleurNaarCss(v), img: optie.images?.[v] }))\n .filter((d): d is { v: string; css: string; img: string | undefined } => d.css !== null);\n if (dots.length === 0) return null;\n return (\n <span className=\"xicms-shop-card__swatches\" aria-label={`Kleuren: ${optie.values.join(\", \")}`}>\n {dots.map((d) => (\n <span\n key={d.v}\n className=\"xicms-shop-card__swatch\"\n title={d.v}\n onMouseEnter={d.img && onHover ? () => onHover(d.img ?? null) : undefined}\n onMouseLeave={d.img && onHover ? () => onHover(null) : undefined}\n style={{\n display: \"inline-block\",\n width: 12,\n height: 12,\n borderRadius: 999,\n background: d.css,\n boxShadow: \"inset 0 0 0 1px rgba(0,0,0,0.18)\",\n }}\n />\n ))}\n </span>\n );\n}\n\nexport function ProductCard({\n product,\n siteId,\n currency,\n detailPath,\n cartPath,\n t,\n filterColor,\n}: {\n product: StoredProduct;\n siteId: string;\n currency: string;\n detailPath: string;\n cartPath: string;\n t: ShopT;\n /** Actief kleurfilter uit het overzicht — toont bij voorkeur de foto van die kleur. */\n filterColor?: string | null;\n}) {\n const [added, setAdded] = useState(false);\n const [hoverImage, setHoverImage] = useState<string | null>(null);\n const href = `${detailPath}?p=${encodeURIComponent(product.slug)}`;\n const simple = (product.options ?? []).length === 0 && !(product.personalization ?? []).length;\n const soldOut = isSoldOut(product);\n const filterImage = filterColor ? kleurOptie(product)?.images?.[filterColor] : undefined;\n const image = hoverImage ?? filterImage ?? product.images?.[0];\n\n return (\n // Flex-kolom over de volle kaarthoogte: titel (vast 2 regels) → prijs → swatches →\n // knop onderaan. Zo lijnen prijs/swatches/knop over álle kaarten in de rij uit, ook\n // als een productnaam één of twee regels beslaat. Alle opmaak in styles.css.\n // `data-xicms-product` maakt de kaart in de bewerkmodus aanwijsbaar als PRODUCT (potlood voor\n // de naam, tandwiel voor het hele formulier). Op de cataloguspagina was dat er niet, en dus was\n // een productnaam daar het enige stuk tekst op de site dat je nergens kon aanklikken.\n <Card padding={0} className=\"xicms-shop-card\" data-xicms-product={product.id}>\n <a className=\"xicms-shop-card__link\" href={href}>\n <div className=\"xicms-shop-card__media\">\n {image ? (\n <img src={image} alt={product.name} loading=\"lazy\" className=\"xicms-shop-card__img\" />\n ) : (\n <div className=\"xicms-shop-card__placeholder\" aria-hidden=\"true\" />\n )}\n {soldOut && <span className=\"xicms-shop-card__soldout\">{t(\"soldOut\")}</span>}\n </div>\n <div className=\"xicms-shop-card__body\">\n <span className=\"xicms-shop-card__name\" data-xicms-product-edit=\"name\">{product.name}</span>\n <span className=\"xicms-shop-card__priceline\">\n <PriceLine product={product} currency={currency} />\n </span>\n <span className=\"xicms-shop-card__swatchrow\">\n <ColorSwatches product={product} onHover={setHoverImage} />\n </span>\n </div>\n </a>\n <div className=\"xicms-shop-card__actions\">\n {simple ? (\n added ? (\n <a className=\"xicms-shop-card__added\" href={cartPath}>\n {t(\"addedGoToCart\")}\n </a>\n ) : (\n <button\n type=\"button\"\n className=\"xicms-btn xicms-btn--primary\"\n disabled={soldOut}\n style={{ cursor: soldOut ? \"not-allowed\" : \"pointer\" }}\n onClick={() => {\n cartAdd(siteId, {\n productId: product.id,\n slug: product.slug,\n name: product.name,\n unitPriceCents: product.priceCents,\n imageUrl: product.images?.[0],\n });\n setAdded(true);\n }}\n >\n {t(\"addToCart\")}\n </button>\n )\n ) : (\n <a className=\"xicms-btn xicms-btn--secondary\" href={href}>\n {t(\"view\")}\n </a>\n )}\n </div>\n </Card>\n );\n}\n\nfunction ProductGridRender({ block, siteId }: BlockRenderProps<Blk>) {\n const settings = useShopSettings();\n const t = useShopStrings();\n const serverData = useBlockData<ShopPageData>(\"shop\");\n const [products, setProducts] = useState<StoredProduct[] | null>(serverData?.products ?? null);\n const [cats, setCats] = useState<StoredShopCategory[]>(serverData?.categories ?? []);\n const [queryCat, setQueryCat] = useState<string | null>(null);\n const [filterColor, setFilterColor] = useState<string | null>(null);\n const [filterSize, setFilterSize] = useState<string | null>(null);\n const [sort, setSort] = useState<Blk[\"sort\"]>(block.sort);\n\n useEffect(() => {\n // Server-data aanwezig (SSR/ISR)? Dan geen client-fetch — geen flits, minder reads.\n if (!serverData?.products) {\n void fetchActiveProducts(siteId).then(setProducts).catch((e) => {\n console.warn(\"[xicms] producten laden mislukt:\", e);\n setProducts([]);\n });\n }\n if (!serverData?.categories) {\n void fetchShopCategories(siteId).then(setCats).catch(() => setCats([]));\n }\n if (block.useQueryCategory && !block.categorySlug) setQueryCat(readQueryParam(\"cat\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [siteId, block.useQueryCategory, block.categorySlug]);\n\n const activeSlug = block.categorySlug || queryCat || null;\n const activeCat = activeSlug ? cats.find((c) => c.slug === activeSlug) ?? null : null;\n\n /** Beschikbare filterwaarden uit de geladen set (client-side; geen extra reads). */\n const filterValues = useMemo(() => {\n if (!block.showFilters || !products) return { colors: [] as string[], sizes: [] as string[] };\n const colors = new Set<string>();\n const sizes = new Set<string>();\n for (const p of products) {\n for (const o of p.options ?? []) {\n if (/^kleur|^colou?r/i.test(o.name)) o.values.forEach((v) => colors.add(v));\n if (/^maat|^size/i.test(o.name)) o.values.forEach((v) => sizes.add(v));\n }\n }\n return { colors: [...colors], sizes: [...sizes].sort((a, b) => Number(a) - Number(b) || a.localeCompare(b)) };\n }, [products, block.showFilters]);\n\n const visible = useMemo(() => {\n if (!products) return [];\n let list = products;\n if (activeCat) list = list.filter((p) => (p.categoryIds ?? []).includes(activeCat.id));\n if (block.featuredOnly) list = list.filter((p) => p.featured);\n if (filterColor) {\n list = list.filter((p) =>\n (p.options ?? []).some((o) => /^kleur|^colou?r/i.test(o.name) && o.values.includes(filterColor)),\n );\n }\n if (filterSize) {\n list = list.filter((p) =>\n (p.options ?? []).some((o) => /^maat|^size/i.test(o.name) && o.values.includes(filterSize)),\n );\n }\n const sorted = [...list];\n if (sort === \"name\") sorted.sort((a, b) => a.name.localeCompare(b.name, \"nl\"));\n else if (sort === \"priceAsc\") sorted.sort((a, b) => a.priceCents - b.priceCents);\n else if (sort === \"priceDesc\") sorted.sort((a, b) => b.priceCents - a.priceCents);\n else sorted.sort((a, b) => (a.order ?? 0) - (b.order ?? 0) || a.name.localeCompare(b.name, \"nl\"));\n return sorted.slice(0, block.limit);\n }, [products, activeCat, block.featuredOnly, block.limit, sort, filterColor, filterSize]);\n\n if (products === null) return null;\n\n const chip = (label: string, active: boolean, onClick: () => void, swatch?: string | null) => (\n <button\n key={label}\n type=\"button\"\n className={`xicms-shop-filterchip${active ? \" xicms-shop-filterchip--active\" : \"\"}`}\n aria-pressed={active}\n onClick={onClick}\n >\n {swatch && (\n <span\n aria-hidden\n style={{ display: \"inline-block\", width: 10, height: 10, borderRadius: 999, background: swatch, boxShadow: \"inset 0 0 0 1px rgba(0,0,0,0.18)\", marginRight: 5 }}\n />\n )}\n {label}\n </button>\n );\n\n return (\n <div className=\"xicms-shop-grid\">\n {(block.heading || activeCat) && (\n <Heading level={2} data-xicms-edit=\"heading\">\n {activeCat?.name ?? block.heading}\n </Heading>\n )}\n {activeCat && (\n <Text size=\"sm\" display=\"block\" style={{ marginTop: 4 }}>\n <a href={settings.shopPath}>← {t(\"allCategories\")}</a>\n </Text>\n )}\n\n {block.showFilters && (filterValues.colors.length > 0 || filterValues.sizes.length > 0) && (\n <div className=\"xicms-shop-filters\">\n {filterValues.colors.length > 0 && (\n <div className=\"xicms-shop-filters__row\" role=\"group\" aria-label=\"Kleur\">\n {chip(t(\"filterAll\"), filterColor === null, () => setFilterColor(null))}\n {filterValues.colors.map((c) =>\n chip(c, filterColor === c, () => setFilterColor(filterColor === c ? null : c), kleurNaarCss(c)),\n )}\n </div>\n )}\n {filterValues.sizes.length > 0 && (\n <div className=\"xicms-shop-filters__row\" role=\"group\" aria-label=\"Maat\">\n {chip(t(\"filterAll\"), filterSize === null, () => setFilterSize(null))}\n {filterValues.sizes.map((s) => chip(s, filterSize === s, () => setFilterSize(filterSize === s ? null : s)))}\n </div>\n )}\n <label className=\"xicms-shop-filters__sort\">\n <span>{t(\"sortLabel\")}</span>\n <select className=\"xicms-input\" value={sort} onChange={(e) => setSort(e.target.value as Blk[\"sort\"])}>\n <option value=\"order\">{t(\"sortDefault\")}</option>\n <option value=\"name\">{t(\"sortName\")}</option>\n <option value=\"priceAsc\">{t(\"sortPriceAsc\")}</option>\n <option value=\"priceDesc\">{t(\"sortPriceDesc\")}</option>\n </select>\n </label>\n </div>\n )}\n\n {visible.length === 0 ? (\n <Card padding={4} variant=\"muted\" style={{ marginTop: \"1rem\" }}>\n <Text>{t(\"noProducts\")}</Text>\n </Card>\n ) : (\n <div\n className=\"xicms-shop-grid__items\"\n data-columns={block.columns}\n style={{\n display: \"grid\",\n gridTemplateColumns: `repeat(auto-fill, minmax(min(240px, calc(100%/${block.columns} - 1rem)), 1fr))`,\n gap: \"1.25rem\",\n marginTop: \"1.25rem\",\n }}\n >\n {visible.map((p) => (\n <ProductCard\n key={p.id}\n product={p}\n siteId={siteId}\n currency={settings.currency}\n detailPath={settings.detailPath}\n cartPath={settings.cartPath}\n t={t}\n filterColor={filterColor}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\nexport const productGridBlock = defineBlock({\n type: \"productGrid\",\n Render: ProductGridRender,\n label: \"Producten-overzicht\",\n icon: \"🛍️\",\n defaults: () => ({ useQueryCategory: true, columns: 3, limit: 60, sort: \"order\" }),\n});\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/shop/blocks/ProductGrid.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport type { z } from \"zod\";\nimport { formatCents } from \"../../../schema/shopGeld\";\nimport type { ProductGridBlockSchema } from \"../../../schema/shop\";\nimport { defineBlock, type BlockRenderProps } from \"../../../blocks/registry\";\nimport { useBlockData } from \"../../../blocks/context\";\nimport { Card, Heading, Text } from \"../../../blocks/ui\";\nimport { cartAdd } from \"../cartStore\";\nimport { useShopStrings, type ShopT } from \"../strings\";\nimport {\n fetchActiveProducts,\n fetchShopCategories,\n kleurNaarCss,\n kleurOptie,\n readQueryParam,\n useShopSettings,\n type StoredProduct,\n type StoredShopCategory,\n} from \"../lib\";\nimport type { ShopPageData } from \"../types\";\n\ntype Blk = z.infer<typeof ProductGridBlockSchema>;\n\n/** Prijsregel met optionele doorgestreepte \"van\"-prijs en \"vanaf\" bij variant-prijzen. */\nexport function PriceLine({ product, currency }: { product: StoredProduct; currency: string }) {\n const variantPrices = (product.variants ?? [])\n .filter((v) => v.priceCents !== undefined)\n .map((v) => v.priceCents as number);\n const min = Math.min(product.priceCents, ...variantPrices);\n const hasRange = variantPrices.some((p) => p !== product.priceCents);\n return (\n <span className=\"xicms-shop-price\">\n {product.compareAtCents !== undefined && product.compareAtCents > min && (\n <s style={{ opacity: 0.6, marginRight: 6 }}>{formatCents(product.compareAtCents, currency)}</s>\n )}\n {hasRange ? `vanaf ${formatCents(min, currency)}` : formatCents(min, currency)}\n </span>\n );\n}\n\n/**\n * Uitverkocht. Zonder opties: de voorraad van het product zelf. MÉT opties: pas uitverkocht als\n * élke variant met een expliciete voorraad op 0 staat — dat was eerder helemaal niet af te lezen,\n * waardoor een volledig uitverkocht t-shirt gewoon als beschikbaar in het grid stond.\n */\nfunction isSoldOut(p: StoredProduct): boolean {\n if (p.trackStock !== true) return false;\n if ((p.options ?? []).length === 0) return p.stock !== undefined && p.stock <= 0;\n const metVoorraad = (p.variants ?? []).filter((v) => v.stock !== undefined && v.active !== false);\n return metVoorraad.length > 0 && metVoorraad.every((v) => (v.stock as number) <= 0);\n}\n\n/** Stof-stipjes; hover wisselt de kaartfoto naar de per-kleur-afbeelding (als die er is). */\nfunction ColorSwatches({ product, onHover }: { product: StoredProduct; onHover?: (url: string | null) => void }) {\n const optie = kleurOptie(product);\n if (!optie) return null;\n const dots = optie.values\n .map((v) => ({ v, css: kleurNaarCss(v), img: optie.images?.[v] }))\n .filter((d): d is { v: string; css: string; img: string | undefined } => d.css !== null);\n if (dots.length === 0) return null;\n return (\n <span className=\"xicms-shop-card__swatches\" aria-label={`Kleuren: ${optie.values.join(\", \")}`}>\n {dots.map((d) => (\n <span\n key={d.v}\n className=\"xicms-shop-card__swatch\"\n title={d.v}\n onMouseEnter={d.img && onHover ? () => onHover(d.img ?? null) : undefined}\n onMouseLeave={d.img && onHover ? () => onHover(null) : undefined}\n style={{\n display: \"inline-block\",\n width: 12,\n height: 12,\n borderRadius: 999,\n background: d.css,\n boxShadow: \"inset 0 0 0 1px rgba(0,0,0,0.18)\",\n }}\n />\n ))}\n </span>\n );\n}\n\nexport function ProductCard({\n product,\n siteId,\n currency,\n detailPath,\n cartPath,\n t,\n filterColor,\n}: {\n product: StoredProduct;\n siteId: string;\n currency: string;\n detailPath: string;\n cartPath: string;\n t: ShopT;\n /** Actief kleurfilter uit het overzicht — toont bij voorkeur de foto van die kleur. */\n filterColor?: string | null;\n}) {\n const [added, setAdded] = useState(false);\n const [hoverImage, setHoverImage] = useState<string | null>(null);\n const href = `${detailPath}?p=${encodeURIComponent(product.slug)}`;\n const simple = (product.options ?? []).length === 0 && !(product.personalization ?? []).length;\n const soldOut = isSoldOut(product);\n const filterImage = filterColor ? kleurOptie(product)?.images?.[filterColor] : undefined;\n const image = hoverImage ?? filterImage ?? product.images?.[0];\n\n return (\n // Flex-kolom over de volle kaarthoogte: titel (vast 2 regels) → prijs → swatches →\n // knop onderaan. Zo lijnen prijs/swatches/knop over álle kaarten in de rij uit, ook\n // als een productnaam één of twee regels beslaat. Alle opmaak in styles.css.\n // `data-xicms-product` maakt de kaart in de bewerkmodus aanwijsbaar als PRODUCT (potlood voor\n // de naam, tandwiel voor het hele formulier). Op de cataloguspagina was dat er niet, en dus was\n // een productnaam daar het enige stuk tekst op de site dat je nergens kon aanklikken.\n <Card padding={0} className=\"xicms-shop-card\" data-xicms-product={product.id}>\n <a className=\"xicms-shop-card__link\" href={href}>\n <div className=\"xicms-shop-card__media\">\n {image ? (\n <img src={image} alt={product.name} loading=\"lazy\" className=\"xicms-shop-card__img\" />\n ) : (\n <div className=\"xicms-shop-card__placeholder\" aria-hidden=\"true\" />\n )}\n {soldOut && <span className=\"xicms-shop-card__soldout\">{t(\"soldOut\")}</span>}\n </div>\n <div className=\"xicms-shop-card__body\">\n <span className=\"xicms-shop-card__name\" data-xicms-product-edit=\"name\">{product.name}</span>\n <span className=\"xicms-shop-card__priceline\">\n <PriceLine product={product} currency={currency} />\n </span>\n <span className=\"xicms-shop-card__swatchrow\">\n <ColorSwatches product={product} onHover={setHoverImage} />\n </span>\n </div>\n </a>\n <div className=\"xicms-shop-card__actions\">\n {simple ? (\n added ? (\n <a className=\"xicms-shop-card__added\" href={cartPath}>\n {t(\"addedGoToCart\")}\n </a>\n ) : (\n <button\n type=\"button\"\n className=\"xicms-btn xicms-btn--primary\"\n disabled={soldOut}\n style={{ cursor: soldOut ? \"not-allowed\" : \"pointer\" }}\n onClick={() => {\n cartAdd(siteId, {\n productId: product.id,\n slug: product.slug,\n name: product.name,\n unitPriceCents: product.priceCents,\n imageUrl: product.images?.[0],\n });\n setAdded(true);\n }}\n >\n {t(\"addToCart\")}\n </button>\n )\n ) : (\n <a className=\"xicms-btn xicms-btn--secondary\" href={href}>\n {t(\"view\")}\n </a>\n )}\n </div>\n </Card>\n );\n}\n\nfunction ProductGridRender({ block, siteId }: BlockRenderProps<Blk>) {\n const settings = useShopSettings();\n const t = useShopStrings();\n const serverData = useBlockData<ShopPageData>(\"shop\");\n const [products, setProducts] = useState<StoredProduct[] | null>(serverData?.products ?? null);\n const [cats, setCats] = useState<StoredShopCategory[]>(serverData?.categories ?? []);\n const [queryCat, setQueryCat] = useState<string | null>(null);\n const [filterColor, setFilterColor] = useState<string | null>(null);\n const [filterSize, setFilterSize] = useState<string | null>(null);\n const [sort, setSort] = useState<Blk[\"sort\"]>(block.sort);\n\n useEffect(() => {\n // Server-data aanwezig (SSR/ISR)? Dan geen client-fetch — geen flits, minder reads.\n if (!serverData?.products) {\n void fetchActiveProducts(siteId).then(setProducts).catch((e) => {\n console.warn(\"[xicms] producten laden mislukt:\", e);\n setProducts([]);\n });\n }\n if (!serverData?.categories) {\n void fetchShopCategories(siteId).then(setCats).catch(() => setCats([]));\n }\n if (block.useQueryCategory && !block.categorySlug) setQueryCat(readQueryParam(\"cat\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [siteId, block.useQueryCategory, block.categorySlug]);\n\n const activeSlug = block.categorySlug || queryCat || null;\n const activeCat = activeSlug ? cats.find((c) => c.slug === activeSlug) ?? null : null;\n\n /** Beschikbare filterwaarden uit de geladen set (client-side; geen extra reads). */\n const filterValues = useMemo(() => {\n if (!block.showFilters || !products) return { colors: [] as string[], sizes: [] as string[] };\n const colors = new Set<string>();\n const sizes = new Set<string>();\n for (const p of products) {\n for (const o of p.options ?? []) {\n if (/^kleur|^colou?r/i.test(o.name)) o.values.forEach((v) => colors.add(v));\n if (/^maat|^size/i.test(o.name)) o.values.forEach((v) => sizes.add(v));\n }\n }\n return { colors: [...colors], sizes: [...sizes].sort((a, b) => Number(a) - Number(b) || a.localeCompare(b)) };\n }, [products, block.showFilters]);\n\n const visible = useMemo(() => {\n if (!products) return [];\n let list = products;\n if (activeCat) list = list.filter((p) => (p.categoryIds ?? []).includes(activeCat.id));\n if (block.featuredOnly) list = list.filter((p) => p.featured);\n if (filterColor) {\n list = list.filter((p) =>\n (p.options ?? []).some((o) => /^kleur|^colou?r/i.test(o.name) && o.values.includes(filterColor)),\n );\n }\n if (filterSize) {\n list = list.filter((p) =>\n (p.options ?? []).some((o) => /^maat|^size/i.test(o.name) && o.values.includes(filterSize)),\n );\n }\n const sorted = [...list];\n if (sort === \"name\") sorted.sort((a, b) => a.name.localeCompare(b.name, \"nl\"));\n else if (sort === \"priceAsc\") sorted.sort((a, b) => a.priceCents - b.priceCents);\n else if (sort === \"priceDesc\") sorted.sort((a, b) => b.priceCents - a.priceCents);\n else sorted.sort((a, b) => (a.order ?? 0) - (b.order ?? 0) || a.name.localeCompare(b.name, \"nl\"));\n /**\n * Uitverkochte artikelen altijd achteraan, ongeacht de gekozen sortering: ze bleven op hun\n * plek staan en duwden zo leverbare producten van de eerste rij. De volgorde binnen elke\n * groep blijft die van de sortering hierboven — een stabiele sort verandert daar niets aan.\n */\n sorted.sort((a, b) => Number(isSoldOut(a)) - Number(isSoldOut(b)));\n return sorted.slice(0, block.limit);\n }, [products, activeCat, block.featuredOnly, block.limit, sort, filterColor, filterSize]);\n\n if (products === null) return null;\n\n const chip = (label: string, active: boolean, onClick: () => void, swatch?: string | null) => (\n <button\n key={label}\n type=\"button\"\n className={`xicms-shop-filterchip${active ? \" xicms-shop-filterchip--active\" : \"\"}`}\n aria-pressed={active}\n onClick={onClick}\n >\n {swatch && (\n <span\n aria-hidden\n style={{ display: \"inline-block\", width: 10, height: 10, borderRadius: 999, background: swatch, boxShadow: \"inset 0 0 0 1px rgba(0,0,0,0.18)\", marginRight: 5 }}\n />\n )}\n {label}\n </button>\n );\n\n return (\n <div className=\"xicms-shop-grid\">\n {(block.heading || activeCat) && (\n <Heading level={2} data-xicms-edit=\"heading\">\n {activeCat?.name ?? block.heading}\n </Heading>\n )}\n {activeCat && (\n <Text size=\"sm\" display=\"block\" style={{ marginTop: 4 }}>\n <a href={settings.shopPath}>← {t(\"allCategories\")}</a>\n </Text>\n )}\n\n {block.showFilters && (filterValues.colors.length > 0 || filterValues.sizes.length > 0) && (\n <div className=\"xicms-shop-filters\">\n {filterValues.colors.length > 0 && (\n <div className=\"xicms-shop-filters__row\" role=\"group\" aria-label=\"Kleur\">\n {chip(t(\"filterAll\"), filterColor === null, () => setFilterColor(null))}\n {filterValues.colors.map((c) =>\n chip(c, filterColor === c, () => setFilterColor(filterColor === c ? null : c), kleurNaarCss(c)),\n )}\n </div>\n )}\n {filterValues.sizes.length > 0 && (\n <div className=\"xicms-shop-filters__row\" role=\"group\" aria-label=\"Maat\">\n {chip(t(\"filterAll\"), filterSize === null, () => setFilterSize(null))}\n {filterValues.sizes.map((s) => chip(s, filterSize === s, () => setFilterSize(filterSize === s ? null : s)))}\n </div>\n )}\n <label className=\"xicms-shop-filters__sort\">\n <span>{t(\"sortLabel\")}</span>\n <select className=\"xicms-input\" value={sort} onChange={(e) => setSort(e.target.value as Blk[\"sort\"])}>\n <option value=\"order\">{t(\"sortDefault\")}</option>\n <option value=\"name\">{t(\"sortName\")}</option>\n <option value=\"priceAsc\">{t(\"sortPriceAsc\")}</option>\n <option value=\"priceDesc\">{t(\"sortPriceDesc\")}</option>\n </select>\n </label>\n </div>\n )}\n\n {visible.length === 0 ? (\n <Card padding={4} variant=\"muted\" style={{ marginTop: \"1rem\" }}>\n <Text>{t(\"noProducts\")}</Text>\n </Card>\n ) : (\n <div\n className=\"xicms-shop-grid__items\"\n data-columns={block.columns}\n style={{\n display: \"grid\",\n gridTemplateColumns: `repeat(auto-fill, minmax(min(240px, calc(100%/${block.columns} - 1rem)), 1fr))`,\n gap: \"1.25rem\",\n marginTop: \"1.25rem\",\n }}\n >\n {visible.map((p) => (\n <ProductCard\n key={p.id}\n product={p}\n siteId={siteId}\n currency={settings.currency}\n detailPath={settings.detailPath}\n cartPath={settings.cartPath}\n t={t}\n filterColor={filterColor}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\nexport const productGridBlock = defineBlock({\n type: \"productGrid\",\n Render: ProductGridRender,\n label: \"Producten-overzicht\",\n icon: \"🛍️\",\n defaults: () => ({ useQueryCategory: true, columns: 3, limit: 60, sort: \"order\" }),\n});\n"],"mappings":"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","names":[]}
|
|
@@ -15,6 +15,12 @@ export declare const ShopSettingsSchema: z.ZodMiniObject<{
|
|
|
15
15
|
currency: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
16
16
|
shippingFlatCents: z.ZodMiniDefault<z.ZodMiniNumberFormat>;
|
|
17
17
|
shippingFreeFromCents: z.ZodMiniDefault<z.ZodMiniNumberFormat>;
|
|
18
|
+
shippingZones: z.ZodMiniDefault<z.ZodMiniArray<z.ZodMiniObject<{
|
|
19
|
+
naam: z.ZodMiniString<string>;
|
|
20
|
+
landen: z.ZodMiniDefault<z.ZodMiniArray<z.ZodMiniString<string>>>;
|
|
21
|
+
flatCents: z.ZodMiniDefault<z.ZodMiniNumberFormat>;
|
|
22
|
+
freeFromCents: z.ZodMiniDefault<z.ZodMiniNumberFormat>;
|
|
23
|
+
}, z.core.$strip>>>;
|
|
18
24
|
orderPrefix: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
19
25
|
invoicePrefix: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
20
26
|
businessName: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
@@ -23,6 +29,8 @@ export declare const ShopSettingsSchema: z.ZodMiniObject<{
|
|
|
23
29
|
businessCity: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
24
30
|
businessKvk: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
25
31
|
businessBtw: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
32
|
+
businessEmail: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
33
|
+
businessPhone: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
26
34
|
}, z.core.$strip>;
|
|
27
35
|
export type ShopSettings = z.infer<typeof ShopSettingsSchema>;
|
|
28
36
|
export declare const defaultShopSettings: ShopSettings;
|
|
@@ -8,6 +8,18 @@ const ShopSettingsSchema = z.object({
|
|
|
8
8
|
currency: z._default(z.string().check(z.minLength(3)).check(z.maxLength(3)), "EUR").register(z.globalRegistry, { description: "Valuta (ISO-code)" }),
|
|
9
9
|
shippingFlatCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1e5)), 495).register(z.globalRegistry, { description: "Verzendkosten (centen)" }),
|
|
10
10
|
shippingFreeFromCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1e8)), 0).register(z.globalRegistry, { description: "Gratis verzending vanaf (centen, 0 = nooit)" }),
|
|
11
|
+
/**
|
|
12
|
+
* Verzendzones (7.20): tarief per (groep) land(en). Leeg = het enkele tarief hierboven voor
|
|
13
|
+
* alles — het gedrag van vóór 7.20, dus bestaande winkels merken niets. Een zone ZONDER landen
|
|
14
|
+
* is de "overige landen"-zone; staat die er niet, dan verzendt de winkel alleen naar de landen
|
|
15
|
+
* die wél in een zone staan (en toont de checkout precies die keuze).
|
|
16
|
+
*/
|
|
17
|
+
shippingZones: z._default(z.array(z.object({
|
|
18
|
+
naam: z.string().check(z.minLength(1)).check(z.maxLength(60)),
|
|
19
|
+
landen: z._default(z.array(z.string().check(z.maxLength(2))).check(z.maxLength(60)), []),
|
|
20
|
+
flatCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1e5)), 0),
|
|
21
|
+
freeFromCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1e8)), 0)
|
|
22
|
+
})).check(z.maxLength(10)), []).register(z.globalRegistry, { description: "Verzendzones (tarief per land)" }),
|
|
11
23
|
orderPrefix: z._default(z.string().check(z.maxLength(12)), "ORDER").register(z.globalRegistry, { description: "Ordernummer-prefix" }),
|
|
12
24
|
/**
|
|
13
25
|
* Prefix van de FACTUURreeks (7.18). Leeg = dezelfde als het ordernummer. De factuurreeks is
|
|
@@ -21,7 +33,15 @@ const ShopSettingsSchema = z.object({
|
|
|
21
33
|
businessZip: z._default(z.string().check(z.maxLength(20)), "").register(z.globalRegistry, { description: "Postcode (factuur)" }),
|
|
22
34
|
businessCity: z._default(z.string().check(z.maxLength(120)), "").register(z.globalRegistry, { description: "Plaats (factuur)" }),
|
|
23
35
|
businessKvk: z._default(z.string().check(z.maxLength(20)), "").register(z.globalRegistry, { description: "KVK-nummer (factuur)" }),
|
|
24
|
-
businessBtw: z._default(z.string().check(z.maxLength(30)), "").register(z.globalRegistry, { description: "Btw-nummer (factuur)" })
|
|
36
|
+
businessBtw: z._default(z.string().check(z.maxLength(30)), "").register(z.globalRegistry, { description: "Btw-nummer (factuur)" }),
|
|
37
|
+
/**
|
|
38
|
+
* Contactgegevens in de mailfooter en op de factuur (7.21). `businessEmail` werd al door
|
|
39
|
+
* `mailLayout.ts` en `invoice.ts` UITGELEZEN, maar bestond nergens als instelling — een dood
|
|
40
|
+
* veld op drie plekken, waardoor de klant in zijn bestelbevestiging geen enkel adres zag om
|
|
41
|
+
* op te reageren.
|
|
42
|
+
*/
|
|
43
|
+
businessEmail: z._default(z.string().check(z.maxLength(200)), "").register(z.globalRegistry, { description: "Contact-e-mail (factuur + mailfooter)" }),
|
|
44
|
+
businessPhone: z._default(z.string().check(z.maxLength(40)), "").register(z.globalRegistry, { description: "Telefoon (factuur + mailfooter)" })
|
|
25
45
|
});
|
|
26
46
|
const defaultShopSettings = ShopSettingsSchema.parse({});
|
|
27
47
|
export {
|