├── .browserslistrc ├── .editorconfig ├── .gitattributes ├── .gitconfig ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.yml │ ├── docs.yml │ └── feature-request.yml ├── actions │ └── setup-node │ │ └── action.yml ├── commit-convention.md ├── contributing.md ├── pull_request_template.md ├── release-drafter.yml ├── semantic.yml └── workflows │ ├── build.yml │ ├── changeset-version.yml │ ├── ci.yml │ ├── codeql.yml │ ├── deploy.yml │ ├── draft.yml │ ├── issue-close-require.yml │ ├── issue-labeled.yml │ ├── lock.yml │ ├── release-tag.yml │ ├── rerun.yml │ ├── semantic-pull-request.yml │ └── stale.yml ├── .gitignore ├── .gitpod.yml ├── .husky ├── commit-msg ├── post-merge └── pre-commit ├── .lintstagedrc.mjs ├── .node-version ├── .npmrc ├── .prettierignore ├── .prettierrc.mjs ├── .stylelintignore ├── .vercel ├── README.txt └── project.json ├── .vscode └── settings.json ├── apps ├── backend-mock │ ├── .env │ ├── .vercel │ │ ├── README.txt │ │ └── project.json │ ├── README.md │ ├── api │ │ ├── auth │ │ │ ├── codes.ts │ │ │ ├── login.post.ts │ │ │ ├── logout.post.ts │ │ │ └── refresh.post.ts │ │ ├── menu │ │ │ └── all.ts │ │ ├── status.ts │ │ ├── table │ │ │ └── list.ts │ │ ├── test.get.ts │ │ ├── test.post.ts │ │ └── user │ │ │ └── info.ts │ ├── error.ts │ ├── middleware │ │ └── 1.api.ts │ ├── nitro.config.ts │ ├── package.json │ ├── routes │ │ └── [...].ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── utils │ │ ├── cookie-utils.ts │ │ ├── jwt-utils.ts │ │ ├── mock-data.ts │ │ └── response.ts └── web-antd │ ├── .env │ ├── .env.analyze │ ├── .env.development │ ├── .env.production │ ├── index.html │ ├── package.json │ ├── postcss.config.mjs │ ├── public │ └── images │ │ ├── avatar.png │ │ └── logo.svg │ ├── src │ ├── App.tsx │ ├── api │ │ ├── core │ │ │ ├── auth.ts │ │ │ └── index.ts │ │ ├── index.ts │ │ └── request.ts │ ├── bootstrap.tsx │ ├── components │ │ └── MForm │ │ │ └── src │ │ │ ├── AddButton │ │ │ ├── AddButton.tsx │ │ │ └── index.ts │ │ │ ├── ArrayFieldItemTemplate │ │ │ ├── ArrayFieldItemTemplate.tsx │ │ │ └── index.ts │ │ │ ├── ArrayFieldTemplate │ │ │ ├── ArrayFieldTemplate.tsx │ │ │ └── index.ts │ │ │ ├── BaseInputTemplate │ │ │ ├── BaseInputTemplate.tsx │ │ │ └── index.ts │ │ │ ├── CheckboxWidget │ │ │ ├── CheckboxWidget.tsx │ │ │ └── index.ts │ │ │ ├── CheckboxesWidget │ │ │ ├── CheckboxesWidget.tsx │ │ │ └── index.ts │ │ │ ├── DescriptionField │ │ │ ├── DescriptionField.tsx │ │ │ └── index.ts │ │ │ ├── ErrorList │ │ │ ├── ErrorList.tsx │ │ │ └── index.ts │ │ │ ├── FieldErrorTemplate │ │ │ ├── FieldErrorTemplate.tsx │ │ │ └── index.ts │ │ │ ├── FieldHelpTemplate │ │ │ ├── FieldHelpTemplate.tsx │ │ │ └── index.ts │ │ │ ├── FieldTemplate │ │ │ ├── FieldTemplate.tsx │ │ │ └── index.ts │ │ │ ├── IconButton │ │ │ ├── IconButton.tsx │ │ │ └── index.ts │ │ │ ├── MuiForm │ │ │ ├── MuiForm.tsx │ │ │ └── index.ts │ │ │ ├── ObjectFieldTemplate │ │ │ ├── ObjectFieldTemplate.tsx │ │ │ └── index.ts │ │ │ ├── RadioWidget │ │ │ ├── RadioWidget.tsx │ │ │ └── index.ts │ │ │ ├── RangeWidget │ │ │ ├── RangeWidget.tsx │ │ │ └── index.ts │ │ │ ├── SelectWidget │ │ │ ├── SelectWidget.tsx │ │ │ └── index.ts │ │ │ ├── SubmitButton │ │ │ ├── SubmitButton.tsx │ │ │ └── index.ts │ │ │ ├── Templates │ │ │ ├── Templates.ts │ │ │ └── index.ts │ │ │ ├── TextareaWidget │ │ │ ├── TextareaWidget.tsx │ │ │ └── index.ts │ │ │ ├── Theme │ │ │ ├── Theme.tsx │ │ │ └── index.ts │ │ │ ├── TitleField │ │ │ ├── TitleField.tsx │ │ │ └── index.ts │ │ │ ├── Widgets │ │ │ ├── Widgets.ts │ │ │ └── index.ts │ │ │ ├── WrapIfAdditionalTemplate │ │ │ ├── WrapIfAdditionalTemplate.tsx │ │ │ └── index.ts │ │ │ └── index.ts │ ├── constants │ │ ├── adapter.ts │ │ └── baseurl.ts │ ├── layout │ │ └── index.tsx │ ├── main.tsx │ ├── pages │ │ ├── dashboard │ │ │ ├── analysis │ │ │ │ ├── components │ │ │ │ │ ├── StatCard.tsx │ │ │ │ │ ├── SubscriptionProgress.tsx │ │ │ │ │ └── charts │ │ │ │ │ │ ├── GrowthAreaChart.tsx │ │ │ │ │ │ ├── RevenueChart.tsx │ │ │ │ │ │ └── SubscribersChart.tsx │ │ │ │ └── index.tsx │ │ │ └── workbench │ │ │ │ ├── components │ │ │ │ ├── BoardColumn.tsx │ │ │ │ ├── KanbanBoard.tsx │ │ │ │ ├── TaskCard.tsx │ │ │ │ ├── multipleContainersKeyboardPreset.ts │ │ │ │ └── utils.ts │ │ │ │ └── index.tsx │ │ ├── login │ │ │ └── index.tsx │ │ ├── nest │ │ │ ├── nest1 │ │ │ │ └── index.tsx │ │ │ └── nest2 │ │ │ │ ├── nest2-1 │ │ │ │ ├── index.tsx │ │ │ │ └── nest2-2-1 │ │ │ │ │ └── index.tsx │ │ │ │ └── nest2-2 │ │ │ │ └── nest2-2-2 │ │ │ │ └── index.tsx │ │ ├── not-access │ │ │ └── index.tsx │ │ ├── not-found │ │ │ └── index.tsx │ │ ├── offline │ │ │ └── index.tsx │ │ ├── server-error │ │ │ └── index.tsx │ │ ├── settings │ │ │ └── index.tsx │ │ └── system │ │ │ ├── menu │ │ │ └── index.tsx │ │ │ ├── role │ │ │ └── index.tsx │ │ │ └── user │ │ │ └── index.tsx │ ├── preferences.ts │ └── router │ │ ├── access.ts │ │ ├── index.ts │ │ └── routes │ │ ├── core │ │ └── index.tsx │ │ ├── index.ts │ │ └── modules │ │ ├── error-page.tsx │ │ ├── home.tsx │ │ ├── nest.tsx │ │ ├── settings.tsx │ │ └── system.tsx │ ├── tailwind.config.mjs │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.mts ├── eslint.config.mjs ├── internal ├── lint-configs │ ├── eslint-config │ │ ├── README.md │ │ ├── build.config.ts │ │ ├── package.json │ │ ├── src │ │ │ ├── configs │ │ │ │ ├── command.ts │ │ │ │ ├── comments.ts │ │ │ │ ├── disableds.ts │ │ │ │ ├── ignores.ts │ │ │ │ ├── import.ts │ │ │ │ ├── index.ts │ │ │ │ ├── javascript.ts │ │ │ │ ├── jsdoc.ts │ │ │ │ ├── jsonc │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── sortPackageJson.ts │ │ │ │ │ └── sortTsconfig.ts │ │ │ │ ├── node.ts │ │ │ │ ├── perfectionist.ts │ │ │ │ ├── prettier.ts │ │ │ │ ├── react.ts │ │ │ │ ├── regexp.ts │ │ │ │ ├── test.ts │ │ │ │ ├── turbo.ts │ │ │ │ ├── typescript.ts │ │ │ │ └── unicorn.ts │ │ │ ├── custom-config.ts │ │ │ ├── index.ts │ │ │ ├── typings │ │ │ │ └── pkg.d.ts │ │ │ └── util.ts │ │ └── tsconfig.json │ ├── prettier-config │ │ ├── index.mjs │ │ └── package.json │ └── stylelint-config │ │ ├── index.mjs │ │ └── package.json ├── node-utils │ ├── build.config.ts │ ├── package.json │ ├── src │ │ ├── __tests__ │ │ │ ├── hash.test.ts │ │ │ └── path.test.ts │ │ ├── constants.ts │ │ ├── date.ts │ │ ├── fs.ts │ │ ├── git.ts │ │ ├── hash.ts │ │ ├── index.ts │ │ ├── monorepo.ts │ │ ├── path.ts │ │ ├── prettier.ts │ │ └── spinner.ts │ └── tsconfig.json ├── tailwind-config │ ├── build.config.ts │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── module.d.ts │ │ ├── plugins │ │ │ └── entry.ts │ │ └── postcss.config.ts │ └── tsconfig.json ├── tsconfig │ ├── base.json │ ├── library.json │ ├── node.json │ ├── package.json │ ├── web-app.json │ └── web.json └── vite-config │ ├── build.config.ts │ ├── package.json │ ├── src │ ├── config │ │ ├── application.ts │ │ ├── common.ts │ │ ├── index.ts │ │ └── library.ts │ ├── index.ts │ ├── options.ts │ ├── plugins │ │ ├── archiver.ts │ │ ├── extra-app-config.ts │ │ ├── importmap.ts │ │ ├── index.ts │ │ ├── inject-app-loading │ │ │ ├── README.md │ │ │ ├── default-loading-antd.html │ │ │ ├── default-loading.html │ │ │ └── index.ts │ │ ├── inject-metadata.ts │ │ ├── nitro-mock.ts │ │ └── print.ts │ ├── typing.ts │ └── utils │ │ └── env.ts │ └── tsconfig.json ├── package.json ├── packages ├── @core │ ├── base │ │ ├── README.md │ │ ├── design │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ ├── css │ │ │ │ │ ├── global.css │ │ │ │ │ ├── transition.css │ │ │ │ │ └── ui.css │ │ │ │ ├── design-tokens │ │ │ │ │ ├── dark.css │ │ │ │ │ ├── default.css │ │ │ │ │ ├── index.ts │ │ │ │ │ └── toast.css │ │ │ │ ├── index.ts │ │ │ │ ├── scss-bem │ │ │ │ │ ├── bem.scss │ │ │ │ │ └── constants.scss │ │ │ │ └── scss │ │ │ │ │ ├── bell.scss │ │ │ │ │ ├── menu.scss │ │ │ │ │ └── normal-menu.scss │ │ │ ├── tsconfig.json │ │ │ └── vite.config.mts │ │ ├── icons │ │ │ ├── build.config.ts │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ ├── create-icon.tsx │ │ │ │ ├── index.ts │ │ │ │ └── lucide.ts │ │ │ └── tsconfig.json │ │ ├── shared │ │ │ ├── build.config.ts │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ ├── cache │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── storage-manager.test.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── storage-manager.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── color │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── convert.test.ts │ │ │ │ │ ├── color.ts │ │ │ │ │ ├── convert.ts │ │ │ │ │ ├── generator.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── constants │ │ │ │ │ ├── globals.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── global-state.ts │ │ │ │ └── utils │ │ │ │ │ ├── __tests__ │ │ │ │ │ ├── diff.test.ts │ │ │ │ │ ├── dom.test.ts │ │ │ │ │ ├── letter.test.ts │ │ │ │ │ ├── state-handler.test.ts │ │ │ │ │ ├── tree.test.ts │ │ │ │ │ ├── unique.test.ts │ │ │ │ │ ├── update-css-variables.test.ts │ │ │ │ │ ├── util.test.ts │ │ │ │ │ └── window.test.ts │ │ │ │ │ ├── clamp │ │ │ │ │ └── index.ts │ │ │ │ │ ├── cn.ts │ │ │ │ │ ├── date.ts │ │ │ │ │ ├── diff.ts │ │ │ │ │ ├── dom.ts │ │ │ │ │ ├── download.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── inference.ts │ │ │ │ │ ├── letter.ts │ │ │ │ │ ├── merge.ts │ │ │ │ │ ├── number │ │ │ │ │ └── index.ts │ │ │ │ │ ├── state-handler.ts │ │ │ │ │ ├── to.ts │ │ │ │ │ ├── tree.ts │ │ │ │ │ ├── unique.ts │ │ │ │ │ ├── update-css-variables.ts │ │ │ │ │ ├── util.ts │ │ │ │ │ └── window.ts │ │ │ └── tsconfig.json │ │ └── typings │ │ │ ├── build.config.ts │ │ │ ├── package.json │ │ │ ├── src │ │ │ ├── app.d.ts │ │ │ ├── basic.d.ts │ │ │ ├── global.d.ts │ │ │ ├── helper.d.ts │ │ │ ├── index.ts │ │ │ ├── menu-record.ts │ │ │ └── router.d.ts │ │ │ └── tsconfig.json │ ├── hooks │ │ ├── build.config.ts │ │ ├── package.json │ │ ├── src │ │ │ ├── index.ts │ │ │ ├── useAnimation.ts │ │ │ ├── useBreakpoints.ts │ │ │ ├── useControlledState.ts │ │ │ ├── useCssVar.ts │ │ │ ├── useEnhancedScroll.ts │ │ │ ├── useFindMenu.ts │ │ │ ├── useIsMobile.ts │ │ │ ├── useLayoutStyle.ts │ │ │ ├── useMediaQuery.ts │ │ │ ├── useNamespace.ts │ │ │ ├── usePresseHold.ts │ │ │ ├── useScrollLock.ts │ │ │ ├── useShow │ │ │ │ ├── async.ts │ │ │ │ ├── index.ts │ │ │ │ ├── sync.ts │ │ │ │ └── types.ts │ │ │ └── useWatermark.ts │ │ └── tsconfig.json │ ├── preferences │ │ ├── __tests__ │ │ │ ├── __snapshots__ │ │ │ │ └── config.test.ts.snap │ │ │ ├── config.test.ts │ │ │ └── preferences.test.tsx │ │ ├── build.config.ts │ │ ├── package.json │ │ ├── src │ │ │ ├── config.ts │ │ │ ├── constants.ts │ │ │ ├── index.ts │ │ │ ├── preferences.tsx │ │ │ ├── types.ts │ │ │ └── update-css-variables.ts │ │ └── tsconfig.json │ └── ui-kit │ │ ├── layout-ui │ │ ├── build.config.ts │ │ ├── package.json │ │ ├── postcss.config.mjs │ │ ├── src │ │ │ ├── components │ │ │ │ ├── index.ts │ │ │ │ ├── layout-content │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── types.ts │ │ │ │ ├── layout-footer │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── types.ts │ │ │ │ ├── layout-header │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── types.ts │ │ │ │ ├── layout-sidebar │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── types.ts │ │ │ │ │ └── useLayoutStyles.ts │ │ │ │ ├── layout-tabbar │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── types.ts │ │ │ │ └── widgets │ │ │ │ │ ├── SidebarCollapseButton.tsx │ │ │ │ │ ├── SidebarFixedButton.tsx │ │ │ │ │ └── index.ts │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── useLayout.ts │ │ │ ├── index.ts │ │ │ └── xpress-layout │ │ │ │ ├── LayoutProvider.tsx │ │ │ │ ├── context.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── types.ts │ │ ├── tailwind.config.mjs │ │ └── tsconfig.json │ │ ├── popup-ui │ │ ├── build.config.ts │ │ ├── package.json │ │ ├── src │ │ │ ├── drawer │ │ │ │ ├── Drawer.tsx │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ ├── index.ts │ │ │ └── modal │ │ │ │ ├── Modal.tsx │ │ │ │ ├── index.ts │ │ │ │ └── useModalDraggable.ts │ │ └── tsconfig.json │ │ ├── react-menu │ │ ├── README.md │ │ ├── build.config.ts │ │ ├── package.json │ │ ├── postcss.config.mjs │ │ ├── src │ │ │ ├── MenuView.tsx │ │ │ ├── SubMenuView.tsx │ │ │ ├── components │ │ │ │ ├── collapse-transition │ │ │ │ │ └── index.tsx │ │ │ │ ├── contexts.ts │ │ │ │ ├── hooks │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ ├── useMenuContext.tsx │ │ │ │ │ ├── useMenuStructure.ts │ │ │ │ │ └── useMenuStyle.ts │ │ │ │ ├── index.ts │ │ │ │ ├── menu-badge │ │ │ │ │ ├── MenuBadgeDot.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── menu-item │ │ │ │ │ └── index.tsx │ │ │ │ ├── menu │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── menuReducer.ts │ │ │ │ ├── normal-menu │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── types.ts │ │ │ │ ├── ripple │ │ │ │ │ └── index.ts │ │ │ │ ├── sub-menu-content │ │ │ │ │ └── index.tsx │ │ │ │ ├── sub-menu │ │ │ │ │ └── index.tsx │ │ │ │ └── types.ts │ │ │ ├── constants.ts │ │ │ ├── index.ts │ │ │ ├── types │ │ │ │ └── material-ripple-effects.d.ts │ │ │ └── utils │ │ │ │ └── Ripple.ts │ │ ├── tailwind.config.mjs │ │ └── tsconfig.json │ │ ├── shadcn-ui │ │ ├── build.config.ts │ │ ├── components.json │ │ ├── package.json │ │ ├── postcss.config.mjs │ │ ├── src │ │ │ ├── components │ │ │ │ ├── base │ │ │ │ │ ├── avatar │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── breadcrumb │ │ │ │ │ │ ├── Breadcrumb.tsx │ │ │ │ │ │ ├── BreadcrumbBackground.tsx │ │ │ │ │ │ ├── BreadcrumbView.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── style.css │ │ │ │ │ │ └── type.ts │ │ │ │ │ ├── button │ │ │ │ │ │ ├── Button.tsx │ │ │ │ │ │ ├── IconButton.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── context-menu │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── dropdown-menu │ │ │ │ │ │ ├── DropdownMenu.tsx │ │ │ │ │ │ ├── DropdownRadioMenu.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── type.ts │ │ │ │ │ ├── hover-card │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── icon │ │ │ │ │ │ ├── icon.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── loading │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── logo │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── number-field │ │ │ │ │ │ ├── NumberField.tsx │ │ │ │ │ │ ├── NumberFieldCom.tsx │ │ │ │ │ │ ├── NumberFieldContent.tsx │ │ │ │ │ │ ├── NumberFieldDecrement.tsx │ │ │ │ │ │ ├── NumberFieldIncrement.tsx │ │ │ │ │ │ ├── NumberFieldInput.tsx │ │ │ │ │ │ ├── NumberFieldItem.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── scroll-area │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── styles.module.css │ │ │ │ │ │ ├── styles.module.css.d.ts │ │ │ │ │ │ └── styles.module.css.json │ │ │ │ │ ├── segmented │ │ │ │ │ │ ├── TabsIndicator.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── tooltip │ │ │ │ │ │ ├── HelpTooltip.tsx │ │ │ │ │ │ ├── Tooltip.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── types.ts │ │ │ │ └── ui │ │ │ │ │ ├── avatar.tsx │ │ │ │ │ ├── badge │ │ │ │ │ ├── badge.ts │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── breadcrumb.tsx │ │ │ │ │ ├── button │ │ │ │ │ ├── Component.tsx │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── types.ts │ │ │ │ │ ├── card.tsx │ │ │ │ │ ├── checkbox.tsx │ │ │ │ │ ├── context-menu.tsx │ │ │ │ │ ├── dialog.tsx │ │ │ │ │ ├── dropdown-menu.tsx │ │ │ │ │ ├── form.tsx │ │ │ │ │ ├── hover-card.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── input.tsx │ │ │ │ │ ├── label.tsx │ │ │ │ │ ├── popover.tsx │ │ │ │ │ ├── scroll-area.tsx │ │ │ │ │ ├── select.tsx │ │ │ │ │ ├── separator.tsx │ │ │ │ │ ├── sheet.tsx │ │ │ │ │ ├── switch.tsx │ │ │ │ │ ├── tabs.tsx │ │ │ │ │ ├── toggle-group.tsx │ │ │ │ │ ├── toggle.tsx │ │ │ │ │ └── tooltip.tsx │ │ │ └── index.ts │ │ ├── tailwind.config.mjs │ │ └── tsconfig.json │ │ └── tabs-ui │ │ ├── build.config.ts │ │ ├── package.json │ │ ├── postcss.config.mjs │ │ ├── src │ │ ├── AnimationWrap │ │ │ └── index.tsx │ │ ├── TabsView.tsx │ │ ├── components │ │ │ ├── DraggableTabs.tsx │ │ │ └── SortableTab.tsx │ │ ├── hooks │ │ │ ├── useDraggableTabs.ts │ │ │ └── useTransition.ts │ │ ├── index.ts │ │ ├── tabs-base │ │ │ └── index.tsx │ │ ├── tabs-chrome │ │ │ ├── index.tsx │ │ │ └── style.css │ │ ├── types.ts │ │ ├── use-tabs-view-scroll.ts │ │ └── widgets │ │ │ ├── ToolMore.tsx │ │ │ ├── ToolScreen.tsx │ │ │ └── index.ts │ │ ├── tailwind.config.mjs │ │ └── tsconfig.json ├── components │ ├── package.json │ ├── src │ │ ├── index.ts │ │ └── progress │ │ │ ├── index.tsx │ │ │ └── utils.ts │ └── tsconfig.json ├── constants │ ├── README.md │ ├── package.json │ ├── src │ │ ├── core.ts │ │ └── index.ts │ └── tsconfig.json ├── effects │ ├── common-ui │ │ ├── package.json │ │ ├── src │ │ │ ├── components │ │ │ │ ├── icon-picker │ │ │ │ │ └── index.tsx │ │ │ │ ├── index.ts │ │ │ │ └── page │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── types.ts │ │ │ ├── index.ts │ │ │ └── ui │ │ │ │ ├── about │ │ │ │ └── index.tsx │ │ │ │ ├── fullback │ │ │ │ └── index.tsx │ │ │ │ └── index.ts │ │ └── tsconfig.json │ ├── layouts │ │ ├── package.json │ │ ├── src │ │ │ ├── authentication │ │ │ │ ├── AuthenticationFormView.tsx │ │ │ │ ├── IconCloud.tsx │ │ │ │ ├── Toolbar.tsx │ │ │ │ ├── icons │ │ │ │ │ ├── android.svg │ │ │ │ │ ├── androidstudio.svg │ │ │ │ │ ├── css3.svg │ │ │ │ │ ├── cypress.svg │ │ │ │ │ ├── dart.svg │ │ │ │ │ ├── docker.svg │ │ │ │ │ ├── express.svg │ │ │ │ │ ├── figma.svg │ │ │ │ │ ├── firebase.svg │ │ │ │ │ ├── flutter.svg │ │ │ │ │ ├── git.svg │ │ │ │ │ ├── github.svg │ │ │ │ │ ├── gitlab.svg │ │ │ │ │ ├── html5.svg │ │ │ │ │ ├── javascript.svg │ │ │ │ │ ├── jest.svg │ │ │ │ │ ├── jira.svg │ │ │ │ │ ├── nextdotjs.svg │ │ │ │ │ ├── nginx.svg │ │ │ │ │ ├── nodedotjs.svg │ │ │ │ │ ├── postgresql.svg │ │ │ │ │ ├── prisma.svg │ │ │ │ │ ├── react.svg │ │ │ │ │ ├── sonarqube.svg │ │ │ │ │ ├── testinglibrary.svg │ │ │ │ │ ├── typescript.svg │ │ │ │ │ └── vercel.svg │ │ │ │ ├── index.tsx │ │ │ │ └── style.css │ │ │ ├── basic │ │ │ │ ├── BasicLayout.tsx │ │ │ │ ├── content-components │ │ │ │ │ └── content.tsx │ │ │ │ ├── copyright │ │ │ │ │ └── index.tsx │ │ │ │ ├── extra │ │ │ │ │ └── index.tsx │ │ │ │ ├── footer │ │ │ │ │ └── index.tsx │ │ │ │ ├── header │ │ │ │ │ └── index.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── login-layout │ │ │ │ │ └── .gitkeep │ │ │ │ ├── menu │ │ │ │ │ ├── extra-menu │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── menu │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── mixed-menu │ │ │ │ │ │ └── index.tsx │ │ │ │ ├── tabbar │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── useTabbar.ts │ │ │ │ ├── use-extra-menu.ts │ │ │ │ └── use-mixed-menu.ts │ │ │ ├── index.ts │ │ │ └── widgets │ │ │ │ ├── breadcrumb │ │ │ │ └── index.tsx │ │ │ │ ├── check-updates │ │ │ │ ├── index.tsx │ │ │ │ └── versionChecker.worker.ts │ │ │ │ ├── fullscreen │ │ │ │ └── index.tsx │ │ │ │ ├── global-search │ │ │ │ ├── SearchPanel.tsx │ │ │ │ └── index.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── language-toggle │ │ │ │ └── index.tsx │ │ │ │ ├── notification │ │ │ │ └── index.tsx │ │ │ │ ├── preferences │ │ │ │ ├── PreferencesDrawer.tsx │ │ │ │ ├── blocks │ │ │ │ │ ├── Block.tsx │ │ │ │ │ ├── InputItem.tsx │ │ │ │ │ ├── SelectItem.tsx │ │ │ │ │ ├── SwitchItem.tsx │ │ │ │ │ ├── ToggleItem.tsx │ │ │ │ │ ├── general │ │ │ │ │ │ ├── Animation │ │ │ │ │ │ │ ├── PreviewAnimationCell.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── General.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── layout │ │ │ │ │ │ ├── Breadcrumb.tsx │ │ │ │ │ │ ├── Content.tsx │ │ │ │ │ │ ├── Copyright.tsx │ │ │ │ │ │ ├── Footer.tsx │ │ │ │ │ │ ├── Header.tsx │ │ │ │ │ │ ├── Layout.tsx │ │ │ │ │ │ ├── Navigation.tsx │ │ │ │ │ │ ├── Sidebar.tsx │ │ │ │ │ │ ├── Tabbar.tsx │ │ │ │ │ │ ├── Widget.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── shortcutkey │ │ │ │ │ │ ├── Global.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── theme │ │ │ │ │ │ ├── BuiltinTheme.tsx │ │ │ │ │ │ ├── Other.tsx │ │ │ │ │ │ ├── Radius.tsx │ │ │ │ │ │ ├── Theme.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ ├── icons │ │ │ │ │ ├── ContentCompact.tsx │ │ │ │ │ ├── FullContent.tsx │ │ │ │ │ ├── HeaderMixedNav.tsx │ │ │ │ │ ├── HeaderNav.tsx │ │ │ │ │ ├── HeaderSidebarNav.tsx │ │ │ │ │ ├── MixedNav.tsx │ │ │ │ │ ├── Setting.tsx │ │ │ │ │ ├── SidebarMixedNav.tsx │ │ │ │ │ ├── SidebarNav.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── modules │ │ │ │ │ ├── appearance │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── general │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── layout │ │ │ │ │ └── index.tsx │ │ │ │ │ └── shortcutkey │ │ │ │ │ └── index.tsx │ │ │ │ ├── reload │ │ │ │ └── index.tsx │ │ │ │ ├── theme-toggle │ │ │ │ ├── ThemeButton.tsx │ │ │ │ ├── ThemeToggle.tsx │ │ │ │ └── index.ts │ │ │ │ └── user-dropdown │ │ │ │ └── index.tsx │ │ └── tsconfig.json │ ├── request │ │ ├── package.json │ │ ├── src │ │ │ ├── index.ts │ │ │ └── request-client │ │ │ │ ├── README.md │ │ │ │ ├── index.ts │ │ │ │ ├── modules │ │ │ │ ├── downloader.test.ts │ │ │ │ ├── downloader.ts │ │ │ │ ├── interceptor.ts │ │ │ │ ├── uploader.test.ts │ │ │ │ └── uploader.ts │ │ │ │ ├── preset-interceptors.ts │ │ │ │ ├── request-client.test.ts │ │ │ │ ├── request-client.ts │ │ │ │ └── types.ts │ │ └── tsconfig.json │ └── router-toolset │ │ ├── build.config.ts │ │ ├── package.json │ │ ├── src │ │ ├── HistoryRouter.tsx │ │ ├── history.ts │ │ ├── index.ts │ │ ├── router.ts │ │ └── utils │ │ │ ├── Auth.tsx │ │ │ ├── accessible.ts │ │ │ ├── common.tsx │ │ │ ├── generate-menus.ts │ │ │ ├── generate-routes-backend.ts │ │ │ ├── generate-routes-frontend.ts │ │ │ ├── index.ts │ │ │ └── merge-route-modules.ts │ │ └── tsconfig.json ├── icons │ ├── README.md │ ├── package.json │ ├── src │ │ ├── iconify │ │ │ └── index.ts │ │ ├── icons │ │ │ └── EmptyIcon.tsx │ │ ├── index.ts │ │ └── svg │ │ │ ├── genExports.js │ │ │ ├── icons │ │ │ ├── 403.svg │ │ │ ├── 404.svg │ │ │ ├── 500.svg │ │ │ ├── antdv-logo.svg │ │ │ ├── avatar-1.svg │ │ │ ├── avatar-2.svg │ │ │ ├── avatar-3.svg │ │ │ ├── avatar-4.svg │ │ │ ├── bell.svg │ │ │ ├── cake.svg │ │ │ ├── card.svg │ │ │ ├── coming-soon.svg │ │ │ ├── download.svg │ │ │ ├── offline.svg │ │ │ └── warning.svg │ │ │ ├── index.ts │ │ │ └── load.ts │ └── tsconfig.json ├── stores │ ├── package.json │ ├── src │ │ ├── access.ts │ │ ├── index.ts │ │ ├── tabbar │ │ │ └── index.ts │ │ └── user.ts │ └── tsconfig.json ├── styles │ ├── README.md │ ├── package.json │ ├── src │ │ ├── global │ │ │ └── index.scss │ │ └── index.ts │ └── tsconfig.json └── utils │ ├── README.md │ ├── package.json │ ├── src │ ├── index.ts │ ├── unmount-global-loading.ts │ └── use-app-config.ts │ └── tsconfig.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── readme.md ├── scripts ├── clean.mjs ├── cli │ ├── README.md │ ├── bin │ │ └── xpress.mjs │ ├── build.config.ts │ ├── package.json │ ├── src │ │ ├── check-circular │ │ │ └── index.ts │ │ ├── check-dep │ │ │ └── index.ts │ │ ├── code-workspace │ │ │ └── index.ts │ │ ├── commit │ │ │ ├── index.ts │ │ │ └── locales.ts │ │ ├── index.ts │ │ ├── lint │ │ │ └── index.ts │ │ └── publint │ │ │ └── index.ts │ └── tsconfig.json └── turbo-run │ ├── README.md │ ├── bin │ └── turbo-run.mjs │ ├── build.config.ts │ ├── package.json │ ├── src │ ├── index.ts │ └── run.ts │ └── tsconfig.json ├── stylelint.config.mjs ├── turbo.json ├── vercel.json ├── vitest.config.ts ├── vitest.workspace.ts └── xpress.code-workspace /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | not ie 11 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # 表明这是最顶层的 EditorConfig 配置文件 2 | root = true 3 | 4 | # 对所有文件生效的配置 5 | [*] 6 | # 设置文件编码为 UTF-8 7 | charset=utf-8 8 | # 使用 LF 作为换行符 9 | end_of_line=lf 10 | # 文件末尾添加空行 11 | insert_final_newline=true 12 | # 使用空格作为缩进 13 | indent_style=space 14 | # 缩进大小为2个空格 15 | indent_size=2 16 | # 每行最大长度为100个字符 17 | max_line_length = 100 18 | # 删除行尾空格 19 | trim_trailing_whitespace = true 20 | # 使用单引号作为引号类型 21 | quote_type = single 22 | 23 | # 针对 YAML 和 JSON 文件的特殊配置 24 | [*.{yml,yaml,json}] 25 | indent_style = space 26 | indent_size = 2 27 | 28 | # Markdown 文件的特殊配置 29 | [*.md] 30 | # Markdown 文件不删除行尾空格,因为可能会影响格式 31 | trim_trailing_whitespace = false 32 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/cn/get-started/getting-started-with-git/configuring-git-to-handle-line-endings 2 | 3 | # Automatically normalize line endings (to LF) for all text-based files. 4 | * text=auto eol=lf 5 | 6 | # Declare files that will always have CRLF line endings on checkout. 7 | *.{cmd,[cC][mM][dD]} text eol=crlf 8 | *.{bat,[bB][aA][tT]} text eol=crlf 9 | 10 | # Denote all files that are truly binary and should not be modified. 11 | *.{ico,png,jpg,jpeg,gif,webp,svg,woff,woff2} binary -------------------------------------------------------------------------------- /.gitconfig: -------------------------------------------------------------------------------- 1 | [core] 2 | ignorecase = false 3 | -------------------------------------------------------------------------------- /.github/semantic.yml: -------------------------------------------------------------------------------- 1 | titleAndCommits: true 2 | types: 3 | - feat 4 | - fix 5 | - docs 6 | - chore 7 | - style 8 | - refactor 9 | - perf 10 | - test 11 | - build 12 | - ci 13 | - revert 14 | -------------------------------------------------------------------------------- /.github/workflows/draft.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | permissions: 9 | contents: read 10 | pull-requests: write 11 | 12 | jobs: 13 | update_release_draft: 14 | permissions: 15 | # write permission is required to create a github release 16 | contents: write 17 | # write permission is required for autolabeler 18 | # otherwise, read permission is required at least 19 | pull-requests: write 20 | if: github.repository == 'Rascal-Coder/xpress' 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: release-drafter/release-drafter@v6 24 | env: 25 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 26 | -------------------------------------------------------------------------------- /.github/workflows/lock.yml: -------------------------------------------------------------------------------- 1 | name: Lock Threads 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | workflow_dispatch: 7 | 8 | permissions: 9 | issues: write 10 | pull-requests: write 11 | 12 | jobs: 13 | action: 14 | if: github.repository == 'Rascal-Coder/xpress' 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: dessant/lock-threads@v5 18 | with: 19 | github-token: ${{ secrets.GITHUB_TOKEN }} 20 | issue-inactive-days: '14' 21 | issue-lock-reason: '' 22 | pr-inactive-days: '30' 23 | pr-lock-reason: '' 24 | process-only: 'issues, prs' 25 | -------------------------------------------------------------------------------- /.github/workflows/rerun.yml: -------------------------------------------------------------------------------- 1 | name: Rerun workflow 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | run_id: 7 | description: The workflow id to relanch 8 | required: true 9 | jobs: 10 | rerun: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: rerun ${{ inputs.run_id }} 14 | env: 15 | GH_REPO: ${{ github.repository }} 16 | GH_TOKEN: ${{ github.token }} 17 | run: | 18 | gh run watch ${{ inputs.run_id }} > /dev/null 2>&1 19 | gh run rerun ${{ inputs.run_id }} --failed 20 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: 'Close stale issues' 2 | 3 | on: 4 | schedule: 5 | - cron: '0 1 * * *' 6 | 7 | jobs: 8 | stale: 9 | if: github.repository == 'Rascal-Coder/xpress' 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/stale@v9 13 | with: 14 | repo-token: ${{ secrets.GITHUB_TOKEN }} 15 | stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days' 16 | stale-pr-message: 'This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days' 17 | exempt-issue-labels: 'bug,enhancement' 18 | days-before-stale: 60 19 | days-before-close: 7 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | dist.zip 6 | dist.tar 7 | dist.war 8 | .nitro 9 | .output 10 | build 11 | *-dist.zip 12 | *-dist.tar 13 | *-dist.war 14 | coverage 15 | *.local 16 | **/.vitepress/cache 17 | .cache 18 | .turbo 19 | .temp 20 | dev-dist 21 | .stylelintcache 22 | .react-router 23 | yarn.lock 24 | package-lock.json 25 | .VSCodeCounter 26 | **/backend-mock/data 27 | 28 | # local env files 29 | .env.local 30 | .env.*.local 31 | .eslintcache 32 | 33 | logs 34 | *.log 35 | npm-debug.log* 36 | yarn-debug.log* 37 | yarn-error.log* 38 | pnpm-debug.log* 39 | lerna-debug.log* 40 | vite.config.mts.* 41 | vite.config.mjs.* 42 | vite.config.js.* 43 | vite.config.ts.* 44 | 45 | # Editor directories and files 46 | .idea 47 | # .vscode 48 | *.suo 49 | *.ntvs* 50 | *.njsproj 51 | *.sln 52 | *.sw? 53 | .history 54 | 55 | .vercel 56 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | ports: 2 | - port: 5555 3 | onOpen: open-preview 4 | tasks: 5 | - init: corepack enable && pnpm install 6 | command: pnpm run dev:play 7 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | echo "开始运行 commit-msg 钩子..." 2 | 3 | # 使用 pnpm run 执行已定义的脚本 4 | pnpm run commit:verify 5 | 6 | echo "commit-msg 钩子运行完成。" 7 | -------------------------------------------------------------------------------- /.husky/post-merge: -------------------------------------------------------------------------------- 1 | # 每次 git pull 之后, 安装依赖 2 | 3 | pnpm install 4 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | # update `xpress.code-workspace` file 2 | pnpm xpress code-workspace --auto-commit 3 | 4 | # Format and submit code according to lintstagedrc.js configuration 5 | pnpm exec lint-staged 6 | 7 | echo Run pre-commit hook done. 8 | -------------------------------------------------------------------------------- /.lintstagedrc.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | '*.{js,jsx,ts,tsx}': [ 3 | 'prettier --cache --ignore-unknown --write', 4 | 'eslint --cache --fix', 5 | ], 6 | '*.{scss,less,styl,html,css}': [ 7 | 'prettier --cache --ignore-unknown --write', 8 | (files) => { 9 | const filteredFiles = files 10 | .filter((file) => !file.includes('loadingTemplate')) 11 | .filter((file) => !file.endsWith('.html')); 12 | return filteredFiles.length > 0 13 | ? `stylelint --fix --allow-empty-input ${filteredFiles.join(' ')}` 14 | : 'echo "No style files to lint"'; 15 | }, 16 | ], 17 | '*.md': ['prettier --cache --ignore-unknown --write'], 18 | '{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': [ 19 | 'prettier --cache --write--parser json', 20 | ], 21 | 'package.json': ['prettier --cache --write'], 22 | }; 23 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 20.14.0 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry = "https://registry.npmmirror.com" 2 | # public-hoist-pattern 指定公共依赖 3 | public-hoist-pattern[]=husky 4 | public-hoist-pattern[]=eslint 5 | public-hoist-pattern[]=prettier 6 | public-hoist-pattern[]=prettier-plugin-tailwindcss 7 | public-hoist-pattern[]=stylelint 8 | public-hoist-pattern[]=*postcss* 9 | 10 | strict-peer-dependencies=false 11 | auto-install-peers=true 12 | dedupe-peer-dependents=true 13 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | dev-dist 3 | .local 4 | .output.js 5 | node_modules 6 | .nvmrc 7 | coverage 8 | CODEOWNERS 9 | .nitro 10 | .output 11 | 12 | 13 | **/*.svg 14 | **/*.sh 15 | 16 | public 17 | .npmrc 18 | *-lock.yaml 19 | -------------------------------------------------------------------------------- /.prettierrc.mjs: -------------------------------------------------------------------------------- 1 | export { default } from '@xpress/prettier-config'; 2 | -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | dist 2 | public 3 | __tests__ 4 | coverage 5 | **/loadingTemplate/**/*.html 6 | -------------------------------------------------------------------------------- /.vercel/README.txt: -------------------------------------------------------------------------------- 1 | > Why do I have a folder named ".vercel" in my project? 2 | The ".vercel" folder is created when you link a directory to a Vercel project. 3 | 4 | > What does the "project.json" file contain? 5 | The "project.json" file contains: 6 | - The ID of the Vercel project that you linked ("projectId") 7 | - The ID of the user or team your Vercel project is owned by ("orgId") 8 | 9 | > Should I commit the ".vercel" folder? 10 | No, you should not share the ".vercel" folder with anyone. 11 | Upon creation, it will be automatically added to your ".gitignore" file. 12 | -------------------------------------------------------------------------------- /.vercel/project.json: -------------------------------------------------------------------------------- 1 | {"projectId":"prj_6YLv6oYIJfLqM8w59AoqkbjbhT8f","orgId":"team_9DhgAnxP0NxeXlGBZGG3AQff"} -------------------------------------------------------------------------------- /apps/backend-mock/.env: -------------------------------------------------------------------------------- 1 | PORT=5320 2 | ACCESS_TOKEN_SECRET=access_token_secret 3 | REFRESH_TOKEN_SECRET=refresh_token_secret 4 | -------------------------------------------------------------------------------- /apps/backend-mock/.vercel/README.txt: -------------------------------------------------------------------------------- 1 | > Why do I have a folder named ".vercel" in my project? 2 | The ".vercel" folder is created when you link a directory to a Vercel project. 3 | 4 | > What does the "project.json" file contain? 5 | The "project.json" file contains: 6 | - The ID of the Vercel project that you linked ("projectId") 7 | - The ID of the user or team your Vercel project is owned by ("orgId") 8 | 9 | > Should I commit the ".vercel" folder? 10 | No, you should not share the ".vercel" folder with anyone. 11 | Upon creation, it will be automatically added to your ".gitignore" file. 12 | -------------------------------------------------------------------------------- /apps/backend-mock/.vercel/project.json: -------------------------------------------------------------------------------- 1 | {"projectId":"prj_vMiKOVDxL3oiOYz627avQuo3bF5p","orgId":"team_9DhgAnxP0NxeXlGBZGG3AQff"} -------------------------------------------------------------------------------- /apps/backend-mock/README.md: -------------------------------------------------------------------------------- 1 | # @xpress/backend-mock 2 | 3 | ## Running the app 4 | 5 | ```bash 6 | # development 7 | $ pnpm run start 8 | 9 | # production mode 10 | $ pnpm run build 11 | ``` 12 | -------------------------------------------------------------------------------- /apps/backend-mock/api/auth/codes.ts: -------------------------------------------------------------------------------- 1 | import { verifyAccessToken } from '~/utils/jwt-utils'; 2 | import { unAuthorizedResponse } from '~/utils/response'; 3 | 4 | export default eventHandler((event) => { 5 | const userinfo = verifyAccessToken(event); 6 | if (!userinfo) { 7 | return unAuthorizedResponse(event); 8 | } 9 | 10 | const codes = 11 | MOCK_CODES.find((item) => item.username === userinfo.username)?.codes ?? []; 12 | 13 | return useResponseSuccess(codes); 14 | }); 15 | -------------------------------------------------------------------------------- /apps/backend-mock/api/auth/logout.post.ts: -------------------------------------------------------------------------------- 1 | import { 2 | clearRefreshTokenCookie, 3 | getRefreshTokenFromCookie, 4 | } from '~/utils/cookie-utils'; 5 | 6 | export default defineEventHandler(async (event) => { 7 | const refreshToken = getRefreshTokenFromCookie(event); 8 | if (!refreshToken) { 9 | return useResponseSuccess(''); 10 | } 11 | 12 | clearRefreshTokenCookie(event); 13 | 14 | return useResponseSuccess(''); 15 | }); 16 | -------------------------------------------------------------------------------- /apps/backend-mock/api/auth/refresh.post.ts: -------------------------------------------------------------------------------- 1 | import { 2 | clearRefreshTokenCookie, 3 | getRefreshTokenFromCookie, 4 | setRefreshTokenCookie, 5 | } from '~/utils/cookie-utils'; 6 | import { verifyRefreshToken } from '~/utils/jwt-utils'; 7 | import { forbiddenResponse } from '~/utils/response'; 8 | 9 | export default defineEventHandler(async (event) => { 10 | const refreshToken = getRefreshTokenFromCookie(event); 11 | if (!refreshToken) { 12 | return forbiddenResponse(event); 13 | } 14 | 15 | clearRefreshTokenCookie(event); 16 | 17 | const userinfo = verifyRefreshToken(refreshToken); 18 | if (!userinfo) { 19 | return forbiddenResponse(event); 20 | } 21 | 22 | const findUser = MOCK_USERS.find( 23 | (item) => item.username === userinfo.username, 24 | ); 25 | if (!findUser) { 26 | return forbiddenResponse(event); 27 | } 28 | const accessToken = generateAccessToken(findUser); 29 | 30 | setRefreshTokenCookie(event, refreshToken); 31 | 32 | return accessToken; 33 | }); 34 | -------------------------------------------------------------------------------- /apps/backend-mock/api/menu/all.ts: -------------------------------------------------------------------------------- 1 | // import { verifyAccessToken } from '~/utils/jwt-utils'; 2 | // import { unAuthorizedResponse } from '~/utils/response'; 3 | 4 | export default eventHandler(async (_event) => { 5 | // const userinfo = verifyAccessToken(event); 6 | // if (!userinfo) { 7 | // return unAuthorizedResponse(event); 8 | // } 9 | 10 | // const menus = 11 | // .find((item) => item.username === userinfo.username)?.menus ?? []; 12 | return useResponseSuccess(MOCK_MENUS); 13 | }); 14 | -------------------------------------------------------------------------------- /apps/backend-mock/api/status.ts: -------------------------------------------------------------------------------- 1 | export default eventHandler((event) => { 2 | const { status } = getQuery(event); 3 | setResponseStatus(event, Number(status)); 4 | return useResponseError(`${status}`); 5 | }); 6 | -------------------------------------------------------------------------------- /apps/backend-mock/api/test.get.ts: -------------------------------------------------------------------------------- 1 | export default defineEventHandler(() => 'Test get handler'); 2 | -------------------------------------------------------------------------------- /apps/backend-mock/api/test.post.ts: -------------------------------------------------------------------------------- 1 | export default defineEventHandler(() => 'Test post handler'); 2 | -------------------------------------------------------------------------------- /apps/backend-mock/api/user/info.ts: -------------------------------------------------------------------------------- 1 | import { verifyAccessToken } from '~/utils/jwt-utils'; 2 | import { unAuthorizedResponse } from '~/utils/response'; 3 | 4 | export default eventHandler((event) => { 5 | const userinfo = verifyAccessToken(event); 6 | if (!userinfo) { 7 | return unAuthorizedResponse(event); 8 | } 9 | return useResponseSuccess(userinfo); 10 | }); 11 | -------------------------------------------------------------------------------- /apps/backend-mock/error.ts: -------------------------------------------------------------------------------- 1 | import type { NitroErrorHandler } from 'nitropack'; 2 | 3 | const errorHandler: NitroErrorHandler = function (error, event) { 4 | event.node.res.end(`[Error Handler] ${error.stack}`); 5 | }; 6 | 7 | export default errorHandler; 8 | -------------------------------------------------------------------------------- /apps/backend-mock/middleware/1.api.ts: -------------------------------------------------------------------------------- 1 | export default defineEventHandler((event) => { 2 | if (event.method === 'OPTIONS') { 3 | event.node.res.statusCode = 204; 4 | event.node.res.statusMessage = 'No Content.'; 5 | return 'OK'; 6 | } 7 | }); 8 | -------------------------------------------------------------------------------- /apps/backend-mock/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@xpress/backend-mock", 3 | "version": "1.0.0", 4 | "description": "", 5 | "private": true, 6 | "license": "MIT", 7 | "author": "", 8 | "scripts": { 9 | "build": "nitro build", 10 | "start": "nitro dev" 11 | }, 12 | "dependencies": { 13 | "@faker-js/faker": "catalog:", 14 | "jsonwebtoken": "catalog:", 15 | "nitropack": "catalog:" 16 | }, 17 | "devDependencies": { 18 | "@types/jsonwebtoken": "catalog:", 19 | "h3": "catalog:" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /apps/backend-mock/routes/[...].ts: -------------------------------------------------------------------------------- 1 | export default defineEventHandler(() => { 2 | return ` 3 |

