@qlover/create-app 0.3.2 → 0.3.3

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 (66) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/package.json +3 -3
  3. package/templates/react-app/config/Identifier.I18n.ts +878 -0
  4. package/templates/react-app/config/app.router.json +7 -7
  5. package/templates/react-app/config/theme.json +7 -88
  6. package/templates/react-app/package.json +7 -3
  7. package/templates/react-app/postcss.config.js +1 -2
  8. package/templates/react-app/public/locales/en/common.json +118 -1
  9. package/templates/react-app/public/locales/zh/common.json +118 -1
  10. package/templates/react-app/src/App.tsx +14 -2
  11. package/templates/react-app/src/base/cases/RequestLogger.ts +1 -1
  12. package/templates/react-app/src/base/services/I18nService.ts +31 -3
  13. package/templates/react-app/src/base/services/ProcesserService.ts +0 -1
  14. package/templates/react-app/src/core/IOC.ts +12 -7
  15. package/templates/react-app/src/core/bootstrap.ts +42 -53
  16. package/templates/react-app/src/core/bootstraps/PrintBootstrap.ts +14 -0
  17. package/templates/react-app/src/core/bootstraps/index.ts +36 -7
  18. package/templates/react-app/src/core/registers/RegisterApi.ts +2 -5
  19. package/templates/react-app/src/core/registers/RegisterCommon.ts +38 -29
  20. package/templates/react-app/src/core/registers/RegisterControllers.ts +5 -10
  21. package/templates/react-app/src/core/registers/RegisterGlobals.ts +13 -13
  22. package/templates/react-app/src/core/registers/index.ts +27 -12
  23. package/templates/react-app/src/main.tsx +1 -1
  24. package/templates/react-app/src/pages/404.tsx +1 -1
  25. package/templates/react-app/src/pages/500.tsx +1 -1
  26. package/templates/react-app/src/pages/auth/Login.tsx +128 -36
  27. package/templates/react-app/src/pages/base/About.tsx +5 -2
  28. package/templates/react-app/src/pages/base/ErrorIdentifier.tsx +38 -19
  29. package/templates/react-app/src/pages/base/Executor.tsx +447 -29
  30. package/templates/react-app/src/pages/base/Home.tsx +99 -93
  31. package/templates/react-app/src/pages/base/JSONStorage.tsx +47 -38
  32. package/templates/react-app/src/pages/base/Layout.tsx +5 -2
  33. package/templates/react-app/src/pages/base/Request.tsx +90 -208
  34. package/templates/react-app/src/pages/base/components/BaseHeader.tsx +13 -5
  35. package/templates/react-app/src/styles/css/page.css +11 -0
  36. package/templates/react-app/src/styles/css/tailwind.css +5 -0
  37. package/templates/react-app/src/styles/css/themes/_default.css +200 -0
  38. package/templates/react-app/src/styles/css/themes/dark.css +154 -0
  39. package/templates/react-app/src/styles/css/themes/index.css +3 -0
  40. package/templates/react-app/src/styles/css/themes/pink.css +160 -0
  41. package/templates/react-app/src/uikit/components/LanguageSwitcher.tsx +56 -0
  42. package/templates/react-app/src/uikit/components/Loading.tsx +27 -21
  43. package/templates/react-app/src/uikit/components/ThemeSwitcher.tsx +63 -13
  44. package/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +1 -1
  45. package/templates/react-app/src/uikit/controllers/UserController.ts +1 -1
  46. package/templates/react-app/tailwind.config.js +1 -15
  47. package/templates/react-app/vite.config.ts +7 -1
  48. package/templates/react-app/lib/tailwind/root10px.js +0 -178
  49. package/templates/react-app/lib/tailwind/theme-generator.js +0 -238
  50. package/templates/react-app/public/locales/en/about.json +0 -3
  51. package/templates/react-app/public/locales/en/executor.json +0 -6
  52. package/templates/react-app/public/locales/en/home.json +0 -10
  53. package/templates/react-app/public/locales/en/jsonStorage.json +0 -11
  54. package/templates/react-app/public/locales/en/login.json +0 -7
  55. package/templates/react-app/public/locales/en/request.json +0 -15
  56. package/templates/react-app/public/locales/zh/about.json +0 -3
  57. package/templates/react-app/public/locales/zh/executor.json +0 -6
  58. package/templates/react-app/public/locales/zh/home.json +0 -10
  59. package/templates/react-app/public/locales/zh/jsonStorage.json +0 -11
  60. package/templates/react-app/public/locales/zh/login.json +0 -7
  61. package/templates/react-app/public/locales/zh/request.json +0 -15
  62. package/templates/react-app/src/base/port/InversifyIocInterface.ts +0 -9
  63. package/templates/react-app/src/uikit/styles/css/page.css +0 -3
  64. package/templates/react-app/src/uikit/styles/css/tailwind.css +0 -3
  65. /package/templates/react-app/config/{ErrorIdentifier.ts → Identifier.Error.ts} +0 -0
  66. /package/templates/react-app/src/{uikit/styles → styles}/css/index.css +0 -0
