@qlover/create-app 0.3.3 → 0.3.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 (43) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/package.json +3 -3
  3. package/templates/react-app/README.md +311 -120
  4. package/templates/react-app/config/Identifier.I18n.ts +170 -0
  5. package/templates/react-app/config/common.ts +13 -0
  6. package/templates/react-app/package.json +4 -2
  7. package/templates/react-app/public/locales/en/common.json +25 -1
  8. package/templates/react-app/public/locales/zh/common.json +25 -1
  9. package/templates/react-app/src/App.tsx +5 -4
  10. package/templates/react-app/src/base/apis/AiApi.ts +4 -4
  11. package/templates/react-app/src/base/apis/feApi/FeApiAdapter.ts +2 -2
  12. package/templates/react-app/src/base/apis/userApi/UserApiAdapter.ts +2 -2
  13. package/templates/react-app/src/base/cases/AppConfig.ts +103 -0
  14. package/templates/react-app/src/base/cases/{appError/AppError.ts → AppError.ts} +0 -3
  15. package/templates/react-app/src/base/cases/DialogHandler.ts +86 -0
  16. package/templates/react-app/src/base/cases/RouterLoader.ts +166 -0
  17. package/templates/react-app/src/base/port/InteractionHubInterface.ts +94 -0
  18. package/templates/react-app/src/base/services/I18nService.ts +19 -0
  19. package/templates/react-app/src/base/types/deprecated-antd.d.ts +60 -0
  20. package/templates/react-app/src/core/IOC.ts +6 -1
  21. package/templates/react-app/src/core/bootstrap.ts +21 -31
  22. package/templates/react-app/src/core/globals.ts +8 -1
  23. package/templates/react-app/src/core/registers/RegisterGlobals.ts +11 -7
  24. package/templates/react-app/src/core/registers/index.ts +1 -2
  25. package/templates/react-app/src/pages/base/About.tsx +114 -1
  26. package/templates/react-app/src/pages/base/Executor.tsx +10 -15
  27. package/templates/react-app/src/styles/css/antd-themes/_default.css +239 -0
  28. package/templates/react-app/src/styles/css/antd-themes/dark.css +176 -0
  29. package/templates/react-app/src/styles/css/antd-themes/index.css +3 -0
  30. package/templates/react-app/src/styles/css/antd-themes/no-context.css +34 -0
  31. package/templates/react-app/src/styles/css/antd-themes/pink.css +199 -0
  32. package/templates/react-app/src/styles/css/index.css +3 -0
  33. package/templates/react-app/src/styles/css/themes/_default.css +10 -181
  34. package/templates/react-app/src/styles/css/themes/dark.css +10 -135
  35. package/templates/react-app/src/styles/css/themes/pink.css +10 -141
  36. package/templates/react-app/src/uikit/components/RouterRenderComponent.tsx +1 -1
  37. package/templates/react-app/src/uikit/controllers/RouterController.ts +1 -1
  38. package/templates/react-app/src/uikit/controllers/UserController.ts +1 -1
  39. package/templates/react-app/tsconfig.json +3 -2
  40. package/templates/react-app/tsconfig.node.json +2 -1
  41. package/templates/react-app/vite.config.ts +8 -2
  42. package/templates/react-app/src/base/cases/router-loader/index.ts +0 -90
  43. package/templates/react-app/src/core/AppConfig.ts +0 -36
