@js-empire/emperor-ui 1.0.1 → 1.1.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.
Files changed (166) hide show
  1. package/.husky/pre-commit +4 -0
  2. package/.storybook/main.ts +2 -11
  3. package/.storybook/preview.ts +1 -1
  4. package/.vscode/extensions.json +3 -0
  5. package/README.md +68 -1
  6. package/package.json +16 -4
  7. package/public/icons/emperor-ui-logo.ico +0 -0
  8. package/public/images/avatar-female.jpg +0 -0
  9. package/public/images/avatar-male.jpg +0 -0
  10. package/public/images/emperor-ui-logo.png +0 -0
  11. package/src/components/atoms/brand/brand.stories.tsx +27 -0
  12. package/src/components/atoms/brand/brand.tsx +56 -0
  13. package/src/components/atoms/brand/index.ts +1 -0
  14. package/src/components/atoms/brand/styles/classes.ts +9 -0
  15. package/src/components/atoms/brand/styles/index.ts +2 -0
  16. package/src/components/atoms/brand/styles/styles.ts +0 -0
  17. package/src/components/atoms/column/column.stories.tsx +36 -0
  18. package/src/components/atoms/column/column.tsx +21 -0
  19. package/src/components/atoms/column/index.ts +1 -0
  20. package/src/components/atoms/container/column.stories.tsx +36 -0
  21. package/src/components/atoms/container/container.tsx +28 -0
  22. package/src/components/atoms/container/index.ts +1 -0
  23. package/src/components/atoms/index.ts +6 -0
  24. package/src/components/atoms/portal/index.ts +1 -0
  25. package/src/components/atoms/portal/portal.stories.tsx +43 -0
  26. package/src/components/atoms/portal/portal.tsx +23 -0
  27. package/src/components/atoms/row/index.ts +1 -0
  28. package/src/components/atoms/row/row.stories.tsx +36 -0
  29. package/src/components/atoms/row/row.tsx +26 -0
  30. package/src/components/atoms/uploader/avatar-label.tsx +83 -0
  31. package/src/components/atoms/uploader/index.ts +7 -0
  32. package/src/components/atoms/uploader/stories/uploader.stories.tsx +41 -0
  33. package/src/components/atoms/uploader/upload-file-error-box.tsx +29 -0
  34. package/src/components/atoms/uploader/upload-file-input.tsx +36 -0
  35. package/src/components/atoms/uploader/upload-file-label.tsx +74 -0
  36. package/src/components/atoms/uploader/upload-file-listing.tsx +53 -0
  37. package/src/components/atoms/uploader/uploader.tsx +55 -0
  38. package/src/components/atoms/uploader/view-image-modal.tsx +39 -0
  39. package/src/components/index.ts +4 -8
  40. package/src/components/molecules/index.ts +5 -0
  41. package/src/components/molecules/item-card/item-card.tsx +6 -0
  42. package/src/components/molecules/nav-bar/index.ts +3 -0
  43. package/src/components/molecules/nav-bar/nav-bar-item.tsx +70 -0
  44. package/src/components/molecules/nav-bar/nav-bar.tsx +65 -0
  45. package/src/components/molecules/nav-bar/stories/hover-effect/nav-bar-hover-effect.stories.tsx +52 -0
  46. package/src/components/molecules/nav-bar/stories/nav-bar.stories.tsx +50 -0
  47. package/src/components/molecules/nav-bar/styles/classes.ts +68 -0
  48. package/src/components/molecules/nav-bar/styles/index.ts +2 -0
  49. package/src/components/molecules/nav-bar/styles/styles.ts +84 -0
  50. package/src/components/molecules/nav-bar/sub-items-box.tsx +57 -0
  51. package/src/components/molecules/scaffold/scaffold.stories.tsx +21 -0
  52. package/src/components/molecules/scaffold/scaffold.tsx +36 -0
  53. package/src/components/molecules/side-bar/compact-side-bar.tsx +73 -0
  54. package/src/components/molecules/side-bar/index.ts +1 -0
  55. package/src/components/molecules/side-bar/side-bar-drawer.tsx +124 -0
  56. package/src/components/molecules/side-bar/side-bar.stories.tsx +110 -0
  57. package/src/components/molecules/side-bar/side-bar.tsx +31 -0
  58. package/src/components/molecules/side-bar/styles/classes.ts +28 -0
  59. package/src/components/molecules/side-bar/styles/index.ts +2 -0
  60. package/src/components/molecules/side-bar/styles/styles.ts +13 -0
  61. package/src/components/organisms/footer/footer.tsx +20 -0
  62. package/src/components/organisms/footer/styles/classes.ts +15 -0
  63. package/src/components/organisms/footer/styles/index.ts +2 -0
  64. package/src/components/organisms/footer/styles/styles.ts +9 -0
  65. package/src/components/organisms/header/header.tsx +94 -0
  66. package/src/components/organisms/header/segmented-header-content.tsx +37 -0
  67. package/src/components/organisms/header/stories/header.stories.tsx +143 -0
  68. package/src/components/organisms/header/styles/classes.ts +22 -0
  69. package/src/components/organisms/header/styles/index.ts +2 -0
  70. package/src/components/organisms/header/styles/styles.ts +39 -0
  71. package/src/components/organisms/index.ts +4 -0
  72. package/src/components/templates/index.ts +1 -0
  73. package/src/components/templates/landing-page/index.ts +1 -0
  74. package/src/components/templates/landing-page/landing-page.stories.tsx +21 -0
  75. package/src/components/templates/landing-page/landing-page.tsx +57 -0
  76. package/src/components/templates/landing-page/styles/classes.ts +11 -0
  77. package/src/components/templates/landing-page/styles/index.ts +1 -0
  78. package/src/constants/defaults.ts +42 -7
  79. package/src/constants/fake.ts +2 -0
  80. package/src/constants/index.ts +2 -0
  81. package/src/constants/uploader.ts +27 -0
  82. package/src/context/emperor-ui-context.ts +4 -4
  83. package/src/context/index.ts +2 -0
  84. package/src/context/navigation-context.ts +6 -0
  85. package/src/context/uploader-context.ts +6 -0
  86. package/src/enums/index.ts +2 -0
  87. package/src/enums/placeholders.ts +4 -0
  88. package/src/enums/preserved-keys.ts +3 -0
  89. package/src/hooks/index.ts +3 -0
  90. package/src/hooks/use-navigation.ts +12 -0
  91. package/src/hooks/use-uploader-context.ts +14 -0
  92. package/src/hooks/use-uploader.tsx +215 -0
  93. package/src/index.ts +9 -5
  94. package/src/main.tsx +3 -0
  95. package/src/mocks/header.tsx +118 -0
  96. package/src/mocks/index.ts +1 -0
  97. package/src/providers/config-provider.tsx +54 -0
  98. package/src/providers/emperor-ui-provider.tsx +17 -24
  99. package/src/providers/index.ts +3 -0
  100. package/src/providers/navigation-provider.tsx +42 -0
  101. package/src/providers/uploader-provider.tsx +53 -0
  102. package/src/styles/globals.css +13 -0
  103. package/src/styles/hero.ts +2 -0
  104. package/src/types/components/atoms/brand.ts +13 -0
  105. package/src/types/components/atoms/column.ts +3 -0
  106. package/src/types/components/atoms/container.ts +3 -0
  107. package/src/types/components/atoms/index.ts +6 -0
  108. package/src/types/components/atoms/portal.ts +6 -0
  109. package/src/types/components/atoms/row.ts +3 -0
  110. package/src/types/components/atoms/uploader.ts +104 -0
  111. package/src/types/components/index.ts +3 -8
  112. package/src/types/components/molecules/header/header.ts +51 -0
  113. package/src/types/components/molecules/index.ts +9 -0
  114. package/src/types/components/molecules/nav-bar/nav-bar.ts +65 -0
  115. package/src/types/components/molecules/side-bar/index.ts +1 -0
  116. package/src/types/components/molecules/side-bar/side-bar.ts +40 -0
  117. package/src/types/components/templates/index.ts +1 -0
  118. package/src/types/components/templates/landing-page.ts +10 -0
  119. package/src/types/context/config.ts +54 -0
  120. package/src/types/context/index.ts +2 -1
  121. package/src/types/context/navigation.ts +17 -0
  122. package/src/types/shared/components.ts +4 -0
  123. package/src/utils/compress-images.ts +36 -0
  124. package/src/utils/index.ts +2 -0
  125. package/src/utils/storybook.tsx +15 -0
  126. package/tsconfig.app.json +3 -2
  127. package/tsconfig.node.json +0 -1
  128. package/vite.config.ts +4 -0
  129. package/dist/emperor-ui.js +0 -3171
  130. package/dist/emperor-ui.umd.cjs +0 -6
  131. package/dist/index.d.ts +0 -200
  132. package/src/components/footer/footer.tsx +0 -6
  133. package/src/components/header/header.tsx +0 -49
  134. package/src/components/item-card/item-card.tsx +0 -6
  135. package/src/components/nav-bar/index.ts +0 -1
  136. package/src/components/nav-bar/nav-bar.tsx +0 -6
  137. package/src/components/scaffold/scaffold.tsx +0 -15
  138. package/src/index.css +0 -1
  139. package/src/types/components/header/header.ts +0 -21
  140. package/src/types/components/nav-bar/nav-bar.ts +0 -9
  141. package/src/types/context/emperor-ui.ts +0 -37
  142. package/tailwind.config.js +0 -6
  143. /package/src/components/{filter → molecules/filter}/filter.tsx +0 -0
  144. /package/src/components/{filter → molecules/filter}/index.ts +0 -0
  145. /package/src/components/{item-card → molecules/item-card}/index.ts +0 -0
  146. /package/src/components/{scaffold → molecules/scaffold}/index.ts +0 -0
  147. /package/src/components/{footer → organisms/footer}/index.ts +0 -0
  148. /package/src/components/{header → organisms/header}/index.ts +0 -0
  149. /package/src/components/{item-details → organisms/item-details}/index.ts +0 -0
  150. /package/src/components/{item-details → organisms/item-details}/item-details.tsx +0 -0
  151. /package/src/components/{listings → organisms/listings}/index.ts +0 -0
  152. /package/src/components/{listings → organisms/listings}/listings.tsx +0 -0
  153. /package/src/types/components/{filter → molecules/filter}/filter.ts +0 -0
  154. /package/src/types/components/{filter → molecules/filter}/index.ts +0 -0
  155. /package/src/types/components/{footer → molecules/footer}/footer.ts +0 -0
  156. /package/src/types/components/{footer → molecules/footer}/index.ts +0 -0
  157. /package/src/types/components/{header → molecules/header}/index.ts +0 -0
  158. /package/src/types/components/{item-card → molecules/item-card}/index.ts +0 -0
  159. /package/src/types/components/{item-card → molecules/item-card}/item-card.ts +0 -0
  160. /package/src/types/components/{item-details → molecules/item-details}/index.ts +0 -0
  161. /package/src/types/components/{item-details → molecules/item-details}/item-details.ts +0 -0
  162. /package/src/types/components/{listings → molecules/listings}/index.ts +0 -0
  163. /package/src/types/components/{listings → molecules/listings}/listings.ts +0 -0
  164. /package/src/types/components/{nav-bar → molecules/nav-bar}/index.ts +0 -0
  165. /package/src/types/components/{scaffold → molecules/scaffold}/index.ts +0 -0
  166. /package/src/types/components/{scaffold → molecules/scaffold}/scaffold.ts +0 -0
