├── .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 |
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 |
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 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/authentication/icons/css3.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/authentication/icons/dart.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/authentication/icons/express.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/authentication/icons/figma.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/authentication/icons/flutter.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/authentication/icons/git.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/authentication/icons/github.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/authentication/icons/gitlab.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/authentication/icons/html5.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/authentication/icons/javascript.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/authentication/icons/jira.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/authentication/icons/nextdotjs.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/authentication/icons/nginx.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/authentication/icons/prisma.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/authentication/icons/sonarqube.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/authentication/icons/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/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 |
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 |
44 |
45 |
46 |
47 |
48 | >
49 | );
50 | };
51 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/widgets/preferences/modules/shortcutkey/index.tsx:
--------------------------------------------------------------------------------
1 | import { Block, Global } from '../../blocks';
2 |
3 | export const PreferencesShortcutKey = () => {
4 | return (
5 |
6 |
7 |
8 | );
9 | };
10 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/widgets/reload/index.tsx:
--------------------------------------------------------------------------------
1 | import { RotateCw } from '@xpress/icons';
2 | import { useTabbar } from '@xpress/stores';
3 | import { XpressButton } from '@xpress-core/shadcn-ui';
4 |
5 | export function Reload() {
6 | const { refresh } = useTabbar();
7 | return (
8 | {
10 | refresh();
11 | }}
12 | size="icon"
13 | style={{ padding: '7px' }}
14 | variant="icon"
15 | >
16 |
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/widgets/theme-toggle/ThemeToggle.tsx:
--------------------------------------------------------------------------------
1 | import { usePreferencesContext } from '@xpress-core/preferences';
2 |
3 | import { ThemeButton } from './ThemeButton';
4 |
5 | interface ThemeToggleProps {
6 | className?: string;
7 | }
8 |
9 | export function ThemeToggle({ className }: ThemeToggleProps) {
10 | const { isDark, updatePreferences } = usePreferencesContext();
11 |
12 | const handleChange = (isDark: boolean) => {
13 | updatePreferences({
14 | theme: { mode: isDark ? 'dark' : 'light' },
15 | });
16 | };
17 |
18 | return (
19 |
20 |
21 |
22 | );
23 | }
24 |
--------------------------------------------------------------------------------
/packages/effects/layouts/src/widgets/theme-toggle/index.ts:
--------------------------------------------------------------------------------
1 | export * from './ThemeButton';
2 | export * from './ThemeToggle';
3 |
--------------------------------------------------------------------------------
/packages/effects/layouts/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/request/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@xpress/request",
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 | "axios": "^1.8.4",
18 | "qs": "^6.14.0"
19 | },
20 | "devDependencies": {
21 | "@types/qs": "^6.9.18",
22 | "axios-mock-adapter": "^2.1.0"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/effects/request/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './request-client';
2 | export * from 'axios';
3 |
--------------------------------------------------------------------------------
/packages/effects/request/src/request-client/index.ts:
--------------------------------------------------------------------------------
1 | export * from './preset-interceptors';
2 | export * from './request-client';
3 | export type * from './types';
4 |
--------------------------------------------------------------------------------
/packages/effects/request/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/router-toolset/build.config.ts:
--------------------------------------------------------------------------------
1 | import { defineBuildConfig } from 'unbuild';
2 |
3 | export default defineBuildConfig({
4 | clean: true,
5 | declaration: true,
6 | entries: ['src/index'],
7 | failOnWarn: false,
8 | rollup: {
9 | emitCJS: true,
10 | esbuild: {
11 | jsx: 'automatic',
12 | jsxImportSource: 'react',
13 | minify: true,
14 | treeShaking: true,
15 | tsconfigRaw: {
16 | compilerOptions: {
17 | jsx: 'react-jsx',
18 | },
19 | },
20 | },
21 | inlineDependencies: true,
22 | },
23 | });
24 |
--------------------------------------------------------------------------------
/packages/effects/router-toolset/src/HistoryRouter.tsx:
--------------------------------------------------------------------------------
1 | import type { BrowserHistory } from 'history';
2 |
3 | import { useLayoutEffect, useState } from 'react';
4 | import { Router } from 'react-router-dom';
5 |
6 | export interface HistoryRouterProps {
7 | basename?: string;
8 | children?: React.ReactNode;
9 | history: BrowserHistory;
10 | }
11 |
12 | export default function HistoryRouter({
13 | basename,
14 | history,
15 | children,
16 | }: HistoryRouterProps) {
17 | const [state, setState] = useState({
18 | action: history.action,
19 | location: history.location,
20 | });
21 |
22 | useLayoutEffect(() => history.listen(setState), [history]);
23 |
24 | return (
25 |
31 | {children}
32 |
33 | );
34 | }
35 |
--------------------------------------------------------------------------------
/packages/effects/router-toolset/src/history.ts:
--------------------------------------------------------------------------------
1 | import { createBrowserHistory } from 'history';
2 |
3 | const history = createBrowserHistory();
4 |
5 | export default history;
6 |
--------------------------------------------------------------------------------
/packages/effects/router-toolset/src/index.ts:
--------------------------------------------------------------------------------
1 | export { default as history } from './history';
2 |
3 | export { default as HistoryRouter } from './HistoryRouter';
4 |
5 | export { Router, useRouter } from './router';
6 |
7 | export * from './utils';
8 | export * from 'react-router-dom';
9 |
--------------------------------------------------------------------------------
/packages/effects/router-toolset/src/utils/generate-routes-frontend.ts:
--------------------------------------------------------------------------------
1 | import type { RouteConfig } from '@xpress-core/typings';
2 |
3 | import { filterTree, mapTree } from '@xpress-core/shared/utils';
4 |
5 | import { hasPermission, menuHasVisibleWithForbidden } from './common';
6 |
7 | /**
8 | * 动态生成路由 - 前端方式
9 | */
10 | async function generateRoutesByFrontend(
11 | routes: RouteConfig[],
12 | roles: string[],
13 | forbiddenComponent?: RouteConfig['component'],
14 | ): Promise {
15 | // 根据角色标识过滤路由表,判断当前用户是否拥有指定权限
16 | const finalRoutes = filterTree(routes, (route) => {
17 | return hasPermission(route, roles);
18 | });
19 |
20 | if (!forbiddenComponent) {
21 | return finalRoutes;
22 | }
23 |
24 | // 如果有禁止访问的页面,将禁止访问的页面替换为403页面
25 | return mapTree(finalRoutes, (route) => {
26 | if (menuHasVisibleWithForbidden(route)) {
27 | route.component = forbiddenComponent;
28 | }
29 | return route;
30 | });
31 | }
32 |
33 | export { generateRoutesByFrontend };
34 |
--------------------------------------------------------------------------------
/packages/effects/router-toolset/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | export * from './accessible';
2 | export * from './common';
3 | export * from './generate-menus';
4 | export * from './generate-routes-backend';
5 | export * from './generate-routes-frontend';
6 | export * from './merge-route-modules';
7 |
--------------------------------------------------------------------------------
/packages/effects/router-toolset/src/utils/merge-route-modules.ts:
--------------------------------------------------------------------------------
1 | import type { RouteConfig } from '@xpress-core/typings';
2 |
3 | // 定义模块类型
4 | interface RouteModuleType {
5 | default: RouteConfig[];
6 | }
7 |
8 | /**
9 | * 合并动态路由模块的默认导出 import.meta.default
10 | * @param routeModules 动态导入的路由模块对象
11 | * @returns 合并后的路由配置数组
12 | */
13 | function mergeRouteModules(
14 | routeModules: Record,
15 | ): RouteConfig[] {
16 | const mergedRoutes: RouteConfig[] = [];
17 |
18 | for (const routeModule of Object.values(routeModules)) {
19 | const moduleRoutes = (routeModule as RouteModuleType)?.default ?? [];
20 | mergedRoutes.push(...moduleRoutes);
21 | }
22 |
23 | return mergedRoutes;
24 | }
25 |
26 | export { mergeRouteModules };
27 |
28 | export type { RouteModuleType };
29 |
--------------------------------------------------------------------------------
/packages/effects/router-toolset/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/icons/README.md:
--------------------------------------------------------------------------------
1 | # @xpress/icons
2 |
--------------------------------------------------------------------------------
/packages/icons/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@xpress/icons",
3 | "version": "1.0.0",
4 | "license": "MIT",
5 | "type": "module",
6 | "exports": {
7 | ".": {
8 | "types": "./src/index.ts",
9 | "default": "./src/index.ts"
10 | }
11 | },
12 | "dependencies": {
13 | "@xpress-core/icons": "workspace:*"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/packages/icons/src/iconify/index.ts:
--------------------------------------------------------------------------------
1 | import { createIconifyIcon } from '@xpress-core/icons';
2 |
3 | export * from '@xpress-core/icons';
4 |
5 | export const MdiKeyboardEsc = createIconifyIcon('mdi:keyboard-esc');
6 |
7 | export const MdiWechat = createIconifyIcon('mdi:wechat');
8 |
9 | export const MdiGithub = createIconifyIcon('mdi:github');
10 |
11 | export const MdiGoogle = createIconifyIcon('mdi:google');
12 |
13 | export const MdiQqchat = createIconifyIcon('mdi:qqchat');
14 |
--------------------------------------------------------------------------------
/packages/icons/src/icons/EmptyIcon.tsx:
--------------------------------------------------------------------------------
1 | function EmptyIcon() {
2 | return null;
3 | }
4 |
5 | export default EmptyIcon;
6 |
--------------------------------------------------------------------------------
/packages/icons/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './iconify';
2 | export { default as EmptyIcon } from './icons/EmptyIcon';
3 | export * from './svg';
4 |
--------------------------------------------------------------------------------
/packages/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/stores/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@xpress/stores",
3 | "version": "1.0.0",
4 | "license": "MIT",
5 | "author": "",
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-core/preferences": "workspace:*",
18 | "@xpress-core/shared": "workspace:*",
19 | "@xpress-core/tabs-ui": "workspace:*",
20 | "@xpress-core/typings": "workspace:*",
21 | "nprogress": "catalog:",
22 | "react-router-dom": "catalog:",
23 | "zustand": "catalog:"
24 | },
25 | "devDependencies": {
26 | "@types/nprogress": "catalog:"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/packages/stores/src/index.ts:
--------------------------------------------------------------------------------
1 | import { useAccessStore } from './access';
2 | import { useUserStore } from './user';
3 |
4 | export * from './access';
5 | export * from './tabbar';
6 | export * from './user';
7 |
8 | export const resetAllStores = () => {
9 | useAccessStore.getState().reset();
10 | useUserStore.getState().reset();
11 | };
12 |
--------------------------------------------------------------------------------
/packages/stores/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "extends": "@xpress/tsconfig/web.json",
4 | "include": ["src"]
5 | }
6 |
--------------------------------------------------------------------------------
/packages/styles/README.md:
--------------------------------------------------------------------------------
1 | # @xpress/styles
2 |
3 | 用于多个 `app` 公用的样式文件,继承了 `@xpress-core/design` 的所有能力。业务上有通用的样式文件可以放在这里。
4 |
--------------------------------------------------------------------------------
/packages/styles/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@xpress/styles",
3 | "version": "1.0.0",
4 | "license": "MIT",
5 | "type": "module",
6 | "exports": {
7 | ".": {
8 | "types": "./src/index.ts",
9 | "default": "./src/index.ts"
10 | },
11 | "./global": {
12 | "default": "./src/global/index.scss"
13 | }
14 | },
15 | "dependencies": {
16 | "@xpress-core/design": "workspace:*"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/packages/styles/src/global/index.scss:
--------------------------------------------------------------------------------
1 | @use '@xpress-core/design/bem' as *;
2 |
--------------------------------------------------------------------------------
/packages/styles/src/index.ts:
--------------------------------------------------------------------------------
1 | import '@xpress-core/design';
2 |
--------------------------------------------------------------------------------
/packages/styles/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/utils/README.md:
--------------------------------------------------------------------------------
1 | # @xpress/utils
2 |
3 | ## 用法
4 |
5 | ### 添加依赖
6 |
7 | ```bash
8 | # 进入目标应用目录,例如 apps/xxxx-app
9 | # cd apps/xxxx-app
10 | pnpm add @xpress/utils
11 | ```
12 |
--------------------------------------------------------------------------------
/packages/utils/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@xpress/utils",
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 | "@xpress-core/typings": "workspace:*"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/packages/utils/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './unmount-global-loading';
2 | export * from './use-app-config';
3 | export * from '@xpress-core/shared/cache';
4 | export * from '@xpress-core/shared/color';
5 | export * from '@xpress-core/shared/utils';
6 |
--------------------------------------------------------------------------------
/packages/utils/src/unmount-global-loading.ts:
--------------------------------------------------------------------------------
1 | export function unmountGlobalLoading() {
2 | // 查找全局 loading 元素
3 | const loadingElement = document.querySelector('#__app-loading__');
4 |
5 | if (loadingElement) {
6 | // 添加隐藏类,触发过渡动画
7 | loadingElement.classList.add('hidden');
8 |
9 | // 查找所有需要移除的注入 loading 元素
10 | const injectLoadingElements = document.querySelectorAll(
11 | '[data-app-loading^="inject"]',
12 | );
13 |
14 | // 当过渡动画结束时,移除 loading 元素和所有注入的 loading 元素
15 | loadingElement.addEventListener(
16 | 'transitionend',
17 | () => {
18 | loadingElement.remove(); // 移除 loading 元素
19 | injectLoadingElements.forEach((el) => el.remove()); // 移除所有注入的 loading 元素
20 | },
21 | { once: true },
22 | ); // 确保事件只触发一次
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/utils/src/use-app-config.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | ApplicationConfig,
3 | XpressAdminProAppConfigRaw,
4 | } from '@xpress-core/typings';
5 |
6 | /**
7 | * 由 vite-inject-app-config 注入的全局配置
8 | */
9 | export function useAppConfig(
10 | env: Record,
11 | isProduction: boolean,
12 | ): ApplicationConfig {
13 | // 生产环境下,直接使用 window._XPRESS_ADMIN_PRO_APP_CONF_ 全局变量
14 | const config = isProduction
15 | ? window._XPRESS_ADMIN_PRO_APP_CONF_
16 | : (env as XpressAdminProAppConfigRaw);
17 |
18 | const { VITE_GLOB_API_URL } = config;
19 |
20 | return {
21 | apiURL: VITE_GLOB_API_URL,
22 | };
23 | }
24 |
--------------------------------------------------------------------------------
/packages/utils/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 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | []tab右键菜单bug
2 |
--------------------------------------------------------------------------------
/scripts/cli/README.md:
--------------------------------------------------------------------------------
1 | # @xpress/vsh
2 |
3 | shell 脚本工具集合
4 |
--------------------------------------------------------------------------------
/scripts/cli/bin/xpress.mjs:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | import('../dist/index.mjs');
4 |
--------------------------------------------------------------------------------
/scripts/cli/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 |
--------------------------------------------------------------------------------
/scripts/cli/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@xpress/cli",
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 | "bin": {
14 | "xpress": "./bin/xpress.mjs"
15 | },
16 | "main": "./dist/index.mjs",
17 | "module": "./dist/index.mjs",
18 | "exports": {
19 | ".": {
20 | "default": "./dist/index.mjs"
21 | },
22 | "./package.json": "./package.json"
23 | },
24 | "dependencies": {
25 | "@clack/prompts": "catalog:",
26 | "@xpress/node-utils": "workspace:*",
27 | "cac": "catalog:",
28 | "circular-dependency-scanner": "catalog:",
29 | "depcheck": "catalog:",
30 | "publint": "catalog:"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/scripts/cli/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 |
--------------------------------------------------------------------------------
/scripts/turbo-run/README.md:
--------------------------------------------------------------------------------
1 | # @xpress/turbo-run
2 |
3 | turbo-run is a command line tool that allows you to run multiple commands in parallel.
4 |
--------------------------------------------------------------------------------
/scripts/turbo-run/bin/turbo-run.mjs:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | import('../dist/index.mjs');
4 |
--------------------------------------------------------------------------------
/scripts/turbo-run/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 |
--------------------------------------------------------------------------------
/scripts/turbo-run/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@xpress/turbo-run",
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 | "bin": {
14 | "turbo-run": "./bin/turbo-run.mjs"
15 | },
16 | "main": "./dist/index.mjs",
17 | "module": "./dist/index.mjs",
18 | "exports": {
19 | ".": {
20 | "default": "./dist/index.mjs"
21 | },
22 | "./package.json": "./package.json"
23 | },
24 | "dependencies": {
25 | "@clack/prompts": "catalog:",
26 | "@xpress/node-utils": "workspace:*",
27 | "cac": "catalog:"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/scripts/turbo-run/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 |
--------------------------------------------------------------------------------
/stylelint.config.mjs:
--------------------------------------------------------------------------------
1 | export default {
2 | extends: ['@xpress/stylelint-config'],
3 | root: true,
4 | };
5 |
--------------------------------------------------------------------------------
/turbo.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://turbo.build/schema.json",
3 | "globalDependencies": [
4 | "pnpm-lock.yaml",
5 | "**/.env.*local",
6 | "**/tsconfig*.json",
7 | "internal/node-utils/*.json",
8 | "internal/node-utils/src/**/*.ts",
9 | "scripts/*/src/**/*.ts",
10 | "scripts/*/src/**/*.json"
11 | ],
12 | "globalEnv": ["NODE_ENV"],
13 | "tasks": {
14 | "build": {
15 | "dependsOn": ["^build"],
16 | "outputs": ["dist/**", "build/client/**"]
17 | },
18 | "preview": {
19 | "dependsOn": ["^build"],
20 | "outputs": ["dist/**", "build/client/**"]
21 | },
22 | "build:analyze": {
23 | "dependsOn": ["^build"],
24 | "outputs": ["dist/**"]
25 | },
26 | "@xpress/backend-mock#build": {
27 | "dependsOn": ["^build"],
28 | "outputs": [".nitro/**", ".output/**"]
29 | },
30 | "test:e2e": {},
31 | "dev": {
32 | "dependsOn": [],
33 | "outputs": [],
34 | "cache": false,
35 | "persistent": true
36 | },
37 | "typecheck": {
38 | "outputs": []
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/vercel.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 2,
3 | "buildCommand": "pnpm run build:mock",
4 | "outputDirectory": "apps/backend-mock/.output",
5 | "builds": [
6 | {
7 | "src": "apps/backend-mock/.output/server/index.mjs",
8 | "use": "@vercel/node"
9 | }
10 | ],
11 | "routes": [
12 | {
13 | "src": "/(.*)",
14 | "dest": "apps/backend-mock/.output/server/index.mjs"
15 | }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/vitest.config.ts:
--------------------------------------------------------------------------------
1 | import { configDefaults, defineConfig } from 'vitest/config';
2 |
3 | // export default defineConfig({
4 | // // plugins: [Vue(), VueJsx()],
5 | // test: {
6 | // environment: 'happy-dom',
7 | // exclude: [...configDefaults.exclude, '**/e2e/**'],
8 | // },
9 | // });
10 | export default defineConfig({
11 | test: {
12 | environment: 'jsdom',
13 | exclude: [...configDefaults.exclude, '**/e2e/**'],
14 | globals: true,
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/vitest.workspace.ts:
--------------------------------------------------------------------------------
1 | import { defineWorkspace } from 'vitest/config';
2 |
3 | export default defineWorkspace(['vitest.config.ts']);
4 |
--------------------------------------------------------------------------------