@@ -0,0 +1,166 @@
1
+ import type { ComponentType, LazyExoticComponent, ReactNode } from 'react';
2
+ import { RouteObject } from 'react-router-dom';
3
+ import isString from 'lodash/isString';
4
+
5
+ /**
6
+ * Component mapping type for lazy-loaded components
7
+ * @description Maps component identifiers to their lazy-loaded implementations
8
+ */
9
+ export type ComponentValue = Record<string, () => unknown>;
10
+
11
+ /**
12
+ * Route component type definition supporting both regular and lazy-loaded components
13
+ */
14
+ type RouteComponentType<T = unknown> =
15
+ | ComponentType<T>
16
+ | LazyExoticComponent<ComponentType<T>>;
17
+
18
+ /**
19
+ * Extended route configuration interface
20
+ * @description Extends React Router's RouteObject with additional meta information
21
+ */
22
+ export type RouteConfigValue = Omit<RouteObject, 'element' | 'children'> & {
23
+ /**
24
+ * Component identifier string that maps to a component in componentMaps
25
+ *
26
+ * TODO: support `ReactNode`
27
+ *
28
+ * @description Used to lookup the actual component implementation
29
+ */
30
+ element?: string;
31
+
32
+ /**
33
+ * Nested route configurations
34
+ */
35
+ children?: RouteConfigValue[];
36
+
37
+ /**
38
+ * Additional metadata for the route
39
+ * @description Can store any route-specific data like permissions, titles, etc.
40
+ */
41
+ meta?: Record<string, unknown>;
42
+ };
43
+
44
+ /**
45
+ * Route rendering function type
46
+ * @description Function to customize how route components are rendered
47
+ */
48
+ export type RouterLoaderRender = (
49
+ route: Omit<RouteConfigValue, 'element'> & {
50
+ element: () => RouteComponentType;
51
+ }
52
+ ) => ReactNode;
53
+
54
+ /**
55
+ * Router loader configuration options
56
+ */
57
+ export type RouterLoaderOptions = {
58
+ /**
59
+ * Route configuration array
60
+ * @description Defines the application's routing structure
61
+ */
62
+ routes?: RouteConfigValue[];
63
+
64
+ /**
65
+ * Component mapping object
66
+ * @description Maps component identifiers to their actual implementations
67
+ * @example
68
+ * {
69
+ * 'Home': () => import('./pages/Home'),
70
+ * 'About': () => import('./pages/About')
71
+ * }
72
+ */
73
+ componentMaps?: ComponentValue;
74
+
75
+ /**
76
+ * Custom route rendering function
77
+ * @description Controls how route components are rendered
78
+ * @required
79
+ */
80
+ render: RouterLoaderRender;
81
+ };
82
+
83
+ /**
84
+ * Router Configuration Loader
85
+ *
86
+ * Significance: Manages dynamic route configuration and component loading
87
+ * Core idea: Separate route definitions from component implementations
88
+ * Main function: Transform route configurations into React Router compatible routes
89
+ * Main purpose: Enable dynamic and code-split routing with lazy loading
90
+ *
91
+ * @example
92
+ * const loader = new RouterLoader({
93
+ * routes: [{
94
+ * path: '/',
95
+ * element: 'Home',
96
+ * children: [{
97
+ * path: 'about',
98
+ * element: 'About'
99
+ * }]
100
+ * }],
101
+ * componentMaps: {
102
+ * 'Home': () => import('./pages/Home'),
103
+ * 'About': () => import('./pages/About')
104
+ * },
105
+ * render: (route) => <Suspense><route.element /></Suspense>
106
+ * });
107
+ */
108
+ export class RouterLoader {
109
+ constructor(private readonly options: RouterLoaderOptions) {
110
+ if (!options.render) {
111
+ throw new Error('RouterLoader render is required');
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Get the component mapping object
117
+ * @returns Component mapping dictionary
118
+ */
119
+ getComponentMaps(): ComponentValue {
120
+ const { componentMaps = {} } = this.options;
121
+ return componentMaps;
122
+ }
123
+
124
+ /**
125
+ * Retrieve a component implementation by its identifier
126
+ * @param element Component identifier string
127
+ * @returns Component loader function
128
+ * @throws Error if component is not found in componentMaps
129
+ */
130
+ getComponent(element: string): () => RouteComponentType {
131
+ const maps = this.getComponentMaps();
132
+ const component = maps[element];
133
+
134
+ if (!component) {
135
+ throw new Error(`Component not found: ${element}`);
136
+ }
137
+
138
+ return component as () => RouteComponentType;
139
+ }
140
+
141
+ /**
142
+ * Transform a route configuration into a React Router compatible route
143
+ * @param route Route configuration object
144
+ * @returns React Router route object
145
+ */
146
+ toRoute(route: RouteConfigValue): RouteObject {
147
+ const { render } = this.options;
148
+ const { element, children, ...rest } = route;
149
+
150
+ if (!element || !isString(element)) {
151
+ console.warn(
152
+ `Invalid route, path is: ${route.path}, element is: ${element}`
153
+ );
154
+ }
155
+
156
+ const componet = this.getComponent(element || '404');
157
+ const Element = render({ ...rest, element: componet });
158
+
159
+ // @ts-expect-error
160
+ return {
161
+ ...rest,
162
+ element: Element,
163
+ children: children?.map((child) => this.toRoute(child))
164
+ };
165
+ }
166
+ }
@@ -0,0 +1,94 @@
1
+ import type { ModalFuncProps } from 'antd';
2
+
3
+ /**
4
+ * Confirmation dialog configuration options
5
+ * Extends Ant Design's ModalFuncProps and requires a title
6
+ */
7
+ export interface ConfirmOptions extends ModalFuncProps {
8
+ content: string;
9
+ }
10
+
11
+ /**
12
+ * Basic dialog configuration options
13
+ */
14
+ export interface InteractionOptions {
15
+ /** Display duration (milliseconds) */
16
+ duration?: number;
17
+ /** Close callback function */
18
+ onClose?: () => void;
19
+ /** Error object */
20
+ error?: unknown;
21
+ }
22
+
23
+ /**
24
+ * Interaction Hub Interface
25
+ *
26
+ * This interface serves as the central interaction layer for the application,
27
+ * managing all user interface interactions, notifications, and feedback functionality.
28
+ * Main responsibilities include:
29
+ * 1. Providing a unified message notification mechanism (success/error/info/warn)
30
+ * 2. Handling user interaction confirmation scenarios (confirm)
31
+ * 3. Unified error display and handling approach
32
+ *
33
+ * Design Goals:
34
+ * - Uniformity: Provide consistent user interaction experience
35
+ * - Extensibility: Easy to add new interaction types
36
+ * - Configurability: Support custom interaction behaviors
37
+ * - Decoupling: Separate UI interaction layer from business logic
38
+ *
39
+ * Use Cases:
40
+ * - Operation success/failure feedback
41
+ * - Important operation confirmation prompts
42
+ * - System message notifications
43
+ * - Warning message display
44
+ *
45
+ * Implementation Notes:
46
+ * - Currently implemented based on Ant Design component library
47
+ * - Supports other UI libraries through different adapters
48
+ * - Supports global configuration of default behaviors
49
+ *
50
+ * @example
51
+ * // Success notification
52
+ * interactionHub.success("Operation successful", { duration: 3000 });
53
+ *
54
+ * // Confirmation dialog
55
+ * interactionHub.confirm({
56
+ * content: "Are you sure you want to delete?",
57
+ * onOk: () => handleDelete()
58
+ * });
59
+ */
60
+ export interface InteractionHubInterface {
61
+ /**
62
+ * Display success notification
63
+ * @param message Notification message
64
+ * @param options Configuration options
65
+ */
66
+ success(message: string, options?: InteractionOptions): void;
67
+
68
+ /**
69
+ * Display error notification
70
+ * @param message Error message
71
+ * @param options Configuration options
72
+ */
73
+ error(message: string, options?: InteractionOptions): void;
74
+
75
+ /**
76
+ * Display information notification
77
+ * @param message Information message
78
+ * @param options Configuration options
79
+ */
80
+ info(message: string, options?: InteractionOptions): void;
81
+
82
+ /**
83
+ * Display warning notification
84
+ * @param message Warning message
85
+ * @param options Configuration options
86
+ */
87
+ warn(message: string, options?: InteractionOptions): void;
88
+
89
+ /**
90
+ * Display confirmation dialog
91
+ * @param options Confirmation dialog configuration options
92
+ */
93
+ confirm(options: ConfirmOptions): void;
94
+ }
@@ -88,4 +88,23 @@ export class I18nService
88
88
  static isValidLanguage(language: string): language is I18nServiceLocale {
89
89
  return supportedLngs.includes(language as I18nServiceLocale);
90
90
  }
91
+
92
+ /**
93
+ * translate the key
94
+ * @param key - key to translate
95
+ * @param params - params to pass to the translation
96
+ * @returns translated value
97
+ */
98
+ t(key: string, params?: Record<string, unknown>): string {
99
+ const i18nValue = i18n.t(key, {
100
+ lng: i18n.language,
101
+ ...params
102
+ });
103
+
104
+ if (!i18nValue || i18nValue === key) {
105
+ return key;
106
+ }
107
+
108
+ return i18nValue;
109
+ }
91
110
  }
@@ -0,0 +1,60 @@
1
+ import AntdMessageStatic from 'antd/es/message';
2
+ import { TypeOpen } from 'antd/es/message/interface';
3
+ import AntdModalStatic from 'antd/es/modal';
4
+
5
+ import { ModalFunc } from 'antd/es/modal/confirm';
6
+
7
+ declare module 'antd' {
8
+ /**
9
+ * @deprecated Please use alternative message implementation instead
10
+ */
11
+ export const message: typeof AntdMessageStatic & {
12
+ /**
13
+ * @deprecated Please use alternative message implementation instead
14
+ */
15
+ info: TypeOpen;
16
+ /**
17
+ * @deprecated Please use alternative message implementation instead
18
+ */
19
+ success: TypeOpen;
20
+ /**
21
+ * @deprecated Please use alternative message implementation instead
22
+ */
23
+ error: TypeOpen;
24
+ /**
25
+ * @deprecated Please use alternative message implementation instead
26
+ */
27
+ warning: TypeOpen;
28
+ /**
29
+ * @deprecated Please use alternative message implementation instead
30
+ */
31
+ loading: TypeOpen;
32
+ };
33
+
34
+ export const Modal: typeof AntdModalStatic & {
35
+ /**
36
+ * @deprecated Please use alternative message implementation instead
37
+ */
38
+ confirm: ModalFunc;
39
+ /**
40
+ * @deprecated Please use alternative message implementation instead
41
+ */
42
+ info: ModalFunc;
43
+ /**
44
+ * @deprecated Please use alternative message implementation instead
45
+ */
46
+ success: ModalFunc;
47
+ /**
48
+ * @deprecated Please use alternative message implementation instead
49
+ */
50
+ error: ModalFunc;
51
+ /**
52
+ * @deprecated Please use alternative message implementation instead
53
+ */
54
+ warn: ModalFunc;
55
+ /**
56
+ * @deprecated Please use alternative message implementation instead
57
+ */
58
+ warning: ModalFunc;
59
+ };
60
+ }
@@ -11,11 +11,14 @@ import {
11
11
  } from '@qlover/corekit-bridge';
12
12
  import type { JSONSerializer, JSONStorage } from '@qlover/fe-corekit';
13
13
  import type { LoggerInterface } from '@qlover/logger';
14
+ import type { AppConfig } from '@/base/cases/AppConfig';
14
15
  import { Container } from 'inversify';
15
16
  import { IOCRegisterInterface } from '@qlover/corekit-bridge';
17
+ import { DialogHandler } from '@/base/cases/DialogHandler';
16
18
 
17
19
  export type IocRegisterOptions = {
18
20
  pathname: string;
21
+ appConfig: AppConfig;
19
22
  };
20
23
 
21
24
  export type InversifyRegisterContainer = Container;
@@ -72,7 +75,8 @@ export const IOCIdentifier = Object.freeze({
72
75
  FeApiCommonPlugin: 'FeApiCommonPlugin',
73
76
  AppConfig: 'AppConfig',
74
77
  ApiMockPlugin: 'ApiMockPlugin',
75
- ApiCatchPlugin: 'ApiCatchPlugin'
78
+ ApiCatchPlugin: 'ApiCatchPlugin',
79
+ DialogHandler: 'DialogHandler'
76
80
  });
77
81
 
78
82
  /**
@@ -87,6 +91,7 @@ export interface IOCIdentifierMap {
87
91
  [IOCIdentifier.AppConfig]: EnvConfigInterface;
88
92
  [IOCIdentifier.ApiMockPlugin]: ApiMockPlugin;
89
93
  [IOCIdentifier.ApiCatchPlugin]: ApiCatchPlugin;
94
+ [IOCIdentifier.DialogHandler]: DialogHandler;
90
95
  }
91
96
 
92
97
  export const IOC = createIOCFunction<IOCIdentifierMap>(
@@ -1,11 +1,4 @@
1
- import {
2
- Bootstrap,
3
- type InjectGlobalConfig,
4
- type InjectIOCOptions,
5
- type IOCContainerInterface,
6
- type InjectEnvConfig
7
- } from '@qlover/corekit-bridge';
8
- import AppConfig from '@/core/AppConfig';
1
+ import { Bootstrap } from '@qlover/corekit-bridge';
9
2
  import { envBlackList, envPrefix, browserGlobalsName } from '@config/common';
10
3
  import { IOC } from './IOC';
11
4
  import * as globals from '@/core/globals';
@@ -24,33 +17,30 @@ export default async function startup({
24
17
  throw new Error(GLOBAL_NO_WINDOW);
25
18
  }
26
19
 
27
- const { logger } = globals;
20
+ const { logger, appConfig } = globals;
28
21
 
29
- const envOptions: InjectEnvConfig = {
30
- target: AppConfig,
31
- source: envSource,
32
- prefix: envPrefix,
33
- blackList: envBlackList
34
- };
35
-
36
- const iocOptions: InjectIOCOptions<IOCContainerInterface> = {
37
- manager: IOC,
38
- register: new IocRegister({
39
- pathname: root.location.pathname
40
- })
41
- };
42
-
43
- const globalOptions: InjectGlobalConfig = {
44
- sources: globals,
45
- target: browserGlobalsName
46
- };
22
+ const iocRegister = new IocRegister({
23
+ pathname: root.location.pathname,
24
+ appConfig
25
+ });
47
26
 
48
27
  const bootstrap = new Bootstrap({
49
28
  root,
50
29
  logger,
51
- ioc: iocOptions,
52
- envOptions,
53
- globalOptions
30
+ ioc: {
31
+ manager: IOC,
32
+ register: iocRegister
33
+ },
34
+ envOptions: {
35
+ target: appConfig,
36
+ source: envSource,
37
+ prefix: envPrefix,
38
+ blackList: envBlackList
39
+ },
40
+ globalOptions: {
41
+ sources: globals,
42
+ target: browserGlobalsName
43
+ }
54
44
  });
55
45
 
56
46
  try {
@@ -63,6 +53,6 @@ export default async function startup({
63
53
 
64
54
  await bootstrap.use(bootstrapsRegistry.register()).start();
65
55
  } catch (error) {
66
- logger.error(`${AppConfig.appName} starup error:`, error);
56
+ logger.error(`${appConfig.appName} starup error:`, error);
67
57
  }
68
58
  }
@@ -1,14 +1,21 @@
1
1
  // ! global variables, don't import any dependencies and don't have side effects
2
2
  import { JSONStorage, JSONSerializer, SyncStorage } from '@qlover/fe-corekit';
3
3
  import { ColorFormatter, ConsoleHandler, Logger } from '@qlover/corekit-bridge';
4
+ import { DialogHandler } from '@/base/cases/DialogHandler';
5
+ import { loggerStyles } from '@config/common';
6
+ import { AppConfig } from '@/base/cases/AppConfig';
4
7
 
5
8
  const isProduction = import.meta.env.VITE_USER_NODE_ENV === 'production';
6
9
 
10
+ export const appConfig = new AppConfig();
11
+
12
+ export const dialogHandler = new DialogHandler();
13
+
7
14
  /**
8
15
  * Global logger
9
16
  */
10
17
  export const logger = new Logger({
11
- handlers: new ConsoleHandler(new ColorFormatter()),
18
+ handlers: new ConsoleHandler(new ColorFormatter(loggerStyles)),
12
19
  silent: isProduction
13
20
  });
14
21
 
@@ -1,19 +1,23 @@
1
1
  import { JSONSerializer, JSONStorage } from '@qlover/fe-corekit';
2
- import type { EnvConfigInterface } from '@qlover/corekit-bridge';
3
- import { JSON, localJsonStorage, logger } from '../globals';
2
+ import type { IOCManagerInterface } from '@qlover/corekit-bridge';
3
+ import { dialogHandler, JSON, localJsonStorage, logger } from '../globals';
4
4
  import {
5
5
  type InversifyContainer,
6
6
  type InversifyRegisterInterface,
7
- IOCIdentifier
7
+ IOCIdentifier,
8
+ IocRegisterOptions
8
9
  } from '@/core/IOC';
9
10
  import { Logger } from '@qlover/logger';
10
11
 
11
12
  export class RegisterGlobals implements InversifyRegisterInterface {
12
- constructor(private appConfig: EnvConfigInterface) {}
13
-
14
- register(container: InversifyContainer): void {
13
+ register(
14
+ container: InversifyContainer,
15
+ _: IOCManagerInterface<InversifyContainer>,
16
+ options: IocRegisterOptions
17
+ ): void {
15
18
  // inject AppConfig to IOC
16
- container.bind(IOCIdentifier.AppConfig, this.appConfig);
19
+ container.bind(IOCIdentifier.AppConfig, options.appConfig);
20
+ container.bind(IOCIdentifier.DialogHandler, dialogHandler);
17
21
 
18
22
  container.bind(JSONSerializer, JSON);
19
23
  container.bind(IOCIdentifier.JSON, JSON);
@@ -2,7 +2,6 @@ import { RegisterGlobals } from './RegisterGlobals';
2
2
  import { RegisterCommon } from './RegisterCommon';
3
3
  import { RegisterApi } from './RegisterApi';
4
4
  import { RegisterControllers } from './RegisterControllers';
5
- import AppConfig from '../AppConfig';
6
5
  import {
7
6
  InversifyContainer,
8
7
  InversifyRegisterInterface,
@@ -15,7 +14,7 @@ export class IocRegister implements InversifyRegisterInterface {
15
14
 
16
15
  getRegisterList(): InversifyRegisterInterface[] {
17
16
  return [
18
- new RegisterGlobals(AppConfig),
17
+ new RegisterGlobals(),
19
18
  new RegisterCommon(),
20
19
  new RegisterApi(),
21
20
  new RegisterControllers()
@@ -1,14 +1,127 @@
1
1
  import { useBaseRoutePage } from '@/uikit/contexts/BaseRouteContext';
2
2
  import * as i18nKeys from '@config/Identifier.I18n';
3
+ import {
4
+ Button,
5
+ Tooltip,
6
+ message,
7
+ notification,
8
+ Modal,
9
+ Drawer,
10
+ Popover,
11
+ Popconfirm,
12
+ Alert
13
+ } from 'antd';
14
+ import { useState } from 'react';
3
15
 
4
16
  export default function About() {
5
17
  const { t } = useBaseRoutePage();
18
+ const [messageApi, contextHolder] = message.useMessage();
19
+ const [notificationApi, contextHolder2] = notification.useNotification();
20
+ const [isModalOpen, setIsModalOpen] = useState(false);
21
+ const [isDrawerOpen, setIsDrawerOpen] = useState(false);
22
+
23
+ const showMessage = () => {
24
+ messageApi.info(t(i18nKeys.ABOUT_MESSAGE_TEST), 2000);
25
+ };
26
+
27
+ const showNotification = () => {
28
+ notificationApi.open({
29
+ message: t(i18nKeys.ABOUT_NOTIFICATION_TITLE),
30
+ description: t(i18nKeys.ABOUT_NOTIFICATION_DESC),
31
+ duration: 2000
32
+ });
33
+ };
34
+ const showNotification2 = () => {
35
+ notification.open({
36
+ message: t(i18nKeys.ABOUT_NOTIFICATION_TITLE),
37
+ description: t(i18nKeys.ABOUT_NOTIFICATION_DESC),
38
+ duration: 2000
39
+ });
40
+ };
41
+
42
+ const showModal = () => {
43
+ setIsModalOpen(true);
44
+ };
45
+ const showMessage2 = () => {
46
+ message.info(t(i18nKeys.ABOUT_MESSAGE_TEST), 200);
47
+ };
48
+
49
+ const showDrawer = () => {
50
+ setIsDrawerOpen(true);
51
+ };
52
+
6
53
  return (
7
54
  <div className="min-h-screen bg-primary py-6 flex flex-col justify-center sm:py-12">
55
+ {contextHolder}
56
+ {contextHolder2}
8
57
  <div className="relative py-3 sm:max-w-xl sm:mx-auto">
9
- <h1 className="text-2xl font-bold text-center text-text">
58
+ <h1 className="text-2xl font-bold text-center text-text mb-8">
10
59
  {t(i18nKeys.PAGE_ABOUT_TITLE)}
11
60
  </h1>
61
+
62
+ <div className="space-x-4 flex justify-center flex-wrap gap-4">
63
+ <Button onClick={showMessage}>{t(i18nKeys.ABOUT_BTN_MESSAGE)}</Button>
64
+ <Button onClick={showMessage2}>
65
+ {t(i18nKeys.ABOUT_BTN_MESSAGE2)}
66
+ </Button>
67
+
68
+ <Button onClick={showNotification}>
69
+ {t(i18nKeys.ABOUT_BTN_NOTIFICATION)}
70
+ </Button>
71
+
72
+ <Button onClick={showNotification2}>
73
+ {t(i18nKeys.ABOUT_BTN_NOTIFICATION2)}
74
+ </Button>
75
+
76
+ <Tooltip title={t(i18nKeys.ABOUT_TOOLTIP_TEXT)}>
77
+ <Button>{t(i18nKeys.ABOUT_BTN_TOOLTIP)}</Button>
78
+ </Tooltip>
79
+
80
+ <Modal
81
+ title={t(i18nKeys.ABOUT_MODAL_TITLE)}
82
+ open={isModalOpen}
83
+ onOk={() => setIsModalOpen(false)}
84
+ onCancel={() => setIsModalOpen(false)}
85
+ >
86
+ <p>{t(i18nKeys.ABOUT_MODAL_CONTENT)}</p>
87
+ </Modal>
88
+
89
+ <Button onClick={showModal}>{t(i18nKeys.ABOUT_BTN_MODAL)}</Button>
90
+
91
+ <Drawer
92
+ title={t(i18nKeys.ABOUT_DRAWER_TITLE)}
93
+ open={isDrawerOpen}
94
+ onClose={() => setIsDrawerOpen(false)}
95
+ >
96
+ <p>{t(i18nKeys.ABOUT_DRAWER_CONTENT)}</p>
97
+ </Drawer>
98
+
99
+ <Button onClick={showDrawer}>{t(i18nKeys.ABOUT_BTN_DRAWER)}</Button>
100
+
101
+ <Popover
102
+ content={t(i18nKeys.ABOUT_POPOVER_CONTENT)}
103
+ title={t(i18nKeys.ABOUT_POPOVER_TITLE)}
104
+ >
105
+ <Button>{t(i18nKeys.ABOUT_BTN_POPOVER)}</Button>
106
+ </Popover>
107
+
108
+ <Popconfirm
109
+ title={t(i18nKeys.ABOUT_POPCONFIRM_TITLE)}
110
+ description={t(i18nKeys.ABOUT_POPCONFIRM_DESC)}
111
+ okText={t(i18nKeys.COMMON_OK)}
112
+ cancelText={t(i18nKeys.COMMON_CANCEL)}
113
+ >
114
+ <Button>{t(i18nKeys.ABOUT_BTN_POPCONFIRM)}</Button>
115
+ </Popconfirm>
116
+
117
+ <Alert
118
+ message={t(i18nKeys.ABOUT_ALERT_MESSAGE)}
119
+ type="warning"
120
+ showIcon
121
+ closable
122
+ className="mt-4"
123
+ />
124
+ </div>
12
125
  </div>
13
126
  </div>
14
127
  );