@js-empire/emperor-ui 1.2.3 → 1.2.4

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.
Files changed (157) hide show
  1. package/.cursor/rules/code-conventions.mdc +50 -0
  2. package/README.md +0 -15
  3. package/dist/emperor-ui.js +119 -71
  4. package/dist/emperor-ui.umd.cjs +27 -13
  5. package/dist/globals.css +1 -1
  6. package/dist/index-BXtdEByK.js +5 -0
  7. package/dist/index-CDB93OLO.js +55965 -0
  8. package/dist/index-CYORMghp.js +290 -0
  9. package/dist/index.d.ts +334 -33
  10. package/dist/src-UW24ZMRV-C1Pn8-w8.js +5 -0
  11. package/package.json +32 -2
  12. package/src/animations/blink.ts +26 -0
  13. package/src/animations/floating.ts +12 -0
  14. package/src/animations/index.ts +2 -0
  15. package/src/components/atoms/brand/brand.tsx +1 -1
  16. package/src/components/atoms/color-picker/color-picker.tsx +13 -0
  17. package/src/components/atoms/color-picker/free-color-picker.tsx +60 -0
  18. package/src/components/atoms/color-picker/index.ts +3 -0
  19. package/src/components/atoms/color-picker/preset-color-picker.tsx +64 -0
  20. package/src/components/atoms/color-picker/stories/color-picker.stories.tsx +49 -0
  21. package/src/components/atoms/color-picker/styles/color-picker.css +23 -0
  22. package/src/components/atoms/copy-button/copy-button.tsx +73 -0
  23. package/src/components/atoms/copy-button/index.ts +1 -0
  24. package/src/components/atoms/copy-button/stories/copy-button.stories.tsx +21 -0
  25. package/src/components/atoms/field/field.stories.tsx +27 -0
  26. package/src/components/atoms/field/field.tsx +11 -0
  27. package/src/components/atoms/field/index.ts +1 -0
  28. package/src/components/atoms/field/styles/classes.ts +9 -0
  29. package/src/components/atoms/field/styles/index.ts +1 -0
  30. package/src/components/atoms/filter/filter.tsx +92 -0
  31. package/src/components/atoms/filter/index.ts +3 -0
  32. package/src/components/atoms/filter/stories/filter.stories.tsx +97 -0
  33. package/src/components/atoms/filter/styles/classes.ts +20 -0
  34. package/src/components/atoms/filter/styles/index.ts +1 -0
  35. package/src/components/atoms/filter/units/autocomplete-filter.tsx +39 -0
  36. package/src/components/atoms/filter/units/checkbox-filter.tsx +32 -0
  37. package/src/components/atoms/filter/units/checkbox-group-filter.tsx +37 -0
  38. package/src/components/atoms/filter/units/date-filter.tsx +50 -0
  39. package/src/components/atoms/filter/units/index.ts +9 -0
  40. package/src/components/atoms/filter/units/numeric-filter.tsx +36 -0
  41. package/src/components/atoms/filter/units/range-filter.tsx +36 -0
  42. package/src/components/atoms/filter/units/search-filter.tsx +52 -0
  43. package/src/components/atoms/filter/units/select-filter.tsx +49 -0
  44. package/src/components/atoms/filter/units/switch-filter.tsx +33 -0
  45. package/src/components/atoms/index.ts +5 -0
  46. package/src/components/atoms/theme-switch/index.ts +1 -0
  47. package/src/components/atoms/theme-switch/styles/classes.ts +16 -0
  48. package/src/components/atoms/theme-switch/styles/index.ts +1 -0
  49. package/src/components/atoms/theme-switch/theme-switch.stories.tsx +26 -0
  50. package/src/components/atoms/theme-switch/theme-switch.tsx +54 -0
  51. package/src/components/atoms/uploader/avatar-label.tsx +3 -1
  52. package/src/components/atoms/uploader/stories/uploader.stories.tsx +1 -1
  53. package/src/components/atoms/uploader/upload-file-error-box.tsx +1 -1
  54. package/src/components/atoms/uploader/upload-file-input.tsx +1 -1
  55. package/src/components/atoms/uploader/upload-file-label.tsx +2 -1
  56. package/src/components/atoms/uploader/upload-file-listing.tsx +2 -1
  57. package/src/components/atoms/uploader/view-image-modal.tsx +2 -1
  58. package/src/components/molecules/index.ts +0 -1
  59. package/src/components/molecules/item-card/index.ts +6 -0
  60. package/src/components/molecules/item-card/item-actions-dropdown.tsx +57 -0
  61. package/src/components/molecules/item-card/item-banner.tsx +22 -0
  62. package/src/components/molecules/item-card/item-card-body.tsx +68 -0
  63. package/src/components/molecules/item-card/item-card-footer.tsx +55 -0
  64. package/src/components/molecules/item-card/item-card-header.tsx +61 -0
  65. package/src/components/molecules/item-card/item-card.tsx +83 -3
  66. package/src/components/molecules/item-card/loading-item.tsx +88 -0
  67. package/src/components/molecules/item-card/stories/item-card.stories.tsx +182 -0
  68. package/src/components/molecules/item-card/styles/classes.ts +138 -0
  69. package/src/components/molecules/item-card/styles/index.ts +1 -0
  70. package/src/components/molecules/nav-bar/sub-items-box.tsx +2 -1
  71. package/src/components/molecules/scaffold/index.ts +1 -0
  72. package/src/components/molecules/scaffold/scaffold.tsx +4 -17
  73. package/src/components/molecules/scaffold/styles/index.ts +1 -0
  74. package/src/components/molecules/scaffold/styles/scaffold-classes.ts +10 -0
  75. package/src/components/molecules/side-bar/compact-side-bar.tsx +3 -1
  76. package/src/components/molecules/side-bar/side-bar-drawer.tsx +6 -17
  77. package/src/components/molecules/side-bar/side-bar.stories.tsx +1 -1
  78. package/src/components/organisms/filters/filters.stories.tsx +32 -0
  79. package/src/components/organisms/filters/filters.tsx +36 -0
  80. package/src/components/organisms/filters/index.ts +1 -0
  81. package/src/components/organisms/filters/styles/classes.ts +9 -0
  82. package/src/components/organisms/filters/styles/index.ts +1 -0
  83. package/src/components/organisms/footer/copy-rights-box.tsx +1 -1
  84. package/src/components/organisms/footer/footer.tsx +1 -1
  85. package/src/components/organisms/footer/policies-box.tsx +2 -1
  86. package/src/components/organisms/footer/quick-links-box.tsx +2 -1
  87. package/src/components/organisms/footer/social-links-box.tsx +2 -1
  88. package/src/components/organisms/footer/stories/footer.stories.tsx +1 -1
  89. package/src/components/organisms/header/header.tsx +1 -8
  90. package/src/components/organisms/index.ts +1 -0
  91. package/src/components/organisms/listings/empty-listings.tsx +80 -0
  92. package/src/components/organisms/listings/index.ts +2 -0
  93. package/src/components/organisms/listings/listings.tsx +90 -9
  94. package/src/components/organisms/listings/stories/grid-listings.stories.tsx +153 -0
  95. package/src/components/organisms/listings/stories/list-listings.stories.tsx +171 -0
  96. package/src/components/organisms/listings/styles/classes.ts +41 -3
  97. package/src/constants/animations.ts +14 -0
  98. package/src/constants/card.tsx +26 -0
  99. package/src/constants/defaults.ts +1 -16
  100. package/src/constants/index.ts +2 -0
  101. package/src/hooks/index.ts +3 -0
  102. package/src/hooks/use-filters.ts +20 -0
  103. package/src/hooks/use-search-params-handler.tsx +186 -0
  104. package/src/hooks/use-uploader.tsx +1 -1
  105. package/src/hooks/use-window-size.tsx +53 -0
  106. package/src/i18n/locales/atoms/ar.ts +3 -0
  107. package/src/i18n/locales/atoms/en.ts +3 -0
  108. package/src/i18n/locales/organisms/ar.ts +7 -1
  109. package/src/i18n/locales/organisms/en.ts +7 -1
  110. package/src/mocks/constants.ts +103 -0
  111. package/src/mocks/index.ts +2 -0
  112. package/src/mocks/listings.tsx +154 -0
  113. package/src/mocks/types.ts +64 -0
  114. package/src/providers/config-provider.tsx +0 -8
  115. package/src/providers/emperor-ui-provider.tsx +16 -5
  116. package/src/providers/index.ts +1 -0
  117. package/src/providers/theme-provider.tsx +16 -0
  118. package/src/providers/uploader-provider.tsx +1 -1
  119. package/src/styles/hero.ts +1 -1
  120. package/src/styles/index.css +23 -0
  121. package/src/types/components/atoms/color-picker/color-picker.ts +12 -0
  122. package/src/types/components/atoms/color-picker/index.ts +1 -0
  123. package/src/types/components/atoms/field/field.ts +9 -0
  124. package/src/types/components/atoms/field/index.ts +1 -0
  125. package/src/types/components/atoms/filter/filter.ts +43 -0
  126. package/src/types/components/atoms/filter/index.ts +2 -0
  127. package/src/types/components/atoms/filter/select-filter.ts +8 -0
  128. package/src/types/components/atoms/index.ts +3 -0
  129. package/src/types/components/atoms/uploader.ts +1 -1
  130. package/src/types/components/index.ts +1 -0
  131. package/src/types/components/molecules/index.ts +1 -1
  132. package/src/types/components/molecules/item-card/item-card.ts +50 -0
  133. package/src/types/components/molecules/listings/listings.ts +21 -5
  134. package/src/types/components/molecules/side-bar/side-bar.ts +1 -1
  135. package/src/types/components/molecules/theme-switch/index.ts +1 -0
  136. package/src/types/components/molecules/theme-switch/theme-switch.ts +9 -0
  137. package/src/types/components/organisms/filters/filters.ts +11 -0
  138. package/src/types/components/organisms/filters/index.ts +1 -0
  139. package/src/types/components/organisms/index.ts +1 -0
  140. package/src/types/context/config.ts +3 -4
  141. package/src/types/context/index.ts +0 -1
  142. package/src/types/context/localization.ts +1 -0
  143. package/src/types/shared/components.ts +3 -0
  144. package/src/utils/uploader.ts +1 -1
  145. package/dist/features-animation-w9dWMd15.js +0 -1938
  146. package/dist/index-BY47HgaP.js +0 -26533
  147. package/dist/index-CN4cJ1N7.js +0 -1630
  148. package/dist/index-Cr1mc-d4.js +0 -5
  149. package/dist/src-UW24ZMRV-nsR4cpiy.js +0 -5
  150. package/src/components/molecules/filter/filter.tsx +0 -6
  151. package/src/components/molecules/filter/index.ts +0 -1
  152. package/src/components/organisms/listings/stories/listings.stories.tsx +0 -30
  153. package/src/main.tsx +0 -3
  154. package/src/mocks/listings.ts +0 -200
  155. package/src/types/components/molecules/filter/filter.ts +0 -9
  156. package/src/types/components/molecules/filter/index.ts +0 -1
  157. package/src/types/context/theme.ts +0 -17