Hello Xpress Admin

4 |

Mock service is starting

5 | 11 | `; 12 | }); 13 | -------------------------------------------------------------------------------- /apps/backend-mock/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /apps/backend-mock/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nitro/types/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /apps/backend-mock/utils/cookie-utils.ts: -------------------------------------------------------------------------------- 1 | import type { EventHandlerRequest, H3Event } from 'h3'; 2 | 3 | export function clearRefreshTokenCookie(event: H3Event) { 4 | deleteCookie(event, 'jwt', { 5 | httpOnly: true, 6 | sameSite: 'none', 7 | secure: true, 8 | }); 9 | } 10 | 11 | export function setRefreshTokenCookie( 12 | event: H3Event, 13 | refreshToken: string, 14 | ) { 15 | setCookie(event, 'jwt', refreshToken, { 16 | httpOnly: true, 17 | maxAge: 24 * 60 * 60 * 1000, 18 | sameSite: 'none', 19 | secure: true, 20 | }); 21 | } 22 | 23 | export function getRefreshTokenFromCookie(event: H3Event) { 24 | const refreshToken = getCookie(event, 'jwt'); 25 | return refreshToken; 26 | } 27 | -------------------------------------------------------------------------------- /apps/web-antd/.env: -------------------------------------------------------------------------------- 1 | # 应用标题 2 | VITE_APP_TITLE=Xpress Antd 3 | 4 | # 应用命名空间,用于缓存、store等功能的前缀,确保隔离 5 | VITE_APP_NAMESPACE=xpress-antd 6 | 7 | # 应用版本 8 | VITE_APP_VERSION=1.0.0 9 | 10 | # 权限模式 11 | VITE_ACCESS_MODE=frontend 12 | 13 | 14 | # 登录过期模式 可选值: modal, page 15 | VITE_LOGIN_EXPIRED_MODE=modal 16 | 17 | # 是否启用刷新token 18 | VITE_ENABLE_REFRESH_TOKEN=false 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /apps/web-antd/.env.analyze: -------------------------------------------------------------------------------- 1 | # public path 2 | VITE_BASE=/ 3 | 4 | # Basic interface address SPA 5 | VITE_GLOB_API_URL=/api 6 | 7 | VITE_VISUALIZER=true 8 | -------------------------------------------------------------------------------- /apps/web-antd/.env.development: -------------------------------------------------------------------------------- 1 | # 端口号 2 | VITE_PORT=5666 3 | 4 | VITE_BASE=/ 5 | 6 | # 接口地址 7 | VITE_GLOB_API_URL=/api 8 | 9 | # 是否开启 Nitro Mock服务,true 为开启,false 为关闭 10 | VITE_NITRO_MOCK=true 11 | 12 | # 是否打开 devtools,true 为打开,false 为关闭 13 | VITE_DEVTOOLS=false 14 | 15 | # 是否注入全局loading 16 | VITE_INJECT_APP_LOADING=true 17 | -------------------------------------------------------------------------------- /apps/web-antd/.env.production: -------------------------------------------------------------------------------- 1 | VITE_BASE=/ 2 | 3 | # 接口地址 4 | VITE_GLOB_API_URL="https://xpress-backend.ras-cal.cc/api/" 5 | 6 | # 是否开启压缩,可以设置为 none, brotli, gzip 7 | VITE_COMPRESS=none 8 | 9 | # 是否开启 PWA 10 | VITE_PWA=false 11 | 12 | # vue-router 的模式 13 | VITE_ROUTER_HISTORY=hash 14 | 15 | # 是否注入全局loading 16 | VITE_INJECT_APP_LOADING=true 17 | 18 | # 打包后是否生成dist.zip 19 | VITE_ARCHIVER=true 20 | -------------------------------------------------------------------------------- /apps/web-antd/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 14 | 24 | 25 | 26 | 27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /apps/web-antd/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from '@xpress/tailwind-config/postcss'; 2 | -------------------------------------------------------------------------------- /apps/web-antd/public/images/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rascal-Coder/xpress/175d3625049fd8243be155185d53cafcfbbcebe6/apps/web-antd/public/images/avatar.png -------------------------------------------------------------------------------- /apps/web-antd/src/api/core/auth.ts: -------------------------------------------------------------------------------- 1 | import { requestClient } from '../request'; 2 | 3 | export namespace AuthApi { 4 | /** 登录接口参数 */ 5 | export interface LoginParams { 6 | password?: string; 7 | username?: string; 8 | } 9 | 10 | /** 登录接口返回值 */ 11 | export interface LoginResult { 12 | accessToken: string; 13 | } 14 | 15 | export interface RefreshTokenResult { 16 | data: string; 17 | status: number; 18 | } 19 | } 20 | /** 21 | * 登录 22 | */ 23 | export async function loginApi(data: AuthApi.LoginParams) { 24 | return requestClient.post('/auth/login', data); 25 | } 26 | -------------------------------------------------------------------------------- /apps/web-antd/src/api/core/index.ts: -------------------------------------------------------------------------------- 1 | export * from './auth'; 2 | -------------------------------------------------------------------------------- /apps/web-antd/src/api/index.ts: -------------------------------------------------------------------------------- 1 | export * from './core'; 2 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/AddButton/AddButton.tsx: -------------------------------------------------------------------------------- 1 | import AddIcon from '@mui/icons-material/Add'; 2 | import IconButton from '@mui/material/IconButton'; 3 | import { 4 | type FormContextType, 5 | type IconButtonProps, 6 | type RJSFSchema, 7 | type StrictRJSFSchema, 8 | TranslatableString, 9 | } from '@rjsf/utils'; 10 | 11 | /** The `AddButton` renders a button that represent the `Add` action on a form 12 | */ 13 | export default function AddButton< 14 | T = any, 15 | S extends StrictRJSFSchema = RJSFSchema, 16 | F extends FormContextType = any, 17 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 18 | >({ uiSchema, registry, ...props }: IconButtonProps) { 19 | const { translateString } = registry; 20 | return ( 21 | 26 | 27 | 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/AddButton/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './AddButton'; 2 | export * from './AddButton'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/ArrayFieldItemTemplate/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './ArrayFieldItemTemplate'; 2 | export * from './ArrayFieldItemTemplate'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/ArrayFieldTemplate/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './ArrayFieldTemplate'; 2 | export * from './ArrayFieldTemplate'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/BaseInputTemplate/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './BaseInputTemplate'; 2 | export * from './BaseInputTemplate'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/CheckboxWidget/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './CheckboxWidget'; 2 | export * from './CheckboxWidget'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/CheckboxesWidget/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './CheckboxesWidget'; 2 | export * from './CheckboxesWidget'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/DescriptionField/DescriptionField.tsx: -------------------------------------------------------------------------------- 1 | import Typography from '@mui/material/Typography'; 2 | import { 3 | type DescriptionFieldProps, 4 | type FormContextType, 5 | type RJSFSchema, 6 | type StrictRJSFSchema, 7 | } from '@rjsf/utils'; 8 | 9 | /** The `DescriptionField` is the template to use to render the description of a field 10 | * 11 | * @param props - The `DescriptionFieldProps` for this component 12 | */ 13 | export default function DescriptionField< 14 | T = any, 15 | S extends StrictRJSFSchema = RJSFSchema, 16 | F extends FormContextType = any, 17 | >(props: DescriptionFieldProps) { 18 | const { id, description } = props; 19 | if (description) { 20 | return ( 21 | 22 | {description} 23 | 24 | ); 25 | } 26 | 27 | return null; 28 | } 29 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/DescriptionField/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './DescriptionField'; 2 | export * from './DescriptionField'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/ErrorList/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './ErrorList'; 2 | export * from './ErrorList'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/FieldErrorTemplate/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './FieldErrorTemplate'; 2 | export * from './FieldErrorTemplate'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/FieldHelpTemplate/FieldHelpTemplate.tsx: -------------------------------------------------------------------------------- 1 | import FormHelperText from '@mui/material/FormHelperText'; 2 | import { 3 | type FieldHelpProps, 4 | type FormContextType, 5 | helpId, 6 | type RJSFSchema, 7 | type StrictRJSFSchema, 8 | } from '@rjsf/utils'; 9 | 10 | /** The `FieldHelpTemplate` component renders any help desired for a field 11 | * 12 | * @param props - The `FieldHelpProps` to be rendered 13 | */ 14 | export default function FieldHelpTemplate< 15 | T = any, 16 | S extends StrictRJSFSchema = RJSFSchema, 17 | F extends FormContextType = any, 18 | >(props: FieldHelpProps) { 19 | const { idSchema, help } = props; 20 | if (!help) { 21 | return null; 22 | } 23 | const id = helpId(idSchema); 24 | return ( 25 | 26 | {help} 27 | 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/FieldHelpTemplate/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './FieldHelpTemplate'; 2 | export * from './FieldHelpTemplate'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/FieldTemplate/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './FieldTemplate'; 2 | export * from './FieldTemplate'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/IconButton/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './IconButton'; 2 | export * from './IconButton'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/MuiForm/MuiForm.tsx: -------------------------------------------------------------------------------- 1 | import { type FormProps, withTheme } from '@rjsf/core'; 2 | import { 3 | type FormContextType, 4 | type RJSFSchema, 5 | type StrictRJSFSchema, 6 | } from '@rjsf/utils'; 7 | import { type ComponentType } from 'react'; 8 | 9 | import { generateTheme } from '../Theme'; 10 | 11 | export function generateForm< 12 | T = any, 13 | S extends StrictRJSFSchema = RJSFSchema, 14 | F extends FormContextType = any, 15 | >(): ComponentType> { 16 | return withTheme(generateTheme()); 17 | } 18 | 19 | export default generateForm(); 20 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/MuiForm/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './MuiForm'; 2 | export * from './MuiForm'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/ObjectFieldTemplate/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './ObjectFieldTemplate'; 2 | export * from './ObjectFieldTemplate'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/RadioWidget/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './RadioWidget'; 2 | export * from './RadioWidget'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/RangeWidget/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './RangeWidget'; 2 | export * from './RangeWidget'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/SelectWidget/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './SelectWidget'; 2 | export * from './SelectWidget'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/SubmitButton/SubmitButton.tsx: -------------------------------------------------------------------------------- 1 | import Box from '@mui/material/Box'; 2 | import Button from '@mui/material/Button'; 3 | import { 4 | type FormContextType, 5 | getSubmitButtonOptions, 6 | type RJSFSchema, 7 | type StrictRJSFSchema, 8 | type SubmitButtonProps, 9 | } from '@rjsf/utils'; 10 | 11 | /** The `SubmitButton` renders a button that represent the `Submit` action on a form 12 | */ 13 | export default function SubmitButton< 14 | T = any, 15 | S extends StrictRJSFSchema = RJSFSchema, 16 | F extends FormContextType = any, 17 | >({ uiSchema }: SubmitButtonProps) { 18 | const { 19 | submitText, 20 | norender, 21 | props: submitButtonProps = {}, 22 | } = getSubmitButtonOptions(uiSchema); 23 | if (norender) { 24 | return null; 25 | } 26 | return ( 27 | 28 | 36 | 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/SubmitButton/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './SubmitButton'; 2 | export * from './SubmitButton'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/Templates/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './Templates'; 2 | export * from './Templates'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/TextareaWidget/TextareaWidget.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | type FormContextType, 3 | getTemplate, 4 | type RJSFSchema, 5 | type StrictRJSFSchema, 6 | type WidgetProps, 7 | } from '@rjsf/utils'; 8 | 9 | /** The `TextareaWidget` is a widget for rendering input fields as textarea. 10 | * 11 | * @param props - The `WidgetProps` for this component 12 | */ 13 | export default function TextareaWidget< 14 | T = any, 15 | S extends StrictRJSFSchema = RJSFSchema, 16 | F extends FormContextType = any, 17 | >(props: WidgetProps) { 18 | const { options, registry } = props; 19 | const BaseInputTemplate = getTemplate<'BaseInputTemplate', T, S, F>( 20 | 'BaseInputTemplate', 21 | registry, 22 | options, 23 | ); 24 | 25 | let rows: number | string = 5; 26 | if (typeof options.rows === 'string' || typeof options.rows === 'number') { 27 | rows = options.rows; 28 | } 29 | 30 | return ; 31 | } 32 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/TextareaWidget/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './TextareaWidget'; 2 | export * from './TextareaWidget'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/Theme/Theme.tsx: -------------------------------------------------------------------------------- 1 | import { type ThemeProps } from '@rjsf/core'; 2 | import { 3 | type FormContextType, 4 | type RJSFSchema, 5 | type StrictRJSFSchema, 6 | } from '@rjsf/utils'; 7 | 8 | import { generateTemplates } from '../Templates'; 9 | import { generateWidgets } from '../Widgets'; 10 | 11 | export function generateTheme< 12 | T = any, 13 | S extends StrictRJSFSchema = RJSFSchema, 14 | F extends FormContextType = any, 15 | >(): ThemeProps { 16 | return { 17 | templates: generateTemplates(), 18 | widgets: generateWidgets(), 19 | }; 20 | } 21 | 22 | export default generateTheme(); 23 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/Theme/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './Theme'; 2 | export * from './Theme'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/TitleField/TitleField.tsx: -------------------------------------------------------------------------------- 1 | import Box from '@mui/material/Box'; 2 | import Divider from '@mui/material/Divider'; 3 | import Typography from '@mui/material/Typography'; 4 | import { 5 | type FormContextType, 6 | type RJSFSchema, 7 | type StrictRJSFSchema, 8 | type TitleFieldProps, 9 | } from '@rjsf/utils'; 10 | 11 | /** The `TitleField` is the template to use to render the title of a field 12 | * 13 | * @param props - The `TitleFieldProps` for this component 14 | */ 15 | export default function TitleField< 16 | T = any, 17 | S extends StrictRJSFSchema = RJSFSchema, 18 | F extends FormContextType = any, 19 | >({ id, title }: TitleFieldProps) { 20 | return ( 21 | 22 | {title} 23 | 24 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/TitleField/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './TitleField'; 2 | export * from './TitleField'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/Widgets/Widgets.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type FormContextType, 3 | type RegistryWidgetsType, 4 | type RJSFSchema, 5 | type StrictRJSFSchema, 6 | } from '@rjsf/utils'; 7 | 8 | import CheckboxesWidget from '../CheckboxesWidget/CheckboxesWidget'; 9 | import CheckboxWidget from '../CheckboxWidget/CheckboxWidget'; 10 | import RadioWidget from '../RadioWidget/RadioWidget'; 11 | import RangeWidget from '../RangeWidget/RangeWidget'; 12 | import SelectWidget from '../SelectWidget/SelectWidget'; 13 | import TextareaWidget from '../TextareaWidget/TextareaWidget'; 14 | 15 | export function generateWidgets< 16 | T = any, 17 | S extends StrictRJSFSchema = RJSFSchema, 18 | F extends FormContextType = any, 19 | >(): RegistryWidgetsType { 20 | return { 21 | CheckboxWidget, 22 | CheckboxesWidget, 23 | RadioWidget, 24 | RangeWidget, 25 | SelectWidget, 26 | TextareaWidget, 27 | }; 28 | } 29 | 30 | export default generateWidgets(); 31 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/Widgets/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './Widgets'; 2 | export * from './Widgets'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/WrapIfAdditionalTemplate/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './WrapIfAdditionalTemplate'; 2 | export * from './WrapIfAdditionalTemplate'; 3 | -------------------------------------------------------------------------------- /apps/web-antd/src/components/MForm/src/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Form, generateForm } from './MuiForm'; 2 | export { default } from './MuiForm/MuiForm'; 3 | export { default as Templates, generateTemplates } from './Templates'; 4 | export { default as Theme, generateTheme } from './Theme'; 5 | 6 | export { default as Widgets, generateWidgets } from './Widgets'; 7 | -------------------------------------------------------------------------------- /apps/web-antd/src/constants/baseurl.ts: -------------------------------------------------------------------------------- 1 | const env = import.meta.env.PROD ? 'prod' : 'dev'; 2 | 3 | // TODO:临时这样处理,后续需要封装http请求 4 | export const baseUrl = 5 | env === 'prod' 6 | ? 'https://xpress-backend.ras-cal.cc' 7 | : 'http://localhost:5320'; 8 | -------------------------------------------------------------------------------- /apps/web-antd/src/pages/dashboard/workbench/components/utils.ts: -------------------------------------------------------------------------------- 1 | import { type Active, type DataRef, type Over } from '@dnd-kit/core'; 2 | 3 | import { type ColumnDragData } from './BoardColumn'; 4 | import { type TaskDragData } from './TaskCard'; 5 | 6 | type DraggableData = ColumnDragData | TaskDragData; 7 | 8 | export function hasDraggableData( 9 | entry: null | T | undefined, 10 | ): entry is { 11 | data: DataRef; 12 | } & T { 13 | if (!entry) { 14 | return false; 15 | } 16 | 17 | const data = entry.data.current; 18 | 19 | if (data?.type === 'Column' || data?.type === 'Task') { 20 | return true; 21 | } 22 | 23 | return false; 24 | } 25 | -------------------------------------------------------------------------------- /apps/web-antd/src/pages/dashboard/workbench/index.tsx: -------------------------------------------------------------------------------- 1 | import { KanbanBoard } from './components/KanbanBoard'; 2 | 3 | export default function Workbench() { 4 | return ; 5 | } 6 | -------------------------------------------------------------------------------- /apps/web-antd/src/pages/nest/nest1/index.tsx: -------------------------------------------------------------------------------- 1 | import { XpressPage } from '@xpress/common-ui'; 2 | import { Card, CardContent } from '@xpress-core/shadcn-ui'; 3 | 4 | import React from 'react'; 5 | 6 | const Nest1: React.FC = () => { 7 | return ( 8 | 9 |
10 | 11 | 12 |
/nest
13 |
14 | 15 | 16 |

菜单1

17 |
/nest/nest1
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | ); 26 | }; 27 | 28 | export default Nest1; 29 | -------------------------------------------------------------------------------- /apps/web-antd/src/pages/not-access/index.tsx: -------------------------------------------------------------------------------- 1 | import { XpressPage } from '@xpress/common-ui'; 2 | import { DEFAULT_HOME_PATH } from '@xpress/constants'; 3 | import { ArrowLeft, Svg403Icon } from '@xpress/icons'; 4 | import { XpressButton } from '@xpress-core/shadcn-ui'; 5 | 6 | import React from 'react'; 7 | 8 | import { useNavigate } from '#/router'; 9 | 10 | const NotFound: React.FC = () => { 11 | const navigate = useNavigate(); 12 | 13 | return ( 14 | 15 |
16 | 17 |
18 | navigate(DEFAULT_HOME_PATH)} size="lg"> 19 | 20 | 返回首页 21 | 22 |
23 |
24 |
25 | ); 26 | }; 27 | 28 | export default NotFound; 29 | -------------------------------------------------------------------------------- /apps/web-antd/src/pages/not-found/index.tsx: -------------------------------------------------------------------------------- 1 | import { XpressPage } from '@xpress/common-ui'; 2 | import { DEFAULT_HOME_PATH } from '@xpress/constants'; 3 | import { ArrowLeft, Svg404Icon } from '@xpress/icons'; 4 | import { XpressButton } from '@xpress-core/shadcn-ui'; 5 | 6 | import React from 'react'; 7 | 8 | import { useNavigate } from '#/router'; 9 | 10 | const NotFound: React.FC = () => { 11 | const navigate = useNavigate(); 12 | 13 | return ( 14 | 15 |
16 | 17 |
18 | navigate(DEFAULT_HOME_PATH)} size="lg"> 19 | 20 | 返回首页 21 | 22 |
23 |
24 |
25 | ); 26 | }; 27 | 28 | export default NotFound; 29 | -------------------------------------------------------------------------------- /apps/web-antd/src/pages/offline/index.tsx: -------------------------------------------------------------------------------- 1 | import { XpressPage } from '@xpress/common-ui'; 2 | import { DEFAULT_HOME_PATH } from '@xpress/constants'; 3 | import { ArrowLeft, SvgOfflineIcon } from '@xpress/icons'; 4 | import { XpressButton } from '@xpress-core/shadcn-ui'; 5 | 6 | import React from 'react'; 7 | 8 | import { useNavigate } from '#/router'; 9 | 10 | const Offline: React.FC = () => { 11 | const navigate = useNavigate(); 12 | 13 | return ( 14 | 15 |
16 | 17 |
18 | navigate(DEFAULT_HOME_PATH)} size="lg"> 19 | 20 | 返回首页 21 | 22 |
23 |
24 |
25 | ); 26 | }; 27 | 28 | export default Offline; 29 | -------------------------------------------------------------------------------- /apps/web-antd/src/pages/server-error/index.tsx: -------------------------------------------------------------------------------- 1 | import { XpressPage } from '@xpress/common-ui'; 2 | import { DEFAULT_HOME_PATH } from '@xpress/constants'; 3 | import { ArrowLeft, Svg500Icon } from '@xpress/icons'; 4 | import { XpressButton } from '@xpress-core/shadcn-ui'; 5 | 6 | import React from 'react'; 7 | 8 | import { useNavigate } from '#/router'; 9 | 10 | const ServerError: React.FC = () => { 11 | const navigate = useNavigate(); 12 | 13 | return ( 14 | 15 |
16 | 17 |
18 | navigate(DEFAULT_HOME_PATH)} size="lg"> 19 | 20 | 返回首页 21 | 22 |
23 |
24 |
25 | ); 26 | }; 27 | 28 | export default ServerError; 29 | -------------------------------------------------------------------------------- /apps/web-antd/src/pages/settings/index.tsx: -------------------------------------------------------------------------------- 1 | export default function Settings() { 2 | return
Settings
; 3 | } 4 | -------------------------------------------------------------------------------- /apps/web-antd/src/pages/system/role/index.tsx: -------------------------------------------------------------------------------- 1 | export default function Role() { 2 | return
Role
; 3 | } 4 | -------------------------------------------------------------------------------- /apps/web-antd/src/pages/system/user/index.tsx: -------------------------------------------------------------------------------- 1 | export default function User() { 2 | return
User
; 3 | } 4 | -------------------------------------------------------------------------------- /apps/web-antd/src/preferences.ts: -------------------------------------------------------------------------------- 1 | import type { Preferences } from '@xpress-core/preferences'; 2 | import type { DeepPartial } from '@xpress-core/typings'; 3 | /** 4 | * @description 项目配置文件 5 | * 只需要覆盖项目中的一部分配置,不需要的配置不用覆盖,会自动使用默认配置 6 | * !!! 更改配置后请清空缓存,否则可能不生效 7 | */ 8 | export const overridesPreferences: DeepPartial = { 9 | // overrides 10 | app: { 11 | // name: '测试213', 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /apps/web-antd/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { Router } from '@xpress/router'; 2 | 3 | import { generateAccessRoutes } from './access'; 4 | 5 | const { accessibleRoutes } = await generateAccessRoutes( 6 | import.meta.env.VITE_ACCESS_MODE, 7 | ); 8 | const router = new Router(accessibleRoutes); 9 | 10 | export default router; 11 | 12 | export * from '@xpress/router'; 13 | -------------------------------------------------------------------------------- /apps/web-antd/src/router/routes/index.ts: -------------------------------------------------------------------------------- 1 | import type { RouteConfig } from '@xpress-core/typings'; 2 | 3 | import { mergeRouteModules } from '@xpress/router'; 4 | 5 | import { constantRoutes, fallBackRoutes, rootRoutes } from './core'; 6 | 7 | const dynamicRouteFiles = import.meta.glob('./modules/**/*.tsx', { 8 | eager: true, 9 | }); 10 | 11 | const dynamicRoutes: RouteConfig[] = mergeRouteModules(dynamicRouteFiles); 12 | const staticRoutes = rootRoutes.map((item) => { 13 | if (item.isRoot) { 14 | return { 15 | ...item, 16 | children: [...dynamicRoutes], 17 | }; 18 | } 19 | return item; 20 | }); 21 | const routes = [...staticRoutes, ...constantRoutes, ...fallBackRoutes]; 22 | const basicRoutes = [...constantRoutes, ...fallBackRoutes]; 23 | export { basicRoutes, constantRoutes, routes }; 24 | -------------------------------------------------------------------------------- /apps/web-antd/src/router/routes/modules/home.tsx: -------------------------------------------------------------------------------- 1 | import type { RouteConfig } from '@xpress-core/typings'; 2 | 3 | const routes: RouteConfig[] = [ 4 | { 5 | path: 'home', 6 | meta: { 7 | title: '概览', 8 | badgeType: 'dot', 9 | icon: 'lucide:layout-dashboard', 10 | }, 11 | defaultPath: 'analysis', 12 | children: [ 13 | { 14 | path: 'analysis', 15 | component: () => import('#/pages/dashboard/analysis'), 16 | meta: { 17 | // menuVisibleWithForbidden: true, 18 | title: '分析页', 19 | // permission: ['homeIndex'], 20 | affixTab: true, 21 | icon: 'lucide:area-chart', 22 | // affixTabOrder: 2, 23 | }, 24 | }, 25 | { 26 | path: 'workbench', 27 | component: () => import('#/pages/dashboard/workbench'), 28 | meta: { 29 | title: '工作台', 30 | icon: 'carbon:workspace', 31 | // keepAlive: true, 32 | // affixTab: true, 33 | }, 34 | }, 35 | ], 36 | }, 37 | ]; 38 | 39 | export default routes; 40 | -------------------------------------------------------------------------------- /apps/web-antd/src/router/routes/modules/settings.tsx: -------------------------------------------------------------------------------- 1 | import type { RouteConfig } from '@xpress-core/typings'; 2 | 3 | const routes: RouteConfig[] = [ 4 | { 5 | path: 'settings', 6 | meta: { 7 | title: '设置', 8 | icon: 'mdi:cog-outline', 9 | }, 10 | component: () => import('#/pages/settings'), 11 | }, 12 | ]; 13 | export default routes; 14 | -------------------------------------------------------------------------------- /apps/web-antd/src/router/routes/modules/system.tsx: -------------------------------------------------------------------------------- 1 | import type { RouteConfig } from '@xpress-core/typings'; 2 | 3 | const routes: RouteConfig[] = [ 4 | { 5 | path: 'system', 6 | meta: { 7 | title: '系统管理', 8 | icon: 'mdi:cog-outline', 9 | order: 9999, 10 | }, 11 | defaultPath: 'user', 12 | children: [ 13 | { 14 | path: 'user', 15 | component: () => import('#/pages/system/user'), 16 | meta: { 17 | title: '用户管理', 18 | icon: 'mdi:account-outline', 19 | order: 10_000, 20 | }, 21 | }, 22 | { 23 | path: 'role', 24 | component: () => import('#/pages/system/role'), 25 | meta: { 26 | title: '角色管理', 27 | icon: 'mdi:shield-account-outline', 28 | order: 10_001, 29 | }, 30 | }, 31 | { 32 | path: 'menu', 33 | component: () => import('#/pages/system/menu'), 34 | meta: { 35 | title: '菜单管理', 36 | icon: 'mdi:menu', 37 | }, 38 | }, 39 | ], 40 | }, 41 | ]; 42 | 43 | export default routes; 44 | -------------------------------------------------------------------------------- /apps/web-antd/tailwind.config.mjs: -------------------------------------------------------------------------------- 1 | import { dirname, resolve } from 'node:path'; 2 | import { fileURLToPath } from 'node:url'; 3 | 4 | import baseConfig from '@xpress/tailwind-config'; 5 | 6 | const __dirname = dirname(fileURLToPath(import.meta.url)); 7 | 8 | /** @type {import('tailwindcss').Config} */ 9 | export default { 10 | ...baseConfig, 11 | content: [ 12 | ...baseConfig.content, 13 | resolve(__dirname, './index.html'), 14 | resolve(__dirname, './src/**/*.{js,ts,jsx,tsx}'), 15 | ], 16 | }; 17 | -------------------------------------------------------------------------------- /apps/web-antd/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/web-app.json", 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "paths": { 7 | "#/*": ["./src/*"] 8 | } 9 | }, 10 | "references": [{ "path": "./tsconfig.node.json" }], 11 | "include": ["src/**/*.ts", "src/**/*.tsx"] 12 | } 13 | -------------------------------------------------------------------------------- /apps/web-antd/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/node.json", 4 | "compilerOptions": { 5 | "composite": true, 6 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 7 | "noEmit": false 8 | }, 9 | "include": ["vite.config.mts"] 10 | } 11 | -------------------------------------------------------------------------------- /apps/web-antd/vite.config.mts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@xpress/vite-config'; 2 | 3 | export default defineConfig(async () => { 4 | return { 5 | application: {}, 6 | vite: { 7 | server: { 8 | proxy: { 9 | '/api': { 10 | changeOrigin: true, 11 | rewrite: (path: string) => path.replace(/^\/api/, ''), 12 | // mock代理目标地址 13 | target: 'http://localhost:5320/api', 14 | ws: true, 15 | }, 16 | }, 17 | }, 18 | }, 19 | }; 20 | }); 21 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | import { defineConfig } from '@xpress/eslint-config'; 4 | 5 | export default defineConfig(); 6 | -------------------------------------------------------------------------------- /internal/lint-configs/eslint-config/build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | clean: true, 5 | declaration: true, 6 | entries: ['src/index'], 7 | }); 8 | -------------------------------------------------------------------------------- /internal/lint-configs/eslint-config/src/configs/command.ts: -------------------------------------------------------------------------------- 1 | import createCommand from 'eslint-plugin-command/config'; 2 | 3 | /** 4 | * ESLint 命令相关规则配置 5 | * 用于规范和限制 ESLint 命令的使用 6 | */ 7 | export async function command() { 8 | return [ 9 | { 10 | // @ts-expect-error - no types 11 | ...createCommand(), 12 | }, 13 | ]; 14 | } 15 | -------------------------------------------------------------------------------- /internal/lint-configs/eslint-config/src/configs/comments.ts: -------------------------------------------------------------------------------- 1 | import type { Linter } from 'eslint'; 2 | 3 | import { interopDefault } from '../util'; 4 | 5 | /** 6 | * ESLint 注释相关规则配置 7 | * 用于规范和限制 ESLint 注释的使用 8 | */ 9 | export async function comments(): Promise { 10 | const [pluginComments] = await Promise.all([ 11 | // @ts-expect-error - no types 12 | interopDefault(import('eslint-plugin-eslint-comments')), 13 | ] as const); 14 | 15 | return [ 16 | { 17 | plugins: { 18 | 'eslint-comments': pluginComments, 19 | }, 20 | rules: { 21 | // 禁止使用 eslint-enable 注释来启用多个规则 22 | 'eslint-comments/no-aggregating-enable': 'error', 23 | // 禁止重复的 eslint-disable 注释 24 | 'eslint-comments/no-duplicate-disable': 'error', 25 | // 禁止使用没有具体规则的 eslint-disable 注释 26 | 'eslint-comments/no-unlimited-disable': 'error', 27 | // 禁止使用未匹配的 eslint-enable 注释 28 | 'eslint-comments/no-unused-enable': 'error', 29 | }, 30 | }, 31 | ]; 32 | } 33 | -------------------------------------------------------------------------------- /internal/lint-configs/eslint-config/src/configs/disableds.ts: -------------------------------------------------------------------------------- 1 | import type { Linter } from 'eslint'; 2 | 3 | /** 4 | * ESLint 规则禁用配置 5 | * 针对特定文件类型禁用某些规则 6 | */ 7 | export async function disableds(): Promise { 8 | return [ 9 | { 10 | // 测试文件的规则配置 11 | files: ['**/__tests__/**/*.?([cm])[jt]s?(x)'], 12 | name: 'disables/test', 13 | rules: { 14 | // 允许在测试文件中使用 @ts-comment 15 | '@typescript-eslint/ban-ts-comment': 'off', 16 | // 允许在测试文件中使用 console 17 | 'no-console': 'off', 18 | }, 19 | }, 20 | { 21 | // 类型声明文件(.d.ts)的规则配置 22 | files: ['**/*.d.ts'], 23 | name: 'disables/dts', 24 | rules: { 25 | // 允许使用三斜线引用指令 26 | '@typescript-eslint/triple-slash-reference': 'off', 27 | }, 28 | }, 29 | { 30 | // JavaScript 文件的规则配置 31 | files: ['**/*.js', '**/*.mjs', '**/*.cjs'], 32 | name: 'disables/js', 33 | rules: { 34 | // 关闭导出函数必须指定返回类型的检查 35 | '@typescript-eslint/explicit-module-boundary-types': 'off', 36 | }, 37 | }, 38 | ]; 39 | } 40 | -------------------------------------------------------------------------------- /internal/lint-configs/eslint-config/src/configs/index.ts: -------------------------------------------------------------------------------- 1 | export * from './command'; 2 | export * from './comments'; 3 | export * from './disableds'; 4 | export * from './ignores'; 5 | export * from './import'; 6 | export * from './javascript'; 7 | export * from './jsdoc'; 8 | export * from './jsonc'; 9 | export * from './node'; 10 | export * from './perfectionist'; 11 | export * from './prettier'; 12 | export * from './react'; 13 | export * from './regexp'; 14 | export * from './test'; 15 | export * from './turbo'; 16 | export * from './typescript'; 17 | export * from './unicorn'; 18 | -------------------------------------------------------------------------------- /internal/lint-configs/eslint-config/src/configs/prettier.ts: -------------------------------------------------------------------------------- 1 | import type { Linter } from 'eslint'; 2 | 3 | import { interopDefault } from '../util'; 4 | 5 | export async function prettier(): Promise { 6 | const [pluginPrettier] = await Promise.all([ 7 | interopDefault(import('eslint-plugin-prettier')), 8 | ] as const); 9 | return [ 10 | { 11 | plugins: { 12 | prettier: pluginPrettier, 13 | }, 14 | rules: { 15 | 'prettier/prettier': 'error', 16 | }, 17 | }, 18 | ]; 19 | } 20 | -------------------------------------------------------------------------------- /internal/lint-configs/eslint-config/src/configs/regexp.ts: -------------------------------------------------------------------------------- 1 | import type { Linter } from 'eslint'; 2 | 3 | import { interopDefault } from '../util'; 4 | 5 | export async function regexp(): Promise { 6 | const [pluginRegexp] = await Promise.all([ 7 | interopDefault(import('eslint-plugin-regexp')), 8 | ] as const); 9 | 10 | return [ 11 | { 12 | plugins: { 13 | regexp: pluginRegexp, 14 | }, 15 | rules: { 16 | ...pluginRegexp.configs.recommended.rules, 17 | }, 18 | }, 19 | ]; 20 | } 21 | -------------------------------------------------------------------------------- /internal/lint-configs/eslint-config/src/configs/turbo.ts: -------------------------------------------------------------------------------- 1 | import type { Linter } from 'eslint'; 2 | 3 | import { interopDefault } from '../util'; 4 | 5 | export async function turbo(): Promise { 6 | const [pluginTurbo] = await Promise.all([ 7 | // @ts-expect-error - no types 8 | interopDefault(import('eslint-config-turbo')), 9 | ] as const); 10 | 11 | return [ 12 | { 13 | plugins: { 14 | turbo: pluginTurbo, 15 | }, 16 | }, 17 | ]; 18 | } 19 | -------------------------------------------------------------------------------- /internal/lint-configs/eslint-config/src/typings/pkg.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'eslint-plugin-react' { 2 | type ReactConfigKey = 'all' | 'jsx-runtime' | 'recommended'; 3 | 4 | const plugin: { 5 | configs: Record; 6 | } & import('eslint').ESLint.Plugin; 7 | 8 | export default plugin; 9 | } 10 | declare module 'eslint-plugin-react-hooks' { 11 | const plugin: import('eslint').ESLint.Plugin; 12 | 13 | export default plugin; 14 | } 15 | declare module 'eslint-plugin-react-refresh' { 16 | const plugin: import('eslint').ESLint.Plugin; 17 | 18 | export default plugin; 19 | } 20 | -------------------------------------------------------------------------------- /internal/lint-configs/eslint-config/src/util.ts: -------------------------------------------------------------------------------- 1 | export type Awaitable = Promise | T; 2 | 3 | export async function interopDefault( 4 | m: Awaitable, 5 | ): Promise { 6 | const resolved = await m; 7 | return (resolved as any).default || resolved; 8 | } 9 | -------------------------------------------------------------------------------- /internal/lint-configs/eslint-config/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/node.json", 4 | "include": ["src"], 5 | "exclude": ["node_modules"] 6 | } 7 | -------------------------------------------------------------------------------- /internal/lint-configs/prettier-config/index.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | arrowParens: 'always', 3 | bracketSameLine: false, 4 | endOfLine: 'auto', 5 | jsxSingleQuote: false, 6 | overrides: [ 7 | { 8 | files: ['*.json5'], 9 | options: { 10 | quoteProps: 'preserve', 11 | singleQuote: false, 12 | }, 13 | }, 14 | ], 15 | plugins: ['prettier-plugin-tailwindcss'], 16 | printWidth: 80, 17 | proseWrap: 'never', 18 | semi: true, 19 | singleQuote: true, 20 | trailingComma: 'all', 21 | }; 22 | -------------------------------------------------------------------------------- /internal/lint-configs/prettier-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@xpress/prettier-config", 3 | "version": "1.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "type": "module", 7 | "files": [ 8 | "dist" 9 | ], 10 | "main": "./index.mjs", 11 | "module": "./index.mjs", 12 | "exports": { 13 | ".": { 14 | "default": "./index.mjs" 15 | } 16 | }, 17 | "dependencies": { 18 | "prettier": "catalog:", 19 | "prettier-plugin-tailwindcss": "catalog:" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /internal/lint-configs/stylelint-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@xpress/stylelint-config", 3 | "version": "1.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "type": "module", 7 | "files": [ 8 | "dist" 9 | ], 10 | "main": "./index.mjs", 11 | "module": "./index.mjs", 12 | "exports": { 13 | ".": { 14 | "import": "./index.mjs", 15 | "default": "./index.mjs" 16 | } 17 | }, 18 | "dependencies": { 19 | "@stylistic/stylelint-plugin": "catalog:", 20 | "stylelint-config-recess-order": "catalog:", 21 | "stylelint-scss": "catalog:" 22 | }, 23 | "devDependencies": { 24 | "postcss": "catalog:", 25 | "postcss-scss": "catalog:", 26 | "postcss-styled-syntax": "catalog:", 27 | "prettier": "catalog:", 28 | "stylelint": "catalog:", 29 | "stylelint-config-css-modules": "catalog:", 30 | "stylelint-config-recommended": "catalog:", 31 | "stylelint-config-recommended-scss": "catalog:", 32 | "stylelint-config-standard": "catalog:", 33 | "stylelint-order": "catalog:", 34 | "stylelint-prettier": "catalog:" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /internal/node-utils/build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | clean: true, 5 | declaration: true, 6 | entries: ['src/index'], 7 | }); 8 | -------------------------------------------------------------------------------- /internal/node-utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@xpress/node-utils", 3 | "version": "1.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "type": "module", 7 | "scripts": { 8 | "stub": "pnpm unbuild --stub" 9 | }, 10 | "files": [ 11 | "dist" 12 | ], 13 | "main": "./dist/index.mjs", 14 | "module": "./dist/index.mjs", 15 | "types": "./dist/index.d.ts", 16 | "exports": { 17 | ".": { 18 | "types": "./src/index.ts", 19 | "import": "./dist/index.mjs", 20 | "default": "./dist/index.mjs" 21 | } 22 | }, 23 | "dependencies": { 24 | "@changesets/git": "catalog:", 25 | "@manypkg/get-packages": "catalog:", 26 | "cac": "catalog:", 27 | "chalk": "catalog:", 28 | "circular-dependency-scanner": "catalog:", 29 | "consola": "catalog:", 30 | "dayjs": "catalog:", 31 | "depcheck": "catalog:", 32 | "execa": "catalog:", 33 | "find-up": "catalog:", 34 | "ora": "catalog:", 35 | "pkg-types": "catalog:", 36 | "prettier": "catalog:", 37 | "publint": "catalog:", 38 | "rimraf": "catalog:" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /internal/node-utils/src/constants.ts: -------------------------------------------------------------------------------- 1 | enum UNICODE { 2 | FAILURE = '\u2716', // ✖ 3 | SUCCESS = '\u2714', // ✔ 4 | } 5 | 6 | export { UNICODE }; 7 | -------------------------------------------------------------------------------- /internal/node-utils/src/date.ts: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs'; 2 | import timezone from 'dayjs/plugin/timezone'; 3 | import utc from 'dayjs/plugin/utc'; 4 | 5 | dayjs.extend(utc); 6 | dayjs.extend(timezone); 7 | 8 | dayjs.tz.setDefault('Asia/Shanghai'); 9 | 10 | const dateUtil = dayjs; 11 | 12 | export { dateUtil }; 13 | -------------------------------------------------------------------------------- /internal/node-utils/src/git.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | 3 | import { execa } from 'execa'; 4 | 5 | export * from '@changesets/git'; 6 | 7 | /** 8 | * 获取暂存区文件 9 | */ 10 | async function getStagedFiles(): Promise { 11 | try { 12 | const { stdout } = await execa('git', [ 13 | '-c', 14 | 'submodule.recurse=false', 15 | 'diff', 16 | '--staged', 17 | '--diff-filter=ACMR', 18 | '--name-only', 19 | '--ignore-submodules', 20 | '-z', 21 | ]); 22 | 23 | let changedList = stdout ? stdout.replace(/\0$/, '').split('\0') : []; 24 | changedList = changedList.map((item) => path.resolve(process.cwd(), item)); 25 | const changedSet = new Set(changedList); 26 | changedSet.delete(''); 27 | return [...changedSet]; 28 | } catch (error) { 29 | console.error('Failed to get staged files:', error); 30 | return []; 31 | } 32 | } 33 | 34 | export { getStagedFiles }; 35 | -------------------------------------------------------------------------------- /internal/node-utils/src/hash.ts: -------------------------------------------------------------------------------- 1 | import { createHash } from 'node:crypto'; 2 | 3 | /** 4 | * 生产基于内容的 hash,可自定义长度 5 | * @param content 6 | * @param hashLSize 7 | */ 8 | function generatorContentHash(content: string, hashLSize?: number) { 9 | const hash = createHash('md5').update(content, 'utf8').digest('hex'); 10 | 11 | if (hashLSize) { 12 | return hash.slice(0, hashLSize); 13 | } 14 | 15 | return hash; 16 | } 17 | 18 | export { generatorContentHash }; 19 | -------------------------------------------------------------------------------- /internal/node-utils/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './constants'; 2 | export * from './date'; 3 | export * from './fs'; 4 | export * from './git'; 5 | export { add as gitAdd, getStagedFiles } from './git'; 6 | export { generatorContentHash } from './hash'; 7 | export * from './monorepo'; 8 | export { toPosixPath } from './path'; 9 | export { prettierFormat } from './prettier'; 10 | export * from './spinner'; 11 | export type { Package } from '@manypkg/get-packages'; 12 | export { default as colors } from 'chalk'; 13 | export { consola } from 'consola'; 14 | 15 | export * from 'execa'; 16 | 17 | export { default as fs } from 'node:fs/promises'; 18 | export { type PackageJson, readPackageJSON } from 'pkg-types'; 19 | export { rimraf } from 'rimraf'; 20 | -------------------------------------------------------------------------------- /internal/node-utils/src/path.ts: -------------------------------------------------------------------------------- 1 | import { posix } from 'node:path'; 2 | 3 | /** 4 | * 将给定的文件路径转换为 POSIX 风格。 5 | * @param {string} pathname - 原始文件路径。 6 | */ 7 | function toPosixPath(pathname: string) { 8 | return pathname.split(`\\`).join(posix.sep); 9 | } 10 | 11 | export { toPosixPath }; 12 | -------------------------------------------------------------------------------- /internal/node-utils/src/prettier.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs/promises'; 2 | 3 | import { format, getFileInfo, resolveConfig } from 'prettier'; 4 | 5 | async function prettierFormat(filepath: string) { 6 | const prettierOptions = await resolveConfig(filepath, {}); 7 | 8 | const fileInfo = await getFileInfo(filepath); 9 | 10 | const input = await fs.readFile(filepath, 'utf8'); 11 | const output = await format(input, { 12 | ...prettierOptions, 13 | parser: fileInfo.inferredParser as any, 14 | }); 15 | if (output !== input) { 16 | await fs.writeFile(filepath, output, 'utf8'); 17 | } 18 | return output; 19 | } 20 | 21 | export { prettierFormat }; 22 | -------------------------------------------------------------------------------- /internal/node-utils/src/spinner.ts: -------------------------------------------------------------------------------- 1 | import ora, { type Ora } from 'ora'; 2 | 3 | interface SpinnerOptions { 4 | failedText?: string; 5 | successText?: string; 6 | title: string; 7 | } 8 | export async function spinner( 9 | { failedText, successText, title }: SpinnerOptions, 10 | callback: () => Promise, 11 | ): Promise { 12 | const loading: Ora = ora(title).start(); 13 | 14 | try { 15 | const result = await callback(); 16 | loading.succeed(successText || 'Success!'); 17 | return result; 18 | } catch (error) { 19 | loading.fail(failedText || 'Failed!'); 20 | throw error; 21 | } finally { 22 | loading.stop(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /internal/node-utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/node.json", 4 | "include": ["src"], 5 | "exclude": ["node_modules"] 6 | } 7 | -------------------------------------------------------------------------------- /internal/tailwind-config/build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | clean: true, 5 | declaration: true, 6 | entries: ['src/index', './src/postcss.config'], 7 | rollup: { 8 | emitCJS: true, 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /internal/tailwind-config/src/module.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@tailwindcss/nesting' { 2 | export default any; 3 | } 4 | -------------------------------------------------------------------------------- /internal/tailwind-config/src/postcss.config.ts: -------------------------------------------------------------------------------- 1 | import config from '.'; 2 | 3 | export default { 4 | plugins: { 5 | ...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {}), 6 | // Specifying the config is not necessary in most cases, but it is included 7 | autoprefixer: {}, 8 | 'postcss-import': {}, 9 | 'postcss-preset-env': {}, 10 | tailwindcss: { config }, 11 | 'tailwindcss/nesting': {}, 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /internal/tailwind-config/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/node.json", 4 | "include": ["src"], 5 | "exclude": ["node_modules"] 6 | } 7 | -------------------------------------------------------------------------------- /internal/tsconfig/library.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Web Application", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "jsx": "preserve", 7 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 8 | "useDefineForClassFields": true, 9 | "moduleResolution": "bundler", 10 | "declaration": true, 11 | "noEmit": false 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /internal/tsconfig/node.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Node Config", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "composite": false, 7 | "lib": ["ESNext"], 8 | "baseUrl": "./", 9 | "types": ["node"], 10 | "noImplicitAny": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /internal/tsconfig/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@xpress/tsconfig", 3 | "version": "1.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "type": "module", 7 | "files": [ 8 | "base.json", 9 | "library.json", 10 | "node.json", 11 | "web-app.json", 12 | "web.json" 13 | ], 14 | "dependencies": { 15 | "vite": "catalog:" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /internal/tsconfig/web-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Web Application", 4 | "extends": "./web.json", 5 | "compilerOptions": { 6 | "types": ["vite/client"] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /internal/tsconfig/web.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Web Package", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "jsx": "react-jsx", 7 | "jsxImportSource": "react", 8 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 9 | "useDefineForClassFields": true, 10 | "moduleResolution": "bundler", 11 | "types": ["vite/client"], 12 | "allowJs": true, 13 | "declaration": false, 14 | "esModuleInterop": true, 15 | "isolatedModules": true 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /internal/vite-config/build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | clean: true, 5 | declaration: true, 6 | entries: ['src/index'], 7 | }); 8 | -------------------------------------------------------------------------------- /internal/vite-config/src/config/common.ts: -------------------------------------------------------------------------------- 1 | import type { UserConfig } from 'vite'; 2 | 3 | async function getCommonConfig(): Promise { 4 | return { 5 | build: { 6 | chunkSizeWarningLimit: 2000, 7 | reportCompressedSize: false, 8 | sourcemap: false, 9 | }, 10 | }; 11 | } 12 | 13 | export { getCommonConfig }; 14 | -------------------------------------------------------------------------------- /internal/vite-config/src/config/index.ts: -------------------------------------------------------------------------------- 1 | import type { DefineConfig } from '../typing'; 2 | 3 | import { existsSync } from 'node:fs'; 4 | import { join } from 'node:path'; 5 | 6 | import { defineApplicationConfig } from './application'; 7 | import { defineLibraryConfig } from './library'; 8 | 9 | export * from './application'; 10 | export * from './library'; 11 | 12 | function defineConfig( 13 | userConfigPromise?: DefineConfig, 14 | type: 'application' | 'auto' | 'library' = 'auto', 15 | ) { 16 | let projectType = type; 17 | 18 | // 根据包是否存在 index.html,自动判断类型 19 | if (projectType === 'auto') { 20 | const htmlPath = join(process.cwd(), 'index.html'); 21 | projectType = existsSync(htmlPath) ? 'application' : 'library'; 22 | } 23 | 24 | switch (projectType) { 25 | case 'application': { 26 | return defineApplicationConfig(userConfigPromise); 27 | } 28 | case 'library': { 29 | return defineLibraryConfig(userConfigPromise); 30 | } 31 | default: { 32 | throw new Error(`Unsupported project type: ${projectType}`); 33 | } 34 | } 35 | } 36 | 37 | export { defineConfig }; 38 | -------------------------------------------------------------------------------- /internal/vite-config/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './config'; 2 | export * from './options'; 3 | export * from './plugins'; 4 | export { loadAndConvertEnv } from './utils/env'; 5 | -------------------------------------------------------------------------------- /internal/vite-config/src/options.ts: -------------------------------------------------------------------------------- 1 | import type { Options as PwaPluginOptions } from 'vite-plugin-pwa'; 2 | 3 | // const isDevelopment = process.env.NODE_ENV === 'development'; 4 | 5 | const getDefaultPwaOptions = (_name: string): Partial => ({ 6 | manifest: {}, 7 | }); 8 | 9 | // /** 10 | // * importmap CDN 暂时不开启,因为有些包不支持,且网络不稳定 11 | // */ 12 | // const defaultImportmapOptions: ImportmapPluginOptions = { 13 | // // 通过 Importmap CDN 方式引入, 14 | // // 目前只有esm.sh源兼容性好一点,jspm.io对于 esm 入口要求高 15 | // defaultProvider: 'esm.sh', 16 | // importmap: [{ name: 'react' }, { name: 'react-dom' }, { name: 'dayjs' }], 17 | // }; 18 | 19 | export { getDefaultPwaOptions }; 20 | -------------------------------------------------------------------------------- /internal/vite-config/src/plugins/inject-app-loading/README.md: -------------------------------------------------------------------------------- 1 | # inject-app-loading 2 | 3 | 用于在应用加载时显示加载动画的插件,可自行选择加载动画的样式。 4 | -------------------------------------------------------------------------------- /internal/vite-config/src/plugins/print.ts: -------------------------------------------------------------------------------- 1 | import type { PluginOption } from 'vite'; 2 | 3 | import { colors } from '@xpress/node-utils'; 4 | 5 | export const vitePrintPlugin = ( 6 | infoMap: Record = {}, 7 | ): PluginOption => { 8 | return { 9 | configureServer(server) { 10 | const _printUrls = server.printUrls; 11 | server.printUrls = () => { 12 | _printUrls(); 13 | for (const [key, value] of Object.entries(infoMap)) { 14 | console.log( 15 | ` ${colors.green('➜')} ${colors.bold(key)}: ${colors.cyan(value)}`, 16 | ); 17 | } 18 | }; 19 | }, 20 | enforce: 'pre', 21 | name: 'vite:print-info', 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /internal/vite-config/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/node.json", 4 | "include": ["src"], 5 | "exclude": ["node_modules"] 6 | } 7 | -------------------------------------------------------------------------------- /packages/@core/base/README.md: -------------------------------------------------------------------------------- 1 | # base 2 | 3 | 基础共享包,请勿引入 workspace 依赖 4 | 5 | - 6 | -------------------------------------------------------------------------------- /packages/@core/base/design/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@xpress-core/design", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "type": "module", 6 | "scripts": { 7 | "build": "pnpm vite build", 8 | "prepublishOnly": "npm run build" 9 | }, 10 | "files": [ 11 | "dist", 12 | "src" 13 | ], 14 | "main": "./dist/index.mjs", 15 | "module": "./dist/index.mjs", 16 | "exports": { 17 | "./bem": { 18 | "development": "./src/scss-bem/bem.scss", 19 | "default": "./dist/bem.scss" 20 | }, 21 | ".": { 22 | "types": "./src/index.ts", 23 | "development": "./src/index.ts", 24 | "default": "./dist/design.css" 25 | } 26 | }, 27 | "publishConfig": { 28 | "exports": { 29 | ".": { 30 | "default": "./dist/index.mjs" 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/@core/base/design/src/design-tokens/index.ts: -------------------------------------------------------------------------------- 1 | import './default.css'; 2 | import './dark.css'; 3 | import './toast.css'; 4 | 5 | export {}; 6 | -------------------------------------------------------------------------------- /packages/@core/base/design/src/index.ts: -------------------------------------------------------------------------------- 1 | import './design-tokens'; 2 | 3 | import './scss/bell.scss'; 4 | import './scss/menu.scss'; 5 | import './scss/normal-menu.scss'; 6 | import './css/global.css'; 7 | import './css/transition.css'; 8 | import './css/ui.css'; 9 | 10 | export {}; 11 | -------------------------------------------------------------------------------- /packages/@core/base/design/src/scss-bem/bem.scss: -------------------------------------------------------------------------------- 1 | @forward './constants'; 2 | 3 | @mixin b($block) { 4 | $B: $namespace + '-' + $block !global; 5 | 6 | .#{$B} { 7 | @content; 8 | } 9 | } 10 | 11 | @mixin e($name) { 12 | @at-root { 13 | &#{$element-separator}#{$name} { 14 | @content; 15 | } 16 | } 17 | } 18 | 19 | @mixin m($name) { 20 | @at-root { 21 | &#{$modifier-separator}#{$name} { 22 | @content; 23 | } 24 | } 25 | } 26 | 27 | // block__element.is-active {} 28 | @mixin is($state, $prefix: $state-prefix) { 29 | @at-root { 30 | &.#{$prefix}-#{$state} { 31 | @content; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/@core/base/design/src/scss-bem/constants.scss: -------------------------------------------------------------------------------- 1 | $namespace: 'xpress' !default; 2 | $common-separator: '-' !default; 3 | $element-separator: '__' !default; 4 | $modifier-separator: '--' !default; 5 | $state-prefix: 'is' !default; 6 | -------------------------------------------------------------------------------- /packages/@core/base/design/src/scss/bell.scss: -------------------------------------------------------------------------------- 1 | $namespace: xpress; 2 | .#{$namespace}-bell-button { 3 | &:hover { 4 | svg { 5 | animation: bell-ring 1s both; 6 | } 7 | } 8 | } 9 | 10 | @keyframes bell-ring { 11 | 0%, 12 | 100% { 13 | transform-origin: top; 14 | } 15 | 16 | 15% { 17 | transform: rotateZ(10deg); 18 | } 19 | 20 | 30% { 21 | transform: rotateZ(-10deg); 22 | } 23 | 24 | 45% { 25 | transform: rotateZ(5deg); 26 | } 27 | 28 | 60% { 29 | transform: rotateZ(-5deg); 30 | } 31 | 32 | 75% { 33 | transform: rotateZ(2deg); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/@core/base/design/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/web.json", 4 | "include": ["src"], 5 | "exclude": ["node_modules"] 6 | } 7 | -------------------------------------------------------------------------------- /packages/@core/base/design/vite.config.mts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@xpress/vite-config'; 2 | 3 | export default defineConfig(async () => { 4 | return { 5 | vite: { 6 | publicDir: 'src/scss-bem', 7 | }, 8 | }; 9 | }); 10 | -------------------------------------------------------------------------------- /packages/@core/base/icons/build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | clean: true, 5 | declaration: true, 6 | entries: ['src/index'], 7 | // externals: ['react', 'react-dom', 'react/jsx-runtime'], 8 | failOnWarn: false, 9 | rollup: { 10 | emitCJS: true, 11 | esbuild: { 12 | jsx: 'automatic', 13 | jsxImportSource: 'react', 14 | minify: true, 15 | treeShaking: true, 16 | tsconfigRaw: { 17 | compilerOptions: { 18 | jsx: 'react-jsx', 19 | }, 20 | }, 21 | }, 22 | inlineDependencies: true, 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /packages/@core/base/icons/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@xpress-core/icons", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "type": "module", 6 | "scripts": { 7 | "build": "pnpm unbuild" 8 | }, 9 | "files": [ 10 | "dist" 11 | ], 12 | "main": "./dist/index.mjs", 13 | "module": "./dist/index.mjs", 14 | "exports": { 15 | ".": { 16 | "types": "./src/index.ts", 17 | "development": "./src/index.ts", 18 | "default": "./dist/index.mjs" 19 | } 20 | }, 21 | "publishConfig": { 22 | "exports": { 23 | ".": { 24 | "types": "./dist/index.d.ts", 25 | "default": "./dist/index.mjs" 26 | } 27 | } 28 | }, 29 | "dependencies": { 30 | "@iconify/react": "catalog:", 31 | "lucide-react": "catalog:", 32 | "react": "catalog:" 33 | }, 34 | "devDependencies": { 35 | "@types/react": "catalog:" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/@core/base/icons/src/create-icon.tsx: -------------------------------------------------------------------------------- 1 | import type { IconProps } from '@iconify/react'; 2 | import type { ForwardRefRenderFunction } from 'react'; 3 | 4 | import { Icon } from '@iconify/react'; 5 | import { forwardRef } from 'react'; 6 | 7 | type IconComponentProps = Omit; 8 | type IconComponentRef = SVGSVGElement; 9 | 10 | function createIconifyIcon(icon: string) { 11 | const IconComponent: ForwardRefRenderFunction< 12 | IconComponentRef, 13 | IconComponentProps 14 | > = (props, ref) => { 15 | return ; 16 | }; 17 | 18 | return forwardRef(IconComponent); 19 | } 20 | 21 | export type { IconComponentProps }; 22 | export { createIconifyIcon }; 23 | -------------------------------------------------------------------------------- /packages/@core/base/icons/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-icon'; 2 | 3 | export * from './lucide'; 4 | export type { 5 | IconifyIcon as IconifyIconStructure, 6 | IconifyIconProps, 7 | } from '@iconify/react'; 8 | export { 9 | addCollection, 10 | addIcon, 11 | Icon as IconifyIcon, 12 | listIcons, 13 | } from '@iconify/react'; 14 | -------------------------------------------------------------------------------- /packages/@core/base/icons/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/web.json", 4 | "include": ["src"], 5 | "exclude": ["node_modules"] 6 | } 7 | -------------------------------------------------------------------------------- /packages/@core/base/shared/build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | clean: true, 5 | declaration: true, 6 | entries: [ 7 | 'src/constants/index', 8 | 'src/utils/index', 9 | 'src/color/index', 10 | 'src/cache/index', 11 | 'src/global-state', 12 | ], 13 | }); 14 | -------------------------------------------------------------------------------- /packages/@core/base/shared/src/cache/index.ts: -------------------------------------------------------------------------------- 1 | export * from './storage-manager'; 2 | -------------------------------------------------------------------------------- /packages/@core/base/shared/src/cache/types.ts: -------------------------------------------------------------------------------- 1 | type StorageType = 'localStorage' | 'sessionStorage'; 2 | 3 | interface StorageValue { 4 | data: T; 5 | expiry: null | number; 6 | } 7 | 8 | interface IStorageCache { 9 | clear(): void; 10 | getItem(key: string): null | T; 11 | key(index: number): null | string; 12 | length(): number; 13 | removeItem(key: string): void; 14 | setItem(key: string, value: T, expiryInMinutes?: number): void; 15 | } 16 | 17 | export type { IStorageCache, StorageType, StorageValue }; 18 | -------------------------------------------------------------------------------- /packages/@core/base/shared/src/color/color.ts: -------------------------------------------------------------------------------- 1 | import { TinyColor } from '@ctrl/tinycolor'; 2 | 3 | export function isDarkColor(color: string) { 4 | return new TinyColor(color).isDark(); 5 | } 6 | 7 | export function isLightColor(color: string) { 8 | return new TinyColor(color).isLight(); 9 | } 10 | -------------------------------------------------------------------------------- /packages/@core/base/shared/src/color/index.ts: -------------------------------------------------------------------------------- 1 | export * from './color'; 2 | export * from './convert'; 3 | export * from './generator'; 4 | -------------------------------------------------------------------------------- /packages/@core/base/shared/src/constants/globals.ts: -------------------------------------------------------------------------------- 1 | /** layout content 组件的高度 */ 2 | export const CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT = `--xpress-content-height`; 3 | /** layout content 组件的宽度 */ 4 | export const CSS_VARIABLE_LAYOUT_CONTENT_WIDTH = `--xpress-content-width`; 5 | /** layout header 组件的高度 */ 6 | export const CSS_VARIABLE_LAYOUT_HEADER_HEIGHT = `--xpress-header-height`; 7 | /** layout footer 组件的高度 */ 8 | export const CSS_VARIABLE_LAYOUT_FOOTER_HEIGHT = `--xpress-footer-height`; 9 | 10 | /** 内容区域的组件ID */ 11 | export const ELEMENT_ID_MAIN_CONTENT = `__xpress_main_content`; 12 | 13 | /** 14 | * @zh_CN 默认命名空间 15 | */ 16 | export const DEFAULT_NAMESPACE = 'xpress'; 17 | -------------------------------------------------------------------------------- /packages/@core/base/shared/src/constants/index.ts: -------------------------------------------------------------------------------- 1 | export * from './globals'; 2 | -------------------------------------------------------------------------------- /packages/@core/base/shared/src/global-state.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 全局复用的变量、组件、配置,各个模块之间共享 3 | * 通过单例模式实现,单例必须注意不受请求影响,例如用户信息这些需要根据请求获取的。后续如果有ssr需求,也不会影响 4 | */ 5 | 6 | interface ComponentsState { 7 | [key: string]: any; 8 | } 9 | 10 | interface MessageState { 11 | copyPreferencesSuccess?: (title: string, content?: string) => void; 12 | } 13 | 14 | export interface IGlobalSharedState { 15 | components: ComponentsState; 16 | message: MessageState; 17 | } 18 | 19 | class GlobalShareState { 20 | #components: ComponentsState = {}; 21 | #message: MessageState = {}; 22 | 23 | /** 24 | * 定义框架内部各个场景的消息提示 25 | */ 26 | public defineMessage({ copyPreferencesSuccess }: MessageState) { 27 | this.#message = { 28 | copyPreferencesSuccess, 29 | }; 30 | } 31 | 32 | public getComponents(): ComponentsState { 33 | return this.#components; 34 | } 35 | 36 | public getMessage(): MessageState { 37 | return this.#message; 38 | } 39 | 40 | public setComponents(value: ComponentsState) { 41 | this.#components = value; 42 | } 43 | } 44 | 45 | export const globalShareState = new GlobalShareState(); 46 | -------------------------------------------------------------------------------- /packages/@core/base/shared/src/utils/__tests__/window.test.ts: -------------------------------------------------------------------------------- 1 | import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; 2 | 3 | import { openWindow } from '../window'; 4 | 5 | describe('openWindow', () => { 6 | // 保存原始的 window.open 函数 7 | let originalOpen: typeof window.open; 8 | 9 | beforeEach(() => { 10 | originalOpen = window.open; 11 | }); 12 | 13 | afterEach(() => { 14 | window.open = originalOpen; 15 | }); 16 | 17 | it('should call window.open with correct arguments', () => { 18 | const url = 'https://example.com'; 19 | const options = { noopener: true, noreferrer: true, target: '_blank' }; 20 | 21 | window.open = vi.fn(); 22 | 23 | // 调用函数 24 | openWindow(url, options); 25 | 26 | // 验证 window.open 是否被正确地调用 27 | expect(window.open).toHaveBeenCalledWith( 28 | url, 29 | options.target, 30 | 'noopener=yes,noreferrer=yes', 31 | ); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /packages/@core/base/shared/src/utils/cn.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from 'clsx'; 2 | import { twMerge } from 'tailwind-merge'; 3 | 4 | function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | 8 | export { cn }; 9 | -------------------------------------------------------------------------------- /packages/@core/base/shared/src/utils/date.ts: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs'; 2 | 3 | export function formatDate(time: number | string, format = 'YYYY-MM-DD') { 4 | try { 5 | const date = dayjs(time); 6 | if (!date.isValid()) { 7 | throw new Error('Invalid date'); 8 | } 9 | return date.format(format); 10 | } catch (error) { 11 | console.error(`Error formatting date: ${error}`); 12 | return time; 13 | } 14 | } 15 | 16 | export function formatDateTime(time: number | string) { 17 | return formatDate(time, 'YYYY-MM-DD HH:mm:ss'); 18 | } 19 | -------------------------------------------------------------------------------- /packages/@core/base/shared/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './clamp'; 2 | export * from './cn'; 3 | export * from './date'; 4 | export * from './diff'; 5 | export * from './dom'; 6 | export * from './download'; 7 | export * from './inference'; 8 | export * from './letter'; 9 | export * from './merge'; 10 | export * from './number'; 11 | export * from './state-handler'; 12 | export * from './to'; 13 | export * from './tree'; 14 | export * from './unique'; 15 | export * from './update-css-variables'; 16 | export * from './util'; 17 | export * from './window'; 18 | export { default as cloneDeep } from 'lodash.clonedeep'; 19 | export { default as get } from 'lodash.get'; 20 | export { default as uniqueId } from 'lodash.uniqueid'; 21 | -------------------------------------------------------------------------------- /packages/@core/base/shared/src/utils/merge.ts: -------------------------------------------------------------------------------- 1 | import { createDefu } from 'defu'; 2 | 3 | export { createDefu as createMerge, defu as merge } from 'defu'; 4 | 5 | export const mergeWithArrayOverride = createDefu((originObj, key, updates) => { 6 | if (Array.isArray(originObj[key]) && Array.isArray(updates)) { 7 | originObj[key] = updates; 8 | return true; 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /packages/@core/base/shared/src/utils/to.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param { Readonly } promise 3 | * @param {object=} errorExt - Additional Information you can pass to the err object 4 | * @return { Promise } 5 | */ 6 | export async function to( 7 | promise: Readonly>, 8 | errorExt?: object, 9 | ): Promise<[null, T] | [U, undefined]> { 10 | try { 11 | const data = await promise; 12 | const result: [null, T] = [null, data]; 13 | return result; 14 | } catch (error) { 15 | if (errorExt) { 16 | const parsedError = Object.assign({}, error, errorExt); 17 | return [parsedError as U, undefined]; 18 | } 19 | return [error as U, undefined]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/@core/base/shared/src/utils/unique.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 根据指定字段对对象数组进行去重 3 | * @param arr 要去重的对象数组 4 | * @param key 去重依据的字段名 5 | * @returns 去重后的对象数组 6 | */ 7 | function uniqueByField(arr: T[], key: keyof T): T[] { 8 | const seen = new Map(); 9 | return arr.filter((item) => { 10 | const value = item[key]; 11 | return seen.has(value) ? false : (seen.set(value, item), true); 12 | }); 13 | } 14 | 15 | export { uniqueByField }; 16 | -------------------------------------------------------------------------------- /packages/@core/base/shared/src/utils/update-css-variables.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 更新 CSS 变量的函数 3 | * @param variables 要更新的 CSS 变量与其新值的映射 4 | */ 5 | function updateCSSVariables( 6 | variables: { [key: string]: string }, 7 | id = '__xpress-styles__', 8 | ): void { 9 | // 获取或创建内联样式表元素 10 | const styleElement = 11 | document.querySelector(`#${id}`) || document.createElement('style'); 12 | 13 | styleElement.id = id; 14 | 15 | // 构建要更新的 CSS 变量的样式文本 16 | let cssText = ':root {'; 17 | for (const key in variables) { 18 | if (Object.prototype.hasOwnProperty.call(variables, key)) { 19 | cssText += `${key}: ${variables[key]};`; 20 | } 21 | } 22 | cssText += '}'; 23 | 24 | // 将样式文本赋值给内联样式表 25 | styleElement.textContent = cssText; 26 | 27 | // 将内联样式表添加到文档头部 28 | if (!document.querySelector(`#${id}`)) { 29 | setTimeout(() => { 30 | document.head.append(styleElement); 31 | }); 32 | } 33 | } 34 | 35 | export { updateCSSVariables }; 36 | -------------------------------------------------------------------------------- /packages/@core/base/shared/src/utils/window.ts: -------------------------------------------------------------------------------- 1 | interface OpenWindowOptions { 2 | noopener?: boolean; 3 | noreferrer?: boolean; 4 | target?: '_blank' | '_parent' | '_self' | '_top' | string; 5 | } 6 | 7 | /** 8 | * 新窗口打开URL。 9 | * 10 | * @param url - 需要打开的网址。 11 | * @param options - 打开窗口的选项。 12 | */ 13 | function openWindow(url: string, options: OpenWindowOptions = {}): void { 14 | // 解构并设置默认值 15 | const { noopener = true, noreferrer = true, target = '_blank' } = options; 16 | 17 | // 基于选项创建特性字符串 18 | const features = [noopener && 'noopener=yes', noreferrer && 'noreferrer=yes'] 19 | .filter(Boolean) 20 | .join(','); 21 | 22 | // 打开窗口 23 | window.open(url, target, features); 24 | } 25 | 26 | /** 27 | * 在新窗口中打开路由。 28 | * @param path 29 | */ 30 | function openRouteInNewWindow(path: string) { 31 | const { hash, origin } = location; 32 | const fullPath = path.startsWith('/') ? path : `/${path}`; 33 | const url = `${origin}${hash ? '/#' : ''}${fullPath}`; 34 | openWindow(url, { target: '_blank' }); 35 | } 36 | 37 | export { openRouteInNewWindow, openWindow }; 38 | -------------------------------------------------------------------------------- /packages/@core/base/shared/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/library.json", 4 | "include": ["src"], 5 | "exclude": ["node_modules"] 6 | } 7 | -------------------------------------------------------------------------------- /packages/@core/base/typings/build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | clean: true, 5 | declaration: true, 6 | entries: ['src/index'], 7 | }); 8 | -------------------------------------------------------------------------------- /packages/@core/base/typings/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@xpress-core/typings", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "type": "module", 6 | "scripts": { 7 | "build": "pnpm unbuild" 8 | }, 9 | "files": [ 10 | "dist" 11 | ], 12 | "main": "./dist/index.mjs", 13 | "module": "./dist/index.mjs", 14 | "types": "./dist/index.d.ts", 15 | "exports": { 16 | ".": { 17 | "types": "./src/index.ts", 18 | "development": "./src/index.ts", 19 | "default": "./dist/index.mjs" 20 | } 21 | }, 22 | "publishConfig": { 23 | "exports": { 24 | ".": { 25 | "types": "./dist/index.d.ts", 26 | "default": "./dist/index.mjs" 27 | } 28 | } 29 | }, 30 | "peerDependencies": { 31 | "react": "catalog:" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/@core/base/typings/src/basic.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unused-vars */ 2 | declare const SIDE_OPTIONS: readonly ['top', 'right', 'bottom', 'left']; 3 | declare const ALIGN_OPTIONS: readonly ['start', 'center', 'end']; 4 | type Side = (typeof SIDE_OPTIONS)[number]; 5 | type Align = (typeof ALIGN_OPTIONS)[number]; 6 | type Icon = 7 | | ((props: any) => React.ReactNode) 8 | | React.ComponentType 9 | | string; 10 | export type { Align, Icon, Side }; 11 | -------------------------------------------------------------------------------- /packages/@core/base/typings/src/global.d.ts: -------------------------------------------------------------------------------- 1 | export interface XpressAdminProAppConfigRaw { 2 | VITE_GLOB_API_URL: string; 3 | } 4 | 5 | export interface ApplicationConfig { 6 | apiURL: string; 7 | } 8 | 9 | declare global { 10 | interface Window { 11 | _XPRESS_ADMIN_PRO_APP_CONF_: XpressAdminProAppConfigRaw; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/@core/base/typings/src/index.ts: -------------------------------------------------------------------------------- 1 | export type * from './app'; 2 | export type * from './basic'; 3 | export type * from './global'; 4 | export type * from './helper'; 5 | export type * from './menu-record'; 6 | export type * from './router'; 7 | -------------------------------------------------------------------------------- /packages/@core/base/typings/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/library.json", 4 | "include": ["src"], 5 | "exclude": ["node_modules"] 6 | } 7 | -------------------------------------------------------------------------------- /packages/@core/hooks/build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | clean: true, 5 | declaration: true, 6 | entries: ['src/index'], 7 | }); 8 | -------------------------------------------------------------------------------- /packages/@core/hooks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@xpress-core/hooks", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "type": "module", 6 | "scripts": { 7 | "build": "pnpm unbuild" 8 | }, 9 | "files": [ 10 | "dist" 11 | ], 12 | "sideEffects": false, 13 | "main": "./dist/index.mjs", 14 | "module": "./dist/index.mjs", 15 | "exports": { 16 | ".": { 17 | "types": "./src/index.ts", 18 | "development": "./src/index.ts", 19 | "default": "./dist/index.mjs" 20 | } 21 | }, 22 | "publishConfig": { 23 | "exports": { 24 | ".": { 25 | "types": "./dist/index.d.ts", 26 | "default": "./dist/index.mjs" 27 | } 28 | } 29 | }, 30 | "dependencies": { 31 | "@xpress-core/shared": "workspace:*", 32 | "@xpress-core/typings": "workspace:*", 33 | "ahooks": "catalog:", 34 | "react": "catalog:", 35 | "watermark-js-plus": "^1.5.9" 36 | }, 37 | "devDependencies": { 38 | "@types/react": "catalog:" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/@core/hooks/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useAnimation'; 2 | export * from './useBreakpoints'; 3 | export * from './useControlledState'; 4 | export * from './useCssVar'; 5 | export * from './useEnhancedScroll'; 6 | export * from './useFindMenu'; 7 | export * from './useIsMobile'; 8 | export * from './useLayoutStyle'; 9 | export * from './useMediaQuery'; 10 | export * from './useNamespace'; 11 | export * from './usePresseHold'; 12 | export * from './useScrollLock'; 13 | export * from './useShow'; 14 | export * from './useWatermark'; 15 | export * from 'ahooks'; 16 | -------------------------------------------------------------------------------- /packages/@core/hooks/src/useControlledState.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useEffect, useState } from 'react'; 2 | 3 | interface Props { 4 | defaultValue?: T; 5 | modelValue?: T; 6 | onModelValueChange?: (value: T) => void; 7 | } 8 | 9 | export const useControlledState = (props: Props) => { 10 | const [value, setValue] = useState( 11 | props.modelValue ?? props.defaultValue ?? (null as T), 12 | ); 13 | 14 | useEffect(() => { 15 | if (props.modelValue !== undefined) { 16 | setValue(props.modelValue); 17 | } 18 | }, [props.modelValue]); 19 | 20 | const handleChange = useCallback( 21 | (newValue: T) => { 22 | setValue(newValue); 23 | props.onModelValueChange?.(newValue); 24 | }, 25 | [props], 26 | ); 27 | 28 | return [value, handleChange] as const; 29 | }; 30 | -------------------------------------------------------------------------------- /packages/@core/hooks/src/useIsMobile.ts: -------------------------------------------------------------------------------- 1 | import { breakpointsTailwind, useBreakpoints } from './useBreakpoints'; 2 | 3 | export function useIsMobile() { 4 | const breakpoints = useBreakpoints(breakpointsTailwind); 5 | const isMobile = breakpoints.smaller('md'); 6 | return { isMobile }; 7 | } 8 | -------------------------------------------------------------------------------- /packages/@core/hooks/src/useShow/index.ts: -------------------------------------------------------------------------------- 1 | export * from './async'; 2 | export * from './sync'; 3 | export * from './types'; 4 | -------------------------------------------------------------------------------- /packages/@core/hooks/src/useShow/types.ts: -------------------------------------------------------------------------------- 1 | import { type ReactNode } from 'react'; 2 | 3 | /** 4 | * 渲染函数类型 5 | * @template T 数据类型 6 | */ 7 | export type RenderFunction = (data: T) => ReactNode; 8 | 9 | /** 10 | * 异步Show Hook的返回值类型 11 | */ 12 | export type AsyncShowResult = { 13 | /** 渲染的内容 */ 14 | content: ReactNode; 15 | /** 是否有错误 */ 16 | error?: Error; 17 | /** 是否正在加载 */ 18 | isLoading: boolean; 19 | }; 20 | -------------------------------------------------------------------------------- /packages/@core/hooks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/library.json", 4 | "include": ["src"], 5 | "exclude": ["node_modules"] 6 | } 7 | -------------------------------------------------------------------------------- /packages/@core/preferences/__tests__/config.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from 'vitest'; 2 | 3 | import { defaultPreferences } from '../src/config'; 4 | 5 | describe('defaultPreferences immutability test', () => { 6 | // 创建快照,确保默认配置对象不被修改 7 | it('should not modify the config object', () => { 8 | expect(defaultPreferences).toMatchSnapshot(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/@core/preferences/build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | clean: true, 5 | declaration: true, 6 | entries: ['src/index'], 7 | }); 8 | -------------------------------------------------------------------------------- /packages/@core/preferences/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@xpress-core/preferences", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "type": "module", 6 | "scripts": { 7 | "#build": "pnpm unbuild" 8 | }, 9 | "files": [ 10 | "dist", 11 | "src" 12 | ], 13 | "sideEffects": [ 14 | "**/*.css" 15 | ], 16 | "exports": { 17 | ".": { 18 | "types": "./src/index.ts", 19 | "development": "./src/index.ts", 20 | "default": "./src/index.ts", 21 | "#default": "./dist/index.mjs" 22 | } 23 | }, 24 | "dependencies": { 25 | "@xpress-core/hooks": "workspace:*", 26 | "@xpress-core/shared": "workspace:*", 27 | "@xpress-core/typings": "workspace:*", 28 | "ahooks": "catalog:", 29 | "react": "catalog:" 30 | }, 31 | "devDependencies": { 32 | "@types/react": "catalog:" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/@core/preferences/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './config'; 2 | export * from './constants'; 3 | export * from './preferences'; 4 | export type * from './types'; 5 | export * from './update-css-variables'; 6 | -------------------------------------------------------------------------------- /packages/@core/preferences/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/web.json", 4 | "include": ["src", "__tests__"], 5 | "exclude": ["node_modules"] 6 | } 7 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/layout-ui/build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | clean: true, 5 | declaration: true, 6 | entries: ['src/index'], 7 | // externals: ['react', 'react-dom', 'react/jsx-runtime'], 8 | failOnWarn: false, 9 | rollup: { 10 | emitCJS: true, 11 | esbuild: { 12 | jsx: 'automatic', 13 | jsxImportSource: 'react', 14 | minify: true, 15 | treeShaking: true, 16 | tsconfigRaw: { 17 | compilerOptions: { 18 | jsx: 'react-jsx', 19 | }, 20 | }, 21 | }, 22 | inlineDependencies: true, 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/layout-ui/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from '@xpress/tailwind-config/postcss'; 2 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/layout-ui/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export { default as LayoutContent } from './layout-content'; 2 | export { default as LayoutFooter } from './layout-footer'; 3 | export { default as LayoutHeader } from './layout-header'; 4 | export { default as LayoutSidebar } from './layout-sidebar'; 5 | export { default as LayoutTabbar } from './layout-tabbar'; 6 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/layout-ui/src/components/layout-content/types.ts: -------------------------------------------------------------------------------- 1 | import type { HTMLAttributes } from 'react'; 2 | 3 | type ContentCompactType = 'compact' | 'wide'; 4 | export interface LayoutContentProps extends HTMLAttributes { 5 | /** 6 | * 内容区域定宽 7 | */ 8 | contentCompact: ContentCompactType; 9 | /** 10 | * 定宽布局宽度 11 | */ 12 | contentCompactWidth: number; 13 | overlay?: React.ReactNode; 14 | padding: number; 15 | paddingBottom: number; 16 | paddingLeft: number; 17 | paddingRight: number; 18 | paddingTop: number; 19 | } 20 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/layout-ui/src/components/layout-footer/index.tsx: -------------------------------------------------------------------------------- 1 | import type { LayoutFooterProps } from './types'; 2 | 3 | import { type CSSProperties, type FC, useMemo } from 'react'; 4 | 5 | const LayoutFooter: FC = ({ 6 | fixed, 7 | height, 8 | show = true, 9 | width, 10 | zIndex, 11 | children, 12 | }) => { 13 | const style = useMemo((): CSSProperties => { 14 | return { 15 | height: `${height}px`, 16 | marginBottom: show ? '0' : `-${height}px`, 17 | position: fixed ? 'fixed' : 'static', 18 | width, 19 | zIndex, 20 | }; 21 | }, [fixed, height, show, width, zIndex]); 22 | return ( 23 |
27 | {children} 28 |
29 | ); 30 | }; 31 | 32 | export default LayoutFooter; 33 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/layout-ui/src/components/layout-footer/types.ts: -------------------------------------------------------------------------------- 1 | import type { PropsWithChildren } from 'react'; 2 | 3 | export interface LayoutFooterProps extends PropsWithChildren { 4 | /** 5 | * 是否固定在底部 6 | */ 7 | fixed?: boolean; 8 | height: number; 9 | /** 10 | * 是否显示 11 | * @default true 12 | */ 13 | show?: boolean; 14 | width: string; 15 | zIndex: number; 16 | } 17 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/layout-ui/src/components/layout-header/types.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | export interface LayoutHeaderProps { 4 | /** 5 | * 默认插槽内容 6 | */ 7 | children?: ReactNode; 8 | /** 9 | * 横屏 10 | */ 11 | fullWidth?: boolean; 12 | /** 13 | * 高度 14 | */ 15 | height?: number; 16 | /** 17 | * 是否移动端 18 | */ 19 | isMobile?: boolean; 20 | /** 21 | * Logo 插槽内容 22 | */ 23 | logo?: ReactNode; 24 | /** 25 | * 是否显示 26 | */ 27 | show?: boolean; 28 | /** 29 | * 侧边菜单宽度 30 | */ 31 | sidebarWidth?: number; 32 | /** 33 | * 主题 34 | */ 35 | theme?: string; 36 | /** 37 | * 切换按钮插槽内容 38 | */ 39 | toggleButton?: ReactNode; 40 | } 41 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/layout-ui/src/components/layout-tabbar/index.tsx: -------------------------------------------------------------------------------- 1 | import type { LayoutTabbarProps } from './types'; 2 | 3 | import { cn } from '@xpress-core/shared/utils'; 4 | 5 | import { type CSSProperties, type FC, useMemo } from 'react'; 6 | 7 | const LayoutTabbar: FC = ({ 8 | className, 9 | height, 10 | style, 11 | children, 12 | }: LayoutTabbarProps) => { 13 | const baseStyle = useMemo((): CSSProperties => { 14 | return { 15 | height: `${height}px`, 16 | }; 17 | }, [height]); 18 | 19 | const mergedStyle = useMemo( 20 | () => ({ 21 | ...baseStyle, 22 | ...style, 23 | }), 24 | [baseStyle, style], 25 | ); 26 | 27 | return ( 28 |
35 | {children} 36 |
37 | ); 38 | }; 39 | 40 | export default LayoutTabbar; 41 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/layout-ui/src/components/layout-tabbar/types.ts: -------------------------------------------------------------------------------- 1 | import type { HTMLAttributes } from 'react'; 2 | 3 | export interface LayoutTabbarProps extends HTMLAttributes { 4 | className?: string; 5 | height?: number; 6 | } 7 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/layout-ui/src/components/widgets/SidebarCollapseButton.tsx: -------------------------------------------------------------------------------- 1 | import { useIsMobile } from '@xpress-core/hooks'; 2 | import { ChevronsLeft, ChevronsRight } from '@xpress-core/icons'; 3 | 4 | export default function SidebarCollapseButton({ 5 | setSidebarCollapse, 6 | sidebarCollapse, 7 | }: { 8 | setSidebarCollapse: (value: boolean) => void; 9 | sidebarCollapse: boolean; 10 | }) { 11 | const { isMobile } = useIsMobile(); 12 | 13 | return ( 14 |
setSidebarCollapse(!sidebarCollapse)} 19 | > 20 | {sidebarCollapse ? ( 21 | 22 | ) : ( 23 | 24 | )} 25 |
26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/layout-ui/src/components/widgets/SidebarFixedButton.tsx: -------------------------------------------------------------------------------- 1 | import { useIsMobile } from '@xpress-core/hooks'; 2 | import { Pin, PinOff } from '@xpress-core/icons'; 3 | 4 | export default function SidebarFixedButton({ 5 | setSidebarExpandOnHover, 6 | sidebarExpandOnHover, 7 | }: { 8 | setSidebarExpandOnHover: (value: boolean) => void; 9 | sidebarExpandOnHover: boolean; 10 | }) { 11 | const { isMobile } = useIsMobile(); 12 | return ( 13 |
setSidebarExpandOnHover(!sidebarExpandOnHover)} 18 | > 19 | {sidebarExpandOnHover ? ( 20 | 21 | ) : ( 22 | 23 | )} 24 |
25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/layout-ui/src/components/widgets/index.ts: -------------------------------------------------------------------------------- 1 | export { default as SidebarCollapseButton } from './SidebarCollapseButton'; 2 | export { default as SidebarFixedButton } from './SidebarFixedButton'; 3 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/layout-ui/src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useLayout'; 2 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/layout-ui/src/hooks/useLayout.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | BaseXpressLayoutProps, 3 | LayoutType, 4 | UseLayoutResult, 5 | } from '@xpress-core/typings'; 6 | 7 | import { useMemo } from 'react'; 8 | 9 | /** 10 | * 布局hook 11 | * @param {BaseXpressLayoutProps} props - 布局属性 12 | * @returns {UseLayoutResult} 布局结果 13 | */ 14 | export const useLayout = ({ 15 | isMobile, 16 | layout, 17 | }: BaseXpressLayoutProps): UseLayoutResult => { 18 | const currentLayout = useMemo( 19 | () => (isMobile ? 'sidebar-nav' : (layout as LayoutType)), 20 | [isMobile, layout], 21 | ); 22 | 23 | const layoutStates = useMemo( 24 | () => ({ 25 | isFullContent: currentLayout === 'full-content', 26 | isHeaderNav: currentLayout === 'header-nav', 27 | isMixedNav: 28 | currentLayout === 'mixed-nav' || currentLayout === 'header-sidebar-nav', 29 | isSidebarMixedNav: currentLayout === 'sidebar-mixed-nav', 30 | }), 31 | [currentLayout], 32 | ); 33 | 34 | return { 35 | currentLayout, 36 | ...layoutStates, 37 | }; 38 | }; 39 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/layout-ui/src/index.ts: -------------------------------------------------------------------------------- 1 | // export * from './components'; 2 | export { default as XpressLayout } from './xpress-layout'; 3 | export * from './xpress-layout/types'; 4 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/layout-ui/src/xpress-layout/context.tsx: -------------------------------------------------------------------------------- 1 | import { createContext, useContext } from 'react'; 2 | 3 | interface LayoutContextType { 4 | onSideMouseLeave?: () => void; 5 | setSidebarCollapse: (value: boolean) => void; 6 | setSidebarEnable: (value: boolean) => void; 7 | setSidebarExpandOnHover: (value: boolean) => void; 8 | setSidebarExpandOnHovering: (value: boolean) => void; 9 | setSidebarExtraCollapse: (value: boolean) => void; 10 | setSidebarExtraVisible: (value: boolean) => void; 11 | sidebarCollapse: boolean; 12 | sidebarEnable: boolean; 13 | sidebarExpandOnHover: boolean; 14 | sidebarExpandOnHovering: boolean; 15 | sidebarExtraCollapse: boolean; 16 | sidebarExtraVisible: boolean; 17 | } 18 | 19 | export const LayoutContext = createContext( 20 | undefined, 21 | ); 22 | 23 | export const useLayoutContext = () => { 24 | const context = useContext(LayoutContext); 25 | if (!context) { 26 | throw new Error('useLayoutContext must be used within a LayoutProvider'); 27 | } 28 | return context; 29 | }; 30 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/layout-ui/tailwind.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from '@xpress/tailwind-config'; 2 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/layout-ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/web.json", 4 | "compilerOptions": { 5 | "jsx": "react-jsx", 6 | "allowSyntheticDefaultImports": true, 7 | "esModuleInterop": true 8 | }, 9 | "include": ["src/**/*.ts", "src/**/*.tsx"], 10 | "exclude": ["node_modules"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/popup-ui/build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | clean: true, 5 | declaration: true, 6 | entries: ['src/index'], 7 | // externals: ['react', 'react-dom', 'react/jsx-runtime'], 8 | failOnWarn: false, 9 | rollup: { 10 | emitCJS: true, 11 | esbuild: { 12 | jsx: 'automatic', 13 | jsxImportSource: 'react', 14 | minify: true, 15 | treeShaking: true, 16 | tsconfigRaw: { 17 | compilerOptions: { 18 | jsx: 'react-jsx', 19 | }, 20 | }, 21 | }, 22 | inlineDependencies: true, 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/popup-ui/src/drawer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Drawer'; 2 | export * from './types'; 3 | // export { useDrawer } from './useDrawer'; 4 | // export type { DrawerApi } from './useDrawer'; 5 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/popup-ui/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './drawer'; 2 | export * from './modal'; 3 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/popup-ui/src/modal/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Modal'; 2 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/popup-ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/web.json", 4 | "include": ["src"], 5 | "exclude": ["node_modules"] 6 | } 7 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/react-menu/README.md: -------------------------------------------------------------------------------- 1 | # 菜单组件 2 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/react-menu/build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | clean: true, 5 | declaration: true, 6 | entries: ['src/index'], 7 | // externals: ['react', 'react-dom', 'react/jsx-runtime'], 8 | failOnWarn: false, 9 | rollup: { 10 | emitCJS: true, 11 | esbuild: { 12 | jsx: 'automatic', 13 | jsxImportSource: 'react', 14 | minify: true, 15 | treeShaking: true, 16 | tsconfigRaw: { 17 | compilerOptions: { 18 | jsx: 'react-jsx', 19 | }, 20 | }, 21 | }, 22 | inlineDependencies: true, 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/react-menu/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from '@xpress/tailwind-config/postcss'; 2 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/react-menu/src/components/collapse-transition/index.tsx: -------------------------------------------------------------------------------- 1 | import type { PropsWithChildren } from 'react'; 2 | 3 | import { AnimatePresence, motion } from 'framer-motion'; 4 | 5 | interface Props extends PropsWithChildren { 6 | show?: boolean; 7 | } 8 | 9 | function CollapseTransition({ show = true, children }: Props) { 10 | return ( 11 | 12 | {show && ( 13 | 32 | {children} 33 | 34 | )} 35 | 36 | ); 37 | } 38 | 39 | export default CollapseTransition; 40 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/react-menu/src/components/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useMenuContext'; 2 | export * from './useMenuStructure'; 3 | export * from './useMenuStyle'; 4 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/react-menu/src/components/hooks/useMenuContext.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | 3 | import { MenuContext } from '../contexts'; 4 | 5 | export const useMenuContext = () => { 6 | const context = useContext(MenuContext); 7 | if (!context) { 8 | throw new Error('useMenuContext must be used within a MenuProvider'); 9 | } 10 | return context; 11 | }; 12 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/react-menu/src/components/hooks/useMenuStyle.ts: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react'; 2 | 3 | export function useMenuStyle(level = 0) { 4 | const menuStyle = useMemo(() => { 5 | return { 6 | '--menu-level': level + 1, 7 | } as React.CSSProperties; 8 | }, [level]); 9 | return menuStyle; 10 | } 11 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/react-menu/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export { default as CollapseTransition } from './collapse-transition'; 2 | export { default as MenuBadge } from './menu-badge'; 3 | export { default as MenuItem } from './menu-item'; 4 | export { default as NormalMenu } from './normal-menu'; 5 | export { default as SubMenu } from './sub-menu'; 6 | export type * from './types'; 7 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/react-menu/src/components/menu-badge/MenuBadgeDot.tsx: -------------------------------------------------------------------------------- 1 | import type { CSSProperties } from 'react'; 2 | 3 | import { cn } from '@xpress-core/shared/utils'; 4 | 5 | interface MenuBadgeDotProps { 6 | dotClass?: string; 7 | dotStyle?: CSSProperties; 8 | } 9 | function MenuBadgeDot({ dotClass, dotStyle }: MenuBadgeDotProps) { 10 | return ( 11 | 12 | 19 | 23 | 24 | ); 25 | } 26 | 27 | export default MenuBadgeDot; 28 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/react-menu/src/components/normal-menu/types.ts: -------------------------------------------------------------------------------- 1 | import type { MenuRecordRaw } from '@xpress-core/typings'; 2 | 3 | interface NormalMenuProps { 4 | /** 5 | * 菜单数据 6 | */ 7 | activePath?: string; 8 | /** 9 | * 是否折叠 10 | */ 11 | collapse?: boolean; 12 | /** 13 | * 菜单项 14 | */ 15 | menus?: MenuRecordRaw[]; 16 | onEnter?: (menu: MenuRecordRaw) => void; 17 | onSelect?: (menu: MenuRecordRaw) => void; 18 | /** 19 | * @zh_CN 是否圆润风格 20 | * @default true 21 | */ 22 | rounded?: boolean; 23 | /** 24 | * 主题 25 | */ 26 | theme?: 'dark' | 'light'; 27 | } 28 | export type { NormalMenuProps }; 29 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/react-menu/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const SUB_MENU_MORE_NAME = 'sub-menu-more'; 2 | export const SUB_MENU_MORE_WIDTH = 46; 3 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/react-menu/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components'; 2 | export * from './components/normal-menu/types'; 3 | export { default as MenuView } from './MenuView'; 4 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/react-menu/src/types/material-ripple-effects.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'material-ripple-effects' { 2 | export default class Ripple { 3 | private x: number; 4 | private y: number; 5 | private z: number; 6 | 7 | constructor(); 8 | 9 | private applyAnimation(element: HTMLElement): void; 10 | 11 | private appyStyles( 12 | element: HTMLElement, 13 | color: 'dark' | 'light', 14 | rect: DOMRect, 15 | radius: number, 16 | event: MouseEvent, 17 | ): void; 18 | 19 | private findFurthestPoint( 20 | clickPointX: number, 21 | elementWidth: number, 22 | offsetX: number, 23 | clickPointY: number, 24 | elementHeight: number, 25 | offsetY: number, 26 | ): number; 27 | 28 | create(event: MouseEvent, color: 'dark' | 'light'): void; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/react-menu/tailwind.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from '@xpress/tailwind-config'; 2 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/react-menu/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/web.json", 4 | "compilerOptions": { 5 | "jsx": "react-jsx", 6 | "allowSyntheticDefaultImports": true, 7 | "esModuleInterop": true 8 | }, 9 | "include": ["src/**/*.ts", "src/**/*.tsx"], 10 | "exclude": ["node_modules"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | clean: true, 5 | declaration: true, 6 | entries: ['src/index'], 7 | }); 8 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": false, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.mjs", 8 | "css": "src/styles/globals.css", 9 | "baseColor": "slate", 10 | "cssVariables": true 11 | }, 12 | "aliases": { 13 | "components": "@xpress-core/shadcn-ui/components", 14 | "utils": "@xpress-core/shared/utils", 15 | "lib": "@xpress-core/shared/utils", 16 | "ui": "@xpress-core/shadcn-ui/components/ui" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from '@xpress/tailwind-config/postcss'; 2 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/base/breadcrumb/BreadcrumbView.tsx: -------------------------------------------------------------------------------- 1 | import type { BreadcrumbProps } from './type'; 2 | 3 | import { XpressBreadcrumb } from './Breadcrumb'; 4 | import { XpressBreadcrumbBackground } from './BreadcrumbBackground'; 5 | 6 | export function XpressBreadcrumbView({ styleType, ...props }: BreadcrumbProps) { 7 | return ( 8 |
9 | {styleType === 'normal' && } 10 | {styleType === 'background' && } 11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/base/breadcrumb/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Breadcrumb'; 2 | export * from './BreadcrumbBackground'; 3 | export * from './BreadcrumbView'; 4 | export * from './type'; 5 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/base/breadcrumb/type.ts: -------------------------------------------------------------------------------- 1 | import type { BreadcrumbStyleType, Icon } from '@xpress-core/typings'; 2 | 3 | interface IBreadcrumb { 4 | defaultPath?: string; 5 | icon?: Icon; 6 | isHome?: boolean; 7 | items?: IBreadcrumb[]; 8 | path?: string; 9 | title?: string; 10 | } 11 | 12 | interface BreadcrumbProps { 13 | breadcrumbs: IBreadcrumb[]; 14 | className?: string; 15 | onSelect?: (path?: string, defaultPath?: string) => void; 16 | showIcon?: boolean; 17 | styleType?: BreadcrumbStyleType; 18 | } 19 | 20 | export type { BreadcrumbProps, IBreadcrumb }; 21 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/base/button/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Button'; 2 | export * from './IconButton'; 3 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/base/button/types.ts: -------------------------------------------------------------------------------- 1 | import type { ButtonVariants, ButtonVariantSize } from '../../ui'; 2 | 3 | export interface XpressButtonProps { 4 | asChild?: boolean; 5 | disabled?: boolean; 6 | loading?: boolean; 7 | size?: ButtonVariantSize; 8 | variant?: ButtonVariants; 9 | } 10 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/base/dropdown-menu/index.ts: -------------------------------------------------------------------------------- 1 | export * from './DropdownMenu'; 2 | export * from './DropdownRadioMenu'; 3 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/base/dropdown-menu/type.ts: -------------------------------------------------------------------------------- 1 | import type { Icon } from '@xpress-core/typings'; 2 | 3 | interface XpressDropdownMenuItem { 4 | disabled?: boolean; 5 | /** 6 | * @zh_CN 点击事件处理 7 | * @param data 8 | */ 9 | handler?: (data: any) => void; 10 | /** 11 | * @zh_CN 图标 12 | */ 13 | icon?: Icon; 14 | /** 15 | * @zh_CN 标题 16 | */ 17 | label: string; 18 | /** 19 | * @zh_CN 是否是分割线 20 | */ 21 | separator?: boolean; 22 | /** 23 | * @zh_CN 唯一标识 24 | */ 25 | value: string; 26 | } 27 | 28 | export type { XpressDropdownMenuItem }; 29 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/base/icon/index.ts: -------------------------------------------------------------------------------- 1 | export { default as XpressIcon } from './icon'; 2 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/base/index.ts: -------------------------------------------------------------------------------- 1 | export * from './avatar'; 2 | export * from './breadcrumb'; 3 | export * from './button'; 4 | export * from './context-menu'; 5 | export * from './dropdown-menu'; 6 | export * from './hover-card'; 7 | export * from './icon'; 8 | export * from './loading'; 9 | export * from './logo'; 10 | export * from './number-field'; 11 | export * from './scroll-area'; 12 | export * from './segmented'; 13 | export * from './tooltip'; 14 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/base/number-field/NumberField.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@xpress-core/shared/utils'; 2 | 3 | export const NumberField = ({ 4 | className, 5 | children, 6 | }: { 7 | children: React.ReactNode; 8 | className?: string; 9 | }) => { 10 | return
{children}
; 11 | }; 12 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/base/number-field/NumberFieldContent.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@xpress-core/shared/utils'; 2 | 3 | export const NumberFieldContent = ({ 4 | className, 5 | children, 6 | }: { 7 | children: React.ReactNode; 8 | className?: string; 9 | }) => { 10 | return
{children}
; 11 | }; 12 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/base/number-field/index.ts: -------------------------------------------------------------------------------- 1 | export * from './NumberField'; 2 | export * from './NumberFieldCom'; 3 | export * from './NumberFieldContent'; 4 | export * from './NumberFieldDecrement'; 5 | export * from './NumberFieldIncrement'; 6 | export * from './NumberFieldInput'; 7 | export * from './NumberFieldItem'; 8 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/base/scroll-area/styles.module.css: -------------------------------------------------------------------------------- 1 | .xpressScrollbar { 2 | &:not(.both-shadow).left-shadow { 3 | mask-image: linear-gradient(90deg, transparent, #000 16px); 4 | } 5 | 6 | &:not(.both-shadow).right-shadow { 7 | mask-image: linear-gradient( 8 | 90deg, 9 | #000 0%, 10 | #000 calc(100% - 16px), 11 | transparent 12 | ); 13 | } 14 | 15 | &.both-shadow { 16 | mask-image: linear-gradient( 17 | 90deg, 18 | transparent, 19 | #000 16px, 20 | #000 calc(100% - 16px), 21 | transparent 100% 22 | ); 23 | } 24 | } 25 | 26 | .scrollbarTopShadow { 27 | background: linear-gradient( 28 | to bottom, 29 | hsl(var(--scroll-shadow, var(--background))), 30 | transparent 31 | ); 32 | } 33 | 34 | .scrollbarBottomShadow { 35 | background: linear-gradient( 36 | to top, 37 | hsl(var(--scroll-shadow, var(--background))), 38 | transparent 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/base/scroll-area/styles.module.css.d.ts: -------------------------------------------------------------------------------- 1 | declare const styles: { 2 | readonly 'both-shadow': string; 3 | readonly 'left-shadow': string; 4 | readonly 'right-shadow': string; 5 | readonly scrollbarBottomShadow: string; 6 | readonly scrollbarTopShadow: string; 7 | readonly xpressScrollbar: string; 8 | }; 9 | 10 | export default styles; 11 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/base/scroll-area/styles.module.css.json: -------------------------------------------------------------------------------- 1 | { 2 | "_xpressScrollbar_hdxd6_1": "styles-module___xpressScrollbar_hdxd6_1___HvP-M", 3 | "_both-shadow_hdxd6_2": "styles-module___both-shadow_hdxd6_2___TA3Hy", 4 | "_left-shadow_hdxd6_2": "styles-module___left-shadow_hdxd6_2___XCZez", 5 | "_right-shadow_hdxd6_6": "styles-module___right-shadow_hdxd6_6___OKVFV", 6 | "_scrollbarTopShadow_hdxd6_26": "styles-module___scrollbarTopShadow_hdxd6_26___yjnyk", 7 | "_scrollbarBottomShadow_hdxd6_34": "styles-module___scrollbarBottomShadow_hdxd6_34___UE7AJ" 8 | } 9 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/base/tooltip/HelpTooltip.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@xpress-core/shared/utils'; 2 | 3 | import { CircleHelp } from 'lucide-react'; 4 | 5 | import { XpressTooltip } from './Tooltip'; 6 | 7 | interface HelpTooltipProps { 8 | children: React.ReactNode; 9 | trigger?: React.ReactNode; 10 | triggerClass?: string; 11 | } 12 | 13 | export function XpressHelpTooltip({ 14 | trigger, 15 | triggerClass, 16 | children, 17 | }: HelpTooltipProps) { 18 | return ( 19 | 30 | ) 31 | } 32 | > 33 | {children} 34 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/base/tooltip/Tooltip.tsx: -------------------------------------------------------------------------------- 1 | import type { XpressTooltipProps } from './types'; 2 | 3 | import { cn } from '@xpress-core/shared/utils'; 4 | 5 | import { 6 | Tooltip, 7 | TooltipContent, 8 | TooltipProvider, 9 | TooltipTrigger, 10 | } from '../../ui'; 11 | 12 | export function XpressTooltip({ 13 | contentClass, 14 | contentStyle, 15 | delayDuration = 0, 16 | side = 'right', 17 | trigger, 18 | children, 19 | }: XpressTooltipProps) { 20 | return ( 21 | 22 | 23 | 24 | {trigger} 25 | 26 | 34 | {children} 35 | 36 | 37 | 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/base/tooltip/index.ts: -------------------------------------------------------------------------------- 1 | export * from './HelpTooltip'; 2 | export * from './Tooltip'; 3 | export type { XpressTooltipProps } from './types'; 4 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/base/tooltip/types.ts: -------------------------------------------------------------------------------- 1 | import type { Side } from '@xpress-core/typings'; 2 | 3 | export interface XpressTooltipProps { 4 | children: React.ReactNode; 5 | contentClass?: string; 6 | contentStyle?: React.CSSProperties; 7 | delayDuration?: number; 8 | side?: Side; 9 | trigger: React.ReactNode; 10 | } 11 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/ui/badge/badge.ts: -------------------------------------------------------------------------------- 1 | import type { VariantProps } from 'class-variance-authority'; 2 | 3 | import { cva } from 'class-variance-authority'; 4 | 5 | export const badgeVariants = cva( 6 | 'inline-flex items-center rounded-md border border-border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', 7 | { 8 | defaultVariants: { 9 | variant: 'default', 10 | }, 11 | variants: { 12 | variant: { 13 | default: 14 | 'border-transparent bg-accent hover:bg-accent text-primary-foreground shadow', 15 | destructive: 16 | 'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive-hover', 17 | outline: 'text-foreground', 18 | secondary: 19 | 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80', 20 | }, 21 | }, 22 | }, 23 | ); 24 | 25 | export type BadgeVariants = VariantProps; 26 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/ui/badge/index.tsx: -------------------------------------------------------------------------------- 1 | import type { BadgeVariants } from './badge'; 2 | 3 | import { cn } from '@xpress-core/shared/utils'; 4 | 5 | import { badgeVariants } from './badge'; 6 | 7 | export const Badge = ({ 8 | className, 9 | variant, 10 | children, 11 | }: { 12 | children: React.ReactNode; 13 | className?: string; 14 | variant?: BadgeVariants['variant']; 15 | }) => { 16 | return ( 17 |
{children}
18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/ui/button/Component.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@xpress-core/shared/utils'; 2 | 3 | import { Slot } from '@radix-ui/react-slot'; 4 | import { type VariantProps } from 'class-variance-authority'; 5 | import * as React from 'react'; 6 | 7 | import { buttonVariants } from './constants'; 8 | 9 | export interface ButtonProps 10 | extends React.ButtonHTMLAttributes, 11 | VariantProps { 12 | asChild?: boolean; 13 | } 14 | 15 | const Button = React.forwardRef( 16 | ({ asChild = false, className, size, variant, ...props }, ref) => { 17 | const Comp = asChild ? Slot : 'button'; 18 | return ( 19 | 24 | ); 25 | }, 26 | ); 27 | Button.displayName = 'Button'; 28 | 29 | export { Button }; 30 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/ui/button/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Component'; 2 | export * from './constants'; 3 | export * from './types'; 4 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/ui/button/types.ts: -------------------------------------------------------------------------------- 1 | export type ButtonVariantSize = 2 | | 'default' 3 | | 'icon' 4 | | 'lg' 5 | | 'sm' 6 | | 'xs' 7 | | null 8 | | undefined; 9 | 10 | export type ButtonVariants = 11 | | 'default' 12 | | 'destructive' 13 | | 'ghost' 14 | | 'heavy' 15 | | 'icon' 16 | | 'link' 17 | | 'outline' 18 | | 'secondary' 19 | | null 20 | | undefined; 21 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/ui/index.ts: -------------------------------------------------------------------------------- 1 | export * from './avatar'; 2 | export * from './badge'; 3 | export * from './breadcrumb'; 4 | export * from './button'; 5 | export * from './card'; 6 | export * from './checkbox'; 7 | export * from './context-menu'; 8 | export * from './dialog'; 9 | export * from './dropdown-menu'; 10 | export * from './form'; 11 | export * from './input'; 12 | export * from './label'; 13 | export * from './scroll-area'; 14 | export * from './select'; 15 | export * from './separator'; 16 | export * from './sheet'; 17 | export * from './switch'; 18 | export * from './tabs'; 19 | export * from './tabs'; 20 | export * from './toggle'; 21 | export * from './toggle-group'; 22 | export * from './tooltip'; 23 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/ui/input.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@xpress-core/shared/utils'; 2 | 3 | import * as React from 'react'; 4 | 5 | const Input = React.forwardRef>( 6 | ({ className, type, ...props }, ref) => { 7 | return ( 8 | 17 | ); 18 | }, 19 | ); 20 | Input.displayName = 'Input'; 21 | 22 | export { Input }; 23 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@xpress-core/shared/utils'; 2 | 3 | import * as LabelPrimitive from '@radix-ui/react-label'; 4 | import { cva, type VariantProps } from 'class-variance-authority'; 5 | import * as React from 'react'; 6 | 7 | const labelVariants = cva( 8 | 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70', 9 | ); 10 | 11 | const Label = React.forwardRef< 12 | React.ElementRef, 13 | React.ComponentPropsWithoutRef & 14 | VariantProps 15 | >(({ className, ...props }, ref) => ( 16 | 21 | )); 22 | Label.displayName = LabelPrimitive.Root.displayName; 23 | 24 | export { Label }; 25 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/components/ui/separator.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@xpress-core/shared/utils'; 2 | 3 | import * as SeparatorPrimitive from '@radix-ui/react-separator'; 4 | import * as React from 'react'; 5 | 6 | const Separator = React.forwardRef< 7 | React.ElementRef, 8 | React.ComponentPropsWithoutRef 9 | >( 10 | ( 11 | { className, decorative = true, orientation = 'horizontal', ...props }, 12 | ref, 13 | ) => ( 14 | 25 | ), 26 | ); 27 | Separator.displayName = SeparatorPrimitive.Root.displayName; 28 | 29 | export { Separator }; 30 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/base'; 2 | export * from './components/ui'; 3 | export { Slot } from '@radix-ui/react-slot'; 4 | export { VisuallyHidden } from '@radix-ui/react-visually-hidden'; 5 | export * from 'class-variance-authority'; 6 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/tailwind.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from '@xpress/tailwind-config'; 2 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/shadcn-ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/web.json", 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "paths": { 7 | "@xpress-core/shadcn-ui/*": ["./src/*"], 8 | "@xpress-core/shared/utils": ["../../../@core/base/shared/src/utils"], 9 | "@xpress-core/shared/utils/*": ["../../../@core/base/shared/src/utils/*"] 10 | } 11 | }, 12 | "include": ["src"], 13 | "exclude": ["node_modules"] 14 | } 15 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/tabs-ui/build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild'; 2 | 3 | export default defineBuildConfig({ 4 | clean: true, 5 | declaration: true, 6 | entries: ['src/index'], 7 | // externals: ['react', 'react-dom', 'react/jsx-runtime'], 8 | failOnWarn: false, 9 | rollup: { 10 | emitCJS: true, 11 | esbuild: { 12 | jsx: 'automatic', 13 | jsxImportSource: 'react', 14 | minify: true, 15 | treeShaking: true, 16 | tsconfigRaw: { 17 | compilerOptions: { 18 | jsx: 'react-jsx', 19 | }, 20 | }, 21 | }, 22 | inlineDependencies: true, 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/tabs-ui/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from '@xpress/tailwind-config/postcss'; 2 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/tabs-ui/src/index.ts: -------------------------------------------------------------------------------- 1 | export { DraggableTabs } from './components/DraggableTabs'; 2 | export { SortableTab } from './components/SortableTab'; 3 | export { useDraggableTabs } from './hooks/useDraggableTabs'; 4 | export { useTransition } from './hooks/useTransition'; 5 | export * from './tabs-base'; 6 | export * from './tabs-chrome'; 7 | 8 | export * from './TabsView'; 9 | export * from './types'; 10 | 11 | export { useTabsViewScroll } from './use-tabs-view-scroll'; 12 | export * from './widgets'; 13 | 14 | export type { IContextMenuItem } from '@xpress-core/shadcn-ui'; 15 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/tabs-ui/src/tabs-chrome/style.css: -------------------------------------------------------------------------------- 1 | .tabs-chrome { 2 | &__item { 3 | @apply cursor-pointer; 4 | 5 | &:hover:not(.is-active) { 6 | & + .tabs-chrome__item { 7 | .tabs-chrome__divider { 8 | @apply opacity-0; 9 | } 10 | } 11 | 12 | .tabs-chrome__divider { 13 | @apply opacity-0; 14 | } 15 | 16 | .tabs-chrome__background { 17 | @apply pb-[2px]; 18 | 19 | &-content { 20 | @apply bg-accent hover:bg-accent mx-[2px] rounded-md; 21 | } 22 | } 23 | } 24 | 25 | &.is-active { 26 | @apply z-[2]; 27 | 28 | & + .tabs-chrome__item { 29 | .tabs-chrome__divider { 30 | @apply opacity-0 !important; 31 | } 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/tabs-ui/src/widgets/ToolMore.tsx: -------------------------------------------------------------------------------- 1 | import { ChevronDown } from '@xpress-core/icons'; 2 | import { XpressDropdownMenu } from '@xpress-core/shadcn-ui'; 3 | 4 | export function TabsToolMore({ menus }: { menus: any[] }) { 5 | return ( 6 | 7 |
8 | 9 |
10 |
11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/tabs-ui/src/widgets/ToolScreen.tsx: -------------------------------------------------------------------------------- 1 | import { Fullscreen, Minimize2 } from '@xpress-core/icons'; 2 | 3 | export function TabsToolScreen({ 4 | screen, 5 | toggleScreen, 6 | }: { 7 | screen: boolean; 8 | toggleScreen: () => void; 9 | }) { 10 | return ( 11 |
toggleScreen()} 14 | > 15 | {screen ? ( 16 | 17 | ) : ( 18 | 19 | )} 20 |
21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/tabs-ui/src/widgets/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ToolMore'; 2 | export * from './ToolScreen'; 3 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/tabs-ui/tailwind.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from '@xpress/tailwind-config'; 2 | -------------------------------------------------------------------------------- /packages/@core/ui-kit/tabs-ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/web.json", 4 | "include": ["src"], 5 | "exclude": ["node_modules"] 6 | } 7 | -------------------------------------------------------------------------------- /packages/components/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@xpress/components", 3 | "version": "1.0.0", 4 | "keywords": [], 5 | "license": "MIT", 6 | "type": "module", 7 | "sideEffects": [ 8 | "**/*.css" 9 | ], 10 | "exports": { 11 | ".": { 12 | "types": "./src/index.ts", 13 | "default": "./src/index.ts" 14 | } 15 | }, 16 | "dependencies": { 17 | "@xpress/constants": "workspace:*", 18 | "@xpress/router": "workspace:*", 19 | "@xpress/stores": "workspace:*", 20 | "framer-motion": "catalog:", 21 | "nprogress": "catalog:", 22 | "react": "catalog:", 23 | "react-router-dom": "catalog:" 24 | }, 25 | "devDependencies": { 26 | "@types/nprogress": "catalog:", 27 | "@types/react": "catalog:" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/components/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './progress'; 2 | -------------------------------------------------------------------------------- /packages/components/src/progress/utils.ts: -------------------------------------------------------------------------------- 1 | interface Opts { 2 | force?: boolean; 3 | } 4 | 5 | export function setNProgressColor(color: string, opts?: Opts) { 6 | const { force = false } = opts ?? {}; 7 | const styleDom = 8 | document.querySelector('#nprogressThemeColor') ?? 9 | document.createElement('style'); 10 | if (!force && styleDom.id) return; 11 | 12 | styleDom.id = 'nprogressThemeColor'; 13 | styleDom.innerHTML = ` 14 | #nprogress .bar { 15 | background: ${color}!important; 16 | box-shadow: 0 0 2px ${color}; 17 | } 18 | 19 | #nprogress .peg { 20 | box-shadow: 0 0 10px ${color}, 0 0 5px ${color}; 21 | } 22 | 23 | #nprogress .spinner-icon { 24 | border-top-color: ${color}; 25 | border-inline-start-color: ${color}; 26 | } 27 | `; 28 | document.body.append(styleDom); 29 | } 30 | -------------------------------------------------------------------------------- /packages/components/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/web.json", 4 | "include": ["src"], 5 | "exclude": ["node_modules"] 6 | } 7 | -------------------------------------------------------------------------------- /packages/constants/README.md: -------------------------------------------------------------------------------- 1 | # @xpress/constants 2 | 3 | ``` 4 | 5 | ``` 6 | -------------------------------------------------------------------------------- /packages/constants/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@xpress/constants", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "type": "module", 6 | "sideEffects": [ 7 | "**/*.css" 8 | ], 9 | "exports": { 10 | ".": { 11 | "types": "./src/index.ts", 12 | "default": "./src/index.ts" 13 | } 14 | }, 15 | "dependencies": { 16 | "@xpress-core/shared": "workspace:*" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/constants/src/core.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @zh_CN 默认首页地址 3 | */ 4 | 5 | export const DEFAULT_HOME_PATH = '/home/analysis'; 6 | export interface LanguageOption { 7 | label: string; 8 | value: 'en-US' | 'zh-CN'; 9 | } 10 | 11 | /** 12 | * Supported languages 13 | */ 14 | export const SUPPORT_LANGUAGES: LanguageOption[] = [ 15 | { 16 | label: '简体中文', 17 | value: 'zh-CN', 18 | }, 19 | { 20 | label: 'English', 21 | value: 'en-US', 22 | }, 23 | ]; 24 | 25 | /** 26 | * @zh_CN 登录页面 url 地址 27 | */ 28 | export const LOGIN_PATH = '/login'; 29 | /** 30 | * @zh_CN 核心路由名称 31 | */ 32 | export const CORE_ROUTE_NAMES = new Set(['/login', '/register']); 33 | -------------------------------------------------------------------------------- /packages/constants/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './core'; 2 | export * from '@xpress-core/shared/constants'; 3 | -------------------------------------------------------------------------------- /packages/constants/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/web.json", 4 | "include": ["src"], 5 | "exclude": ["node_modules"] 6 | } 7 | -------------------------------------------------------------------------------- /packages/effects/common-ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@xpress/common-ui", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "type": "module", 6 | "sideEffects": [ 7 | "**/*.css" 8 | ], 9 | "exports": { 10 | ".": { 11 | "types": "./src/index.ts", 12 | "default": "./src/index.ts" 13 | } 14 | }, 15 | "dependencies": { 16 | "@xpress-core/shared": "workspace:*", 17 | "react": "catalog:", 18 | "react-dom": "catalog:" 19 | }, 20 | "devDependencies": { 21 | "@types/react": "catalog:", 22 | "@types/react-dom": "catalog:" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/effects/common-ui/src/components/icon-picker/index.tsx: -------------------------------------------------------------------------------- 1 | export const IconPicker = () => { 2 | return
IconPicker
; 3 | }; 4 | -------------------------------------------------------------------------------- /packages/effects/common-ui/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './icon-picker'; 2 | export * from './page'; 3 | -------------------------------------------------------------------------------- /packages/effects/common-ui/src/components/page/types.ts: -------------------------------------------------------------------------------- 1 | export interface PageProps { 2 | title?: string; 3 | description?: string; 4 | contentClass?: string; 5 | /** 6 | * 根据content可见高度自适应 7 | */ 8 | autoContentHeight?: boolean; 9 | headerClass?: string; 10 | footerClass?: string; 11 | } 12 | -------------------------------------------------------------------------------- /packages/effects/common-ui/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components'; 2 | export * from './ui'; 3 | -------------------------------------------------------------------------------- /packages/effects/common-ui/src/ui/about/index.tsx: -------------------------------------------------------------------------------- 1 | export const About = () => { 2 | return
About
; 3 | }; 4 | -------------------------------------------------------------------------------- /packages/effects/common-ui/src/ui/fullback/index.tsx: -------------------------------------------------------------------------------- 1 | export const Fullback = () => { 2 | return
Fullback
; 3 | }; 4 | -------------------------------------------------------------------------------- /packages/effects/common-ui/src/ui/index.ts: -------------------------------------------------------------------------------- 1 | export * from './about'; 2 | export * from './fullback'; 3 | -------------------------------------------------------------------------------- /packages/effects/common-ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@xpress/tsconfig/web.json", 4 | "include": ["src"], 5 | "exclude": ["node_modules"] 6 | } 7 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/AuthenticationFormView.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@xpress-core/shared/utils'; 2 | 3 | export const AuthenticationFormView = ({ 4 | className, 5 | children, 6 | copyright, 7 | }: { 8 | children: React.ReactNode; 9 | className?: string; 10 | copyright: React.ReactNode; 11 | }) => { 12 | return ( 13 |
19 |
20 | {children} 21 |
22 |
23 | {copyright} 24 |
25 |
26 | ); 27 | }; 28 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/Toolbar.tsx: -------------------------------------------------------------------------------- 1 | import { usePreferencesContext } from '@xpress-core/preferences'; 2 | import { cn } from '@xpress-core/shared/utils'; 3 | 4 | import { useMemo } from 'react'; 5 | 6 | import { ThemeToggle } from '../widgets'; 7 | 8 | export const Toolbar = ({ toolbarList }: { toolbarList: string[] }) => { 9 | const { preferences } = usePreferencesContext(); 10 | const showTheme = useMemo(() => { 11 | return toolbarList.includes('theme') && preferences.widget.themeToggle; 12 | }, [toolbarList, preferences.widget.themeToggle]); 13 | return ( 14 |
1 && 'bg-accent rounded-3xl px-3 py-1', 18 | )} 19 | > 20 | {showTheme && } 21 |
22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/icons/android.svg: -------------------------------------------------------------------------------- 1 | Android -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/icons/css3.svg: -------------------------------------------------------------------------------- 1 | CSS3 -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/icons/dart.svg: -------------------------------------------------------------------------------- 1 | Dart -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/icons/express.svg: -------------------------------------------------------------------------------- 1 | Express -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/icons/figma.svg: -------------------------------------------------------------------------------- 1 | Figma -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/icons/flutter.svg: -------------------------------------------------------------------------------- 1 | Flutter -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/icons/git.svg: -------------------------------------------------------------------------------- 1 | Git -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/icons/github.svg: -------------------------------------------------------------------------------- 1 | GitHub -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/icons/gitlab.svg: -------------------------------------------------------------------------------- 1 | GitLab -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/icons/html5.svg: -------------------------------------------------------------------------------- 1 | HTML5 -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/icons/javascript.svg: -------------------------------------------------------------------------------- 1 | JavaScript -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/icons/jira.svg: -------------------------------------------------------------------------------- 1 | Jira -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/icons/nextdotjs.svg: -------------------------------------------------------------------------------- 1 | Next.js -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/icons/nginx.svg: -------------------------------------------------------------------------------- 1 | NGINX -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/icons/prisma.svg: -------------------------------------------------------------------------------- 1 | Prisma -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/icons/sonarqube.svg: -------------------------------------------------------------------------------- 1 | SonarQube -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/icons/vercel.svg: -------------------------------------------------------------------------------- 1 | Vercel -------------------------------------------------------------------------------- /packages/effects/layouts/src/authentication/style.css: -------------------------------------------------------------------------------- 1 | .login-background { 2 | background: linear-gradient( 3 | 154deg, 4 | #07070915 30%, 5 | hsl(var(--primary) / 30%) 48%, 6 | #07070915 64% 7 | ); 8 | filter: blur(100px); 9 | } 10 | 11 | .dark { 12 | .login-background { 13 | background: linear-gradient( 14 | 154deg, 15 | #07070915 30%, 16 | hsl(var(--primary) / 20%) 48%, 17 | #07070915 64% 18 | ); 19 | filter: blur(100px); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/basic/footer/index.tsx: -------------------------------------------------------------------------------- 1 | function Footer({ children }: { children: React.ReactNode }) { 2 | return ( 3 |
4 | {children} 5 |
6 | ); 7 | } 8 | 9 | export default Footer; 10 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/basic/index.ts: -------------------------------------------------------------------------------- 1 | export { default as BasicLayout } from './BasicLayout'; 2 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/basic/login-layout/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rascal-Coder/xpress/175d3625049fd8243be155185d53cafcfbbcebe6/packages/effects/layouts/src/basic/login-layout/.gitkeep -------------------------------------------------------------------------------- /packages/effects/layouts/src/basic/menu/index.ts: -------------------------------------------------------------------------------- 1 | export { default as ExtraMenu } from './extra-menu'; 2 | export { default as Menu } from './menu'; 3 | export { default as MixedMenu } from './mixed-menu'; 4 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/basic/menu/menu/index.tsx: -------------------------------------------------------------------------------- 1 | import type { MenuRecordRaw } from '@xpress-core/typings'; 2 | 3 | import { type MenuProps, MenuView } from '@xpress-core/react-menu'; 4 | 5 | interface Props extends Omit { 6 | menus: MenuRecordRaw[]; 7 | } 8 | function Menu({ 9 | menus = [], 10 | accordion = true, 11 | onOpen, 12 | onSelect, 13 | ...props 14 | }: Props) { 15 | return ( 16 | 23 | ); 24 | } 25 | 26 | export default Menu; 27 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './authentication'; 2 | export * from './basic'; 3 | export * from './widgets/user-dropdown'; 4 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/widgets/fullscreen/index.tsx: -------------------------------------------------------------------------------- 1 | import { Maximize, Minimize } from '@xpress/icons'; 2 | import { useFullscreen } from '@xpress-core/hooks'; 3 | import { XpressButton } from '@xpress-core/shadcn-ui'; 4 | 5 | export function Fullscreen({ className }: { className?: string }) { 6 | const targetRef = document.querySelector('#root'); 7 | const [isFullscreen, { toggleFullscreen }] = useFullscreen(targetRef); 8 | 9 | return ( 10 | 16 | {isFullscreen ? ( 17 | 18 | ) : ( 19 | 20 | )} 21 | 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/widgets/index.ts: -------------------------------------------------------------------------------- 1 | export * from './breadcrumb'; 2 | export * from './fullscreen'; 3 | export * from './global-search'; 4 | export * from './language-toggle'; 5 | export * from './notification'; 6 | export * from './preferences'; 7 | export * from './reload'; 8 | export * from './theme-toggle'; 9 | export * from './user-dropdown'; 10 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/widgets/language-toggle/index.tsx: -------------------------------------------------------------------------------- 1 | import { Languages } from '@xpress/icons'; 2 | import { XpressButton } from '@xpress-core/shadcn-ui'; 3 | 4 | export function LanguageToggle({ className }: { className?: string }) { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/widgets/notification/index.tsx: -------------------------------------------------------------------------------- 1 | import { Bell } from '@xpress/icons'; 2 | import { XpressButton } from '@xpress-core/shadcn-ui'; 3 | 4 | export function Notification() { 5 | return ( 6 |
7 | 12 | 13 | 14 | 15 |
16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/widgets/preferences/blocks/Block.tsx: -------------------------------------------------------------------------------- 1 | export const Block = ({ 2 | title, 3 | children, 4 | }: { 5 | children: React.ReactNode; 6 | title?: string; 7 | }) => { 8 | return ( 9 |
10 |

11 | {title} 12 |

13 | {children} 14 |
15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/widgets/preferences/blocks/general/General.tsx: -------------------------------------------------------------------------------- 1 | import { usePreferencesContext } from '@xpress-core/preferences'; 2 | 3 | import { SwitchItem } from '../SwitchItem'; 4 | 5 | export const General = () => { 6 | const { preferences, updatePreferences } = usePreferencesContext(); 7 | return ( 8 | <> 9 | { 12 | updatePreferences({ app: { dynamicTitle: value } }); 13 | }} 14 | > 15 | 动态标题 16 | 17 | { 20 | updatePreferences({ app: { watermark: value } }); 21 | }} 22 | > 23 | 水印 24 | 25 | { 28 | updatePreferences({ app: { enableCheckUpdates: value } }); 29 | }} 30 | > 31 | 自动检查更新 32 | 33 | 34 | ); 35 | }; 36 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/widgets/preferences/blocks/general/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Animation'; 2 | export * from './General'; 3 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/widgets/preferences/blocks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Block'; 2 | export * from './general'; 3 | export * from './layout'; 4 | export * from './shortcutkey'; 5 | export * from './theme'; 6 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/widgets/preferences/blocks/layout/Footer.tsx: -------------------------------------------------------------------------------- 1 | import { usePreferencesContext } from '@xpress-core/preferences'; 2 | 3 | import { SwitchItem } from '../SwitchItem'; 4 | 5 | export const Footer = () => { 6 | const { preferences, updatePreferences } = usePreferencesContext(); 7 | return ( 8 | <> 9 | { 12 | updatePreferences({ footer: { enable: checked } }); 13 | }} 14 | > 15 | 显示页脚 16 | 17 | { 21 | updatePreferences({ footer: { fixed: checked } }); 22 | }} 23 | > 24 | 固定页脚 25 | 26 | 27 | ); 28 | }; 29 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/widgets/preferences/blocks/layout/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Breadcrumb'; 2 | export * from './Content'; 3 | export * from './Copyright'; 4 | export * from './Footer'; 5 | export * from './Header'; 6 | export * from './Layout'; 7 | export * from './Navigation'; 8 | export * from './Sidebar'; 9 | export * from './Tabbar'; 10 | export * from './Widget'; 11 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/widgets/preferences/blocks/shortcutkey/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Global'; 2 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/widgets/preferences/blocks/theme/Other.tsx: -------------------------------------------------------------------------------- 1 | import { usePreferencesContext } from '@xpress-core/preferences'; 2 | 3 | import { SwitchItem } from '../SwitchItem'; 4 | 5 | export const Other = () => { 6 | const { updatePreferences, preferences } = usePreferencesContext(); 7 | return ( 8 | <> 9 | 12 | updatePreferences({ app: { colorWeakMode: checked } }) 13 | } 14 | > 15 | 色弱模式 16 | 17 | 20 | updatePreferences({ app: { colorGrayMode: checked } }) 21 | } 22 | > 23 | 灰色模式 24 | 25 | 26 | ); 27 | }; 28 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/widgets/preferences/blocks/theme/index.ts: -------------------------------------------------------------------------------- 1 | export * from './BuiltinTheme'; 2 | export * from './Other'; 3 | export * from './Radius'; 4 | export * from './Theme'; 5 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/widgets/preferences/icons/Setting.tsx: -------------------------------------------------------------------------------- 1 | export const Setting = () => { 2 | return ( 3 | <> 4 | 10 | 11 | 12 | 13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/widgets/preferences/icons/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './ContentCompact'; 2 | export * from './FullContent'; 3 | export * from './HeaderMixedNav'; 4 | export * from './HeaderNav'; 5 | export * from './HeaderSidebarNav'; 6 | export * from './MixedNav'; 7 | export * from './Setting'; 8 | export * from './SidebarMixedNav'; 9 | export * from './SidebarNav'; 10 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/widgets/preferences/index.tsx: -------------------------------------------------------------------------------- 1 | import { Settings } from '@xpress/icons'; 2 | import { XpressButton } from '@xpress-core/shadcn-ui'; 3 | import { cn } from '@xpress-core/shared/utils'; 4 | 5 | import { useState } from 'react'; 6 | 7 | import { PreferencesDrawer } from './PreferencesDrawer'; 8 | 9 | export function Preferences({ className }: { className?: string }) { 10 | const [isOpen, setIsOpen] = useState(false); 11 | return ( 12 | <> 13 |
14 | setIsOpen(true)} 16 | size="icon" 17 | variant="icon" 18 | > 19 | 20 | 21 | 22 |
23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/widgets/preferences/modules/appearance/index.tsx: -------------------------------------------------------------------------------- 1 | import { Block, BuiltinTheme, Other, Radius, Theme } from '../../blocks'; 2 | 3 | export const PreferencesAppearance = () => { 4 | return ( 5 | <> 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/widgets/preferences/modules/general/index.tsx: -------------------------------------------------------------------------------- 1 | import { Animation, Block, General } from '../../blocks'; 2 | 3 | export const PreferencesGeneral = () => { 4 | return ( 5 | <> 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /packages/effects/layouts/src/widgets/preferences/modules/layout/index.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Block, 3 | Breadcrumb, 4 | Content, 5 | Copyright, 6 | Footer, 7 | Header, 8 | Layout, 9 | Navigation, 10 | Sidebar, 11 | Tabbar, 12 | Widget, 13 | } from '../../blocks'; 14 | 15 | export const PreferencesLayout = () => { 16 | return ( 17 | <> 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |