@qlover/create-app 0.10.1 → 0.10.2

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 (108) hide show
  1. package/CHANGELOG.md +141 -0
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/templates/next-app/config/IOCIdentifier.ts +2 -2
  5. package/dist/templates/next-app/config/Identifier/common/common.ts +14 -0
  6. package/dist/templates/next-app/config/Identifier/pages/index.ts +1 -0
  7. package/dist/templates/next-app/config/Identifier/pages/page.about.ts +20 -0
  8. package/dist/templates/next-app/config/common.ts +1 -1
  9. package/dist/templates/next-app/config/cookies.ts +23 -0
  10. package/dist/templates/next-app/config/i18n/AboutI18n.ts +14 -0
  11. package/dist/templates/next-app/config/i18n/i18nConfig.ts +3 -1
  12. package/dist/templates/next-app/config/i18n/index.ts +1 -0
  13. package/dist/templates/next-app/config/i18n/loginI18n.ts +8 -0
  14. package/dist/templates/next-app/config/theme.ts +4 -0
  15. package/dist/templates/next-app/eslint.config.mjs +4 -1
  16. package/dist/templates/next-app/next.config.ts +1 -0
  17. package/dist/templates/next-app/package.json +13 -4
  18. package/dist/templates/next-app/public/locales/en.json +5 -0
  19. package/dist/templates/next-app/public/locales/zh.json +5 -0
  20. package/dist/templates/next-app/src/app/[locale]/admin/AdminI18nProvider.tsx +37 -0
  21. package/dist/templates/next-app/src/app/[locale]/admin/layout.tsx +30 -6
  22. package/dist/templates/next-app/src/app/[locale]/admin/locales/page.tsx +1 -1
  23. package/dist/templates/next-app/src/app/[locale]/layout.tsx +47 -10
  24. package/dist/templates/next-app/src/app/[locale]/login/LoginForm.tsx +1 -1
  25. package/dist/templates/next-app/src/app/[locale]/login/page.tsx +22 -10
  26. package/dist/templates/next-app/src/app/[locale]/page.tsx +23 -8
  27. package/dist/templates/next-app/src/app/[locale]/register/page.tsx +21 -9
  28. package/dist/templates/next-app/src/app/api/admin/locales/create/route.ts +7 -28
  29. package/dist/templates/next-app/src/app/api/admin/locales/import/route.ts +7 -34
  30. package/dist/templates/next-app/src/app/api/admin/locales/route.ts +12 -34
  31. package/dist/templates/next-app/src/app/api/admin/locales/update/route.ts +7 -26
  32. package/dist/templates/next-app/src/app/api/admin/users/route.ts +14 -33
  33. package/dist/templates/next-app/src/app/api/locales/json/route.ts +13 -25
  34. package/dist/templates/next-app/src/app/api/user/login/route.ts +6 -46
  35. package/dist/templates/next-app/src/app/api/user/logout/route.ts +5 -24
  36. package/dist/templates/next-app/src/app/api/user/register/route.ts +6 -45
  37. package/dist/templates/next-app/src/app/manifest.ts +16 -0
  38. package/dist/templates/next-app/src/app/robots.txt +2 -0
  39. package/dist/templates/next-app/src/base/cases/NavigateBridge.ts +12 -2
  40. package/dist/templates/next-app/src/base/cases/RouterService.ts +5 -5
  41. package/dist/templates/next-app/src/base/port/AppApiInterface.ts +22 -0
  42. package/dist/templates/next-app/src/base/port/IOCInterface.ts +9 -0
  43. package/dist/templates/next-app/src/base/types/{PageProps.ts → AppPageRouter.ts} +4 -1
  44. package/dist/templates/next-app/src/base/types/PagesRouter.ts +9 -0
  45. package/dist/templates/next-app/src/core/bootstraps/BootstrapClient.ts +19 -5
  46. package/dist/templates/next-app/src/core/bootstraps/BootstrapServer.ts +2 -2
  47. package/dist/templates/next-app/src/core/bootstraps/BootstrapsRegistry.ts +0 -1
  48. package/dist/templates/next-app/src/core/clientIoc/ClientIOC.ts +29 -8
  49. package/dist/templates/next-app/src/core/clientIoc/ClientIOCRegister.ts +4 -2
  50. package/dist/templates/next-app/src/core/serverIoc/ServerIOC.ts +25 -7
  51. package/dist/templates/next-app/src/core/serverIoc/ServerIOCRegister.ts +1 -1
  52. package/dist/templates/next-app/src/i18n/loadMessages.ts +103 -0
  53. package/dist/templates/next-app/src/i18n/request.ts +3 -22
  54. package/dist/templates/next-app/src/pages/[locale]/about.tsx +61 -0
  55. package/dist/templates/next-app/src/pages/_app.tsx +50 -0
  56. package/dist/templates/next-app/src/pages/_document.tsx +13 -0
  57. package/dist/templates/next-app/src/{middleware.ts → proxy.ts} +2 -1
  58. package/dist/templates/next-app/src/server/AppPageRouteParams.ts +94 -0
  59. package/dist/templates/next-app/src/server/NextApiServer.ts +53 -0
  60. package/dist/templates/next-app/src/server/PagesRouteParams.ts +136 -0
  61. package/dist/templates/next-app/src/server/{sqlBridges/SupabaseBridge.ts → SupabaseBridge.ts} +2 -0
  62. package/dist/templates/next-app/src/server/controllers/AdminLocalesController.ts +74 -0
  63. package/dist/templates/next-app/src/server/controllers/AdminUserController.ts +39 -0
  64. package/dist/templates/next-app/src/server/controllers/LocalesController.ts +33 -0
  65. package/dist/templates/next-app/src/server/controllers/UserController.ts +77 -0
  66. package/dist/templates/next-app/src/server/port/AIControllerInterface.ts +8 -0
  67. package/dist/templates/next-app/src/server/port/AdminLocalesControllerInterface.ts +21 -0
  68. package/dist/templates/next-app/src/server/port/AdminUserControllerInterface.ts +11 -0
  69. package/dist/templates/next-app/src/server/port/LocalesControllerInterface.ts +10 -0
  70. package/dist/templates/next-app/src/server/port/{ParamsHandlerInterface.ts → RouteParamsnHandlerInterface.ts} +9 -2
  71. package/dist/templates/next-app/src/server/port/ServerInterface.ts +2 -2
  72. package/dist/templates/next-app/src/server/port/UserControllerInerface.ts +8 -0
  73. package/dist/templates/next-app/src/server/port/UserServiceInterface.ts +1 -1
  74. package/dist/templates/next-app/src/server/port/ValidatorInterface.ts +2 -2
  75. package/dist/templates/next-app/src/server/repositorys/LocalesRepository.ts +8 -2
  76. package/dist/templates/next-app/src/{base → server}/services/AdminLocalesService.ts +2 -2
  77. package/dist/templates/next-app/src/server/services/ApiLocaleService.ts +25 -10
  78. package/dist/templates/next-app/src/server/services/ApiUserService.ts +5 -2
  79. package/dist/templates/next-app/src/server/validators/LocalesValidator.ts +4 -2
  80. package/dist/templates/next-app/src/server/validators/LoginValidator.ts +1 -1
  81. package/dist/templates/next-app/src/server/validators/PaginationValidator.ts +10 -10
  82. package/dist/templates/next-app/src/styles/css/antd-themes/_common/_default.css +0 -44
  83. package/dist/templates/next-app/src/styles/css/antd-themes/_common/dark.css +0 -44
  84. package/dist/templates/next-app/src/styles/css/antd-themes/_common/pink.css +0 -44
  85. package/dist/templates/next-app/src/styles/css/index.css +1 -1
  86. package/dist/templates/next-app/src/styles/css/scrollbar.css +34 -0
  87. package/dist/templates/next-app/src/uikit/components/AdminLayout.tsx +34 -11
  88. package/dist/templates/next-app/src/uikit/components/BootstrapsProvider.tsx +69 -39
  89. package/dist/templates/next-app/src/uikit/components/ClientRootProvider.tsx +64 -0
  90. package/dist/templates/next-app/src/uikit/components/ClinetRenderProvider.tsx +42 -0
  91. package/dist/templates/next-app/src/uikit/components/IOCProvider.tsx +34 -0
  92. package/dist/templates/next-app/src/uikit/components-app/AppBridge.tsx +17 -0
  93. package/dist/templates/next-app/src/uikit/components-app/AppRoutePage.tsx +112 -0
  94. package/dist/templates/next-app/src/uikit/{components → components-app}/LanguageSwitcher.tsx +15 -19
  95. package/dist/templates/next-app/src/uikit/{components → components-app}/ThemeSwitcher.tsx +53 -52
  96. package/dist/templates/next-app/src/uikit/components-pages/LanguageSwitcher.tsx +98 -0
  97. package/dist/templates/next-app/src/uikit/components-pages/PagesRoutePage.tsx +93 -0
  98. package/dist/templates/next-app/src/uikit/context/IOCContext.ts +16 -4
  99. package/dist/templates/next-app/src/uikit/hook/useStrictEffect.ts +32 -0
  100. package/dist/templates/next-app/tsconfig.json +3 -2
  101. package/package.json +1 -1
  102. package/dist/templates/next-app/src/server/PageParams.ts +0 -66
  103. package/dist/templates/next-app/src/uikit/components/BaseHeader.tsx +0 -80
  104. package/dist/templates/next-app/src/uikit/components/BaseLayout.tsx +0 -65
  105. package/dist/templates/next-app/src/uikit/components/ComboProvider.tsx +0 -58
  106. package/dist/templates/next-app/src/uikit/components/NextIntlProvider.tsx +0 -21
  107. /package/dist/templates/next-app/{src/app/[locale] → public}/favicon.ico +0 -0
  108. /package/dist/templates/next-app/src/uikit/{components → components-app}/LogoutButton.tsx +0 -0