@@ -0,0 +1,68 @@
1
+ "use client";
2
+
3
+ import type { ItemCardProps } from "@/types";
4
+ import { cn } from "@/utils";
5
+ import {
6
+ itemBodyClasses,
7
+ itemDescriptionClasses,
8
+ itemPriceClasses,
9
+ itemTitleClasses,
10
+ } from "./styles";
11
+ import { CardBody } from "@heroui/card";
12
+ import { ItemActionsDropdown } from "./item-actions-dropdown";
13
+
14
+ export function ItemCardBody({
15
+ item,
16
+ orientation,
17
+ classNames,
18
+ actions,
19
+ onActionClick,
20
+ }: Pick<
21
+ ItemCardProps,
22
+ "item" | "orientation" | "classNames" | "actions" | "onActionClick"
23
+ >) {
24
+ return (
25
+ <CardBody
26
+ data-slot="emperor-ui-item-card-body"
27
+ className={cn(itemBodyClasses({ orientation }), classNames?.body)}
28
+ >
29
+ {item?.title && (
30
+ <h3
31
+ data-slot="emperor-ui-item-card-title"
32
+ className={cn(itemTitleClasses({ orientation }), classNames?.title)}
33
+ >
34
+ {item?.title}
35
+ </h3>
36
+ )}
37
+
38
+ {item?.description && (
39
+ <p
40
+ data-slot="emperor-ui-item-card-description"
41
+ className={cn(
42
+ itemDescriptionClasses({ orientation }),
43
+ classNames?.description,
44
+ )}
45
+ >
46
+ {item?.description}
47
+ </p>
48
+ )}
49
+
50
+ {item?.price && (
51
+ <p
52
+ data-slot="emperor-ui-item-card-price"
53
+ className={cn(itemPriceClasses({ orientation }), classNames?.price)}
54
+ >
55
+ {item?.price}
56
+ </p>
57
+ )}
58
+
59
+ {orientation === "horizontal" && (
60
+ <ItemActionsDropdown
61
+ actions={actions}
62
+ classNames={classNames}
63
+ onActionClick={onActionClick}
64
+ />
65
+ )}
66
+ </CardBody>
67
+ );
68
+ }
@@ -0,0 +1,55 @@
1
+ "use client";
2
+
3
+ import type { ItemCardProps } from "@/types";
4
+ import { cn } from "@/utils";
5
+ import { itemFooterClasses, itemChipsClasses } from "./styles";
6
+ import { CardFooter } from "@heroui/card";
7
+ import { Chip } from "@heroui/chip";
8
+
9
+ export function ItemCardFooter({
10
+ item,
11
+ orientation,
12
+ classNames,
13
+ }: Pick<ItemCardProps, "item" | "orientation" | "classNames">) {
14
+ return (
15
+ <CardFooter
16
+ data-slot="emperor-ui-item-card-footer"
17
+ className={cn(itemFooterClasses({ orientation }), classNames?.footer)}
18
+ >
19
+ {item?.chips && item?.chips?.length > 0 && (
20
+ <menu
21
+ data-slot="emperor-ui-item-card-chips"
22
+ className={cn(itemChipsClasses({ orientation }), classNames?.chips)}
23
+ >
24
+ {item?.chips?.map(
25
+ (
26
+ {
27
+ label,
28
+ className: chipClassName,
29
+ classNames: chipClassNames,
30
+ ...props
31
+ },
32
+ index,
33
+ ) => (
34
+ <Chip
35
+ key={index}
36
+ data-slot="emperor-ui-item-card-chip"
37
+ className={cn(chipClassName, classNames?.chip)}
38
+ classNames={{
39
+ content: "text-xs mx-1",
40
+ ...chipClassNames,
41
+ }}
42
+ size="sm"
43
+ variant="flat"
44
+ color="primary"
45
+ {...props}
46
+ >
47
+ {label}
48
+ </Chip>
49
+ ),
50
+ )}
51
+ </menu>
52
+ )}
53
+ </CardFooter>
54
+ );
55
+ }
@@ -0,0 +1,61 @@
1
+ "use client";
2
+
3
+ import { CardHeader } from "@heroui/card";
4
+ import { cn } from "@/utils";
5
+ import { itemHeaderClasses } from "./styles";
6
+ import { itemImageWrapperClasses } from "./styles";
7
+ import { Image } from "@heroui/image";
8
+ import { ItemBanner } from "@/components";
9
+ import { ItemActionsDropdown } from "./item-actions-dropdown";
10
+ import type { ItemCardProps } from "@/types";
11
+
12
+ export function ItemCardHeader({
13
+ item,
14
+ orientation,
15
+ classNames,
16
+ actions,
17
+ onActionClick,
18
+ }: Pick<
19
+ ItemCardProps,
20
+ "item" | "orientation" | "classNames" | "actions" | "onActionClick"
21
+ >) {
22
+ return (
23
+ <CardHeader
24
+ data-slot="emperor-ui-item-card-header"
25
+ className={cn(itemHeaderClasses({ orientation }), classNames?.header)}
26
+ >
27
+ {item?.image && (
28
+ <div
29
+ data-slot="emperor-ui-item-card-image-wrapper"
30
+ className={cn(
31
+ itemImageWrapperClasses({ orientation }),
32
+ classNames?.imageWrapper,
33
+ )}
34
+ >
35
+ <Image
36
+ data-slot="emperor-ui-item-card-image"
37
+ src={item?.image?.src}
38
+ alt={item?.image?.alt}
39
+ className={cn("size-full object-cover", classNames?.image)}
40
+ radius="none"
41
+ removeWrapper
42
+ />
43
+ </div>
44
+ )}
45
+
46
+ <ItemBanner
47
+ item={item}
48
+ orientation={orientation}
49
+ classNames={classNames}
50
+ />
51
+
52
+ {orientation === "vertical" && (
53
+ <ItemActionsDropdown
54
+ actions={actions}
55
+ classNames={classNames}
56
+ onActionClick={onActionClick}
57
+ />
58
+ )}
59
+ </CardHeader>
60
+ );
61
+ }
@@ -1,6 +1,86 @@
1
- import type { ItemCardProps } from "@/types";
1
+ "use client";
2
+
3
+ import type { ItemCardOrientation, ItemCardProps } from "@/types";
2
4
  import { cn } from "@/utils";
