@sunggang/ui-lib 0.0.3 → 0.0.5
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/.eslintrc.json +18 -0
- package/.storybook/main.js +14 -0
- package/.storybook/preview.js +1 -0
- package/.storybook/tailwind-imports.css +81 -0
- package/components.json +15 -0
- package/package.json +8 -4
- package/postcss.config.js +10 -0
- package/project.json +31 -0
- package/src/components/ui/switch.tsx +27 -0
- package/src/index.ts +7 -0
- package/src/lib/DropImage/index.stories.tsx +42 -0
- package/src/lib/DropImage/index.tsx +110 -0
- package/src/lib/Modal/BaseModal.jsx +52 -0
- package/src/lib/Modal/ErrorContent.tsx +21 -0
- package/src/lib/Modal/FullScreenModal.jsx +39 -0
- package/src/lib/Modal/Modal.tsx +36 -0
- package/src/lib/Modal/ModalContent.tsx +60 -0
- package/src/lib/Modal/NoticeModal.jsx +91 -0
- package/src/lib/Modal/index.jsx +1 -0
- package/src/lib/Spin/index.tsx +20 -0
- package/src/lib/Switch/index.stories.tsx +24 -0
- package/src/lib/UploadImage/BaseTemplate.tsx +73 -0
- package/src/lib/UploadImage/CustomUpload.stories.tsx +52 -0
- package/src/lib/UploadImage/CustomUpload.tsx +95 -0
- package/src/lib/hello-server.tsx +4 -0
- package/src/lib/uiLibrary.spec.tsx +10 -0
- package/src/lib/uiLibrary.tsx +14 -0
- package/src/lib/utils.ts +6 -0
- package/src/server.ts +2 -0
- package/storybook-static/249.d700bcb8.iframe.bundle.js +95 -0
- package/storybook-static/249.d700bcb8.iframe.bundle.js.LICENSE.txt +25 -0
- package/storybook-static/249.d700bcb8.iframe.bundle.js.map +1 -0
- package/storybook-static/272.859c45b5.iframe.bundle.js +1 -0
- package/storybook-static/297.86b29044.iframe.bundle.js +1 -0
- package/storybook-static/301.7b83a51f.iframe.bundle.js +1 -0
- package/storybook-static/311.5beb2d3d.iframe.bundle.js +1 -0
- package/storybook-static/312.aa18d841.iframe.bundle.js +1 -0
- package/storybook-static/501.1fba3663.iframe.bundle.js +1 -0
- package/storybook-static/754.9ec23ac4.iframe.bundle.js +1 -0
- package/storybook-static/777.4b1d90f9.iframe.bundle.js +1 -0
- package/storybook-static/794.2230a3f3.iframe.bundle.js +1 -0
- package/storybook-static/852.18487f4c.iframe.bundle.js +402 -0
- package/storybook-static/852.18487f4c.iframe.bundle.js.LICENSE.txt +23 -0
- package/storybook-static/852.18487f4c.iframe.bundle.js.map +1 -0
- package/storybook-static/DropImage-index-stories.befa1b35.iframe.bundle.js +1 -0
- package/storybook-static/Switch-index-stories.9cfb2ba1.iframe.bundle.js +1 -0
- package/storybook-static/UploadImage-CustomUpload-stories.521444aa.iframe.bundle.js +1 -0
- package/storybook-static/favicon.svg +7 -0
- package/storybook-static/iframe.html +370 -0
- package/storybook-static/index.html +151 -0
- package/storybook-static/index.json +1 -0
- package/storybook-static/main.6f3c811b.iframe.bundle.js +1 -0
- package/storybook-static/project.json +1 -0
- package/storybook-static/runtime~main.28408b82.iframe.bundle.js +1 -0
- package/storybook-static/sb-addons/essentials-actions-2/manager-bundle.js +3 -0
- package/storybook-static/sb-addons/essentials-actions-2/manager-bundle.js.LEGAL.txt +0 -0
- package/storybook-static/sb-addons/essentials-backgrounds-3/manager-bundle.js +12 -0
- package/storybook-static/sb-addons/essentials-backgrounds-3/manager-bundle.js.LEGAL.txt +0 -0
- package/storybook-static/sb-addons/essentials-controls-1/manager-bundle.js +79 -0
- package/storybook-static/sb-addons/essentials-controls-1/manager-bundle.js.LEGAL.txt +28 -0
- package/storybook-static/sb-addons/essentials-measure-6/manager-bundle.js +3 -0
- package/storybook-static/sb-addons/essentials-measure-6/manager-bundle.js.LEGAL.txt +0 -0
- package/storybook-static/sb-addons/essentials-outline-7/manager-bundle.js +3 -0
- package/storybook-static/sb-addons/essentials-outline-7/manager-bundle.js.LEGAL.txt +0 -0
- package/storybook-static/sb-addons/essentials-toolbars-5/manager-bundle.js +3 -0
- package/storybook-static/sb-addons/essentials-toolbars-5/manager-bundle.js.LEGAL.txt +0 -0
- package/storybook-static/sb-addons/essentials-viewport-4/manager-bundle.js +3 -0
- package/storybook-static/sb-addons/essentials-viewport-4/manager-bundle.js.LEGAL.txt +0 -0
- package/storybook-static/sb-addons/storybook-core-server-presets-0/common-manager-bundle.js +3 -0
- package/storybook-static/sb-addons/storybook-core-server-presets-0/common-manager-bundle.js.LEGAL.txt +0 -0
- package/storybook-static/sb-common-assets/fonts.css +31 -0
- package/storybook-static/sb-common-assets/nunito-sans-bold-italic.woff2 +0 -0
- package/storybook-static/sb-common-assets/nunito-sans-bold.woff2 +0 -0
- package/storybook-static/sb-common-assets/nunito-sans-italic.woff2 +0 -0
- package/storybook-static/sb-common-assets/nunito-sans-regular.woff2 +0 -0
- package/storybook-static/sb-manager/WithTooltip-Y7J54OF7-KHQOWZXS.js +1 -0
- package/storybook-static/sb-manager/chunk-3F3RRPB3.js +347 -0
- package/storybook-static/sb-manager/chunk-62YMTM65.js +6 -0
- package/storybook-static/sb-manager/chunk-AQBE2B7B.js +183 -0
- package/storybook-static/sb-manager/chunk-Q3RBXCN3.js +231 -0
- package/storybook-static/sb-manager/chunk-XP3HGWTR.js +1 -0
- package/storybook-static/sb-manager/chunk-YME6VNXZ.js +9 -0
- package/storybook-static/sb-manager/formatter-B5HCVTEV-7DCBOGO6.js +58 -0
- package/storybook-static/sb-manager/globals-module-info.js +1 -0
- package/storybook-static/sb-manager/globals-runtime.js +1 -0
- package/storybook-static/sb-manager/globals.js +1 -0
- package/storybook-static/sb-manager/index.js +1 -0
- package/storybook-static/sb-manager/runtime.js +1 -0
- package/storybook-static/sb-manager/syntaxhighlighter-JOJW2KGS-WAFIMSO6.js +1 -0
- package/storybook-static/sb-preview/globals.js +1 -0
- package/storybook-static/sb-preview/runtime.js +128 -0
- package/tailwind.config.js +76 -0
- package/tsconfig.json +25 -0
- package/tsconfig.lib.json +29 -0
- package/tsconfig.storybook.json +31 -0
- package/index.esm.d.ts +0 -1
- package/index.esm.js +0 -5755
- package/src/index.d.ts +0 -4
- package/src/lib/DropImage/index.d.ts +0 -8
- package/src/lib/Modal/ErrorContent.d.ts +0 -7
- package/src/lib/Modal/Modal.d.ts +0 -7
- package/src/lib/Modal/ModalContent.d.ts +0 -10
- package/src/lib/Spin/index.d.ts +0 -5
- package/src/lib/UploadImage/BaseTemplate.d.ts +0 -7
- package/src/lib/UploadImage/CustomUpload.d.ts +0 -10
- package/src/lib/hello-server.d.ts +0 -1
- package/src/lib/uiLibrary.d.ts +0 -4
- package/src/server.d.ts +0 -1
- /package/{index.esm.css → src/lib/uiLibrary.module.css} +0 -0
package/.eslintrc.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": ["plugin:@nx/react", "../.eslintrc.json"],
|
|
3
|
+
"ignorePatterns": ["!**/*", "storybook-static"],
|
|
4
|
+
"overrides": [
|
|
5
|
+
{
|
|
6
|
+
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
|
7
|
+
"rules": {}
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"files": ["*.ts", "*.tsx"],
|
|
11
|
+
"rules": {}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"files": ["*.js", "*.jsx"],
|
|
15
|
+
"rules": {}
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const config = {
|
|
2
|
+
stories: ['../src/lib/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
|
|
3
|
+
addons: ['@storybook/addon-essentials'],
|
|
4
|
+
framework: {
|
|
5
|
+
name: '@storybook/nextjs',
|
|
6
|
+
options: {},
|
|
7
|
+
},
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default config;
|
|
11
|
+
|
|
12
|
+
// To customize your webpack configuration you can use the webpackFinal field.
|
|
13
|
+
// Check https://storybook.js.org/docs/react/builders/webpack#extending-storybooks-webpack-config
|
|
14
|
+
// and https://nx.dev/recipes/storybook/custom-builder-configs
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import './tailwind-imports.css';
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
@layer base {
|
|
6
|
+
:root {
|
|
7
|
+
--background: 0 0% 100%;
|
|
8
|
+
--foreground: 222.2 47.4% 11.2%;
|
|
9
|
+
|
|
10
|
+
--muted: 210 40% 96.1%;
|
|
11
|
+
--muted-foreground: 215.4 16.3% 46.9%;
|
|
12
|
+
|
|
13
|
+
--popover: 0 0% 100%;
|
|
14
|
+
--popover-foreground: 222.2 47.4% 11.2%;
|
|
15
|
+
|
|
16
|
+
--border: 214.3 31.8% 91.4%;
|
|
17
|
+
--input: 214.3 31.8% 91.4%;
|
|
18
|
+
|
|
19
|
+
--card: 0 0% 100%;
|
|
20
|
+
--card-foreground: 222.2 47.4% 11.2%;
|
|
21
|
+
|
|
22
|
+
--primary: 222.2 47.4% 11.2%;
|
|
23
|
+
--primary-foreground: 210 40% 98%;
|
|
24
|
+
|
|
25
|
+
--secondary: 210 40% 96.1%;
|
|
26
|
+
--secondary-foreground: 222.2 47.4% 11.2%;
|
|
27
|
+
|
|
28
|
+
--accent: 210 40% 96.1%;
|
|
29
|
+
--accent-foreground: 222.2 47.4% 11.2%;
|
|
30
|
+
|
|
31
|
+
--destructive: 0 100% 50%;
|
|
32
|
+
--destructive-foreground: 210 40% 98%;
|
|
33
|
+
|
|
34
|
+
--ring: 215 20.2% 65.1%;
|
|
35
|
+
|
|
36
|
+
--radius: 0.5rem;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.dark {
|
|
40
|
+
--background: 224 71% 4%;
|
|
41
|
+
--foreground: 213 31% 91%;
|
|
42
|
+
|
|
43
|
+
--muted: 223 47% 11%;
|
|
44
|
+
--muted-foreground: 215.4 16.3% 56.9%;
|
|
45
|
+
|
|
46
|
+
--accent: 216 34% 17%;
|
|
47
|
+
--accent-foreground: 210 40% 98%;
|
|
48
|
+
|
|
49
|
+
--popover: 224 71% 4%;
|
|
50
|
+
--popover-foreground: 215 20.2% 65.1%;
|
|
51
|
+
|
|
52
|
+
--border: 216 34% 17%;
|
|
53
|
+
--input: 216 34% 17%;
|
|
54
|
+
|
|
55
|
+
--card: 224 71% 4%;
|
|
56
|
+
--card-foreground: 213 31% 91%;
|
|
57
|
+
|
|
58
|
+
--primary: 210 40% 98%;
|
|
59
|
+
--primary-foreground: 222.2 47.4% 1.2%;
|
|
60
|
+
|
|
61
|
+
--secondary: 222.2 47.4% 11.2%;
|
|
62
|
+
--secondary-foreground: 210 40% 98%;
|
|
63
|
+
|
|
64
|
+
--destructive: 0 63% 31%;
|
|
65
|
+
--destructive-foreground: 210 40% 98%;
|
|
66
|
+
|
|
67
|
+
--ring: 216 34% 17%;
|
|
68
|
+
|
|
69
|
+
--radius: 0.5rem;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@layer base {
|
|
74
|
+
* {
|
|
75
|
+
@apply border-border;
|
|
76
|
+
}
|
|
77
|
+
body {
|
|
78
|
+
@apply bg-background text-foreground;
|
|
79
|
+
font-feature-settings: 'rlig' 1, 'calt' 1;
|
|
80
|
+
}
|
|
81
|
+
}
|
package/components.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema.json",
|
|
3
|
+
"style": "new-york",
|
|
4
|
+
"rsc": false,
|
|
5
|
+
"tailwind": {
|
|
6
|
+
"config": "apps/**/tailwind.config.js",
|
|
7
|
+
"css": "apps/**/app/global.css",
|
|
8
|
+
"baseColor": "stone",
|
|
9
|
+
"cssVariables": true
|
|
10
|
+
},
|
|
11
|
+
"aliases": {
|
|
12
|
+
"components": "@sunggang/uiLibrary/components",
|
|
13
|
+
"utils": "@sunggang/uiLibrary/lib/utils"
|
|
14
|
+
}
|
|
15
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sunggang/ui-lib",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
"version": "0.0.5",
|
|
4
|
+
"dependencies": {
|
|
5
|
+
"@radix-ui/react-switch": "^1.0.3",
|
|
6
|
+
"class-variance-authority": "^0.7.0",
|
|
7
|
+
"clsx": "^2.1.0",
|
|
8
|
+
"tailwind-merge": "^2.2.2",
|
|
9
|
+
"tailwindcss-animate": "^1.0.7"
|
|
10
|
+
}
|
|
7
11
|
}
|
package/project.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "uiLibrary",
|
|
3
|
+
"$schema": "../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"sourceRoot": "uiLibrary/src",
|
|
5
|
+
"projectType": "library",
|
|
6
|
+
"tags": [],
|
|
7
|
+
"targets": {
|
|
8
|
+
"build": {
|
|
9
|
+
"executor": "@nx/rollup:rollup",
|
|
10
|
+
"outputs": ["{options.outputPath}"],
|
|
11
|
+
"options": {
|
|
12
|
+
"outputPath": "dist/uiLibrary",
|
|
13
|
+
"styles": ["apps/ui-lib/styles.css"],
|
|
14
|
+
"postcssConfig": "apps/ui-lib/postcss.config.js",
|
|
15
|
+
"tsConfig": "uiLibrary/tsconfig.lib.json",
|
|
16
|
+
"project": "uiLibrary/package.json",
|
|
17
|
+
"entryFile": "uiLibrary/src/index.ts",
|
|
18
|
+
"external": ["react", "react-dom", "react/jsx-runtime"],
|
|
19
|
+
"rollupConfig": "@nx/react/plugins/bundle-rollup",
|
|
20
|
+
"compiler": "swc",
|
|
21
|
+
"assets": [
|
|
22
|
+
{
|
|
23
|
+
"glob": "uiLibrary/README.md",
|
|
24
|
+
"input": ".",
|
|
25
|
+
"output": "."
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import * as SwitchPrimitives from "@radix-ui/react-switch"
|
|
3
|
+
|
|
4
|
+
import { cn } from "@sunggang/uiLibrary/lib/utils"
|
|
5
|
+
|
|
6
|
+
const Switch = React.forwardRef<
|
|
7
|
+
React.ElementRef<typeof SwitchPrimitives.Root>,
|
|
8
|
+
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
|
|
9
|
+
>(({ className, ...props }, ref) => (
|
|
10
|
+
<SwitchPrimitives.Root
|
|
11
|
+
className={cn(
|
|
12
|
+
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
|
13
|
+
className
|
|
14
|
+
)}
|
|
15
|
+
{...props}
|
|
16
|
+
ref={ref}
|
|
17
|
+
>
|
|
18
|
+
<SwitchPrimitives.Thumb
|
|
19
|
+
className={cn(
|
|
20
|
+
"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
|
|
21
|
+
)}
|
|
22
|
+
/>
|
|
23
|
+
</SwitchPrimitives.Root>
|
|
24
|
+
))
|
|
25
|
+
Switch.displayName = SwitchPrimitives.Root.displayName
|
|
26
|
+
|
|
27
|
+
export { Switch }
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Use this file to export React client components (e.g. those with 'use client' directive) or other non-server utilities
|
|
2
|
+
|
|
3
|
+
export * from './lib/uiLibrary';
|
|
4
|
+
export * from './lib/Spin';
|
|
5
|
+
export * from './lib/DropImage';
|
|
6
|
+
export * from './lib/UploadImage/CustomUpload';
|
|
7
|
+
export * from './components/ui/switch';
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Meta, StoryFn } from '@storybook/react';
|
|
2
|
+
import { DropImage } from './index';
|
|
3
|
+
|
|
4
|
+
interface ImageItem {
|
|
5
|
+
map?: any;
|
|
6
|
+
length?: ImageItem | undefined;
|
|
7
|
+
url: string;
|
|
8
|
+
book_items_category_id: string | null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface DropImageProps {
|
|
12
|
+
preview: boolean;
|
|
13
|
+
imageUrls?: ImageItem[];
|
|
14
|
+
setFiles: React.Dispatch<React.SetStateAction<File[]>>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default {
|
|
18
|
+
component: DropImage,
|
|
19
|
+
title: 'DropImage',
|
|
20
|
+
} as Meta;
|
|
21
|
+
|
|
22
|
+
const demoImage: ImageItem[] = [
|
|
23
|
+
{
|
|
24
|
+
url: 'https://gobobook.s3.ap-northeast-1.amazonaws.com/regions/DEV/region1.png',
|
|
25
|
+
book_items_category_id: null,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
url: 'https://gobobook.s3.ap-northeast-1.amazonaws.com/regions/DEV/region2.png',
|
|
29
|
+
book_items_category_id: null,
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
const Template: StoryFn<DropImageProps> = (args) => {
|
|
34
|
+
return <DropImage {...args} />;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const Base = Template.bind({});
|
|
38
|
+
Base.args = {
|
|
39
|
+
preview: true,
|
|
40
|
+
setFiles: () => ({}),
|
|
41
|
+
imageUrls: demoImage,
|
|
42
|
+
};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { useDropzone } from 'react-dropzone';
|
|
3
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
4
|
+
import { Icon } from '@iconify/react';
|
|
5
|
+
|
|
6
|
+
interface ImageItem {
|
|
7
|
+
map?: any;
|
|
8
|
+
length?: ImageItem | undefined;
|
|
9
|
+
url: string;
|
|
10
|
+
book_items_category_id: string | null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface DropImageProps {
|
|
14
|
+
preview?: boolean;
|
|
15
|
+
imageUrls?: ImageItem[];
|
|
16
|
+
setFiles: React.Dispatch<React.SetStateAction<File[]>>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const DropImage: React.FC<DropImageProps> = ({
|
|
20
|
+
preview = true,
|
|
21
|
+
setFiles,
|
|
22
|
+
imageUrls,
|
|
23
|
+
}) => {
|
|
24
|
+
const [previewFiles, setPreviewFiles] = useState<File[]>([]);
|
|
25
|
+
|
|
26
|
+
const {
|
|
27
|
+
getRootProps,
|
|
28
|
+
getInputProps,
|
|
29
|
+
isDragActive,
|
|
30
|
+
isDragAccept,
|
|
31
|
+
isDragReject,
|
|
32
|
+
} = useDropzone({
|
|
33
|
+
accept: { 'image/png': ['.png'], 'image/jpeg': ['.jpg', '.jpeg'] },
|
|
34
|
+
maxFiles: 10,
|
|
35
|
+
maxSize: 5000000,
|
|
36
|
+
onDrop: (dropFiles) => {
|
|
37
|
+
const newFiles: File[] = [];
|
|
38
|
+
|
|
39
|
+
setFiles(dropFiles);
|
|
40
|
+
|
|
41
|
+
dropFiles.forEach((dropFile) => {
|
|
42
|
+
Object.assign(dropFile, {
|
|
43
|
+
preview: URL.createObjectURL(dropFile),
|
|
44
|
+
uuid: uuidv4(),
|
|
45
|
+
});
|
|
46
|
+
newFiles.push(dropFile);
|
|
47
|
+
|
|
48
|
+
setPreviewFiles(newFiles);
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<section className="w-full">
|
|
55
|
+
<div {...getRootProps({ className: 'dropzone' })}>
|
|
56
|
+
<input {...getInputProps()} />
|
|
57
|
+
<div className="flex justify-between">
|
|
58
|
+
<div className="w-full bg-gray-light rounded-lg">
|
|
59
|
+
<div className="border-2 border-dashed border-gray-400 rounded-lg bg-gray-100">
|
|
60
|
+
<div className="flex justify-center py-8">
|
|
61
|
+
<Icon
|
|
62
|
+
icon="material-symbols:upload"
|
|
63
|
+
width="2.5rem"
|
|
64
|
+
height="2.5rem"
|
|
65
|
+
/>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<div className="flex items-center flex-col justify-center">
|
|
69
|
+
<p className="font-normal text-sm text-gray-400 pb-4">
|
|
70
|
+
圖片僅支援 png、jpg、jpeg
|
|
71
|
+
</p>
|
|
72
|
+
|
|
73
|
+
<h5 className="mb-2 text-xl font-bold tracking-tight text-gray-700 pb-4">
|
|
74
|
+
拖曳圖片至此
|
|
75
|
+
</h5>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
{preview && (
|
|
82
|
+
<div className="flex pt-2 gap-2">
|
|
83
|
+
{previewFiles?.length
|
|
84
|
+
? previewFiles.length > 0
|
|
85
|
+
? previewFiles.map((item: any) => (
|
|
86
|
+
<div key={item?.uuid}>
|
|
87
|
+
<img
|
|
88
|
+
className="w-24 h-24 object-cover"
|
|
89
|
+
src={item?.preview}
|
|
90
|
+
alt=""
|
|
91
|
+
/>
|
|
92
|
+
</div>
|
|
93
|
+
))
|
|
94
|
+
: null
|
|
95
|
+
: imageUrls && imageUrls.length
|
|
96
|
+
? imageUrls.map((item) => (
|
|
97
|
+
<div key={item?.url}>
|
|
98
|
+
<img
|
|
99
|
+
className="w-24 h-24 object-cover"
|
|
100
|
+
src={item?.url}
|
|
101
|
+
alt=""
|
|
102
|
+
/>
|
|
103
|
+
</div>
|
|
104
|
+
))
|
|
105
|
+
: null}
|
|
106
|
+
</div>
|
|
107
|
+
)}
|
|
108
|
+
</section>
|
|
109
|
+
);
|
|
110
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { Icon } from '@iconify/react';
|
|
4
|
+
|
|
5
|
+
const BaseModal = ({
|
|
6
|
+
isOpen = false,
|
|
7
|
+
content,
|
|
8
|
+
height,
|
|
9
|
+
className,
|
|
10
|
+
onClose,
|
|
11
|
+
showCloseIcon = false,
|
|
12
|
+
fixCloseBtn = false,
|
|
13
|
+
}) =>
|
|
14
|
+
isOpen && (
|
|
15
|
+
<div className="fixed top-0 left-0 h-full z-[1000] p-4 duration-300 transition-opacity bg-[#000000b3] w-full">
|
|
16
|
+
<div className="w-full h-full flex justify-center items-center relative">
|
|
17
|
+
{showCloseIcon && (
|
|
18
|
+
<div className="text-right p-2 absolute right-0 top-0">
|
|
19
|
+
<Icon
|
|
20
|
+
className="ml-auto cursor-pointer text-white"
|
|
21
|
+
icon="ion:close"
|
|
22
|
+
width="24"
|
|
23
|
+
height="24"
|
|
24
|
+
onClick={onClose}
|
|
25
|
+
/>
|
|
26
|
+
</div>
|
|
27
|
+
)}
|
|
28
|
+
<div
|
|
29
|
+
className={[
|
|
30
|
+
'bg-white rounded-xl overflow-y-auto m-auto',
|
|
31
|
+
fixCloseBtn ? '' : 'max-w-[932px] max-h-[90vh]',
|
|
32
|
+
height,
|
|
33
|
+
className,
|
|
34
|
+
].join(' ')}
|
|
35
|
+
>
|
|
36
|
+
{content}
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
BaseModal.propTypes = {
|
|
43
|
+
isOpen: PropTypes.bool,
|
|
44
|
+
content: PropTypes.element,
|
|
45
|
+
height: PropTypes.string,
|
|
46
|
+
className: PropTypes.string,
|
|
47
|
+
onClose: PropTypes.func,
|
|
48
|
+
showCloseIcon: PropTypes.bool,
|
|
49
|
+
fixCloseBtn: PropTypes.bool,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default BaseModal;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Icon } from '@iconify/react';
|
|
3
|
+
import ModalContent from './ModalContent';
|
|
4
|
+
|
|
5
|
+
interface ErrorContentProps {
|
|
6
|
+
setModal: any;
|
|
7
|
+
errmsg: React.ReactNode | string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const ErrorContent: React.FC<ErrorContentProps> = ({ setModal, errmsg }) => (
|
|
11
|
+
<ModalContent setModal={setModal} onClick={setModal} notice>
|
|
12
|
+
<div className="w-full max-w-xl">
|
|
13
|
+
<div className="flex justify-center items-center mb-6">
|
|
14
|
+
<Icon icon="fluent-mdl2:status-error-full" color="red" height={60} />
|
|
15
|
+
</div>
|
|
16
|
+
<div className="text-center text-lg text-gray-500">{errmsg}</div>
|
|
17
|
+
</div>
|
|
18
|
+
</ModalContent>
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
export default ErrorContent;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
|
|
4
|
+
const FullScreenModal = ({ overHidden, isOpen, children }) => {
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
if (overHidden) return;
|
|
7
|
+
// 在 Modal 打開時,禁止滾動
|
|
8
|
+
if (isOpen) {
|
|
9
|
+
document.body.style.overflow = 'hidden';
|
|
10
|
+
} else {
|
|
11
|
+
// 在 Modal 關閉時,啟用滾動
|
|
12
|
+
document.body.style.overflow = 'visible';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// 在組件卸載時清除樣式
|
|
16
|
+
// eslint-disable-next-line consistent-return
|
|
17
|
+
return () => {
|
|
18
|
+
document.body.style.overflow = 'visible';
|
|
19
|
+
};
|
|
20
|
+
}, [isOpen]);
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div
|
|
24
|
+
className={`fixed top-0 left-0 w-full h-full overflow-hidden flex items-center justify-center z-[9999] bg-black bg-opacity-10 ${
|
|
25
|
+
isOpen ? 'block' : 'hidden'
|
|
26
|
+
}`}
|
|
27
|
+
>
|
|
28
|
+
<div className="modal-content bg-white p-[30px] rounded-lg relative">{children}</div>
|
|
29
|
+
</div>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
FullScreenModal.propTypes = {
|
|
34
|
+
isOpen: PropTypes.bool.isRequired,
|
|
35
|
+
children: PropTypes.node.isRequired,
|
|
36
|
+
overHidden: PropTypes.bool,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default FullScreenModal;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React, { useEffect, KeyboardEvent } from 'react';
|
|
2
|
+
|
|
3
|
+
interface ModalProps {
|
|
4
|
+
modal: React.ReactElement;
|
|
5
|
+
unsetModal?: () => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const Modal: React.FC<ModalProps> = ({ modal, unsetModal = () => {} }) => {
|
|
9
|
+
const handleKeyUp = (e: any) => {
|
|
10
|
+
if (
|
|
11
|
+
e.key === 'Escape' &&
|
|
12
|
+
!['INPUT', 'SELECT'].includes(
|
|
13
|
+
(document.activeElement as HTMLElement)?.tagName
|
|
14
|
+
)
|
|
15
|
+
) {
|
|
16
|
+
unsetModal();
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
document.addEventListener('keyup', handleKeyUp);
|
|
22
|
+
return () => document.removeEventListener('keyup', handleKeyUp);
|
|
23
|
+
}, [unsetModal]);
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div className="fixed top-0 left-0 h-screen z-[2000] transition-opacity duration-300 transition-opacity bg-[#000000b3] w-full">
|
|
27
|
+
<div className="w-full h-full flex justify-center items-center p-6">
|
|
28
|
+
<div className="bg-white rounded overflow-y-auto w-full m-auto max-w-[455px] rounded-xl">
|
|
29
|
+
{modal}
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default Modal;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
interface ModalContentProps {
|
|
4
|
+
title?: string;
|
|
5
|
+
setModal?: any;
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
onClick?: any;
|
|
8
|
+
notice?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const ModalContent: React.FC<ModalContentProps> = ({
|
|
12
|
+
title,
|
|
13
|
+
setModal,
|
|
14
|
+
children,
|
|
15
|
+
onClick,
|
|
16
|
+
notice = false,
|
|
17
|
+
}) => (
|
|
18
|
+
<form>
|
|
19
|
+
{title && (
|
|
20
|
+
<div className="text-2xl text-gray-700 font-medium border-solid border-b border-gray-300 mb-4 p-4">
|
|
21
|
+
{title}
|
|
22
|
+
</div>
|
|
23
|
+
)}
|
|
24
|
+
|
|
25
|
+
{children && <div className="py-4 px-8">{children}</div>}
|
|
26
|
+
|
|
27
|
+
<div className="flex items-center text-base p-4 px-8 justify-around">
|
|
28
|
+
{notice ? (
|
|
29
|
+
<button
|
|
30
|
+
type="button"
|
|
31
|
+
className="w-24 h-10 px-2 text-white bg-gray-600 rounded"
|
|
32
|
+
onClick={setModal}
|
|
33
|
+
>
|
|
34
|
+
確定
|
|
35
|
+
</button>
|
|
36
|
+
) : (
|
|
37
|
+
<>
|
|
38
|
+
<button
|
|
39
|
+
type="button"
|
|
40
|
+
className="w-24 h-10 px-2 text-white bg-gray-600 rounded"
|
|
41
|
+
onClick={setModal}
|
|
42
|
+
>
|
|
43
|
+
取消
|
|
44
|
+
</button>
|
|
45
|
+
{onClick && (
|
|
46
|
+
<button
|
|
47
|
+
type="button"
|
|
48
|
+
className="w-24 h-10 mx-3 text-white bg-gray-500 rounded"
|
|
49
|
+
onClick={onClick}
|
|
50
|
+
>
|
|
51
|
+
送出
|
|
52
|
+
</button>
|
|
53
|
+
)}
|
|
54
|
+
</>
|
|
55
|
+
)}
|
|
56
|
+
</div>
|
|
57
|
+
</form>
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
export default ModalContent;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { Icon } from '@iconify/react';
|
|
4
|
+
|
|
5
|
+
const NoticeModal = ({
|
|
6
|
+
title,
|
|
7
|
+
buttonName,
|
|
8
|
+
content,
|
|
9
|
+
setModal,
|
|
10
|
+
onClick,
|
|
11
|
+
onlyCheck,
|
|
12
|
+
action,
|
|
13
|
+
cancelButtonName = '取消',
|
|
14
|
+
cancelFunc,
|
|
15
|
+
}) => {
|
|
16
|
+
const statusCode = action?.statusCode;
|
|
17
|
+
|
|
18
|
+
const actionFunc = () => {
|
|
19
|
+
if (statusCode === 'book_dates') return action?.resetCalendar();
|
|
20
|
+
if (statusCode === 'book_expired') return action?.redirectBook();
|
|
21
|
+
if (statusCode === 'not_registered_2times') return action?.redirectToPay();
|
|
22
|
+
return null;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const actionName =
|
|
26
|
+
statusCode === 'book_dates' ? action?.resetCalendarName : action?.redirectCalendarName;
|
|
27
|
+
|
|
28
|
+
const onlyCheckList = ['points', 'tickets', 'promo_tickets', 'member_group'];
|
|
29
|
+
|
|
30
|
+
const onlyCheckAction = onlyCheck || onlyCheckList.includes(statusCode);
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<div className="px-8 py-9">
|
|
34
|
+
<button className="w-full flex justify-end" type="button" onClick={() => setModal()}>
|
|
35
|
+
<Icon className="text-[#000000]" icon="ic:baseline-close" width="24" height="24" />
|
|
36
|
+
</button>
|
|
37
|
+
<div className="text-[28px] text-gray-700 font-medium min-w-[16rem] pb-2">{title}</div>
|
|
38
|
+
|
|
39
|
+
<div className="text-[20px] text-[#5A5A5A] pb-8">
|
|
40
|
+
<div>{content}</div>
|
|
41
|
+
</div>
|
|
42
|
+
<div className="flex items-center text-lg text-base justify-center gap-8">
|
|
43
|
+
{onlyCheckAction ? (
|
|
44
|
+
<button
|
|
45
|
+
type="button"
|
|
46
|
+
className={['px-8 py-3 px-2 text-white bg-[#0C7489] rounded-[10px]'].join(' ')}
|
|
47
|
+
onClick={() => {
|
|
48
|
+
setModal();
|
|
49
|
+
}}
|
|
50
|
+
>
|
|
51
|
+
確認
|
|
52
|
+
</button>
|
|
53
|
+
) : (
|
|
54
|
+
<>
|
|
55
|
+
<button
|
|
56
|
+
type="button"
|
|
57
|
+
className={[
|
|
58
|
+
'px-6 lg:px-8 py-3 rounded-[10px]',
|
|
59
|
+
'border border-solid border-[#656565] text-[#5A5A5A] bg-[#F5F5F5]',
|
|
60
|
+
].join(' ')}
|
|
61
|
+
onClick={() => (cancelFunc ? cancelFunc() : setModal())}
|
|
62
|
+
>
|
|
63
|
+
{cancelButtonName}
|
|
64
|
+
</button>
|
|
65
|
+
<button
|
|
66
|
+
type="button"
|
|
67
|
+
className="px-6 lg:px-8 py-3 text-white bg-[#0C7489] rounded-[10px]"
|
|
68
|
+
onClick={statusCode ? actionFunc : onClick}
|
|
69
|
+
>
|
|
70
|
+
{actionName || buttonName}
|
|
71
|
+
</button>
|
|
72
|
+
</>
|
|
73
|
+
)}
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
NoticeModal.propTypes = {
|
|
80
|
+
setModal: PropTypes.func,
|
|
81
|
+
title: PropTypes.string,
|
|
82
|
+
buttonName: PropTypes.string,
|
|
83
|
+
content: PropTypes.node,
|
|
84
|
+
onClick: PropTypes.func,
|
|
85
|
+
onlyCheck: PropTypes.bool,
|
|
86
|
+
action: PropTypes.shape(),
|
|
87
|
+
cancelButtonName: PropTypes.string,
|
|
88
|
+
cancelFunc: PropTypes.func,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export default NoticeModal;
|