@@ -0,0 +1,98 @@
1
+ 'use client';
2
+
3
+ import { TranslationOutlined } from '@ant-design/icons';
4
+ import { Dropdown } from 'antd';
5
+ import { useRouter } from 'next/router';
6
+ import { useLocale } from 'next-intl';
7
+ import { useCallback, useMemo, useState } from 'react';
8
+ import { useLocaleRoutes } from '@config/common';
9
+ import { i18nConfig } from '@config/i18n';
10
+ import type { LocaleType } from '@config/i18n';
11
+ import type { ItemType } from 'antd/es/menu/interface';
12
+
13
+ export function LanguageSwitcher() {
14
+ const router = useRouter();
15
+ const currentLocale = useLocale() as LocaleType;
16
+ const [isPending, setIsPending] = useState(false);
17
+
18
+ const options: ItemType[] = useMemo(() => {
19
+ return i18nConfig.supportedLngs.map(
20
+ (lang) =>
21
+ ({
22
+ type: 'item',
23
+ key: lang,
24
+ value: lang,
25
+ label:
26
+ i18nConfig.localeNames[lang as keyof typeof i18nConfig.localeNames]
27
+ }) as ItemType
28
+ );
29
+ }, []);
30
+
31
+ const handleLanguageChange = useCallback(
32
+ async (value: string) => {
33
+ if (isPending || value === currentLocale) return;
34
+
35
+ setIsPending(true);
36
+
37
+ try {
38
+ // Get current path
39
+ let newPath = router.asPath;
40
+
41
+ if (useLocaleRoutes) {
42
+ // Replace locale in path (e.g., /en/about -> /zh/about)
43
+ const pathWithoutLocale = newPath.replace(
44
+ new RegExp(`^/${currentLocale}(/|$)`),
45
+ '/'
46
+ );
47
+ // Remove leading slash if path is root
48
+ const cleanPath = pathWithoutLocale === '/' ? '' : pathWithoutLocale;
49
+ newPath = `/${value}${cleanPath}`;
50
+ } else {
51
+ // If not using locale routes, just update query param
52
+ newPath = router.pathname;
53
+ router.replace({
54
+ pathname: router.pathname,
55
+ query: { ...router.query, locale: value }
56
+ });
57
+ setIsPending(false);
58
+ return;
59
+ }
60
+
61
+ // Replace the route
62
+ router.replace(newPath);
63
+ } finally {
64
+ setIsPending(false);
65
+ }
66
+ },
67
+ [router, currentLocale, isPending]
68
+ );
69
+
70
+ const nextLocale = useMemo(() => {
71
+ const targetIndex = i18nConfig.supportedLngs.indexOf(currentLocale) + 1;
72
+ return i18nConfig.supportedLngs[
73
+ targetIndex % i18nConfig.supportedLngs.length
74
+ ];
75
+ }, [currentLocale]);
76
+
77
+ return (
78
+ <Dropdown
79
+ data-testid="LanguageSwitcherDropdown"
80
+ trigger={['hover']}
81
+ menu={{
82
+ selectedKeys: [currentLocale],
83
+ items: options,
84
+ onClick: ({ key }) => {
85
+ handleLanguageChange(key);
86
+ }
87
+ }}
88
+ >
89
+ <span
90
+ data-testid="LanguageSwitcher"
91
+ className="text-text hover:text-text-hover cursor-pointer text-lg transition-colors"
92
+ onClick={() => handleLanguageChange(nextLocale)}
93
+ >
94
+ <TranslationOutlined />
95
+ </span>
96
+ </Dropdown>
97
+ );
98
+ }
@@ -0,0 +1,93 @@
1
+ import { TeamOutlined } from '@ant-design/icons';
2
+ import { clsx } from 'clsx';
3
+ import { useLocale } from 'next-intl';
4
+ import { useMemo } from 'react';
5
+ import { LanguageSwitcher } from './LanguageSwitcher';
6
+ import { LocaleLink } from '../components/LocaleLink';
7
+ import { ThemeSwitcher } from '../components-app/ThemeSwitcher';
8
+ import type { AppRoutePageProps } from '../components-app/AppRoutePage';
9
+
10
+ /**
11
+ * App Route Page
12
+ *
13
+ * 主要用于 /src/app 目录下页面的基础布局,包含头部、主体内容等
14
+ *
15
+ * @description
16
+ * - /src/app/[locale]/page.tsx
17
+ * - /src/app/[locale]/login/page.tsx
18
+ *
19
+ */
20
+ export function PagesRoutePage({
21
+ children,
22
+ showAdminButton,
23
+ mainProps,
24
+ headerClassName,
25
+ tt,
26
+ headerHref = '/',
27
+ ...props
28
+ }: AppRoutePageProps) {
29
+ const locale = useLocale();
30
+ const adminTitle = tt.adminTitle;
31
+
32
+ const actions = useMemo(() => {
33
+ return [
34
+ showAdminButton && (
35
+ <LocaleLink
36
+ key="admin-button"
37
+ href="/admin"
38
+ title={adminTitle}
39
+ locale={locale}
40
+ className="text-text hover:text-text-hover cursor-pointer text-lg transition-colors"
41
+ >
42
+ <TeamOutlined className="text-lg text-text" />
43
+ </LocaleLink>
44
+ ),
45
+
46
+ <LanguageSwitcher key="language-switcher" />,
47
+
48
+ <ThemeSwitcher key="theme-switcher" />
49
+ ].filter(Boolean);
50
+ }, [adminTitle, showAdminButton, locale]);
51
+
52
+ return (
53
+ <div
54
+ data-testid="AppRoutePage"
55
+ className="flex flex-col min-h-screen"
56
+ {...props}
57
+ >
58
+ <header
59
+ data-testid="BaseHeader"
60
+ className="h-14 bg-secondary border-b border-c-border sticky top-0 z-50"
61
+ >
62
+ <div
63
+ className={clsx(
64
+ 'flex items-center justify-between h-full px-4 mx-auto max-w-7xl',
65
+ headerClassName
66
+ )}
67
+ >
68
+ <div className="flex items-center">
69
+ <LocaleLink
70
+ data-testid="BaseHeaderLogo"
71
+ title={tt.title}
72
+ href={headerHref}
73
+ locale={locale}
74
+ className="flex items-center hover:opacity-80 transition-opacity"
75
+ >
76
+ <span
77
+ data-testid="base-header-app-name"
78
+ className="text-lg font-semibold text-text"
79
+ >
80
+ {tt.title}
81
+ </span>
82
+ </LocaleLink>
83
+ </div>
84
+ <div className="flex items-center gap-2 md:gap-4">{actions}</div>
85
+ </div>
86
+ </header>
87
+
88
+ <main className="flex flex-1 flex-col bg-primary" {...mainProps}>
89
+ {children}
90
+ </main>
91
+ </div>
92
+ );
93
+ }
@@ -1,11 +1,23 @@
1
1
  'use client';
