@q2devel/q2-storybook 1.0.73 → 1.0.77
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/components/Ecommerce/product-detail/ProductDetail.js +31 -74
- package/dist/components/Ecommerce/product-detail/ProductDetailGallery.d.ts +16 -0
- package/dist/components/Ecommerce/product-detail/ProductDetailGallery.js +36 -0
- package/dist/components/Forms/dropdown/Dropdown.js +1 -1
- package/dist/components/Web/blog/BlogCard.d.ts +22 -0
- package/dist/components/Web/blog/BlogCard.js +35 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/style.css +1 -1
- package/package.json +2 -1
- package/dist/components/badge/Badge.d.ts +0 -11
- package/dist/components/badge/Badge.js +0 -4
- package/dist/components/banner/Banner.d.ts +0 -37
- package/dist/components/banner/Banner.js +0 -126
- package/dist/components/basket-dialog/BasketDialog.d.ts +0 -55
- package/dist/components/basket-dialog/BasketDialog.js +0 -101
- package/dist/components/button/Button.d.ts +0 -18
- package/dist/components/button/Button.js +0 -38
- package/dist/components/category-tree/CategoryTree.d.ts +0 -14
- package/dist/components/category-tree/CategoryTree.js +0 -55
- package/dist/components/heading/Heading.d.ts +0 -9
- package/dist/components/heading/Heading.js +0 -16
- package/dist/components/nav-bar/NavBar.d.ts +0 -19
- package/dist/components/nav-bar/NavBar.js +0 -17
- package/dist/components/product-card/ProductCard.d.ts +0 -66
- package/dist/components/product-card/ProductCard.js +0 -156
- package/dist/components/select-field/SelectField.d.ts +0 -29
- package/dist/components/select-field/SelectField.js +0 -142
- package/dist/components/select-field/SelectFieldOption.d.ts +0 -4
- package/dist/components/select-field/SelectFieldOption.js +0 -7
- package/dist/components/text-field/TextField.d.ts +0 -21
- package/dist/components/text-field/TextField.js +0 -57
- package/dist/components/text-with-image/ImageWithText.d.ts +0 -14
- package/dist/components/text-with-image/ImageWithText.js +0 -7
- package/dist/components/tooltip/Tooltip.d.ts +0 -18
- package/dist/components/tooltip/Tooltip.js +0 -18
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { Tab, TabGroup, TabList, TabPanel, TabPanels } from '@headlessui/react';
|
|
4
3
|
import { MinusIcon, PlusIcon } from '@heroicons/react/24/outline';
|
|
5
4
|
import { useRef, useState } from 'react';
|
|
6
5
|
import { formatPercentage, formatPriceForHTML, formatPriceString, } from '../../../utils/generalHelperFunction';
|
|
7
6
|
import { buildClassesByJoining } from '../../../utils/StyleHelper';
|
|
8
7
|
import Button from '../../Base/button/Button';
|
|
9
8
|
import Heading from '../../Base/heading/Heading';
|
|
10
|
-
import { ImageGalleryModal } from '../../Base/image-gallery-modal/ImageGalleryModal';
|
|
11
9
|
import { HorizontalTab } from '../../Web/tabs/HorizontalTab';
|
|
12
|
-
import LikeButton from '../wishlist/LikeButton';
|
|
13
10
|
import WishlistDropdown from '../wishlist/WishlistDropdown';
|
|
11
|
+
import ProductDetailGallery from './ProductDetailGallery';
|
|
14
12
|
export const ProductDetail = ({ name = '', price = 0, href = '', discountPercent = 0, description = '', detail = { tabs: [] }, buttonText = 'Add to bag', className = '',
|
|
15
13
|
// Cart props
|
|
16
14
|
product, currentQuantity = 0, onQuantityChange, maxQuantity = 99, disabled = false, badges = [], showVariations = false, variations = [], currentVariationId, cartMode = 'full', onOpenBasket,
|
|
@@ -21,17 +19,6 @@ showWishlistDropdown = false, onCloseWishlistDropdown, onAddToSpecificWishlist,
|
|
|
21
19
|
//modals
|
|
22
20
|
onShippingOptionsClick, isWatchdogEnabled = false, onWatchdogClick, onDemandClick, translations, locale, quantUnit, priceFormatOptions, }) => {
|
|
23
21
|
const wishlistButtonRef = useRef(null);
|
|
24
|
-
// Pridaj state pre galériu:
|
|
25
|
-
const [isGalleryOpen, setIsGalleryOpen] = useState(false);
|
|
26
|
-
const [galleryInitialIndex, setGalleryInitialIndex] = useState(0);
|
|
27
|
-
// Funkcie pre navigáciu
|
|
28
|
-
const openGallery = (imageIndex) => {
|
|
29
|
-
setGalleryInitialIndex(imageIndex);
|
|
30
|
-
setIsGalleryOpen(true);
|
|
31
|
-
};
|
|
32
|
-
const closeGallery = () => {
|
|
33
|
-
setIsGalleryOpen(false);
|
|
34
|
-
};
|
|
35
22
|
// Cart functions - updated logic based on cartMode
|
|
36
23
|
const shouldShowQuantityControls = () => {
|
|
37
24
|
if (cartMode === 'add-only') {
|
|
@@ -72,36 +59,6 @@ onShippingOptionsClick, isWatchdogEnabled = false, onWatchdogClick, onDemandClic
|
|
|
72
59
|
onQuantityChange(product, newQuantity);
|
|
73
60
|
}
|
|
74
61
|
};
|
|
75
|
-
// Wishlist callback wrappers
|
|
76
|
-
const handleWishlistToggleWrapper = () => {
|
|
77
|
-
if (onWishlistToggle && product) {
|
|
78
|
-
onWishlistToggle(product);
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
const handleAddToWishlistWrapper = (wishlistId) => (e) => {
|
|
82
|
-
e.stopPropagation();
|
|
83
|
-
if (onAddToWishlist && product) {
|
|
84
|
-
onAddToWishlist(product, wishlistId);
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
const handleRemoveFromWishlistWrapper = (wishlistId) => (e) => {
|
|
88
|
-
e.stopPropagation();
|
|
89
|
-
if (onRemoveFromWishlist && product) {
|
|
90
|
-
onRemoveFromWishlist(product, wishlistId);
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
const handleCreateNewWishlistWrapper = (e) => {
|
|
94
|
-
e.stopPropagation();
|
|
95
|
-
e.preventDefault();
|
|
96
|
-
if (onCreateWishlist && product) {
|
|
97
|
-
const form = e.target;
|
|
98
|
-
const formData = new FormData(form);
|
|
99
|
-
const name = formData.get('wishlistName');
|
|
100
|
-
if (name?.trim()) {
|
|
101
|
-
onCreateWishlist(name.trim(), product);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
62
|
const [showAll, setShowAll] = useState(false);
|
|
106
63
|
const sortedVariations = [...variations].sort((a, b) => {
|
|
107
64
|
if (a.id === currentVariationId)
|
|
@@ -126,34 +83,34 @@ onShippingOptionsClick, isWatchdogEnabled = false, onWatchdogClick, onDemandClic
|
|
|
126
83
|
priceFormatOptions?.numberClassName ||
|
|
127
84
|
priceFormatOptions?.currencyClassName ||
|
|
128
85
|
priceFormatOptions?.containerClassName;
|
|
129
|
-
return (
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
86
|
+
return (_jsx("div", { className: buildClassesByJoining('bg-white', className), children: _jsxs("div", { className: "py-4", children: [_jsxs("div", { className: "lg:grid lg:grid-cols-2 lg:items-start lg:gap-x-8 ", children: [_jsx(ProductDetailGallery, { product: product, showWishlistButton: showWishlistButton, enableMultipleWishlists: enableMultipleWishlists, isInWishlist: isInWishlist, wishlists: wishlists, productWishlistIds: productWishlistIds, isWishlistPending: isWishlistPending, onWishlistToggle: onWishlistToggle || (() => { }), onAddToWishlist: onAddToWishlist || (() => { }), onRemoveFromWishlist: onRemoveFromWishlist || (() => { }), onCreateWishlist: onCreateWishlist || (() => { }) }), _jsxs("div", { className: "mt-10 px-4 sm:mt-16 sm:px-0 lg:mt-0", children: [badges && badges.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-2", children: badges.map((badge, index) => (_jsx("span", { className: badge.color
|
|
87
|
+
? `${badge.color} inline-flex items-center px-2 py-1 text-xs font-medium text-w`
|
|
88
|
+
: 'bg-gray-200 text-gray-800 px-2 py-1 text-xs font-medium', children: badge.text }, index))) })), _jsx(Heading, { className: "mt-8 font-extralight", level: 1, children: name }), _jsxs("div", { className: "flex gap-4", children: [_jsxs("span", { className: "text-sm text-gray-500", children: ["K\u00F3d: ", product.sku] }), _jsxs("span", { className: "text-sm text-gray-500", children: ["EAN: ", product.ean] })] }), _jsxs("div", { className: "mt-6", children: [_jsx(Heading, { level: 3, className: "sr-only", children: "Description" }), _jsx("div", { dangerouslySetInnerHTML: { __html: description }, className: "space-y-6 text-base text-gray-700" })] }), _jsxs("form", { className: "mt-6", children: [showVariations && (_jsxs("div", { children: [_jsx(Heading, { level: 3, className: "text-gray-600 mb-2", children: "Variace" }), _jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-1 2xl:grid-cols-2 gap-3", children: visibleVariations.map((variation) => (_jsxs(Button, { asLink: true, unstyled: true, href: variation.href, "aria-label": variation.title, className: buildClassesByJoining('w-full border p-4 flex justify-between items-center shadow-sm', currentVariationId == variation.id
|
|
89
|
+
? 'border-[var(--primary)]'
|
|
90
|
+
: 'border-gray-200', 'cursor-pointer transition-all duration-150 hover:border-[var(--primary)] hover:shadow-md'), children: [_jsxs("div", { className: "flex flex-col justify-between gap-1", children: [_jsx("span", { className: "font-medium text-base capitalize", children: variation.title }), _jsx("span", { className: (variation.stock ?? 0) > 0
|
|
91
|
+
? 'text-green-600 text-sm'
|
|
92
|
+
: 'text-red-600 text-sm', children: (variation.stock ?? 0) > 0
|
|
93
|
+
? `Skladem: ${variation.stock ?? 0} ks`
|
|
94
|
+
: 'Není skladem' })] }), _jsxs("div", { className: "flex flex-col justify-center items-end text-right gap-1", children: [_jsxs("span", { className: "text-xs text-gray-500", children: ["K\u00F3d: ", variation.sku] }), _jsxs("span", { className: "text-xs text-gray-500", children: ["EAN: ", variation.ean] }), shouldUseHtml ? (_jsx("span", { className: "font-semibold text-lg", dangerouslySetInnerHTML: formatPriceForHTML(variation.price, locale, priceFormatOptions) })) : (_jsx("span", { className: "font-semibold text-lg", children: formatPriceString(variation.price, locale, priceFormatOptions) }))] })] }, variation.id))) }), sortedVariations.length > numberOfVisibleVariations && (_jsx("button", { type: "button", onClick: () => setShowAll(!showAll), className: "mt-3 text-sm font-medium text-green-700 hover:underline", children: showAll
|
|
95
|
+
? 'Zobrazit méně variant'
|
|
96
|
+
: 'Zobrazit více variant' }))] })), _jsxs("div", { className: "mt-3", children: [_jsx(Heading, { level: 2, className: "sr-only", children: "Product information" }), _jsxs("div", { children: [shouldUseHtml ? (_jsxs("span", { className: "flex items-baseline gap-1", children: [_jsx("div", { className: "text-3xl tracking-tight font-semibold text-[var(--primary)]", dangerouslySetInnerHTML: formatPriceForHTML(price, locale, priceFormatOptions) }), quantUnit && (_jsx("p", { className: "text-3xl tracking-tight font-semibold text-black", children: quantUnit }))] })) : (_jsxs("span", { className: "flex items-baseline gap-1", children: [_jsx("p", { className: "text-3xl tracking-tight font-semibold text-[var(--primary)]", children: formatPriceString(price, locale, priceFormatOptions) }), quantUnit && (_jsx("p", { className: "text-3xl tracking-tight font-semibold text-black", children: quantUnit }))] })), product?.discountPercent != null &&
|
|
97
|
+
product.discountPercent > 0 && (_jsxs("p", { className: "text-sm text-gray-500", children: [translations.recommendedPrice, ' ', shouldUseHtml ? (_jsx("span", { className: "font-bold", dangerouslySetInnerHTML: formatPriceForHTML(price /
|
|
98
|
+
(1 - product.discountPercent / 100), locale, priceFormatOptions) })) : (_jsx("span", { className: "font-bold", children: formatPriceString(price /
|
|
99
|
+
(1 - product.discountPercent / 100), locale, priceFormatOptions) })), ' ', _jsx("span", { className: "text-red-500", children: discountPercent
|
|
100
|
+
? formatPercentage(discountPercent)
|
|
101
|
+
: '' })] }))] })] }), _jsx("div", { className: "mt-10 flex justify-start", children: _jsxs("div", { className: "relative w-full", children: [_jsx("div", { className: buildClassesByJoining('transition-all duration-300 ease-in-out transform', shouldShowQuantityControls()
|
|
102
|
+
? 'scale-0 opacity-0'
|
|
103
|
+
: 'scale-100 opacity-100'), children: shouldShowAddButton() && (_jsx(Button, { onClick: handleAddToCart, disabled: disabled, rounded: "none", className: `button-brand ${disabled
|
|
104
|
+
? 'bg-accent cursor-not-allowed'
|
|
105
|
+
: 'bg-primary hover:bg-[var(--background)] hover:text-[var(--primary)] hover:shadow-lg'} px-8 py-3 text-base font-medium text-white focus:ring-2 focus:ring-[var(--primary)] focus:ring-offset-2 focus:outline-hidden`, children: buttonText })) }), _jsx("div", { className: buildClassesByJoining('absolute top-0 left-0 right-0 transition-all duration-300 ease-in-out transform', !shouldShowQuantityControls()
|
|
106
|
+
? 'scale-0 opacity-0'
|
|
107
|
+
: 'scale-100 opacity-100'), children: cartMode === 'full' && (_jsx("div", { className: "flex items-center justify-center px-4 py-3 w-full space-x-4", children: _jsxs("div", { className: "flex items-center space-x-2 lg:space-x-4", children: [_jsx("button", { type: "button", onClick: handleDecrement, disabled: currentQuantity <= 0 || disabled, className: `flex h-10 w-10 items-center justify-center rounded-full ${disabled
|
|
108
|
+
? 'bg-red-300 cursor-not-allowed'
|
|
109
|
+
: 'bg-red-500 hover:bg-red-600'} text-white disabled:opacity-50 disabled:bg-red-300 disabled:cursor-not-allowed shadow-sm transition-all duration-200`, "aria-label": "Zn\u00ED\u017Ei\u0165 mno\u017Estvo", children: _jsx(MinusIcon, { className: "h-5 w-5" }) }), _jsx("div", { className: "w-8 text-center text-xl font-semibold text-gray-900", children: currentQuantity }), _jsx("button", { type: "button", onClick: handleIncrement, disabled: currentQuantity >= maxQuantity ||
|
|
110
|
+
disabled, className: `flex h-10 w-10 items-center justify-center rounded-full ${disabled
|
|
111
|
+
? 'bg-black-300 cursor-not-allowed'
|
|
112
|
+
: 'bg-primary hover:bg-green-600'} text-white disabled:opacity-50 disabled:bg-black-300 disabled:cursor-not-allowed shadow-sm transition-all duration-200`, "aria-label": "Zv\u00FD\u0161i\u0165 mno\u017Estvo", children: _jsx(PlusIcon, { className: "h-5 w-5" }) })] }) })) })] }) })] }), _jsxs("section", { "aria-labelledby": "details-heading", className: "mt-8", children: [_jsx(Heading, { level: 2, id: "details-heading", className: "sr-only", children: "Additional details" }), _jsx("div", { className: "mt-3", children: price > 1000 ? (_jsx("p", { className: "text-sm text-gray-800", children: translations.shippingDetailFree })) : (_jsx("p", { className: "text-sm text-gray-800", children: translations.shippingDetailFee })) }), _jsx("div", { className: "mt-8", children: _jsxs("div", { className: "border-t py-5 border-gray-200 flex flex-col sm:flex-row flex-wrap gap-6 text-gray-600", children: [isWatchdogEnabled && (_jsxs(Button, { unstyled: true, className: "flex gap-2", onClick: onWatchdogClick, children: [_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, stroke: "currentColor", className: "size-5 text-[var(--primary)]", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 0 0 5.454-1.31A8.967 8.967 0 0 1 18 9.75V9A6 6 0 0 0 6 9v.75a8.967 8.967 0 0 1-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 0 1-5.714 0m5.714 0a3 3 0 1 1-5.714 0M3.124 7.5A8.969 8.969 0 0 1 5.292 3m13.416 0a8.969 8.969 0 0 1 2.168 4.5" }) }), _jsx("span", { className: "underline hover:no-underline", children: translations.watchDog })] })), _jsxs(Button, { unstyled: true, className: "flex gap-2", onClick: onDemandClick, children: [_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, stroke: "currentColor", className: "size-5 text-[var(--primary)]", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 5.25h.008v.008H12v-.008Z" }) }), _jsx("span", { className: "underline hover:no-underline", children: translations.question })] }), _jsxs(Button, { unstyled: true, className: "flex gap-2", onClick: onShippingOptionsClick, children: [_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, stroke: "currentColor", className: "size-5 text-[var(--primary)]", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 5.25h.008v.008H12v-.008Z" }) }), _jsx("span", { className: "underline hover:no-underline cursor-pointer", children: translations.optionOfShipping })] }), isLogged && (_jsxs("div", { className: "relative", children: [_jsxs("button", { ref: wishlistButtonRef, className: "flex gap-2 text-left hover:text-green-600 transition-colors", onClick: onWishlistTextClick, children: [_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, stroke: "currentColor", className: "size-5 text-[var(--primary)]", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 12h3.75M9 15h3.75M9 18h3.75m3 .75H18a2.25 2.25 0 0 0 2.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 0 0-1.123-.08m-5.801 0c-.065.21-.1.433-.1.664 0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75 2.25 2.25 0 0 0-.1-.664m-5.8 0A2.251 2.251 0 0 1 13.5 2.25H15c1.012 0 1.867.668 2.15 1.586m-5.8 0c-.376.023-.75.05-1.124.08C9.095 4.01 8.25 4.973 8.25 6.108V8.25m0 0H4.875c-.621 0-1.125.504-1.125 1.125v11.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V9.375c0-.621-.504-1.125-1.125-1.125H8.25ZM6.75 12h.008v.008H6.75V12Zm0 3h.008v.008H6.75V15Zm0 3h.008v.008H6.75V18Z" }) }), _jsx("span", { className: "underline hover:no-underline", children: translations.addToWishlist })] }), showWishlistDropdown && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40", onClick: onCloseWishlistDropdown }), _jsx("div", { className: "absolute top-full left-52 mt-1 z-50", children: _jsx(WishlistDropdown, { show: true, wishlists: wishlists || [], productWishlistIds: productWishlistIds || [], isWishlistPending: isWishlistPending, onAddToWishlist: onAddToSpecificWishlist ||
|
|
113
|
+
(() => { }), onRemoveFromWishlist: onRemoveFromSpecificWishlist ||
|
|
114
|
+
(() => { }), onCreateNewWishlist: onCreateNewWishlistFromDropdown ||
|
|
115
|
+
(() => { }), onClose: onCloseWishlistDropdown, isModal: false }) })] }))] }))] }) })] })] })] }), _jsx("section", { className: "mt-10", children: _jsx(HorizontalTab, { ...detail }) })] }) }));
|
|
159
116
|
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Product } from '@q2devel/q2-core';
|
|
2
|
+
type ProductDetailGalleryProps = {
|
|
3
|
+
product: Product;
|
|
4
|
+
showWishlistButton: boolean;
|
|
5
|
+
enableMultipleWishlists: boolean;
|
|
6
|
+
isInWishlist: boolean;
|
|
7
|
+
wishlists: any;
|
|
8
|
+
productWishlistIds: string[];
|
|
9
|
+
isWishlistPending: boolean;
|
|
10
|
+
onWishlistToggle: (product: Product) => void;
|
|
11
|
+
onAddToWishlist: (product: Product, wishlistId: string) => void;
|
|
12
|
+
onRemoveFromWishlist: (product: Product, wishlistId: string) => void;
|
|
13
|
+
onCreateWishlist: (name: string, product: Product) => void;
|
|
14
|
+
};
|
|
15
|
+
declare const ProductDetailGallery: ({ product, showWishlistButton, enableMultipleWishlists, isInWishlist, wishlists, productWishlistIds, isWishlistPending, onWishlistToggle, onAddToWishlist, onRemoveFromWishlist, onCreateWishlist, }: ProductDetailGalleryProps) => import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export default ProductDetailGallery;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Tab, TabGroup, TabList, TabPanel, TabPanels } from '@headlessui/react';
|
|
4
|
+
import { ImageGalleryModal } from '../../Base/image-gallery-modal/ImageGalleryModal';
|
|
5
|
+
import LikeButton from '../wishlist/LikeButton';
|
|
6
|
+
const ProductDetailGallery = ({ product, showWishlistButton, enableMultipleWishlists, isInWishlist, wishlists, productWishlistIds, isWishlistPending, onWishlistToggle, onAddToWishlist, onRemoveFromWishlist, onCreateWishlist, }) => {
|
|
7
|
+
// State pre modálnu galériu
|
|
8
|
+
const [isGalleryOpen, setIsGalleryOpen] = useState(false);
|
|
9
|
+
const [galleryInitialIndex, setGalleryInitialIndex] = useState(0);
|
|
10
|
+
const openGallery = (index) => {
|
|
11
|
+
setGalleryInitialIndex(index);
|
|
12
|
+
setIsGalleryOpen(true);
|
|
13
|
+
};
|
|
14
|
+
const closeGallery = () => setIsGalleryOpen(false);
|
|
15
|
+
// Wishlist callback wrappers
|
|
16
|
+
const handleWishlistToggle = () => onWishlistToggle(product);
|
|
17
|
+
const handleAddToWishlist = (wishlistId) => (e) => {
|
|
18
|
+
e.stopPropagation();
|
|
19
|
+
onAddToWishlist(product, wishlistId);
|
|
20
|
+
};
|
|
21
|
+
const handleRemoveFromWishlist = (wishlistId) => (e) => {
|
|
22
|
+
e.stopPropagation();
|
|
23
|
+
onRemoveFromWishlist(product, wishlistId);
|
|
24
|
+
};
|
|
25
|
+
const handleCreateNewWishlist = (e) => {
|
|
26
|
+
e.preventDefault();
|
|
27
|
+
e.stopPropagation();
|
|
28
|
+
const form = e.target;
|
|
29
|
+
const name = new FormData(form).get('wishlistName')?.trim();
|
|
30
|
+
if (name) {
|
|
31
|
+
onCreateWishlist(name, product);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
return (_jsxs(_Fragment, { children: [_jsxs(TabGroup, { className: "flex flex-col-reverse items-center", children: [_jsx("div", { className: "mx-auto mt-6 hidden w-full max-w-2xl sm:block lg:max-w-none", children: _jsx(TabList, { className: "grid grid-cols-4 gap-6", children: product.variation_images.map((image, i) => (_jsxs(Tab, { className: "group relative flex h-24 cursor-pointer items-center justify-center bg-white text-sm font-medium text-gray-900 uppercase hover:bg-gray-50 focus:ring-3 focus:ring-[var(--primary)]/50 focus:ring-offset-4 focus:outline-hidden", children: [_jsx("span", { className: "sr-only", children: image.alt }), _jsx("span", { className: "absolute inset-0 overflow-hidden", children: _jsx("img", { src: image.href, alt: "", className: "size-full object-contain" }) }), _jsx("span", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 ring-2 ring-transparent ring-offset-2 group-data-selected:ring-[var(--primary)]" })] }, i))) }) }), _jsxs(TabPanels, { className: "relative w-full", children: [product.variation_images.map((image, i) => (_jsx(TabPanel, { className: "relative", children: _jsx("img", { src: image.href, alt: image.alt, className: "aspect-[7/5] w-full object-contain border-1 border-gray-200 cursor-pointer hover:opacity-90 transition-opacity", onClick: () => openGallery(i) }) }, i))), showWishlistButton && (_jsx("div", { className: "absolute top-3 right-3 z-10", children: _jsx(LikeButton, { show: true, enableMultiple: enableMultipleWishlists, isInWishlist: isInWishlist, wishlists: wishlists, productWishlistIds: productWishlistIds, isWishlistPending: isWishlistPending, handleAddToWishlist: handleAddToWishlist, handleRemoveFromWishlist: handleRemoveFromWishlist, handleCreateNewWishlist: handleCreateNewWishlist, handleWishlistToggle: handleWishlistToggle, wishlistButtonClassName: "bg-white/90 backdrop-blur-sm border border-gray-200 shadow-lg hover:shadow-xl" }) }))] })] }), _jsx(ImageGalleryModal, { images: product.variation_images, isOpen: isGalleryOpen, initialIndex: galleryInitialIndex, onClose: closeGallery })] }));
|
|
35
|
+
};
|
|
36
|
+
export default ProductDetailGallery;
|
|
@@ -9,5 +9,5 @@ export default function Dropdown({ name = '', options, onSelect, selectedId = ''
|
|
|
9
9
|
const handleSelect = (option) => {
|
|
10
10
|
onSelect(option.id);
|
|
11
11
|
};
|
|
12
|
-
return (_jsxs(Menu, { as: "div", className: "relative inline-block text-left z-
|
|
12
|
+
return (_jsxs(Menu, { as: "div", className: "relative inline-block text-left z-40", children: [_jsx("div", { children: _jsxs(MenuButton, { className: buildClassesByJoining('inline-flex w-full justify-center gap-x-1.5 rounded-md bg-white px-3 py-2 text-sm font-normal text-gray-900 shadow-xs ring-1 ring-gray-300 ring-inset hover:bg-gray-50', buttonClassName), children: [buttonLabel, _jsx(ChevronDownIcon, { "aria-hidden": "true", className: "-mr-1 size-5 text-gray-400" })] }) }), _jsx(MenuItems, { className: buildClassesByJoining('absolute right-0 z-10 mt-2 w-56 origin-top-right rounded-md bg-white shadow-lg ring-1 ring-black/5 focus:outline-none', menuClassName), children: _jsx("div", { className: "py-1", children: options.map((option) => (_jsx(MenuItem, { children: ({ active }) => (_jsx("button", { onClick: () => handleSelect(option), className: buildClassesByJoining('block w-full text-left px-4 py-2 text-sm', active ? 'bg-gray-100 text-gray-900' : 'text-gray-700', itemClassName), children: option.label })) }, option.id))) }) })] }));
|
|
13
13
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BlogItem } from '@q2devel/q2-core';
|
|
2
|
+
type BlogCardProps = {
|
|
3
|
+
post: BlogItem;
|
|
4
|
+
variant?: 'imageOverlay' | 'imageTop';
|
|
5
|
+
fallbackBackgroundColor?: string;
|
|
6
|
+
textHorizontal?: 'left' | 'center' | 'right';
|
|
7
|
+
textVertical?: 'top' | 'center' | 'bottom';
|
|
8
|
+
buttonText?: string;
|
|
9
|
+
showSeparator?: boolean;
|
|
10
|
+
bodyLimit?: number;
|
|
11
|
+
href?: string;
|
|
12
|
+
className?: {
|
|
13
|
+
article?: string;
|
|
14
|
+
image?: string;
|
|
15
|
+
heading?: string;
|
|
16
|
+
button?: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
separator?: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
declare const BlogCard: ({ post, variant, fallbackBackgroundColor, textHorizontal, textVertical, buttonText, showSeparator, bodyLimit, href, className, }: BlogCardProps) => import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export default BlogCard;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import Heading from '../../Base/heading/Heading';
|
|
3
|
+
import Button from '../../Base/button/Button';
|
|
4
|
+
import clsx from 'clsx';
|
|
5
|
+
const stripHtmlTags = (html) => {
|
|
6
|
+
return html.replace(/<\/?[^>]+(>|$)/g, '');
|
|
7
|
+
};
|
|
8
|
+
const truncateText = (text, limit) => {
|
|
9
|
+
return text.length > limit ? text.slice(0, limit).trim() + '…' : text;
|
|
10
|
+
};
|
|
11
|
+
const BlogCard = ({ post, variant = 'imageOverlay', fallbackBackgroundColor = 'bg-gray-200', textHorizontal = 'center', textVertical = 'center', buttonText = 'Více informací', showSeparator = true, bodyLimit = 150, href, className = {}, }) => {
|
|
12
|
+
const { article = '', image = '', heading = '', button = '', description = '', separator = '', } = className;
|
|
13
|
+
const hasImage = Boolean(post.field_image_url);
|
|
14
|
+
const finalHref = href || post.href;
|
|
15
|
+
const cleanBody = post.body ? stripHtmlTags(post.body) : '';
|
|
16
|
+
const limitedBody = bodyLimit ? truncateText(cleanBody, bodyLimit) : cleanBody;
|
|
17
|
+
const horizontalAlignments = {
|
|
18
|
+
left: 'items-start text-left',
|
|
19
|
+
center: 'items-center text-center',
|
|
20
|
+
right: 'items-end text-right',
|
|
21
|
+
};
|
|
22
|
+
const verticalAlignments = {
|
|
23
|
+
top: 'justify-start',
|
|
24
|
+
center: 'justify-center',
|
|
25
|
+
bottom: 'justify-end',
|
|
26
|
+
};
|
|
27
|
+
if (variant === 'imageTop') {
|
|
28
|
+
return (_jsxs("article", { className: clsx('bg-white shadow-sm rounded overflow-hidden', article), children: [hasImage ? (_jsx("img", { alt: post.title, src: post.field_image_url, className: clsx('w-full h-48 object-cover', image) })) : (_jsx("div", { className: clsx('w-full h-48 flex items-center justify-center', fallbackBackgroundColor), children: _jsx("span", { className: "text-gray-600 text-center px-4 text-sm font-medium", children: post.title }) })), _jsxs("div", { className: "p-4", children: [_jsx(Heading, { level: 3, className: clsx('text-black font-semibold mb-2', heading), children: post.title }), limitedBody && (_jsx("p", { className: clsx('text-gray-600 text-sm mb-4', description), children: limitedBody })), showSeparator && _jsx("hr", { className: clsx('my-4', separator) }), _jsx(Button, { asLink: true, unstyled: true, href: finalHref, className: clsx('text-sm font-medium', button), children: buttonText })] })] }));
|
|
29
|
+
}
|
|
30
|
+
// imageOverlay variant
|
|
31
|
+
return (_jsx("article", { className: clsx('relative isolate overflow-hidden flex flex-col', hasImage
|
|
32
|
+
? 'px-8 pt-8 pb-8 bg-gray-900 h-[320px]'
|
|
33
|
+
: `h-80 ${fallbackBackgroundColor}`, article), children: hasImage ? (_jsxs(_Fragment, { children: [_jsx("img", { alt: post.title, src: post.field_image_url, className: clsx('absolute inset-0 -z-10 w-full h-full object-cover', image) }), _jsx("div", { className: "absolute inset-0 -z-10 bg-gradient-to-t from-gray-900 via-gray-900/40" }), _jsx("div", { className: "absolute inset-0 -z-10 ring-1 ring-gray-900/10 ring-inset" }), _jsx("div", { className: clsx('flex flex-1 flex-col', verticalAlignments[textVertical], horizontalAlignments[textHorizontal]), children: _jsx(Heading, { level: 3, className: clsx('font-extralight text-white', heading), children: _jsxs(Button, { asLink: true, unstyled: true, href: finalHref, className: clsx(button), children: [_jsx("span", { className: "absolute inset-0" }), post.title] }) }) })] })) : (_jsx("div", { className: clsx('flex flex-1 flex-col px-8', verticalAlignments[textVertical], horizontalAlignments[textHorizontal]), children: _jsx(Heading, { level: 3, className: clsx('text-gray-800 font-medium', heading), children: _jsx(Button, { asLink: true, unstyled: true, href: finalHref, className: clsx(button), children: post.title }) }) })) }));
|
|
34
|
+
};
|
|
35
|
+
export default BlogCard;
|
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export { default as ImageWithText } from "./components/Web/text-with-image/Image
|
|
|
22
22
|
export { default as Heading } from "./components/Base/heading/Heading";
|
|
23
23
|
export { default as CategoryTree } from "./components/Ecommerce/category-tree/CategoryTree";
|
|
24
24
|
export { default as Spinner } from "./components/Base/spinner/Spinner";
|
|
25
|
+
export { default as BlogCard } from "./components/Web/blog/BlogCard";
|
|
25
26
|
export { Breadcrumb, BreadcrumbProps, } from "./components/Web/breadcrumb/Breadcrumb";
|
|
26
27
|
export { HorizontalTab, HorizontalTabProps, TabData, } from "./components/Web/tabs/HorizontalTab";
|
|
27
28
|
export { Faq } from "./components/Web/faq/FaqSection";
|
package/dist/index.js
CHANGED
|
@@ -25,6 +25,7 @@ export { default as ImageWithText } from "./components/Web/text-with-image/Image
|
|
|
25
25
|
export { default as Heading } from "./components/Base/heading/Heading";
|
|
26
26
|
export { default as CategoryTree } from "./components/Ecommerce/category-tree/CategoryTree";
|
|
27
27
|
export { default as Spinner } from "./components/Base/spinner/Spinner";
|
|
28
|
+
export { default as BlogCard } from "./components/Web/blog/BlogCard";
|
|
28
29
|
export { Breadcrumb, } from "./components/Web/breadcrumb/Breadcrumb";
|
|
29
30
|
export { HorizontalTab, } from "./components/Web/tabs/HorizontalTab";
|
|
30
31
|
export { Faq } from "./components/Web/faq/FaqSection";
|