├── client ├── src │ ├── website │ │ ├── configs │ │ │ └── .gitkeep │ │ ├── services │ │ │ ├── chat │ │ │ │ └── .gitkeep │ │ │ ├── notify │ │ │ │ ├── @notify-service.dto.ts │ │ │ │ ├── index.ts │ │ │ │ └── @notify-service.api.ts │ │ │ ├── http │ │ │ │ ├── index.ts │ │ │ │ └── @interceptors │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── res-error-catcher.ts │ │ │ │ │ ├── res-data.ts │ │ │ │ │ └── request-type.ts │ │ │ ├── category │ │ │ │ ├── index.ts │ │ │ │ └── @category-service.api.ts │ │ │ ├── markdown-service │ │ │ │ ├── index.ts │ │ │ │ ├── @plugins │ │ │ │ │ ├── index.ts │ │ │ │ │ └── inline-processor.tsx │ │ │ │ └── @markdown-config.ts │ │ │ ├── observer │ │ │ │ ├── index.ts │ │ │ │ ├── observer.ts │ │ │ │ └── subject.ts │ │ │ ├── regex │ │ │ │ ├── index.ts │ │ │ │ ├── regex.ts │ │ │ │ └── regex-utils.ts │ │ │ ├── time │ │ │ │ ├── index.ts │ │ │ │ ├── time-utils.ts │ │ │ │ └── time-service.ts │ │ │ ├── user │ │ │ │ ├── index.ts │ │ │ │ ├── @user-service.api.ts │ │ │ │ └── user-service.dto.ts │ │ │ ├── document │ │ │ │ ├── index.ts │ │ │ │ ├── document-service.dto.ts │ │ │ │ └── @document-service.api.ts │ │ │ ├── route │ │ │ │ ├── guards │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── deactivated-guard.ts │ │ │ │ │ └── activated-guard.ts │ │ │ │ └── index.ts │ │ │ ├── permission │ │ │ │ ├── index.ts │ │ │ │ ├── @permission-service.api.ts │ │ │ │ ├── permission-service.dto.ts │ │ │ │ └── permission-service.ts │ │ │ ├── organization │ │ │ │ ├── index.ts │ │ │ │ ├── @organization-service.api.ts │ │ │ │ └── organization-service.dto.ts │ │ │ ├── dialog │ │ │ │ └── index.ts │ │ │ ├── message │ │ │ │ ├── index.ts │ │ │ │ └── message-service.api.ts │ │ │ ├── arrow-cache.ts │ │ │ ├── catalog-service.ts │ │ │ ├── tab-service.ts │ │ │ ├── backdrop-service.ts │ │ │ ├── doc-service.ts │ │ │ ├── toast.ts │ │ │ ├── jwt-service.ts │ │ │ ├── index.ts │ │ │ ├── todo-service.ts │ │ │ └── draft-service.ts │ │ ├── assets │ │ │ ├── index.ts │ │ │ ├── static │ │ │ │ ├── main.png │ │ │ │ ├── wand.png │ │ │ │ ├── github.png │ │ │ │ ├── phone.png │ │ │ │ ├── rabbit.png │ │ │ │ ├── wizard.png │ │ │ │ ├── loading.gif │ │ │ │ ├── magic_wand.png │ │ │ │ ├── main_cover.png │ │ │ │ ├── wizard-card.png │ │ │ │ ├── advantage │ │ │ │ │ ├── chat.png │ │ │ │ │ ├── phone.png │ │ │ │ │ ├── font_docs.png │ │ │ │ │ ├── swagger.png │ │ │ │ │ └── open_source.png │ │ │ │ ├── organization.png │ │ │ │ ├── wizard-white.jpg │ │ │ │ ├── wizard_person.png │ │ │ │ ├── magic_wand_white.png │ │ │ │ ├── default_categories.png │ │ │ │ ├── register_successful.png │ │ │ │ ├── wizard-card-variant.png │ │ │ │ ├── wizard_person_white.png │ │ │ │ └── wizard-card-variant2.png │ │ │ ├── iconfont │ │ │ │ ├── iconfont.eot │ │ │ │ ├── iconfont.ttf │ │ │ │ ├── iconfont.woff │ │ │ │ └── iconfont.woff2 │ │ │ └── svg.tsx │ │ ├── ui │ │ │ ├── menu │ │ │ │ └── index.ts │ │ │ ├── drawer │ │ │ │ ├── index.ts │ │ │ │ └── drawer.tsx │ │ │ ├── search │ │ │ │ ├── index.ts │ │ │ │ └── @search-prompt.tsx │ │ │ ├── catalog │ │ │ │ └── index.ts │ │ │ ├── breadcrumbs │ │ │ │ └── index.ts │ │ │ ├── upload │ │ │ │ ├── index.ts │ │ │ │ └── type-upload.tsx │ │ │ ├── tree-view │ │ │ │ └── index.ts │ │ │ ├── form-control │ │ │ │ └── index.ts │ │ │ ├── input │ │ │ │ ├── index.ts │ │ │ │ ├── normal.tsx │ │ │ │ └── input.ts │ │ │ ├── button │ │ │ │ ├── index.ts │ │ │ │ └── button.ts │ │ │ ├── link.tsx │ │ │ ├── view-way.tsx │ │ │ ├── carpet.tsx │ │ │ ├── form-text-field.tsx │ │ │ ├── center.tsx │ │ │ ├── index.ts │ │ │ ├── line.tsx │ │ │ └── drawer-header.tsx │ │ ├── utils │ │ │ ├── page.ts │ │ │ ├── svg-generator.tsx │ │ │ ├── diff.ts │ │ │ ├── MIME.ts │ │ │ ├── sync.ts │ │ │ ├── color-generator.ts │ │ │ ├── initialize.ts │ │ │ ├── import.ts │ │ │ ├── viewport-listener.ts │ │ │ ├── store-injector.ts │ │ │ ├── index.ts │ │ │ ├── env.ts │ │ │ └── storage.ts │ │ ├── components │ │ │ ├── footer │ │ │ │ ├── index.ts │ │ │ │ ├── @panel │ │ │ │ │ ├── index.ts │ │ │ │ │ └── footer-panel.tsx │ │ │ │ └── footer.tsx │ │ │ ├── doc │ │ │ │ ├── share │ │ │ │ │ ├── index.ts │ │ │ │ │ └── @shape.tsx │ │ │ │ ├── index.ts │ │ │ │ └── doc-page │ │ │ │ │ ├── index.ts │ │ │ │ │ └── organization-info-card.tsx │ │ │ ├── overview │ │ │ │ ├── @common │ │ │ │ │ ├── index.ts │ │ │ │ │ └── form.tsx │ │ │ │ ├── overview-side │ │ │ │ │ └── index.ts │ │ │ │ ├── overview-header │ │ │ │ │ ├── index.ts │ │ │ │ │ └── overview-header.tsx │ │ │ │ ├── overview-docs │ │ │ │ │ ├── category │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── document │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── document-title.tsx │ │ │ │ │ │ └── create-document-header.tsx │ │ │ │ │ └── overview-doc-cards.tsx │ │ │ │ ├── organization-edit │ │ │ │ │ ├── index.ts │ │ │ │ │ └── member-manager │ │ │ │ │ │ ├── invite-member-dialog │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── index.ts │ │ │ │ └── index.ts │ │ │ ├── pen │ │ │ │ ├── original │ │ │ │ │ └── index.ts │ │ │ │ ├── utils │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── @list-utils.ts │ │ │ │ │ ├── @text-utils.ts │ │ │ │ │ ├── @func-utils.ts │ │ │ │ │ └── @markdown-utils.ts │ │ │ │ ├── viewer │ │ │ │ │ ├── index.ts │ │ │ │ │ └── viewer.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── pen-header.tsx │ │ │ │ └── pen.tsx │ │ │ ├── register │ │ │ │ └── index.ts │ │ │ ├── common │ │ │ │ ├── side-bar │ │ │ │ │ └── index.ts │ │ │ │ ├── upload │ │ │ │ │ ├── index.ts │ │ │ │ │ └── image-upload.tsx │ │ │ │ ├── transition-fab │ │ │ │ │ └── index.ts │ │ │ │ ├── markdown │ │ │ │ │ ├── @function-pannel │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── function-panel.tsx │ │ │ │ │ │ └── @document-info-block.tsx │ │ │ │ │ ├── document-comments │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── render-components │ │ │ │ │ │ ├── link.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── text.tsx │ │ │ │ │ │ ├── inline-code.tsx │ │ │ │ │ │ ├── block-quote.tsx │ │ │ │ │ │ ├── heading.tsx │ │ │ │ │ │ └── img.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── @document-catalog.tsx │ │ │ │ │ └── markdown-header.tsx │ │ │ │ ├── avatar │ │ │ │ │ ├── index.ts │ │ │ │ │ └── current-avatar.tsx │ │ │ │ ├── dialogs │ │ │ │ │ └── index.ts │ │ │ │ ├── invite-member-box │ │ │ │ │ └── index.ts │ │ │ │ ├── tab │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── tab-content.tsx │ │ │ │ │ └── tab-content-item.tsx │ │ │ │ ├── loading │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── normal-loading.tsx │ │ │ │ │ ├── backdrop-loading.tsx │ │ │ │ │ └── inline-loading.tsx │ │ │ │ ├── fab.tsx │ │ │ │ ├── lazy-loading.tsx │ │ │ │ ├── overview-title.tsx │ │ │ │ ├── md-render.tsx │ │ │ │ ├── login-permission.tsx │ │ │ │ ├── fab-card.tsx │ │ │ │ ├── layout-toggle.tsx │ │ │ │ ├── index.ts │ │ │ │ └── default-view.tsx │ │ │ ├── main │ │ │ │ ├── knowledge-card │ │ │ │ │ └── index.ts │ │ │ │ ├── main-header-bar │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── main-header-bar.tsx │ │ │ │ │ └── @main-header-buttons.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── graphic │ │ │ │ │ └── index.ts │ │ │ │ ├── @skew-block.tsx │ │ │ │ ├── advantage-cards.tsx │ │ │ │ └── main-content.tsx │ │ │ ├── community │ │ │ │ ├── document-list │ │ │ │ │ ├── index.ts │ │ │ │ │ └── document-list.tsx │ │ │ │ └── index.ts │ │ │ ├── message-center │ │ │ │ ├── message-side │ │ │ │ │ ├── index.ts │ │ │ │ │ └── message-side.tsx │ │ │ │ ├── message-header │ │ │ │ │ └── index.ts │ │ │ │ ├── message-overview │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── @message-tag.tsx │ │ │ │ │ └── @message-tag-config.tsx │ │ │ │ ├── views │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── message-trash.tsx │ │ │ │ │ ├── user-message.tsx │ │ │ │ │ ├── system-message.tsx │ │ │ │ │ └── message-panel.tsx │ │ │ │ ├── index.ts │ │ │ │ └── message-switcher.tsx │ │ │ ├── access │ │ │ │ ├── props.tsx │ │ │ │ └── username.tsx │ │ │ ├── optional-tip │ │ │ │ ├── index.ts │ │ │ │ └── todo │ │ │ │ │ └── index.ts │ │ │ ├── about │ │ │ │ ├── index.ts │ │ │ │ ├── contributors.tsx │ │ │ │ └── contributor-avatar.tsx │ │ │ ├── release-banner │ │ │ │ ├── index.ts │ │ │ │ ├── release-tag.tsx │ │ │ │ └── release-banner.tsx │ │ │ ├── user-detail │ │ │ │ ├── index.ts │ │ │ │ ├── organization-detail-card.tsx │ │ │ │ └── user-card.tsx │ │ │ ├── header-bar │ │ │ │ ├── index.ts │ │ │ │ └── @icon-funcs.tsx │ │ │ ├── user │ │ │ │ ├── index.ts │ │ │ │ └── @user-avatar │ │ │ │ │ └── index.ts │ │ │ ├── user-settings │ │ │ │ ├── index.ts │ │ │ │ └── settings-title.tsx │ │ │ ├── @login.tsx │ │ │ ├── organization │ │ │ │ └── index.ts │ │ │ ├── doc-recent-update-drawer.tsx │ │ │ └── index.ts │ │ ├── pages │ │ │ ├── document-pages │ │ │ │ ├── index.ts │ │ │ │ └── document-center.tsx │ │ │ ├── organization-pages │ │ │ │ ├── index.ts │ │ │ │ └── select-organization │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── select-organization.tsx │ │ │ │ │ └── empty-organization.tsx │ │ │ ├── overview │ │ │ │ ├── index.ts │ │ │ │ └── overview-organization.tsx │ │ │ ├── why-use.tsx │ │ │ ├── page-not-found.tsx │ │ │ ├── user-pages │ │ │ │ ├── index.ts │ │ │ │ ├── user-settings │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── user-settings-phone.tsx │ │ │ │ │ └── user-settings.tsx │ │ │ │ └── user-detail.tsx │ │ │ ├── common-style-component │ │ │ │ ├── tip.tsx │ │ │ │ ├── access-wrapper.tsx │ │ │ │ └── center.tsx │ │ │ ├── community.tsx │ │ │ ├── doc.tsx │ │ │ ├── public-space.tsx │ │ │ ├── message-center.tsx │ │ │ └── document-detail.tsx │ │ ├── guards │ │ │ ├── organizations │ │ │ │ ├── index.ts │ │ │ │ └── organization-empty-guard.ts │ │ │ ├── index.ts │ │ │ └── overview │ │ │ │ ├── index.ts │ │ │ │ ├── overview-auth.ts │ │ │ │ └── organization-guard.ts │ │ ├── constant │ │ │ ├── apis │ │ │ │ ├── doc.ts │ │ │ │ ├── upload.ts │ │ │ │ ├── todo.ts │ │ │ │ ├── index.ts │ │ │ │ ├── organization.ts │ │ │ │ └── user.ts │ │ │ ├── links.ts │ │ │ ├── index.ts │ │ │ ├── routes.ts │ │ │ └── advantage-config.ts │ │ ├── types │ │ │ ├── dialog.ts │ │ │ ├── globals.d.ts │ │ │ ├── images.d.ts │ │ │ ├── environment.ts │ │ │ ├── type-utils.ts │ │ │ └── decorators.d.ts │ │ ├── .config │ │ │ ├── server-config.dev.json │ │ │ └── server-config.prod.json │ │ ├── theme │ │ │ ├── index.ts │ │ │ ├── palette.ts │ │ │ └── with-theme.tsx │ │ ├── animations │ │ │ ├── index.ts │ │ │ ├── router-animation.tsx │ │ │ ├── @common-animation.tsx │ │ │ ├── swipe.tsx │ │ │ └── animation-mounted-controller.tsx │ │ ├── routes │ │ │ ├── index.ts │ │ │ ├── community-route.ts │ │ │ ├── public-space-route.ts │ │ │ ├── team-route.ts │ │ │ ├── app-route.ts │ │ │ ├── doc-route.ts │ │ │ └── organization-route.ts │ │ └── index.tsx │ ├── index.tsx │ └── test │ │ └── utils │ │ └── env.spec.ts ├── webpack │ ├── utils │ │ ├── index.ts │ │ └── path.ts │ ├── tsconfig-for-webpack-config.json │ ├── webpack.config.prod.ts │ └── webpack.config.dev.ts ├── tsconfig.prod.json ├── tsconfig.test.json ├── config │ ├── jest │ │ ├── typescriptTransform.js │ │ ├── fileTransform.js │ │ └── cssTransform.js │ └── polyfills.js ├── .parcelrc ├── .gitignore ├── public │ └── index.html ├── tsconfig.json ├── tslint.json └── jest.config.js ├── packages ├── http-request │ ├── example │ │ ├── ts │ │ │ └── .gitkeep │ │ ├── js │ │ │ ├── index.js │ │ │ ├── http │ │ │ │ ├── interceptors │ │ │ │ │ ├── res-error-catcher.js │ │ │ │ │ ├── req-logger.js │ │ │ │ │ └── res-logger.js │ │ │ │ └── http-service.js │ │ │ ├── github-service.js │ │ │ └── main.js │ │ └── configs │ │ │ └── sever-config.json │ ├── src │ │ ├── index.ts │ │ └── lib │ │ │ ├── index.ts │ │ │ └── interceptor.ts │ ├── .babelrc │ ├── README.md │ ├── tsconfig.json │ └── package.json ├── markdown │ ├── src │ │ ├── components │ │ │ ├── index.ts │ │ │ └── header.tsx │ │ └── index.ts │ ├── package.json │ └── tsconfig.json ├── http-utils │ ├── src │ │ ├── index.ts │ │ └── rate-limiter.ts │ ├── tsconfig.json │ └── package.json └── injector │ ├── src │ └── index.ts │ ├── package.json │ └── tsconfig.json ├── .prettierignore ├── server ├── src │ ├── constants │ │ ├── index.ts │ │ └── auth.ts │ ├── decorators │ │ ├── auth │ │ │ ├── index.ts │ │ │ └── jwt.ts │ │ ├── graphql │ │ │ └── index.ts │ │ └── index.ts │ ├── guards │ │ ├── auth │ │ │ ├── index.ts │ │ │ └── auth.guard.ts │ │ ├── index.ts │ │ └── graphql.guard.ts │ ├── middlewares │ │ ├── index.ts │ │ └── reverse-proxy.ts │ ├── controllers │ │ ├── category │ │ │ ├── index.ts │ │ │ └── category.controller.ts │ │ ├── document │ │ │ └── index.ts │ │ ├── index.ts │ │ └── user │ │ │ └── index.ts │ ├── modules │ │ ├── index.ts │ │ ├── static-server.module.ts │ │ └── user.module.ts │ ├── services │ │ ├── interceptors │ │ │ ├── index.ts │ │ │ ├── res-error.ts │ │ │ └── res-data.ts │ │ ├── index.ts │ │ └── auth.service.ts │ ├── filters │ │ ├── index.ts │ │ ├── transfer-request.ts │ │ └── global-error-filter.ts │ ├── .config │ │ └── proxy-config.json │ ├── typings │ │ └── env.d.ts │ ├── app.service.ts │ ├── app.controller.ts │ ├── main.ts │ └── app.module.ts ├── nest-cli.json ├── tsconfig.build.json ├── .gitignore ├── tslint.json └── tsconfig.json ├── shared ├── src │ ├── dto │ │ ├── category │ │ │ ├── index.ts │ │ │ └── category.dto.ts │ │ ├── document │ │ │ └── index.ts │ │ └── index.ts │ ├── index.ts │ └── lib │ │ ├── index.ts │ │ ├── array.ts │ │ ├── request-payload-parser.ts │ │ └── helpers.ts ├── package.json └── tsconfig.json ├── doc ├── react.png ├── golang.png ├── wizard.png └── md │ └── DEVELOPMENT.md ├── .dockerignore ├── lerna.json ├── prettier.config.js ├── .gitignore ├── .vscode ├── typescriptreact.code-snippets └── settings.json ├── Dockerfile └── tsconfig.react.json /client/src/website/configs/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/website/services/chat/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/http-request/example/ts/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | lerna.json 2 | package.json 3 | -------------------------------------------------------------------------------- /client/src/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './website'; 2 | -------------------------------------------------------------------------------- /client/webpack/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './path'; 2 | -------------------------------------------------------------------------------- /server/src/constants/index.ts: -------------------------------------------------------------------------------- 1 | export * from './auth'; 2 | -------------------------------------------------------------------------------- /client/src/website/assets/index.ts: -------------------------------------------------------------------------------- 1 | export * from './svg'; 2 | -------------------------------------------------------------------------------- /client/src/website/ui/menu/index.ts: -------------------------------------------------------------------------------- 1 | export * from './menu'; 2 | -------------------------------------------------------------------------------- /server/src/decorators/auth/index.ts: -------------------------------------------------------------------------------- 1 | export * from './jwt'; 2 | -------------------------------------------------------------------------------- /client/src/website/ui/drawer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './drawer'; 2 | -------------------------------------------------------------------------------- /client/src/website/ui/search/index.ts: -------------------------------------------------------------------------------- 1 | export * from './search'; 2 | -------------------------------------------------------------------------------- /client/src/website/utils/page.ts: -------------------------------------------------------------------------------- 1 | export const INIT_PAGE = 1; 2 | -------------------------------------------------------------------------------- /client/tsconfig.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json" 3 | } -------------------------------------------------------------------------------- /server/src/guards/auth/index.ts: -------------------------------------------------------------------------------- 1 | export * from './auth.guard'; 2 | -------------------------------------------------------------------------------- /server/src/middlewares/index.ts: -------------------------------------------------------------------------------- 1 | export * from './reverse-proxy'; 2 | -------------------------------------------------------------------------------- /shared/src/dto/category/index.ts: -------------------------------------------------------------------------------- 1 | export * from './category.dto'; 2 | -------------------------------------------------------------------------------- /shared/src/dto/document/index.ts: -------------------------------------------------------------------------------- 1 | export * from './document.dto'; 2 | -------------------------------------------------------------------------------- /client/src/website/services/notify/@notify-service.dto.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /client/src/website/ui/catalog/index.ts: -------------------------------------------------------------------------------- 1 | export * from './catalog'; 2 | -------------------------------------------------------------------------------- /client/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/markdown/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './header'; 2 | -------------------------------------------------------------------------------- /shared/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | export * from './dto'; 3 | -------------------------------------------------------------------------------- /client/src/website/components/footer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './footer'; 2 | -------------------------------------------------------------------------------- /client/src/website/services/http/index.ts: -------------------------------------------------------------------------------- 1 | export * from './http-service'; 2 | -------------------------------------------------------------------------------- /client/src/website/ui/breadcrumbs/index.ts: -------------------------------------------------------------------------------- 1 | export * from './breadcrumbs'; 2 | -------------------------------------------------------------------------------- /doc/react.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/doc/react.png -------------------------------------------------------------------------------- /server/src/constants/auth.ts: -------------------------------------------------------------------------------- 1 | export const AUTH_KEY = 'authentication'; 2 | -------------------------------------------------------------------------------- /server/src/decorators/graphql/index.ts: -------------------------------------------------------------------------------- 1 | export * from './graphql-client'; 2 | -------------------------------------------------------------------------------- /client/src/website/components/doc/share/index.ts: -------------------------------------------------------------------------------- 1 | export * from './share-pop'; 2 | -------------------------------------------------------------------------------- /client/src/website/components/overview/@common/index.ts: -------------------------------------------------------------------------------- 1 | export * from './form'; 2 | -------------------------------------------------------------------------------- /client/src/website/components/pen/original/index.ts: -------------------------------------------------------------------------------- 1 | export * from './original'; 2 | -------------------------------------------------------------------------------- /client/src/website/components/pen/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './utils-box'; 2 | -------------------------------------------------------------------------------- /client/src/website/components/pen/viewer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './viewer'; 2 | -------------------------------------------------------------------------------- /client/src/website/components/register/index.ts: -------------------------------------------------------------------------------- 1 | export * from './register'; 2 | -------------------------------------------------------------------------------- /client/src/website/services/notify/index.ts: -------------------------------------------------------------------------------- 1 | export * from './notify-service'; 2 | -------------------------------------------------------------------------------- /doc/golang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/doc/golang.png -------------------------------------------------------------------------------- /doc/wizard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/doc/wizard.png -------------------------------------------------------------------------------- /server/src/controllers/category/index.ts: -------------------------------------------------------------------------------- 1 | export * from './category.controller'; 2 | -------------------------------------------------------------------------------- /client/src/website/components/common/side-bar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './side-bar'; 2 | -------------------------------------------------------------------------------- /client/src/website/components/common/upload/index.ts: -------------------------------------------------------------------------------- 1 | export * from './image-upload'; 2 | -------------------------------------------------------------------------------- /client/src/website/pages/document-pages/index.ts: -------------------------------------------------------------------------------- 1 | export * from './document-center'; 2 | -------------------------------------------------------------------------------- /client/src/website/services/category/index.ts: -------------------------------------------------------------------------------- 1 | export * from './category-service'; 2 | -------------------------------------------------------------------------------- /shared/src/dto/index.ts: -------------------------------------------------------------------------------- 1 | export * from './category'; 2 | export * from './document'; 3 | -------------------------------------------------------------------------------- /client/src/website/services/markdown-service/index.ts: -------------------------------------------------------------------------------- 1 | export * from './markdown-service'; 2 | -------------------------------------------------------------------------------- /server/src/controllers/document/index.ts: -------------------------------------------------------------------------------- 1 | export * from './document-processor.controller'; 2 | -------------------------------------------------------------------------------- /server/src/decorators/index.ts: -------------------------------------------------------------------------------- 1 | export * from './auth'; 2 | export * from './graphql'; 3 | -------------------------------------------------------------------------------- /server/src/guards/index.ts: -------------------------------------------------------------------------------- 1 | export * from './auth'; 2 | export * from './graphql.guard'; 3 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | doc 3 | .github 4 | .vscode 5 | yarn-error.log 6 | client 7 | -------------------------------------------------------------------------------- /client/src/website/components/common/transition-fab/index.ts: -------------------------------------------------------------------------------- 1 | export * from './transition-fab'; 2 | -------------------------------------------------------------------------------- /client/src/website/components/main/knowledge-card/index.ts: -------------------------------------------------------------------------------- 1 | export * from './knowledge-card'; 2 | -------------------------------------------------------------------------------- /client/src/website/components/main/main-header-bar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './main-header-bar'; 2 | -------------------------------------------------------------------------------- /client/src/website/components/overview/overview-side/index.ts: -------------------------------------------------------------------------------- 1 | export * from './overview-side'; 2 | -------------------------------------------------------------------------------- /client/src/website/guards/organizations/index.ts: -------------------------------------------------------------------------------- 1 | export * from './organization-empty-guard'; 2 | -------------------------------------------------------------------------------- /packages/http-request/example/js/index.js: -------------------------------------------------------------------------------- 1 | require("@babel/register") 2 | require("./main.js") 3 | -------------------------------------------------------------------------------- /client/src/website/components/community/document-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './document-list'; 2 | -------------------------------------------------------------------------------- /client/src/website/components/doc/index.ts: -------------------------------------------------------------------------------- 1 | export * from './share'; 2 | export * from './doc-page'; 3 | -------------------------------------------------------------------------------- /client/src/website/components/message-center/message-side/index.ts: -------------------------------------------------------------------------------- 1 | export * from './message-side'; 2 | -------------------------------------------------------------------------------- /client/src/website/components/overview/overview-header/index.ts: -------------------------------------------------------------------------------- 1 | export * from './overview-header'; 2 | -------------------------------------------------------------------------------- /client/src/website/guards/index.ts: -------------------------------------------------------------------------------- 1 | export * from './overview'; 2 | export * from './organizations'; 3 | -------------------------------------------------------------------------------- /client/src/website/ui/upload/index.ts: -------------------------------------------------------------------------------- 1 | export * from './upload'; 2 | export * from './type-upload'; 3 | -------------------------------------------------------------------------------- /packages/markdown/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components'; 2 | export * from './markdown-editor'; 3 | -------------------------------------------------------------------------------- /server/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "@nestjs/schematics", 3 | "sourceRoot": "src" 4 | } 5 | -------------------------------------------------------------------------------- /client/src/website/components/access/props.tsx: -------------------------------------------------------------------------------- 1 | export interface AccessProps { 2 | name: string; 3 | } 4 | -------------------------------------------------------------------------------- /client/src/website/components/message-center/message-header/index.ts: -------------------------------------------------------------------------------- 1 | export * from './message-header'; 2 | -------------------------------------------------------------------------------- /client/src/website/constant/apis/doc.ts: -------------------------------------------------------------------------------- 1 | export const enum DOC_API { 2 | WIZARD = '/doc/wizard', 3 | } 4 | -------------------------------------------------------------------------------- /client/src/website/services/observer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './observer'; 2 | export * from './subject'; 3 | -------------------------------------------------------------------------------- /client/src/website/services/regex/index.ts: -------------------------------------------------------------------------------- 1 | export * from './regex-utils'; 2 | export * from './regex'; 3 | -------------------------------------------------------------------------------- /packages/http-utils/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './url-decorators'; 2 | export * from './rate-limiter'; 3 | -------------------------------------------------------------------------------- /server/src/modules/index.ts: -------------------------------------------------------------------------------- 1 | export * from './user.module'; 2 | export * from './static-server.module'; 3 | -------------------------------------------------------------------------------- /server/src/services/interceptors/index.ts: -------------------------------------------------------------------------------- 1 | export * from './res-data'; 2 | export * from './res-error'; 3 | -------------------------------------------------------------------------------- /client/src/website/components/common/markdown/@function-pannel/index.ts: -------------------------------------------------------------------------------- 1 | export * from './function-panel'; 2 | -------------------------------------------------------------------------------- /client/src/website/components/common/markdown/document-comments/index.ts: -------------------------------------------------------------------------------- 1 | export * from './document-comments'; 2 | -------------------------------------------------------------------------------- /client/src/website/services/time/index.ts: -------------------------------------------------------------------------------- 1 | export * from './time-service'; 2 | export * from './time-utils'; 3 | -------------------------------------------------------------------------------- /client/src/website/ui/tree-view/index.ts: -------------------------------------------------------------------------------- 1 | export * from './tree-view'; 2 | export * from './tree-view-item'; 3 | -------------------------------------------------------------------------------- /server/src/filters/index.ts: -------------------------------------------------------------------------------- 1 | export * from './global-error-filter'; 2 | export * from './transfer-request'; 3 | -------------------------------------------------------------------------------- /client/src/website/components/optional-tip/index.ts: -------------------------------------------------------------------------------- 1 | export * from './optional-tip'; 2 | export * from './todo'; 3 | -------------------------------------------------------------------------------- /client/src/website/components/optional-tip/todo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './todo-item'; 2 | export * from './todos'; 3 | -------------------------------------------------------------------------------- /client/src/website/services/user/index.ts: -------------------------------------------------------------------------------- 1 | export * from './user-service'; 2 | export * from './user-service.dto'; 3 | -------------------------------------------------------------------------------- /client/src/website/types/dialog.ts: -------------------------------------------------------------------------------- 1 | export interface DefaultDialogProps { 2 | handleDialogClose?(): void; 3 | } 4 | -------------------------------------------------------------------------------- /client/src/website/components/about/index.ts: -------------------------------------------------------------------------------- 1 | export * from './contributors'; 2 | export * from './contributor-avatar'; 3 | -------------------------------------------------------------------------------- /client/src/website/components/common/avatar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './avatar'; 2 | export * from './current-avatar'; 3 | -------------------------------------------------------------------------------- /client/src/website/components/common/dialogs/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dialog'; 2 | export * from './confirm-dialog'; 3 | -------------------------------------------------------------------------------- /client/src/website/components/footer/@panel/index.ts: -------------------------------------------------------------------------------- 1 | export * from './footer-panel'; 2 | export * from './link-column'; 3 | -------------------------------------------------------------------------------- /client/src/website/constant/apis/upload.ts: -------------------------------------------------------------------------------- 1 | export const UPLOAD_API = { 2 | getToken: '/upload/qiniu/token', 3 | }; 4 | -------------------------------------------------------------------------------- /client/src/website/guards/overview/index.ts: -------------------------------------------------------------------------------- 1 | export * from './overview-auth'; 2 | export * from './organization-guard'; 3 | -------------------------------------------------------------------------------- /client/src/website/ui/form-control/index.ts: -------------------------------------------------------------------------------- 1 | export * from './form-control'; 2 | export * from './form-control-type'; 3 | -------------------------------------------------------------------------------- /server/src/controllers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './category'; 2 | export * from './document'; 3 | export * from './user'; 4 | -------------------------------------------------------------------------------- /client/src/website/components/community/index.ts: -------------------------------------------------------------------------------- 1 | export * from './document-list'; 2 | export * from './community-banner'; 3 | -------------------------------------------------------------------------------- /client/src/website/components/release-banner/index.ts: -------------------------------------------------------------------------------- 1 | export * from './release-banner'; 2 | export * from './release-tag'; 3 | -------------------------------------------------------------------------------- /client/src/website/ui/input/index.ts: -------------------------------------------------------------------------------- 1 | export * from './input'; 2 | export * from './normal'; 3 | export * from './with-icon'; 4 | -------------------------------------------------------------------------------- /packages/http-request/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './http-request'; 2 | export * from 'axios'; 3 | export * from './lib'; 4 | -------------------------------------------------------------------------------- /server/src/controllers/user/index.ts: -------------------------------------------------------------------------------- 1 | export * from './user-access.controller'; 2 | export * from './user-follow.controller'; 3 | -------------------------------------------------------------------------------- /client/src/website/assets/static/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/main.png -------------------------------------------------------------------------------- /client/src/website/assets/static/wand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/wand.png -------------------------------------------------------------------------------- /client/src/website/components/doc/doc-page/index.ts: -------------------------------------------------------------------------------- 1 | export * from './page-paper'; 2 | export * from './organization-info-card'; 3 | -------------------------------------------------------------------------------- /client/src/website/components/user-detail/index.ts: -------------------------------------------------------------------------------- 1 | export * from './user-card'; 2 | export * from './organization-detail-card'; 3 | -------------------------------------------------------------------------------- /client/src/website/services/document/index.ts: -------------------------------------------------------------------------------- 1 | export * from './document-service.dto'; 2 | export * from './document-service'; 3 | -------------------------------------------------------------------------------- /client/src/website/services/route/guards/index.ts: -------------------------------------------------------------------------------- 1 | export * from './activated-guard'; 2 | export * from './deactivated-guard'; 3 | -------------------------------------------------------------------------------- /client/src/website/assets/static/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/github.png -------------------------------------------------------------------------------- /client/src/website/assets/static/phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/phone.png -------------------------------------------------------------------------------- /client/src/website/assets/static/rabbit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/rabbit.png -------------------------------------------------------------------------------- /client/src/website/assets/static/wizard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/wizard.png -------------------------------------------------------------------------------- /client/src/website/constant/links.ts: -------------------------------------------------------------------------------- 1 | export class Links { 2 | static readonly GitHub = 'https://github.com/wizaaard/wizard'; 3 | } 4 | -------------------------------------------------------------------------------- /client/src/website/pages/organization-pages/index.ts: -------------------------------------------------------------------------------- 1 | export * from './select-organization'; 2 | export * from './new-organization'; 3 | -------------------------------------------------------------------------------- /client/src/website/services/permission/index.ts: -------------------------------------------------------------------------------- 1 | export * from './permission-service.dto'; 2 | export * from './permission-service'; 3 | -------------------------------------------------------------------------------- /client/src/website/ui/input/normal.tsx: -------------------------------------------------------------------------------- 1 | import {TextField} from '@material-ui/core'; 2 | 3 | export const NormalInput = TextField; 4 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "lerna": "3.13.1", 3 | "version": "independent", 4 | "npmClient": "yarn", 5 | "useWorkspaces": true 6 | } 7 | -------------------------------------------------------------------------------- /packages/http-request/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"], 3 | "plugins": ["@babel/plugin-transform-runtime"] 4 | } 5 | -------------------------------------------------------------------------------- /server/src/services/index.ts: -------------------------------------------------------------------------------- 1 | export * from './interceptors'; 2 | export * from './auth.service'; 3 | export * from './http.service'; 4 | -------------------------------------------------------------------------------- /client/src/website/assets/static/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/loading.gif -------------------------------------------------------------------------------- /client/src/website/services/markdown-service/@plugins/index.ts: -------------------------------------------------------------------------------- 1 | export * from './text-processor'; 2 | export * from './inline-processor'; 3 | -------------------------------------------------------------------------------- /client/src/website/services/organization/index.ts: -------------------------------------------------------------------------------- 1 | export * from './organization-service'; 2 | export * from './organization-service.dto'; 3 | -------------------------------------------------------------------------------- /client/src/website/services/route/index.ts: -------------------------------------------------------------------------------- 1 | export * from './router-service'; 2 | export * from './guards'; 3 | export * from './route'; 4 | -------------------------------------------------------------------------------- /server/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /client/src/website/assets/iconfont/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/iconfont/iconfont.eot -------------------------------------------------------------------------------- /client/src/website/assets/iconfont/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/iconfont/iconfont.ttf -------------------------------------------------------------------------------- /client/src/website/assets/iconfont/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/iconfont/iconfont.woff -------------------------------------------------------------------------------- /client/src/website/assets/static/magic_wand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/magic_wand.png -------------------------------------------------------------------------------- /client/src/website/assets/static/main_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/main_cover.png -------------------------------------------------------------------------------- /client/src/website/assets/static/wizard-card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/wizard-card.png -------------------------------------------------------------------------------- /client/src/website/components/common/invite-member-box/index.ts: -------------------------------------------------------------------------------- 1 | export * from './invite-member-box'; 2 | export * from './user-search-line'; 3 | -------------------------------------------------------------------------------- /client/src/website/components/message-center/message-overview/index.ts: -------------------------------------------------------------------------------- 1 | export * from './message-overview'; 2 | export * from './message-item'; 3 | -------------------------------------------------------------------------------- /client/src/website/ui/button/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button'; 2 | export * from './toggle-button'; 3 | export * from './permission-button'; 4 | -------------------------------------------------------------------------------- /server/src/.config/proxy-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "localhost", 3 | "port": 4000, 4 | "protocol": "http", 5 | "mode": "prod" 6 | } 7 | -------------------------------------------------------------------------------- /client/src/website/assets/iconfont/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/iconfont/iconfont.woff2 -------------------------------------------------------------------------------- /client/src/website/assets/static/advantage/chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/advantage/chat.png -------------------------------------------------------------------------------- /client/src/website/assets/static/organization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/organization.png -------------------------------------------------------------------------------- /client/src/website/assets/static/wizard-white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/wizard-white.jpg -------------------------------------------------------------------------------- /client/src/website/assets/static/wizard_person.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/wizard_person.png -------------------------------------------------------------------------------- /client/src/website/components/common/tab/index.ts: -------------------------------------------------------------------------------- 1 | export * from './tab'; 2 | export * from './tab-content'; 3 | export * from './tab-content-item'; 4 | -------------------------------------------------------------------------------- /client/src/website/components/header-bar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './header-bar-tabs'; 2 | export * from './header-bar'; 3 | export * from './logo'; 4 | -------------------------------------------------------------------------------- /client/src/website/components/overview/overview-docs/category/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-category-dialog'; 2 | export * from './category-card'; 3 | -------------------------------------------------------------------------------- /client/src/website/components/user/index.ts: -------------------------------------------------------------------------------- 1 | export * from './profile'; 2 | export * from './user-item'; 3 | export * from './valid-email-dialog'; 4 | -------------------------------------------------------------------------------- /client/src/website/assets/static/advantage/phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/advantage/phone.png -------------------------------------------------------------------------------- /client/src/website/assets/static/magic_wand_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/magic_wand_white.png -------------------------------------------------------------------------------- /client/src/website/constant/apis/todo.ts: -------------------------------------------------------------------------------- 1 | export const TODO_API = { 2 | add: '/todo/add', 3 | remove: '/todo/remove', 4 | all: '/todo/all', 5 | }; 6 | -------------------------------------------------------------------------------- /client/src/website/pages/organization-pages/select-organization/index.ts: -------------------------------------------------------------------------------- 1 | export * from './select-organization'; 2 | export * from './empty-organization'; 3 | -------------------------------------------------------------------------------- /client/src/website/.config/server-config.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "localhost", 3 | "port": 3000, 4 | "protocol": "http", 5 | "prefix": "api" 6 | } 7 | -------------------------------------------------------------------------------- /client/src/website/assets/static/advantage/font_docs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/advantage/font_docs.png -------------------------------------------------------------------------------- /client/src/website/assets/static/advantage/swagger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/advantage/swagger.png -------------------------------------------------------------------------------- /client/src/website/assets/static/default_categories.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/default_categories.png -------------------------------------------------------------------------------- /client/src/website/assets/static/register_successful.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/register_successful.png -------------------------------------------------------------------------------- /client/src/website/assets/static/wizard-card-variant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/wizard-card-variant.png -------------------------------------------------------------------------------- /client/src/website/assets/static/wizard_person_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/wizard_person_white.png -------------------------------------------------------------------------------- /client/src/website/constant/index.ts: -------------------------------------------------------------------------------- 1 | export * from './links'; 2 | export * from './advantage-config'; 3 | export * from './routes'; 4 | export * from './apis'; 5 | -------------------------------------------------------------------------------- /client/src/website/services/dialog/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dialog-service'; 2 | export * from './confirm-dialog-service'; 3 | export * from './dialog-pool'; 4 | -------------------------------------------------------------------------------- /client/src/website/theme/index.ts: -------------------------------------------------------------------------------- 1 | export * from './palette'; 2 | export * from './style'; 3 | export * from './global-style'; 4 | export * from './with-theme'; 5 | -------------------------------------------------------------------------------- /shared/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './array'; 2 | export * from './helpers'; 3 | export * from './typeof'; 4 | export * from './request-payload-parser'; 5 | -------------------------------------------------------------------------------- /client/src/website/.config/server-config.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "182.254.131.141", 3 | "port": 3000, 4 | "protocol": "http", 5 | "prefix": "api" 6 | } 7 | -------------------------------------------------------------------------------- /client/src/website/assets/static/advantage/open_source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/advantage/open_source.png -------------------------------------------------------------------------------- /client/src/website/assets/static/wizard-card-variant2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardoc/wizard/HEAD/client/src/website/assets/static/wizard-card-variant2.png -------------------------------------------------------------------------------- /client/src/website/components/user/@user-avatar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './user-avatar'; 2 | export * from './avatar-selector'; 3 | export * from './scalable-box'; 4 | -------------------------------------------------------------------------------- /client/webpack/utils/path.ts: -------------------------------------------------------------------------------- 1 | import {join} from 'path'; 2 | 3 | export const withWebpackPath = (...path: string[]) => 4 | join(__dirname, '..', '..', ...path); 5 | -------------------------------------------------------------------------------- /packages/http-request/example/configs/sever-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "api.github.com", 3 | "port": 80, 4 | "protocol": "https", 5 | "mode": "prod" 6 | } 7 | -------------------------------------------------------------------------------- /client/src/website/components/user-settings/index.ts: -------------------------------------------------------------------------------- 1 | export * from './user-settings-sidebar'; 2 | export * from './settings-title'; 3 | export * from './update-email'; 4 | -------------------------------------------------------------------------------- /client/src/website/services/message/index.ts: -------------------------------------------------------------------------------- 1 | export * from './message-service'; 2 | export * from './message-service.dto'; 3 | export * from './message-service.api'; 4 | -------------------------------------------------------------------------------- /client/src/website/ui/button/button.ts: -------------------------------------------------------------------------------- 1 | import {ToggleButton} from './toggle-button'; 2 | 3 | export namespace Button { 4 | export const Toggle = ToggleButton; 5 | } 6 | -------------------------------------------------------------------------------- /client/src/website/animations/index.ts: -------------------------------------------------------------------------------- 1 | export * from './router-animation'; 2 | export * from './swipe'; 3 | export * from './slide'; 4 | export * from './animation-mounted-controller'; 5 | -------------------------------------------------------------------------------- /client/src/website/components/overview/organization-edit/index.ts: -------------------------------------------------------------------------------- 1 | export * from './base-edit-card'; 2 | export * from './member-manager'; 3 | export * from './organization-function'; 4 | -------------------------------------------------------------------------------- /client/src/website/components/overview/organization-edit/member-manager/invite-member-dialog/index.ts: -------------------------------------------------------------------------------- 1 | export * from './invite-member-dialog'; 2 | export * from './invite-search-box'; 3 | -------------------------------------------------------------------------------- /client/src/website/ui/link.tsx: -------------------------------------------------------------------------------- 1 | import {Link} from '@material-ui/core'; 2 | import styled from 'styled-components'; 3 | 4 | export const A = styled(Link)` 5 | cursor: pointer; 6 | `; 7 | -------------------------------------------------------------------------------- /client/src/website/constant/apis/index.ts: -------------------------------------------------------------------------------- 1 | export * from './user'; 2 | export * from './doc'; 3 | export * from './organization'; 4 | export * from './todo'; 5 | export * from './upload'; 6 | -------------------------------------------------------------------------------- /server/src/typings/env.d.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | namespace NodeJS { 3 | interface ProcessEnv { 4 | CLIENT_PORT: string; 5 | } 6 | } 7 | } 8 | 9 | export {}; 10 | -------------------------------------------------------------------------------- /client/src/website/components/overview/organization-edit/member-manager/index.ts: -------------------------------------------------------------------------------- 1 | export * from './member-overview'; 2 | export * from './member-box'; 3 | export * from './invite-member-dialog'; 4 | -------------------------------------------------------------------------------- /client/src/website/components/pen/index.ts: -------------------------------------------------------------------------------- 1 | export * from './original'; 2 | export * from './pen-header'; 3 | export * from './pen'; 4 | export * from './viewer'; 5 | export * from './utils'; 6 | -------------------------------------------------------------------------------- /client/src/website/constant/apis/organization.ts: -------------------------------------------------------------------------------- 1 | export const ORGANIZATION = { 2 | JOIN: '/organization/join', 3 | REMOVE: (name: string): string => `/organization/remove/${name}`, 4 | }; 5 | -------------------------------------------------------------------------------- /client/src/website/components/common/loading/index.ts: -------------------------------------------------------------------------------- 1 | export * from './inline-loading'; 2 | export * from './normal-loading'; 3 | export * from './fetch-data'; 4 | export * from './backdrop-loading'; 5 | -------------------------------------------------------------------------------- /packages/http-request/example/js/http/interceptors/res-error-catcher.js: -------------------------------------------------------------------------------- 1 | export class ResErrorCatcher { 2 | catchRes(err) { 3 | console.info("Error: ", err) 4 | 5 | throw err 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /server/src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService { 5 | getHello(): string { 6 | return 'Hello World!'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /client/src/website/components/common/markdown/render-components/link.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import {Link} from '@material-ui/core'; 3 | 4 | export const MDLink = styled(Link)``; 5 | -------------------------------------------------------------------------------- /client/src/website/components/message-center/views/index.ts: -------------------------------------------------------------------------------- 1 | export * from './message-panel'; 2 | export * from './message-trash'; 3 | export * from './system-message'; 4 | export * from './user-message'; 5 | -------------------------------------------------------------------------------- /client/src/website/pages/overview/index.ts: -------------------------------------------------------------------------------- 1 | export * from './overview-organization'; 2 | export * from './overview-page'; 3 | export * from './organization-edit-page'; 4 | export * from './overview-docs'; 5 | -------------------------------------------------------------------------------- /client/src/website/pages/why-use.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | 3 | export class WhyUse extends Component { 4 | render(): ReactNode { 5 | return <>; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /client/src/website/components/overview/overview-docs/index.ts: -------------------------------------------------------------------------------- 1 | export * from './overview-docs-header'; 2 | export * from './category'; 3 | export * from './overview-doc-cards'; 4 | export * from './document'; 5 | -------------------------------------------------------------------------------- /packages/http-request/README.md: -------------------------------------------------------------------------------- 1 | # @Wizardoc/http-request 2 | 3 | ## Motivation 4 | 5 | ## Where do I need to catch errors 6 | 7 | ## Interceptors 8 | 9 | ## Excape callback 10 | 11 | ## License 12 | -------------------------------------------------------------------------------- /client/src/website/components/@login.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | 3 | export class Login extends Component { 4 | render(): ReactNode { 5 | return
Login
; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /client/src/website/types/globals.d.ts: -------------------------------------------------------------------------------- 1 | import type {CustomProcessEnv} from './environment'; 2 | 3 | declare global { 4 | namespace NodeJS { 5 | interface ProcessEnv extends CustomProcessEnv {} 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /client/webpack/tsconfig-for-webpack-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "esModuleInterop": true, 6 | "resolveJsonModule": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /client/src/website/components/pen/pen-header.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | 3 | export class PenHeader extends Component { 4 | render(): ReactNode { 5 | return <>; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/http-request/example/js/http/interceptors/req-logger.js: -------------------------------------------------------------------------------- 1 | export class ReqLogger { 2 | onRequest(config) { 3 | console.info("REQ LOG: ===> ", JSON.stringify(config)) 4 | 5 | return config 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/http-request/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './http-client'; 2 | export * from './http-service'; 3 | export * from './attach-interceptor'; 4 | export * from './configure'; 5 | export * from './interceptor'; 6 | -------------------------------------------------------------------------------- /client/src/website/pages/page-not-found.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | 3 | export class PageNotFound extends Component { 4 | render(): ReactNode { 5 | return
404
; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /client/src/website/pages/user-pages/index.ts: -------------------------------------------------------------------------------- 1 | export * from './login-page'; 2 | export * from './register-page'; 3 | export * from './user-detail'; 4 | export * from './user-settings'; 5 | export * from './reset-password'; 6 | -------------------------------------------------------------------------------- /client/src/website/services/category/@category-service.api.ts: -------------------------------------------------------------------------------- 1 | import {Group} from '@wizardoc/http-utils'; 2 | 3 | @Group('/category') 4 | export class CategoryServiceAPI { 5 | all = '/'; 6 | 7 | create = '/'; 8 | } 9 | -------------------------------------------------------------------------------- /client/src/website/utils/svg-generator.tsx: -------------------------------------------------------------------------------- 1 | import React, {FunctionComponent} from 'react'; 2 | 3 | export const SvgGenerator = (component: JSX.Element): FunctionComponent => { 4 | return () => <>{component}; 5 | }; 6 | -------------------------------------------------------------------------------- /client/src/website/components/message-center/index.ts: -------------------------------------------------------------------------------- 1 | export * from './message-overview'; 2 | export * from './message-switcher'; 3 | export * from './views'; 4 | export * from './message-side'; 5 | export * from './message-header'; 6 | -------------------------------------------------------------------------------- /client/src/website/components/overview/overview-docs/document/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-document-header'; 2 | export * from './cover-selector'; 3 | export * from './document-title'; 4 | export * from './create-document-dialog'; 5 | -------------------------------------------------------------------------------- /client/src/website/utils/diff.ts: -------------------------------------------------------------------------------- 1 | export function objectShallowDiff(origin: any, target: any): boolean { 2 | return Object.keys(origin).reduce( 3 | (pre, key) => pre && target[key] === origin[key], 4 | true, 5 | ); 6 | } 7 | -------------------------------------------------------------------------------- /packages/injector/src/index.ts: -------------------------------------------------------------------------------- 1 | import {Injector} from './injector'; 2 | 3 | export * from './injector'; 4 | 5 | export const injector = new Injector(); 6 | 7 | export const {Injectable, peek, collect, extract, Inject} = injector; 8 | -------------------------------------------------------------------------------- /client/config/jest/typescriptTransform.js: -------------------------------------------------------------------------------- 1 | // Copyright 2004-present Facebook. All Rights Reserved. 2 | 3 | 'use strict'; 4 | 5 | const tsJestPreprocessor = require('ts-jest/preprocessor'); 6 | 7 | module.exports = tsJestPreprocessor; 8 | -------------------------------------------------------------------------------- /client/src/website/components/message-center/views/message-trash.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | 3 | export class MessageTrash extends Component { 4 | render(): ReactNode { 5 | return <>; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /client/src/website/components/message-center/views/user-message.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | 3 | export class UserMessage extends Component { 4 | render(): ReactNode { 5 | return <>; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /client/src/website/components/overview/index.ts: -------------------------------------------------------------------------------- 1 | export * from './organization-panel'; 2 | export * from './organization-edit'; 3 | export * from './overview-docs'; 4 | export * from './overview-side'; 5 | export * from './overview-header'; 6 | -------------------------------------------------------------------------------- /packages/injector/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wizardoc/injector", 3 | "version": "1.2.5", 4 | "main": "dist/index.js", 5 | "license": "MIT", 6 | "dependencies": { 7 | "reflect-metadata": "^0.1.13" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /client/src/website/components/message-center/views/system-message.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | 3 | export class SystemMessage extends Component { 4 | render(): ReactNode { 5 | return <>; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /shared/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wizardoc/shared", 3 | "version": "1.0.0", 4 | "main": "dist/index.js", 5 | "license": "MIT", 6 | "dependencies": { 7 | "qs": "*", 8 | "@wizardoc/http-request": "*" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /client/src/website/constant/routes.ts: -------------------------------------------------------------------------------- 1 | // user router 2 | export enum USER { 3 | LOGIN = '/limpidity/login', 4 | REGISTER = '/limpidity/register', 5 | } 6 | 7 | export enum MAIN_PAGE { 8 | DOCUMENT = '/doc', 9 | ROOT = '/', 10 | } 11 | -------------------------------------------------------------------------------- /client/src/website/ui/input/input.ts: -------------------------------------------------------------------------------- 1 | import {NormalInput} from './normal'; 2 | import {WithIconInput} from './with-icon'; 3 | 4 | export namespace Input { 5 | export const Normal = NormalInput; 6 | export const WithIcon = WithIconInput; 7 | } 8 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 90, 3 | tabWidth: 2, 4 | useTabs: false, 5 | semi: true, 6 | singleQuote: true, 7 | trailingComma: 'all', 8 | bracketSpacing: false, 9 | arrowParens: 'avoid', 10 | }; 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules 3 | 4 | # logs 5 | yarn-error.log 6 | lerna-debug.log 7 | 8 | # dist 9 | dist 10 | 11 | # idea 12 | .idea/ 13 | 14 | # next ssr 15 | .next 16 | 17 | # dll 18 | _dll_vendor.js 19 | 20 | .DS_Store 21 | -------------------------------------------------------------------------------- /client/src/website/components/common/markdown/render-components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './heading'; 2 | export * from './text'; 3 | export * from './link'; 4 | export * from './block-quote'; 5 | export * from './img'; 6 | export * from './inline-code'; 7 | -------------------------------------------------------------------------------- /client/src/website/components/main/index.ts: -------------------------------------------------------------------------------- 1 | export * from './started'; 2 | export * from './main-content'; 3 | export * from './advantage-cards'; 4 | export * from './knowledge-card'; 5 | export * from './graphic'; 6 | export * from './main-header-bar'; 7 | -------------------------------------------------------------------------------- /client/src/website/constant/apis/user.ts: -------------------------------------------------------------------------------- 1 | export const enum USER_API { 2 | REGISTER = '/user/register', 3 | LOGIN = '/user/login', 4 | INFO = '/user/info', 5 | VALID_BASE_INFO = '/user/valid/info/base', 6 | updateAvatar = '/user/avatar', 7 | } 8 | -------------------------------------------------------------------------------- /client/src/website/components/common/markdown/index.ts: -------------------------------------------------------------------------------- 1 | export * from './markdown-content'; 2 | export * from './markdown-header'; 3 | export * from './render-components'; 4 | export * from './document-status-block'; 5 | export * from './document-comments'; 6 | -------------------------------------------------------------------------------- /client/src/website/components/organization/index.ts: -------------------------------------------------------------------------------- 1 | export * from './header-owner'; 2 | export * from './organization-card'; 3 | export * from './organization-card-info'; 4 | export * from './organization-actions'; 5 | export * from './new-organization-card'; 6 | -------------------------------------------------------------------------------- /server/src/services/interceptors/res-error.ts: -------------------------------------------------------------------------------- 1 | import {HTTPResponseErrorCatch, AxiosError} from '@wizardoc/http-request'; 2 | 3 | export class ResError implements HTTPResponseErrorCatch { 4 | catchRes(err: AxiosError): any { 5 | throw err; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /client/src/website/pages/user-pages/user-settings/index.ts: -------------------------------------------------------------------------------- 1 | export * from './user-settings-base'; 2 | export * from './user-settings'; 3 | export * from './user-settings-email'; 4 | export * from './user-settings-password'; 5 | export * from './user-settings-phone'; 6 | -------------------------------------------------------------------------------- /client/src/website/services/http/@interceptors/index.ts: -------------------------------------------------------------------------------- 1 | export * from './request-type'; 2 | export * from './res-data'; 3 | export * from './res-error-catcher'; 4 | export * from './request-type'; 5 | export * from './res-data'; 6 | export * from './res-error-catcher'; 7 | -------------------------------------------------------------------------------- /client/src/website/types/images.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg'; 2 | 3 | declare module '*.png'; 4 | 5 | declare module '*.jpg'; 6 | 7 | declare module '*.jpeg'; 8 | 9 | declare module '*.gif'; 10 | 11 | declare module '*.bmp'; 12 | 13 | declare module '*.tiff'; 14 | -------------------------------------------------------------------------------- /server/src/modules/static-server.module.ts: -------------------------------------------------------------------------------- 1 | import {join} from 'path'; 2 | 3 | import {ServeStaticModule} from '@nestjs/serve-static'; 4 | 5 | export const StaticServerModule = ServeStaticModule.forRoot({ 6 | rootPath: join(__dirname, '..', '..', 'client-dist'), 7 | }); 8 | -------------------------------------------------------------------------------- /client/src/website/services/notify/@notify-service.api.ts: -------------------------------------------------------------------------------- 1 | import {Group} from '@wizardoc/http-utils'; 2 | import {Injectable} from '@wizardoc/injector'; 3 | 4 | @Injectable() 5 | @Group('/message') 6 | export class NotifyMessageAPI { 7 | sendMessage = '/message/send'; 8 | } 9 | -------------------------------------------------------------------------------- /client/src/website/components/common/fab.tsx: -------------------------------------------------------------------------------- 1 | import {Fab} from '@material-ui/core'; 2 | import styled from 'styled-components'; 3 | 4 | /** styled-components 化的 Circle Fab */ 5 | export const StyledFab = styled(Fab)` 6 | background: ${props => props.theme.secondaryColor}; 7 | `; 8 | -------------------------------------------------------------------------------- /client/src/website/services/http/@interceptors/res-error-catcher.ts: -------------------------------------------------------------------------------- 1 | import {HTTPResponseErrorCatch, AxiosError} from '@wizardoc/http-request'; 2 | 3 | export class ResErrorCatcher implements HTTPResponseErrorCatch { 4 | catchRes(err: AxiosError): void { 5 | throw err; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/http-request/example/js/http/interceptors/res-logger.js: -------------------------------------------------------------------------------- 1 | export class ResLogger { 2 | onResponse(res){ 3 | // The res is an raw Axios response, so if u wanna get data when u using it, 4 | // u need to return data of res from res interceptor 5 | return res.data 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /client/src/website/components/common/lazy-loading.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | 3 | export interface LazyLoadingProps {} 4 | 5 | export class LazyLoading extends Component { 6 | render(): ReactNode { 7 | return
loading
; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /server/src/services/interceptors/res-data.ts: -------------------------------------------------------------------------------- 1 | import {HTTPResponseInterceptor, AxiosResponse} from '@wizardoc/http-request'; 2 | 3 | export class ResData implements HTTPResponseInterceptor { 4 | onResponse(res: AxiosResponse): AxiosResponse | Promise { 5 | return res.data; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /client/.parcelrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@parcel/config-default", 3 | "transformers": { 4 | "*.{ts,tsx}": ["@parcel/transformer-typescript-tsc"], 5 | "*.{jpg,png,svg}": ["@parcel/transformer-raw"] 6 | }, 7 | "validators": { 8 | "*.{ts,tsx}": ["@parcel/validator-typescript"] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /client/src/website/components/pen/viewer/viewer.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | const Wrapper = styled.div``; 5 | 6 | export class Viewer extends Component { 7 | render(): ReactNode { 8 | return ; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /client/src/website/components/message-center/views/message-panel.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | 3 | import {MessageOverview} from '../message-overview'; 4 | 5 | export class MessagePanel extends Component { 6 | render(): ReactNode { 7 | return ; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /client/src/website/services/arrow-cache.ts: -------------------------------------------------------------------------------- 1 | import {ArrowCache as ArrowCacheFactory} from 'arrow-cache'; 2 | import {Injectable} from '@wizardoc/injector'; 3 | 4 | @Injectable() 5 | export class ArrowCache extends ArrowCacheFactory { 6 | constructor() { 7 | super({isPermanentMemory: true}); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /client/src/website/components/main/graphic/index.ts: -------------------------------------------------------------------------------- 1 | export * from './graphic'; 2 | export * from './graphic-title'; 3 | export * from './graphic-content-title'; 4 | export * from './graphic-content-standard'; 5 | export * from './graphic-content-desc'; 6 | export * from './graphic-img'; 7 | export * from './graphic-content'; 8 | -------------------------------------------------------------------------------- /client/src/website/components/overview/@common/form.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const SubTitle = styled.div` 4 | font-size: 14px; 5 | margin-bottom: 12px; 6 | `; 7 | 8 | export const Group = styled.div` 9 | display: flex; 10 | align-items: center; 11 | margin: 20px 0; 12 | `; 13 | -------------------------------------------------------------------------------- /client/src/website/pages/overview/overview-organization.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | 3 | import {OrganizationPanel} from 'website/components'; 4 | 5 | export class OverviewOrganization extends Component { 6 | render(): ReactNode { 7 | return ; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /client/src/website/routes/index.ts: -------------------------------------------------------------------------------- 1 | export * from './app-route'; 2 | export * from './doc-route'; 3 | export * from './user-route'; 4 | export * from './public-space-route'; 5 | export * from './team-route'; 6 | export * from './overview-route'; 7 | export * from './community-route'; 8 | export * from './organization-route'; 9 | -------------------------------------------------------------------------------- /client/src/website/services/catalog-service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@wizardoc/injector'; 2 | import {observable} from 'mobx'; 3 | 4 | import {HeadingObject} from './markdown-service'; 5 | 6 | @Injectable() 7 | export class CatalogService { 8 | @observable 9 | currentAnchor: HeadingObject | undefined; 10 | } 11 | -------------------------------------------------------------------------------- /client/src/website/services/http/@interceptors/res-data.ts: -------------------------------------------------------------------------------- 1 | import {HTTPResponseInterceptor, AxiosResponse} from '@wizardoc/http-request'; 2 | 3 | export class ResData implements HTTPResponseInterceptor { 4 | onResponse(res: AxiosResponse): AxiosResponse | Promise { 5 | return res.data.data; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /client/src/website/services/permission/@permission-service.api.ts: -------------------------------------------------------------------------------- 1 | import {Group} from '@wizardoc/http-utils'; 2 | import {Injectable} from '@wizardoc/injector'; 3 | 4 | @Injectable() 5 | @Group('/permission') 6 | export class PermissionServiceAPI { 7 | organizationAll = (id: string): string => `/organization/${id}`; 8 | } 9 | -------------------------------------------------------------------------------- /client/src/website/ui/view-way.tsx: -------------------------------------------------------------------------------- 1 | import {Component} from 'react'; 2 | import {withRouter, RouteComponentProps} from 'react-router-dom'; 3 | 4 | export interface ViewPanelProps { 5 | isClick: boolean; 6 | } 7 | 8 | @withRouter 9 | export class ViewPanel extends Component {} 10 | -------------------------------------------------------------------------------- /client/src/website/routes/community-route.ts: -------------------------------------------------------------------------------- 1 | import {Routes} from '../services'; 2 | import {Community} from '../pages/community'; 3 | 4 | export const CommunityRoute: Routes = [ 5 | { 6 | path: '/community', 7 | layout: 'normal', 8 | component: Community, 9 | headerType: 'default', 10 | }, 11 | ]; 12 | -------------------------------------------------------------------------------- /client/src/website/types/environment.ts: -------------------------------------------------------------------------------- 1 | export enum RuntimeEnv { 2 | DEVELOPMENT = 'development', 3 | STAGING = 'staging', 4 | PRODUCTION = 'production', 5 | } 6 | 7 | export type IRuntimeEnv = typeof RuntimeEnv; 8 | 9 | export interface CustomProcessEnv { 10 | RUNTIME_ENV: IRuntimeEnv[keyof IRuntimeEnv]; 11 | } 12 | -------------------------------------------------------------------------------- /client/src/website/utils/MIME.ts: -------------------------------------------------------------------------------- 1 | export const MIME = { 2 | PNG: 'image/png', 3 | JPG: 'image/jpg', 4 | JPEG: 'image/jpeg', 5 | }; 6 | 7 | export type MIMEType = keyof typeof MIME; 8 | 9 | export function isImage(MIMEType: string): boolean { 10 | return [MIME.PNG, MIME.JPEG, MIME.JPEG].includes(MIMEType); 11 | } 12 | -------------------------------------------------------------------------------- /client/src/website/pages/user-pages/user-settings/user-settings-phone.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | const Wrapper = styled.div``; 5 | 6 | export class UserSettingsPhone extends Component { 7 | render(): ReactNode { 8 | return ; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /client/src/website/components/user-detail/organization-detail-card.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | const Wrapper = styled.div``; 5 | 6 | export class OrganizationDetailCard extends Component { 7 | render(): ReactNode { 8 | return ; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /shared/src/lib/array.ts: -------------------------------------------------------------------------------- 1 | export const last = (arr: T[]): T | undefined => arr.slice().pop(); 2 | 3 | export const tail = ([_, ...xs]: T[]): T[] => xs; 4 | 5 | export const head = ([x, ..._]: T[]): T => x; 6 | 7 | export const reverseDestruct = (arr: T[]): [T[], T | undefined] => [ 8 | arr.slice(1), 9 | last(arr), 10 | ]; 11 | -------------------------------------------------------------------------------- /client/src/website/pages/common-style-component/tip.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const TipBody = styled.div` 4 | display: flex; 5 | flex-direction: column; 6 | align-items: center; 7 | margin-bottom: 30px; 8 | `; 9 | 10 | export const TipText = styled.div` 11 | color: white; 12 | margin-top: 20px; 13 | `; 14 | -------------------------------------------------------------------------------- /client/src/website/ui/carpet.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export interface CarpetProps { 4 | color: string; 5 | } 6 | 7 | export const Carpet = styled.div` 8 | width: 100%; 9 | height: 100%; 10 | position: fixed; 11 | left: 0; 12 | top: 0; 13 | z-index: -2; 14 | background: ${props => props.color}; 15 | `; 16 | -------------------------------------------------------------------------------- /shared/src/dto/category/category.dto.ts: -------------------------------------------------------------------------------- 1 | export interface Category { 2 | id: string; 3 | name: string; 4 | description: string; 5 | cover: string; 6 | createTime: number; 7 | lastModifyTime: number; 8 | createUser: string; 9 | organizationID: string; 10 | } 11 | 12 | export interface Categories { 13 | [organizationID: string]: Category[]; 14 | } 15 | -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | /node_modules 3 | 4 | # testing 5 | /coverage 6 | 7 | # production 8 | /build 9 | /static 10 | 11 | # cache 12 | .cache 13 | .parcel-cache/** 14 | 15 | # misc 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | -------------------------------------------------------------------------------- /client/src/website/components/user-settings/settings-title.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const SettingTitle = styled.div` 4 | font-size: 35px; 5 | color: ${props => props.theme.titleGray}; 6 | `; 7 | 8 | export const SettingSubTitle = styled(SettingTitle)` 9 | font-size: 22px; 10 | color: ${props => props.theme.titleGray}; 11 | `; 12 | -------------------------------------------------------------------------------- /client/src/website/pages/community.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | 3 | import {DocumentList, CommunityBanner} from '../components'; 4 | 5 | export class Community extends Component { 6 | render(): ReactNode { 7 | return ( 8 | <> 9 | 10 | 11 | 12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /client/src/website/routes/public-space-route.ts: -------------------------------------------------------------------------------- 1 | import {lazy} from 'website/utils'; 2 | 3 | import {Routes} from '../services'; 4 | 5 | /** Lazy load */ 6 | const PublicSpace = lazy(import('../pages/public-space'), 'PublicSpace'); 7 | 8 | export const PublicSpaceRoutes: Routes = [ 9 | { 10 | path: '/public-space', 11 | component: PublicSpace, 12 | }, 13 | ]; 14 | -------------------------------------------------------------------------------- /client/src/website/utils/sync.ts: -------------------------------------------------------------------------------- 1 | export type Unlock = () => void; 2 | 3 | export interface SyncPair { 4 | lock: Promise; 5 | unlock: Unlock; 6 | } 7 | 8 | export function genSync(): SyncPair { 9 | let unlock: Unlock = () => {}; 10 | let p = new Promise(resolve => (unlock = resolve)); 11 | 12 | return { 13 | unlock, 14 | lock: p, 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /client/config/jest/fileTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | 5 | // This is a custom Jest transformer turning file imports into filenames. 6 | // http://facebook.github.io/jest/docs/en/webpack.html 7 | 8 | module.exports = { 9 | process(src, filename) { 10 | return `module.exports = ${JSON.stringify(path.basename(filename))};`; 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /server/src/services/auth.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AuthService { 5 | // API Server performs specific JWT validation logic 6 | validateToken(token: string) { 7 | // TODO: just validate the token whether is a JWT or not, 8 | // rather than validate using secret 9 | 10 | return !!token; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /client/src/website/types/type-utils.ts: -------------------------------------------------------------------------------- 1 | export type Optional = {[P in keyof T]?: T[P]}; 2 | 3 | export interface Dict { 4 | [index: string]: T; 5 | } 6 | 7 | export type Compose = { 8 | [P in E]: T[P]; 9 | }; 10 | 11 | export type Omit = Compose>; 12 | 13 | export type Constructable = new (...args: any[]) => T; 14 | -------------------------------------------------------------------------------- /shared/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../node_modules/@magicspace/configs/tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "lib": ["dom", "esnext"], 6 | "outDir": "dist", 7 | "types": ["node"], 8 | "declaration": true, 9 | "suppressImplicitAnyIndexErrors": true 10 | }, 11 | "include": ["src/**/*"], 12 | "exclude": ["node_modules/**/*"] 13 | } 14 | -------------------------------------------------------------------------------- /client/src/website/index.tsx: -------------------------------------------------------------------------------- 1 | // tslint:disable-next-line:scoped-modules 2 | import 'animate.css/animate.min.css'; 3 | import 'highlight.js/styles/atom-one-dark.css'; 4 | 5 | import * as React from 'react'; 6 | import * as ReactDOM from 'react-dom'; 7 | 8 | import {App} from './App'; 9 | import './assets/iconfont/iconfont.css'; 10 | 11 | ReactDOM.render(, document.getElementById('root')); 12 | -------------------------------------------------------------------------------- /client/config/jest/cssTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // This is a custom Jest transformer turning style imports into empty objects. 4 | // http://facebook.github.io/jest/docs/en/webpack.html 5 | 6 | module.exports = { 7 | process() { 8 | return 'module.exports = {};'; 9 | }, 10 | getCacheKey() { 11 | // The output is always the same. 12 | return 'cssTransform'; 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /client/src/website/components/common/markdown/render-components/text.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import {Typography} from '@material-ui/core'; 3 | 4 | import {styledTheme} from 'website/theme'; 5 | 6 | export const MDText = styled(Typography)` 7 | display: inline; 8 | color: ${styledTheme.articleColor}; 9 | font-size: 16px; 10 | font-weight: 400; 11 | line-height: 1.7; 12 | `; 13 | -------------------------------------------------------------------------------- /client/src/website/utils/color-generator.ts: -------------------------------------------------------------------------------- 1 | export function colorGenerator(): string { 2 | const colors: string[] = [ 3 | '#00b894', 4 | '#00cec9', 5 | '#0984e3', 6 | '#6c5ce7', 7 | '#fdcb6e', 8 | '#e17055', 9 | '#e84393', 10 | '#2d3436', 11 | '#636e72', 12 | '#ff7675', 13 | ]; 14 | 15 | return colors[parseInt((Math.random() * colors.length).toString())]; 16 | } 17 | -------------------------------------------------------------------------------- /server/src/decorators/auth/jwt.ts: -------------------------------------------------------------------------------- 1 | import {createParamDecorator, ExecutionContext, CustomDecorator} from '@nestjs/common'; 2 | import {Request} from 'express'; 3 | 4 | import {AUTH_KEY} from 'src/constants'; 5 | 6 | export const Jwt = createParamDecorator((_data: unknown, ctx: ExecutionContext) => { 7 | const {headers}: Request = ctx.switchToHttp().getRequest(); 8 | 9 | return headers[AUTH_KEY]; 10 | }); 11 | -------------------------------------------------------------------------------- /packages/http-request/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../node_modules/@magicspace/configs/tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "lib": ["dom", "esnext"], 6 | "outDir": "dist", 7 | "types": ["node"], 8 | "declaration": true, 9 | "suppressImplicitAnyIndexErrors": true 10 | }, 11 | "include": ["src/**/*"], 12 | "exclude": ["node_modules/**/*"] 13 | } 14 | -------------------------------------------------------------------------------- /client/src/website/components/common/overview-title.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | const Wrapper = styled.div` 5 | color: ${props => props.theme.titleColor}; 6 | font-size: 30px; 7 | `; 8 | 9 | export class OverviewTitle extends Component { 10 | render(): ReactNode { 11 | return {this.props.children}; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /client/src/website/routes/team-route.ts: -------------------------------------------------------------------------------- 1 | import {lazy} from 'website/utils'; 2 | 3 | import {Routes} from '../services'; 4 | 5 | const About = lazy(import('../pages/about'), 'About'); 6 | 7 | export const TeamRoutes: Routes = [ 8 | { 9 | path: '/team', 10 | layout: 'no-footer', 11 | children: [ 12 | { 13 | path: '/about', 14 | component: About, 15 | }, 16 | ], 17 | }, 18 | ]; 19 | -------------------------------------------------------------------------------- /client/src/website/services/tab-service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@wizardoc/injector'; 2 | import {observable, action} from 'mobx'; 3 | 4 | @Injectable() 5 | export class TabService { 6 | @observable 7 | isMainPage: boolean = true; 8 | 9 | /** 10 | * 根据切换的 tab 来判断是否需要更新样式 11 | */ 12 | @action 13 | updatePage(pathname: string): void { 14 | this.isMainPage = ['/home', '/'].includes(pathname); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/http-request/example/js/github-service.js: -------------------------------------------------------------------------------- 1 | import {http} from './http/http-service' 2 | 3 | export class GitHubService { 4 | getUserDetail(name) { 5 | return http.get(`/users/${name}`) 6 | } 7 | 8 | // Request to an incorrect addr 9 | async getWhatever() { 10 | const res = await http.get('/foo') 11 | 12 | res.expect(() => "This addr cannot be reached!").success(() => "impossible!") 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /server/src/app.controller.ts: -------------------------------------------------------------------------------- 1 | import {Controller, Get} from '@nestjs/common'; 2 | 3 | import {HTTP} from './services'; 4 | 5 | @Controller('/') 6 | export class AppController { 7 | constructor(private readonly http: HTTP) {} 8 | 9 | @Get() 10 | async getHello(): Promise { 11 | const res = await this.http.get('/doc/wizard'); 12 | 13 | console.info(res.data.data); 14 | 15 | return '/'; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /client/src/website/services/document/document-service.dto.ts: -------------------------------------------------------------------------------- 1 | import {UserModel} from '../user'; 2 | 3 | export interface DocumentComment { 4 | id: string; 5 | content: string; 6 | reply: string; 7 | createTime: number; 8 | up: number; 9 | down: number; 10 | user: UserModel; 11 | status: CommentStatus; 12 | documentID: string; 13 | } 14 | 15 | export enum CommentStatus { 16 | UP, 17 | DOWN, 18 | NONE, 19 | } 20 | -------------------------------------------------------------------------------- /client/src/website/theme/palette.ts: -------------------------------------------------------------------------------- 1 | import {red} from '@material-ui/core/colors'; 2 | import {createMuiTheme} from '@material-ui/core/styles'; 3 | 4 | export const theme = createMuiTheme({ 5 | palette: { 6 | primary: { 7 | main: '#3970f5', 8 | light: '#1976d2', 9 | }, 10 | secondary: { 11 | main: '#f06292', 12 | }, 13 | error: red, 14 | type: 'light', // mode: light dark 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /client/src/website/types/decorators.d.ts: -------------------------------------------------------------------------------- 1 | import 'react-router-dom'; 2 | import 'notistack'; 3 | import '@material-ui/core'; 4 | 5 | declare module 'react-router-dom' { 6 | export function withRouter(component: any): any; 7 | } 8 | 9 | declare module 'notistack' { 10 | export function withSnackbar(component: any): any; 11 | } 12 | 13 | declare module '@material-ui/core' { 14 | export function withStyles(...args: any[]): any; 15 | } 16 | -------------------------------------------------------------------------------- /client/src/website/components/common/tab/tab-content.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode, createContext} from 'react'; 2 | 3 | interface TabContentProps { 4 | query: string; 5 | } 6 | 7 | export const TabContext = createContext(undefined); 8 | 9 | export class TabContent extends Component { 10 | render(): ReactNode { 11 | return ; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/http-utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../node_modules/@magicspace/configs/tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "lib": ["dom", "esnext"], 6 | "outDir": "dist", 7 | "types": ["node"], 8 | "declaration": true, 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true 11 | }, 12 | "include": ["src/**/*"], 13 | "exclude": ["node_modules/**/*"] 14 | } 15 | -------------------------------------------------------------------------------- /client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Wizardoc 7 | 8 | 9 | 10 |
11 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /client/src/website/pages/doc.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {PageHeader} from '../components'; 5 | 6 | const Wrapper = styled.div` 7 | width: 100%; 8 | display: flex; 9 | `; 10 | 11 | export class Doc extends Component { 12 | render(): ReactNode { 13 | return ( 14 | 15 | 16 | 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/injector/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES5", 4 | "rootDir": "src", 5 | "lib": ["dom", "esnext"], 6 | "module": "commonjs", 7 | "outDir": "dist", 8 | "types": ["node"], 9 | "declaration": true, 10 | "suppressImplicitAnyIndexErrors": true, 11 | "experimentalDecorators": true, 12 | "emitDecoratorMetadata": true 13 | }, 14 | "include": ["src/**/*"], 15 | "exclude": ["node_modules/**/*"] 16 | } 17 | -------------------------------------------------------------------------------- /client/src/website/components/main/@skew-block.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | const Wrapper = styled.div` 5 | width: 100%; 6 | height: 450px; 7 | background: ${props => props.theme.mainPrimaryColor}; 8 | transform-origin: left; 9 | transform: skewY(-18deg); 10 | `; 11 | 12 | export class SkewBlock extends Component { 13 | render(): ReactNode { 14 | return ; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /client/src/website/ui/form-text-field.tsx: -------------------------------------------------------------------------------- 1 | import {TextField} from '@material-ui/core'; 2 | import {TextFieldProps} from '@material-ui/core/TextField'; 3 | import React, {FunctionComponent} from 'react'; 4 | 5 | interface FormTextFieldInnerProps { 6 | name: string; 7 | } 8 | 9 | export type FormTextFieldProps = FormTextFieldInnerProps & TextFieldProps; 10 | 11 | export const FormTextField: FunctionComponent = (props: FormTextFieldProps) => ( 12 | 13 | ); 14 | -------------------------------------------------------------------------------- /server/src/middlewares/reverse-proxy.ts: -------------------------------------------------------------------------------- 1 | import {NestMiddleware} from '@nestjs/common'; 2 | import {Request, Response} from 'express'; 3 | import {createProxyMiddleware} from 'http-proxy-middleware'; 4 | 5 | export class ReverseProxyMiddleware implements NestMiddleware { 6 | use(req: Request, res: Response, next: () => void): void { 7 | createProxyMiddleware({ 8 | target: 'http://localhost:4000', 9 | changeOrigin: true, 10 | })(req, res, next); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.vscode/typescriptreact.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "init_component": { 3 | "prefix": "rinit", 4 | "body": [ 5 | "import React, {Component, ReactNode} from 'react';", 6 | "import styled from 'styled-components';", 7 | "", 8 | "const Wrapper = styled.div``;", 9 | "", 10 | "export class $0 extends Component {", 11 | " render(): ReactNode {", 12 | " return ;", 13 | " }", 14 | "}" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /client/src/website/pages/public-space.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {PageHeader} from '../components'; 5 | 6 | const Wrapper = styled.div` 7 | width: 100%; 8 | display: flex; 9 | `; 10 | 11 | export class PublicSpace extends Component { 12 | render(): ReactNode { 13 | return ( 14 | 15 | 16 | 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /client/src/website/services/backdrop-service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@wizardoc/injector'; 2 | import {observable} from 'mobx'; 3 | 4 | @Injectable() 5 | export class BackdropService { 6 | @observable 7 | private _isViewBackdrop = false; 8 | 9 | get isViewBackdrop(): boolean { 10 | return this._isViewBackdrop; 11 | } 12 | 13 | show(): void { 14 | this._isViewBackdrop = true; 15 | } 16 | 17 | hide(): void { 18 | this._isViewBackdrop = false; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /client/src/website/services/permission/permission-service.dto.ts: -------------------------------------------------------------------------------- 1 | export type PermissionSet = number[]; 2 | 3 | // permission values 4 | export enum PermissionValues { 5 | // organization permissions 6 | ORG_DELETE, 7 | ORG_EDIT, 8 | ORG_INVITE, 9 | 10 | // category permissions 11 | CATEGORY_CREATE, 12 | CATEGORY_EDIT, 13 | 14 | // document permissions 15 | DOCUMENT_WRITE, 16 | DOCUMENT_READ, 17 | DOCUMENT_VIEW, 18 | DOCUMENT_DELETE, 19 | DOCUMENT_CREATE, 20 | } 21 | -------------------------------------------------------------------------------- /packages/http-utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wizardoc/http-utils", 3 | "version": "1.1.2", 4 | "main": "dist/index.js", 5 | "license": "MIT", 6 | "publishConfig": { 7 | "access": "public" 8 | }, 9 | "files": [ 10 | "dist/**/*" 11 | ], 12 | "dependencies": { 13 | "@wizardoc/shared": "^1.0.0", 14 | "reflect-metadata": "^0.1.13" 15 | }, 16 | "scripts": { 17 | "compile": "rimraf ./dist && tsc", 18 | "prepare": "yarn compile" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /client/src/website/services/document/@document-service.api.ts: -------------------------------------------------------------------------------- 1 | import {Group} from '@wizardoc/http-utils'; 2 | import {Injectable} from '@wizardoc/injector'; 3 | 4 | @Injectable() 5 | @Group('/doc') 6 | export class DocumentAPI { 7 | all = '/'; 8 | 9 | new = '/'; 10 | 11 | newComment = '/comment'; 12 | 13 | updateComment = '/comment'; 14 | 15 | comments = (documentID: string): string => `/comments/${documentID}`; 16 | 17 | detail = (id: string): string => `/detail/${id}`; 18 | } 19 | -------------------------------------------------------------------------------- /client/src/website/pages/common-style-component/access-wrapper.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const Wrapper = styled.div` 4 | height: calc(100vh - ${props => props.theme.headerBarHeight}); 5 | width: 100%; 6 | display: flex; 7 | justify-content: center; 8 | align-items: center; 9 | background: #eceff1; 10 | `; 11 | 12 | export const AccessBox = styled.div` 13 | width: 500px; 14 | height: 100%; 15 | background: #fff; 16 | border-radius: 0 10px 10px 0; 17 | `; 18 | -------------------------------------------------------------------------------- /packages/http-request/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wizardoc/http-request", 3 | "version": "1.3.1", 4 | "main": "dist/index.js", 5 | "license": "MIT", 6 | "dependencies": { 7 | "axios": "^0.19.2" 8 | }, 9 | "devDependencies": { 10 | "@babel/core": "^7.12.9", 11 | "@babel/plugin-transform-runtime": "^7.12.1", 12 | "@babel/preset-env": "^7.12.7", 13 | "@babel/register": "^7.12.1", 14 | "@types/axios": "^0.14.0", 15 | "babel-plugin-dynamic-import-node": "^2.3.3" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/markdown/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wizardoc/markdown", 3 | "version": "1.0.0", 4 | "main": "dist/index.js", 5 | "license": "MIT", 6 | "dependencies": { 7 | "draft-js": "^0.11.5", 8 | "draft-js-fluent-markdown-plugin": "^0.1.15", 9 | "draft-js-plugins-editor": "^3.0.0", 10 | "mobx": "^5.9.4", 11 | "mobx-react": "^5.4.3", 12 | "react": "^17.0.1", 13 | "styled-components": "^4.2.0" 14 | }, 15 | "devDependencies": { 16 | "@types/draft-js": "^0.10.40" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /client/src/website/theme/with-theme.tsx: -------------------------------------------------------------------------------- 1 | import React, {ComponentType, Component, ReactNode} from 'react'; 2 | 3 | import {StyledTheme, styledTheme} from './style'; 4 | 5 | export interface ThemeComponentProps { 6 | theme: StyledTheme; 7 | } 8 | 9 | export function withTheme, P>(RenderComponent: T): T { 10 | return class extends Component

{ 11 | render(): ReactNode { 12 | return ; 13 | } 14 | } as T; 15 | } 16 | -------------------------------------------------------------------------------- /client/src/website/utils/initialize.ts: -------------------------------------------------------------------------------- 1 | import {genSync, SyncPair} from './sync'; 2 | 3 | export abstract class Initialize { 4 | private syncPair: SyncPair; 5 | 6 | constructor() { 7 | this.syncPair = genSync(); 8 | this.initOperates(); 9 | } 10 | 11 | async initOperates(): Promise { 12 | await this.init(); 13 | 14 | this.syncPair.unlock(); 15 | } 16 | 17 | isInit(): Promise { 18 | return this.syncPair.lock; 19 | } 20 | 21 | abstract async init(): Promise; 22 | } 23 | -------------------------------------------------------------------------------- /client/src/website/utils/import.ts: -------------------------------------------------------------------------------- 1 | import React, {ComponentType, LazyExoticComponent} from 'react'; 2 | 3 | export interface DefaultModule { 4 | default: ComponentType; 5 | } 6 | 7 | export function defaultify( 8 | loader: Promise, 9 | name: string, 10 | ): Promise> { 11 | return loader.then(module => ({default: module[name]})); 12 | } 13 | 14 | export function lazy(loader: Promise, name: string): LazyExoticComponent { 15 | return React.lazy(() => defaultify(loader, name)); 16 | } 17 | -------------------------------------------------------------------------------- /client/src/website/utils/viewport-listener.ts: -------------------------------------------------------------------------------- 1 | /** 封装 IntersectionObserver,每次只可监听一个 dom 对象 */ 2 | export class ViewportListener { 3 | private io: IntersectionObserver; 4 | 5 | constructor(private dom: Element, cb: any, options?: IntersectionObserverInit) { 6 | this.io = new IntersectionObserver(cb, options); 7 | } 8 | 9 | listen(): void { 10 | this.io.observe(this.dom); 11 | } 12 | 13 | stop(): void { 14 | this.io.unobserve(this.dom); 15 | } 16 | 17 | destroy(): void { 18 | this.io.disconnect(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /client/src/website/components/common/markdown/@document-catalog.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {CatalogProps} from 'website/ui'; 5 | 6 | export interface DocumentCatalogProps extends CatalogProps {} 7 | 8 | const Wrapper = styled.div` 9 | width: 300px; 10 | `; 11 | 12 | export class DocumentCatalog extends Component { 13 | render(): ReactNode { 14 | return {/* */}; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /client/src/website/services/route/guards/deactivated-guard.ts: -------------------------------------------------------------------------------- 1 | import {RouteComponentProps} from 'react-router-dom'; 2 | 3 | import {Constructable} from 'website/types/type-utils'; 4 | 5 | import {Route, OriginGuard} from '../route'; 6 | 7 | export type DeactivatedGuardConstructor = Constructable; 8 | 9 | export type OriginDeactivatedGuardConstructor = OriginGuard; 10 | 11 | export interface DeactivatedGuard { 12 | canDeactivate(route: Route, props: RouteComponentProps): boolean | string; 13 | } 14 | -------------------------------------------------------------------------------- /client/src/website/services/time/time-utils.ts: -------------------------------------------------------------------------------- 1 | import Moment from 'moment'; 2 | 3 | export class TimeUtil { 4 | private _timeStamp: number; 5 | 6 | constructor(timeStamp: number) { 7 | this._timeStamp = timeStamp; 8 | } 9 | 10 | delay(): void {} 11 | 12 | get timeStamp(): number { 13 | return this._timeStamp; 14 | } 15 | 16 | get date(): Date { 17 | return new Date(this._timeStamp); 18 | } 19 | 20 | format(formatString?: string): string { 21 | return Moment(this._timeStamp).format(formatString); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /client/src/website/pages/message-center.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {MessageOverview} from '../components'; 5 | 6 | const Wrapper = styled.div` 7 | width: 100%; 8 | height: 100%; 9 | background: ${props => props.theme.blueGrayBg}; 10 | display: flex; 11 | `; 12 | 13 | export class MessageCenter extends Component { 14 | render(): ReactNode { 15 | return ( 16 | 17 | 18 | 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /client/src/website/components/common/md-render.tsx: -------------------------------------------------------------------------------- 1 | import React, {FunctionComponent} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {markdown} from '../../utils'; 5 | 6 | interface MDRenderProps { 7 | content: string; 8 | } 9 | 10 | const Wrapper = styled.div` 11 | transition: 0.3s all; 12 | 13 | &:target { 14 | transform: translateY(70px); 15 | } 16 | `; 17 | 18 | export const MDRender: FunctionComponent = ({content}) => ( 19 | 20 | ); 21 | -------------------------------------------------------------------------------- /client/src/website/components/common/tab/tab-content-item.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | 3 | import {TabContext} from './tab-content'; 4 | 5 | export interface TabContentItemProps { 6 | view: string; 7 | } 8 | 9 | export class TabContentItem extends Component { 10 | render(): ReactNode { 11 | const {view, children} = this.props; 12 | 13 | return ( 14 | 15 | {value => value && value === view && children} 16 | 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /client-dist 4 | /node_modules 5 | 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | 14 | # OS 15 | .DS_Store 16 | 17 | # Tests 18 | /coverage 19 | /.nyc_output 20 | 21 | # IDEs and editors 22 | /.idea 23 | .project 24 | .classpath 25 | .c9/ 26 | *.launch 27 | .settings/ 28 | *.sublime-workspace 29 | 30 | # IDE - VSCode 31 | .vscode/* 32 | !.vscode/settings.json 33 | !.vscode/tasks.json 34 | !.vscode/launch.json 35 | !.vscode/extensions.json 36 | -------------------------------------------------------------------------------- /server/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@magicspace/configs/tslint-prettier", 3 | "rules": { 4 | "no-void-expression": false, 5 | "no-implicit-dependencies": false, 6 | "no-conditional-assignment": false, 7 | "no-unused-expression": false, 8 | "ordered-imports": false, 9 | "no-inferred-empty-object-type": false, 10 | "object-literal-sort-keys": false, 11 | "no-floating-promises": false, 12 | "no-bitwise": false, 13 | "explicit-return-type": false 14 | }, 15 | "linterOptions": { 16 | "exclude": ["node_modules/**"] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /client/src/website/components/access/username.tsx: -------------------------------------------------------------------------------- 1 | import {TextFieldProps} from '@material-ui/core/TextField'; 2 | import React, {FunctionComponent} from 'react'; 3 | 4 | import {TextFieldWrapper} from '../register'; 5 | 6 | import {AccessProps} from './props'; 7 | 8 | export const UserName: FunctionComponent = props => ( 9 | 19 | ); 20 | -------------------------------------------------------------------------------- /client/src/website/components/common/avatar/current-avatar.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import {Inject} from '@wizardoc/injector'; 3 | 4 | import {User} from 'website/services'; 5 | 6 | import {Avatar} from './avatar'; 7 | 8 | export interface CurrentAvatarProps {} 9 | 10 | export class CurrentAvatar extends Component { 11 | @Inject 12 | user!: User; 13 | 14 | render(): ReactNode { 15 | const {avatar, userInfo} = this.user; 16 | 17 | return ; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /client/src/website/guards/overview/overview-auth.ts: -------------------------------------------------------------------------------- 1 | import {Inject} from '@wizardoc/injector'; 2 | 3 | import {ActivatedGuard, User, Toast} from 'website/services'; 4 | 5 | export class OverviewAuthGuard implements ActivatedGuard { 6 | @Inject 7 | private user!: User; 8 | 9 | @Inject 10 | private toast!: Toast; 11 | 12 | async canActivated(): Promise { 13 | await this.user.isInit(); 14 | 15 | if (!this.user.isLogin) { 16 | this.toast.error('您还未登录哦~'); 17 | 18 | return '/home'; 19 | } 20 | 21 | return true; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /client/src/website/pages/user-pages/user-detail.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {UserCard} from 'website/components'; 5 | 6 | const Wrapper = styled.div` 7 | width: 100%; 8 | height: 100vh; 9 | background: ${props => props.theme.flatGray}; 10 | display: flex; 11 | justify-content: center; 12 | `; 13 | 14 | export class UserDetailPage extends Component { 15 | render(): ReactNode { 16 | return ( 17 | 18 | 19 | 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "editor.tabSize": 2, 4 | "editor.insertSpaces": true, 5 | "files.eol": "\n", 6 | "files.insertFinalNewline": true, 7 | "files.trimTrailingWhitespace": true, 8 | "typescript.tsdk": "node_modules/typescript/lib", 9 | "tslint.autoFixOnSave": true, 10 | "tslint.configFile": "client/tslint.json", 11 | "[plaintext]": { 12 | "files.insertFinalNewline": false 13 | }, 14 | "commentTranslate.targetLanguage": "zh", 15 | "editor.defaultFormatter": "esbenp.prettier-vscode", 16 | "cSpell.words": ["defaultify"] 17 | } 18 | -------------------------------------------------------------------------------- /client/src/website/services/doc-service.ts: -------------------------------------------------------------------------------- 1 | import {Inject, Injectable} from '@wizardoc/injector'; 2 | 3 | import {ContributorInfo} from '../components'; 4 | 5 | import {HTTP} from './http'; 6 | 7 | @Injectable() 8 | export class DocService { 9 | @Inject 10 | http!: HTTP; 11 | 12 | private readonly usernames: string[] = ['HaoDaWang', 'pp3229292', 'mpclyl', 'XyyF']; 13 | 14 | getAboutWizard(): string { 15 | // return await this.http.get(DOC_API.WIZARD); 16 | 17 | return ''; 18 | } 19 | 20 | getContributorAvatars(): ContributorInfo[] { 21 | return []; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /client/src/website/services/organization/@organization-service.api.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@wizardoc/injector'; 2 | import {Group} from '@wizardoc/http-utils'; 3 | 4 | @Injectable() 5 | @Group('/organization') 6 | export class OrganizationAPI { 7 | allName = '/name/all'; 8 | 9 | all = '/joins/all'; 10 | 11 | new = '/new'; 12 | 13 | join = '/join'; 14 | 15 | invite = '/invite'; 16 | 17 | accept = (token: string): string => `/accept/${token}`; 18 | 19 | edit = (id: string): string => `/edit/${id}`; 20 | 21 | remove = (name: string): string => `/remove/${name}`; 22 | } 23 | -------------------------------------------------------------------------------- /client/src/website/components/common/markdown/render-components/inline-code.tsx: -------------------------------------------------------------------------------- 1 | import React, {ReactNode, Component} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {styledTheme} from 'website/theme'; 5 | 6 | const Wrapper = styled.span` 7 | background: ${styledTheme.shallowSecondaryColor}; 8 | color: ${styledTheme.secondaryColor}; 9 | padding: 2px 5px; 10 | border-radius: 3px; 11 | font-size: 14px; 12 | `; 13 | 14 | export class MDInlineCode extends Component { 15 | render(): ReactNode { 16 | return {this.props.children}; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /client/src/website/routes/app-route.ts: -------------------------------------------------------------------------------- 1 | import {lazy} from 'website/utils'; 2 | 3 | import {Routes} from '../services'; 4 | import {Home} from '../pages/home'; 5 | 6 | const Organization = lazy(import('../pages/organization'), 'Organization'); 7 | 8 | export const RootRoutes: Routes = [ 9 | { 10 | path: '/', 11 | redirect: '/home', 12 | }, 13 | { 14 | path: '/home', 15 | component: Home, 16 | headerType: 'default', 17 | isFullContainer: false, 18 | layout: 'no-header', 19 | }, 20 | { 21 | path: '/organizations', 22 | component: Organization, 23 | }, 24 | ]; 25 | -------------------------------------------------------------------------------- /client/src/website/components/doc/doc-page/organization-info-card.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode, ComponentType} from 'react'; 2 | import {Card} from '@material-ui/core'; 3 | import styled from 'styled-components'; 4 | import {CardProps} from '@material-ui/core/Card'; 5 | 6 | const Wrapper = styled(Card)` 7 | width: 300px !important; 8 | height: 500px !important; 9 | flex-shrink: 0; 10 | position: sticky; 11 | top: 70px; 12 | ` as ComponentType; 13 | 14 | export class OrganizationInfoCard extends Component { 15 | render(): ReactNode { 16 | return ; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/http-request/src/lib/interceptor.ts: -------------------------------------------------------------------------------- 1 | import {AxiosRequestConfig, AxiosResponse, AxiosError} from 'axios'; 2 | 3 | export interface HTTPResponseInterceptor { 4 | onResponse(res: AxiosResponse): AxiosResponse | Promise; 5 | } 6 | 7 | export interface HTTPRequestInterceptor { 8 | onRequest( 9 | req: AxiosRequestConfig, 10 | ): AxiosRequestConfig | Promise; 11 | } 12 | 13 | export interface HTTPRequestErrorCatch { 14 | catchReq(err: AxiosError): void; 15 | } 16 | 17 | export interface HTTPResponseErrorCatch { 18 | catchRes(err: AxiosError): void; 19 | } 20 | -------------------------------------------------------------------------------- /client/src/website/components/footer/footer.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {FooterDeclare} from './@footer-declare'; 5 | import {FooterPanel} from './@panel'; 6 | 7 | const Wrapper = styled.div` 8 | width: 100%; 9 | position: absolute; 10 | bottom: 0; 11 | left: 0; 12 | overflow: hidden; 13 | `; 14 | 15 | export class Footer extends Component { 16 | render(): ReactNode { 17 | return ( 18 | 19 | 20 | 21 | 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /server/src/modules/user.module.ts: -------------------------------------------------------------------------------- 1 | import {Module} from '@nestjs/common'; 2 | import {APP_GUARD} from '@nestjs/core'; 3 | 4 | import {UserAccessController, UserFollowController} from 'src/controllers'; 5 | import {HTTP, HTTPFactory, AuthService} from 'src/services'; 6 | import {GraphQL} from 'src/guards'; 7 | 8 | @Module({ 9 | imports: [], 10 | controllers: [UserAccessController, UserFollowController], 11 | providers: [ 12 | HTTPFactory, 13 | AuthService, 14 | HTTP, 15 | { 16 | provide: APP_GUARD, 17 | useClass: GraphQL, 18 | }, 19 | ], 20 | }) 21 | export class UserModule {} 22 | -------------------------------------------------------------------------------- /client/src/website/components/release-banner/release-tag.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | export interface ReleaseTagProps { 5 | tag: 'NEW' | 'PATCH' | 'FEATURE'; 6 | } 7 | 8 | const Wrapper = styled.div` 9 | background: ${props => props.theme.flatYellow}; 10 | padding: 3px; 11 | border-radius: 5px; 12 | color: ${props => props.theme.white}; 13 | margin: 1px; 14 | `; 15 | 16 | export class ReleaseTag extends Component { 17 | render(): ReactNode { 18 | return {this.props.tag}; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /client/src/website/pages/common-style-component/center.tsx: -------------------------------------------------------------------------------- 1 | import React, {FunctionComponent} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {Center} from '../../ui'; 5 | 6 | const TipHeader = styled.div` 7 | width: 100%; 8 | margin-top: 30px; 9 | padding: 0 30px; 10 | box-sizing: border-box; 11 | `; 12 | 13 | const CenterText = styled.span` 14 | color: white; 15 | `; 16 | 17 | export const CenterLine: FunctionComponent = props => ( 18 | 19 |

20 | {props.children} 21 |
22 | 23 | ); 24 | -------------------------------------------------------------------------------- /client/src/website/services/message/message-service.api.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@wizardoc/injector'; 2 | import {Group, AbsURL} from '@wizardoc/http-utils'; 3 | 4 | // import {httpFactory} from '../http'; 5 | 6 | @Injectable() 7 | @Group('/message') 8 | export class MessageServiceAPI { 9 | @AbsURL({protocol: 'ws', baseUrl: 'localhost:4000'}) 10 | connect = '/connect'; 11 | 12 | all = '/all'; 13 | 14 | send = '/send'; 15 | 16 | delete = (id: string): string => `/delete/${id}`; 17 | 18 | revoke = (id: string): string => `/revoke/${id}`; 19 | 20 | read = (id: string): string => `/read/${id}`; 21 | } 22 | -------------------------------------------------------------------------------- /client/src/website/components/common/upload/image-upload.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | 3 | import {UploadProps, TypeUpload} from 'website/ui'; 4 | import {MIME, MIMEType} from 'website/utils'; 5 | 6 | export interface ImageUploadProps extends UploadProps {} 7 | 8 | export class ImageUpload extends Component { 9 | render(): ReactNode { 10 | return ( 11 | 15 | {this.props.children} 16 | 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/markdown/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.react.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "lib": ["dom", "esnext"], 6 | "outDir": "dist", 7 | "types": ["node"], 8 | "declaration": true, 9 | "suppressImplicitAnyIndexErrors": true, 10 | "experimentalDecorators": true, 11 | "emitDecoratorMetadata": true, 12 | "skipDefaultLibCheck": true, 13 | "skipLibCheck": true, 14 | "noImplicitAny": false, 15 | "noUnusedLocals": false, 16 | "noUnusedParameters": false 17 | }, 18 | "include": ["src/**/*"], 19 | "exclude": ["node_modules/**/*"] 20 | } 21 | -------------------------------------------------------------------------------- /client/src/website/components/doc/share/@shape.tsx: -------------------------------------------------------------------------------- 1 | import React, {FunctionComponent} from 'react'; 2 | 3 | export const Shape: FunctionComponent = () => ( 4 | 5 | 6 | 7 | 8 | 14 | 15 | 16 | 17 | 18 | ); 19 | -------------------------------------------------------------------------------- /client/src/website/components/common/markdown/render-components/block-quote.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {styledTheme} from 'website/theme'; 5 | 6 | const Wrapper = styled.div` 7 | width: 100%; 8 | background: ${styledTheme.shallowPrimaryColor}; 9 | padding: 10px 22px; 10 | border-radius: 3px; 11 | border-left: 4px solid ${styledTheme.primaryColor}; 12 | box-sizing: border-box; 13 | `; 14 | 15 | export class MDBlockQuote extends Component { 16 | render(): ReactNode { 17 | return {this.props.children}; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /client/src/website/components/common/markdown/render-components/heading.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode, createElement} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {styledTheme} from 'website/theme'; 5 | 6 | export interface HeaderProps { 7 | level: number; 8 | } 9 | 10 | const Wrapper = styled.div` 11 | color: ${styledTheme.headingColor} !important; 12 | `; 13 | 14 | export class Heading extends Component { 15 | render(): ReactNode { 16 | const {level, children} = this.props; 17 | 18 | return {createElement(`h${level}`, {id: children}, children)}; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /server/src/guards/graphql.guard.ts: -------------------------------------------------------------------------------- 1 | import {CanActivate, Injectable, ExecutionContext} from '@nestjs/common'; 2 | 3 | import {HTTP} from 'src/services'; 4 | import {GraphQLClientRequest} from 'src/decorators'; 5 | 6 | @Injectable() 7 | export class GraphQL implements CanActivate { 8 | constructor(private http: HTTP) {} 9 | 10 | canActivate(ctx: ExecutionContext): boolean { 11 | const req = ctx.switchToHttp().getRequest(); 12 | 13 | // Mount endpoint of GraphQL on request object to visit it 14 | // by GraphQL client later 15 | req.graphQLEndpoint = this.http.graphqlEndpoint; 16 | 17 | return true; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /server/src/main.ts: -------------------------------------------------------------------------------- 1 | import {NestFactory} from '@nestjs/core'; 2 | 3 | import {AppModule} from './app.module'; 4 | import {GlobalErrorFilter, TransferRequest} from './filters'; 5 | import {HTTP} from './services'; 6 | 7 | async function bootstrap(): Promise { 8 | const app = await NestFactory.create(AppModule, { 9 | cors: { 10 | credentials: true, 11 | origin: `http://localhost:${process.env.CLIENT_PORT}`, 12 | }, 13 | }); 14 | 15 | app.useGlobalFilters( 16 | new TransferRequest(app.select(AppModule).get(HTTP)), 17 | new GlobalErrorFilter(), 18 | ); 19 | 20 | await app.listen(3000); 21 | } 22 | 23 | bootstrap(); 24 | -------------------------------------------------------------------------------- /client/src/website/services/toast.ts: -------------------------------------------------------------------------------- 1 | import {Injectable, Inject} from '@wizardoc/injector'; 2 | 3 | import {TipService} from './tip-service'; 4 | 5 | @Injectable() 6 | export class Toast { 7 | @Inject 8 | private tipService!: TipService; 9 | 10 | success(text: string): void { 11 | this.tipService.showSnackBar(text, 'success'); 12 | } 13 | 14 | error(text: string): void { 15 | this.tipService.showSnackBar(text, 'error'); 16 | } 17 | 18 | warning(text: string): void { 19 | this.tipService.showSnackBar(text, 'warning'); 20 | } 21 | 22 | info(text: string): void { 23 | this.tipService.showSnackBar(text, 'info'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /client/src/website/utils/store-injector.ts: -------------------------------------------------------------------------------- 1 | const storePool: Map = new Map(); 2 | 3 | type AttributeDecoratorProcessor = (constructor: object, key: string) => void; 4 | 5 | export function InjectStore(storeConstructor: Function): AttributeDecoratorProcessor { 6 | return (constructor: object, key: string) => { 7 | let storeInstance: Function = storePool.get(storeConstructor)!; 8 | 9 | if (!storePool.has(storeConstructor)) { 10 | storeInstance = new (storeConstructor as FunctionConstructor)(); 11 | storePool.set(storeConstructor, storeInstance); 12 | } 13 | 14 | constructor[key] = storeInstance; 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /client/src/website/components/pen/utils/@list-utils.ts: -------------------------------------------------------------------------------- 1 | import FormatListBulletedIcon from '@material-ui/icons/FormatListBulleted'; 2 | import FormatListNumberedIcon from '@material-ui/icons/FormatListNumbered'; 3 | import WatchIcon from '@material-ui/icons/Watch'; 4 | 5 | import {Util} from './utils-box'; 6 | 7 | export const ListUtils: Util[] = [ 8 | { 9 | tip: '无序列表', 10 | style: 'bulleted-list', 11 | icon: FormatListBulletedIcon, 12 | }, 13 | { 14 | tip: '有序列表', 15 | style: 'numbered-list', 16 | icon: FormatListNumberedIcon, 17 | }, 18 | { 19 | tip: '待办事项', 20 | style: 'todo-list', 21 | icon: WatchIcon, 22 | }, 23 | ]; 24 | -------------------------------------------------------------------------------- /client/src/website/services/organization/organization-service.dto.ts: -------------------------------------------------------------------------------- 1 | import {UserBaseInfo} from '../user'; 2 | import {PermissionValues} from '../permission'; 3 | 4 | export interface OrganizationCardData { 5 | id: string; 6 | ownerInfo: UserBaseInfo; 7 | organizeName: string; 8 | description: string; 9 | hasValid: string; 10 | createTime: number; 11 | joinTime: number; 12 | members: UserBaseInfo[]; 13 | isOwner: boolean; 14 | permissions: PermissionValues[]; 15 | } 16 | 17 | export interface OrganizationNames { 18 | organizeNames: string[]; 19 | } 20 | 21 | export interface AllOrganization { 22 | organizations: OrganizationCardData[]; 23 | } 24 | -------------------------------------------------------------------------------- /client/src/website/components/doc-recent-update-drawer.tsx: -------------------------------------------------------------------------------- 1 | import {List} from '@material-ui/core'; 2 | import PetsIcon from '@material-ui/icons/Pets'; 3 | import {observer} from 'mobx-react'; 4 | import React, {Component, ReactNode} from 'react'; 5 | 6 | import {DrawerHeader} from '../ui'; 7 | 8 | const HEAD_PROMPT = '显示近期的文档动态'; 9 | 10 | @observer 11 | export class DocRecentUpdateDrawer extends Component { 12 | render(): ReactNode { 13 | return ( 14 | 15 | } 18 | description="展示近30天的文档修改记录" 19 | /> 20 | 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /client/src/website/services/observer/observer.ts: -------------------------------------------------------------------------------- 1 | import {NotifyMessage, ChatMessage} from '../message'; 2 | 3 | export interface NotifyMessageObserver { 4 | onNotifyMessage(msg: NotifyMessage): void; 5 | onNotifyMessageAppended(msgs: NotifyMessage[]): void; 6 | } 7 | 8 | export interface ChatMessageObserver { 9 | onChatMessage(msg: ChatMessage): void; 10 | onChatMessageAppended(msgs: ChatMessage[]): void; 11 | } 12 | 13 | type Observers = NotifyMessageObserver & ChatMessageObserver; 14 | 15 | export type Observer = Partial; 16 | 17 | // type UnionToIntersection = 18 | // (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; 19 | -------------------------------------------------------------------------------- /packages/http-request/example/js/main.js: -------------------------------------------------------------------------------- 1 | import {GitHubService} from './github-service'; 2 | 3 | const MOCK_USERNAME = 'youncccat'; 4 | 5 | async function main() { 6 | // The service might inject in class as well as bound a certain variable using 7 | // DI lib that implemented by metadata in particular condition 8 | const githubService = new GitHubService(); 9 | const res = await githubService.getUserDetail(MOCK_USERNAME); 10 | 11 | const {data: avatarURL} = res 12 | .expect(() => `Cannot access ${MOCK_USERNAME} information`) 13 | .pipe(data => data?.avatar_url); 14 | 15 | console.info(`${MOCK_USERNAME}'s avatar is ${avatarURL}`); 16 | } 17 | 18 | main(); 19 | -------------------------------------------------------------------------------- /client/src/website/components/overview/overview-docs/document/document-title.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | import {TextField} from '@material-ui/core'; 4 | 5 | export interface DocumentTitleProps { 6 | onTitleSelected(title: string): void; 7 | } 8 | 9 | const Wrapper = styled.div``; 10 | 11 | export class DocumentTitle extends Component { 12 | render(): ReactNode { 13 | const {onTitleSelected} = this.props; 14 | 15 | return ( 16 | 17 | onTitleSelected(e.target.value)} /> 18 | 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /client/src/website/services/markdown-service/@plugins/inline-processor.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import MarkdownIt from 'markdown-it'; 3 | import {renderToStaticMarkup} from 'react-dom/server'; 4 | 5 | import {MDImage, MDInlineCode} from 'website/components'; 6 | 7 | export function inlineProcessor(markdown: MarkdownIt): void { 8 | markdown.renderer.rules.image = (tokens, idx) => 9 | renderToStaticMarkup(); 10 | 11 | markdown.renderer.rules.code_inline = (tokens, idx) => { 12 | console.info(tokens[idx]); 13 | 14 | return renderToStaticMarkup({tokens[idx].content}); 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /client/src/website/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './about'; 2 | export * from './common'; 3 | export * from './community'; 4 | export * from './doc'; 5 | export * from './doc-recent-update-drawer'; 6 | export * from './floating-pop'; 7 | export * from './footer'; 8 | export * from './header-bar'; 9 | export * from './login'; 10 | export * from './main'; 11 | export * from './message-center'; 12 | export * from './optional-tip'; 13 | export * from './organization'; 14 | export * from './overview'; 15 | export * from './pen'; 16 | export * from './register'; 17 | export * from './release-banner'; 18 | export * from './user'; 19 | export * from './user-detail'; 20 | export * from './user-settings'; 21 | -------------------------------------------------------------------------------- /client/src/website/services/route/guards/activated-guard.ts: -------------------------------------------------------------------------------- 1 | import {RouteComponentProps} from 'react-router-dom'; 2 | 3 | import {Constructable} from 'website/types/type-utils'; 4 | 5 | import {Route, OriginGuard} from '../route'; 6 | 7 | export type ActivatedGuardConstructor = Constructable; 8 | 9 | export type OriginActivatedGuardConstructor = OriginGuard; 10 | 11 | export type PropsInjector = (props: object) => void; 12 | 13 | export interface ActivatedGuard { 14 | canActivated( 15 | route: Route, 16 | props: RouteComponentProps, 17 | inject: PropsInjector, 18 | ): boolean | Route['path'] | Promise; 19 | } 20 | -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../node_modules/@magicspace/configs/tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "declaration": true, 6 | "removeComments": true, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "target": "es2017", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true, 14 | "types": ["express"], 15 | "resolveJsonModule": true, 16 | "strict": false, 17 | "noImplicitAny": false, 18 | "noUnusedLocals": false, 19 | "skipDefaultLibCheck": true, 20 | "skipLibCheck": true, 21 | }, 22 | "exclude": ["node_modules", "dist"] 23 | } 24 | -------------------------------------------------------------------------------- /server/src/filters/transfer-request.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Catch, 3 | ExceptionFilter, 4 | HttpException, 5 | ArgumentsHost, 6 | NotFoundException, 7 | } from '@nestjs/common'; 8 | import {Request, Response} from 'express'; 9 | 10 | import {HTTP} from 'src/services'; 11 | 12 | @Catch(NotFoundException) 13 | export class TransferRequest implements ExceptionFilter { 14 | constructor(private readonly http: HTTP) {} 15 | 16 | async catch(_exception: HttpException, host: ArgumentsHost): Promise { 17 | const {getRequest, getResponse} = host.switchToHttp(); 18 | const req = getRequest(); 19 | const res = getResponse(); 20 | 21 | this.http.proxySend(req, res); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /client/src/website/ui/center.tsx: -------------------------------------------------------------------------------- 1 | import React, {FunctionComponent} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {Line, LineProps} from './line'; 5 | 6 | interface CenterProps extends LineProps {} 7 | 8 | const Wrapper = styled.div` 9 | display: flex; 10 | justify-content: center; 11 | align-items: center; 12 | `; 13 | 14 | const Content = styled.div` 15 | background: ${props => props.theme.primaryColor}; 16 | `; 17 | 18 | const CenterLine = styled(Line)``; 19 | 20 | export const Center: FunctionComponent = props => ( 21 | 22 | 23 | {props.children} 24 | 25 | 26 | ); 27 | -------------------------------------------------------------------------------- /client/src/website/services/http/@interceptors/request-type.ts: -------------------------------------------------------------------------------- 1 | import {HTTPRequestInterceptor, AxiosRequestConfig} from '@wizardoc/http-request'; 2 | import {Inject} from '@wizardoc/injector'; 3 | 4 | import {JWT} from '../../jwt-service'; 5 | 6 | export class RequestType implements HTTPRequestInterceptor { 7 | @Inject 8 | jwtService!: JWT; 9 | 10 | onRequest( 11 | config: AxiosRequestConfig, 12 | ): AxiosRequestConfig | Promise { 13 | // attach jwt in authentication of header 14 | const JWT = this.jwtService.JWTString; 15 | 16 | return { 17 | ...config, 18 | headers: { 19 | ...config.headers, 20 | Authentication: JWT, 21 | }, 22 | }; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /server/src/app.module.ts: -------------------------------------------------------------------------------- 1 | import {Module} from '@nestjs/common'; 2 | 3 | import {AppController} from './app.controller'; 4 | import {AppService} from './app.service'; 5 | import {HTTP, HTTPFactory} from './services'; 6 | import {CategoryController, DocumentProcessorController} from './controllers'; 7 | import {UserModule, StaticServerModule} from './modules'; 8 | 9 | @Module({ 10 | imports: [UserModule, StaticServerModule], 11 | controllers: [AppController, CategoryController, DocumentProcessorController], 12 | providers: [AppService, HTTP, HTTPFactory], 13 | }) 14 | export class AppModule { 15 | // configure(consumer: MiddlewareConsumer): void { 16 | // consumer.apply(ReverseProxyMiddleware).forRoutes('*'); 17 | // } 18 | } 19 | -------------------------------------------------------------------------------- /client/src/website/ui/drawer/drawer.tsx: -------------------------------------------------------------------------------- 1 | import {SwipeableDrawer} from '@material-ui/core'; 2 | import {omit} from 'lodash'; 3 | import {observer} from 'mobx-react'; 4 | import React, {Component, ReactNode} from 'react'; 5 | 6 | import {ParsedDrawerOptions} from '../../services'; 7 | 8 | export interface DrawerProps extends ParsedDrawerOptions { 9 | open: boolean; 10 | renderDrawer?: ReactNode; 11 | } 12 | 13 | @observer 14 | export class Drawer extends Component { 15 | render(): ReactNode { 16 | const innerProps = omit(this.props, 'renderDrawer'); 17 | const {renderDrawer, children} = this.props; 18 | 19 | return {renderDrawer || children}; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /client/src/website/components/common/loading/normal-loading.tsx: -------------------------------------------------------------------------------- 1 | import {CircularProgress} from '@material-ui/core'; 2 | import React, {Component, ReactNode} from 'react'; 3 | import styled from 'styled-components'; 4 | 5 | const Wrapper = styled.div` 6 | display: flex; 7 | flex-direction: column; 8 | justify-content: center; 9 | align-items: center; 10 | width: 100%; 11 | height: 100%; 12 | position: fixed; 13 | z-index: 10000; 14 | background: rgba(0, 0, 0, 0.7); 15 | color: white; 16 | `; 17 | 18 | export class NormalLoading extends Component { 19 | render(): ReactNode { 20 | return ( 21 | 22 | 23 |

Loading...

24 |
25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /client/src/website/services/permission/permission-service.ts: -------------------------------------------------------------------------------- 1 | import {Inject, Injectable} from '@wizardoc/injector'; 2 | 3 | import {HTTP} from '../http'; 4 | 5 | import {PermissionServiceAPI} from './@permission-service.api'; 6 | import {PermissionSet} from './permission-service.dto'; 7 | 8 | @Injectable() 9 | export class PermissionService { 10 | @Inject 11 | private api!: PermissionServiceAPI; 12 | 13 | @Inject 14 | private http!: HTTP; 15 | 16 | async getOrganizationPermissions(): Promise { 17 | const result = await this.http.get(this.api.organizationAll('www')); 18 | 19 | return result 20 | .expect(() => '获取组织权限失败') 21 | .success((data: PermissionSet | null) => data ?? []).data; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /client/src/website/pages/document-pages/document-center.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {SwitchBar, SwitchBarTabItem} from 'website/components'; 5 | 6 | const Wrapper = styled.div` 7 | width: 100%; 8 | height: 100vh; 9 | background: ${props => props.theme.shallowGrayBlue}; 10 | `; 11 | 12 | const switchBarTabs: SwitchBarTabItem[] = [ 13 | {name: '全部', route: '/document/center'}, 14 | {name: '私有', route: '/document/'}, 15 | ]; 16 | 17 | export class DocumentCenter extends Component { 18 | render(): ReactNode { 19 | return ( 20 | 21 | 22 | 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /client/src/website/ui/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button'; 2 | export * from './tip'; 3 | export * from './form-text-field'; 4 | export * from './ghost-page'; 5 | export * from './line'; 6 | export * from './title'; 7 | export * from './center'; 8 | export * from './drawer-header'; 9 | export * from './upload'; 10 | export * from './link'; 11 | export * from './tree-view'; 12 | export * from './form-control'; 13 | export * from './drawer'; 14 | export * from './color-block'; 15 | export * from './input'; 16 | export * from './carpet'; 17 | export * from './view-way'; 18 | export * from './catalog'; 19 | export * from './search'; 20 | export * from './menu'; 21 | export * from './breadcrumbs'; 22 | export * from './popover'; 23 | export * from './filter'; 24 | -------------------------------------------------------------------------------- /client/src/website/components/common/markdown/render-components/img.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode, ImgHTMLAttributes} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | export interface MDImageProps extends ImgHTMLAttributes {} 5 | 6 | const Wrapper = styled.div` 7 | width: 100%; 8 | display: flex; 9 | justify-content: center; 10 | align-items: center; 11 | `; 12 | 13 | const StyledImage = styled.img` 14 | width: 100%; 15 | border-radius: 5px; 16 | max-width: 100%; 17 | `; 18 | 19 | export class MDImage extends Component { 20 | render(): ReactNode { 21 | return ( 22 | 23 | 24 | 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /client/src/website/components/pen/utils/@text-utils.ts: -------------------------------------------------------------------------------- 1 | import FormatBoldIcon from '@material-ui/icons/FormatBold'; 2 | import TitleIcon from '@material-ui/icons/Title'; 3 | import FormatItalicIcon from '@material-ui/icons/FormatItalic'; 4 | import DeleteIcon from '@material-ui/icons/Delete'; 5 | 6 | import {Util} from './utils-box'; 7 | 8 | export const TextUtils: Util[] = [ 9 | { 10 | tip: '加粗', 11 | style: 'bold', 12 | icon: FormatBoldIcon, 13 | }, 14 | { 15 | tip: '标题', 16 | style: 'header-one', 17 | icon: TitleIcon, 18 | }, 19 | { 20 | tip: '斜体', 21 | style: 'italic', 22 | icon: FormatItalicIcon, 23 | }, 24 | { 25 | tip: '删除线', 26 | style: 'delete', 27 | icon: DeleteIcon, 28 | }, 29 | ]; 30 | -------------------------------------------------------------------------------- /client/src/website/services/markdown-service/@markdown-config.ts: -------------------------------------------------------------------------------- 1 | import MarkdownIT from 'markdown-it'; 2 | import hljs from 'highlight.js'; 3 | // import MDContainer from 'markdown-it-container'; 4 | 5 | import * as plugins from './@plugins'; 6 | 7 | export const markdown = MarkdownIT({ 8 | typographer: true, 9 | highlight(code: string) { 10 | return hljs.highlightAuto(code).value; 11 | }, 12 | }); 13 | 14 | for (const name of Object.keys(plugins)) { 15 | markdown.use(plugins[name]); 16 | } 17 | 18 | // markdown.use(MDContainer, '', { 19 | // validate: (_params: any) => { 20 | // return true; 21 | // }, 22 | // render(tokens: any, idx: any) { 23 | // console.info(tokens[idx]); 24 | 25 | // return ''; 26 | // }, 27 | // }); 28 | -------------------------------------------------------------------------------- /client/src/website/components/common/login-permission.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import {Inject} from '@wizardoc/injector'; 3 | 4 | import {User} from 'website/services'; 5 | 6 | import {Default} from './default'; 7 | 8 | export interface LoginPermissionProps { 9 | loginView?: ReactNode; 10 | defaultView?: ReactNode; 11 | } 12 | 13 | export class LoginPermission extends Component { 14 | @Inject 15 | user!: User; 16 | 17 | render(): ReactNode { 18 | const {loginView = <>, defaultView = <>} = this.props; 19 | 20 | return ( 21 | !this.user._isLogin} defaultView={defaultView}> 22 | {loginView} 23 | 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /client/src/website/components/main/advantage-cards.tsx: -------------------------------------------------------------------------------- 1 | import React, {ReactNode, Component} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {advantageConfigs} from '../../constant'; 5 | 6 | import {AdvantageCard} from './@advantage-card'; 7 | 8 | const Cards = styled.div` 9 | width: 100%; 10 | display: flex; 11 | justify-content: space-evenly; 12 | padding: 10px 0; 13 | margin: 100px 0 50px 0; 14 | `; 15 | 16 | export class AdvantageCards extends Component { 17 | render(): ReactNode { 18 | return ( 19 | 20 | {advantageConfigs.map(({title, content, img}) => ( 21 | 22 | ))} 23 | 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /client/src/website/pages/organization-pages/select-organization/select-organization.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import {Inject} from '@wizardoc/injector'; 3 | import styled from 'styled-components'; 4 | 5 | import {OrganizationService} from '../../../services'; 6 | import {FetchData, FetchDataComponentProps} from '../../../components'; 7 | 8 | const Wrapper = styled.div``; 9 | 10 | @FetchData(async ({extract}) => extract(OrganizationService).getAllJoinOrganization()) 11 | export class SelectOrganizationPage extends Component { 12 | @Inject 13 | organizationService!: OrganizationService; 14 | 15 | render(): ReactNode { 16 | console.info(this.props.data); 17 | 18 | return ; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /client/src/website/components/main/main-content.tsx: -------------------------------------------------------------------------------- 1 | import {Container} from '@material-ui/core'; 2 | import React, {Component, ReactNode, ComponentType} from 'react'; 3 | import styled from 'styled-components'; 4 | import {ContainerProps} from '@material-ui/core/Container'; 5 | 6 | import {AboutUsCard} from './@about-us-card'; 7 | import {AdvantageCards} from './advantage-cards'; 8 | 9 | const Wrapper = styled(Container)` 10 | /* position: relative; */ 11 | /* top: 100px; */ 12 | margin-top: 500px; 13 | ` as ComponentType; 14 | 15 | export class MainContent extends Component { 16 | render(): ReactNode { 17 | return ( 18 | 19 | 20 | 21 | 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /client/src/website/components/pen/utils/@func-utils.ts: -------------------------------------------------------------------------------- 1 | import FlightLandIcon from '@material-ui/icons/FlightLand'; 2 | import FlightTakeoffIcon from '@material-ui/icons/FlightTakeoff'; 3 | import DescriptionIcon from '@material-ui/icons/Description'; 4 | import SaveIcon from '@material-ui/icons/Save'; 5 | import UndoIcon from '@material-ui/icons/Undo'; 6 | 7 | import {Util} from './utils-box'; 8 | 9 | export const FuncUtils: Util[] = [ 10 | { 11 | tip: '编辑摘要', 12 | icon: DescriptionIcon, 13 | }, 14 | { 15 | tip: '导入', 16 | icon: FlightLandIcon, 17 | }, 18 | { 19 | tip: '导出', 20 | icon: FlightTakeoffIcon, 21 | }, 22 | { 23 | tip: '保存', 24 | icon: SaveIcon, 25 | }, 26 | { 27 | tip: '撤销', 28 | icon: UndoIcon, 29 | }, 30 | ]; 31 | -------------------------------------------------------------------------------- /shared/src/lib/request-payload-parser.ts: -------------------------------------------------------------------------------- 1 | import QS from 'qs'; 2 | import { 3 | HTTPRequestInterceptor, 4 | AxiosRequestConfig, 5 | ContentType, 6 | } from '@wizardoc/http-request'; 7 | 8 | import {isObject} from './typeof'; 9 | 10 | export class RequestPayloadParser implements HTTPRequestInterceptor { 11 | onRequest( 12 | config: AxiosRequestConfig, 13 | ): AxiosRequestConfig | Promise { 14 | const dup = {...config}; 15 | const {data} = dup; 16 | const contentType = config.headers['Content-Type']; 17 | 18 | // parse request body use QS 19 | if (contentType === ContentType.Form && isObject(data)) { 20 | dup.data = QS.stringify(data); 21 | } 22 | 23 | dup.withCredentials = true; 24 | 25 | return dup; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /client/src/website/services/user/@user-service.api.ts: -------------------------------------------------------------------------------- 1 | import {Group} from '@wizardoc/http-utils'; 2 | import {Injectable} from '@wizardoc/injector'; 3 | 4 | @Injectable() 5 | @Group('/user') 6 | export class UserServiceAPI { 7 | register = '/register'; 8 | 9 | login = '/login'; 10 | 11 | info = '/info'; 12 | 13 | updateInfo = '/info'; 14 | 15 | validBaseInfo = '/valid/info/base'; 16 | 17 | updateAvatar = '/avatar'; 18 | 19 | searchName = '/name/search'; 20 | 21 | followOrganization = '/focus/organization'; 22 | 23 | followUser = '/focus/user'; 24 | 25 | sendEmailCode = '/email/send/code'; 26 | 27 | verifyEmail = '/email/valid'; 28 | 29 | updateEmail = '/email/update'; 30 | 31 | updatePassword = '/password'; 32 | 33 | resetPassword = '/password/reset'; 34 | } 35 | -------------------------------------------------------------------------------- /packages/http-request/example/js/http/http-service.js: -------------------------------------------------------------------------------- 1 | import {HTTPRequestFactory} from '../../..' 2 | import ServerConfig from '../../configs/sever-config.json' 3 | import {ReqLogger} from './interceptors/req-logger' 4 | import {ResLogger} from './interceptors/res-logger' 5 | import {ResErrorCatcher} from './interceptors/res-error-catcher' 6 | 7 | export class HTTPFactory extends HTTPRequestFactory { 8 | configure({interceptor, serverConfigure}) { 9 | serverConfigure.setConfig(ServerConfig) 10 | 11 | interceptor.use([ 12 | ReqLogger, 13 | ResLogger, 14 | ResErrorCatcher 15 | ]) 16 | } 17 | 18 | errorInteract(errMsg, err) { 19 | console.info(err) 20 | } 21 | } 22 | 23 | const httpFactory = new HTTPFactory() 24 | 25 | export const http = httpFactory.create() 26 | -------------------------------------------------------------------------------- /client/webpack/webpack.config.prod.ts: -------------------------------------------------------------------------------- 1 | import {Configuration, EnvironmentPlugin, optimize} from 'webpack'; 2 | import merge from 'webpack-merge'; 3 | 4 | import {RuntimeEnv} from '../src/website/types/environment'; 5 | 6 | import {WebpackDefaultConfig} from './webpack.config'; 7 | import {withWebpackPath} from './utils'; 8 | 9 | const DIST_PATH = withWebpackPath('..', 'server', 'client-dist'); 10 | 11 | const WebpackProdConfig: Configuration = merge(WebpackDefaultConfig, { 12 | mode: RuntimeEnv.PRODUCTION, 13 | output: { 14 | path: DIST_PATH, 15 | }, 16 | plugins: [ 17 | new EnvironmentPlugin({ 18 | RUNTIME_ENV: RuntimeEnv.PRODUCTION, 19 | }), 20 | new optimize.MinChunkSizePlugin({ 21 | minChunkSize: 10000, 22 | }), 23 | ], 24 | }); 25 | 26 | export default WebpackProdConfig; 27 | -------------------------------------------------------------------------------- /client/src/website/components/common/markdown/markdown-header.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | export interface MarkdownHeaderProps { 5 | cover: string; 6 | } 7 | 8 | const Wrapper = styled.div``; 9 | 10 | const CoverWrapper = styled.div` 11 | width: 100%; 12 | display: flex; 13 | justify-content: center; 14 | `; 15 | 16 | const HeadCover = styled.img` 17 | max-width: 100%; 18 | max-height: 560px; 19 | `; 20 | 21 | export class MarkdownHeader extends Component { 22 | render(): ReactNode { 23 | const {cover} = this.props; 24 | 25 | return ( 26 | 27 | 28 | 29 | 30 | 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /client/src/website/components/main/main-header-bar/main-header-bar.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | import {withRouter} from 'react-router-dom'; 4 | 5 | import {Logo} from '../../header-bar'; 6 | 7 | import {MainHeaderButtons} from './@main-header-buttons'; 8 | 9 | const Wrapper = styled.div` 10 | height: 72px; 11 | width: 100%; 12 | background: ${props => props.theme.primaryColor}; 13 | padding: 15px 60px; 14 | display: flex; 15 | justify-content: space-between; 16 | box-sizing: border-box; 17 | `; 18 | 19 | @withRouter 20 | export class MainHeaderBar extends Component { 21 | render(): ReactNode { 22 | return ( 23 | 24 | 25 | 26 | 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /client/src/website/components/message-center/message-side/message-side.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | const Wrapper = styled.div` 5 | width: 250px; 6 | height: 100%; 7 | box-shadow: 0 0 100px ${props => props.theme.deepGray}; 8 | `; 9 | 10 | const Header = styled.div` 11 | width: 100%; 12 | height: 200px; 13 | display: flex; 14 | align-items: center; 15 | justify-content: center; 16 | font-size: 22px; 17 | font-weight: 300; 18 | background: ${props => props.theme.primaryColor}; 19 | color: ${props => props.theme.white}; 20 | `; 21 | 22 | export class MessageSide extends Component { 23 | render(): ReactNode { 24 | return ( 25 | 26 |
消息中心
27 |
28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /client/src/website/pages/organization-pages/select-organization/empty-organization.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import {Inject} from '@wizardoc/injector'; 3 | import styled from 'styled-components'; 4 | import {Button} from '@material-ui/core'; 5 | 6 | import {OrganizationService, DialogService} from '../../../services'; 7 | 8 | const Wrapper = styled.div``; 9 | 10 | export class EmptyOrganizationPage extends Component { 11 | @Inject 12 | organizationService!: OrganizationService; 13 | 14 | @Inject 15 | dialogService!: DialogService; 16 | 17 | handleCreateOrganizationClick(): void {} 18 | 19 | render(): ReactNode { 20 | return ( 21 | 22 | 23 | 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:latest as dep_cache 2 | LABEL younccat "zzhbbdbbd@163.com" 3 | 4 | WORKDIR /deps 5 | 6 | # subpackages 7 | COPY lerna.json ./ 8 | COPY yarn.lock ./ 9 | COPY package.json ./ 10 | COPY ./tsconfig.react.json ./ 11 | COPY packages ./packages 12 | COPY shared ./shared 13 | 14 | RUN mkdir server 15 | 16 | COPY server/package.json server/package.json 17 | 18 | RUN yarn 19 | 20 | FROM node:latest 21 | 22 | WORKDIR /node_middlewares 23 | 24 | COPY . . 25 | COPY --from=dep_cache /deps/node_modules ./node_modules 26 | COPY --from=dep_cache /deps/server/node_modules ./server/node_modules 27 | COPY --from=dep_cache /deps/packages ./packages 28 | COPY --from=dep_cache /deps/shared ./shared 29 | 30 | WORKDIR /node_middlewares/server 31 | 32 | RUN yarn build 33 | 34 | ENTRYPOINT [ "yarn", "start:prod" ] 35 | 36 | EXPOSE 3000 37 | -------------------------------------------------------------------------------- /client/src/website/services/jwt-service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@wizardoc/injector'; 2 | 3 | import {LocalStorage} from '../utils'; 4 | 5 | @Injectable() 6 | export class JWT { 7 | private _JWTString: string | undefined; 8 | private readonly JWT_STORAGE_KEY = 'jwt'; 9 | 10 | constructor() { 11 | const jwt = LocalStorage.getItem(this.JWT_STORAGE_KEY); 12 | 13 | if (jwt) { 14 | this._JWTString = jwt; 15 | } 16 | } 17 | 18 | save(jwtString: string): void { 19 | LocalStorage.setItem(this.JWT_STORAGE_KEY, jwtString); 20 | } 21 | 22 | remove(): void { 23 | LocalStorage.removeItem(this.JWT_STORAGE_KEY); 24 | } 25 | 26 | get isExist(): boolean { 27 | return !!this._JWTString; 28 | } 29 | 30 | get JWTString(): string | undefined { 31 | return this._JWTString; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /client/src/website/services/time/time-service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@wizardoc/injector'; 2 | 3 | import {TimeUtil} from './time-utils'; 4 | 5 | /** int64 */ 6 | export type TimeUnit = number; 7 | 8 | @Injectable() 9 | export class Time { 10 | new(timeStamp: number): TimeUtil { 11 | return new TimeUtil(timeStamp); 12 | } 13 | 14 | /** 15 | * 睡眠 16 | * @param duration 睡眠时间,单位是秒 17 | */ 18 | sleep(duration?: number): Promise { 19 | return new Promise(resolve => setTimeout(resolve, (duration ?? 0) * Time.Second)); 20 | } 21 | 22 | static readonly Second: TimeUnit = 1000; 23 | static readonly MilliSecond: TimeUnit = 1; 24 | static readonly Minute: TimeUnit = 60 * Time.Second; 25 | static readonly Hour: TimeUnit = 60 * Time.Minute; 26 | static readonly Day: TimeUnit = 24 * Time.Hour; 27 | } 28 | -------------------------------------------------------------------------------- /client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.react.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "outDir": "dist", 6 | "sourceMap": true, 7 | "allowJs": true, 8 | "jsx": "react", 9 | "types": ["node", "jest"], 10 | "moduleResolution": "node", 11 | "rootDir": "src", 12 | "isolatedModules": true, 13 | "forceConsistentCasingInFileNames": true, 14 | "noImplicitReturns": true, 15 | "paths": { 16 | "~/*": ["./*"], 17 | "website/*": ["src/website/*"] 18 | } 19 | }, 20 | "exclude": [ 21 | "node_modules/**/*", 22 | "../node_modules/**/*", 23 | "build", 24 | "scripts", 25 | "acceptance-tests", 26 | "webpack", 27 | "jest", 28 | "src/setupTests.ts", 29 | "images.d.ts", 30 | "dist" 31 | ], 32 | "include": ["src/**/*"] 33 | } 34 | -------------------------------------------------------------------------------- /client/src/website/components/common/fab-card.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode, cloneElement, ReactElement} from 'react'; 2 | import styled from 'styled-components'; 3 | import {Card} from '@material-ui/core'; 4 | 5 | interface FabCardProps { 6 | title: string; 7 | } 8 | 9 | const Wrapper = styled(Card)` 10 | padding: 20px; 11 | `; 12 | 13 | const FabTitle = styled.div` 14 | font-size: 22px; 15 | margin: 10px 0; 16 | `; 17 | 18 | export class FabCard extends Component { 19 | render(): ReactNode { 20 | const {children, title} = this.props; 21 | const parsedChildren = cloneElement(children as ReactElement, { 22 | ...this.props, 23 | }); 24 | 25 | return ( 26 | 27 | {title} 28 | {parsedChildren} 29 | 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /client/src/website/ui/search/@search-prompt.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import {Autocomplete} from '@material-ui/lab'; 3 | import {observer} from 'mobx-react'; 4 | 5 | type InputRenderProps = (params: unknown) => ReactNode; 6 | 7 | export interface SearchPromptProps { 8 | children: InputRenderProps; 9 | options: string[]; 10 | } 11 | 12 | @observer 13 | export class SearchPrompt extends Component { 14 | render(): ReactNode { 15 | const {children, options} = this.props; 16 | 17 | return ( 18 | {option}} 21 | autoHighlight 22 | getOptionLabel={(option: any): string => option} 23 | renderInput={children} 24 | /> 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /server/src/controllers/category/category.controller.ts: -------------------------------------------------------------------------------- 1 | import {Controller} from '@nestjs/common'; 2 | 3 | import {HTTP} from '../../services'; 4 | 5 | @Controller('/category') 6 | export class CategoryController { 7 | constructor(readonly _http: HTTP) {} 8 | 9 | // @Get() 10 | // async all(@Req() req: Request, @Res() res: Response): Promise { 11 | // this.http.proxySend( 12 | // req, 13 | // res, 14 | // (data: Category[]): Categories => { 15 | // const categories: Categories = {}; 16 | 17 | // for (const category of data) { 18 | // ( 19 | // categories[category.organizationID] ?? 20 | // (categories[category.organizationID] = []) 21 | // ).push(category); 22 | // } 23 | 24 | // return categories; 25 | // }, 26 | // ); 27 | // } 28 | } 29 | -------------------------------------------------------------------------------- /client/src/website/components/common/layout-toggle.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import ViewColumnIcon from '@material-ui/icons/ViewColumn'; 3 | import ViewModuleIcon from '@material-ui/icons/ViewModule'; 4 | 5 | import {Button, ToggleItem} from 'website/ui'; 6 | 7 | interface LayoutToggleProps { 8 | onChange?(value: string): void; 9 | } 10 | 11 | export class LayoutToggle extends Component { 12 | layouts: ToggleItem[] = [ 13 | { 14 | icon: , 15 | value: 'column', 16 | }, 17 | { 18 | icon: , 19 | value: 'row', 20 | }, 21 | ]; 22 | 23 | render(): ReactNode { 24 | const {onChange} = this.props; 25 | 26 | return ( 27 | 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /client/src/website/components/user-detail/user-card.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {Avatar} from '../common'; 5 | 6 | const Wrapper = styled.div` 7 | width: 600px; 8 | height: 200px; 9 | background: ${props => props.theme.white}; 10 | box-shadow: ${props => props.theme.flatShadow}; 11 | margin-top: 100px; 12 | border-radius: 3px; 13 | `; 14 | 15 | const UserContainer = styled.div``; 16 | 17 | const InfoContainer = styled.div``; 18 | 19 | const Funcs = styled.div``; 20 | 21 | export class UserCard extends Component { 22 | render(): ReactNode { 23 | return ( 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /client/src/website/guards/organizations/organization-empty-guard.ts: -------------------------------------------------------------------------------- 1 | import {RouteComponentProps} from 'react-router-dom'; 2 | import {Inject} from '@wizardoc/injector'; 3 | 4 | import { 5 | ActivatedGuard, 6 | PropsInjector, 7 | Route, 8 | OrganizationService, 9 | } from 'website/services'; 10 | 11 | export class OrganizationEmptyGuard implements ActivatedGuard { 12 | @Inject 13 | organizationService!: OrganizationService; 14 | 15 | async canActivated( 16 | _route: Route, 17 | _props: RouteComponentProps, 18 | inject: PropsInjector, 19 | ): Promise { 20 | await this.organizationService.isInit(); 21 | 22 | if (this.organizationService.isNoOrganization) { 23 | return '/organization/empty'; 24 | } 25 | 26 | inject({organizations: this.organizationService.organizations}); 27 | 28 | return true; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /client/src/website/components/pen/utils/@markdown-utils.ts: -------------------------------------------------------------------------------- 1 | import FormatQuoteIcon from '@material-ui/icons/FormatQuote'; 2 | import CodeIcon from '@material-ui/icons/Code'; 3 | import BorderAllIcon from '@material-ui/icons/BorderAll'; 4 | import LinkIcon from '@material-ui/icons/Link'; 5 | import ImageIcon from '@material-ui/icons/Image'; 6 | 7 | import {Util} from './utils-box'; 8 | 9 | export const MarkdownUtils: Util[] = [ 10 | { 11 | tip: '引用', 12 | style: 'blockquote', 13 | icon: FormatQuoteIcon, 14 | }, 15 | { 16 | tip: '代码块', 17 | style: 'code-block', 18 | icon: CodeIcon, 19 | }, 20 | { 21 | tip: '表格', 22 | style: 'table', 23 | icon: BorderAllIcon, 24 | }, 25 | { 26 | tip: '链接', 27 | style: 'link', 28 | icon: LinkIcon, 29 | }, 30 | { 31 | tip: '图片', 32 | style: 'image', 33 | icon: ImageIcon, 34 | }, 35 | ]; 36 | -------------------------------------------------------------------------------- /client/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@magicspace/configs/tslint-prettier", "tslint-react"], 3 | "rules": { 4 | "no-void-expression": false, 5 | "no-implicit-dependencies": false, 6 | "no-conditional-assignment": false, 7 | "no-unused-expression": false, 8 | "ordered-imports": false, 9 | "no-inferred-empty-object-type": false, 10 | "object-literal-sort-keys": false, 11 | "no-floating-promises": false, 12 | "no-bitwise": false, 13 | "no-redundant-jsdoc": false, 14 | "jsx-no-lambda": false, 15 | "jsx-no-multiline-js": false, 16 | "jsx-key": false, 17 | "jsx-self-close": true, 18 | "jsx-alignment": false, 19 | "jsx-boolean-value": false, 20 | "jsx-wrap-multiline": false, 21 | "jsx-curly-spacing": false, 22 | "jsx-no-bind": false 23 | }, 24 | "linterOptions": { 25 | "exclude": ["node_modules/**"] 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /client/src/website/components/common/markdown/@function-pannel/function-panel.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import { 5 | OrganizationDetailCardProps, 6 | OrganizationDetailCard, 7 | } from './@organization-detail-card'; 8 | import {DocumentInfoBlock} from './@document-info-block'; 9 | 10 | interface FunctionPanelProps extends OrganizationDetailCardProps {} 11 | 12 | const Wrapper = styled.div` 13 | margin-top: 20px; 14 | `; 15 | 16 | export class FunctionPanel extends Component { 17 | render(): ReactNode { 18 | const {organizationInfo} = this.props; 19 | 20 | return ( 21 | 22 | 23 | 24 | 25 | 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /shared/src/lib/helpers.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 遍历数组的方法,用来执行一些带有副作用的方法,当回调函数返回 false 时 break 3 | * @params arr 目标数组 4 | * @params fn 接收数组元素为参数的回调函数 5 | */ 6 | export function traverse(arr: T[], fn: (item: T) => boolean | void): void { 7 | for (const item of arr) { 8 | if (fn(item) === false) { 9 | return; 10 | } 11 | } 12 | } 13 | 14 | export class Pipe { 15 | private constructor(private val: T) {} 16 | 17 | next(cb: (v: T) => T, condition?: (v: T) => boolean): Pipe { 18 | if ((condition ?? (() => {}))(this.value)) { 19 | this.val = cb(this.val); 20 | } 21 | 22 | return this; 23 | } 24 | 25 | valueOf(): T { 26 | return this.val; 27 | } 28 | 29 | toString(): T { 30 | return this.val; 31 | } 32 | 33 | static from(val: T): Pipe { 34 | return new Pipe(val); 35 | } 36 | 37 | get value(): T { 38 | return this.val; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /client/src/website/services/regex/regex.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@wizardoc/injector'; 2 | 3 | /** 4 | * Regular Expression service, provide some validation tool and regex constants 5 | */ 6 | 7 | @Injectable() 8 | export class Regex { 9 | test(regexLiteral: Regex.RegexLiteral, text: string): boolean { 10 | return regexLiteral.test(text); 11 | } 12 | 13 | /** override, the regex used must be defined first in Regex namespace */ 14 | replace( 15 | regexLiteral: Regex.RegexLiteral, 16 | text: string, 17 | replaceText: string, 18 | ): string | undefined { 19 | return text.replace(regexLiteral, replaceText); 20 | } 21 | 22 | exec(regexLiteral: Regex.RegexLiteral, text: string): RegExpExecArray | undefined { 23 | return regexLiteral.exec(text) as RegExpExecArray | undefined; 24 | } 25 | } 26 | 27 | export namespace Regex { 28 | export type RegexLiteral = RegExp; 29 | } 30 | -------------------------------------------------------------------------------- /client/src/website/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './env'; 2 | export * from './MIME'; 3 | export * from './color-generator'; 4 | export * from './diff'; 5 | export * from './import'; 6 | export * from './initialize'; 7 | export * from './markdown'; 8 | export * from './page'; 9 | export * from './storage'; 10 | export * from './store-injector'; 11 | export * from './svg-generator'; 12 | export * from './sync'; 13 | export * from './view-port'; 14 | export * from './viewport-listener'; 15 | export * from './color-generator'; 16 | export * from './diff'; 17 | export * from './env'; 18 | export * from './import'; 19 | export * from './initialize'; 20 | export * from './markdown'; 21 | export * from './page'; 22 | export * from './storage'; 23 | export * from './store-injector'; 24 | export * from './svg-generator'; 25 | export * from './sync'; 26 | export * from './view-port'; 27 | export * from './viewport-listener'; 28 | -------------------------------------------------------------------------------- /client/src/website/components/pen/pen.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {PenHeader} from './pen-header'; 5 | import {Original} from './original'; 6 | // import {Viewer} from './viewer'; 7 | 8 | const Wrapper = styled.div``; 9 | 10 | const EditorWrapper = styled.div` 11 | height: 100%; 12 | width: 100%; 13 | display: flex; 14 | `; 15 | 16 | const Widget = styled.div` 17 | flex: 1; 18 | height: fit-content; 19 | `; 20 | 21 | export class Pen extends Component { 22 | render(): ReactNode { 23 | return ( 24 | 25 | 26 | 27 | 28 | 29 | 30 | {/* 31 | 32 | */} 33 | 34 | 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /client/src/website/components/common/index.ts: -------------------------------------------------------------------------------- 1 | export * from './image-preview'; 2 | export * from './page-header'; 3 | export * from './tree-view'; 4 | export * from './md-render'; 5 | export * from './fab'; 6 | export * from './dialogs'; 7 | export * from './tab'; 8 | export * from './view-banner'; 9 | export * from './lazy-loading'; 10 | export * from './avatar'; 11 | export * from './layout-toggle'; 12 | export * from './overview-title'; 13 | export * from './transition-fab'; 14 | export * from './fab-card'; 15 | export * from './default'; 16 | export * from './side-bar'; 17 | export * from './loading'; 18 | export * from './upload'; 19 | export * from './default-view'; 20 | export * from './loadmore'; 21 | export * from './markdown'; 22 | export * from './login-permission'; 23 | export * from './snack-bar-queue'; 24 | export * from './send-verify-code-button'; 25 | export * from './switch-bar'; 26 | export * from './invite-member-box'; 27 | -------------------------------------------------------------------------------- /client/src/website/components/message-center/message-overview/@message-tag.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {MessageTag as MessageTagValue} from 'website/services'; 5 | 6 | import {MessageTagMap} from './@message-tag-config'; 7 | 8 | export interface MessageTagProps { 9 | tag: MessageTagValue; 10 | } 11 | 12 | interface WrapperProps { 13 | color: string; 14 | } 15 | 16 | const Wrapper = styled.div` 17 | background: ${props => props.color}; 18 | font-size: 12px; 19 | border-radius: 1000px; 20 | padding: 2px 10px; 21 | color: ${props => props.theme.white}; 22 | margin-left: 10px; 23 | `; 24 | 25 | export class MessageTag extends Component { 26 | render(): ReactNode { 27 | const {color, text} = MessageTagMap[this.props.tag]; 28 | 29 | return {text}; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /server/src/guards/auth/auth.guard.ts: -------------------------------------------------------------------------------- 1 | import {CanActivate, ExecutionContext, Injectable} from '@nestjs/common'; 2 | import {isArray} from '@wizardoc/shared'; 3 | 4 | import {HTTP, AuthService} from 'src/services'; 5 | import {AUTH_KEY} from 'src/constants'; 6 | import {GraphQLClientRequest} from 'src/decorators'; 7 | 8 | @Injectable() 9 | export class Auth implements CanActivate { 10 | constructor(private authService: AuthService) {} 11 | 12 | canActivate(ctx: ExecutionContext): boolean { 13 | const req = ctx.switchToHttp().getRequest(); 14 | const token = req.headers[AUTH_KEY]; 15 | 16 | // The token cannot be a array 17 | if (isArray(token)) { 18 | return false; 19 | } 20 | 21 | const hasToken = this.authService.validateToken(token); 22 | 23 | if (!hasToken) { 24 | return false; 25 | } 26 | 27 | req.token = token; 28 | 29 | return true; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /client/src/website/ui/line.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {withTheme, ThemeComponentProps} from '../theme'; 5 | 6 | interface InnerLineProps { 7 | lineColor?: string; 8 | } 9 | 10 | export interface LineProps extends InnerLineProps {} 11 | 12 | const InnerLine = styled.div` 13 | width: 85%; 14 | height: 1px; 15 | background: ${props => props.lineColor}; 16 | `; 17 | 18 | const LineWrapper = styled.div` 19 | width: 100%; 20 | display: flex; 21 | justify-content: center; 22 | `; 23 | 24 | @withTheme 25 | export class Line extends Component> { 26 | render(): ReactNode { 27 | const {theme, lineColor = theme!.grayLineColor} = this.props; 28 | 29 | return ( 30 | 31 | 32 | 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /client/src/website/components/overview/overview-docs/document/create-document-header.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | import {Button} from '@material-ui/core'; 4 | import {Inject} from '@wizardoc/injector'; 5 | 6 | import {DocumentService} from 'website/services/document'; 7 | 8 | export interface CreateDocumentHeaderProps { 9 | onPublishClick(): void; 10 | } 11 | 12 | const Wrapper = styled.div` 13 | height: 65px; 14 | width: 100%; 15 | `; 16 | 17 | export class CreateDocumentHeader extends Component { 18 | @Inject 19 | documentService!: DocumentService; 20 | 21 | render(): ReactNode { 22 | const {onPublishClick} = this.props; 23 | 24 | return ( 25 | 26 | 29 | 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /client/config/polyfills.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (typeof Promise === 'undefined') { 4 | // Rejection tracking prevents a common issue where React gets into an 5 | // inconsistent state due to an error, but it gets swallowed by a Promise, 6 | // and the user has no idea what causes React's erratic future behavior. 7 | require('promise/lib/rejection-tracking').enable(); 8 | window.Promise = require('promise/lib/es6-extensions.js'); 9 | } 10 | 11 | // fetch() polyfill for making API calls. 12 | require('whatwg-fetch'); 13 | 14 | // Object.assign() is commonly used with React. 15 | // It will use the native implementation if it's present and isn't buggy. 16 | Object.assign = require('object-assign'); 17 | 18 | // In tests, polyfill requestAnimationFrame since jsdom doesn't provide it yet. 19 | // We don't polyfill it in the browser--this is user's responsibility. 20 | if (process.env.NODE_ENV === 'test') { 21 | require('raf').polyfill(global); 22 | } 23 | -------------------------------------------------------------------------------- /client/src/website/components/overview/overview-docs/overview-doc-cards.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | import {observer} from 'mobx-react'; 4 | import {Category} from '@wizardoc/shared'; 5 | 6 | import {CategoryCard} from './category'; 7 | 8 | export interface OverviewDocCardsProps { 9 | categories: Category[]; 10 | } 11 | 12 | const Wrapper = styled.div` 13 | display: flex; 14 | flex-wrap: wrap; 15 | margin: -15px; 16 | `; 17 | 18 | const ViewCard = styled.div` 19 | margin: 15px; 20 | `; 21 | 22 | @observer 23 | export class OverviewDocCards extends Component { 24 | render(): ReactNode { 25 | const categoriesCards = this.props.categories.map(category => ( 26 | 27 | 28 | 29 | )); 30 | 31 | return {categoriesCards}; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /client/src/website/components/message-center/message-overview/@message-tag-config.tsx: -------------------------------------------------------------------------------- 1 | import React, {ReactNode} from 'react'; 2 | 3 | import {MessageTag} from 'website/services'; 4 | import {styledTheme} from 'website/theme'; 5 | 6 | import {InviteActionButtons} from './@invite-action-buttons'; 7 | 8 | export interface MessageTagProperty { 9 | text: string; 10 | color: string; 11 | attachComponent?(props: any): ReactNode; 12 | } 13 | 14 | export type MessageTagMap = { 15 | [key in MessageTag]: MessageTagProperty; 16 | }; 17 | 18 | export const MessageTagMap: MessageTagMap = { 19 | [MessageTag.INVITE]: { 20 | text: '邀请', 21 | color: styledTheme.successGreen, 22 | attachComponent: props => , 23 | }, 24 | [MessageTag.PERSONAL]: { 25 | text: '私信', 26 | color: styledTheme.shallowPink, 27 | }, 28 | [MessageTag.SYSTEM]: { 29 | text: '系统', 30 | color: styledTheme.flatYellow, 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /client/src/test/utils/env.spec.ts: -------------------------------------------------------------------------------- 1 | import {RuntimeEnv} from '~/src/website/types/environment'; 2 | import {runtimeEnv} from '~/src/website/utils/env'; 3 | 4 | const changeRuntimeEnv = (env: RuntimeEnv): RuntimeEnv => (process.env.RUNTIME_ENV = env); 5 | 6 | describe('runtime environment function utils', () => { 7 | const OLD_PROCESS_ENV = process.env; 8 | 9 | beforeEach(() => { 10 | jest.resetModules(); 11 | process.env = {...OLD_PROCESS_ENV}; 12 | }); 13 | 14 | it('run in development env', () => { 15 | changeRuntimeEnv(RuntimeEnv.DEVELOPMENT); 16 | 17 | expect(runtimeEnv({DEVELOPMENT: 1})).toBe(1); 18 | }); 19 | 20 | it('run in staging env', () => { 21 | changeRuntimeEnv(RuntimeEnv.STAGING); 22 | 23 | expect(runtimeEnv({STAGING: 1})).toBe(1); 24 | }); 25 | 26 | it('run in production env', () => { 27 | changeRuntimeEnv(RuntimeEnv.PRODUCTION); 28 | 29 | expect(runtimeEnv({PRODUCTION: 1})).toBe(1); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /client/src/website/services/regex/regex-utils.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@wizardoc/injector'; 2 | 3 | import {Regex} from './regex'; 4 | 5 | @Injectable() 6 | export class RegexUtils extends Regex { 7 | validEmail(email: string): boolean { 8 | return this.test(RegexUtils.EmailRegex, email); 9 | } 10 | 11 | validURL(url: string): boolean { 12 | return this.test(RegexUtils.URLRegex, url); 13 | } 14 | 15 | static readonly URLRegex = /^(?:(?:(?:[a-z]+:)?\/\/)|www\.)(?:\S+(?::\S*)?@)?(?:localhost|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3})|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#][^\s"]*)?$/; 16 | static readonly EmailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 17 | } 18 | -------------------------------------------------------------------------------- /client/src/website/utils/env.ts: -------------------------------------------------------------------------------- 1 | import type {IRuntimeEnv} from '../types/environment'; 2 | 3 | export type CrossEnvOptions = { 4 | [K in keyof IRuntimeEnv]: T; 5 | }; 6 | 7 | export const runtimeEnv = (options: Partial>): never | T => { 8 | // U can via process.env.[ENV_NAME] to get the env variable that u want but 9 | // u can't access process.env directly for security reason 10 | // see https://github.com/parcel-bundler/parcel/issues/2299#issuecomment-439768971 for more detail 11 | const target = Object.keys(options).reduce( 12 | (res, cur) => 13 | process.env.RUNTIME_ENV.toLowerCase() === cur.toLowerCase() ? options[cur] : res, 14 | undefined, 15 | ); 16 | 17 | if (!target) { 18 | throw new Error(` 19 | Cannot hit current runtime environment, please check input environment. 20 | 21 | Current runtime environment: ${process.env.RUNTIME_ENV}. 22 | `); 23 | } 24 | 25 | return target; 26 | }; 27 | -------------------------------------------------------------------------------- /tsconfig.react.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@magicspace/configs/tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "module": "esnext", 6 | "target": "es6", 7 | "lib": ["es6", "dom", "esnext", "es7", "dom.iterable"], 8 | "sourceMap": true, 9 | "allowJs": true, 10 | "jsx": "react", 11 | "moduleResolution": "node", 12 | "rootDir": "src", 13 | "forceConsistentCasingInFileNames": true, 14 | "noImplicitReturns": true, 15 | "noImplicitThis": true, 16 | "isolatedModules": true, 17 | "noImplicitAny": true, 18 | "strict": true, 19 | "importHelpers": true, 20 | "strictNullChecks": true, 21 | "esModuleInterop": true, 22 | "suppressImplicitAnyIndexErrors": true, 23 | "noUnusedLocals": false, 24 | "resolveJsonModule": true, 25 | "allowSyntheticDefaultImports": true, 26 | "emitDecoratorMetadata": true, 27 | "experimentalDecorators": true, 28 | "skipLibCheck": true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /client/src/website/components/common/loading/backdrop-loading.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | import {Backdrop, CircularProgress} from '@material-ui/core'; 4 | import {observer} from 'mobx-react'; 5 | import {Inject} from '@wizardoc/injector'; 6 | 7 | import {BackdropService} from 'website/services'; 8 | 9 | const StyledBackdrop = styled(Backdrop)` 10 | z-index: 3000 !important; 11 | `; 12 | 13 | const StyledCircularProgress = styled(CircularProgress)` 14 | color: ${props => props.theme.white} !important; 15 | `; 16 | 17 | @observer 18 | export class BackdropLoading extends Component { 19 | @Inject 20 | backdropService!: BackdropService; 21 | 22 | render(): ReactNode { 23 | const {isViewBackdrop} = this.backdropService; 24 | 25 | return ( 26 | 27 | 28 | 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /client/src/website/components/common/loading/inline-loading.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import {CircularProgress} from '@material-ui/core'; 3 | 4 | import styled from 'website/theme/style'; 5 | 6 | export interface InlineLoadingProps { 7 | isLoading?: boolean; 8 | } 9 | 10 | const Wrapper = styled.div` 11 | width: 100%; 12 | height: 100%; 13 | position: absolute; 14 | left: 0; 15 | top: 0; 16 | display: flex; 17 | justify-content: center; 18 | align-items: center; 19 | z-index: 100; 20 | background: rgba(0, 0, 0, 0.7); 21 | `; 22 | 23 | export class InlineLoading extends Component { 24 | render(): ReactNode { 25 | const {children, isLoading = true} = this.props; 26 | 27 | return ( 28 | <> 29 | {children} 30 | {isLoading && ( 31 | 32 | 33 | 34 | )} 35 | 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/markdown/src/components/header.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode, createElement} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | export interface HeaderProps { 5 | level: string; 6 | } 7 | 8 | const Prefix = styled.div` 9 | color: ${props => props.theme.deepGray}; 10 | `; 11 | 12 | const Content = styled.div``; 13 | 14 | export class Header extends Component { 15 | render(): ReactNode { 16 | const {level, children} = this.props; 17 | const [prefix, content] = parseHeader(children as string); 18 | 19 | console.info(prefix?.toString()); 20 | console.info(prefix, content); 21 | 22 | return createElement( 23 | `h${level}`, 24 | {}, 25 | <> 26 | {prefix} 27 | {content} 28 | , 29 | ); 30 | } 31 | } 32 | 33 | function parseHeader(header: string): [string, string] { 34 | return [header.slice(0, 1), header.slice(2)]; 35 | } 36 | -------------------------------------------------------------------------------- /client/src/website/components/common/markdown/@function-pannel/@document-info-block.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | export interface DocumentInfoBlockProps { 5 | title: string; 6 | } 7 | 8 | const Wrapper = styled.div` 9 | box-shadow: ${props => props.theme.flatShadow}; 10 | border-left: 4px solid ${props => props.theme.primaryColor}; 11 | border-radius: 10px; 12 | `; 13 | 14 | const Title = styled.div` 15 | padding: 20px 0; 16 | border-bottom: 1px solid ${props => props.theme.shallowGray}; 17 | color: ${props => props.theme.titleColor}; 18 | margin: 0 10px; 19 | font-weight: 500; 20 | `; 21 | 22 | export class DocumentInfoBlock extends Component { 23 | render(): ReactNode { 24 | const {title, children} = this.props; 25 | 26 | return ( 27 | 28 | {title} 29 | {children} 30 | 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /client/src/website/components/main/main-header-bar/@main-header-buttons.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | import {Button} from '@material-ui/core'; 4 | 5 | const Wrapper = styled.div``; 6 | 7 | const BaseButton = styled(Button)` 8 | color: ${props => props.theme.white} !important; 9 | margin-right: 20px !important; 10 | `; 11 | 12 | const RegisterButton = styled(Button)` 13 | width: 102px; 14 | background: ${props => props.theme.white} !important; 15 | color: ${props => props.theme.primaryColor} !important; 16 | `; 17 | 18 | export class MainHeaderButtons extends Component { 19 | render(): ReactNode { 20 | return ( 21 | 22 | 关于我们 23 | 帮助 24 | 登录 25 | 注册 26 | 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /client/src/website/constant/advantage-config.ts: -------------------------------------------------------------------------------- 1 | import OpenSourceIcon from 'website/assets/static/advantage/open_source.png'; 2 | import FontDocsIcon from 'website/assets/static/advantage/font_docs.png'; 3 | import SwaggerIcon from 'website/assets/static/advantage/swagger.png'; 4 | import ChatIcon from 'website/assets/static/advantage/chat.png'; 5 | 6 | interface AdvantageConfig { 7 | title: string; 8 | content: string; 9 | img: string; 10 | } 11 | 12 | export const advantageConfigs: AdvantageConfig[] = [ 13 | { 14 | title: '开源免费', 15 | content: '遵循开源协议,免费商用', 16 | img: OpenSourceIcon, 17 | }, 18 | { 19 | title: '管理前端组件文档', 20 | content: '添加项目的图标,可以生成在线链接,以字体形式进行复用', 21 | img: FontDocsIcon, 22 | }, 23 | { 24 | title: 'swagger 文档管理', 25 | content: '创建项目后上传icon,成员可以下载图标,前端同学可以将图标添加至代码', 26 | img: SwaggerIcon, 27 | }, 28 | { 29 | title: '更多技术交流机会', 30 | content: '我们提供一个原创图标共享、交流平台,尊重原创,尊重每个设计师', 31 | img: ChatIcon, 32 | }, 33 | ]; 34 | -------------------------------------------------------------------------------- /client/src/website/routes/doc-route.ts: -------------------------------------------------------------------------------- 1 | import {lazy} from 'website/utils'; 2 | 3 | import {Routes} from '../services'; 4 | import {OrganizationGuard} from '../guards'; 5 | import {DocumentCenter} from '../pages/document-pages'; 6 | 7 | const Pen = lazy(import('../pages/write'), 'WritePage'); 8 | const Doc = lazy(import('../pages/doc'), 'Doc'); 9 | const Detail = lazy(import('../pages/document-detail'), 'DocumentDetail'); 10 | 11 | export const DocumentRoutes: Routes = [ 12 | { 13 | path: '/document', 14 | layout: 'no-footer', 15 | component: Doc, 16 | children: [ 17 | { 18 | path: '/center', 19 | component: DocumentCenter, 20 | }, 21 | { 22 | path: '/:id/write', 23 | component: Pen, 24 | layout: 'limpidity', 25 | activatedGuard: [OrganizationGuard], 26 | }, 27 | { 28 | path: '/detail/:id', 29 | component: Detail, 30 | layout: 'no-footer', 31 | }, 32 | ], 33 | }, 34 | ]; 35 | -------------------------------------------------------------------------------- /client/src/website/services/user/user-service.dto.ts: -------------------------------------------------------------------------------- 1 | import {OrganizationCardData} from '../organization'; 2 | 3 | export interface UserModel { 4 | id: string; 5 | avatar: string; 6 | loginTime: number; 7 | email: string; 8 | displayName: string; 9 | registerTime: number; 10 | username: string; 11 | } 12 | 13 | export interface UserInfoDTO { 14 | userInfo: UserBaseInfo; 15 | } 16 | 17 | export interface UserBaseInfo { 18 | id: string; 19 | displayName: string; 20 | username: string; 21 | password: string; 22 | email: string; 23 | avatar: string; 24 | intro: string; 25 | city?: string; 26 | companyName?: string; 27 | companyTitle?: string; 28 | github?: string; 29 | blog?: string; 30 | payQRCode?: string; 31 | isValidEmail: boolean; 32 | followOrganizations: OrganizationCardData[]; 33 | followUsers: UserBaseInfo[]; 34 | } 35 | 36 | export interface ValidResult { 37 | isValid: boolean; 38 | } 39 | 40 | export type SearchNameResult = UserBaseInfo[]; 41 | -------------------------------------------------------------------------------- /server/src/filters/global-error-filter.ts: -------------------------------------------------------------------------------- 1 | import {join} from 'path'; 2 | 3 | import {Catch, ExceptionFilter, ArgumentsHost} from '@nestjs/common'; 4 | import {Response} from 'express'; 5 | import {ClientError} from 'graphql-request'; 6 | 7 | @Catch(Error) 8 | export class GlobalErrorFilter implements ExceptionFilter { 9 | async catch({response}: ClientError, host: ArgumentsHost): Promise { 10 | const res = host.switchToHttp().getResponse(); 11 | 12 | // return index.html when occur Error 13 | if (!response) { 14 | res.sendFile(join(__dirname, '..', '..', 'client-dist', 'index.html')); 15 | 16 | return; 17 | } 18 | 19 | // tslint:disable-next-line:no-null-keyword 20 | const {data = null, err, error, status} = response; 21 | const UnExpectError = { 22 | msg: error, 23 | status, 24 | }; 25 | 26 | // throw the error that from API server 27 | res.send({ 28 | data, 29 | err: err ?? UnExpectError, 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /client/webpack/webpack.config.dev.ts: -------------------------------------------------------------------------------- 1 | import {Configuration, EnvironmentPlugin} from 'webpack'; 2 | import merge from 'webpack-merge'; 3 | import Webpackbar from 'webpackbar'; 4 | 5 | import {RuntimeEnv} from '../src/website/types/environment'; 6 | 7 | import {WebpackDefaultConfig} from './webpack.config'; 8 | import {withWebpackPath} from './utils'; 9 | 10 | const DIST_PATH = withWebpackPath('dist'); 11 | const APP_NAME = 'Wizardoc'; 12 | 13 | const WebpackDevConfig: Configuration = merge(WebpackDefaultConfig, { 14 | mode: RuntimeEnv.DEVELOPMENT, 15 | output: { 16 | path: DIST_PATH, 17 | }, 18 | plugins: [ 19 | new EnvironmentPlugin({ 20 | RUNTIME_ENV: RuntimeEnv.DEVELOPMENT, 21 | }), 22 | new Webpackbar({ 23 | name: APP_NAME, 24 | }), 25 | ], 26 | devServer: { 27 | contentBase: DIST_PATH, 28 | port: 4200, 29 | historyApiFallback: true, 30 | stats: 'errors-warnings', 31 | }, 32 | stats: 'errors-warnings', 33 | }); 34 | 35 | export default WebpackDevConfig; 36 | -------------------------------------------------------------------------------- /client/src/website/animations/router-animation.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ComponentClass, ReactNode} from 'react'; 2 | // tslint:disable-next-line:no-implicit-dependencies 3 | import {CSSTransition} from 'react-transition-group'; 4 | 5 | export interface RouterAnimationProps { 6 | match: unknown | null; 7 | } 8 | 9 | export function RouterAnimation(RouteViewComponent: ComponentClass): any { 10 | return class extends Component { 11 | render(): ReactNode { 12 | const {match} = this.props; 13 | 14 | return ( 15 | 27 | 28 | 29 | ); 30 | } 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /client/src/website/services/index.ts: -------------------------------------------------------------------------------- 1 | export * from './http'; 2 | export * from './cache'; 3 | export * from './dialog'; 4 | export * from './doc-service'; 5 | export * from './error-manager'; 6 | export * from './jwt-service'; 7 | export * from './markdown'; 8 | export * from './optional-tip-service'; 9 | export * from './toast'; 10 | export * from './drawer-service'; 11 | export * from './time'; 12 | export * from './draft-service'; 13 | export * from './tab-service'; 14 | export * from './regex'; 15 | export * from './todo-service'; 16 | export * from './upload-service'; 17 | export * from './message'; 18 | export * from './notify'; 19 | export * from './user'; 20 | export * from './observer'; 21 | export * from './organization'; 22 | export * from './route'; 23 | export * from './permission'; 24 | export * from './category'; 25 | export * from './arrow-cache'; 26 | export * from './document'; 27 | export * from './markdown-service'; 28 | export * from './catalog-service'; 29 | export * from './tip-service'; 30 | export * from './backdrop-service'; 31 | -------------------------------------------------------------------------------- /client/src/website/ui/upload/type-upload.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import {Inject} from '@wizardoc/injector'; 3 | 4 | import {MIMEType} from 'website/utils'; 5 | import {Toast} from 'website/services'; 6 | 7 | import {UploadProps, Upload} from './upload'; 8 | 9 | export interface TypeUploadProps extends UploadProps { 10 | allowMIMETypes: MIMEType[]; 11 | } 12 | 13 | export class TypeUpload extends Component { 14 | @Inject 15 | toast!: Toast; 16 | 17 | handleFileRead(file?: File): void { 18 | if (!file) { 19 | return; 20 | } 21 | 22 | const {allowMIMETypes, onAfterRead} = this.props; 23 | 24 | if (!allowMIMETypes.includes(file.type as MIMEType)) { 25 | this.toast.error(`不支持的上传类型`); 26 | 27 | return; 28 | } 29 | 30 | onAfterRead(file); 31 | } 32 | 33 | render(): ReactNode { 34 | return ( 35 | this.handleFileRead(file)}> 36 | {this.props.children} 37 | 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /client/src/website/animations/@common-animation.tsx: -------------------------------------------------------------------------------- 1 | // import {SlideProps} from '@material-ui/core/Slide'; 2 | // import {observable} from 'mobx'; 3 | // import {observer} from 'mobx-react'; 4 | // import React, {Component, ComponentType, ReactNode} from 'react'; 5 | 6 | // interface AnimationWrapperProps { 7 | // in: boolean; 8 | // } 9 | 10 | // export function CommonAnimation( 11 | // AnimationWrapper: ComponentType, 12 | // Target: ComponentType, 13 | // ): ComponentType { 14 | // @observer 15 | // class TCommonAnimation extends Component { 16 | // @observable 17 | // private isMounted = false; 18 | 19 | // render(): ReactNode { 20 | // return ( 21 | // 22 | // 23 | // 24 | // ); 25 | // } 26 | 27 | // componentDidMount(): void { 28 | // this.isMounted = true; 29 | // } 30 | // } 31 | 32 | // return TCommonAnimation; 33 | // } 34 | 35 | export {}; 36 | -------------------------------------------------------------------------------- /client/src/website/assets/svg.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import {SvgGenerator} from '../utils'; 4 | 5 | export const GitHubSvg = SvgGenerator( 6 | , 7 | ); 8 | 9 | export const Circle = SvgGenerator( 10 | 11 | ic_icons_192px_light 12 | 13 | 19 | 20 | 21 | , 22 | ); 23 | -------------------------------------------------------------------------------- /client/src/website/components/message-center/message-switcher.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | import {Container} from '@material-ui/core'; 4 | 5 | import {WizardTab, WizardTabConfig} from '../common'; 6 | 7 | const Wrapper = styled.div` 8 | width: 100%; 9 | background: ${props => props.theme.white}; 10 | position: sticky; 11 | top: ${props => props.theme.headerBarHeight}; 12 | box-shadow: ${props => props.theme.shallowShadow}; 13 | z-index: 100; 14 | `; 15 | 16 | export class MessageSwitcher extends Component { 17 | tabs: WizardTabConfig[] = [ 18 | { 19 | text: '系统消息', 20 | query: 'sssss', 21 | }, 22 | { 23 | text: '用户消息', 24 | query: 'ss', 25 | }, 26 | { 27 | text: '回收站', 28 | query: 'sssssssss', 29 | }, 30 | ]; 31 | 32 | render(): ReactNode { 33 | return ( 34 | 35 | 36 | 37 | 38 | 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /client/src/website/components/footer/@panel/footer-panel.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import LinkConfig from './link-config.json'; 5 | import {LinkColumnProps, LinkColumn} from './link-column'; 6 | 7 | interface LinkConfig { 8 | [index: string]: LinkColumnProps; 9 | } 10 | 11 | const Wrapper = styled.div` 12 | width: 100%; 13 | height: 300px; 14 | background: ${props => props.theme.dark}; 15 | padding: 40px 0; 16 | box-sizing: border-box; 17 | display: flex; 18 | justify-content: center; 19 | `; 20 | 21 | export class FooterPanel extends Component { 22 | renderCols: ReactNode; 23 | 24 | constructor(props: {}) { 25 | super(props); 26 | 27 | this.renderCols = this.renderLinks(LinkConfig as LinkConfig); 28 | } 29 | 30 | render(): ReactNode { 31 | return {this.renderCols}; 32 | } 33 | 34 | private renderLinks(config: LinkConfig): ReactNode { 35 | return Object.keys(config).map(key => ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /doc/md/DEVELOPMENT.md: -------------------------------------------------------------------------------- 1 | # 🚀 V1.0.0 Page modules 2 | 3 | ## 用户模块 4 | 5 | - [ ] 用户信息页 6 | - [ ] 个人收藏夹页面 7 | - [ ] 个人设置页面 8 | - [ ] 通知管理(follow 或者收藏的文件变更的通知方式) 9 | - [ ] 个人信息管理 10 | - [ ] 账号安全管理 11 | - [ ] 重置邮箱 12 | - [ ] 邮箱验证 13 | - [ ] 重置密码 14 | - [ ] 个人关注文档列表页面 15 | - [ ] 个人文档列表页面 16 | - [ ] 个人组织列表页面 17 | 18 | ## 组织模块 19 | 20 | - [ ] 组织详情页面 21 | - [ ] 邀请页面(Modal) 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 | - [ ] Plaining... 49 | 50 | ## 消息模块 51 | 52 | - [ ] 所有消息页面 53 | - [ ] filter: 我发送的 54 | - [ ] filter: 我接收的 55 | - [ ] filter: 回收站 56 | - [ ] 消息详情页 57 | 58 | ## 帮助模块 59 | 60 | - [ ] 入门文档 61 | 62 | # 🚀 V1.1.0 Page modules 63 | -------------------------------------------------------------------------------- /client/src/website/animations/swipe.tsx: -------------------------------------------------------------------------------- 1 | import 'animate.css/animate.min.css'; 2 | 3 | import React, {Component, ComponentType, ReactNode} from 'react'; 4 | // tslint:disable-next-line:no-implicit-dependencies 5 | import {CSSTransition} from 'react-transition-group'; 6 | 7 | interface SwipeProps { 8 | isReverse?: boolean; 9 | } 10 | 11 | export function SwipeAnimation(MountedComponent: ComponentType): unknown { 12 | return class extends Component { 13 | render(): ReactNode { 14 | const {isReverse = false} = this.props; 15 | 16 | return ( 17 | <> 18 | 28 | 29 | 30 | 31 | ); 32 | } 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /client/src/website/components/overview/overview-header/overview-header.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | import {Button} from '@material-ui/core'; 4 | import StarRateIcon from '@material-ui/icons/StarRate'; 5 | 6 | import {WizardTab, WizardTabConfig} from '../../common'; 7 | 8 | const Wrapper = styled.div` 9 | padding: 0 10px 0 70px; 10 | display: flex; 11 | justify-content: space-between; 12 | align-items: center; 13 | `; 14 | 15 | const GitHubButton = styled(Button)` 16 | height: 35px !important; 17 | `; 18 | 19 | const HeaderTabs: WizardTabConfig[] = [ 20 | {text: '概览', route: '/overview'}, 21 | {text: '知识共享', route: '/knowledge'}, 22 | ]; 23 | 24 | export class OverviewHeader extends Component { 25 | render(): ReactNode { 26 | return ( 27 | 28 | 29 | 30 | 31 | 贡献 Wizardoc 32 | 33 | 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /client/src/website/services/todo-service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable, Inject} from '@wizardoc/injector'; 2 | import {observable} from 'mobx'; 3 | 4 | import {TODO_API} from '../constant'; 5 | 6 | import {HTTP} from './http'; 7 | 8 | export interface TodoItemData { 9 | name: string; 10 | description: string; 11 | route: string; 12 | } 13 | 14 | @Injectable() 15 | export class TodoService { 16 | @Inject 17 | private httpService!: HTTP; 18 | 19 | @observable 20 | private _todoItems: TodoItemData[] = []; 21 | 22 | constructor() { 23 | this.init(); 24 | } 25 | 26 | async init(): Promise { 27 | const result = await this.httpService.get(TODO_API.all); 28 | 29 | result 30 | .expect(() => '获取待办事项失败') 31 | .success(data => (this._todoItems = data ?? [])); 32 | } 33 | 34 | addItem(item: TodoItemData): void { 35 | this._todoItems.push(item); 36 | } 37 | 38 | get isEmpty(): boolean { 39 | return !this._todoItems.length; 40 | } 41 | 42 | get todoItems(): TodoItemData[] { 43 | return this._todoItems; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /client/src/website/routes/organization-route.ts: -------------------------------------------------------------------------------- 1 | import {lazy} from 'website/utils'; 2 | 3 | import {Routes} from '../services'; 4 | import {OrganizationEmptyGuard} from '../guards'; 5 | 6 | const SelectOrganizationPage = lazy( 7 | import('../pages/organization-pages'), 8 | 'SelectOrganizationPage', 9 | ); 10 | 11 | const EmptyOrganizationPage = lazy( 12 | import('../pages/organization-pages'), 13 | 'EmptyOrganizationPage', 14 | ); 15 | 16 | const NewOrganizationPage = lazy( 17 | import('../pages/organization-pages'), 18 | 'NewOrganizationPage', 19 | ); 20 | 21 | export const OrganizationRoutes: Routes = [ 22 | { 23 | path: '/organization', 24 | layout: 'no-header', 25 | 26 | children: [ 27 | { 28 | path: '/select', 29 | component: SelectOrganizationPage, 30 | activatedGuard: [OrganizationEmptyGuard], 31 | }, 32 | { 33 | path: '/empty', 34 | component: EmptyOrganizationPage, 35 | }, 36 | { 37 | path: '/new', 38 | component: NewOrganizationPage, 39 | }, 40 | ], 41 | }, 42 | ]; 43 | -------------------------------------------------------------------------------- /client/src/website/pages/user-pages/user-settings/user-settings.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {UserSettingsSidebar} from 'website/components'; 5 | 6 | const Wrapper = styled.div` 7 | width: 100%; 8 | min-height: 100vh; 9 | display: flex; 10 | justify-content: center; 11 | background: ${props => props.theme.flatGray}; 12 | `; 13 | 14 | const CardContainer = styled.div` 15 | display: flex; 16 | height: fit-content; 17 | margin: 100px 0; 18 | background: ${props => props.theme.white}; 19 | box-shadow: ${props => props.theme.flatShadow}; 20 | border-radius: 3px; 21 | `; 22 | 23 | const Viewer = styled.div` 24 | width: 690px; 25 | padding: 20px 40px; 26 | box-sizing: border-box; 27 | `; 28 | 29 | export class UserSettings extends Component { 30 | render(): ReactNode { 31 | return ( 32 | 33 | 34 | 35 | {this.props.children} 36 | 37 | 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /client/src/website/components/about/contributors.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import {Inject} from '@wizardoc/injector'; 3 | import styled from 'styled-components'; 4 | 5 | import {DocService} from '../../services'; 6 | 7 | import {ContributorAvatar} from './contributor-avatar'; 8 | 9 | const Wrapper = styled.div``; 10 | 11 | const Split = styled.div` 12 | width: 100%; 13 | height: 1px; 14 | background: ${props => props.theme.deepGray}; 15 | margin: 30px 0; 16 | `; 17 | 18 | const AvatarsWrapper = styled.div` 19 | display: flex; 20 | align-items: center; 21 | `; 22 | 23 | export class Contributors extends Component { 24 | @Inject 25 | docService!: DocService; 26 | 27 | render(): ReactNode { 28 | const avatars = this.docService 29 | .getContributorAvatars() 30 | .map(info => ); 31 | 32 | return ( 33 | 34 |

Contributors

35 | 36 | {avatars} 37 |
38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /client/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}', '!**/*.d.ts'], 3 | setupFiles: ['/config/polyfills.js'], 4 | testMatch: [ 5 | '/src/test/**/*.spec.ts' 6 | ], 7 | testEnvironment: 'jsdom', 8 | testURL: 'http://localhost', 9 | transform: { 10 | '^.+\\.(js|jsx|mjs)$': 'babel-jest', 11 | '^.+\\.tsx?$': '/config/jest/typescriptTransform.js', 12 | '^.+\\.css$': '/config/jest/cssTransform.js', 13 | '^(?!.*\\.(js|jsx|mjs|css|json)$)': 14 | '/config/jest/fileTransform.js', 15 | }, 16 | transformIgnorePatterns: [ 17 | '[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|ts|tsx)$', 18 | ], 19 | moduleNameMapper: { 20 | "^~/(.+)$": "/$1" 21 | }, 22 | moduleFileExtensions: [ 23 | 'web.ts', 24 | 'ts', 25 | 'web.tsx', 26 | 'tsx', 27 | 'web.js', 28 | 'js', 29 | 'web.jsx', 30 | 'jsx', 31 | 'json', 32 | 'node', 33 | 'mjs', 34 | ], 35 | globals: { 36 | 'ts-jest': { 37 | tsConfigFile: 38 | 'tsconfig.test.json', 39 | }, 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /client/src/website/components/release-banner/release-banner.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | import KeyboardArrowRightIcon from '@material-ui/icons/KeyboardArrowRight'; 4 | 5 | import {ReleaseTagProps, ReleaseTag} from './release-tag'; 6 | 7 | export interface ReleaseBannerProps extends ReleaseTagProps {} 8 | 9 | const Wrapper = styled.div` 10 | background: ${props => props.theme.shallowWhite}; 11 | padding: 3px; 12 | border-radius: 5px; 13 | display: flex; 14 | align-items: center; 15 | color: white; 16 | position: absolute; 17 | top: -60px; 18 | `; 19 | 20 | const ReleaseText = styled.div` 21 | color: ${props => props.theme.white}; 22 | margin-left: 10px; 23 | `; 24 | 25 | export class ReleaseBanner extends Component { 26 | render(): ReactNode { 27 | const {tag} = this.props; 28 | 29 | return ( 30 | 31 | 32 | Wizard 0.01-beta is released! 33 | 34 | 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /client/src/website/services/draft-service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@wizardoc/injector'; 2 | import {observable, action, computed} from 'mobx'; 3 | 4 | type StyleHandler = (style: string) => void; 5 | 6 | export namespace DraftEvent { 7 | export const CurrentStyle = Symbol('currentStyle'); 8 | } 9 | 10 | @Injectable() 11 | export class DraftService { 12 | @observable 13 | private _currentStyle: string | undefined; 14 | 15 | // each event can have only listener 16 | private listeners = new Map(); 17 | 18 | @action 19 | setCurrentStyle(style: string): void { 20 | this._currentStyle = style; 21 | 22 | const handler = this.listeners.get(DraftEvent.CurrentStyle); 23 | 24 | if (handler) { 25 | handler(this._currentStyle); 26 | } 27 | } 28 | 29 | @computed 30 | get currentStyle(): string | undefined { 31 | return this._currentStyle; 32 | } 33 | 34 | get handlers(): IterableIterator { 35 | return this.listeners.values(); 36 | } 37 | 38 | on(event: Symbol, cb: StyleHandler): void { 39 | this.listeners.set(event, cb); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /client/src/website/ui/drawer-header.tsx: -------------------------------------------------------------------------------- 1 | import {Divider, ListItem, ListItemText} from '@material-ui/core'; 2 | import React, {FunctionComponent, ReactElement} from 'react'; 3 | import styled from 'styled-components'; 4 | 5 | interface DrawerHeaderProps { 6 | title: string; 7 | icon: ReactElement; 8 | description?: string; 9 | } 10 | 11 | const DrawerHeaderIcon = styled.div` 12 | margin-right: 10px !important; 13 | color: ${props => props.theme.primaryColor} !important; 14 | `; 15 | 16 | const HeaderText = styled.div``; 17 | 18 | const Description = styled.div` 19 | color: ${props => props.theme.descriptionColor}; 20 | font-size: 12px; 21 | `; 22 | 23 | export const DrawerHeader: FunctionComponent = props => { 24 | const {icon, title, description} = props; 25 | 26 | return ( 27 | <> 28 | 29 | {icon} 30 | 31 | 32 | {description} 33 | 34 | 35 | 36 | 37 | ); 38 | }; 39 | -------------------------------------------------------------------------------- /packages/http-utils/src/rate-limiter.ts: -------------------------------------------------------------------------------- 1 | export class Channel { 2 | private mdata: T[] = []; 3 | private locks: ((value?: T | PromiseLike | undefined) => void)[] = []; 4 | 5 | constructor(private buffer: number) {} 6 | 7 | async in(data: T): Promise { 8 | if (this.mdata.length >= this.buffer) { 9 | await new Promise(resolve => this.locks.push(resolve)); 10 | } 11 | 12 | this.mdata.push(data); 13 | } 14 | 15 | get(): T | undefined { 16 | // unlock 17 | (this.locks.shift() || (() => {}))(); 18 | 19 | return this.mdata.shift(); 20 | } 21 | } 22 | 23 | type Task = (...args: any[]) => Promise; 24 | 25 | export class RateLimiter { 26 | private chan: Channel; 27 | 28 | constructor(limitCount: number) { 29 | this.chan = new Channel(limitCount); 30 | } 31 | 32 | async run(task: Task): Promise { 33 | await this.chan.in(undefined); 34 | const res = await task(); 35 | 36 | this.chan.get(); 37 | 38 | return res; 39 | } 40 | 41 | async all(...tasks: Task[]): Promise { 42 | return Promise.all(tasks.map(task => this.run(task))); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /client/src/website/components/about/contributor-avatar.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {Avatar} from '../common'; 5 | 6 | export interface ContributorInfo { 7 | displayName: string; 8 | addr: string; 9 | } 10 | 11 | interface ContributorAvatarProps extends ContributorInfo {} 12 | 13 | const AvatarBox = styled.div` 14 | width: 80px; 15 | height: 80px; 16 | border-radius: 1000px; 17 | margin: 0 10px; 18 | box-sizing: content-box; 19 | overflow: hidden; 20 | `; 21 | 22 | const ContributorName = styled.div` 23 | font-weight: 300; 24 | margin-top: 10px; 25 | font-size: 14px; 26 | text-align: center; 27 | `; 28 | 29 | const Wrapper = styled.div``; 30 | 31 | export class ContributorAvatar extends Component { 32 | render(): ReactNode { 33 | const {addr, displayName} = this.props; 34 | 35 | return ( 36 | 37 | 38 | 39 | 40 | {displayName} 41 | 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /client/src/website/utils/storage.ts: -------------------------------------------------------------------------------- 1 | class BaseStorage { 2 | private storage: Storage; 3 | 4 | constructor(storage: Storage) { 5 | this.storage = storage; 6 | } 7 | 8 | setItem(key: string, data: unknown): void { 9 | if (!data) { 10 | return; 11 | } 12 | 13 | this.storage.setItem(key, typeof data === 'string' ? data : JSON.stringify(data)); 14 | } 15 | 16 | getItem(key: string): T | string | undefined { 17 | const result = this.storage.getItem(key); 18 | 19 | if (result === '' || result === null) { 20 | return undefined; 21 | } 22 | 23 | if (typeof result === 'string') { 24 | return result; 25 | } 26 | 27 | return JSON.parse(result); 28 | } 29 | 30 | removeItem(key: string): void { 31 | this.storage.removeItem(key); 32 | } 33 | 34 | key(index: number): string | null { 35 | return this.storage.key(index); 36 | } 37 | 38 | clear(): void { 39 | return this.storage.clear(); 40 | } 41 | 42 | get length(): number { 43 | return this.storage.length; 44 | } 45 | } 46 | 47 | export const LocalStorage = new BaseStorage(localStorage); 48 | export const SessionStorage = new BaseStorage(sessionStorage); 49 | -------------------------------------------------------------------------------- /client/src/website/animations/animation-mounted-controller.tsx: -------------------------------------------------------------------------------- 1 | // import {observable} from 'mobx'; 2 | // import {observer} from 'mobx-react'; 3 | // import React, {Component, ComponentType, ReactNode} from 'react'; 4 | 5 | // interface TimeoutProps { 6 | // timeout: number; 7 | // } 8 | 9 | // interface InnerAnimationWrapperProps { 10 | // exitAnimation: any; 11 | // } 12 | 13 | // export function AnimationMountedController< 14 | // R extends InnerAnimationWrapperProps, 15 | // T extends TimeoutProps 16 | // >(AnimationWrapper: ComponentType, options: T): ComponentType { 17 | // @observer 18 | // class Body extends Component { 19 | // @observable 20 | // isMounted = false; 21 | 22 | // render(): ReactNode { 23 | // return ; 24 | // } 25 | 26 | // handleExistAnimation(cb: Function): void { 27 | // const {timeout} = options; 28 | 29 | // this.isMounted = false; 30 | 31 | // setTimeout(() => cb(), timeout); 32 | // } 33 | 34 | // componentDidMount(): void { 35 | // this.isMounted = true; 36 | // } 37 | // } 38 | 39 | // return Body; 40 | // } 41 | 42 | export const a = 1; 43 | -------------------------------------------------------------------------------- /client/src/website/services/observer/subject.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@wizardoc/injector'; 2 | import {traverse, emptyAssert} from '@wizardoc/shared'; 3 | 4 | import {NotifyMessage, ChatMessage} from '../message'; 5 | 6 | import {Observer} from './observer'; 7 | 8 | @Injectable() 9 | export class Subject { 10 | private observers: Observer[] = []; 11 | 12 | add(observer: T): void { 13 | this.observers.push(observer); 14 | } 15 | 16 | notifyNotifyMessageObserver(msg: NotifyMessage): void { 17 | this.notify('onNotifyMessage', msg); 18 | } 19 | 20 | notifyChatMessageObserver(msg: ChatMessage): void { 21 | this.notify('onChatMessage', msg); 22 | } 23 | 24 | notifyNotifyMessageAppendedObserver(msgs: NotifyMessage[]): void { 25 | this.notify('onNotifyMessageAppended', msgs); 26 | } 27 | 28 | notifyChatMessageAppendedObserver(msgs: NotifyMessage[]): void { 29 | this.notify('onChatMessageAppended', msgs); 30 | } 31 | 32 | private notify(method: T, ...args: any[]): void { 33 | traverse(this.observers, observer => 34 | emptyAssert(observer[method], (handler: Function) => handler(...args)), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /client/src/website/components/header-bar/@icon-funcs.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import {IconButton, Tooltip} from '@material-ui/core'; 3 | import {observer} from 'mobx-react'; 4 | import {Inject} from '@wizardoc/injector'; 5 | 6 | import {User} from 'website/services'; 7 | 8 | export interface IconFunc { 9 | tooltip: string; 10 | body: ReactNode; 11 | isLogin?: boolean; 12 | handler(event?: React.MouseEvent): void; 13 | } 14 | 15 | export interface IconFuncsProps { 16 | iconFuncs: IconFunc[]; 17 | } 18 | 19 | @observer 20 | export class IconFuncs extends Component { 21 | @Inject 22 | userService!: User; 23 | 24 | render(): ReactNode { 25 | const {iconFuncs} = this.props; 26 | 27 | const renderIconFuncs = iconFuncs.map( 28 | ({tooltip, body, handler, isLogin}) => 29 | !isLogin || 30 | (this.userService.isLogin && ( 31 | 32 | 33 | {body} 34 | 35 | 36 | )), 37 | ); 38 | 39 | return <>{renderIconFuncs}; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /client/src/website/guards/overview/organization-guard.ts: -------------------------------------------------------------------------------- 1 | import {RouteComponentProps} from 'react-router-dom'; 2 | import {Inject} from '@wizardoc/injector'; 3 | 4 | import { 5 | ActivatedGuard, 6 | Route, 7 | OrganizationService, 8 | PropsInjector, 9 | } from 'website/services'; 10 | 11 | interface RouteParams { 12 | id: string; 13 | } 14 | 15 | export class OrganizationGuard implements ActivatedGuard { 16 | @Inject 17 | organizationService!: OrganizationService; 18 | 19 | async canActivated( 20 | _route: Route, 21 | props: RouteComponentProps, 22 | inject: PropsInjector, 23 | ): Promise { 24 | await this.organizationService.isInit(); 25 | 26 | const {id} = props.match.params; 27 | const redirect = '/overview/organization'; 28 | 29 | // valid id 30 | if (!id) { 31 | return redirect; 32 | } 33 | 34 | const organizationInfo = this.organizationService.organizations.find( 35 | ({id: originId}) => originId === id, 36 | ); 37 | 38 | // valid info of organization 39 | if (!organizationInfo) { 40 | return redirect; 41 | } 42 | 43 | inject({organizationInfo}); 44 | 45 | return true; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /client/src/website/components/community/document-list/document-list.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | import {Document} from '@wizardoc/shared'; 4 | import {withRouter, RouteComponentProps} from 'react-router-dom'; 5 | 6 | import {DocumentService} from 'website/services'; 7 | 8 | import {FetchData} from '../../common'; 9 | 10 | import {DocumentListItem} from './@document-list-item'; 11 | 12 | export interface DocumentListProps { 13 | data: Document[]; 14 | } 15 | 16 | const Wrapper = styled.div``; 17 | 18 | @FetchData(({extract}) => extract(DocumentService).all()) 19 | @withRouter 20 | export class DocumentList extends Component< 21 | Partial 22 | > { 23 | handleDocumentListItemClick(id: string): void { 24 | this.props.history!.push(`/document/detail/${id}`); 25 | } 26 | 27 | render(): ReactNode { 28 | const {data} = this.props; 29 | const renderDocumentList = data!.map(doc => ( 30 | this.handleDocumentListItemClick(doc.id)} 32 | document={doc} 33 | key={doc.id} 34 | /> 35 | )); 36 | 37 | return {renderDocumentList}; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /client/src/website/components/common/default-view.tsx: -------------------------------------------------------------------------------- 1 | import React, {ReactNode, Component} from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import {Default} from './default'; 5 | 6 | export interface DefaultViewProps { 7 | defaultImg: string; 8 | children: any; 9 | text: string; 10 | condition(): boolean; 11 | } 12 | 13 | const DefaultPanel = styled.div` 14 | width: 100%; 15 | height: 70%; 16 | display: flex; 17 | flex-direction: column; 18 | justify-content: center; 19 | align-items: center; 20 | `; 21 | 22 | const EmptyCategoryImg = styled.img` 23 | width: 100px; 24 | `; 25 | 26 | const EmptyText = styled.div` 27 | color: ${props => props.theme.grayTextColor}; 28 | margin-top: 10px; 29 | `; 30 | 31 | export class DefaultView extends Component { 32 | render(): ReactNode { 33 | const {defaultImg, condition, children, text} = this.props; 34 | 35 | return ( 36 | 39 | 40 | {text} 41 | 42 | } 43 | condition={condition} 44 | > 45 | {children} 46 | 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /client/src/website/pages/document-detail.tsx: -------------------------------------------------------------------------------- 1 | import React, {Component, ReactNode} from 'react'; 2 | import styled from 'styled-components'; 3 | import {Document} from '@wizardoc/shared'; 4 | import {RouteComponentProps} from 'react-router-dom'; 5 | 6 | import { 7 | MarkdownContent, 8 | FetchData, 9 | FetchDataComponentProps, 10 | MarkdownHeader, 11 | DocumentStatusBlock, 12 | DocumentComments, 13 | } from '../components'; 14 | import {DocumentService} from '../services'; 15 | 16 | interface RouteParams { 17 | id: string; 18 | } 19 | 20 | const Wrapper = styled.div` 21 | background: ${props => props.theme.flatGray}; 22 | `; 23 | 24 | @FetchData( 25 | ({extract}, props: RouteComponentProps): Promise => 26 | extract(DocumentService).detail(props.match.params.id), 27 | ) 28 | export class DocumentDetail extends Component< 29 | Partial> 30 | > { 31 | render(): ReactNode { 32 | const {data: document} = this.props; 33 | const {cover} = document!; 34 | 35 | return ( 36 | 37 | 38 | 39 | 40 | 41 | 42 | ); 43 | } 44 | } 45 | --------------------------------------------------------------------------------