2
2
 
3
+ import {
4
+ type IOCContainerInterface,
5
+ type IOCFunctionInterface
6
+ } from '@qlover/corekit-bridge';
3
7
  import { createContext } from 'react';
8
+ import { ClientIOC } from '@/core/clientIoc/ClientIOC';
4
9
  import type { IOCIdentifierMap } from '@config/IOCIdentifier';
5
- import type {
6
- IOCContainerInterface,
7
- IOCFunctionInterface
8
- } from '@qlover/corekit-bridge';
10
+
11
+ // export const IOCInstance = new ClientIOC();
12
+
13
+ // export const IOCContext =
14
+ // createContext<IOCInterface<IOCIdentifierMap, IOCContainerInterface>>(
15
+ // IOCInstance
16
+ // );
17
+
18
+ export const clientIOC = new ClientIOC();
19
+
20
+ export const IOCInstance = clientIOC.create();
9
21
 
10
22
  export const IOCContext = createContext<IOCFunctionInterface<
11
23
  IOCIdentifierMap,
@@ -0,0 +1,32 @@
1
+ import { useEffect, useRef } from 'react';
2
+
3
+ /**
4
+ * In React Strict Mode, ensure that the effect is executed only once when each dependency changes
5
+ * @param effect The effect function to execute
6
+ * @param deps The dependency array
7
+ */
8
+ export const useStrictEffect = (
9
+ effect: () => void | (() => void),
10
+ deps?: React.DependencyList
11
+ ) => {
12
+ const mountedRef = useRef(false);
13
+ const depsRef = useRef(deps);
14
+
15
+ useEffect(() => {
16
+ // Check if the dependencies have changed
17
+ const depsChanged =
18
+ !deps ||
19
+ !depsRef.current ||
20
+ deps.some((dep, i) => dep !== depsRef.current![i]);
21
+
22
+ // Update the dependency reference
23
+ depsRef.current = deps;
24
+
25
+ // If it's the first mount or the dependencies have changed, execute the effect
26
+ if (!mountedRef.current || depsChanged) {
27
+ mountedRef.current = true;
28
+ return effect();
29
+ }
30
+ // eslint-disable-next-line react-hooks/exhaustive-deps
31
+ }, deps);
32
+ };
@@ -11,7 +11,7 @@
11
11
  "moduleResolution": "bundler",
