@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.
- package/CHANGELOG.md +88 -0
- package/package.json +3 -3
- package/templates/react-app/config/Identifier.I18n.ts +878 -0
- package/templates/react-app/config/app.router.json +7 -7
- package/templates/react-app/config/theme.json +7 -88
- package/templates/react-app/package.json +7 -3
- package/templates/react-app/postcss.config.js +1 -2
- package/templates/react-app/public/locales/en/common.json +118 -1
- package/templates/react-app/public/locales/zh/common.json +118 -1
- package/templates/react-app/src/App.tsx +14 -2
- package/templates/react-app/src/base/cases/RequestLogger.ts +1 -1
- package/templates/react-app/src/base/services/I18nService.ts +31 -3
- package/templates/react-app/src/base/services/ProcesserService.ts +0 -1
- package/templates/react-app/src/core/IOC.ts +12 -7
- package/templates/react-app/src/core/bootstrap.ts +42 -53
- package/templates/react-app/src/core/bootstraps/PrintBootstrap.ts +14 -0
- package/templates/react-app/src/core/bootstraps/index.ts +36 -7
- package/templates/react-app/src/core/registers/RegisterApi.ts +2 -5
- package/templates/react-app/src/core/registers/RegisterCommon.ts +38 -29
- package/templates/react-app/src/core/registers/RegisterControllers.ts +5 -10
- package/templates/react-app/src/core/registers/RegisterGlobals.ts +13 -13
- package/templates/react-app/src/core/registers/index.ts +27 -12
- package/templates/react-app/src/main.tsx +1 -1
- package/templates/react-app/src/pages/404.tsx +1 -1
- package/templates/react-app/src/pages/500.tsx +1 -1
- package/templates/react-app/src/pages/auth/Login.tsx +128 -36
- package/templates/react-app/src/pages/base/About.tsx +5 -2
- package/templates/react-app/src/pages/base/ErrorIdentifier.tsx +38 -19
- package/templates/react-app/src/pages/base/Executor.tsx +447 -29
- package/templates/react-app/src/pages/base/Home.tsx +99 -93
- package/templates/react-app/src/pages/base/JSONStorage.tsx +47 -38
- package/templates/react-app/src/pages/base/Layout.tsx +5 -2
- package/templates/react-app/src/pages/base/Request.tsx +90 -208
- package/templates/react-app/src/pages/base/components/BaseHeader.tsx +13 -5
- package/templates/react-app/src/styles/css/page.css +11 -0
- package/templates/react-app/src/styles/css/tailwind.css +5 -0
- package/templates/react-app/src/styles/css/themes/_default.css +200 -0
- package/templates/react-app/src/styles/css/themes/dark.css +154 -0
- package/templates/react-app/src/styles/css/themes/index.css +3 -0
- package/templates/react-app/src/styles/css/themes/pink.css +160 -0
- package/templates/react-app/src/uikit/components/LanguageSwitcher.tsx +56 -0
- package/templates/react-app/src/uikit/components/Loading.tsx +27 -21
- package/templates/react-app/src/uikit/components/ThemeSwitcher.tsx +63 -13
- package/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +1 -1
- package/templates/react-app/src/uikit/controllers/UserController.ts +1 -1
- package/templates/react-app/tailwind.config.js +1 -15
- package/templates/react-app/vite.config.ts +7 -1
- package/templates/react-app/lib/tailwind/root10px.js +0 -178
- package/templates/react-app/lib/tailwind/theme-generator.js +0 -238
- package/templates/react-app/public/locales/en/about.json +0 -3
- package/templates/react-app/public/locales/en/executor.json +0 -6
- package/templates/react-app/public/locales/en/home.json +0 -10
- package/templates/react-app/public/locales/en/jsonStorage.json +0 -11
- package/templates/react-app/public/locales/en/login.json +0 -7
- package/templates/react-app/public/locales/en/request.json +0 -15
- package/templates/react-app/public/locales/zh/about.json +0 -3
- package/templates/react-app/public/locales/zh/executor.json +0 -6
- package/templates/react-app/public/locales/zh/home.json +0 -10
- package/templates/react-app/public/locales/zh/jsonStorage.json +0 -11
- package/templates/react-app/public/locales/zh/login.json +0 -7
- package/templates/react-app/public/locales/zh/request.json +0 -15
- package/templates/react-app/src/base/port/InversifyIocInterface.ts +0 -9
- package/templates/react-app/src/uikit/styles/css/page.css +0 -3
- package/templates/react-app/src/uikit/styles/css/tailwind.css +0 -3
- /package/templates/react-app/config/{ErrorIdentifier.ts → Identifier.Error.ts} +0 -0
- /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
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
|
9
|
+
import { envBlackList, envPrefix, browserGlobalsName } from '@config/common';
|
|
10
10
|
import { IOC } from './IOC';
|
|
11
11
|
import * as globals from '@/core/globals';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
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
|
-
|
|
18
|
-
|
|
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
|
-
|
|
20
|
+
root: unknown;
|
|
42
21
|
envSource: Record<string, unknown>;
|
|
43
22
|
}) {
|
|
44
|
-
if (!(typeof
|
|
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
|
|
29
|
+
const envOptions: InjectEnvConfig = {
|
|
30
|
+
target: AppConfig,
|
|
31
|
+
source: envSource,
|
|
32
|
+
prefix: envPrefix,
|
|
33
|
+
blackList: envBlackList
|
|
34
|
+
};
|
|
51
35
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
69
|
-
|
|
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
|
|
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 {
|
|
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
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
|
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:
|
|
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
|
|
8
|
-
|
|
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
|
|
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(
|
|
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
|
|
35
|
-
container.bind(UserToken
|
|
42
|
+
container.bind(FetchAbortPlugin, feApiAbort);
|
|
43
|
+
container.bind(UserToken, userToken);
|
|
36
44
|
|
|
37
|
-
container.bind(IOCIdentifier.FeApiToken
|
|
38
|
-
container
|
|
39
|
-
|
|
40
|
-
.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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(
|
|
59
|
+
container.bind(
|
|
60
|
+
ThemeService,
|
|
54
61
|
new ThemeService({
|
|
55
|
-
...
|
|
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:
|
|
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
|
|
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 {
|
|
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:
|
|
14
|
+
register(container: InversifyContainer): void {
|
|
15
15
|
// inject AppConfig to IOC
|
|
16
|
-
container.bind(IOCIdentifier.AppConfig
|
|
16
|
+
container.bind(IOCIdentifier.AppConfig, this.appConfig);
|
|
17
17
|
|
|
18
|
-
container.bind(JSONSerializer
|
|
19
|
-
container.bind(IOCIdentifier.JSON
|
|
18
|
+
container.bind(JSONSerializer, JSON);
|
|
19
|
+
container.bind(IOCIdentifier.JSON, JSON);
|
|
20
20
|
|
|
21
|
-
container.bind(Logger
|
|
22
|
-
container.bind(IOCIdentifier.Logger
|
|
21
|
+
container.bind(Logger, logger);
|
|
22
|
+
container.bind(IOCIdentifier.Logger, logger);
|
|
23
23
|
|
|
24
|
-
container.bind(JSONStorage
|
|
25
|
-
container.bind(IOCIdentifier.JSONStorage
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
+
}
|
|
@@ -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-
|
|
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-
|
|
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({
|
|
22
|
-
|
|
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
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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-
|
|
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">
|
|
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
|
);
|