@qlover/create-app 0.7.14 → 0.8.0
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 +27 -0
- package/dist/configs/_common/.gitignore.template +6 -0
- package/dist/configs/_common/.prettierignore +17 -5
- package/dist/configs/_common/.vscode/settings.json +6 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/templates/next-app/.env.template +1 -1
- package/dist/templates/next-app/README.en.md +130 -0
- package/dist/templates/next-app/README.md +114 -20
- package/dist/templates/next-app/config/Identifier/api.ts +5 -5
- package/dist/templates/next-app/config/Identifier/common/admint.table.ts +69 -0
- package/dist/templates/next-app/config/Identifier/common/common.ts +76 -0
- package/dist/templates/next-app/config/Identifier/common/index.ts +3 -0
- package/dist/templates/next-app/config/Identifier/{validator.ts → common/validators.ts} +5 -5
- package/dist/templates/next-app/config/Identifier/index.ts +2 -12
- package/dist/templates/next-app/config/Identifier/pages/index.ts +6 -0
- package/dist/templates/next-app/config/Identifier/pages/page.admin.home.ts +27 -0
- package/dist/templates/next-app/config/Identifier/pages/page.admin.locales.ts +266 -0
- package/dist/templates/next-app/config/Identifier/pages/page.admin.user.ts +293 -0
- package/dist/templates/{react-app/config/Identifier → next-app/config/Identifier/pages}/page.home.ts +15 -22
- package/dist/templates/next-app/config/Identifier/{page.login.ts → pages/page.login.ts} +28 -34
- package/dist/templates/next-app/config/Identifier/{page.register.ts → pages/page.register.ts} +30 -29
- package/dist/templates/next-app/config/adminNavs.ts +19 -0
- package/dist/templates/next-app/config/common.ts +22 -13
- package/dist/templates/next-app/config/i18n/HomeI18n.ts +5 -5
- package/dist/templates/next-app/config/i18n/admin18n.ts +61 -19
- package/dist/templates/next-app/config/i18n/i18nConfig.ts +2 -0
- package/dist/templates/next-app/config/i18n/i18nKeyScheam.ts +36 -0
- package/dist/templates/next-app/config/i18n/loginI18n.ts +22 -22
- package/dist/templates/next-app/config/i18n/register18n.ts +23 -24
- package/dist/templates/next-app/docs/en/api.md +387 -0
- package/dist/templates/next-app/docs/en/component.md +544 -0
- package/dist/templates/next-app/docs/en/database.md +496 -0
- package/dist/templates/next-app/docs/en/development-guide.md +727 -0
- package/dist/templates/next-app/docs/en/env.md +563 -0
- package/dist/templates/next-app/docs/en/i18n.md +287 -0
- package/dist/templates/next-app/docs/en/index.md +165 -0
- package/dist/templates/next-app/docs/en/page.md +457 -0
- package/dist/templates/next-app/docs/en/project-structure.md +176 -0
- package/dist/templates/next-app/docs/en/router.md +427 -0
- package/dist/templates/next-app/docs/en/theme.md +532 -0
- package/dist/templates/next-app/docs/en/validator.md +478 -0
- package/dist/templates/next-app/docs/zh/api.md +387 -0
- package/dist/templates/next-app/docs/zh/component.md +544 -0
- package/dist/templates/next-app/docs/zh/database.md +496 -0
- package/dist/templates/next-app/docs/zh/development-guide.md +727 -0
- package/dist/templates/next-app/docs/zh/env.md +563 -0
- package/dist/templates/next-app/docs/zh/i18n.md +287 -0
- package/dist/templates/next-app/docs/zh/index.md +165 -0
- package/dist/templates/next-app/docs/zh/page.md +457 -0
- package/dist/templates/next-app/docs/zh/project-structure.md +176 -0
- package/dist/templates/next-app/docs/zh/router.md +427 -0
- package/dist/templates/next-app/docs/zh/theme.md +532 -0
- package/dist/templates/next-app/docs/zh/validator.md +476 -0
- package/dist/templates/next-app/make/generateLocales.ts +19 -12
- package/dist/templates/next-app/migrations/schema/LocalesSchema.ts +15 -0
- package/dist/templates/next-app/migrations/sql/1694244000000.sql +11 -0
- package/dist/templates/next-app/package.json +7 -3
- package/dist/templates/next-app/public/locales/en.json +172 -207
- package/dist/templates/next-app/public/locales/zh.json +172 -207
- package/dist/templates/next-app/src/app/[locale]/admin/locales/page.tsx +153 -0
- package/dist/templates/next-app/src/app/[locale]/admin/users/page.tsx +48 -50
- package/dist/templates/next-app/src/app/[locale]/login/LoginForm.tsx +2 -2
- package/dist/templates/next-app/src/app/api/admin/locales/create/route.ts +34 -0
- package/dist/templates/next-app/src/app/api/admin/locales/import/route.ts +40 -0
- package/dist/templates/next-app/src/app/api/admin/locales/route.ts +42 -0
- package/dist/templates/next-app/src/app/api/admin/locales/update/route.ts +32 -0
- package/dist/templates/next-app/src/app/api/locales/json/route.ts +44 -0
- package/dist/templates/next-app/src/base/cases/AdminPageManager.ts +1 -13
- package/dist/templates/next-app/src/base/cases/Datetime.ts +18 -0
- package/dist/templates/next-app/src/base/cases/DialogErrorPlugin.ts +12 -6
- package/dist/templates/next-app/src/base/cases/ResourceState.ts +17 -0
- package/dist/templates/next-app/src/base/cases/TranslateI18nInterface.ts +25 -0
- package/dist/templates/next-app/src/base/cases/ZodColumnBuilder.ts +200 -0
- package/dist/templates/next-app/src/base/port/ZodBuilderInterface.ts +8 -0
- package/dist/templates/next-app/src/base/services/AdminLocalesService.ts +20 -0
- package/dist/templates/next-app/src/base/services/AdminPageEvent.ts +26 -0
- package/dist/templates/next-app/src/base/services/AdminPageScheduler.ts +42 -0
- package/dist/templates/next-app/src/base/services/ResourceService.ts +122 -0
- package/dist/templates/next-app/src/base/services/adminApi/AdminLocalesApi.ts +104 -0
- package/dist/templates/next-app/src/base/services/adminApi/AdminUserApi.ts +38 -5
- package/dist/templates/next-app/src/base/services/appApi/AppApiPlugin.ts +1 -1
- package/dist/templates/next-app/src/i18n/request.ts +30 -1
- package/dist/templates/next-app/src/server/PageParams.ts +2 -10
- package/dist/templates/next-app/src/server/port/DBBridgeInterface.ts +5 -0
- package/dist/templates/next-app/src/server/port/DBTableInterface.ts +2 -0
- package/dist/templates/next-app/src/server/port/LocalesRepositoryInterface.ts +43 -0
- package/dist/templates/next-app/src/server/repositorys/LocalesRepository.ts +197 -0
- package/dist/templates/next-app/src/server/services/ApiLocaleService.ts +122 -0
- package/dist/templates/next-app/src/server/sqlBridges/SupabaseBridge.ts +60 -11
- package/dist/templates/next-app/src/server/validators/ExtendedExecutorError.ts +6 -0
- package/dist/templates/next-app/src/server/validators/LocalesValidator.ts +131 -0
- package/dist/templates/next-app/src/server/validators/LoginValidator.ts +2 -5
- package/dist/templates/next-app/src/server/validators/PaginationValidator.ts +32 -16
- package/dist/templates/next-app/src/styles/css/antd-themes/pagination/_default.css +2 -1
- package/dist/templates/next-app/src/styles/css/antd-themes/pagination/dark.css +28 -29
- package/dist/templates/next-app/src/styles/css/antd-themes/pagination/pink.css +2 -1
- package/dist/templates/next-app/src/uikit/components/AdminLayout.tsx +17 -3
- package/dist/templates/next-app/src/uikit/components/BaseHeader.tsx +5 -4
- package/dist/templates/next-app/src/uikit/components/BaseLayout.tsx +5 -4
- package/dist/templates/next-app/src/uikit/components/BootstrapsProvider.tsx +3 -2
- package/dist/templates/next-app/src/uikit/components/ComboProvider.tsx +1 -1
- package/dist/templates/next-app/src/uikit/components/EditableCell.tsx +118 -0
- package/dist/templates/next-app/src/uikit/components/LogoutButton.tsx +5 -6
- package/dist/templates/next-app/src/uikit/components/ThemeSwitcher.tsx +1 -1
- package/dist/templates/next-app/src/uikit/components/With.tsx +2 -2
- package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportButton.tsx +62 -0
- package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportEvent.ts +28 -0
- package/dist/templates/next-app/src/uikit/components/localesImportButton/import.module.css +6 -0
- package/dist/templates/next-app/src/uikit/hook/useI18nInterface.ts +8 -14
- package/dist/templates/next-app/src/uikit/hook/useWarnTranslations.ts +25 -0
- package/dist/templates/react-app/.prettierignore +17 -0
- package/dist/templates/react-app/README.en.md +71 -54
- package/dist/templates/react-app/README.md +35 -18
- package/dist/templates/react-app/__tests__/__mocks__/BootstrapTest.ts +14 -0
- package/dist/templates/react-app/__tests__/__mocks__/MockAppConfit.ts +1 -1
- package/dist/templates/react-app/__tests__/__mocks__/MockDialogHandler.ts +2 -2
- package/dist/templates/react-app/__tests__/__mocks__/MockLogger.ts +1 -1
- package/dist/templates/react-app/__tests__/__mocks__/components/TestApp.tsx +45 -0
- package/dist/templates/react-app/__tests__/__mocks__/components/TestBootstrapsProvider.tsx +34 -0
- package/dist/templates/react-app/__tests__/__mocks__/components/TestRouter.tsx +46 -0
- package/dist/templates/react-app/__tests__/__mocks__/components/index.ts +12 -0
- package/dist/templates/react-app/__tests__/__mocks__/createMockGlobals.ts +1 -2
- package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOC.ts +51 -0
- package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOCRegister.ts +69 -0
- package/dist/templates/react-app/__tests__/setup/index.ts +1 -51
- package/dist/templates/react-app/__tests__/setup/setupGlobal.ts +51 -0
- package/dist/templates/react-app/__tests__/src/App.structure.test.tsx +115 -0
- package/dist/templates/react-app/__tests__/src/base/cases/AppConfig.test.ts +2 -2
- package/dist/templates/react-app/__tests__/src/base/cases/AppError.test.ts +1 -1
- package/dist/templates/react-app/__tests__/src/base/cases/DialogHandler.test.ts +3 -5
- package/dist/templates/react-app/__tests__/src/base/cases/I18nKeyErrorPlugin.test.ts +13 -2
- package/dist/templates/react-app/__tests__/src/base/cases/InversifyContainer.test.ts +1 -1
- package/dist/templates/react-app/__tests__/src/base/cases/PublicAssetsPath.test.ts +1 -1
- package/dist/templates/react-app/__tests__/src/base/cases/RequestLogger.test.ts +5 -5
- package/dist/templates/react-app/__tests__/src/base/cases/RequestStatusCatcher.test.ts +1 -2
- package/dist/templates/react-app/__tests__/src/base/cases/RouterLoader.test.ts +25 -15
- package/dist/templates/react-app/__tests__/src/base/services/I18nService.test.ts +29 -15
- package/dist/templates/react-app/__tests__/src/core/IOC.test.ts +19 -9
- package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapClient.test.ts +153 -0
- package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapsApp.test.ts +9 -7
- package/dist/templates/react-app/__tests__/src/main.integration.test.tsx +4 -5
- package/dist/templates/react-app/__tests__/src/main.test.tsx +4 -4
- package/dist/templates/react-app/__tests__/src/uikit/components/BaseHeader.test.tsx +68 -59
- package/dist/templates/react-app/config/IOCIdentifier.ts +8 -8
- package/dist/templates/react-app/config/Identifier/{common.error.ts → common/common.error.ts} +5 -5
- package/dist/templates/react-app/config/Identifier/{common.ts → common/common.ts} +9 -9
- package/dist/templates/react-app/config/Identifier/common/index.ts +2 -0
- package/dist/templates/react-app/config/Identifier/index.ts +1 -9
- package/dist/templates/react-app/config/Identifier/pages/index.ts +8 -0
- package/dist/templates/react-app/config/Identifier/{page.about.ts → pages/page.about.ts} +34 -26
- package/dist/templates/react-app/config/Identifier/{page.executor.ts → pages/page.executor.ts} +47 -39
- package/dist/templates/{next-app/config/Identifier → react-app/config/Identifier/pages}/page.home.ts +24 -23
- package/dist/templates/react-app/config/Identifier/pages/page.identifiter.ts +102 -0
- package/dist/templates/react-app/config/Identifier/{page.jsonStorage.ts → pages/page.jsonStorage.ts} +18 -11
- package/dist/templates/react-app/config/Identifier/{page.login.ts → pages/page.login.ts} +37 -27
- package/dist/templates/react-app/config/Identifier/{page.register.ts → pages/page.register.ts} +37 -25
- package/dist/templates/react-app/config/Identifier/{page.request.ts → pages/page.request.ts} +34 -44
- package/dist/templates/react-app/config/app.router.ts +66 -69
- package/dist/templates/react-app/config/i18n/PageI18nInterface.ts +51 -0
- package/dist/templates/react-app/config/i18n/aboutI18n.ts +42 -0
- package/dist/templates/react-app/config/i18n/executorI18n.ts +51 -0
- package/dist/templates/react-app/config/i18n/homeI18n.ts +24 -0
- package/dist/templates/react-app/config/i18n/i18nConfig.ts +30 -0
- package/dist/templates/react-app/config/i18n/identifiter18n.ts +30 -0
- package/dist/templates/react-app/config/i18n/jsonStorage18n.ts +27 -0
- package/dist/templates/react-app/config/i18n/login18n.ts +42 -0
- package/dist/templates/react-app/config/i18n/notFoundI18n.ts +34 -0
- package/dist/templates/react-app/config/i18n/register18n.ts +40 -0
- package/dist/templates/react-app/config/i18n/request18n.ts +41 -0
- package/dist/templates/react-app/config/theme.ts +14 -4
- package/dist/templates/react-app/docs/en/bootstrap.md +1670 -341
- package/dist/templates/react-app/docs/en/development-guide.md +1021 -345
- package/dist/templates/react-app/docs/en/env.md +1132 -278
- package/dist/templates/react-app/docs/en/i18n.md +858 -147
- package/dist/templates/react-app/docs/en/index.md +733 -104
- package/dist/templates/react-app/docs/en/ioc.md +1228 -287
- package/dist/templates/react-app/docs/en/playwright/e2e-tests.md +321 -0
- package/dist/templates/react-app/docs/en/playwright/index.md +19 -0
- package/dist/templates/react-app/docs/en/playwright/installation-summary.md +332 -0
- package/dist/templates/react-app/docs/en/playwright/overview.md +222 -0
- package/dist/templates/react-app/docs/en/playwright/quickstart.md +325 -0
- package/dist/templates/react-app/docs/en/playwright/reorganization-notes.md +340 -0
- package/dist/templates/react-app/docs/en/playwright/setup-complete.md +290 -0
- package/dist/templates/react-app/docs/en/playwright/testing-guide.md +565 -0
- package/dist/templates/react-app/docs/en/store.md +1194 -184
- package/dist/templates/react-app/docs/en/why-no-globals.md +797 -0
- package/dist/templates/react-app/docs/zh/bootstrap.md +1670 -341
- package/dist/templates/react-app/docs/zh/development-guide.md +1021 -345
- package/dist/templates/react-app/docs/zh/env.md +1132 -275
- package/dist/templates/react-app/docs/zh/i18n.md +858 -147
- package/dist/templates/react-app/docs/zh/index.md +717 -104
- package/dist/templates/react-app/docs/zh/ioc.md +1229 -287
- package/dist/templates/react-app/docs/zh/playwright/e2e-tests.md +321 -0
- package/dist/templates/react-app/docs/zh/playwright/index.md +19 -0
- package/dist/templates/react-app/docs/zh/playwright/installation-summary.md +332 -0
- package/dist/templates/react-app/docs/zh/playwright/overview.md +222 -0
- package/dist/templates/react-app/docs/zh/playwright/quickstart.md +325 -0
- package/dist/templates/react-app/docs/zh/playwright/reorganization-notes.md +340 -0
- package/dist/templates/react-app/docs/zh/playwright/setup-complete.md +290 -0
- package/dist/templates/react-app/docs/zh/playwright/testing-guide.md +565 -0
- package/dist/templates/react-app/docs/zh/store.md +1192 -184
- package/dist/templates/react-app/docs/zh/why-no-globals.md +797 -0
- package/dist/templates/react-app/e2e/App.spec.ts +319 -0
- package/dist/templates/react-app/e2e/fixtures/base.fixture.ts +40 -0
- package/dist/templates/react-app/e2e/main.spec.ts +20 -0
- package/dist/templates/react-app/e2e/utils/test-helpers.ts +19 -0
- package/dist/templates/react-app/eslint.config.mjs +247 -0
- package/dist/templates/react-app/makes/eslint-utils.mjs +195 -0
- package/dist/templates/react-app/makes/generateTs2LocalesOptions.ts +26 -0
- package/dist/templates/react-app/package.json +31 -3
- package/dist/templates/react-app/playwright.config.ts +79 -0
- package/dist/templates/react-app/public/locales/en/common.json +190 -179
- package/dist/templates/react-app/public/locales/zh/common.json +190 -179
- package/dist/templates/react-app/src/App.tsx +15 -42
- package/dist/templates/react-app/src/base/apis/AiApi.ts +5 -5
- package/dist/templates/react-app/src/base/apis/feApi/FeApi.ts +1 -1
- package/dist/templates/react-app/src/base/apis/feApi/FeApiAdapter.ts +1 -1
- package/dist/templates/react-app/src/base/apis/feApi/FeApiBootstarp.ts +8 -8
- package/dist/templates/react-app/src/base/apis/feApi/FeApiType.ts +1 -1
- package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +6 -6
- package/dist/templates/react-app/src/base/apis/userApi/UserApiAdapter.ts +1 -1
- package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +12 -14
- package/dist/templates/react-app/src/base/apis/userApi/UserApiType.ts +1 -1
- package/dist/templates/react-app/src/base/cases/DialogHandler.ts +5 -2
- package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +3 -3
- package/dist/templates/react-app/src/base/cases/InversifyContainer.ts +3 -3
- package/dist/templates/react-app/src/base/cases/RequestLanguages.ts +2 -2
- package/dist/templates/react-app/src/base/cases/RequestLogger.ts +4 -4
- package/dist/templates/react-app/src/base/cases/RequestStatusCatcher.ts +1 -1
- package/dist/templates/react-app/src/base/cases/ResourceState.ts +23 -0
- package/dist/templates/react-app/src/base/cases/RouterLoader.ts +4 -4
- package/dist/templates/react-app/src/base/cases/TranslateI18nInterface.ts +26 -0
- package/dist/templates/react-app/src/base/port/ExecutorPageBridgeInterface.ts +2 -3
- package/dist/templates/react-app/src/base/port/I18nServiceInterface.ts +1 -1
- package/dist/templates/react-app/src/base/port/IOCInterface.ts +36 -0
- package/dist/templates/react-app/src/base/port/JSONStoragePageBridgeInterface.ts +2 -1
- package/dist/templates/react-app/src/base/port/ProcesserExecutorInterface.ts +1 -1
- package/dist/templates/react-app/src/base/port/RequestPageBridgeInterface.ts +2 -2
- package/dist/templates/react-app/src/base/port/RouteServiceInterface.ts +9 -5
- package/dist/templates/react-app/src/base/port/UserServiceInterface.ts +1 -1
- package/dist/templates/react-app/src/base/services/I18nService.ts +29 -29
- package/dist/templates/react-app/src/base/services/IdentifierService.ts +143 -0
- package/dist/templates/react-app/src/base/services/ProcesserExecutor.ts +3 -3
- package/dist/templates/react-app/src/base/services/RouteService.ts +27 -8
- package/dist/templates/react-app/src/base/services/UserService.ts +8 -8
- package/dist/templates/react-app/src/base/types/Page.ts +14 -2
- package/dist/templates/react-app/src/base/types/global.d.ts +1 -1
- package/dist/templates/react-app/src/core/IOC.ts +5 -46
- package/dist/templates/react-app/src/core/bootstraps/{BootstrapApp.ts → BootstrapClient.ts} +44 -17
- package/dist/templates/react-app/src/core/bootstraps/BootstrapsRegistry.ts +14 -7
- package/dist/templates/react-app/src/core/bootstraps/IocIdentifierTest.ts +1 -1
- package/dist/templates/react-app/src/core/bootstraps/PrintBootstrap.ts +1 -1
- package/dist/templates/react-app/src/core/clientIoc/ClientIOC.ts +40 -0
- package/dist/templates/react-app/src/core/{IocRegisterImpl.ts → clientIoc/ClientIOCRegister.ts} +35 -24
- package/dist/templates/react-app/src/core/globals.ts +9 -9
- package/dist/templates/react-app/src/main.tsx +4 -4
- package/dist/templates/react-app/src/pages/404.tsx +6 -3
- package/dist/templates/react-app/src/pages/500.tsx +5 -2
- package/dist/templates/react-app/src/pages/NoRouteFound.tsx +5 -0
- package/dist/templates/react-app/src/pages/auth/Layout.tsx +9 -6
- package/dist/templates/react-app/src/pages/auth/LoginPage.tsx +46 -56
- package/dist/templates/react-app/src/pages/auth/RegisterPage.tsx +46 -58
- package/dist/templates/react-app/src/pages/base/AboutPage.tsx +35 -40
- package/dist/templates/react-app/src/pages/base/ExecutorPage.tsx +51 -51
- package/dist/templates/react-app/src/pages/base/HomePage.tsx +14 -15
- package/dist/templates/react-app/src/pages/base/IdentifierPage.tsx +70 -11
- package/dist/templates/react-app/src/pages/base/JSONStoragePage.tsx +24 -25
- package/dist/templates/react-app/src/pages/base/Layout.tsx +2 -2
- package/dist/templates/react-app/src/pages/base/RedirectPathname.tsx +3 -2
- package/dist/templates/react-app/src/pages/base/RequestPage.tsx +41 -59
- package/dist/templates/react-app/src/styles/css/antd-themes/{_default.css → _common/_default.css} +85 -0
- package/dist/templates/react-app/src/styles/css/antd-themes/{dark.css → _common/dark.css} +99 -0
- package/dist/templates/react-app/src/styles/css/antd-themes/_common/index.css +3 -0
- package/dist/templates/react-app/src/styles/css/antd-themes/{pink.css → _common/pink.css} +86 -0
- package/dist/templates/react-app/src/styles/css/antd-themes/index.css +4 -3
- package/dist/templates/react-app/src/styles/css/antd-themes/menu/_default.css +108 -0
- package/dist/templates/react-app/src/styles/css/antd-themes/menu/dark.css +67 -0
- package/dist/templates/react-app/src/styles/css/antd-themes/menu/index.css +3 -0
- package/dist/templates/react-app/src/styles/css/antd-themes/menu/pink.css +67 -0
- package/dist/templates/react-app/src/styles/css/antd-themes/pagination/_default.css +34 -0
- package/dist/templates/react-app/src/styles/css/antd-themes/pagination/dark.css +31 -0
- package/dist/templates/react-app/src/styles/css/antd-themes/pagination/index.css +3 -0
- package/dist/templates/react-app/src/styles/css/antd-themes/pagination/pink.css +36 -0
- package/dist/templates/react-app/src/styles/css/antd-themes/table/_default.css +44 -0
- package/dist/templates/react-app/src/styles/css/antd-themes/table/dark.css +43 -0
- package/dist/templates/react-app/src/styles/css/antd-themes/table/index.css +3 -0
- package/dist/templates/react-app/src/styles/css/antd-themes/table/pink.css +43 -0
- package/dist/templates/react-app/src/styles/css/page.css +4 -3
- package/dist/templates/react-app/src/styles/css/themes/_default.css +1 -0
- package/dist/templates/react-app/src/styles/css/themes/dark.css +1 -0
- package/dist/templates/react-app/src/styles/css/themes/pink.css +1 -0
- package/dist/templates/react-app/src/styles/css/zIndex.css +1 -1
- package/dist/templates/react-app/src/uikit/bridges/ExecutorPageBridge.ts +3 -3
- package/dist/templates/react-app/src/uikit/bridges/JSONStoragePageBridge.ts +2 -2
- package/dist/templates/react-app/src/uikit/bridges/NavigateBridge.ts +1 -1
- package/dist/templates/react-app/src/uikit/bridges/RequestPageBridge.ts +3 -3
- package/dist/templates/react-app/src/uikit/components/AppRouterProvider.tsx +35 -0
- package/dist/templates/react-app/src/uikit/components/BaseHeader.tsx +15 -11
- package/dist/templates/react-app/src/uikit/components/BaseRouteProvider.tsx +14 -11
- package/dist/templates/react-app/src/uikit/components/BaseRouteSeo.tsx +18 -0
- package/dist/templates/react-app/src/uikit/components/BootstrapsProvider.tsx +13 -0
- package/dist/templates/react-app/src/uikit/components/ClientSeo.tsx +62 -0
- package/dist/templates/react-app/src/uikit/components/ComboProvider.tsx +38 -0
- package/dist/templates/react-app/src/uikit/components/LanguageSwitcher.tsx +48 -27
- package/dist/templates/react-app/src/uikit/components/Loading.tsx +4 -2
- package/dist/templates/react-app/src/uikit/components/LocaleLink.tsx +4 -5
- package/dist/templates/react-app/src/uikit/components/LogoutButton.tsx +34 -11
- package/dist/templates/react-app/src/uikit/components/ProcessExecutorProvider.tsx +9 -5
- package/dist/templates/react-app/src/uikit/components/RouterRenderComponent.tsx +6 -3
- package/dist/templates/react-app/src/uikit/components/ThemeSwitcher.tsx +97 -40
- package/dist/templates/react-app/src/uikit/components/UserAuthProvider.tsx +5 -5
- package/dist/templates/react-app/src/uikit/components/With.tsx +17 -0
- package/dist/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +17 -11
- package/dist/templates/react-app/src/uikit/contexts/IOCContext.ts +13 -0
- package/dist/templates/react-app/src/uikit/hooks/useAppTranslation.ts +26 -0
- package/dist/templates/react-app/src/uikit/hooks/useI18nGuard.ts +8 -11
- package/dist/templates/react-app/src/uikit/hooks/useI18nInterface.ts +25 -0
- package/dist/templates/react-app/src/uikit/hooks/useIOC.ts +35 -0
- package/dist/templates/react-app/src/uikit/hooks/useNavigateBridge.ts +3 -3
- package/dist/templates/react-app/src/uikit/hooks/useStrictEffect.ts +0 -1
- package/dist/templates/react-app/tsconfig.e2e.json +21 -0
- package/dist/templates/react-app/tsconfig.json +8 -1
- package/dist/templates/react-app/tsconfig.node.json +1 -1
- package/dist/templates/react-app/tsconfig.test.json +3 -1
- package/dist/templates/react-app/vite.config.ts +50 -34
- package/package.json +2 -1
- package/dist/configs/react-app/eslint.config.js +0 -94
- package/dist/templates/next-app/config/Identifier/common.error.ts +0 -41
- package/dist/templates/next-app/config/Identifier/common.ts +0 -69
- package/dist/templates/next-app/config/Identifier/page.about.ts +0 -181
- package/dist/templates/next-app/config/Identifier/page.admin.ts +0 -48
- package/dist/templates/next-app/config/Identifier/page.executor.ts +0 -272
- package/dist/templates/next-app/config/Identifier/page.identifiter.ts +0 -39
- package/dist/templates/next-app/config/Identifier/page.jsonStorage.ts +0 -72
- package/dist/templates/next-app/config/Identifier/page.request.ts +0 -182
- package/dist/templates/next-app/docs/env.md +0 -94
- package/dist/templates/next-app/src/base/cases/ChatAction.ts +0 -21
- package/dist/templates/next-app/src/base/cases/FocusBarAction.ts +0 -36
- package/dist/templates/next-app/src/base/cases/RequestState.ts +0 -20
- package/dist/templates/next-app/src/base/port/AdminPageInterface.ts +0 -85
- package/dist/templates/next-app/src/base/port/AsyncStateInterface.ts +0 -7
- package/dist/templates/next-app/src/base/services/AdminUserService.ts +0 -45
- package/dist/templates/next-app/src/uikit/components/ChatRoot.tsx +0 -17
- package/dist/templates/next-app/src/uikit/components/chat/ChatActionInterface.ts +0 -30
- package/dist/templates/next-app/src/uikit/components/chat/ChatFocusBar.tsx +0 -65
- package/dist/templates/next-app/src/uikit/components/chat/ChatMessages.tsx +0 -59
- package/dist/templates/next-app/src/uikit/components/chat/ChatWrap.tsx +0 -28
- package/dist/templates/next-app/src/uikit/components/chat/FocusBarActionInterface.ts +0 -19
- package/dist/templates/next-app/src/uikit/hook/useMountedClient.ts +0 -17
- package/dist/templates/next-app/src/uikit/hook/useStore.ts +0 -15
- package/dist/templates/react-app/__tests__/__mocks__/I18nService.ts +0 -13
- package/dist/templates/react-app/__tests__/src/App.test.tsx +0 -139
- package/dist/templates/react-app/config/Identifier/page.identifiter.ts +0 -39
- package/dist/templates/react-app/config/i18n.ts +0 -15
- package/dist/templates/react-app/docs/en/project-structure.md +0 -434
- package/dist/templates/react-app/docs/zh/project-structure.md +0 -434
- package/dist/templates/react-app/src/base/cases/RequestState.ts +0 -20
- package/dist/templates/react-app/src/base/port/AsyncStateInterface.ts +0 -7
- package/dist/templates/react-app/src/uikit/hooks/useDocumentTitle.ts +0 -15
- package/dist/templates/react-app/src/uikit/hooks/useStore.ts +0 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @qlover/create-app
|
|
2
2
|
|
|
3
|
+
## 0.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
## 0.7.15
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
#### ✨ Features
|
|
12
|
+
|
|
13
|
+
- **next-app:** enhance README and documentation for full-stack application template ([198e829](https://github.com/qlover/fe-base/commit/198e829719dfabb2261aa939c6ae69cdba45c9f0)) ([#522](https://github.com/qlover/fe-base/pull/522))
|
|
14
|
+
- Translated README.md to Chinese and expanded content to provide a comprehensive overview of the Next.js full-stack application template.
|
|
15
|
+
- Added detailed sections on features, project structure, environment requirements, and quick start instructions.
|
|
16
|
+
- Introduced new documentation files covering API development, component development, database management, internationalization, and validation guidelines.
|
|
17
|
+
- Removed outdated env.md file and replaced it with a more comprehensive environment variable configuration guide.
|
|
18
|
+
- Improved organization and clarity of documentation to facilitate better understanding and onboarding for developers.
|
|
19
|
+
|
|
20
|
+
These changes aim to enhance the usability and accessibility of the project documentation, supporting developers in leveraging the full capabilities of the template.
|
|
21
|
+
|
|
22
|
+
- **next-app:** add comprehensive documentation for full-stack application template ([50029df](https://github.com/qlover/fe-base/commit/50029df11026b5f7e7ea0ae49d0938ed955971d3)) ([#522](https://github.com/qlover/fe-base/pull/522))
|
|
23
|
+
- Introduced new documentation files covering API development, component architecture, database management, internationalization, and validation guidelines.
|
|
24
|
+
- Enhanced the README with detailed project features, structure, and quick start instructions.
|
|
25
|
+
- Added environment variable configuration guide to streamline setup across different environments.
|
|
26
|
+
- Improved organization and clarity of documentation to facilitate better understanding and onboarding for developers.
|
|
27
|
+
|
|
28
|
+
These changes aim to enhance the usability and accessibility of the project documentation, supporting developers in leveraging the full capabilities of the template.
|
|
29
|
+
|
|
3
30
|
## 0.7.14
|
|
4
31
|
|
|
5
32
|
### Patch Changes
|
|
@@ -1,5 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
# Build output
|
|
2
|
+
dist
|
|
3
|
+
dist/**
|
|
4
|
+
|
|
5
|
+
# Dependencies
|
|
6
|
+
node_modules
|
|
7
|
+
|
|
8
|
+
# Generated files
|
|
9
|
+
public/locales/**
|
|
10
|
+
|
|
11
|
+
# Coverage
|
|
12
|
+
coverage
|
|
13
|
+
|
|
14
|
+
# Playwright reports
|
|
15
|
+
playwright-report
|
|
16
|
+
test-results
|
|
17
|
+
|
|
@@ -7,5 +7,10 @@
|
|
|
7
7
|
"tailwindCSS.rootFontSize": 10,
|
|
8
8
|
"editor.snippetSuggestions": "top",
|
|
9
9
|
"vitest.autoRun": false,
|
|
10
|
-
"workbench.view.alwaysShowHeaderActions": true
|
|
10
|
+
"workbench.view.alwaysShowHeaderActions": true,
|
|
11
|
+
"playwright.reuseBrowser": true,
|
|
12
|
+
"playwright.showTrace": true,
|
|
13
|
+
"playwright.env": {
|
|
14
|
+
"PLAYWRIGHT_BASE_URL": "http://localhost:3200"
|
|
15
|
+
}
|
|
11
16
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -8,4 +8,4 @@ ${t}`,_n=Object.getOwnPropertyDescriptor(Function.prototype,"toString"),mn=Objec
|
|
|
8
8
|
`))this.#e+=Math.max(1,Math.ceil(Ye(D,{countAnsiEscapeCodes:!0})/t))}get isEnabled(){return this.#a&&!this.#F}set isEnabled(t){if(typeof t!="boolean")throw new TypeError("The `isEnabled` option must be a boolean");this.#a=t}get isSilent(){return this.#F}set isSilent(t){if(typeof t!="boolean")throw new TypeError("The `isSilent` option must be a boolean");this.#F=t}frame(){let t=Date.now();(this.#i===-1||t-this.#c>=this.interval)&&(this.#i=++this.#i%this.#D.frames.length,this.#c=t);let{frames:r}=this.#D,u=r[this.#i];this.color&&(u=d[this.color](u));let i=typeof this.#s=="string"&&this.#s!==""?this.#s+" ":"",D=typeof this.text=="string"?" "+this.text:"",o=typeof this.#o=="string"&&this.#o!==""?" "+this.#o:"";return i+u+D+o}clear(){if(!this.#a||!this.#u.isTTY)return this;this.#u.cursorTo(0);for(let t=0;t<this.#n;t++)t>0&&this.#u.moveCursor(0,-1),this.#u.clearLine(1);return(this.#l||this.lastIndent!==this.#l)&&this.#u.cursorTo(this.#l),this.lastIndent=this.#l,this.#n=0,this}render(){return this.#F?this:(this.clear(),this.#u.write(this.frame()),this.#n=this.#e,this)}start(t){return t&&(this.text=t),this.#F?this:this.#a?this.isSpinning?this:(this.#t.hideCursor&&$e.hide(this.#u),this.#t.discardStdin&&V.default.stdin.isTTY&&(this.#r=!0,Je.start()),this.render(),this.#f=setInterval(this.render.bind(this),this.interval),this):(this.text&&this.#u.write(`- ${this.text}
|
|
9
9
|
`),this)}stop(){return this.#a?(clearInterval(this.#f),this.#f=void 0,this.#i=0,this.clear(),this.#t.hideCursor&&$e.show(this.#u),this.#t.discardStdin&&V.default.stdin.isTTY&&this.#r&&(Je.stop(),this.#r=!1),this):this}succeed(t){return this.stopAndPersist({symbol:H.success,text:t})}fail(t){return this.stopAndPersist({symbol:H.error,text:t})}warn(t){return this.stopAndPersist({symbol:H.warning,text:t})}info(t){return this.stopAndPersist({symbol:H.info,text:t})}stopAndPersist(t={}){if(this.#F)return this;let r=t.prefixText??this.#s,u=this.#E(r," "),i=t.symbol??" ",D=t.text??this.text,s=typeof D=="string"?(i?" ":"")+D:"",a=t.suffixText??this.#o,l=this.#g(a," "),p=u+i+s+l+`
|
|
10
10
|
`;return this.stop(),this.#u.write(p),this}};function rr(e){return new Ze(e)}async function ur(e,t){let r=typeof e=="function",u=typeof e.then=="function";if(!r&&!u)throw new TypeError("Parameter `action` must be a Function or a Promise");let{successText:i,failText:D}=typeof t=="object"?t:{successText:void 0,failText:void 0},o=rr(t).start();try{let a=await(r?e(o):e);return o.succeed(i===void 0?void 0:typeof i=="string"?i:i(a)),a}catch(s){throw o.fail(D===void 0?void 0:typeof D=="string"?D:D(s)),s}}var bt=require("fs");var P=require("path"),me=require("fs"),fr=h(cr(),1),Dt=require("fs");var de=require("fs"),X=class{static ensureDir(t){(0,de.existsSync)(t)||(0,de.mkdirSync)(t,{recursive:!0})}};var{copyFile:us,stat:is}=Dt.promises,_e=class e{constructor(t,r=e.IGNORE_FILE){this.ignoreTargetPath=t;this.ignoreFile=r}static IGNORE_FILE=".gitignore.template";getIg(t=this.ignoreTargetPath){let r=(0,P.join)(t,this.ignoreFile);if(!(0,me.existsSync)(r))return;let D=(0,me.readFileSync)(r,"utf8").split(`
|
|
11
|
-
`).map(o=>o.trim()).filter(o=>o&&!o.startsWith("#"));return(0,fr.default)().add(D)}async copyFiles(t,r,u,i){let D=await Dt.promises.readdir(t);await Promise.all(D.map(async o=>{let s=(0,P.join)(t,o),a=(0,P.join)(r,o);if(u&&u.ignores(o))return;if(X.ensureDir((0,P.dirname)(a)),(await is(s)).isDirectory())await this.copyFiles(s,a,u,i);else{if(i&&await i(s,a))return;await us(s,a)}}))}copyPaths({sourcePath:t,targetPath:r,copyCallback:u}){X.ensureDir(r);let i=this.getIg();return this.copyFiles(t,r,i,u)}};var L=require("fs"),$D=h(kD(),1),xe=class{constructor(){}isJSONFilePath(t){return t.endsWith(".json")||t.endsWith(".json.template")}isTemplateFilePath(t){return t.endsWith(".template")}getRealTemplateFilePath(t){return t.replace(".template","")}readFile(t){return(0,L.readFileSync)(t,"utf-8")}readJSONFile(t){return JSON.parse(this.readFile(t))}writeFile(t,r){(0,L.writeFileSync)(this.getRealTemplateFilePath(t),r,{encoding:"utf-8"})}replaceFile(t,r){let u=this.readFile(t);return Object.keys(r).forEach(i=>{let D=r[i];u=u.replace(new RegExp(`\\[TPL:${i}\\]`,"g"),typeof D=="string"?D:JSON.stringify(D))}),u}mergeJSONFile(t,r){let u=this.readJSONFile(t),i=(0,$D.default)(r,u);this.writeFile(t,JSON.stringify(i,null,2))}composeConfigFile(t,r,u){if(this.isTemplateFilePath(r)){let i=this.replaceFile(r,t);if(this.isJSONFilePath(r)&&this.isJSONFilePath(u)){let D=this.getRealTemplateFilePath(u);return(0,L.existsSync)(D)?(this.mergeJSONFile(D,JSON.parse(i)),!0):(this.writeFile(D,i),!0)}return this.writeFile(u,i),!0}return!1}};var UD=["pack-app"],ye=class{ora;context;subPackages;copyer;compose;constructor(t){let r=t.options?.templateRootPath;if(!r)throw new Error("template path not exit");if(!(0,bt.existsSync)(r))throw new Error("template path not exit");this.ora=ur,this.context=new WD.ScriptContext("create-app",t),this.subPackages=["node-lib","react-app","next-app"],this.copyer=new _e((0,v.join)(this.context.options.configsRootPath,"_common")),this.compose=new xe}get logger(){return this.context.logger}async steps(t){try{return await HD.default.prompt(t)}catch(r){throw r.isTtyError,this.logger.error(r),r}}async action({label:t,task:r}){let u=r();u instanceof Promise||(u=Promise.resolve(u));let i=t;return this.ora(u,i),u}isPackageTemplate(t){return UD.includes(t)}async getGeneratorContext(){let t=wt(this.subPackages,UD),r=await this.steps(t);if(this.isPackageTemplate(r.template)){let u=Pt(this.subPackages),i=await this.steps(u);Object.assign(r,i)}return r.targetPath=(0,v.join)(process.cwd(),r.projectName),r.releasePath=r.releasePath||"src",r}async generate(){let t=await this.getGeneratorContext();if(this.logger.debug("context is:",t,this.context.options.templateRootPath),t.subPackages){await this.action({label:"Generate Directories(subPackages)",task:async()=>{await this.generateTemplateDir(t),await this.generateSubPackages(t),await this.generateConfigs(t,t.targetPath,"_common")}});return}await this.action({label:"Generate Directory",task:async()=>{await this.generateTemplateDir(t),await this.generateConfigs(t,t.targetPath,"_common"),await this.generateConfigs(t,t.targetPath,t.template)}})}async generateConfigs(t,r,u){let i=(a,l)=>(this.logger.debug("copyCallback",a,l),this.compose.composeConfigFile(t,a,l)),{configsRootPath:D,config:o}=this.context.options;if(!o){this.logger.debug("no copy config files");return}let s=(0,v.join)(D,u);if(!(0,bt.existsSync)(s)){this.logger.debug(`Config path not found: ${s}`);return}await this.copyer.copyPaths({sourcePath:s,targetPath:r,copyCallback:i})}generateTemplateDir(t){return this.copyer.copyPaths({sourcePath:(0,v.join)(this.context.options.templateRootPath,t.template),targetPath:t.targetPath})}async generateSubPackages(t){let{packagesNames:r="packages",subPackages:u=[],targetPath:i=""}=t,{templateRootPath:D}=this.context.options;for(let o of u){let s=(0,v.join)(D,o),a=(0,v.join)(i,r,o);this.logger.debug("copy sub package",s,a),await this.copyer.copyPaths({sourcePath:s,targetPath:a})}}};var vt={name:"@qlover/create-app",version:"0.
|
|
11
|
+
`).map(o=>o.trim()).filter(o=>o&&!o.startsWith("#"));return(0,fr.default)().add(D)}async copyFiles(t,r,u,i){let D=await Dt.promises.readdir(t);await Promise.all(D.map(async o=>{let s=(0,P.join)(t,o),a=(0,P.join)(r,o);if(u&&u.ignores(o))return;if(X.ensureDir((0,P.dirname)(a)),(await is(s)).isDirectory())await this.copyFiles(s,a,u,i);else{if(i&&await i(s,a))return;await us(s,a)}}))}copyPaths({sourcePath:t,targetPath:r,copyCallback:u}){X.ensureDir(r);let i=this.getIg();return this.copyFiles(t,r,i,u)}};var L=require("fs"),$D=h(kD(),1),xe=class{constructor(){}isJSONFilePath(t){return t.endsWith(".json")||t.endsWith(".json.template")}isTemplateFilePath(t){return t.endsWith(".template")}getRealTemplateFilePath(t){return t.replace(".template","")}readFile(t){return(0,L.readFileSync)(t,"utf-8")}readJSONFile(t){return JSON.parse(this.readFile(t))}writeFile(t,r){(0,L.writeFileSync)(this.getRealTemplateFilePath(t),r,{encoding:"utf-8"})}replaceFile(t,r){let u=this.readFile(t);return Object.keys(r).forEach(i=>{let D=r[i];u=u.replace(new RegExp(`\\[TPL:${i}\\]`,"g"),typeof D=="string"?D:JSON.stringify(D))}),u}mergeJSONFile(t,r){let u=this.readJSONFile(t),i=(0,$D.default)(r,u);this.writeFile(t,JSON.stringify(i,null,2))}composeConfigFile(t,r,u){if(this.isTemplateFilePath(r)){let i=this.replaceFile(r,t);if(this.isJSONFilePath(r)&&this.isJSONFilePath(u)){let D=this.getRealTemplateFilePath(u);return(0,L.existsSync)(D)?(this.mergeJSONFile(D,JSON.parse(i)),!0):(this.writeFile(D,i),!0)}return this.writeFile(u,i),!0}return!1}};var UD=["pack-app"],ye=class{ora;context;subPackages;copyer;compose;constructor(t){let r=t.options?.templateRootPath;if(!r)throw new Error("template path not exit");if(!(0,bt.existsSync)(r))throw new Error("template path not exit");this.ora=ur,this.context=new WD.ScriptContext("create-app",t),this.subPackages=["node-lib","react-app","next-app"],this.copyer=new _e((0,v.join)(this.context.options.configsRootPath,"_common")),this.compose=new xe}get logger(){return this.context.logger}async steps(t){try{return await HD.default.prompt(t)}catch(r){throw r.isTtyError,this.logger.error(r),r}}async action({label:t,task:r}){let u=r();u instanceof Promise||(u=Promise.resolve(u));let i=t;return this.ora(u,i),u}isPackageTemplate(t){return UD.includes(t)}async getGeneratorContext(){let t=wt(this.subPackages,UD),r=await this.steps(t);if(this.isPackageTemplate(r.template)){let u=Pt(this.subPackages),i=await this.steps(u);Object.assign(r,i)}return r.targetPath=(0,v.join)(process.cwd(),r.projectName),r.releasePath=r.releasePath||"src",r}async generate(){let t=await this.getGeneratorContext();if(this.logger.debug("context is:",t,this.context.options.templateRootPath),t.subPackages){await this.action({label:"Generate Directories(subPackages)",task:async()=>{await this.generateTemplateDir(t),await this.generateSubPackages(t),await this.generateConfigs(t,t.targetPath,"_common")}});return}await this.action({label:"Generate Directory",task:async()=>{await this.generateTemplateDir(t),await this.generateConfigs(t,t.targetPath,"_common"),await this.generateConfigs(t,t.targetPath,t.template)}})}async generateConfigs(t,r,u){let i=(a,l)=>(this.logger.debug("copyCallback",a,l),this.compose.composeConfigFile(t,a,l)),{configsRootPath:D,config:o}=this.context.options;if(!o){this.logger.debug("no copy config files");return}let s=(0,v.join)(D,u);if(!(0,bt.existsSync)(s)){this.logger.debug(`Config path not found: ${s}`);return}await this.copyer.copyPaths({sourcePath:s,targetPath:r,copyCallback:i})}generateTemplateDir(t){return this.copyer.copyPaths({sourcePath:(0,v.join)(this.context.options.templateRootPath,t.template),targetPath:t.targetPath})}async generateSubPackages(t){let{packagesNames:r="packages",subPackages:u=[],targetPath:i=""}=t,{templateRootPath:D}=this.context.options;for(let o of u){let s=(0,v.join)(D,o),a=(0,v.join)(i,r,o);this.logger.debug("copy sub package",s,a),await this.copyer.copyPaths({sourcePath:s,targetPath:a})}}};var vt={name:"@qlover/create-app",version:"0.8.0",description:"Create a new app with a single command",private:!1,type:"module",files:["dist","package.json","README.md","CHANGELOG.md"],bin:{"create-app":"dist/index.js"},scripts:{lint:"eslint src --fix",build:"tsup","create:app":"node ./dist/index.js"},repository:{type:"git",url:"git+https://github.com/qlover/fe-base.git",directory:"packages/create-app"},homepage:"https://github.com/qlover/fe-base#readme",keywords:["create-app","fe-scripts","scripts"],author:"qlover",license:"ISC",publishConfig:{access:"public"},devDependencies:{"@qlover/logger":"workspace:*",ignore:"^7.0.3",lodash:"^4.17.21",ora:"^8.1.1"},dependencies:{"@qlover/scripts-context":"workspace:*",commander:"^13.1.0",inquirer:"^12.3.2"}};function Wl(){let e=new YD.Command;return e.version(vt.version,"-v, --version","Show version").description(vt.description).option("-d, --dry-run","Do not touch or write anything, but show the commands").option("-V, --verbose","Show more information").option("--config","Copy config files (default: true)",!0).option("--no-config","Do not copy config files"),e.parse(),e.opts()}async function VD(e=process.cwd()){let{dryRun:t,verbose:r,...u}=Wl(),i=(0,xt.resolve)(e,"./templates"),D=(0,xt.resolve)(e,"./configs");(0,yt.existsSync)(i)||(console.error("Template is empty!"),process.exit(1)),(0,yt.existsSync)(D)||(console.error("Configs is empty!"),process.exit(1)),await new ye({dryRun:t,verbose:r,options:{...u,templateRootPath:i,configsRootPath:D}}).generate()}VD(__dirname).catch(e=>{console.error(e),process.exit(1)});
|
package/dist/index.js
CHANGED
|
@@ -8,4 +8,4 @@ ${t}`,pD=Object.getOwnPropertyDescriptor(Function.prototype,"toString"),hD=Objec
|
|
|
8
8
|
`))this.#e+=Math.max(1,Math.ceil(Le(n,{countAnsiEscapeCodes:!0})/t))}get isEnabled(){return this.#a&&!this.#F}set isEnabled(t){if(typeof t!="boolean")throw new TypeError("The `isEnabled` option must be a boolean");this.#a=t}get isSilent(){return this.#F}set isSilent(t){if(typeof t!="boolean")throw new TypeError("The `isSilent` option must be a boolean");this.#F=t}frame(){let t=Date.now();(this.#i===-1||t-this.#c>=this.interval)&&(this.#i=++this.#i%this.#n.frames.length,this.#c=t);let{frames:r}=this.#n,u=r[this.#i];this.color&&(u=E[this.color](u));let i=typeof this.#s=="string"&&this.#s!==""?this.#s+" ":"",n=typeof this.text=="string"?" "+this.text:"",o=typeof this.#o=="string"&&this.#o!==""?" "+this.#o:"";return i+u+n+o}clear(){if(!this.#a||!this.#u.isTTY)return this;this.#u.cursorTo(0);for(let t=0;t<this.#D;t++)t>0&&this.#u.moveCursor(0,-1),this.#u.clearLine(1);return(this.#l||this.lastIndent!==this.#l)&&this.#u.cursorTo(this.#l),this.lastIndent=this.#l,this.#D=0,this}render(){return this.#F?this:(this.clear(),this.#u.write(this.frame()),this.#D=this.#e,this)}start(t){return t&&(this.text=t),this.#F?this:this.#a?this.isSpinning?this:(this.#t.hideCursor&&je.hide(this.#u),this.#t.discardStdin&&ce.stdin.isTTY&&(this.#r=!0,We.start()),this.render(),this.#f=setInterval(this.render.bind(this),this.interval),this):(this.text&&this.#u.write(`- ${this.text}
|
|
9
9
|
`),this)}stop(){return this.#a?(clearInterval(this.#f),this.#f=void 0,this.#i=0,this.clear(),this.#t.hideCursor&&je.show(this.#u),this.#t.discardStdin&&ce.stdin.isTTY&&this.#r&&(We.stop(),this.#r=!1),this):this}succeed(t){return this.stopAndPersist({symbol:k.success,text:t})}fail(t){return this.stopAndPersist({symbol:k.error,text:t})}warn(t){return this.stopAndPersist({symbol:k.warning,text:t})}info(t){return this.stopAndPersist({symbol:k.info,text:t})}stopAndPersist(t={}){if(this.#F)return this;let r=t.prefixText??this.#s,u=this.#E(r," "),i=t.symbol??" ",n=t.text??this.text,s=typeof n=="string"?(i?" ":"")+n:"",a=t.suffixText??this.#o,l=this.#g(a," "),p=u+i+s+l+`
|
|
10
10
|
`;return this.stop(),this.#u.write(p),this}};function zt(e){return new He(e)}async function Kt(e,t){let r=typeof e=="function",u=typeof e.then=="function";if(!r&&!u)throw new TypeError("Parameter `action` must be a Function or a Promise");let{successText:i,failText:n}=typeof t=="object"?t:{successText:void 0,failText:void 0},o=zt(t).start();try{let a=await(r?e(o):e);return o.succeed(i===void 0?void 0:typeof i=="string"?i:i(a)),a}catch(s){throw o.fail(n===void 0?void 0:typeof n=="string"?n:n(s)),s}}import{existsSync as Nn}from"fs";var nr=ue(ir(),1);import{dirname as QD,join as Ze}from"path";import{existsSync as es,readFileSync as ts}from"fs";import{promises as Dr}from"fs";import{existsSync as JD,mkdirSync as ZD}from"fs";var H=class{static ensureDir(t){JD(t)||ZD(t,{recursive:!0})}};var{copyFile:rs,stat:us}=Dr,Ce=class e{constructor(t,r=e.IGNORE_FILE){this.ignoreTargetPath=t;this.ignoreFile=r}static IGNORE_FILE=".gitignore.template";getIg(t=this.ignoreTargetPath){let r=Ze(t,this.ignoreFile);if(!es(r))return;let n=ts(r,"utf8").split(`
|
|
11
|
-
`).map(o=>o.trim()).filter(o=>o&&!o.startsWith("#"));return(0,nr.default)().add(n)}async copyFiles(t,r,u,i){let n=await Dr.readdir(t);await Promise.all(n.map(async o=>{let s=Ze(t,o),a=Ze(r,o);if(u&&u.ignores(o))return;if(H.ensureDir(QD(a)),(await us(s)).isDirectory())await this.copyFiles(s,a,u,i);else{if(i&&await i(s,a))return;await rs(s,a)}}))}copyPaths({sourcePath:t,targetPath:r,copyCallback:u}){H.ensureDir(r);let i=this.getIg();return this.copyFiles(t,r,i,u)}};var jn=ue(In(),1);import{readFileSync as $l,writeFileSync as Ul,existsSync as Wl}from"fs";var _e=class{constructor(){}isJSONFilePath(t){return t.endsWith(".json")||t.endsWith(".json.template")}isTemplateFilePath(t){return t.endsWith(".template")}getRealTemplateFilePath(t){return t.replace(".template","")}readFile(t){return $l(t,"utf-8")}readJSONFile(t){return JSON.parse(this.readFile(t))}writeFile(t,r){Ul(this.getRealTemplateFilePath(t),r,{encoding:"utf-8"})}replaceFile(t,r){let u=this.readFile(t);return Object.keys(r).forEach(i=>{let n=r[i];u=u.replace(new RegExp(`\\[TPL:${i}\\]`,"g"),typeof n=="string"?n:JSON.stringify(n))}),u}mergeJSONFile(t,r){let u=this.readJSONFile(t),i=(0,jn.default)(r,u);this.writeFile(t,JSON.stringify(i,null,2))}composeConfigFile(t,r,u){if(this.isTemplateFilePath(r)){let i=this.replaceFile(r,t);if(this.isJSONFilePath(r)&&this.isJSONFilePath(u)){let n=this.getRealTemplateFilePath(u);return Wl(n)?(this.mergeJSONFile(n,JSON.parse(i)),!0):(this.writeFile(n,i),!0)}return this.writeFile(u,i),!0}return!1}};var Gn=["pack-app"],Be=class{ora;context;subPackages;copyer;compose;constructor(t){let r=t.options?.templateRootPath;if(!r)throw new Error("template path not exit");if(!Nn(r))throw new Error("template path not exit");this.ora=Kt,this.context=new Hl("create-app",t),this.subPackages=["node-lib","react-app","next-app"],this.copyer=new Ce(N(this.context.options.configsRootPath,"_common")),this.compose=new _e}get logger(){return this.context.logger}async steps(t){try{return await Yl.prompt(t)}catch(r){throw r.isTtyError,this.logger.error(r),r}}async action({label:t,task:r}){let u=r();u instanceof Promise||(u=Promise.resolve(u));let i=t;return this.ora(u,i),u}isPackageTemplate(t){return Gn.includes(t)}async getGeneratorContext(){let t=mt(this.subPackages,Gn),r=await this.steps(t);if(this.isPackageTemplate(r.template)){let u=_t(this.subPackages),i=await this.steps(u);Object.assign(r,i)}return r.targetPath=N(process.cwd(),r.projectName),r.releasePath=r.releasePath||"src",r}async generate(){let t=await this.getGeneratorContext();if(this.logger.debug("context is:",t,this.context.options.templateRootPath),t.subPackages){await this.action({label:"Generate Directories(subPackages)",task:async()=>{await this.generateTemplateDir(t),await this.generateSubPackages(t),await this.generateConfigs(t,t.targetPath,"_common")}});return}await this.action({label:"Generate Directory",task:async()=>{await this.generateTemplateDir(t),await this.generateConfigs(t,t.targetPath,"_common"),await this.generateConfigs(t,t.targetPath,t.template)}})}async generateConfigs(t,r,u){let i=(a,l)=>(this.logger.debug("copyCallback",a,l),this.compose.composeConfigFile(t,a,l)),{configsRootPath:n,config:o}=this.context.options;if(!o){this.logger.debug("no copy config files");return}let s=N(n,u);if(!Nn(s)){this.logger.debug(`Config path not found: ${s}`);return}await this.copyer.copyPaths({sourcePath:s,targetPath:r,copyCallback:i})}generateTemplateDir(t){return this.copyer.copyPaths({sourcePath:N(this.context.options.templateRootPath,t.template),targetPath:t.targetPath})}async generateSubPackages(t){let{packagesNames:r="packages",subPackages:u=[],targetPath:i=""}=t,{templateRootPath:n}=this.context.options;for(let o of u){let s=N(n,o),a=N(i,r,o);this.logger.debug("copy sub package",s,a),await this.copyer.copyPaths({sourcePath:s,targetPath:a})}}};var Et={name:"@qlover/create-app",version:"0.
|
|
11
|
+
`).map(o=>o.trim()).filter(o=>o&&!o.startsWith("#"));return(0,nr.default)().add(n)}async copyFiles(t,r,u,i){let n=await Dr.readdir(t);await Promise.all(n.map(async o=>{let s=Ze(t,o),a=Ze(r,o);if(u&&u.ignores(o))return;if(H.ensureDir(QD(a)),(await us(s)).isDirectory())await this.copyFiles(s,a,u,i);else{if(i&&await i(s,a))return;await rs(s,a)}}))}copyPaths({sourcePath:t,targetPath:r,copyCallback:u}){H.ensureDir(r);let i=this.getIg();return this.copyFiles(t,r,i,u)}};var jn=ue(In(),1);import{readFileSync as $l,writeFileSync as Ul,existsSync as Wl}from"fs";var _e=class{constructor(){}isJSONFilePath(t){return t.endsWith(".json")||t.endsWith(".json.template")}isTemplateFilePath(t){return t.endsWith(".template")}getRealTemplateFilePath(t){return t.replace(".template","")}readFile(t){return $l(t,"utf-8")}readJSONFile(t){return JSON.parse(this.readFile(t))}writeFile(t,r){Ul(this.getRealTemplateFilePath(t),r,{encoding:"utf-8"})}replaceFile(t,r){let u=this.readFile(t);return Object.keys(r).forEach(i=>{let n=r[i];u=u.replace(new RegExp(`\\[TPL:${i}\\]`,"g"),typeof n=="string"?n:JSON.stringify(n))}),u}mergeJSONFile(t,r){let u=this.readJSONFile(t),i=(0,jn.default)(r,u);this.writeFile(t,JSON.stringify(i,null,2))}composeConfigFile(t,r,u){if(this.isTemplateFilePath(r)){let i=this.replaceFile(r,t);if(this.isJSONFilePath(r)&&this.isJSONFilePath(u)){let n=this.getRealTemplateFilePath(u);return Wl(n)?(this.mergeJSONFile(n,JSON.parse(i)),!0):(this.writeFile(n,i),!0)}return this.writeFile(u,i),!0}return!1}};var Gn=["pack-app"],Be=class{ora;context;subPackages;copyer;compose;constructor(t){let r=t.options?.templateRootPath;if(!r)throw new Error("template path not exit");if(!Nn(r))throw new Error("template path not exit");this.ora=Kt,this.context=new Hl("create-app",t),this.subPackages=["node-lib","react-app","next-app"],this.copyer=new Ce(N(this.context.options.configsRootPath,"_common")),this.compose=new _e}get logger(){return this.context.logger}async steps(t){try{return await Yl.prompt(t)}catch(r){throw r.isTtyError,this.logger.error(r),r}}async action({label:t,task:r}){let u=r();u instanceof Promise||(u=Promise.resolve(u));let i=t;return this.ora(u,i),u}isPackageTemplate(t){return Gn.includes(t)}async getGeneratorContext(){let t=mt(this.subPackages,Gn),r=await this.steps(t);if(this.isPackageTemplate(r.template)){let u=_t(this.subPackages),i=await this.steps(u);Object.assign(r,i)}return r.targetPath=N(process.cwd(),r.projectName),r.releasePath=r.releasePath||"src",r}async generate(){let t=await this.getGeneratorContext();if(this.logger.debug("context is:",t,this.context.options.templateRootPath),t.subPackages){await this.action({label:"Generate Directories(subPackages)",task:async()=>{await this.generateTemplateDir(t),await this.generateSubPackages(t),await this.generateConfigs(t,t.targetPath,"_common")}});return}await this.action({label:"Generate Directory",task:async()=>{await this.generateTemplateDir(t),await this.generateConfigs(t,t.targetPath,"_common"),await this.generateConfigs(t,t.targetPath,t.template)}})}async generateConfigs(t,r,u){let i=(a,l)=>(this.logger.debug("copyCallback",a,l),this.compose.composeConfigFile(t,a,l)),{configsRootPath:n,config:o}=this.context.options;if(!o){this.logger.debug("no copy config files");return}let s=N(n,u);if(!Nn(s)){this.logger.debug(`Config path not found: ${s}`);return}await this.copyer.copyPaths({sourcePath:s,targetPath:r,copyCallback:i})}generateTemplateDir(t){return this.copyer.copyPaths({sourcePath:N(this.context.options.templateRootPath,t.template),targetPath:t.targetPath})}async generateSubPackages(t){let{packagesNames:r="packages",subPackages:u=[],targetPath:i=""}=t,{templateRootPath:n}=this.context.options;for(let o of u){let s=N(n,o),a=N(i,r,o);this.logger.debug("copy sub package",s,a),await this.copyer.copyPaths({sourcePath:s,targetPath:a})}}};var Et={name:"@qlover/create-app",version:"0.8.0",description:"Create a new app with a single command",private:!1,type:"module",files:["dist","package.json","README.md","CHANGELOG.md"],bin:{"create-app":"dist/index.js"},scripts:{lint:"eslint src --fix",build:"tsup","create:app":"node ./dist/index.js"},repository:{type:"git",url:"git+https://github.com/qlover/fe-base.git",directory:"packages/create-app"},homepage:"https://github.com/qlover/fe-base#readme",keywords:["create-app","fe-scripts","scripts"],author:"qlover",license:"ISC",publishConfig:{access:"public"},devDependencies:{"@qlover/logger":"workspace:*",ignore:"^7.0.3",lodash:"^4.17.21",ora:"^8.1.1"},dependencies:{"@qlover/scripts-context":"workspace:*",commander:"^13.1.0",inquirer:"^12.3.2"}};function Kl(){let e=new zl;return e.version(Et.version,"-v, --version","Show version").description(Et.description).option("-d, --dry-run","Do not touch or write anything, but show the commands").option("-V, --verbose","Show more information").option("--config","Copy config files (default: true)",!0).option("--no-config","Do not copy config files"),e.parse(),e.opts()}async function kn(e=process.cwd()){let{dryRun:t,verbose:r,...u}=Kl(),i=Mn(e,"./templates"),n=Mn(e,"./configs");Ln(i)||(console.error("Template is empty!"),process.exit(1)),Ln(n)||(console.error("Configs is empty!"),process.exit(1)),await new Be({dryRun:t,verbose:r,options:{...u,templateRootPath:i,configsRootPath:n}}).generate()}import{fileURLToPath as Xl}from"url";import{dirname as Jl}from"path";var Zl=Xl(import.meta.url),Ql=Jl(Zl);kn(Ql).catch(e=>{console.error(e),process.exit(1)});
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Next.js Full-Stack Application Template
|
|
2
|
+
|
|
3
|
+
A full-stack application template based on Next.js, implementing a clear front-end and back-end layered architecture using an interface-driven design pattern.
|
|
4
|
+
|
|
5
|
+
[中文](./README.md)
|
|
6
|
+
|
|
7
|
+
## 🌟 Key Features
|
|
8
|
+
|
|
9
|
+
- 🏗️ Full-stack application architecture based on Next.js
|
|
10
|
+
- 🔌 Interface-Driven Development pattern
|
|
11
|
+
- 🎨 Theme system integrated with Tailwind CSS
|
|
12
|
+
- 🌍 Comprehensive internationalization support (English & Chinese)
|
|
13
|
+
- 🔄 TypeScript-based IOC container
|
|
14
|
+
- 🛡️ Complete authentication and authorization system
|
|
15
|
+
- 📡 Layered API architecture (Controllers, Services, Repositories)
|
|
16
|
+
- 🎮 State management and page controller pattern
|
|
17
|
+
- 🔗 SQL database bridging layer
|
|
18
|
+
- 📦 Package management with pnpm
|
|
19
|
+
|
|
20
|
+
## 🔧 Requirements
|
|
21
|
+
|
|
22
|
+
- Node.js >= 16
|
|
23
|
+
- pnpm >= 8.0
|
|
24
|
+
|
|
25
|
+
## 📁 Project Structure
|
|
26
|
+
|
|
27
|
+
```tree
|
|
28
|
+
├── config/ # Configuration directory
|
|
29
|
+
│ ├── i18n/ # Internationalization config
|
|
30
|
+
│ ├── Identifier/ # Dependency injection identifiers
|
|
31
|
+
│ ├── common.ts # Common app configuration
|
|
32
|
+
│ ├── IOCIdentifier.ts # IOC container configuration
|
|
33
|
+
│ └── theme.ts # Theme configuration
|
|
34
|
+
├── public/ # Static assets directory
|
|
35
|
+
├── src/
|
|
36
|
+
│ ├── app/ # Next.js app directory
|
|
37
|
+
│ │ ├── [locale]/ # Internationalized routes
|
|
38
|
+
│ │ ├── api/ # API route handlers
|
|
39
|
+
│ │ └── layout.tsx # Application layout
|
|
40
|
+
│ ├── base/ # Client-side base code
|
|
41
|
+
│ │ ├── port/ # Client interface definitions
|
|
42
|
+
│ │ ├── cases/ # Business case implementations
|
|
43
|
+
│ │ ├── services/ # Client service implementations
|
|
44
|
+
│ │ └── types/ # Type definitions
|
|
45
|
+
│ ├── server/ # Server-side code
|
|
46
|
+
│ │ ├── port/ # Server interface definitions
|
|
47
|
+
│ │ ├── services/ # Service implementations
|
|
48
|
+
│ │ ├── repositorys/ # Data repositories
|
|
49
|
+
│ │ ├── validators/ # Request validators
|
|
50
|
+
│ │ └── sqlBridges/ # Database bridging layer
|
|
51
|
+
│ ├── uikit/ # UI component library
|
|
52
|
+
│ │ ├── components/ # Reusable components
|
|
53
|
+
│ │ ├── context/ # React Context
|
|
54
|
+
│ │ └── hook/ # React Hooks
|
|
55
|
+
│ └── styles/ # Style files
|
|
56
|
+
└── next.config.ts # Next.js configuration file
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 🚀 Quick Start
|
|
60
|
+
|
|
61
|
+
### Install Dependencies
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pnpm install
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Development Mode
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pnpm dev
|
|
71
|
+
# cross-env APP_ENV=localhost next dev --turbopack --port 3100
|
|
72
|
+
# Automatically loads .env.localhost -> .env
|
|
73
|
+
|
|
74
|
+
pnpm dev:staging
|
|
75
|
+
# cross-env APP_ENV=staging next dev --turbopack --port 3100
|
|
76
|
+
# Automatically loads .env.staging -> .env
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Build Project
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pnpm build
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## 📚 Documentation Guide
|
|
86
|
+
|
|
87
|
+
The project provides detailed development documentation covering all major features and best practices:
|
|
88
|
+
|
|
89
|
+
### Basic Documentation
|
|
90
|
+
|
|
91
|
+
- [Project Overview](./docs/en/index.md) - Project introduction and quick start guide
|
|
92
|
+
- [Project Structure](./docs/en/project-structure.md) - Detailed project directory structure explanation
|
|
93
|
+
- [Development Guide](./docs/en/development-guide.md) - Project development standards and best practices
|
|
94
|
+
- [Environment Configuration](./docs/en/env.md) - Environment variables and configuration management
|
|
95
|
+
- [Global Configuration](./docs/en/global.md) - Application global configuration and settings
|
|
96
|
+
|
|
97
|
+
### Core Features
|
|
98
|
+
|
|
99
|
+
- [Bootstrap Process](./docs/en/bootstrap.md) - Application startup process and lifecycle management
|
|
100
|
+
- [IOC Container](./docs/en/ioc.md) - Dependency injection system usage guide
|
|
101
|
+
- [Router Management](./docs/en/router.md) - Route configuration and page navigation
|
|
102
|
+
- [State Management](./docs/en/store.md) - Application state management solution
|
|
103
|
+
- [Request Handling](./docs/en/request.md) - API request handling mechanism
|
|
104
|
+
|
|
105
|
+
### Feature Extensions
|
|
106
|
+
|
|
107
|
+
- [Internationalization](./docs/en/i18n.md) - Multi-language support and translation management
|
|
108
|
+
- [Theme System](./docs/en/theme.md) - Theme configuration and dark mode support
|
|
109
|
+
- [TypeScript Guide](./docs/en/typescript-guide.md) - TypeScript usage standards and best practices
|
|
110
|
+
|
|
111
|
+
## 🔨 Architecture Design
|
|
112
|
+
|
|
113
|
+
### Interface-Driven Design Pattern
|
|
114
|
+
|
|
115
|
+
The project adopts an interface-driven design pattern, achieving decoupling and testability through interface definitions:
|
|
116
|
+
|
|
117
|
+
#### Client Interfaces (src/base/port)
|
|
118
|
+
|
|
119
|
+
- **AppUserApiInterface**: User authentication related API interface
|
|
120
|
+
- **AsyncStateInterface**: Asynchronous state management interface
|
|
121
|
+
- **RouterInterface**: Router management interface
|
|
122
|
+
- **I18nServiceInterface**: Internationalization service interface
|
|
123
|
+
|
|
124
|
+
#### Server Interfaces (src/server/port)
|
|
125
|
+
|
|
126
|
+
- **ServerAuthInterface**: Server authentication interface
|
|
127
|
+
- **DBBridgeInterface**: Database operation bridging interface
|
|
128
|
+
- **UserRepositoryInterface**: User data repository interface
|
|
129
|
+
- **ValidatorInterface**: Data validation interface
|
|
130
|
+
- **ParamsHandlerInterface**: Parameter handling interface
|
|
@@ -1,36 +1,130 @@
|
|
|
1
|
-
|
|
1
|
+
# Next.js Full-Stack Application Template
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
一个基于 Next.js 的全栈应用模板,采用面向接口的设计模式,实现了清晰的前后端分层架构。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[English](./README.en.md)
|
|
6
|
+
|
|
7
|
+
## 🌟 特性亮点
|
|
8
|
+
|
|
9
|
+
- 🏗️ 基于 Next.js 的全栈应用架构
|
|
10
|
+
- 🔌 面向接口的设计模式(Interface-Driven Development)
|
|
11
|
+
- 🎨 集成 Tailwind CSS 的主题系统
|
|
12
|
+
- 🌍 完善的国际化支持(中英文)
|
|
13
|
+
- 🔄 基于 TypeScript 的 IOC 容器
|
|
14
|
+
- 🛡️ 完整的身份验证和授权系统
|
|
15
|
+
- 📡 分层的 API 架构(控制器、服务、仓库)
|
|
16
|
+
- 🎮 状态管理与页面控制器模式
|
|
17
|
+
- 🔗 SQL 数据库桥接层
|
|
18
|
+
- 📦 使用 pnpm 进行包管理
|
|
19
|
+
|
|
20
|
+
## 🔧 环境要求
|
|
21
|
+
|
|
22
|
+
- Node.js >= 16
|
|
23
|
+
- pnpm >= 8.0
|
|
24
|
+
|
|
25
|
+
## 📁 项目结构
|
|
26
|
+
|
|
27
|
+
```tree
|
|
28
|
+
├── config/ # 配置文件目录
|
|
29
|
+
│ ├── i18n/ # 国际化配置
|
|
30
|
+
│ ├── Identifier/ # 依赖注入标识符
|
|
31
|
+
│ ├── common.ts # 应用通用配置
|
|
32
|
+
│ ├── IOCIdentifier.ts # IOC容器配置
|
|
33
|
+
│ └── theme.ts # 主题配置
|
|
34
|
+
├── public/ # 静态资源目录
|
|
35
|
+
├── src/
|
|
36
|
+
│ ├── app/ # Next.js 应用目录
|
|
37
|
+
│ │ ├── [locale]/ # 国际化路由
|
|
38
|
+
│ │ ├── api/ # API 路由处理器
|
|
39
|
+
│ │ └── layout.tsx # 应用布局
|
|
40
|
+
│ ├── base/ # 客户端基础代码
|
|
41
|
+
│ │ ├── port/ # 客户端接口定义
|
|
42
|
+
│ │ ├── cases/ # 业务用例实现
|
|
43
|
+
│ │ ├── services/ # 客户端服务实现
|
|
44
|
+
│ │ └── types/ # 类型定义
|
|
45
|
+
│ ├── server/ # 服务端代码
|
|
46
|
+
│ │ ├── port/ # 服务端接口定义
|
|
47
|
+
│ │ ├── services/ # 服务实现
|
|
48
|
+
│ │ ├── repositorys/ # 数据仓库
|
|
49
|
+
│ │ ├── validators/ # 请求验证器
|
|
50
|
+
│ │ └── sqlBridges/ # 数据库桥接层
|
|
51
|
+
│ ├── uikit/ # UI 组件库
|
|
52
|
+
│ │ ├── components/ # 可复用组件
|
|
53
|
+
│ │ ├── context/ # React Context
|
|
54
|
+
│ │ └── hook/ # React Hooks
|
|
55
|
+
│ └── styles/ # 样式文件
|
|
56
|
+
└── next.config.ts # Next.js 配置文件
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 🚀 快速开始
|
|
60
|
+
|
|
61
|
+
### 安装依赖
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pnpm install
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 开发模式
|
|
6
68
|
|
|
7
69
|
```bash
|
|
8
|
-
npm run dev
|
|
9
|
-
# or
|
|
10
|
-
yarn dev
|
|
11
|
-
# or
|
|
12
70
|
pnpm dev
|
|
13
|
-
#
|
|
14
|
-
|
|
71
|
+
# cross-env APP_ENV=localhost next dev --turbopack --port 3100
|
|
72
|
+
# 自动加载 .env.localhost -> .env
|
|
73
|
+
|
|
74
|
+
pnpm dev:staging
|
|
75
|
+
# cross-env APP_ENV=staging next dev --turbopack --port 3100
|
|
76
|
+
# 自动加载 .env.staging -> .env
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 构建项目
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pnpm build
|
|
15
83
|
```
|
|
16
84
|
|
|
17
|
-
|
|
85
|
+
## 📚 文档指南
|
|
86
|
+
|
|
87
|
+
项目提供了详细的开发文档,涵盖了所有主要功能和最佳实践:
|
|
88
|
+
|
|
89
|
+
### 基础文档
|
|
90
|
+
|
|
91
|
+
- [项目概述](./docs/zh/index.md) - 项目整体介绍和快速开始指南
|
|
92
|
+
- [项目结构](./docs/zh/project-structure.md) - 详细的项目目录结构说明
|
|
93
|
+
- [开发指南](./docs/zh/development-guide.md) - 项目开发规范和最佳实践
|
|
94
|
+
- [环境配置](./docs/zh/env.md) - 环境变量和配置管理说明
|
|
95
|
+
- [全局配置](./docs/zh/global.md) - 应用全局配置和设置说明
|
|
96
|
+
|
|
97
|
+
### 核心功能
|
|
98
|
+
|
|
99
|
+
- [启动流程](./docs/zh/bootstrap.md) - 应用启动流程和生命周期管理
|
|
100
|
+
- [IOC容器](./docs/zh/ioc.md) - 依赖注入系统的使用说明
|
|
101
|
+
- [路由管理](./docs/zh/router.md) - 路由配置和页面导航说明
|
|
102
|
+
- [状态管理](./docs/zh/store.md) - 应用状态管理方案说明
|
|
103
|
+
- [请求处理](./docs/zh/request.md) - API 请求处理机制说明
|
|
18
104
|
|
|
19
|
-
|
|
105
|
+
### 功能扩展
|
|
20
106
|
|
|
21
|
-
|
|
107
|
+
- [国际化](./docs/zh/i18n.md) - 多语言支持和翻译管理
|
|
108
|
+
- [主题系统](./docs/zh/theme.md) - 主题配置和暗色模式支持
|
|
109
|
+
- [TypeScript指南](./docs/zh/typescript-guide.md) - TypeScript 使用规范和最佳实践
|
|
22
110
|
|
|
23
|
-
##
|
|
111
|
+
## 🔨 架构设计
|
|
24
112
|
|
|
25
|
-
|
|
113
|
+
### 面向接口的设计模式
|
|
26
114
|
|
|
27
|
-
|
|
28
|
-
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
|
115
|
+
项目采用面向接口的设计模式,通过接口定义实现解耦和可测试性:
|
|
29
116
|
|
|
30
|
-
|
|
117
|
+
#### 客户端接口 (src/base/port)
|
|
31
118
|
|
|
32
|
-
|
|
119
|
+
- **AppUserApiInterface**: 用户认证相关API接口
|
|
120
|
+
- **AsyncStateInterface**: 异步状态管理接口
|
|
121
|
+
- **RouterInterface**: 路由管理接口
|
|
122
|
+
- **I18nServiceInterface**: 国际化服务接口
|
|
33
123
|
|
|
34
|
-
|
|
124
|
+
#### 服务端接口 (src/server/port)
|
|
35
125
|
|
|
36
|
-
|
|
126
|
+
- **ServerAuthInterface**: 服务端认证接口
|
|
127
|
+
- **DBBridgeInterface**: 数据库操作桥接接口
|
|
128
|
+
- **UserRepositoryInterface**: 用户数据仓库接口
|
|
129
|
+
- **ValidatorInterface**: 数据验证接口
|
|
130
|
+
- **ParamsHandlerInterface**: 参数处理接口
|
|
@@ -3,32 +3,32 @@
|
|
|
3
3
|
* @localZh 用户未找到
|
|
4
4
|
* @localEn User not found
|
|
5
5
|
*/
|
|
6
|
-
export const API_USER_NOT_FOUND = '
|
|
6
|
+
export const API_USER_NOT_FOUND = 'api:user__not_found';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @description 用户已存在
|
|
10
10
|
* @localZh 用户已存在
|
|
11
11
|
* @localEn User already exists
|
|
12
12
|
*/
|
|
13
|
-
export const API_USER_ALREADY_EXISTS = '
|
|
13
|
+
export const API_USER_ALREADY_EXISTS = 'api:user__already_exists';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* @description 响应不正确
|
|
17
17
|
* @localZh 响应不正确
|
|
18
18
|
* @localEn Response not correct
|
|
19
19
|
*/
|
|
20
|
-
export const API_RESPONSE_NOT_OK = 'RESPONSE_NOT_OK';
|
|
20
|
+
export const API_RESPONSE_NOT_OK = 'api:RESPONSE_NOT_OK';
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* @description 未授权
|
|
24
24
|
* @localZh 未授权
|
|
25
25
|
* @localEn Not authorized
|
|
26
26
|
*/
|
|
27
|
-
export const API_NOT_AUTHORIZED = '
|
|
27
|
+
export const API_NOT_AUTHORIZED = 'api:not_authorized';
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* @description 页码不正确
|
|
31
31
|
* @localZh 页码不正确
|
|
32
32
|
* @localEn Page number is incorrect
|
|
33
33
|
*/
|
|
34
|
-
export const API_PAGE_INVALID = '
|
|
34
|
+
export const API_PAGE_INVALID = 'api:page__invalid';
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description 表格创建文字
|
|
3
|
+
* @localZh 新建
|
|
4
|
+
* @localEn New
|
|
5
|
+
*/
|
|
6
|
+
export const COMMON_ADMIN_TABLE_CREATE = 'common:admin_table__create';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @description 表格刷新文字
|
|
10
|
+
* @localZh 刷新
|
|
11
|
+
* @localEn Refresh
|
|
12
|
+
*/
|
|
13
|
+
export const COMMON_ADMIN_TABLE_REFRESH = 'common:admin_table__refresh';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @description 表格搜索文字
|
|
17
|
+
* @localZh 搜索
|
|
18
|
+
* @localEn Search
|
|
19
|
+
*/
|
|
20
|
+
export const COMMON_ADMIN_TABLE_SEARCH = 'common:admin_table__search';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @description 表格重置文字
|
|
24
|
+
* @localZh 重置
|
|
25
|
+
* @localEn Reset
|
|
26
|
+
*/
|
|
27
|
+
export const COMMON_ADMIN_TABLE_RESET = 'common:admin_table__reset';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @description 表格导出文字
|
|
31
|
+
* @localZh 导出
|
|
32
|
+
* @localEn Export
|
|
33
|
+
*/
|
|
34
|
+
export const COMMON_ADMIN_TABLE_EXPORT = 'common:admin_table__export';
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @description 表格设置
|
|
38
|
+
* @localZh 设置
|
|
39
|
+
* @localEn Settings
|
|
40
|
+
*/
|
|
41
|
+
export const COMMON_ADMIN_TABLE_SETTINGS = 'common:admin_table__settings';
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @description 表格操作文字
|
|
45
|
+
* @localZh 操作
|
|
46
|
+
* @localEn Action
|
|
47
|
+
*/
|
|
48
|
+
export const COMMON_ADMIN_TABLE_ACTION = 'common:admin_table__action';
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @description 表格编辑文字
|
|
52
|
+
* @localZh 编辑
|
|
53
|
+
* @localEn Edit
|
|
54
|
+
*/
|
|
55
|
+
export const COMMON_ADMIN_TABLE_EDIT = 'common:admin_table__edit';
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @description 表格删除文字
|
|
59
|
+
* @localZh 删除
|
|
60
|
+
* @localEn Delete
|
|
61
|
+
*/
|
|
62
|
+
export const COMMON_ADMIN_TABLE_DELETE = 'common:admin_table__delete';
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @description 表格详情文字
|
|
66
|
+
* @localZh 详情
|
|
67
|
+
* @localEn Detail
|
|
68
|
+
*/
|
|
69
|
+
export const COMMON_ADMIN_TABLE_DETAIL = 'common:admin_table__detail';
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description Save
|
|
3
|
+
* @localZh 保存
|
|
4
|
+
* @localEn Save
|
|
5
|
+
*/
|
|
6
|
+
export const COMMON_SAVE = 'common:save';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @description Cancel
|
|
10
|
+
* @localZh 取消
|
|
11
|
+
* @localEn Cancel
|
|
12
|
+
*/
|
|
13
|
+
export const COMMON_CANCEL = 'common:cancel';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @description Create
|
|
17
|
+
* @localZh 创建
|
|
18
|
+
* @localEn Create
|
|
19
|
+
*/
|
|
20
|
+
export const COMMON_CREATE = 'common:create';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @description Detail
|
|
24
|
+
* @localZh 详情
|
|
25
|
+
* @localEn Detail
|
|
26
|
+
*/
|
|
27
|
+
export const COMMON_DETAIL = 'common:detail';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @description Theme switcher default theme label
|
|
31
|
+
* @localZh 默认主题
|
|
32
|
+
* @localEn Default Theme
|
|
33
|
+
*/
|
|
34
|
+
export const COMMON_THEME_DEFAULT = 'common:theme__default';
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @description Theme switcher dark theme label
|
|
38
|
+
* @localZh 暗色主题
|
|
39
|
+
* @localEn Dark Theme
|
|
40
|
+
*/
|
|
41
|
+
export const COMMON_THEME_DARK = 'common:theme__dark';
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @description Theme switcher pink theme label
|
|
45
|
+
* @localZh 粉色主题
|
|
46
|
+
* @localEn Pink Theme
|
|
47
|
+
*/
|
|
48
|
+
export const COMMON_THEME_PINK = 'common:theme__pink';
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @description Admin page title
|
|
52
|
+
* @localZh 管理后台
|
|
53
|
+
* @localEn Admin Backend
|
|
54
|
+
*/
|
|
55
|
+
export const COMMON_ADMIN_TITLE = 'common:admin__title';
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @description logout dialog title
|
|
59
|
+
* @localZh 登出
|
|
60
|
+
* @localEn Logout
|
|
61
|
+
*/
|
|
62
|
+
export const COMMON_LOGOUT_DIALOG_TITLE = 'common:logout__dialog__title';
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @description logout dialog content
|
|
66
|
+
* @localZh 确定要登出吗?
|
|
67
|
+
* @localEn Are you sure you want to logout?
|
|
68
|
+
*/
|
|
69
|
+
export const COMMON_LOGOUT_DIALOG_CONTENT = 'common:logout__dialog__content';
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @description i18n key invalid
|
|
73
|
+
* @localZh i18n 键格式不正确
|
|
74
|
+
* @localEn I18n key format is incorrect
|
|
75
|
+
*/
|
|
76
|
+
export const COMMON_I18N_KEY_INVALID = 'common:i18n_key_invalid';
|