12
12
  "resolveJsonModule": true,
13
13
  "isolatedModules": true,
14
- "jsx": "preserve",
14
+ "jsx": "react-jsx",
15
15
  "incremental": true,
16
16
  "experimentalDecorators": true,
17
17
  "emitDecoratorMetadata": true,
@@ -32,7 +32,8 @@
32
32
  "src/**/*.tsx",
33
33
  "migrations/**/*.ts",
34
34
  ".next/types/**/*.ts",
35
- "config/**/*.ts"
35
+ "config/**/*.ts",
36
+ ".next/dev/types/**/*.ts"
36
37
  ],
37
38
  "exclude": ["node_modules"]
38
39
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qlover/create-app",
3
- "version": "0.10.1",
3
+ "version": "0.10.2",
4
4
  "description": "Create a new app with a single command",
5
5
  "private": false,
6
6
  "type": "module",
@@ -1,66 +0,0 @@
1
- import { notFound } from 'next/navigation';
2
- import { getMessages, getTranslations } from 'next-intl/server';
3
- import { TranslateI18nInterface } from '@/base/cases/TranslateI18nInterface';
4
- import { i18nConfig } from '@config/i18n';
5
- import type { LocaleType, PageI18nInterface } from '@config/i18n';
6
- import type { ParamsHandlerInterface as ParamsHandlerInterface } from './port/ParamsHandlerInterface';
7
-
8
- export interface PageWithParams {
9
- params?: Promise<PageParamsType>;
10
- }
11
-
12
- export interface PageParamsType {
13
- locale?: string;
14
- }
15
-
16
- /**
17
- * Handler Page Params
18
- */
19
- export class PageParams implements ParamsHandlerInterface {
20
- private locale: string | null;
21
-
22
- constructor(protected readonly params: PageParamsType) {
23
- this.locale = this.params.locale || i18nConfig.fallbackLng;
24
- }
25
-
26
- public getLocale(defaultLocale?: string): string {
27
- if (this.locale) {
28
- return this.locale;
29
- }
30
-
31
- this.locale = this.params.locale || defaultLocale || i18nConfig.fallbackLng;
32
-
33
- return this.locale;
34
- }
35
-
36
- public getI18nWithNotFound(): string {
37
- const locale = this.getLocale();
38
-
39
- if (!i18nConfig.supportedLngs.includes(locale as LocaleType)) {
40
- notFound();
41
- }
42
-
43
- return locale;
44
- }
45
-
46
- public async getI18nMessages(): Promise<Record<string, string>> {
47
- const locale = this.getLocale();
48
-
49
- const messages = await getMessages({ locale });
50
-
51
- return messages;
52
- }
53
-
54
- public async getI18nInterface<T extends PageI18nInterface>(
55
- i18nInterface: T,
56
- namespace?: string
57
- ): Promise<T> {
58
- // Load translation messages from the HomePage namespace
59
- const t = await getTranslations({
60
- locale: this.getLocale(),
61
- namespace: namespace
62
- });
63
-
64
- return TranslateI18nInterface.translate<T>(i18nInterface, t);
65
- }
66
- }
@@ -1,80 +0,0 @@
1
- 'use client';
2
-
3
- import { clsx } from 'clsx';
4
- import { useLocale } from 'next-intl';
5
- import { useMemo } from 'react';
6
- import { useIOC } from '@/uikit/hook/useIOC';
7
- import { COMMON_ADMIN_TITLE } from '@config/Identifier';
8
- import { IOCIdentifier } from '@config/IOCIdentifier';
9
- import { LocaleLink } from './LocaleLink';
10
- import { useWarnTranslations } from '../hook/useWarnTranslations';
11
-
12
- export type RenderLeftFunction = (props: {
13
- locale: string;
14
- defaultElement: React.ReactNode;
15
- }) => React.ReactNode;
16
-
17
- export function BaseHeader(props: {
18
- href?: string;
19
- renderLeft?: React.ReactNode | RenderLeftFunction;
20
- rightActions?: React.ReactNode;
21
- className?: string;
22
- }) {
23
- const { href = '/', className, renderLeft, rightActions } = props;
24
- const appConfig = useIOC(IOCIdentifier.AppConfig);
25
- const locale = useLocale();
26
- const t = useWarnTranslations();
27
-
28
- const tt = {
29
- title: appConfig.appName,
30
- admin: t(COMMON_ADMIN_TITLE)
31
- };
32
-
33
- const leftDefault = useMemo(
34
- () => (
35
- <LocaleLink
36
- data-testid="BaseHeaderLogo"
37
- title={tt.title}
38
- href={href}
39
- locale={locale}
40
- className="flex items-center hover:opacity-80 transition-opacity"
41
- >
42
- <span
43
- data-testid="base-header-app-name"
44
- className="text-lg font-semibold text-text"
45
- >
46
- {tt.title}
47
- </span>
48
- </LocaleLink>
49
- ),
50
- [href, locale, tt.title]
51
- );
52
-
53
- const RenderLeft = useMemo(() => {
54
- if (!renderLeft) {
55
- return leftDefault;
56
- }
57
-
58
- if (typeof renderLeft === 'function') {
59
- return renderLeft({ locale, defaultElement: leftDefault });
60
- }
61
- return renderLeft;
62
- }, [renderLeft, locale, leftDefault]);
63
-
64
- return (
65
- <header
66
- data-testid="BaseHeader"
67
- className="h-14 bg-secondary border-b border-c-border sticky top-0 z-50"
68
- >
69
- <div
70
- className={clsx(
71
- 'flex items-center justify-between h-full px-4 mx-auto max-w-7xl',
72
- className
73
- )}
74
- >
75
- <div className="flex items-center">{RenderLeft}</div>
76
- <div className="flex items-center gap-2 md:gap-4">{rightActions}</div>
77
- </div>
78
- </header>
79
- );
80
- }
@@ -1,65 +0,0 @@
1
- import { TeamOutlined } from '@ant-design/icons';
2
- import { useLocale } from 'next-intl';
3
- import { useMemo, type HTMLAttributes } from 'react';
4
- import { COMMON_ADMIN_TITLE } from '@config/Identifier';
5
- import { BaseHeader } from './BaseHeader';
6
- import { LanguageSwitcher } from './LanguageSwitcher';
7
- import { LocaleLink } from './LocaleLink';
8
- import { LogoutButton } from './LogoutButton';
9
- import { ThemeSwitcher } from './ThemeSwitcher';
10
- import { useWarnTranslations } from '../hook/useWarnTranslations';
11
-
12
- export interface BaseLayoutProps extends HTMLAttributes<HTMLDivElement> {
13
- showLogoutButton?: boolean;
14
- showAdminButton?: boolean;
15
- mainProps?: HTMLAttributes<HTMLElement>;
16
- }
17
-
18
- export function BaseLayout({
19
- children,
20
- showLogoutButton,
21
- showAdminButton,
22
- mainProps,
23
- ...props
24
- }: BaseLayoutProps) {
25
- const locale = useLocale();
26
- const t = useWarnTranslations();
27
-
28
- const tt = {
29
- admin: t(COMMON_ADMIN_TITLE)
30
- };
31
-
32
- const actions = useMemo(
33
- () =>
34
- [
35
- showAdminButton && (
36
- <LocaleLink
37
- key="admin-button"
38
- href="/admin"
39
- title={tt.admin}
40
- locale={locale}
41
- className="text-text hover:text-text-hover cursor-pointer text-lg transition-colors"
42
- >
43
- <TeamOutlined className="text-lg text-text" />
44
- </LocaleLink>
45
- ),
46
- <LanguageSwitcher key="language-switcher" />,
47
- <ThemeSwitcher key="theme-switcher" />,
48
- showLogoutButton && <LogoutButton key="logout-button" />
49
- ].filter(Boolean),
50
- [showAdminButton, tt.admin, locale, showLogoutButton]
51
- );
52
-
53
- return (
54
- <div
55
- data-testid="BaseLayout"
56
- className="flex flex-col min-h-screen"
57
- {...props}
58
- >
59
- <BaseHeader rightActions={actions} />
60
- <main className="flex flex-1 flex-col bg-primary" {...mainProps}>
61
- {children}
62
- </main>
63
- </div>
64
- );
65
- }
@@ -1,58 +0,0 @@
1
- 'use client';
2
- import '@ant-design/v5-patch-for-react-19';
3
- import { AntdRegistry } from '@ant-design/nextjs-registry';
4
- import { AntdThemeProvider } from '@brain-toolkit/antd-theme-override/react';
5
- import { useMountedClient } from '@brain-toolkit/react-kit';
6
- import { ThemeProvider } from 'next-themes';
7
- import { clientIOC } from '@/core/clientIoc/ClientIOC';
8
- import { IOCIdentifier } from '@config/IOCIdentifier';
9
- import type { CommonThemeConfig } from '@config/theme';
10
- import { BootstrapsProvider } from './BootstrapsProvider';
11
-
12
- /**
13
- * CommonProvider is a provider for the common components
14
- *
15
- * - IOCProvider
16
- * - BootstrapsProvider
17
- * - ThemeProvider
18
- * - AntdProvider
19
- *
20
- * @param param0
21
- * @returns
22
- */
23
- export function ComboProvider(props: {
24
- themeConfig: CommonThemeConfig;
25
- children: React.ReactNode;
26
- }) {
27
- /**
28
- * useMountedClient 会等待客户端完全初始化
29
- * 只有在客户端准备就绪后才渲染组件内容
30
- * 这样可以确保所有的客户端代码(包括 API 配置、插件等)都已经正确初始化
31
- */
32
- const mounted = useMountedClient();
33
-
34
- const { themeConfig, children } = props;
35
-
36
- const IOC = clientIOC.create();
37
-
38
- return (
39
- <AntdThemeProvider
40
- data-testid="ComboProvider"
41
- theme={themeConfig.antdTheme}
42
- staticApi={IOC(IOCIdentifier.DialogHandler)}
43
- >
44
- <ThemeProvider
45
- themes={themeConfig.supportedThemes as unknown as string[]}
46
- attribute={themeConfig.domAttribute}
47
- defaultTheme={themeConfig.defaultTheme}
48
- enableSystem
49
- enableColorScheme={false}
50
- storageKey={themeConfig.storageKey}
51
- >
52
- <BootstrapsProvider>
53
- <AntdRegistry>{mounted ? children : null}</AntdRegistry>
54
- </BootstrapsProvider>
55
- </ThemeProvider>
56
- </AntdThemeProvider>
57
- );
58
- }
@@ -1,21 +0,0 @@
1
- import { NextIntlClientProvider, useMessages } from 'next-intl';
2
- import type { ReactNode } from 'react';
3
-
4
- type Props = {
5
- children: ReactNode;
6
- locale: string;
7
- };
8
-
9
- export function NextIntlProvider({ children, locale }: Props) {
10
- const messages = useMessages();
11
-
12
- return (
13
- <NextIntlClientProvider
14
- data-testid="NextIntlProvider"
15
- locale={locale}
16
- messages={messages}
17
- >
18
- {children}
19
- </NextIntlClientProvider>
20
- );
21
- }