@q2devel/q2-storybook 1.0.1 → 1.0.2
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.
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type NavItem = {
|
|
3
|
+
name: string;
|
|
4
|
+
href: string;
|
|
5
|
+
};
|
|
6
|
+
export type NavBarProps = {
|
|
7
|
+
items?: NavItem[];
|
|
8
|
+
logo?: React.ReactNode;
|
|
9
|
+
rightContent?: React.ReactNode;
|
|
10
|
+
backgroundColor?: string;
|
|
11
|
+
textColor?: string;
|
|
12
|
+
activeColor?: string;
|
|
13
|
+
mobileMenuBgColor?: string;
|
|
14
|
+
containerClassName?: string;
|
|
15
|
+
navClassName?: string;
|
|
16
|
+
itemClassName?: string;
|
|
17
|
+
mobileItemClassName?: string;
|
|
18
|
+
};
|
|
19
|
+
export declare const NavBar: ({ items, logo, rightContent, backgroundColor, textColor, activeColor, mobileMenuBgColor, containerClassName, navClassName, itemClassName, mobileItemClassName }: NavBarProps) => React.JSX.Element;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
export var NavBar = function (_a) {
|
|
6
|
+
var
|
|
7
|
+
// Structure
|
|
8
|
+
_b = _a.items,
|
|
9
|
+
// Structure
|
|
10
|
+
items = _b === void 0 ? [] : _b,
|
|
11
|
+
// Logo
|
|
12
|
+
_c = _a.logo,
|
|
13
|
+
// Logo
|
|
14
|
+
logo = _c === void 0 ? React.createElement("div", { className: "h-8 w-8 bg-indigo-600 rounded-md" }) : _c,
|
|
15
|
+
// Right side elements
|
|
16
|
+
rightContent = _a.rightContent,
|
|
17
|
+
// Styling
|
|
18
|
+
_d = _a.backgroundColor,
|
|
19
|
+
// Styling
|
|
20
|
+
backgroundColor = _d === void 0 ? "bg-white" : _d, _e = _a.textColor, textColor = _e === void 0 ? "text-gray-600" : _e, _f = _a.activeColor, activeColor = _f === void 0 ? "text-indigo-600" : _f, _g = _a.mobileMenuBgColor, mobileMenuBgColor = _g === void 0 ? "bg-white" : _g, _h = _a.containerClassName, containerClassName = _h === void 0 ? "" : _h, _j = _a.navClassName, navClassName = _j === void 0 ? "" : _j, _k = _a.itemClassName, itemClassName = _k === void 0 ? "" : _k, _l = _a.mobileItemClassName, mobileItemClassName = _l === void 0 ? "" : _l;
|
|
21
|
+
var _m = useState(false), mobileMenuOpen = _m[0], setMobileMenuOpen = _m[1];
|
|
22
|
+
return (React.createElement("header", { className: "".concat(backgroundColor, " ").concat(containerClassName) },
|
|
23
|
+
React.createElement("nav", { className: "mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 ".concat(navClassName) },
|
|
24
|
+
React.createElement("div", { className: "flex h-16 items-center justify-between" },
|
|
25
|
+
React.createElement("div", { className: "flex-shrink-0" }, logo),
|
|
26
|
+
React.createElement("div", { className: "flex md:hidden" },
|
|
27
|
+
React.createElement("button", { type: "button", className: "inline-flex items-center justify-center rounded-md p-2 ".concat(textColor, " hover:").concat(activeColor, " hover:bg-gray-100"), onClick: function () { return setMobileMenuOpen(!mobileMenuOpen); } },
|
|
28
|
+
React.createElement("span", { className: "sr-only" }, "Open main menu"),
|
|
29
|
+
mobileMenuOpen ? (React.createElement(XMarkIcon, { className: "block h-6 w-6", "aria-hidden": "true" })) : (React.createElement(Bars3Icon, { className: "block h-6 w-6", "aria-hidden": "true" })))),
|
|
30
|
+
React.createElement("div", { className: "hidden md:flex md:flex-1 md:items-center md:justify-center md:space-x-8" }, items.map(function (item) { return (React.createElement("a", { key: item.name, href: item.href, className: "text-sm font-medium ".concat(textColor, " hover:").concat(activeColor, " ").concat(itemClassName) }, item.name)); })),
|
|
31
|
+
rightContent && (React.createElement("div", { className: "hidden md:flex md:items-center" }, rightContent)))),
|
|
32
|
+
mobileMenuOpen && (React.createElement("div", { className: "md:hidden ".concat(mobileMenuBgColor) },
|
|
33
|
+
React.createElement("div", { className: "space-y-1 px-2 pb-3 pt-2" }, items.map(function (item) { return (React.createElement("a", { key: item.name, href: item.href, className: "block rounded-md px-3 py-2 text-base font-medium ".concat(textColor, " hover:").concat(activeColor, " hover:bg-gray-100 ").concat(mobileItemClassName) }, item.name)); })),
|
|
34
|
+
rightContent && (React.createElement("div", { className: "border-t border-gray-200 pb-3 pt-4" },
|
|
35
|
+
React.createElement("div", { className: "flex items-center px-5" }, rightContent)))))));
|
|
36
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type Product = {
|
|
3
|
+
id: string;
|
|
4
|
+
imageSrc: string;
|
|
5
|
+
imageAlt: string;
|
|
6
|
+
href: string;
|
|
7
|
+
name: string;
|
|
8
|
+
color?: string;
|
|
9
|
+
price: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
badges?: Array<{
|
|
12
|
+
text: string;
|
|
13
|
+
color: string;
|
|
14
|
+
}>;
|
|
15
|
+
};
|
|
16
|
+
export type QuantityControlProps = {
|
|
17
|
+
quantity: number;
|
|
18
|
+
onIncrement: (e: React.MouseEvent) => void;
|
|
19
|
+
onDecrement: (e: React.MouseEvent) => void;
|
|
20
|
+
minQuantity?: number;
|
|
21
|
+
maxQuantity?: number;
|
|
22
|
+
controlsClassName?: string;
|
|
23
|
+
buttonClassName?: string;
|
|
24
|
+
quantityClassName?: string;
|
|
25
|
+
};
|
|
26
|
+
export type ProductCardProps = {
|
|
27
|
+
product: Product;
|
|
28
|
+
className?: string;
|
|
29
|
+
imageClassName?: string;
|
|
30
|
+
contentClassName?: string;
|
|
31
|
+
titleClassName?: string;
|
|
32
|
+
colorClassName?: string;
|
|
33
|
+
priceClassName?: string;
|
|
34
|
+
descriptionClassName?: string;
|
|
35
|
+
badgeClassName?: string;
|
|
36
|
+
aspectRatio?: 'square' | 'auto' | 'video' | 'wide';
|
|
37
|
+
imagePosition?: 'top' | 'bottom' | 'center';
|
|
38
|
+
imageObjectFit?: 'cover' | 'contain' | 'fill' | 'none';
|
|
39
|
+
layout?: 'default' | 'compact' | 'horizontal';
|
|
40
|
+
hoverEffect?: 'opacity' | 'scale' | 'shadow' | 'border' | 'none';
|
|
41
|
+
renderBadges?: boolean;
|
|
42
|
+
renderColor?: boolean;
|
|
43
|
+
renderDescription?: boolean;
|
|
44
|
+
elevationLevel?: 0 | 1 | 2 | 3;
|
|
45
|
+
rounded?: 'none' | 'sm' | 'md' | 'lg' | 'full';
|
|
46
|
+
titleLines?: 1 | 2 | 3;
|
|
47
|
+
onCardClick?: (product: Product) => void;
|
|
48
|
+
onImageClick?: (product: Product) => void;
|
|
49
|
+
renderFooter?: (product: Product) => React.ReactNode;
|
|
50
|
+
renderHeader?: (product: Product) => React.ReactNode;
|
|
51
|
+
actionButton?: React.ReactNode;
|
|
52
|
+
showAddButton?: boolean;
|
|
53
|
+
initialQuantity?: number;
|
|
54
|
+
onQuantityChange?: (product: Product, quantity: number) => void;
|
|
55
|
+
addButtonIcon?: React.ReactNode;
|
|
56
|
+
maxQuantity?: number;
|
|
57
|
+
quantityControlProps?: Partial<QuantityControlProps>;
|
|
58
|
+
customAddButton?: React.ReactNode;
|
|
59
|
+
customQuantityControl?: React.ReactNode;
|
|
60
|
+
};
|
|
61
|
+
export declare const ProductCard: ({ product, className, imageClassName, contentClassName, titleClassName, colorClassName, priceClassName, descriptionClassName, badgeClassName, aspectRatio, imagePosition, imageObjectFit, layout, hoverEffect, renderBadges, renderColor, renderDescription, elevationLevel, rounded, titleLines, onCardClick, onImageClick, renderFooter, renderHeader, actionButton, showAddButton, initialQuantity, onQuantityChange, addButtonIcon, maxQuantity, quantityControlProps, customAddButton, customQuantityControl, }: ProductCardProps) => React.JSX.Element;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
import { MinusIcon, PlusIcon } from '@heroicons/react/24/solid';
|
|
13
|
+
import React, { useState } from 'react';
|
|
14
|
+
import { buildClassesByJoining } from '../../utils/StyleHelper';
|
|
15
|
+
// Quantity Control Component
|
|
16
|
+
var QuantityControl = function (_a) {
|
|
17
|
+
var quantity = _a.quantity, onIncrement = _a.onIncrement, onDecrement = _a.onDecrement, _b = _a.minQuantity, minQuantity = _b === void 0 ? 0 : _b, _c = _a.maxQuantity, maxQuantity = _c === void 0 ? 99 : _c, _d = _a.controlsClassName, controlsClassName = _d === void 0 ? '' : _d, _e = _a.buttonClassName, buttonClassName = _e === void 0 ? '' : _e, _f = _a.quantityClassName, quantityClassName = _f === void 0 ? '' : _f;
|
|
18
|
+
return (React.createElement("div", { className: "flex items-center gap-2 ".concat(controlsClassName) },
|
|
19
|
+
React.createElement("button", { onClick: onDecrement, disabled: quantity <= minQuantity, className: "w-8 h-8 flex items-center justify-center rounded-full bg-red-500 text-white hover:bg-red-600 disabled:opacity-50 disabled:bg-red-300 disabled:cursor-not-allowed shadow-sm transition-all duration-200 ".concat(buttonClassName), "aria-label": "Decrease quantity" },
|
|
20
|
+
React.createElement(MinusIcon, { className: "h-4 w-4" })),
|
|
21
|
+
React.createElement("div", { className: "w-8 h-8 rounded-full bg-white flex items-center justify-center text-sm font-medium shadow-sm transition-all duration-200 ".concat(quantityClassName) }, quantity),
|
|
22
|
+
React.createElement("button", { onClick: onIncrement, disabled: quantity >= maxQuantity, className: "w-8 h-8 flex items-center justify-center rounded-full bg-green-500 text-white hover:bg-green-600 disabled:opacity-50 disabled:bg-green-300 disabled:cursor-not-allowed shadow-sm transition-all duration-200 ".concat(buttonClassName), "aria-label": "Increase quantity" },
|
|
23
|
+
React.createElement(PlusIcon, { className: "h-4 w-4" }))));
|
|
24
|
+
};
|
|
25
|
+
export var ProductCard = function (_a) {
|
|
26
|
+
var product = _a.product, className = _a.className, imageClassName = _a.imageClassName, contentClassName = _a.contentClassName, titleClassName = _a.titleClassName, colorClassName = _a.colorClassName, priceClassName = _a.priceClassName, descriptionClassName = _a.descriptionClassName, badgeClassName = _a.badgeClassName, _b = _a.aspectRatio, aspectRatio = _b === void 0 ? 'square' : _b, _c = _a.imagePosition, imagePosition = _c === void 0 ? 'center' : _c, _d = _a.imageObjectFit, imageObjectFit = _d === void 0 ? 'cover' : _d, _e = _a.layout, layout = _e === void 0 ? 'default' : _e, _f = _a.hoverEffect, hoverEffect = _f === void 0 ? 'opacity' : _f, _g = _a.renderBadges, renderBadges = _g === void 0 ? true : _g, _h = _a.renderColor, renderColor = _h === void 0 ? true : _h, _j = _a.renderDescription, renderDescription = _j === void 0 ? false : _j, _k = _a.elevationLevel, elevationLevel = _k === void 0 ? 0 : _k, _l = _a.rounded, rounded = _l === void 0 ? 'md' : _l, _m = _a.titleLines, titleLines = _m === void 0 ? 1 : _m, onCardClick = _a.onCardClick, onImageClick = _a.onImageClick, renderFooter = _a.renderFooter, renderHeader = _a.renderHeader, actionButton = _a.actionButton,
|
|
27
|
+
// Add to cart functionality
|
|
28
|
+
_o = _a.showAddButton,
|
|
29
|
+
// Add to cart functionality
|
|
30
|
+
showAddButton = _o === void 0 ? false : _o, _p = _a.initialQuantity, initialQuantity = _p === void 0 ? 0 : _p, onQuantityChange = _a.onQuantityChange, _q = _a.addButtonIcon, addButtonIcon = _q === void 0 ? React.createElement(PlusIcon, { className: "h-4 w-4" }) : _q, _r = _a.maxQuantity, maxQuantity = _r === void 0 ? 99 : _r, _s = _a.quantityControlProps, quantityControlProps = _s === void 0 ? {} : _s, customAddButton = _a.customAddButton, customQuantityControl = _a.customQuantityControl;
|
|
31
|
+
var _t = useState(initialQuantity), quantity = _t[0], setQuantity = _t[1];
|
|
32
|
+
var _u = useState(initialQuantity > 0), showQuantityControls = _u[0], setShowQuantityControls = _u[1];
|
|
33
|
+
// Create aspect ratio class
|
|
34
|
+
var aspectRatioClass = {
|
|
35
|
+
square: 'aspect-square',
|
|
36
|
+
auto: 'aspect-auto',
|
|
37
|
+
video: 'aspect-video',
|
|
38
|
+
wide: 'aspect-[16/9]',
|
|
39
|
+
}[aspectRatio];
|
|
40
|
+
// Create object-fit class
|
|
41
|
+
var objectFitClass = {
|
|
42
|
+
cover: 'object-cover',
|
|
43
|
+
contain: 'object-contain',
|
|
44
|
+
fill: 'object-fill',
|
|
45
|
+
none: 'object-none',
|
|
46
|
+
}[imageObjectFit];
|
|
47
|
+
// Create object-position class
|
|
48
|
+
var objectPositionClass = {
|
|
49
|
+
top: 'object-top',
|
|
50
|
+
center: 'object-center',
|
|
51
|
+
bottom: 'object-bottom',
|
|
52
|
+
}[imagePosition];
|
|
53
|
+
// Create hover effect class
|
|
54
|
+
var hoverClass = {
|
|
55
|
+
opacity: 'group-hover:opacity-75',
|
|
56
|
+
scale: 'transform transition-transform group-hover:scale-105',
|
|
57
|
+
shadow: 'transition-shadow group-hover:shadow-lg',
|
|
58
|
+
border: 'border border-transparent group-hover:border-primary-500',
|
|
59
|
+
none: '',
|
|
60
|
+
}[hoverEffect];
|
|
61
|
+
// Create shadow elevation class
|
|
62
|
+
var elevationClass = {
|
|
63
|
+
0: '',
|
|
64
|
+
1: 'shadow-sm',
|
|
65
|
+
2: 'shadow',
|
|
66
|
+
3: 'shadow-md',
|
|
67
|
+
}[elevationLevel];
|
|
68
|
+
// Create rounded class
|
|
69
|
+
var roundedClass = {
|
|
70
|
+
none: 'rounded-none',
|
|
71
|
+
sm: 'rounded-sm',
|
|
72
|
+
md: 'rounded-md',
|
|
73
|
+
lg: 'rounded-lg',
|
|
74
|
+
full: 'rounded-full',
|
|
75
|
+
}[rounded];
|
|
76
|
+
// Create title line clamp class
|
|
77
|
+
var titleLineClampClass = {
|
|
78
|
+
1: 'line-clamp-1',
|
|
79
|
+
2: 'line-clamp-2',
|
|
80
|
+
3: 'line-clamp-3',
|
|
81
|
+
}[titleLines];
|
|
82
|
+
// Create layout class
|
|
83
|
+
var layoutClass = layout === 'horizontal' ? 'flex gap-4' : '';
|
|
84
|
+
var imageLayoutClass = layout === 'horizontal' ? 'w-1/3' : 'w-full';
|
|
85
|
+
var contentLayoutClass = layout === 'horizontal' ? 'w-2/3' : 'w-full';
|
|
86
|
+
var compactClass = layout === 'compact' ? 'space-y-1' : 'space-y-2';
|
|
87
|
+
var handleCardClick = function () {
|
|
88
|
+
onCardClick && onCardClick(product);
|
|
89
|
+
};
|
|
90
|
+
var handleImageClick = function (e) {
|
|
91
|
+
if (onImageClick) {
|
|
92
|
+
e.stopPropagation();
|
|
93
|
+
onImageClick(product);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
var handleAddToCart = function (e) {
|
|
97
|
+
e.stopPropagation(); // Prevent card click
|
|
98
|
+
setShowQuantityControls(true);
|
|
99
|
+
setQuantity(1);
|
|
100
|
+
onQuantityChange && onQuantityChange(product, 1);
|
|
101
|
+
};
|
|
102
|
+
var handleIncrement = function (e) {
|
|
103
|
+
e.stopPropagation(); // Prevent card click
|
|
104
|
+
var newQuantity = Math.min(quantity + 1, maxQuantity);
|
|
105
|
+
setQuantity(newQuantity);
|
|
106
|
+
onQuantityChange && onQuantityChange(product, newQuantity);
|
|
107
|
+
};
|
|
108
|
+
var handleDecrement = function (e) {
|
|
109
|
+
e.stopPropagation(); // Prevent card click
|
|
110
|
+
var newQuantity = Math.max(quantity - 1, 0);
|
|
111
|
+
if (newQuantity === 0) {
|
|
112
|
+
setQuantity(0);
|
|
113
|
+
// Use timeout to allow animation to play before hiding
|
|
114
|
+
setTimeout(function () {
|
|
115
|
+
setShowQuantityControls(false);
|
|
116
|
+
}, 300);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
setQuantity(newQuantity);
|
|
120
|
+
}
|
|
121
|
+
onQuantityChange && onQuantityChange(product, newQuantity);
|
|
122
|
+
};
|
|
123
|
+
return (React.createElement("div", { key: product.id, className: buildClassesByJoining('group relative', layoutClass, elevationClass, onCardClick ? 'cursor-pointer' : '', className), onClick: handleCardClick },
|
|
124
|
+
renderHeader && renderHeader(product),
|
|
125
|
+
React.createElement("div", { className: "".concat(imageLayoutClass, " relative") },
|
|
126
|
+
product.badges && renderBadges && (React.createElement("div", { className: "absolute top-2 left-2 z-10 flex flex-wrap gap-1" }, product.badges.map(function (badge, index) { return (React.createElement("span", { key: index, className: buildClassesByJoining("inline-flex items-center px-2 py-1 text-xs font-medium ".concat(badge.color), roundedClass, badgeClassName) }, badge.text)); }))),
|
|
127
|
+
React.createElement("img", { alt: product.imageAlt, src: product.imageSrc, className: buildClassesByJoining(aspectRatioClass, objectFitClass, objectPositionClass, hoverEffect !== 'none' ? hoverClass : '', roundedClass, 'bg-gray-200', onImageClick ? 'cursor-pointer' : '', imageClassName), onClick: handleImageClick }),
|
|
128
|
+
(showAddButton || showQuantityControls) && (React.createElement("div", { className: "absolute bottom-2 right-2 z-10", onClick: function (e) { return e.stopPropagation(); } },
|
|
129
|
+
React.createElement("div", { className: "relative" },
|
|
130
|
+
React.createElement("div", { className: "transition-all duration-300 ease-in-out transform\n ".concat(showQuantityControls
|
|
131
|
+
? 'scale-0 opacity-0'
|
|
132
|
+
: 'scale-100 opacity-100') }, customAddButton || (React.createElement("button", { onClick: handleAddToCart, className: "p-2 w-10 h-10 flex items-center justify-center rounded-full bg-green-500 text-white shadow-md hover:bg-green-600 transition-colors duration-200", "aria-label": "Add to cart" }, addButtonIcon))),
|
|
133
|
+
React.createElement("div", { className: "absolute top-0 right-0 transition-all duration-300 ease-in-out transform origin-right\n ".concat(!showQuantityControls
|
|
134
|
+
? 'scale-0 opacity-0'
|
|
135
|
+
: 'scale-100 opacity-100') }, customQuantityControl || (React.createElement(QuantityControl, __assign({ quantity: quantity, onIncrement: handleIncrement, onDecrement: handleDecrement, minQuantity: 0, maxQuantity: maxQuantity }, quantityControlProps)))))))),
|
|
136
|
+
React.createElement("div", { className: buildClassesByJoining('mt-4', contentLayoutClass, compactClass, contentClassName) },
|
|
137
|
+
React.createElement("div", { className: "flex justify-between" },
|
|
138
|
+
React.createElement("div", null,
|
|
139
|
+
React.createElement("h3", { className: buildClassesByJoining('text-sm text-gray-700', titleLineClampClass, titleClassName) },
|
|
140
|
+
React.createElement("a", { href: product.href },
|
|
141
|
+
!onCardClick && (React.createElement("span", { "aria-hidden": "true", className: "absolute inset-0" })),
|
|
142
|
+
product.name)),
|
|
143
|
+
renderColor && product.color && (React.createElement("p", { className: buildClassesByJoining('mt-1 text-sm text-gray-500', colorClassName) }, product.color)),
|
|
144
|
+
renderDescription && product.description && (React.createElement("p", { className: buildClassesByJoining('mt-1 text-sm text-gray-500 line-clamp-2', descriptionClassName) }, product.description))),
|
|
145
|
+
React.createElement("p", { className: buildClassesByJoining('text-sm font-medium text-gray-900', priceClassName) }, product.price)),
|
|
146
|
+
actionButton && React.createElement("div", { className: "mt-2" }, actionButton),
|
|
147
|
+
renderFooter && renderFooter(product))));
|
|
148
|
+
};
|