@@ -1,78 +1,67 @@
1
1
  import {
2
2
  Bootstrap,
3
- type BootstrapExecutorPlugin,
4
- InjectEnv,
5
- InjectIOC,
6
- InjectGlobal
3
+ type InjectGlobalConfig,
4
+ type InjectIOCOptions,
5
+ type IOCContainerInterface,
6
+ type InjectEnvConfig
7
7
  } from '@qlover/corekit-bridge';
8
8
  import AppConfig from '@/core/AppConfig';
9
- import { envPrefix, browserGlobalsName, envBlackList } from '@config/common';
9
+ import { envBlackList, envPrefix, browserGlobalsName } from '@config/common';
10
10
  import { IOC } from './IOC';
11
11
  import * as globals from '@/core/globals';
12
- import { I18nService } from '@/base/services/I18nService';
13
- import { registerList } from './registers';
14
- import { appBootstrapList } from './bootstraps';
15
- import { GLOBAL_NO_WINDOW } from '@config/ErrorIdentifier';
12
+ import { IocRegister } from './registers';
13
+ import { BootstrapsRegistry } from './bootstraps';
14
+ import { GLOBAL_NO_WINDOW } from '@config/Identifier.Error';
16
15
 
17
- const printBootstrap: BootstrapExecutorPlugin = {
18
- pluginName: 'PrintBootstrap',
19
- onSuccess({ parameters: { logger } }) {
20
- logger.info(
21
- 'bootstrap success!\n\n' +
22
- `You can use \`%cwindow.${browserGlobalsName}%c\` to access the globals`,
23
- 'color: #0ff; font-weight: bold;',
24
- 'all: unset;'
25
- );
26
- }
27
- };
28
-
29
- /**
30
- * Bootstrap
31
- *
32
- * 1. inject env config to AppConfig
33
- * 2. inject IOC to Application
34
- * 3. inject globals to window
35
- *
36
- */
37
- export default function startup({
38
- window,
16
+ export default async function startup({
17
+ root,
39
18
  envSource
40
19
  }: {
41
- window: unknown;
20
+ root: unknown;
42
21
  envSource: Record<string, unknown>;
43
22
  }) {
44
- if (!(typeof window !== 'undefined' && window instanceof Window)) {
23
+ if (!(typeof root !== 'undefined' && root instanceof Window)) {
45
24
  throw new Error(GLOBAL_NO_WINDOW);
46
25
  }
47
26
 
48
27
  const { logger } = globals;
49
28
 
50
- const bootstrap = new Bootstrap(window, IOC.implemention!, logger);
29
+ const envOptions: InjectEnvConfig = {
30
+ target: AppConfig,
31
+ source: envSource,
32
+ prefix: envPrefix,
33
+ blackList: envBlackList
34
+ };
51
35
 
52
- /**
53
- * bootstrap start list
54
- *
55
- * - inject env config to AppConfig
56
- * - inject IOC to Application
57
- * - inject globals to window
58
- * - inject i18n service to Application
59
- */
60
- const bootstrapList: BootstrapExecutorPlugin[] = [
61
- new InjectEnv(AppConfig, envSource, envPrefix, envBlackList),
62
- new InjectIOC(IOC, registerList),
63
- new InjectGlobal(globals, browserGlobalsName),
64
- new I18nService(window.location.pathname),
65
- ...appBootstrapList
66
- ];
36
+ const iocOptions: InjectIOCOptions<IOCContainerInterface> = {
37
+ manager: IOC,
38
+ register: new IocRegister({
39
+ pathname: root.location.pathname
40
+ })
41
+ };
67
42
 
68
- if (AppConfig.env !== 'production') {
69
- bootstrapList.push(printBootstrap);
70
- }
43
+ const globalOptions: InjectGlobalConfig = {
44
+ sources: globals,
45
+ target: browserGlobalsName
46
+ };
47
+
48
+ const bootstrap = new Bootstrap({
49
+ root,
50
+ logger,
51
+ ioc: iocOptions,
52
+ envOptions,
53
+ globalOptions
54
+ });
71
55
 
72
56
  try {
73
57
  logger.info('bootstrap start...');
74
58
 
75
- bootstrap.use(bootstrapList).start();
59
+ // init bootstrap
60
+ await bootstrap.initialize();
61
+
62
+ const bootstrapsRegistry = new BootstrapsRegistry(IOC);
63
+
64
+ await bootstrap.use(bootstrapsRegistry.register()).start();
76
65
  } catch (error) {
77
66
  logger.error(`${AppConfig.appName} starup error:`, error);
78
67
  }
@@ -0,0 +1,14 @@
1
+ import { browserGlobalsName } from '@config/common';
2
+ import { BootstrapExecutorPlugin } from '@qlover/corekit-bridge';
3
+
4
+ export const printBootstrap: BootstrapExecutorPlugin = {
5
+ pluginName: 'PrintBootstrap',
6
+ onSuccess({ parameters: { logger } }) {
7
+ logger.info(
8
+ 'bootstrap success!\n\n' +
9
+ `You can use \`%cwindow.${browserGlobalsName}%c\` to access the globals`,
10
+ 'color: #0ff; font-weight: bold;',
11
+ 'all: unset;'
12
+ );
13
+ }
14
+ };
@@ -1,12 +1,41 @@
1
- import type { BootstrapExecutorPlugin } from '@qlover/corekit-bridge';
1
+ import type {
2
+ BootstrapExecutorPlugin,
3
+ EnvConfigInterface,
4
+ IOCContainerInterface,
5
+ IOCFunctionInterface
6
+ } from '@qlover/corekit-bridge';
2
7
  import { BootstrapApp } from './BootstrapApp';
3
8
  import { UserApiBootstarp } from '@/base/apis/userApi/UserApiBootstarp';
4
9
  import { FeApiBootstarp } from '@/base/apis/feApi/FeApiBootstarp';
5
10
  import { AiApiBootstarp } from '@/base/apis/AiApi';
11
+ import { printBootstrap } from './PrintBootstrap';
12
+ import { IOCIdentifier, type IOCIdentifierMap } from '../IOC';
13
+ import { I18nService } from '@/base/services/I18nService';
6
14
 
7
- export const appBootstrapList: BootstrapExecutorPlugin[] = [
8
- new UserApiBootstarp(),
9
- new FeApiBootstarp(),
10
- AiApiBootstarp,
11
- new BootstrapApp()
12
- ];
15
+ export class BootstrapsRegistry {
16
+ constructor(
17
+ protected IOC: IOCFunctionInterface<IOCIdentifierMap, IOCContainerInterface>
18
+ ) {}
19
+
20
+ get appConfig(): EnvConfigInterface {
21
+ return this.IOC(IOCIdentifier.AppConfig);
22
+ }
23
+
24
+ register(): BootstrapExecutorPlugin[] {
25
+ const IOC = this.IOC;
26
+
27
+ const bootstrapList = [
28
+ IOC(I18nService),
29
+ new UserApiBootstarp(),
30
+ new FeApiBootstarp(),
31
+ AiApiBootstarp,
32
+ new BootstrapApp()
33
+ ];
34
+
35
+ if (this.appConfig.env !== 'production') {
36
+ bootstrapList.push(printBootstrap);
37
+ }
38
+
39
+ return bootstrapList;
40
+ }
41
+ }
@@ -1,8 +1,5 @@
1
- import type {
2
- InversifyRegisterInterface,
3
- InversifyRegisterContainer
4
- } from '@/base/port/InversifyIocInterface';
1
+ import { InversifyContainer, InversifyRegisterInterface } from '../IOC';
5
2
 
6
3
  export class RegisterApi implements InversifyRegisterInterface {
7
- register(_container: InversifyRegisterContainer): void {}
4
+ register(_container: InversifyContainer): void {}
8
5
  }
@@ -1,25 +1,33 @@
1
- import type {
2
- InversifyRegisterInterface,
3
- InversifyRegisterContainer
4
- } from '@/base/port/InversifyIocInterface';
5
1
  import { FetchAbortPlugin, JSONStorage } from '@qlover/fe-corekit';
6
- import { Logger }from '@qlover/logger';
7
- import AppConfig from '@/core/AppConfig';
8
- import { IOCIdentifier } from '@/core/IOC';
2
+ import { Logger } from '@qlover/logger';
3
+ import {
4
+ InversifyContainer,
5
+ InversifyRegisterInterface,
6
+ IOCIdentifier,
7
+ IocRegisterOptions
8
+ } from '@/core/IOC';
9
9
  import {
10
10
  UserToken,
11
11
  RequestCommonPlugin,
12
12
  ApiMockPlugin,
13
13
  ApiCatchPlugin,
14
- ThemeService
14
+ ThemeService,
15
+ IOCManagerInterface
15
16
  } from '@qlover/corekit-bridge';
16
17
  import mockDataJson from '@config/feapi.mock.json';
17
18
  import { RequestStatusCatcher } from '@/base/cases/RequestStatusCatcher';
18
- import { override as themeOverride } from '@config/theme.json';
19
+ import themeConfig from '@config/theme.json';
19
20
  import { localJsonStorage } from '../globals';
21
+ import { I18nService } from '@/base/services/I18nService';
20
22
 
21
23
  export class RegisterCommon implements InversifyRegisterInterface {
22
- register(container: InversifyRegisterContainer): void {
24
+ register(
25
+ container: InversifyContainer,
26
+ _: IOCManagerInterface<InversifyContainer>,
27
+ options: IocRegisterOptions
28
+ ): void {
29
+ const AppConfig = container.get(IOCIdentifier.AppConfig);
30
+
23
31
  const userToken = new UserToken(
24
32
  AppConfig.userTokenStorageKey,
25
33
  container.get(JSONStorage)
@@ -31,30 +39,31 @@ export class RegisterCommon implements InversifyRegisterInterface {
31
39
  token: () => userToken.getToken()
32
40
  });
33
41
 
34
- container.bind(FetchAbortPlugin).toConstantValue(feApiAbort);
35
- container.bind(UserToken).toConstantValue(userToken);
42
+ container.bind(FetchAbortPlugin, feApiAbort);
43
+ container.bind(UserToken, userToken);
36
44
 
37
- container.bind(IOCIdentifier.FeApiToken).toConstantValue(userToken);
38
- container
39
- .bind(IOCIdentifier.FeApiCommonPlugin)
40
- .toConstantValue(feApiRequestCommonPlugin);
41
- container
42
- .bind(IOCIdentifier.ApiMockPlugin)
43
- .toConstantValue(new ApiMockPlugin(mockDataJson, container.get(Logger)));
44
- container
45
- .bind(IOCIdentifier.ApiCatchPlugin)
46
- .toConstantValue(
47
- new ApiCatchPlugin(
48
- container.get(Logger),
49
- container.get(RequestStatusCatcher)
50
- )
51
- );
45
+ container.bind(IOCIdentifier.FeApiToken, userToken);
46
+ container.bind(IOCIdentifier.FeApiCommonPlugin, feApiRequestCommonPlugin);
47
+ container.bind(
48
+ IOCIdentifier.ApiMockPlugin,
49
+ new ApiMockPlugin(mockDataJson, container.get(Logger))
50
+ );
51
+ container.bind(
52
+ IOCIdentifier.ApiCatchPlugin,
53
+ new ApiCatchPlugin(
54
+ container.get(Logger),
55
+ container.get(RequestStatusCatcher)
56
+ )
57
+ );
52
58
 
53
- container.bind(ThemeService).toConstantValue(
59
+ container.bind(
60
+ ThemeService,
54
61
  new ThemeService({
55
- ...themeOverride,
62
+ ...themeConfig,
56
63
  storage: localJsonStorage
57
64
  })
58
65
  );
66
+
67
+ container.bind(I18nService, new I18nService(options.pathname));
59
68
  }
60
69
  }
@@ -1,17 +1,14 @@
1
- import type {
2
- InversifyRegisterInterface,
3
- InversifyRegisterContainer
4
- } from '@/base/port/InversifyIocInterface';
5
-
6
1
  import { localJsonStorage, logger } from '../globals';
7
2
  import { RouterController } from '@/uikit/controllers/RouterController';
8
3
  import { JSONStorageController } from '@/uikit/controllers/JSONStorageController';
9
4
  import { ProcesserService } from '@/base/services/ProcesserService';
10
5
  import { UserController } from '@/uikit/controllers/UserController';
11
6
  import { base as baseRoutes } from '@config/app.router.json';
7
+ import { InversifyRegisterInterface } from '../IOC';
8
+ import { InversifyContainer } from '../IOC';
12
9
 
13
10
  export class RegisterControllers implements InversifyRegisterInterface {
14
- register(container: InversifyRegisterContainer): void {
11
+ register(container: InversifyContainer): void {
15
12
  const routerController = new RouterController({
16
13
  config: baseRoutes,
17
14
  logger
@@ -19,10 +16,8 @@ export class RegisterControllers implements InversifyRegisterInterface {
19
16
 
20
17
  const jsonStorageController = new JSONStorageController(localJsonStorage);
21
18
 
22
- container.bind(RouterController).toConstantValue(routerController);
23
- container
24
- .bind(JSONStorageController)
25
- .toConstantValue(jsonStorageController);
19
+ container.bind(RouterController, routerController);
20
+ container.bind(JSONStorageController, jsonStorageController);
26
21
 
27
22
  container.get(ProcesserService).use(container.get(UserController));
28
23
  }
@@ -1,27 +1,27 @@
1
1
  import { JSONSerializer, JSONStorage } from '@qlover/fe-corekit';
2
2
  import type { EnvConfigInterface } from '@qlover/corekit-bridge';
3
- import type {
4
- InversifyRegisterInterface,
5
- InversifyRegisterContainer
6
- } from '@/base/port/InversifyIocInterface';
7
3
  import { JSON, localJsonStorage, logger } from '../globals';
8
- import { IOCIdentifier } from '@/core/IOC';
4
+ import {
5
+ type InversifyContainer,
6
+ type InversifyRegisterInterface,
7
+ IOCIdentifier
8
+ } from '@/core/IOC';
9
9
  import { Logger } from '@qlover/logger';
10
10
 
11
11
  export class RegisterGlobals implements InversifyRegisterInterface {
12
12
  constructor(private appConfig: EnvConfigInterface) {}
13
13
 
14
- register(container: InversifyRegisterContainer): void {
14
+ register(container: InversifyContainer): void {
15
15
  // inject AppConfig to IOC
16
- container.bind(IOCIdentifier.AppConfig).toConstantValue(this.appConfig);
16
+ container.bind(IOCIdentifier.AppConfig, this.appConfig);
17
17
 
18
- container.bind(JSONSerializer).toConstantValue(JSON);
19
- container.bind(IOCIdentifier.JSON).toConstantValue(JSON);
18
+ container.bind(JSONSerializer, JSON);
19
+ container.bind(IOCIdentifier.JSON, JSON);
20
20
 
21
- container.bind(Logger).toConstantValue(logger);
22
- container.bind(IOCIdentifier.Logger).toConstantValue(logger);
21
+ container.bind(Logger, logger);
22
+ container.bind(IOCIdentifier.Logger, logger);
23
23
 
24
- container.bind(JSONStorage).toConstantValue(localJsonStorage);
25
- container.bind(IOCIdentifier.JSONStorage).toConstantValue(localJsonStorage);
24
+ container.bind(JSONStorage, localJsonStorage);
25
+ container.bind(IOCIdentifier.JSONStorage, localJsonStorage);
26
26
  }
27
27
  }
@@ -1,18 +1,33 @@
1
- import type { InversifyRegisterInterface } from '@/base/port/InversifyIocInterface';
2
1
  import { RegisterGlobals } from './RegisterGlobals';
3
2
  import { RegisterCommon } from './RegisterCommon';
4
3
  import { RegisterApi } from './RegisterApi';
5
4
  import { RegisterControllers } from './RegisterControllers';
6
5
  import AppConfig from '../AppConfig';
6
+ import {
7
+ InversifyContainer,
8
+ InversifyRegisterInterface,
9
+ IocRegisterOptions
10
+ } from '../IOC';
11
+ import { IOCManagerInterface } from '@qlover/corekit-bridge';
7
12
 
8
- /**
9
- * Register List
10
- *
11
- * Register List is used to register dependencies in bootstrap
12
- */
13
- export const registerList: InversifyRegisterInterface[] = [
14
- new RegisterGlobals(AppConfig),
15
- new RegisterCommon(),
16
- new RegisterApi(),
17
- new RegisterControllers()
18
- ];
13
+ export class IocRegister implements InversifyRegisterInterface {
14
+ constructor(protected options: IocRegisterOptions) {}
15
+
16
+ getRegisterList(): InversifyRegisterInterface[] {
17
+ return [
18
+ new RegisterGlobals(AppConfig),
19
+ new RegisterCommon(),
20
+ new RegisterApi(),
21
+ new RegisterControllers()
22
+ ];
23
+ }
24
+
25
+ register(
26
+ ioc: InversifyContainer,
27
+ manager: IOCManagerInterface<InversifyContainer>
28
+ ): void {
29
+ this.getRegisterList().forEach((register) => {
30
+ register.register(ioc, manager, this.options);
31
+ });
32
+ }
33
+ }
@@ -6,7 +6,7 @@ import App from './App.tsx';
6
6
  import startup from './core/bootstrap';
7
7
 
8
8
  startup({
9
- window: window,
9
+ root: window,
10
10
  envSource: import.meta.env
11
11
  });
12
12
 
@@ -5,7 +5,7 @@ export default function NotFound({ route }: { route?: string }) {
5
5
  return (
6
6
  <div className="flex flex-col justify-center min-h-screen py-6 bg-background sm:py-12">
7
7
  <div className="relative py-3 mx-auto sm:max-w-xl">
8
- <h1 className="text-primary text-2xl font-bold text-center">
8
+ <h1 className="text-text text-2xl font-bold text-center">
9
9
  404 -{route ? `${t('404.notComponent')}: ${route}` : t('404.notPage')}
10
10
  </h1>
11
11
  </div>
@@ -5,7 +5,7 @@ export default function NotFound500() {
5
5
  return (
6
6
  <div className="flex flex-col justify-center min-h-screen py-6 bg-background sm:py-12">
7
7
  <div className="relative py-3 mx-auto sm:max-w-xl">
8
- <h1 className="text-primary text-2xl font-bold text-center">
8
+ <h1 className="text-text text-2xl font-bold text-center">
9
9
  500 - {t('500.title')}
10
10
  </h1>
11
11
  </div>
@@ -1,28 +1,33 @@
1
1
  import { useState } from 'react';
2
+ import { Form, Input, Button } from 'antd';
3
+ import { UserOutlined, LockOutlined, GoogleOutlined } from '@ant-design/icons';
2
4
  import { IOC } from '@/core/IOC';
3
5
  import { useBaseRoutePage } from '@/uikit/contexts/BaseRouteContext';
4
6
  import { RouterController } from '@/uikit/controllers/RouterController';
5
7
  import { UserController } from '@/uikit/controllers/UserController';
6
- import AppConfig from '@/core/AppConfig';
7
8
  import { useSliceStore } from '@qlover/slice-store-react';
8
9
 
10
+ interface LoginFormData {
11
+ email: string;
12
+ password: string;
13
+ }
14
+
9
15
  export default function Login() {
10
16
  const { t } = useBaseRoutePage();
11
17
  const userController = IOC(UserController);
18
+ const AppConfig = IOC('AppConfig');
12
19
  useSliceStore(userController);
13
-
14
- const [email, setEmail] = useState(AppConfig.loginUser);
15
- const [password, setPassword] = useState(AppConfig.loginPassword);
16
20
  const [loading, setLoading] = useState(false);
17
21
 
18
- const handleLogin = async () => {
22
+ const handleLogin = async (values: LoginFormData) => {
19
23
  try {
20
24
  setLoading(true);
21
- await userController.login({ username: email, password });
22
- // Redirect or show success message
25
+ await userController.login({
26
+ username: values.email,
27
+ password: values.password
28
+ });
23
29
  IOC(RouterController).replaceToHome();
24
30
  } catch (error) {
25
- // Handle login error
26
31
  console.error(error);
27
32
  } finally {
28
33
  setLoading(false);
@@ -30,37 +35,124 @@ export default function Login() {
30
35
  };
31
36
 
32
37
  return (
33
- <div className="min-h-screen bg-gray-100 py-6 flex flex-col justify-center sm:py-12">
34
- <div className="relative py-3 sm:max-w-xl sm:mx-auto">
35
- <div className="bg-white shadow-lg rounded-lg px-8 py-6">
36
- <h1 className="text-base font-bold text-center text-gray-800 mb-8">
37
- {t('login')}
38
- </h1>
39
- <div className="space-y-6">
40
- <input
41
- type="email"
42
- value={email}
43
- onChange={(e) => setEmail(e.target.value)}
44
- placeholder={t('email')}
45
- className="w-full px-4 py-2 border rounded-lg"
46
- />
47
- <input
48
- type="password"
49
- value={password}
50
- onChange={(e) => setPassword(e.target.value)}
51
- placeholder={t('password')}
52
- className="w-full px-4 py-2 border rounded-lg"
53
- />
54
- <button
55
- onClick={handleLogin}
56
- className="w-full px-6 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors duration-200"
57
- disabled={loading}
38
+ <div className="flex min-h-screen text-xs1 bg-primary">
39
+ {/* Left side - Brand section */}
40
+ <div className="hidden lg:flex lg:w-1/2 bg-secondary p-12 flex-col">
41
+ <div className="flex items-center gap-3 mb-12">
42
+ <div className="w-10 h-10 bg-brand rounded-lg"></div>
43
+ <span className="text-2xl font-semibold text-text">
44
+ {AppConfig.appName}
45
+ </span>
46
+ </div>
47
+ <h1 className="text-4xl font-bold text-text mb-4">
48
+ Welcome back to the future of learning
49
+ </h1>
50
+ <p className="text-text-secondary text-lg mb-8">
51
+ Unlock personalized AI-powered learning experiences designed to
52
+ accelerate your knowledge journey.
53
+ </p>
54
+ <div className="space-y-4">
55
+ <FeatureItem
56
+ icon="🎯"
57
+ text="AI-powered personalized learning paths"
58
+ />
59
+ <FeatureItem icon="🎯" text="Smart content recommendations" />
60
+ <FeatureItem icon="📊" text="Real-time progress tracking" />
61
+ </div>
62
+ </div>
63
+
64
+ {/* Right side - Login form */}
65
+ <div className="w-full lg:w-1/2 p-8 sm:p-12 flex items-center justify-center">
66
+ <div className="w-full max-w-[420px]">
67
+ <h2 className="text-2xl font-semibold mb-2 text-text">
68
+ {t('Sign in to your account')}
69
+ </h2>
70
+ <p className="text-text-secondary mb-8">
71
+ Enter your credentials to access your dashboard
72
+ </p>
73
+
74
+ <Form
75
+ name="login"
76
+ initialValues={{
77
+ email: AppConfig.loginUser,
78
+ password: AppConfig.loginPassword
79
+ }}
80
+ onFinish={handleLogin}
81
+ layout="vertical"
82
+ className="space-y-4"
83
+ >
84
+ <Form.Item
85
+ name="email"
86
+ rules={[{ required: true, message: 'Please input your email!' }]}
58
87
  >
59
- {loading ? 'Loading...' : t('login')}
60
- </button>
61
- </div>
88
+ <Input
89
+ prefix={<UserOutlined className="text-text-tertiary" />}
90
+ placeholder={t('email')}
91
+ className="h-12 text-base bg-secondary border-border"
92
+ />
93
+ </Form.Item>
94
+
95
+ <Form.Item
96
+ name="password"
97
+ rules={[
98
+ { required: true, message: 'Please input your password!' }
99
+ ]}
100
+ >
101
+ <Input.Password
102
+ prefix={<LockOutlined />}
103
+ placeholder={t('password')}
104
+ className="h-12 text-base"
105
+ />
106
+ </Form.Item>
107
+
108
+ <div className="flex justify-end">
109
+ <a href="#" className="text-brand hover:text-brand-hover">
110
+ {t('Forgot your password?')}
111
+ </a>
112
+ </div>
113
+
114
+ <Form.Item>
115
+ <Button
116
+ type="primary"
117
+ htmlType="submit"
118
+ loading={loading}
119
+ className="w-full h-12 text-base"
120
+ >
121
+ {t('Sign In')}
122
+ </Button>
123
+ </Form.Item>
124
+
125
+ <div className="text-center text-text-tertiary my-4">
126
+ or continue with
127
+ </div>
128
+
129
+ <Button icon={<GoogleOutlined />} className="w-full h-12 text-base">
130
+ Sign in with Google
131
+ </Button>
132
+
133
+ <div className="text-center mt-6">
134
+ <span className="text-text-tertiary">
135
+ Don't have an account?{' '}
136
+ </span>
137
+ <a href="#" className="text-brand hover:text-brand-hover">
138
+ Create one here
139
+ </a>
140
+ </div>
141
+ </Form>
62
142
  </div>
63
143
  </div>
64
144
  </div>
65
145
  );
66
146
  }
147
+
148
+ // Helper component for feature items
149
+ function FeatureItem({ icon, text }: { icon: string; text: string }) {
150
+ return (
151
+ <div className="flex items-center gap-3 text-text">
152
+ <div className="w-8 h-8 bg-elevated rounded-lg flex items-center justify-center">
153
+ {icon}
154
+ </div>
155
+ <span>{text}</span>
156
+ </div>
157
+ );
158
+ }
@@ -1,11 +1,14 @@
1
1
  import { useBaseRoutePage } from '@/uikit/contexts/BaseRouteContext';
2
+ import * as i18nKeys from '@config/Identifier.I18n';
2
3
 
3
4
  export default function About() {
4
5
  const { t } = useBaseRoutePage();
5
6
  return (
6
- <div className="min-h-screen bg-gray-100 py-6 flex flex-col justify-center sm:py-12">
7
+ <div className="min-h-screen bg-primary py-6 flex flex-col justify-center sm:py-12">
7
8
  <div className="relative py-3 sm:max-w-xl sm:mx-auto">
8
- <h1 className="text-2xl font-bold text-center">{t('title')}</h1>
9
+ <h1 className="text-2xl font-bold text-center text-text">
10
+ {t(i18nKeys.PAGE_ABOUT_TITLE)}
11
+ </h1>
9
12
  </div>
10
13
  </div>
11
14
  );