@@ -0,0 +1,4 @@
1
+ pnpm run format
2
+ git add .
3
+ pnpm run lint
4
+ pnpm run build
@@ -4,16 +4,7 @@ import tsconfigPaths from "vite-tsconfig-paths";
4
4
 
5
5
  const config: StorybookConfig = {
6
6
  stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
7
- addons: [
8
- "@chromatic-com/storybook",
9
- "@storybook/addon-vitest",
10
- "@storybook/addon-a11y",
11
- "@storybook/addon-docs",
12
- "@storybook/addon-links",
13
- "@storybook/addon-essentials",
14
- "@storybook/addon-onboarding",
15
- "@storybook/addon-interactions",
16
- ],
7
+ addons: [],
17
8
  framework: {
18
9
  name: "@storybook/react-vite",
19
10
  options: {},
@@ -22,7 +13,7 @@ const config: StorybookConfig = {
22
13
  config.plugins?.push(
23
14
  /** @see https://github.com/aleclarson/vite-tsconfig-paths */
24
15
  tsconfigPaths({
25
- projects: [path.resolve(path.dirname(__dirname), "tsconfig.json")],
16
+ projects: [path.resolve("..", "tsconfig.json")],
26
17
  }),
27
18
  );
28
19
 
@@ -1,5 +1,5 @@
1
1
  import type { Preview } from "@storybook/react-vite";
2
- import "../src/index.css";
2
+ import "../src/styles/globals.css";
3
3
 
4
4
  const preview: Preview = {
5
5
  parameters: {
@@ -0,0 +1,3 @@
1
+ {
2
+
3
+ }
package/README.md CHANGED
@@ -1 +1,68 @@
1
- # EmperorUI
1
+ # Emperor UI
2
+
3
+ ![Emperor UI Logo](./public/images/emperor-ui-logo.png)
4
+
5
+ ## Intro
6
+
7
+ A modular UI library built for React and Nextjs. It depends on HeroUI to implement advanced organisms and pages.
8
+
9
+ Each one of them has props to control every aspect pf the component, with enabling/disabling the optional features.
10
+
11
+ ---
12
+
13
+ ## Components
14
+
15
+ ### Footer
16
+
17
+ - copy rights placeholder
18
+ - Quick links
19
+ - Quick form
20
+ - Social buttons with logos
21
+
22
+ ### Item Card
23
+
24
+ - Image
25
+ - Title
26
+ - Subtitle (for description)
27
+ - Price
28
+ - Drop-down with actions and a dots-icon for opening it
29
+
30
+ ### Listings
31
+
32
+ - Listing any type of components
33
+ - Pagination or infinite scrolling
34
+ - Specifying the page size
35
+ - View controller: list, grid, carousel (swiper)
36
+
37
+ ### Details page
38
+
39
+ - Breadcrumbs
40
+ - Image or carousel
41
+ - Title
42
+ - Subtitle
43
+ - Description
44
+ - Price
45
+
46
+ ### Nav-bar
47
+
48
+ - Navigation buttons using a provided custom router
49
+ - Auto-controlled position: at the top for desktop, or at the bottom for mobile view
50
+
51
+ ### Filter
52
+
53
+ - Filter layouts: side box on desktop, drawer on mobile
54
+ - Custom filter items with different types:
55
+ - search term
56
+ - checkbox
57
+ - Multiple checkboxes under an accordion
58
+ - autocomplete or select box
59
+ - Action buttons: apply filters, reset filters
60
+
61
+ ---
62
+
63
+ ## Documentation Page
64
+
65
+ - Introducing the tool and its usage
66
+ - Installation guide
67
+ - Components with usage and code variants
68
+ - Components API
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@js-empire/emperor-ui",
3
3
  "description": "They provide the atoms, we provide the empire.",
4
- "version": "1.0.1",
4
+ "version": "1.1.0",
5
5
  "author": "JS Empire - Mustafa Alhasanat",
6
6
  "license": "ISC",
7
7
  "type": "module",
@@ -14,7 +14,8 @@
14
14
  "types": "./dist/index.d.ts",
15
15
  "import": "./dist/emperor-ui.js",
16
16
  "require": "./dist/emperor-ui-umd.cjs"
17
- }
17
+ },
18
+ "./globals.css": "./dist/globals.css"
18
19
  },
19
20
  "scripts": {
20
21
  "dev": "vite",
@@ -24,7 +25,8 @@
24
25
  "lint": "eslint .",
25
26
  "preview": "vite preview",
26
27
  "storybook": "storybook dev -p 6006",
27
- "build-storybook": "storybook build"
28
+ "build-storybook": "storybook build",
29
+ "prepare": "husky"
28
30
  },
29
31
  "publishConfig": {
30
32
  "access": "public"
@@ -43,15 +45,25 @@
43
45
  ]
44
46
  },
45
47
  "dependencies": {
48
+ "@heroui/react": "^2.8.5",
49
+ "@heroui/theme": "^2.4.25",
50
+ "@storybook/react": "^10.1.8",
46
51
  "@tailwindcss/vite": "^4.1.17",
52
+ "browser-image-compression": "^2.0.2",
47
53
  "class-variance-authority": "^0.7.1",
48
54
  "clsx": "^2.1.1",
55
+ "framer-motion": "^12.23.26",
56
+ "husky": "^9.1.7",
57
+ "lucide-react": "^0.560.0",
58
+ "motion": "^12.26.2",
49
59
  "prettier": "^3.7.4",
50
60
  "react": "^19.2.0",
51
61
  "react-dom": "^19.2.0",
52
62
  "tailwind-merge": "^3.4.0",
63
+ "tailwind-scrollbar-hide": "^4.0.0",
53
64
  "tailwindcss": "^4.1.17",
54
- "vite-tsconfig-paths": "^5.1.4"
65
+ "vite-tsconfig-paths": "^5.1.4",
66
+ "xlsx": "^0.18.5"
55
67
  },
56
68
  "devDependencies": {
57
69
  "@chromatic-com/storybook": "^4.1.3",
Binary file
Binary file
Binary file
@@ -0,0 +1,27 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Brand } from "@components";
3
+ import { getStorybookDecorators } from "@utils";
4
+
5
+ const meta: Meta<typeof Brand> = {
6
+ title: "Atoms/Brand",
7
+ component: Brand,
8
+ parameters: {
9
+ layout: "centered",
10
+ },
11
+ tags: ["autodocs"],
12
+ decorators: getStorybookDecorators({
13
+ config: {
14
+ layout: {
15
+ withScaffold: false,
16
+ },
17
+ },
18
+ }),
19
+ };
20
+
21
+ export default meta;
22
+
23
+ type Story = StoryObj<typeof meta>;
24
+
25
+ export const Default: Story = {
26
+ args: {},
27
+ };
@@ -0,0 +1,56 @@
1
+ import type { BrandProps } from "@types";
2
+ import { cn } from "@utils";
3
+ import { VariantProps } from "class-variance-authority";
4
+ import { ComponentProps, forwardRef } from "react";
5
+ import { Row } from "@components";
6
+ import { brandStyles } from "./styles";
7
+ import { Image } from "@heroui/react";
8
+
9
+ export const Brand = forwardRef<
10
+ HTMLElement,
11
+ ComponentProps<"div"> & VariantProps<typeof brandStyles> & BrandProps
12
+ >(
13
+ (
14
+ {
15
+ className,
16
+ variant,
17
+ src = "/images/emperor-ui-logo.png",
18
+ alt = "Emperor UI",
19
+ name = "Emperor UI",
20
+ isIconOnly = false,
21
+ classNames,
22
+ ...props
23
+ },
24
+ ref,
25
+ ) => {
26
+ return (
27
+ <Row
28
+ ref={ref}
29
+ data-slot="emperor-brand"
30
+ className={cn(
31
+ brandStyles({ variant, className: cn(className, classNames?.base) }),
32
+ )}
33
+ {...props}
34
+ >
35
+ {src && (
36
+ <Image
37
+ data-slot="emperor-brand-logo"
38
+ src={src}
39
+ alt={alt}
40
+ radius="md"
41
+ className={cn("min-w-7 min-h-7 size-7", classNames?.logo)}
42
+ />
43
+ )}
44
+
45
+ {name && !isIconOnly && (
46
+ <p
47
+ data-slot="emperor-brand-name"
48
+ className={cn("font-semibold text-lg", classNames?.name)}
49
+ >
50
+ {name}
51
+ </p>
52
+ )}
53
+ </Row>
54
+ );
55
+ },
56
+ );
@@ -0,0 +1 @@
1
+ export * from "./brand";
@@ -0,0 +1,9 @@
1
+ import { cva } from "class-variance-authority";
2
+
3
+ export const brandStyles = cva([""], {
4
+ variants: {
5
+ variant: {},
6
+ },
7
+ defaultVariants: {},
8
+ compoundVariants: [],
9
+ });
@@ -0,0 +1,2 @@
1
+ export * from "./classes";
2
+ export * from "./styles";
File without changes
@@ -0,0 +1,36 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Column } from "@components";
3
+ import { getStorybookDecorators } from "@utils";
4
+
5
+ const meta: Meta<typeof Column> = {
6
+ title: "Atoms/Column",
7
+ component: Column,
8
+ parameters: {
9
+ layout: "centered",
10
+ },
11
+ tags: ["autodocs"],
12
+ decorators: getStorybookDecorators({
13
+ config: {
14
+ layout: {
15
+ withScaffold: false,
16
+ },
17
+ },
18
+ }),
19
+ };
20
+
21
+ export default meta;
22
+
23
+ type Story = StoryObj<typeof meta>;
24
+
25
+ export const Default: Story = {
26
+ args: {},
27
+ render: (args) => (
28
+ <Column {...args}>
29
+ {Array.from({ length: 5 }).map((_, index) => (
30
+ <div key={index} className="bg-blue-300 p-2 rounded-md">
31
+ Item {index + 1}
32
+ </div>
33
+ ))}
34
+ </Column>
35
+ ),
36
+ };
@@ -0,0 +1,21 @@
1
+ import type { ColumnProps } from "@types";
2
+ import { cn } from "@utils";
3
+ import { cva, VariantProps } from "class-variance-authority";
4
+ import { forwardRef, ComponentProps } from "react";
5
+
6
+ const columnStyles = cva(["flex flex-col gap-3"], {
7
+ variants: {},
8
+ defaultVariants: {},
9
+ compoundVariants: [],
10
+ });
11
+
12
+ export const Column = forwardRef<
13
+ HTMLElement,
14
+ ComponentProps<"section"> & VariantProps<typeof columnStyles> & ColumnProps
15
+ >(({ className, children, ...props }, ref) => {
16
+ return (
17
+ <section ref={ref} className={cn(columnStyles({ className }))} {...props}>
18
+ {children}
19
+ </section>
20
+ );
21
+ });
@@ -0,0 +1 @@
1
+ export * from "./column";
@@ -0,0 +1,36 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Container } from "@components";
3
+ import { getStorybookDecorators } from "@utils";
4
+
5
+ const meta: Meta<typeof Container> = {
6
+ title: "Atoms/Container",
7
+ component: Container,
8
+ parameters: {
9
+ layout: "fullscreen",
10
+ },
11
+ tags: ["autodocs"],
12
+ decorators: getStorybookDecorators({
13
+ config: {
14
+ layout: {
15
+ withScaffold: false,
16
+ },
17
+ },
18
+ }),
19
+ };
20
+
21
+ export default meta;
22
+
23
+ type Story = StoryObj<typeof meta>;
24
+
25
+ export const Default: Story = {
26
+ args: {
27
+ className: "h-screen flex items-center justify-center",
28
+ },
29
+ render: (args) => (
30
+ <Container {...args}>
31
+ <div className="bg-blue-300 p-2 text-center rounded-md w-full h-fit">
32
+ Responsive contained content
33
+ </div>
34
+ </Container>
35
+ ),
36
+ };
@@ -0,0 +1,28 @@
1
+ import type { ContainerProps } from "@types";
2
+ import { cn } from "@utils";
3
+ import { cva, VariantProps } from "class-variance-authority";
4
+ import { forwardRef, ComponentProps } from "react";
5
+
6
+ const containerStyles = cva(["flex w-full container p-4 mx-auto"], {
7
+ variants: {},
8
+ defaultVariants: {},
9
+ compoundVariants: [],
10
+ });
11
+
12
+ export const Container = forwardRef<
13
+ HTMLElement,
14
+ ComponentProps<"section"> &
15
+ VariantProps<typeof containerStyles> &
16
+ ContainerProps
17
+ >(({ className, children, ...props }, ref) => {
18
+ return (
19
+ <section
20
+ ref={ref}
21
+ data-slot="container"
22
+ className={cn(containerStyles({ className }))}
23
+ {...props}
24
+ >
25
+ {children}
26
+ </section>
27
+ );
28
+ });
@@ -0,0 +1 @@
1
+ export * from "./container";
@@ -0,0 +1,6 @@
1
+ export * from "./brand";
2
+ export * from "./column";
3
+ export * from "./container";
4
+ export * from "./row";
5
+ export * from "./portal";
6
+ export * from "./uploader";
@@ -0,0 +1 @@
1
+ export * from "./portal";
@@ -0,0 +1,43 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Portal } from "@components";
3
+ import { getStorybookDecorators } from "@utils";
4
+ import { FAKE_PARAGRAPH } from "@constants";
5
+
6
+ const meta: Meta<typeof Portal> = {
7
+ title: "Atoms/Portal",
8
+ component: Portal,
9
+ parameters: {
10
+ layout: "fullscreen",
11
+ },
12
+ tags: ["autodocs"],
13
+ decorators: getStorybookDecorators({
14
+ config: {
15
+ layout: {
16
+ withScaffold: false,
17
+ },
18
+ },
19
+ }),
20
+ };
21
+
22
+ export default meta;
23
+
24
+ type Story = StoryObj<typeof meta>;
25
+
26
+ export const Default: Story = {
27
+ args: {},
28
+ render: () => (
29
+ <main className="h-screen w-full flex flex-col gap-10 p-5">
30
+ <div id="portal-container" />
31
+
32
+ <p>{FAKE_PARAGRAPH}</p>
33
+ <p>{FAKE_PARAGRAPH}</p>
34
+ <p>{FAKE_PARAGRAPH}</p>
35
+
36
+ <Portal containerId="portal-container">
37
+ <div className="bg-blue-300 p-2 rounded-md absolute top-5 left-1/2 -translate-x-1/2">
38
+ <h2>Portal Content</h2>
39
+ </div>
40
+ </Portal>
41
+ </main>
42
+ ),
43
+ };
@@ -0,0 +1,23 @@
1
+ import { PortalProps } from "@types";
2
+ import { useEffect, useState } from "react";
3
+ import { createPortal } from "react-dom";
4
+
5
+ export function Portal({
6
+ children,
7
+ containerId,
8
+ isVisible = true,
9
+ }: PortalProps) {
10
+ const [container, setContainer] = useState<HTMLElement | null>(null);
11
+
12
+ useEffect(() => {
13
+ const element = document.getElementById(containerId);
14
+
15
+ setContainer(element);
16
+ }, [containerId]);
17
+
18
+ if (!container || !isVisible) {
19
+ return null;
20
+ }
21
+
22
+ return createPortal(children, container);
23
+ }
@@ -0,0 +1 @@
1
+ export * from "./row";
@@ -0,0 +1,36 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Row } from "@components";
3
+ import { getStorybookDecorators } from "@utils";
4
+
5
+ const meta: Meta<typeof Row> = {
6
+ title: "Atoms/Row",
7
+ component: Row,
8
+ parameters: {
9
+ layout: "centered",
10
+ },
11
+ tags: ["autodocs"],
12
+ decorators: getStorybookDecorators({
13
+ config: {
14
+ layout: {
15
+ withScaffold: false,
16
+ },
17
+ },
18
+ }),
19
+ };
20
+
21
+ export default meta;
22
+
23
+ type Story = StoryObj<typeof meta>;
24
+
25
+ export const Default: Story = {
26
+ args: {},
27
+ render: (args) => (
28
+ <Row {...args}>
29
+ {Array.from({ length: 5 }).map((_, index) => (
30
+ <div key={index} className="bg-blue-300 p-2 rounded-md">
31
+ Item {index + 1}
32
+ </div>
33
+ ))}
34
+ </Row>
35
+ ),
36
+ };
@@ -0,0 +1,26 @@
1
+ import type { RowProps } from "@types";
2
+ import { cn } from "@utils";
3
+ import { cva, VariantProps } from "class-variance-authority";
4
+ import { forwardRef, ComponentProps } from "react";
5
+
6
+ const rowStyles = cva(["flex items-center gap-3"], {
7
+ variants: {},
8
+ defaultVariants: {},
9
+ compoundVariants: [],
10
+ });
11
+
12
+ export const Row = forwardRef<
13
+ HTMLElement,
14
+ ComponentProps<"section"> & VariantProps<typeof rowStyles> & RowProps
15
+ >(({ className, children, ...props }, ref) => {
16
+ return (
17
+ <section
18
+ ref={ref}
19
+ data-slot="row"
20
+ className={cn(rowStyles({ className }))}
21
+ {...props}
22
+ >
23
+ {children}
24
+ </section>
25
+ );
26
+ });
@@ -0,0 +1,83 @@
1
+ "use client";
2
+
3
+ import { Placeholders } from "@enums";
4
+ import { Avatar, Spinner, cn } from "@heroui/react";
5
+ import { useEmperorUI, useUploaderContext } from "@hooks";
6
+ import { useState } from "react";
7
+
8
+ export function AvatarLabel() {
9
+ const { config } = useEmperorUI();
10
+ const [draggableMessage, setDraggableMessage] = useState<string | null>(null);
11
+ const {
12
+ labelId,
13
+ classNames,
14
+ labelContent,
15
+ isDraggable,
16
+ onInputChange,
17
+ avatarLabelContent,
18
+ placeholderImage,
19
+ files,
20
+ isLoading,
21
+ } = useUploaderContext();
22
+
23
+ const locales = config?.interLocalization?.locales;
24
+ const lang = config?.interLocalization?.lang;
25
+
26
+ const locale = locales?.[lang || "en"];
27
+
28
+ const handleDrop = (
29
+ event: React.ChangeEvent<HTMLInputElement> &
30
+ React.DragEvent<HTMLLabelElement>,
31
+ ) => {
32
+ event.preventDefault();
33
+ if (onInputChange) onInputChange(event);
34
+ };
35
+
36
+ const handleDragOver = (
37
+ event: React.ChangeEvent<HTMLInputElement> &
38
+ React.DragEvent<HTMLLabelElement>,
39
+ ) => {
40
+ event.preventDefault();
41
+ setDraggableMessage(locale?.dropHere || "");
42
+ };
43
+
44
+ const handleDragLeave = () => {
45
+ setDraggableMessage("");
46
+ };
47
+
48
+ if (isLoading)
49
+ return (
50
+ <div className={cn("mx-auto", classNames?.label)}>
51
+ <Spinner className="mx-auto" size="lg" />;
52
+ </div>
53
+ );
54
+
55
+ return (
56
+ <label
57
+ className={cn(
58
+ "w-full cursor-pointer mx-auto transition-opacity flex flex-col gap-5",
59
+ draggableMessage && "opacity-60",
60
+ classNames?.label,
61
+ )}
62
+ htmlFor={labelId}
63
+ onDrop={isDraggable ? handleDrop : () => {}}
64
+ onDragOver={isDraggable ? handleDragOver : () => {}}
65
+ onDragLeave={isDraggable ? handleDragLeave : () => {}}
66
+ >
67
+ {avatarLabelContent}
68
+
69
+ {labelContent || (
70
+ <Avatar
71
+ src={
72
+ files?.[0]?.view ||
73
+ placeholderImage ||
74
+ Placeholders.PLACEHOLDER_MALE_AVATAR
75
+ }
76
+ alt="avatar"
77
+ size="lg"
78
+ className={cn("size-24", classNames?.avatar)}
79
+ />
80
+ )}
81
+ </label>
82
+ );
83
+ }
@@ -0,0 +1,7 @@
1
+ export * from "./uploader";
2
+ export * from "./avatar-label";
3
+ export * from "./upload-file-label";
4
+ export * from "./view-image-modal";
5
+ export * from "./upload-file-listing";
6
+ export * from "./upload-file-error-box";
7
+ export * from "./upload-file-input";