5
+ import { Card } from "@heroui/card";
6
+ import { motion } from "framer-motion";
7
+ import { itemMainWrapperClasses, itemCardMotionClasses } from "./styles";
8
+ import { getCardMotion } from "@/constants";
9
+ import {
10
+ LoadingItem,
11
+ ItemCardHeader,
12
+ ItemCardBody,
13
+ ItemCardFooter,
14
+ } from "@/components";
15
+ import { useWindowSize } from "@/hooks";
16
+
17
+ export function ItemCard({
18
+ variants,
19
+ isLoading = false,
20
+ className,
21
+ classNames,
22
+ item,
23
+ actions = [],
24
+ hoverEffect = "none",
25
+ onActionClick,
26
+ orientation: defaultOrientation = "vertical",
27
+ }: ItemCardProps) {
28
+ const { isExtraSmallDevice } = useWindowSize();
29
+
30
+ const orientation: ItemCardOrientation = isExtraSmallDevice
31
+ ? "vertical"
32
+ : defaultOrientation;
33
+
34
+ if (isLoading)
35
+ return (
36
+ <LoadingItem
37
+ className={className}
38
+ classNames={classNames}
39
+ orientation={orientation}
40
+ />
41
+ );
42
+
43
+ return (
44
+ <motion.div
45
+ data-slot="emperor-ui-item-card"
46
+ className={cn(
47
+ itemCardMotionClasses({ orientation }),
48
+ classNames?.base,
49
+ className,
50
+ )}
51
+ variants={variants}
52
+ {...getCardMotion({ hoverEffect })}
53
+ >
54
+ <Card
55
+ shadow="sm"
56
+ data-slot="emperor-ui-item-card-main-wrapper"
57
+ className={cn(
58
+ itemMainWrapperClasses({ orientation }),
59
+ classNames?.mainWrapper,
60
+ )}
61
+ >
62
+ <ItemCardHeader
63
+ item={item}
64
+ orientation={orientation}
65
+ classNames={classNames}
66
+ actions={actions}
67
+ onActionClick={onActionClick}
68
+ />
69
+
70
+ <ItemCardBody
71
+ item={item}
72
+ orientation={orientation}
73
+ classNames={classNames}
74
+ actions={actions}
75
+ onActionClick={onActionClick}
76
+ />
3
77
 
4
- export function ItemCard({ className }: ItemCardProps) {
5
- return <div className={cn("", className)}>Item Card Component</div>;
78
+ <ItemCardFooter
79
+ item={item}
80
+ orientation={orientation}
81
+ classNames={classNames}
82
+ />
83
+ </Card>
84
+ </motion.div>
85
+ );
6
86
  }
@@ -0,0 +1,88 @@
1
+ "use client";
2
+
3
+ import { cn } from "@/utils";
4
+ import { Card, CardBody, CardFooter, CardHeader } from "@heroui/card";
5
+ import { Skeleton } from "@heroui/skeleton";
6
+ import { motion } from "framer-motion";
7
+ import {
8
+ itemMainWrapperClasses,
9
+ itemCardMotionClasses,
10
+ itemImageWrapperClasses,
11
+ itemHeaderClasses,
12
+ itemBodyClasses,
13
+ itemFooterClasses,
14
+ itemChipsClasses,
15
+ } from "./styles";
16
+ import { getCardMotion } from "@/constants";
17
+ import type { ItemCardProps } from "@/types";
18
+
19
+ export function LoadingItem({
20
+ className,
21
+ classNames,
22
+ hoverEffect = "none",
23
+ orientation = "vertical",
24
+ }: Pick<
25
+ ItemCardProps,
26
+ "className" | "classNames" | "hoverEffect" | "orientation"
27
+ >) {
28
+ return (
29
+ <motion.div
30
+ {...getCardMotion({ hoverEffect })}
31
+ data-slot="emperor-ui-item-card"
32
+ className={cn(
33
+ itemCardMotionClasses({ orientation }),
34
+ classNames?.base,
35
+ className,
36
+ )}
37
+ >
38
+ <Card
39
+ shadow="sm"
40
+ data-slot="emperor-ui-item-card-main-wrapper"
41
+ className={cn(
42
+ itemMainWrapperClasses({ orientation }),
43
+ classNames?.mainWrapper,
44
+ )}
45
+ >
46
+ <CardHeader
47
+ data-slot="emperor-ui-item-card-header"
48
+ className={cn(itemHeaderClasses({ orientation }), classNames?.header)}
49
+ >
50
+ <Skeleton
51
+ className={cn(
52
+ itemImageWrapperClasses({ orientation }),
53
+ classNames?.imageWrapper,
54
+ )}
55
+ />
56
+ </CardHeader>
57
+
58
+ <CardBody
59
+ data-slot="emperor-ui-item-card-body"
60
+ className={cn(itemBodyClasses({ orientation }), classNames?.body)}
61
+ >
62
+ <div className="flex items-start justify-between gap-2">
63
+ <Skeleton className="h-5 flex-1 rounded-lg" />
64
+ <Skeleton className="size-8 shrink-0 rounded-lg" />
65
+ </div>
66
+
67
+ <Skeleton className="h-4 w-4/5 rounded-lg" />
68
+ <Skeleton className="h-4 w-full rounded-lg" />
69
+ </CardBody>
70
+
71
+ <CardFooter
72
+ data-slot="emperor-ui-item-card-footer"
73
+ className={cn(itemFooterClasses({ orientation }), classNames?.footer)}
74
+ >
75
+ <menu
76
+ data-slot="emperor-ui-item-card-chips"
77
+ className={cn(itemChipsClasses({ orientation }), classNames?.chips)}
78
+ >
79
+ {" "}
80
+ <Skeleton className="h-6 w-16 rounded-full" />
81
+ <Skeleton className="h-6 w-20 rounded-full" />
82
+ <Skeleton className="h-6 w-14 rounded-full" />
83
+ </menu>
84
+ </CardFooter>
85
+ </Card>
86
+ </motion.div>
87
+ );
88
+ }
@@ -0,0 +1,182 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { ItemCard } from "@/components";
3
+ import { getStorybookDecorators } from "@/utils";
4
+ import { getListing, MOCK_LISTINGS } from "@/mocks";
5
+ import type { MockItemType } from "@/mocks";
6
+ import { useEffect, useState } from "storybook/internal/preview-api";
7
+ import { ItemCardProps } from "@/types";
8
+ import { ITEM_CARD_ACTIONS } from "@/constants";
9
+
10
+ const meta: Meta<typeof ItemCard> = {
11
+ title: "Molecules/Item Card",
12
+ component: ItemCard,
13
+ parameters: {
14
+ layout: "centered",
15
+ },
16
+ tags: ["autodocs"],
17
+ decorators: getStorybookDecorators({
18
+ config: {
19
+ layout: {
20
+ withScaffold: false,
21
+ },
22
+ },
23
+ }),
24
+ };
25
+
26
+ export default meta;
27
+
28
+ type Story = StoryObj<typeof meta>;
29
+
30
+ export const Default: Story = {
31
+ args: {
32
+ item: {
33
+ key: String(MOCK_LISTINGS[0]?.id),
34
+ title: MOCK_LISTINGS[0]?.title,
35
+ description: MOCK_LISTINGS[0]?.description,
36
+ image: {
37
+ src: MOCK_LISTINGS[0]?.image || "",
38
+ alt: MOCK_LISTINGS[0]?.title || "",
39
+ },
40
+ },
41
+ },
42
+ };
43
+
44
+ export const WithLoading: Story = {
45
+ args: {},
46
+ render: () => {
47
+ const [item, setItem] = useState<MockItemType | null | undefined>(null);
48
+ const [isLoading, setIsLoading] = useState(true);
49
+
50
+ useEffect(() => {
51
+ (async () => {
52
+ const { item } = await getListing();
53
+
54
+ setItem(item);
55
+ setIsLoading(false);
56
+ })();
57
+ }, []);
58
+
59
+ return (
60
+ <ItemCard
61
+ isLoading={isLoading}
62
+ item={{
63
+ key: String(item?.id),
64
+ title: item?.title,
65
+ description: item?.description,
66
+ image: { src: item?.image || "", alt: item?.title || "" },
67
+ }}
68
+ />
69
+ );
70
+ },
71
+ };
72
+
73
+ export const WithHorizontalLoading: Story = {
74
+ args: {
75
+ orientation: "horizontal",
76
+ },
77
+ render: (args: ItemCardProps) => {
78
+ const [item, setItem] = useState<MockItemType | null | undefined>(null);
79
+ const [isLoading, setIsLoading] = useState(true);
80
+
81
+ useEffect(() => {
82
+ (async () => {
83
+ const { item } = await getListing();
84
+
85
+ setItem(item);
86
+ setIsLoading(false);
87
+ })();
88
+ }, []);
89
+
90
+ return (
91
+ <ItemCard
92
+ {...args}
93
+ isLoading={isLoading}
94
+ item={{
95
+ key: String(item?.id),
96
+ title: item?.title,
97
+ description: item?.description,
98
+ image: { src: item?.image || "", alt: item?.title || "" },
99
+ }}
100
+ />
101
+ );
102
+ },
103
+ };
104
+
105
+ export const WithActions: Story = {
106
+ args: {
107
+ item: {
108
+ key: String(MOCK_LISTINGS[0]?.id),
109
+ title: MOCK_LISTINGS[0]?.title,
110
+ description: MOCK_LISTINGS[0]?.description,
111
+ image: {
112
+ src: MOCK_LISTINGS[0]?.image || "",
113
+ alt: MOCK_LISTINGS[0]?.title || "",
114
+ },
115
+ },
116
+ actions: ITEM_CARD_ACTIONS,
117
+ },
118
+ };
119
+
120
+ export const WithChips: Story = {
121
+ args: {
122
+ item: {
123
+ key: String(MOCK_LISTINGS[2]?.id),
124
+ title: MOCK_LISTINGS[2]?.title,
125
+ description: MOCK_LISTINGS[2]?.description,
126
+ image: {
127
+ src: MOCK_LISTINGS[2]?.image || "",
128
+ alt: MOCK_LISTINGS[2]?.title || "",
129
+ },
130
+ chips: MOCK_LISTINGS[2]?.categories,
131
+ },
132
+ },
133
+ };
134
+
135
+ export const WithBanner: Story = {
136
+ args: {
137
+ item: {
138
+ key: String(MOCK_LISTINGS[0]?.id),
139
+ title: MOCK_LISTINGS[0]?.title,
140
+ description: MOCK_LISTINGS[0]?.description,
141
+ image: {
142
+ src: MOCK_LISTINGS[0]?.image || "",
143
+ alt: MOCK_LISTINGS[0]?.title || "",
144
+ },
145
+ banner: MOCK_LISTINGS[0]?.isBestSeller ? "Best Seller" : undefined,
146
+ },
147
+ },
148
+ };
149
+
150
+ export const WithPrice: Story = {
151
+ args: {
152
+ item: {
153
+ key: String(MOCK_LISTINGS[0]?.id),
154
+ title: MOCK_LISTINGS[0]?.title,
155
+ description: MOCK_LISTINGS[0]?.description,
156
+ price: `$ ${MOCK_LISTINGS[0]?.price}`,
157
+ image: {
158
+ src: MOCK_LISTINGS[0]?.image || "",
159
+ alt: MOCK_LISTINGS[0]?.title || "",
160
+ },
161
+ },
162
+ },
163
+ };
164
+
165
+ export const Horizontal: Story = {
166
+ args: {
167
+ orientation: "horizontal",
168
+ actions: ITEM_CARD_ACTIONS,
169
+ item: {
170
+ key: String(MOCK_LISTINGS[0]?.id),
171
+ title: MOCK_LISTINGS[0]?.title,
172
+ description: MOCK_LISTINGS[0]?.description,
173
+ image: {
174
+ src: MOCK_LISTINGS[0]?.image || "",
175
+ alt: MOCK_LISTINGS[0]?.title || "",
176
+ },
177
+ banner: MOCK_LISTINGS[0]?.isBestSeller ? "Best Seller" : undefined,
178
+ chips: MOCK_LISTINGS[0]?.categories,
179
+ price: `$ ${MOCK_LISTINGS[0]?.price}`,
180
+ },
181
+ },
182
+ };
@@ -0,0 +1,138 @@
1
+ import { cva } from "class-variance-authority";
2
+
3
+ export const itemCardMotionClasses = cva(["w-full relative"], {
4
+ variants: {
5
+ orientation: {
6
+ vertical: "max-w-80",
7
+ horizontal: "min-w-full max-w-full",
8
+ },
9
+ },
10
+ defaultVariants: {},
11
+ compoundVariants: [],
12
+ });
13
+
14
+ export const itemMainWrapperClasses = cva(["size-full"], {
15
+ variants: {
16
+ orientation: {
17
+ vertical: "flex flex-col",
18
+ horizontal: "grid grid-cols-[200px_auto]",
19
+ },
20
+ },
21
+ defaultVariants: {},
22
+ compoundVariants: [],
23
+ });
24
+
25
+ export const itemImageWrapperClasses = cva(
26
+ ["relative aspect-4/3 overflow-hidden"],
27
+ {
28
+ variants: {
29
+ orientation: {
30
+ vertical: "w-full",
31
+ horizontal: "w-fit h-full",
32
+ },
33
+ },
34
+ defaultVariants: {},
35
+ compoundVariants: [],
36
+ },
37
+ );
38
+
39
+ export const itemHeaderClasses = cva(["relative p-0"], {
40
+ variants: {
41
+ orientation: {
42
+ vertical: "",
43
+ horizontal: "row-span-2",
44
+ },
45
+ },
46
+ defaultVariants: {},
47
+ compoundVariants: [],
48
+ });
49
+
50
+ export const itemBodyClasses = cva(["relative flex flex-col gap-2 p-4"], {
51
+ variants: {
52
+ orientation: {
53
+ vertical: "",
54
+ horizontal: "",
55
+ },
56
+ },
57
+ defaultVariants: {},
58
+ compoundVariants: [],
59
+ });
60
+
61
+ export const itemFooterClasses = cva(["flex items-center p-4"], {
62
+ variants: {
63
+ orientation: {
64
+ vertical: "",
65
+ horizontal: "justify-end",
66
+ },
67
+ },
68
+ defaultVariants: {},
69
+ compoundVariants: [],
70
+ });
71
+
72
+ export const itemTitleClasses = cva(
73
+ ["line-clamp-1 font-semibold text-foreground"],
74
+ {
75
+ variants: {
76
+ orientation: {
77
+ vertical: "",
78
+ horizontal: "w-[calc(100%-30px)]",
79
+ },
80
+ },
81
+ defaultVariants: {},
82
+ compoundVariants: [],
83
+ },
84
+ );
85
+
86
+ export const itemPriceClasses = cva(["text-2xl font-bold text-foreground"], {
87
+ variants: {
88
+ orientation: {
89
+ vertical: "",
90
+ horizontal: "",
91
+ },
92
+ },
93
+ defaultVariants: {},
94
+ compoundVariants: [],
95
+ });
96
+
97
+ export const itemDescriptionClasses = cva(
98
+ ["line-clamp-2 text-sm text-default-600"],
99
+ {
100
+ variants: {
101
+ orientation: {
102
+ vertical: "",
103
+ horizontal: "",
104
+ },
105
+ },
106
+ defaultVariants: {},
107
+ compoundVariants: [],
108
+ },
109
+ );
110
+
111
+ export const itemChipsClasses = cva(["flex flex-wrap items-center gap-2 p-1"], {
112
+ variants: {
113
+ orientation: {
114
+ vertical: "",
115
+ horizontal: "",
116
+ },
117
+ },
118
+ defaultVariants: {},
119
+ compoundVariants: [],
120
+ });
121
+
122
+ export const itemBannerClasses = cva(
123
+ [
124
+ "absolute left-0 top-0 z-10 px-2 py-1 text-xs font-semibold",
125
+ "bg-primary-500/50 backdrop-blur-sm text-center flex justify-center items-center",
126
+ "-rotate-45 w-full text-white",
127
+ ],
128
+ {
129
+ variants: {
130
+ orientation: {
131
+ vertical: "-translate-x-28 translate-y-7",
132
+ horizontal: "-translate-x-14 translate-y-7",
133
+ },
134
+ },
135
+ defaultVariants: {},
136
+ compoundVariants: [],
137
+ },
138
+ );
@@ -0,0 +1 @@
1
+ export * from "./classes";
@@ -1,4 +1,5 @@
1
- import { cn, Link } from "@heroui/react";
1
+ import { cn } from "@/utils";
2
+ import { Link } from "@heroui/link";
2
3
  import { useNavigation } from "@/hooks";
3
4
  import { SubItemsBoxProps } from "@/types";
4
5
 
@@ -1 +1,2 @@
1
1
  export * from "./scaffold";
2
+ export * from "./styles";