├── .browserlistrc ├── .docker ├── .gitignore ├── compose │ ├── docker-compose.dev.yml │ ├── docker-compose.prod.yml │ └── docker-compose.services.yml ├── dockerfile │ └── dev.Dockerfile ├── project.json └── sh │ └── entrypoint.dev.sh ├── .dockerignore ├── .editorconfig ├── .eslintrc.js ├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ ├── build.yml │ ├── lint.yml │ └── storybook.yml ├── .gitignore ├── .husky ├── commit-msg ├── pre-commit └── pre-push ├── .lintstagedrc ├── .nvmrc ├── .nxignore ├── .prettierignore ├── .prettierrc ├── .yarn ├── .gitignore ├── plugins │ └── @yarnpkg │ │ ├── plugin-interactive-tools.cjs │ │ ├── plugin-typescript.cjs │ │ └── plugin-workspace-tools.cjs └── releases │ └── yarn-3.6.3.cjs ├── .yarnrc.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── apps ├── client │ ├── .config │ │ └── vite │ │ │ ├── entry.ts │ │ │ ├── fonts.ts │ │ │ └── plugins.ts │ ├── .eslintrc.js │ ├── Dockerfile │ ├── index.html │ ├── nginx.conf │ ├── package.json │ ├── project.json │ ├── public │ │ ├── favicon.svg │ │ ├── manifest-logo │ │ │ ├── logo192.png │ │ │ └── logo512.png │ │ ├── manifest.json │ │ └── service-worker.js │ ├── src │ │ ├── app │ │ │ ├── entrypoint │ │ │ │ └── core │ │ │ │ │ └── entry.tsx │ │ │ ├── index.ts │ │ │ ├── providers │ │ │ │ ├── router │ │ │ │ │ ├── config │ │ │ │ │ │ └── router.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── ui │ │ │ │ │ │ └── router-provider.tsx │ │ │ │ └── store │ │ │ │ │ ├── config │ │ │ │ │ └── store.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── ui │ │ │ │ │ └── store-provider.tsx │ │ │ └── root │ │ │ │ └── index.tsx │ │ ├── entities │ │ │ └── sign-in-modal-template │ │ │ │ ├── index.ts │ │ │ │ ├── lib │ │ │ │ └── helpers.ts │ │ │ │ └── ui │ │ │ │ ├── sign-in-modal-template.styles.ts │ │ │ │ └── sign-in-modal-template.tsx │ │ ├── features │ │ │ └── .gitkeep │ │ ├── pages │ │ │ ├── edit │ │ │ │ ├── index.ts │ │ │ │ └── ui │ │ │ │ │ └── edit-page.tsx │ │ │ └── main │ │ │ │ ├── index.ts │ │ │ │ └── ui │ │ │ │ └── main.tsx │ │ ├── shared │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── useStore.ts │ │ │ └── lib │ │ │ │ ├── components │ │ │ │ └── page │ │ │ │ │ ├── auth-guard.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── page.tsx │ │ │ │ └── index.ts │ │ └── widgets │ │ │ └── sign-in-modal │ │ │ ├── graphql │ │ │ ├── get-profile.query.ts │ │ │ └── sign-in.mutation.ts │ │ │ ├── index.ts │ │ │ ├── lib │ │ │ └── exceptions.ts │ │ │ ├── store │ │ │ ├── auth.services.ts │ │ │ └── auth.store.ts │ │ │ └── ui │ │ │ └── sign-in-modal.tsx │ ├── tsconfig.app.json │ ├── tsconfig.json │ └── tsconfig.spec.json ├── docs │ ├── .eslintrc.js │ ├── .vitepress │ │ ├── config.mts │ │ └── theme │ │ │ ├── index.ts │ │ │ └── style.css │ ├── architecture │ │ ├── backend.md │ │ └── frontend.md │ ├── ending │ │ └── further-development.md │ ├── features │ │ ├── animations.md │ │ ├── automation.md │ │ ├── config-incapsulation.md │ │ ├── custom-libraries.md │ │ ├── file-system-api.md │ │ ├── prisma.md │ │ ├── pwa.md │ │ └── storybook.md │ ├── index.md │ ├── introduction │ │ ├── about-project.md │ │ ├── getting-started.md │ │ └── who-am-i.md │ ├── other-concepts │ │ ├── authorization.md │ │ ├── code-generation.md │ │ ├── frontend-business-logic.md │ │ ├── graphql.md │ │ ├── precommit-hooks.md │ │ ├── testing.md │ │ ├── ts-morph.md │ │ └── validation.md │ ├── package.json │ ├── project.json │ ├── public │ │ ├── logo-large.png │ │ ├── logo.svg │ │ └── overview │ │ │ ├── functionality-color-picker.png │ │ │ ├── functionality-ending.png │ │ │ ├── functionality-html.png │ │ │ ├── functionality-intro.png │ │ │ └── functionality-login.png │ ├── scripts │ │ └── deploy.sh │ └── vite.config.ts └── server │ ├── gateway │ ├── .config │ │ ├── jest.ts │ │ └── webpack.ts │ ├── .eslintrc.json │ ├── .gitignore │ ├── Dockerfile │ ├── package.json │ ├── prisma │ │ ├── .gitignore │ │ ├── concat-prisma-files.js │ │ ├── config │ │ │ └── base.prisma │ │ └── models │ │ │ └── users.prisma │ ├── project.json │ ├── src │ │ ├── app.module.ts │ │ ├── config │ │ │ ├── cors.ts │ │ │ └── swagger.ts │ │ ├── core │ │ │ ├── auth │ │ │ │ ├── auth.module.ts │ │ │ │ └── auth.resolver.ts │ │ │ └── code-executor │ │ │ │ ├── code-executor.controller.ts │ │ │ │ ├── code-executor.module.ts │ │ │ │ └── index.ts │ │ └── main.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ └── tsconfig.spec.json │ ├── service-auth │ ├── .config │ │ ├── jest.ts │ │ └── webpack.ts │ ├── .eslintrc.js │ ├── Dockerfile │ ├── README.md │ ├── package.json │ ├── project.json │ ├── src │ │ ├── auth.consumer.ts │ │ ├── auth.module.ts │ │ ├── auth.service.ts │ │ ├── lib │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── main.ts │ │ ├── repository │ │ │ └── accounts.repository.ts │ │ └── strategies │ │ │ ├── jwt.strategy.ts │ │ │ └── local.strategy.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ └── tsconfig.spec.json │ └── service-code-executor │ ├── .config │ ├── jest.ts │ └── webpack.ts │ ├── .eslintrc.json │ ├── Dockerfile │ ├── package.json │ ├── project.json │ ├── src │ ├── code-executor.consumer.ts │ ├── code-executor.module.ts │ ├── exceptions │ │ ├── failed-to-fetch.exception.ts │ │ └── index.ts │ ├── lib │ │ ├── helpers │ │ │ └── transform-language.ts │ │ └── type-guards.ts │ ├── main.ts │ └── queries │ │ ├── handlers │ │ ├── execute-code.handler.ts │ │ └── index.ts │ │ └── impl │ │ ├── execute-code.query.ts │ │ └── index.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ └── tsconfig.spec.json ├── commitlint.config.js ├── jest.config.ts ├── jest.preset.js ├── nx.json ├── package.json ├── packages ├── api │ ├── common │ │ ├── .config │ │ │ └── jest.ts │ │ ├── .eslintrc.json │ │ ├── README.md │ │ ├── package.json │ │ ├── project.json │ │ ├── src │ │ │ ├── consts │ │ │ │ ├── index.ts │ │ │ │ └── microservices.ts │ │ │ ├── decorators │ │ │ │ ├── index.ts │ │ │ │ ├── string-field.decorator.ts │ │ │ │ └── user.decorator.ts │ │ │ ├── exception-filters │ │ │ │ ├── http-exception.filter.ts │ │ │ │ ├── index.ts │ │ │ │ └── rpc-exception.filter.ts │ │ │ ├── guards │ │ │ │ ├── gql-auth.guard.ts │ │ │ │ ├── gql-local-auth.guard.ts │ │ │ │ ├── index.ts │ │ │ │ └── jwt-auth.guard.ts │ │ │ ├── index.ts │ │ │ ├── modules │ │ │ │ ├── database │ │ │ │ │ ├── database.module.ts │ │ │ │ │ ├── database.service.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── env │ │ │ │ │ ├── conf │ │ │ │ │ │ ├── database.config.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── kafka.config.ts │ │ │ │ │ │ ├── misc.config.ts │ │ │ │ │ │ └── server.config.ts │ │ │ │ │ ├── env.decorator.ts │ │ │ │ │ ├── env.module.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── types │ │ │ │ │ │ ├── enviroment.interfaces.ts │ │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── jwt │ │ │ │ │ ├── index.ts │ │ │ │ │ └── jwt.module.ts │ │ │ │ ├── kafka │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── kafka.interface.ts │ │ │ │ │ ├── kafka.module.ts │ │ │ │ │ └── kafka.service.ts │ │ │ │ └── listener │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── listener.consts.ts │ │ │ │ │ ├── listener.interfaces.ts │ │ │ │ │ ├── listener.module.ts │ │ │ │ │ └── listener.service.ts │ │ │ ├── pipes │ │ │ │ ├── index.ts │ │ │ │ └── validation.pipe.ts │ │ │ ├── types │ │ │ │ ├── _prisma.ts │ │ │ │ └── guards │ │ │ │ │ ├── index.ts │ │ │ │ │ └── is-custom-rpc-exception.ts │ │ │ └── utils │ │ │ │ └── validators │ │ │ │ ├── env.validator.ts │ │ │ │ └── index.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.lib.json │ │ └── tsconfig.spec.json │ └── contracts │ │ ├── .eslintrc.json │ │ ├── README.md │ │ ├── package.json │ │ ├── project.json │ │ ├── src │ │ ├── dto │ │ │ ├── execute-code.dto.ts │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── inputs │ │ │ ├── index.ts │ │ │ └── sign-in.input.ts │ │ ├── interfaces │ │ │ ├── auth.interfaces.ts │ │ │ ├── execute-code.interfaces.ts │ │ │ └── index.ts │ │ ├── responses │ │ │ ├── index.ts │ │ │ ├── token.response.ts │ │ │ └── user.response.ts │ │ └── rpc │ │ │ ├── auth.rpc.ts │ │ │ ├── code-executor.rpc.ts │ │ │ └── index.ts │ │ ├── tsconfig.json │ │ └── tsconfig.lib.json ├── config │ ├── .eslintrc.json │ ├── README.md │ ├── package.json │ ├── project.json │ ├── src │ │ ├── babel │ │ │ └── vite.json │ │ ├── consts │ │ │ ├── client.ts │ │ │ └── server.ts │ │ ├── index.ts │ │ ├── jest │ │ │ ├── create-jest-config.ts │ │ │ └── index.ts │ │ ├── lib.ts │ │ ├── storybook │ │ │ ├── create-preview-defaults.ts │ │ │ ├── create-storybook-config.ts │ │ │ ├── index.ts │ │ │ └── plugins │ │ │ │ └── create-viewports.ts │ │ ├── tsconfig │ │ │ ├── base.json │ │ │ └── paths │ │ │ │ ├── second-layer.json │ │ │ │ └── third-layer.json │ │ ├── types.ts │ │ ├── vite │ │ │ ├── builders │ │ │ │ ├── aliases.ts │ │ │ │ ├── build.ts │ │ │ │ ├── globals.ts │ │ │ │ ├── index.ts │ │ │ │ ├── plugins.ts │ │ │ │ ├── preview.ts │ │ │ │ ├── server.ts │ │ │ │ └── vitest.ts │ │ │ ├── create-vite-config.ts │ │ │ ├── index.ts │ │ │ ├── misc.ts │ │ │ └── types.ts │ │ └── webpack │ │ │ ├── build-webpack-config.ts │ │ │ ├── index.ts │ │ │ ├── resolvers │ │ │ ├── index.ts │ │ │ └── tsconfig-paths.ts │ │ │ └── types.ts │ ├── tsconfig.json │ └── tsconfig.lib.json ├── generator │ ├── README.md │ ├── package.json │ ├── project.json │ └── templates │ │ ├── _generator │ │ └── g │ │ │ ├── README.ejs.t │ │ │ ├── new │ │ │ └── index.ejs.t │ │ │ ├── prompt.ejs.t │ │ │ └── prompt.js │ │ ├── fsd-module │ │ ├── README.md │ │ └── new │ │ │ ├── hooks │ │ │ └── index.ejs.t │ │ │ ├── index.ejs.t │ │ │ ├── lib │ │ │ └── index.ejs.t │ │ │ ├── prompt.js │ │ │ ├── store │ │ │ └── gitkeep.ejs.t │ │ │ └── ui │ │ │ ├── component.ejs.t │ │ │ └── component.styles.ejs.t │ │ └── ui │ │ ├── README.md │ │ └── new │ │ ├── component.ejs.t │ │ ├── component.stories.ejs.t │ │ ├── component.styles.ejs.t │ │ ├── index.ejs.t │ │ └── prompt.js └── web │ ├── editor │ ├── .babelrc │ ├── .config │ │ └── vite.ts │ ├── .eslintrc.json │ ├── README.md │ ├── package.json │ ├── project.json │ ├── public │ │ └── logo.svg │ ├── src │ │ ├── app │ │ │ ├── editor.tsx │ │ │ ├── index.ts │ │ │ ├── providers │ │ │ │ ├── editor-store │ │ │ │ │ ├── config │ │ │ │ │ │ ├── editor.actions.ts │ │ │ │ │ │ ├── editor.getters.ts │ │ │ │ │ │ ├── editor.services.ts │ │ │ │ │ │ └── editor.store.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── lib │ │ │ │ │ │ └── default-code-template.ts │ │ │ │ │ └── ui │ │ │ │ │ │ └── editor-store-provider.tsx │ │ │ │ ├── modals-provider │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ └── ui │ │ │ │ │ │ └── modals-context-provider.tsx │ │ │ │ └── theme-loader │ │ │ │ │ ├── hooks │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── use-custom-theme │ │ │ │ │ │ └── use-custom-theme.ts │ │ │ │ │ └── use-theme-loader │ │ │ │ │ │ ├── assert-theme-object.ts │ │ │ │ │ │ ├── themes │ │ │ │ │ │ ├── Dracula.json │ │ │ │ │ │ ├── Dreamweaver.json │ │ │ │ │ │ ├── Eiffel.json │ │ │ │ │ │ ├── GitHub.json │ │ │ │ │ │ ├── IDLE.json │ │ │ │ │ │ ├── Monokai.json │ │ │ │ │ │ ├── Nord.json │ │ │ │ │ │ ├── Tomorrow.json │ │ │ │ │ │ └── Twilight.json │ │ │ │ │ │ └── use-theme-loader.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── ui │ │ │ │ │ └── theme-loader.tsx │ │ │ └── styles │ │ │ │ └── editor.styles.ts │ │ ├── entities │ │ │ ├── editor-core │ │ │ │ ├── editor-core.tsx │ │ │ │ └── index.ts │ │ │ ├── header-options │ │ │ │ ├── index.ts │ │ │ │ └── ui │ │ │ │ │ ├── header-options.styles.ts │ │ │ │ │ └── header-options.tsx │ │ │ ├── header-right-section │ │ │ │ ├── index.ts │ │ │ │ └── ui │ │ │ │ │ ├── header-right-section.styles.ts │ │ │ │ │ └── header-right-section.tsx │ │ │ ├── key-buildings │ │ │ │ ├── index.ts │ │ │ │ └── key-buildings.tsx │ │ │ ├── preview-editor │ │ │ │ ├── index.ts │ │ │ │ └── ui │ │ │ │ │ ├── preview-editor.styles.ts │ │ │ │ │ └── preview-editor.tsx │ │ │ ├── preview-i-frame │ │ │ │ ├── index.ts │ │ │ │ ├── lib │ │ │ │ │ └── create-html-template.ts │ │ │ │ └── ui │ │ │ │ │ └── i-frame.tsx │ │ │ └── terminal-output │ │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── use-terminal-output-animations.ts │ │ │ │ ├── index.ts │ │ │ │ └── ui │ │ │ │ ├── bottom-scroll │ │ │ │ └── bottom-scroll.tsx │ │ │ │ ├── terminal-output.styles.ts │ │ │ │ └── terminal-output │ │ │ │ └── terminal-output.tsx │ │ ├── features │ │ │ ├── language-switcher │ │ │ │ ├── hooks │ │ │ │ │ ├── index.ts │ │ │ │ │ └── use-mapped-languages.ts │ │ │ │ ├── index.ts │ │ │ │ └── ui │ │ │ │ │ └── language-switcher.tsx │ │ │ ├── switch-font-size │ │ │ │ ├── index.ts │ │ │ │ └── ui │ │ │ │ │ └── font-size-switcher.tsx │ │ │ ├── switch-tab-size │ │ │ │ ├── index.ts │ │ │ │ └── ui │ │ │ │ │ └── tab-size-switcher.tsx │ │ │ └── switch-theme │ │ │ │ ├── index.ts │ │ │ │ └── ui │ │ │ │ └── theme-switcher.tsx │ │ ├── index.ts │ │ ├── shared │ │ │ ├── consts │ │ │ │ ├── font-sizes.ts │ │ │ │ ├── key-buildings.ts │ │ │ │ ├── languages.ts │ │ │ │ └── themes.ts │ │ │ ├── editor-config.ts │ │ │ ├── exceptions.ts │ │ │ └── hooks │ │ │ │ ├── index.ts │ │ │ │ ├── use-editor.ts │ │ │ │ ├── use-modals-context.ts │ │ │ │ └── use-store.ts │ │ └── widgets │ │ │ ├── aside │ │ │ ├── hooks │ │ │ │ ├── use-aside-animation.ts │ │ │ │ └── use-editor-actions.ts │ │ │ ├── index.ts │ │ │ └── ui │ │ │ │ ├── aside.styles.ts │ │ │ │ └── aside.tsx │ │ │ ├── editor-content │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ ├── use-alt-navigation │ │ │ │ │ └── use-alt-navigation.ts │ │ │ │ ├── use-file-service │ │ │ │ │ ├── lib │ │ │ │ │ │ ├── consts.ts │ │ │ │ │ │ └── get-language-from-name.ts │ │ │ │ │ ├── use-file-handler.ts │ │ │ │ │ ├── use-file-saver.ts │ │ │ │ │ └── use-file-service.ts │ │ │ │ └── use-keyboard-manager │ │ │ │ │ └── use-keyboard-manager.ts │ │ │ ├── index.ts │ │ │ ├── store │ │ │ │ └── content.actions.ts │ │ │ ├── types │ │ │ │ ├── guards │ │ │ │ │ └── is-file-data.ts │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ └── ui │ │ │ │ ├── editor-content.styles.ts │ │ │ │ └── editor-content.tsx │ │ │ ├── header │ │ │ ├── errors.ts │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ ├── use-code-runner.ts │ │ │ │ └── use-header-animation.ts │ │ │ ├── index.ts │ │ │ ├── store │ │ │ │ └── execute.services.ts │ │ │ ├── types.ts │ │ │ └── ui │ │ │ │ ├── header.styles.ts │ │ │ │ └── header.tsx │ │ │ ├── html-preview │ │ │ ├── context │ │ │ │ ├── html-preview-provider.tsx │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── types.ts │ │ │ └── ui │ │ │ │ ├── html-preview.styles.ts │ │ │ │ └── html-preview.tsx │ │ │ ├── settings │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── use-color-callback.ts │ │ │ ├── index.ts │ │ │ └── ui │ │ │ │ ├── settings.styles.ts │ │ │ │ └── settings.tsx │ │ │ ├── tabs │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ ├── use-confirm.ts │ │ │ │ └── use-mapped-tabs.ts │ │ │ ├── index.ts │ │ │ ├── lib │ │ │ │ ├── helpers │ │ │ │ │ ├── generate-new-tab.ts │ │ │ │ │ └── is-max-tabs-length.ts │ │ │ │ └── index.ts │ │ │ ├── store │ │ │ │ └── tabs.actions.ts │ │ │ ├── types.ts │ │ │ └── ui │ │ │ │ ├── tabs.styles.ts │ │ │ │ └── tabs.tsx │ │ │ └── terminal │ │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── use-terminal-tabs.ts │ │ │ ├── index.ts │ │ │ ├── store │ │ │ └── terminal.actions.ts │ │ │ ├── types.ts │ │ │ └── ui │ │ │ ├── terminal.styles.ts │ │ │ └── terminal.tsx │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json │ ├── shared │ ├── .babelrc │ ├── .config │ │ └── vite.ts │ ├── .eslintrc.json │ ├── README.md │ ├── env.d.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── assets │ │ │ ├── index.ts │ │ │ ├── logo.png │ │ │ └── logo.svg │ │ ├── config │ │ │ ├── apollo-client.ts │ │ │ ├── axios.ts │ │ │ ├── index.ts │ │ │ ├── local-storage.ts │ │ │ └── paths.ts │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── use-notifications.ts │ │ ├── index.ts │ │ ├── lib │ │ │ ├── apollo │ │ │ │ ├── apollo-middleware.ts │ │ │ │ └── index.ts │ │ │ ├── components │ │ │ │ ├── Display.ts │ │ │ │ └── index.ts │ │ │ ├── helpers │ │ │ │ ├── index.ts │ │ │ │ └── local-storage.ts │ │ │ └── icons.ts │ │ ├── providers │ │ │ ├── animations │ │ │ │ └── animation-provider.tsx │ │ │ ├── error-boundary │ │ │ │ ├── error-boundary.tsx │ │ │ │ └── ui │ │ │ │ │ └── error-template.tsx │ │ │ ├── index.ts │ │ │ ├── notifications │ │ │ │ └── notifications-provider.tsx │ │ │ ├── styles │ │ │ │ ├── app.styles.ts │ │ │ │ └── index.ts │ │ │ └── theme │ │ │ │ ├── config │ │ │ │ ├── antd-config.ts │ │ │ │ └── themes.ts │ │ │ │ ├── index.ts │ │ │ │ ├── styled.d.ts │ │ │ │ └── ui │ │ │ │ └── theme-provider.tsx │ │ ├── storybook │ │ │ ├── decorators │ │ │ │ ├── animation.decorator.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── styles.decorator.tsx │ │ │ │ └── theme.decorator.tsx │ │ │ ├── index.ts │ │ │ ├── lib │ │ │ │ ├── create-storybook-variant.ts │ │ │ │ └── index.ts │ │ │ └── types.ts │ │ ├── styles │ │ │ ├── index.ts │ │ │ ├── mixins.ts │ │ │ └── variables.ts │ │ └── types │ │ │ ├── common │ │ │ ├── graphql.ts │ │ │ └── grnx.ts │ │ │ ├── index.ts │ │ │ └── lib │ │ │ ├── animations.ts │ │ │ └── context.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json │ └── ui │ ├── .babelrc │ ├── .config │ ├── storybook │ │ ├── main.ts │ │ ├── preview.ts │ │ └── test-runner.config.ts │ └── vite.ts │ ├── .eslintrc.json │ ├── README.md │ ├── package.json │ ├── project.json │ ├── src │ ├── color-button │ │ ├── color-button.stories.tsx │ │ └── color-button.tsx │ ├── index.ts │ ├── modal │ │ ├── hooks │ │ │ └── use-modal-transitions.ts │ │ ├── index.ts │ │ └── ui │ │ │ ├── modal.stories.tsx │ │ │ ├── modal.styles.ts │ │ │ └── modal.tsx │ ├── popover │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── use-popover-animation.ts │ │ ├── index.ts │ │ └── ui │ │ │ ├── popover.stories.tsx │ │ │ ├── popover.styles.tsx │ │ │ └── popover.tsx │ └── select │ │ ├── select.stories.tsx │ │ └── select.tsx │ ├── tsconfig.json │ ├── tsconfig.lib.json │ ├── tsconfig.spec.json │ └── tsconfig.storybook.json ├── project.json ├── tools ├── database │ └── dump.sql ├── dev │ ├── package.json │ ├── project.json │ └── src │ │ ├── env │ │ ├── .env │ │ ├── .gitignore │ │ └── .override.env │ │ └── img │ │ ├── architecture_diagram.png │ │ ├── git_flow_trunk_based.png │ │ ├── microfrontend.png │ │ └── nestjs_folders.png ├── generators │ ├── .eslintrc.js │ ├── generators.json │ ├── package.json │ ├── project.json │ ├── src │ │ └── microservice │ │ │ ├── files │ │ │ ├── .config │ │ │ │ ├── jest.ts.template │ │ │ │ └── webpack.ts.template │ │ │ ├── .eslintrc.js.template │ │ │ ├── Dockerfile.template │ │ │ ├── README.md.template │ │ │ ├── package.json.template │ │ │ ├── project.json.template │ │ │ ├── src │ │ │ │ ├── __name__.consumer.ts.template │ │ │ │ ├── __name__.module.ts.template │ │ │ │ ├── lib │ │ │ │ │ └── index.ts.template │ │ │ │ ├── main.ts.template │ │ │ │ └── queries │ │ │ │ │ ├── handlers │ │ │ │ │ └── index.ts.template │ │ │ │ │ └── impl │ │ │ │ │ └── index.ts.template │ │ │ ├── tsconfig.app.json.template │ │ │ ├── tsconfig.json.template │ │ │ └── tsconfig.spec.json.template │ │ │ ├── generator.ts │ │ │ └── schema.json │ ├── tsconfig.json │ └── tsconfig.lib.json └── scripts │ ├── .eslintrc.json │ ├── package.json │ ├── project.json │ ├── src │ ├── lib │ │ ├── helpers.ts │ │ └── run-project-files.ts │ └── ts-morph │ │ ├── check-uppercase-files.ts │ │ ├── remove-all-console-logs.ts │ │ ├── rename-client-shared.ts │ │ ├── rename-imports │ │ ├── consts.ts │ │ └── script.ts │ │ └── rename-projects-to-kebab-case.ts │ └── tsconfig.json ├── tsconfig.base.json └── yarn.lock /.browserlistrc: -------------------------------------------------------------------------------- 1 | [production] 2 | defaults 3 | not IE 11 4 | 5 | [development] 6 | last 2 Chrome versions 7 | -------------------------------------------------------------------------------- /.docker/.gitignore: -------------------------------------------------------------------------------- 1 | .override.env 2 | -------------------------------------------------------------------------------- /.docker/compose/docker-compose.dev.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | workspace: 5 | build: 6 | dockerfile: .docker/dockerfile/dev.Dockerfile 7 | context: . 8 | restart: always 9 | profiles: 10 | - workspace 11 | env_file: 12 | - .env 13 | - .docker/.override.env 14 | volumes: 15 | - ./apps:/opt/app/apps 16 | - ./packages:/opt/app/packages 17 | - /opt/app/node_modules 18 | container_name: workspace 19 | networks: 20 | - cgnet 21 | entrypoint: sh entrypoint.sh 22 | ports: 23 | - 3000:3000 24 | - 6868:6868 25 | -------------------------------------------------------------------------------- /.docker/dockerfile/dev.Dockerfile: -------------------------------------------------------------------------------- 1 | #/** 2 | # * This docker file is used only in development mode 3 | # * It runs all processes, microservices and libraries 4 | # * in one large container so as not to take up a lot of 5 | # * space. Hot reload enabled. 6 | # */ 7 | 8 | FROM --platform=linux/amd64 node:20.8.0-alpine as build 9 | WORKDIR /opt/app 10 | 11 | ## Installing dependencies ## 12 | 13 | COPY package.json yarn.lock .yarnrc.yml ./ 14 | COPY .yarn .yarn 15 | 16 | COPY packages/config/package.json packages/config/package.json 17 | 18 | RUN yarn install 19 | 20 | ## Copying source code ## 21 | 22 | COPY packages packages 23 | 24 | COPY apps apps 25 | 26 | RUN yarn install 27 | 28 | COPY . . 29 | 30 | ## Copying entrypoint scripts ## 31 | 32 | COPY .docker/sh/entrypoint.dev.sh entrypoint.sh 33 | 34 | 35 | RUN chmod +x entrypoint.sh; 36 | 37 | RUN echo "done." 38 | -------------------------------------------------------------------------------- /.docker/sh/entrypoint.dev.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | yarn nx run gateway:prisma:init 4 | 5 | yarn nx serve --host=0.0.0.0 6 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | dist 2 | tmp 3 | node_modules 4 | .idea 5 | .husky 6 | .editorconfig 7 | .lintstagedrc 8 | commitlint.config.js 9 | CHANGELOG.md 10 | LICENSE 11 | README.md 12 | jest.config.ts 13 | jest.preset.js 14 | local 15 | data 16 | tmp 17 | .github 18 | .gitignore 19 | .gitattributes 20 | .yarn/cache 21 | .yarn/install-state.gz 22 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [*.md] 11 | max_line_length = off 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | const grnx = require('@grnx-utils/eslint') 2 | 3 | module.exports = grnx({ 4 | root: __dirname, 5 | tsconfig: 'tsconfig.base.json', 6 | monorepo: true, 7 | enableImports: false, 8 | ext: { 9 | 'max-len': 'off' 10 | } 11 | }) 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | tmp 3 | node_modules 4 | .idea 5 | local 6 | *.env 7 | data 8 | cache 9 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | yarn dlx commitlint --edit $1 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | yarn install 5 | 6 | yarn dlx yarn-upgrade-all 7 | 8 | yarn lint-staged --relative 9 | 10 | -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | 5 | -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "*.ts": ["yarn dlx nx lint"] 3 | } 4 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 20.8.0 2 | -------------------------------------------------------------------------------- /.nxignore: -------------------------------------------------------------------------------- 1 | # Added to avoid causing additional problems when serving nestjs applications. 2 | _schema.gql 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearonix/code-gear/428293078745619b14bce932d30b9b73e5cce08c/.prettierignore -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "bracketSpacing": true, 4 | "bracketSameLine": true, 5 | "arrowParens": "always", 6 | "singleQuote": true 7 | } 8 | -------------------------------------------------------------------------------- /.yarn/.gitignore: -------------------------------------------------------------------------------- 1 | install-state.gz 2 | unplugged 3 | cache 4 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | #checksumBehavior: update 4 | 5 | #cacheFolder: ./.yarn/cache 6 | 7 | #enableImmutableInstalls: false 8 | 9 | plugins: 10 | - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs 11 | spec: "@yarnpkg/plugin-interactive-tools" 12 | - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs 13 | spec: "@yarnpkg/plugin-workspace-tools" 14 | - path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs 15 | spec: "@yarnpkg/plugin-typescript" 16 | 17 | yarnPath: .yarn/releases/yarn-3.6.3.cjs 18 | -------------------------------------------------------------------------------- /apps/client/.config/vite/entry.ts: -------------------------------------------------------------------------------- 1 | // It is important to specify relative paths here. 2 | import { resolve } from 'path' 3 | 4 | import { createViteConfig } from '../../../../packages/config/src/vite' 5 | import { buildCustomPlugins } from './plugins' 6 | 7 | export default createViteConfig({ 8 | projectName: 'client', 9 | projectType: 'application', 10 | rootDir: resolve(__dirname, '..'), 11 | layer: 'second', 12 | external: [], 13 | plugins: buildCustomPlugins() 14 | }) 15 | -------------------------------------------------------------------------------- /apps/client/.config/vite/fonts.ts: -------------------------------------------------------------------------------- 1 | export const fonts: string[] = [ 2 | 'https://fonts.googleapis.com/css2?family=Poppins&display=swap' 3 | ] 4 | -------------------------------------------------------------------------------- /apps/client/.config/vite/plugins.ts: -------------------------------------------------------------------------------- 1 | import preact from '@preact/preset-vite' 2 | import { PluginOption } from 'vite' 3 | import { VitePWA } from 'vite-plugin-pwa' 4 | import webfontDownload from 'vite-plugin-webfont-dl' 5 | 6 | import { fonts } from './fonts' 7 | 8 | export const buildCustomPlugins = (): PluginOption[] => [ 9 | webfontDownload(fonts), 10 | preact(), 11 | VitePWA({ 12 | registerType: 'autoUpdate', 13 | injectRegister: 'auto', 14 | strategies: 'injectManifest', 15 | srcDir: 'public', 16 | filename: 'service-worker.js', 17 | workbox: { 18 | globPatterns: ['**/*.{js,css,html,ico,png,svg}'], 19 | clientsClaim: true, 20 | skipWaiting: true 21 | }, 22 | devOptions: { 23 | enabled: false 24 | }, 25 | includeAssets: ['**/*'] 26 | }) 27 | ] 28 | -------------------------------------------------------------------------------- /apps/client/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | plugins: ['preact'], 4 | extends: ['../../.eslintrc.js'], 5 | ignorePatterns: ['!**/*'] 6 | } 7 | -------------------------------------------------------------------------------- /apps/client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM --platform=linux/amd64 node:20.8.0-alpine as build 2 | WORKDIR /opt/app 3 | 4 | ## Installing dependencies ## 5 | 6 | COPY package.json yarn.lock .yarnrc.yml ./ 7 | COPY .yarn .yarn 8 | 9 | COPY packages/config/package.json packages/config/package.json 10 | 11 | RUN yarn install 12 | 13 | ## Copying source code ## 14 | 15 | COPY apps/client apps/client 16 | 17 | COPY packages packages 18 | 19 | RUN yarn install 20 | 21 | COPY . . 22 | 23 | ## Building app to produciton ## 24 | 25 | RUN yarn nx run client:build 26 | 27 | ## Nginx setup ## 28 | 29 | FROM nginx:1.24-alpine 30 | 31 | COPY --from=build /opt/app/dist/apps/client /usr/share/nginx/html 32 | COPY ./apps/client/nginx.conf /etc/nginx/conf.d/default.conf 33 | 34 | EXPOSE 80 35 | -------------------------------------------------------------------------------- /apps/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | CodeGear 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /apps/client/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | root /usr/share/nginx/html; 4 | 5 | location / { 6 | index index.html index.htm; 7 | try_files $uri $uri/ /index.html; 8 | } 9 | 10 | error_page 404 /index.html; 11 | location = /404 { 12 | return 404; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /apps/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cg-client", 3 | "version": "0.0.1", 4 | "devDependencies": { 5 | "cg-config": "workspace:^", 6 | "cg-ui": "workspace:^" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /apps/client/public/manifest-logo/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearonix/code-gear/428293078745619b14bce932d30b9b73e5cce08c/apps/client/public/manifest-logo/logo192.png -------------------------------------------------------------------------------- /apps/client/public/manifest-logo/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearonix/code-gear/428293078745619b14bce932d30b9b73e5cce08c/apps/client/public/manifest-logo/logo512.png -------------------------------------------------------------------------------- /apps/client/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "CodeGear", 3 | "short_name": "CodeGear", 4 | "theme_color": "#2196f3", 5 | "background_color": "#2196f3", 6 | "scope": "/", 7 | "start_url": ".", 8 | "display": "standalone", 9 | "orientation": "portrait", 10 | "description": "Fast online text editor", 11 | "icons": [ 12 | { 13 | "src": "/manifest-logo/logo192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "/manifest-logo/logo512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /apps/client/src/app/entrypoint/core/entry.tsx: -------------------------------------------------------------------------------- 1 | import { render } from 'preact' 2 | 3 | import { Root } from '../../root' 4 | 5 | render(, document.querySelector('#root')!) 6 | -------------------------------------------------------------------------------- /apps/client/src/app/index.ts: -------------------------------------------------------------------------------- 1 | export { RootStore, StoreContext } from './providers/store' 2 | -------------------------------------------------------------------------------- /apps/client/src/app/providers/router/config/router.tsx: -------------------------------------------------------------------------------- 1 | import { RoutePaths } from '@code-gear/web/shared' 2 | import { createBrowserRouter } from 'react-router-dom' 3 | 4 | import { EditPage } from '@/pages/edit' 5 | import { Main } from '@/pages/main' 6 | 7 | const router = createBrowserRouter([ 8 | { 9 | path: RoutePaths.MAIN, 10 | element:
11 | }, 12 | { 13 | path: RoutePaths.EDITOR, 14 | element: 15 | } 16 | ]) 17 | 18 | export default router 19 | -------------------------------------------------------------------------------- /apps/client/src/app/providers/router/index.ts: -------------------------------------------------------------------------------- 1 | export { default as RouterProvider } from './ui/router-provider' 2 | -------------------------------------------------------------------------------- /apps/client/src/app/providers/router/ui/router-provider.tsx: -------------------------------------------------------------------------------- 1 | import { RouterProvider as Router } from 'react-router-dom' 2 | 3 | import router from '../config/router' 4 | 5 | const RouterProvider = () => { 6 | return 7 | } 8 | 9 | export default RouterProvider 10 | -------------------------------------------------------------------------------- /apps/client/src/app/providers/store/config/store.ts: -------------------------------------------------------------------------------- 1 | import { EditorStore } from '@code-gear/web/editor' 2 | import { makeAutoObservable } from 'mobx' 3 | 4 | import { AuthStore } from '@/widgets/sign-in-modal' 5 | 6 | class RootStore { 7 | editor: EditorStore 8 | auth: AuthStore 9 | 10 | constructor() { 11 | makeAutoObservable(this) 12 | this.editor = new EditorStore() 13 | this.auth = new AuthStore() 14 | } 15 | } 16 | 17 | export default RootStore 18 | -------------------------------------------------------------------------------- /apps/client/src/app/providers/store/index.ts: -------------------------------------------------------------------------------- 1 | export { default as RootStore } from './config/store' 2 | export { StoreContext, default as StoreProvider } from './ui/store-provider' 3 | -------------------------------------------------------------------------------- /apps/client/src/app/providers/store/ui/store-provider.tsx: -------------------------------------------------------------------------------- 1 | import { WithPreactChildren } from '@code-gear/web/shared' 2 | import { createContext } from 'react' 3 | 4 | import RootStore from '../config/store' 5 | 6 | export const StoreContext = createContext({} as RootStore) 7 | 8 | export const StoreProvider = ({ children }: WithPreactChildren) => { 9 | const root = new RootStore() 10 | 11 | return {children} 12 | } 13 | 14 | export default StoreProvider 15 | -------------------------------------------------------------------------------- /apps/client/src/app/root/index.tsx: -------------------------------------------------------------------------------- 1 | import 'normalize.css' 2 | 3 | import { GlobalStyles } from '@code-gear/web/shared' 4 | import { ThemeProvider } from '@code-gear/web/shared' 5 | 6 | import { RouterProvider } from '../providers/router' 7 | import { StoreProvider } from '../providers/store' 8 | 9 | export const Root = () => { 10 | return ( 11 | 12 | 13 | 14 | 15 | 16 | 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /apps/client/src/entities/sign-in-modal-template/index.ts: -------------------------------------------------------------------------------- 1 | export { SignInModalTemplate } from './ui/sign-in-modal-template' 2 | -------------------------------------------------------------------------------- /apps/client/src/entities/sign-in-modal-template/lib/helpers.ts: -------------------------------------------------------------------------------- 1 | export const getFormItemRules = () => [{ required: true, min: 6, max: 14 }] 2 | -------------------------------------------------------------------------------- /apps/client/src/entities/sign-in-modal-template/ui/sign-in-modal-template.styles.ts: -------------------------------------------------------------------------------- 1 | import { s } from '@code-gear/web/shared' 2 | import { Form } from 'antd' 3 | import styled from 'styled-components' 4 | 5 | export const SignInModalStyles = styled(Form)` 6 | width: 84%; 7 | margin: 0 auto; 8 | ` 9 | 10 | export const SubmitButton = styled.button` 11 | height: 40px; 12 | width: 100%; 13 | cursor: pointer; 14 | font-size: ${({ theme }) => theme.fz7}; 15 | margin: 0 auto; 16 | margin-top: 80px; 17 | display: block; 18 | ` 19 | 20 | export const LogoWrapper = styled.img` 21 | ${s.wh('68px', '92px')} 22 | margin: 10px auto; 23 | display: block; 24 | ` 25 | -------------------------------------------------------------------------------- /apps/client/src/features/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearonix/code-gear/428293078745619b14bce932d30b9b73e5cce08c/apps/client/src/features/.gitkeep -------------------------------------------------------------------------------- /apps/client/src/pages/edit/index.ts: -------------------------------------------------------------------------------- 1 | export { default as EditPage } from './ui/edit-page' 2 | -------------------------------------------------------------------------------- /apps/client/src/pages/edit/ui/edit-page.tsx: -------------------------------------------------------------------------------- 1 | import { Editor } from '@code-gear/web/editor' 2 | import { Suspense } from 'react' 3 | 4 | import { Page } from '@/shared/lib' 5 | import { SignInModal } from '@/widgets/sign-in-modal' 6 | 7 | const EditPage = () => { 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 | ) 15 | } 16 | 17 | export default EditPage 18 | -------------------------------------------------------------------------------- /apps/client/src/pages/main/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Main } from './ui/main' 2 | -------------------------------------------------------------------------------- /apps/client/src/pages/main/ui/main.tsx: -------------------------------------------------------------------------------- 1 | import { RoutePaths } from '@code-gear/web/shared' 2 | import { Link } from 'react-router-dom' 3 | 4 | import { Page } from '@/shared/lib' 5 | 6 | const Main = () => { 7 | return ( 8 | 9 |
10 | Not Ready Yet. 11 | Link to Editor 12 |
13 |
14 | ) 15 | } 16 | 17 | export default Main 18 | -------------------------------------------------------------------------------- /apps/client/src/shared/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { useStore } from './useStore' 2 | -------------------------------------------------------------------------------- /apps/client/src/shared/hooks/useStore.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | 3 | import { RootStore } from '@/app' 4 | import { StoreContext } from '@/app' 5 | 6 | export const useStore = (name: T) => { 7 | return useContext(StoreContext)[name] 8 | } 9 | -------------------------------------------------------------------------------- /apps/client/src/shared/lib/components/page/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Page } from './page' 2 | -------------------------------------------------------------------------------- /apps/client/src/shared/lib/components/page/page.tsx: -------------------------------------------------------------------------------- 1 | import { ErrorBoundary } from '@code-gear/web/shared' 2 | import { WithChildren } from '@code-gear/web/shared' 3 | 4 | import AuthGuard from '@/shared/lib/components/page/auth-guard' 5 | 6 | const Page = ({ children }: WithChildren) => { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | 14 | export default Page 15 | -------------------------------------------------------------------------------- /apps/client/src/shared/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/page' 2 | -------------------------------------------------------------------------------- /apps/client/src/widgets/sign-in-modal/graphql/get-profile.query.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/react-hooks' 2 | import { ApolloOperation } from '@code-gear/web/shared' 3 | 4 | export const getProfileQuery: ApolloOperation = { 5 | gql: gql` 6 | query { 7 | getProfile { 8 | username 9 | avatarUrl 10 | } 11 | } 12 | `, 13 | method: 'getProfile' 14 | } 15 | -------------------------------------------------------------------------------- /apps/client/src/widgets/sign-in-modal/graphql/sign-in.mutation.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/react-hooks' 2 | import { ApolloOperation } from '@code-gear/web/shared' 3 | 4 | export const SignInMutation: ApolloOperation = { 5 | gql: gql` 6 | mutation SignIn($payload: SignIn!) { 7 | signIn(_graphql: $payload) { 8 | accessToken 9 | } 10 | } 11 | `, 12 | method: 'signIn' 13 | } 14 | -------------------------------------------------------------------------------- /apps/client/src/widgets/sign-in-modal/index.ts: -------------------------------------------------------------------------------- 1 | export { AuthStore } from './store/auth.store' 2 | export { default as SignInModal } from './ui/sign-in-modal' 3 | -------------------------------------------------------------------------------- /apps/client/src/widgets/sign-in-modal/lib/exceptions.ts: -------------------------------------------------------------------------------- 1 | export const WrongPassword = 'You entered the wrong password.' 2 | -------------------------------------------------------------------------------- /apps/client/src/widgets/sign-in-modal/store/auth.store.ts: -------------------------------------------------------------------------------- 1 | import { makeAutoObservable } from 'mobx' 2 | 3 | import { AuthServices } from './auth.services' 4 | 5 | export class AuthStore { 6 | username: string 7 | isAuthorized: boolean 8 | readonly services: AuthServices 9 | 10 | constructor() { 11 | makeAutoObservable(this) 12 | 13 | this.services = new AuthServices(this) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /apps/client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "cg-config/src/tsconfig/paths/second-layer.json", 3 | "compilerOptions": { 4 | "target": "ESNext", 5 | "module": "ESNext", 6 | "moduleResolution": "node", 7 | "allowSyntheticDefaultImports": true, 8 | "esModuleInterop": true, 9 | "jsx": "preserve", 10 | "jsxFactory": "h", 11 | "jsxFragmentFactory": "Fragment", 12 | "jsxImportSource": "preact", 13 | "types": ["vite/client", "vitest"], 14 | "strictNullChecks": true 15 | }, 16 | "files": [], 17 | "include": [], 18 | "references": [ 19 | { 20 | "path": "./tsconfig.app.json" 21 | }, 22 | { 23 | "path": "./tsconfig.spec.json" 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /apps/client/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node"] 6 | }, 7 | "include": [ 8 | "vite.config.ts", 9 | "src/**/*.test.ts", 10 | "src/**/*.spec.ts", 11 | "src/**/*.test.tsx", 12 | "src/**/*.spec.tsx", 13 | "src/**/*.test.js", 14 | "src/**/*.spec.js", 15 | "src/**/*.test.jsx", 16 | "src/**/*.spec.jsx", 17 | "src/**/*.d.ts" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /apps/docs/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['../../.eslintrc.js'], 3 | ignorePatterns: ['!**/*', '.vitepress/cache', 'node_modules'] 4 | } 5 | -------------------------------------------------------------------------------- /apps/docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | import { h } from 'vue' 2 | import Theme from 'vitepress/theme' 3 | import './style.css' 4 | 5 | if (typeof localStorage !== 'undefined') { 6 | localStorage.setItem('vitepress-theme-appearance', 'dark') 7 | } 8 | 9 | export default { 10 | extends: Theme, 11 | Layout: () => { 12 | return h(Theme.Layout, null, {}) 13 | }, 14 | enhanceApp({ app, router, siteData }) {} 15 | } 16 | -------------------------------------------------------------------------------- /apps/docs/ending/further-development.md: -------------------------------------------------------------------------------- 1 | # Further Development 2 | 3 | I'm not sure that the project will develop in the future. 4 | 5 | The main goal of the project was to try a bunch of technologies and make it work. 6 | And overall, I succeeded. 7 | 8 | In general, I planned to add more things, such as [Ansible](https://www.ansible.com/), 9 | deployment to AWS, [docker-swarm](https://habr.com/ru/articles/659813/). 10 | I also planned to cover everything with [tests](./../features/testing) 11 | as well, try DDD, make a cool landing page with framer-motion and 12 | [threejs](https://github.com/mrdoob/three.js) (currently actively studying). 13 | 14 | And maybe in the future I will do this. I stopped working on the project as it became 15 | more of a chore than learning something new. 16 | 17 | If you liked it, don't forget to star it on [github](https://github.com/Gearonix/code-gear). 18 | 19 | *Bye 8)* 20 | -------------------------------------------------------------------------------- /apps/docs/other-concepts/authorization.md: -------------------------------------------------------------------------------- 1 | # Authorization 2 | 3 | The project has a regular JWT authorization via [passport.js](https://github.com/jaredhanson/passport). 4 | Plus, refresh tokens and access token expiry have been added. 5 | 6 | There is nothing unusual here, I would like to add that it was more difficult 7 | to do authorization with passport than to create it from scratch. lmao. 8 | 9 | You can look at it in the `auth` microservice. 10 | -------------------------------------------------------------------------------- /apps/docs/other-concepts/frontend-business-logic.md: -------------------------------------------------------------------------------- 1 | # Frontend Business Logic 2 | 3 | In the project I use [MobX](https://mobx.js.org/installation.html) for the state manager. 4 | 5 | ## Division into services 6 | 7 | I divide mobx stores into 4 categories. 8 | 9 | - cats.`actions`.ts - state mutations 10 | - cats.`getters`.ts - state getters 11 | - cats.`services`.ts - anchyronous state mutations 12 | - cats.`store`.ts - a module that combines everything and adds the state itself 13 | 14 | ::: tip Examples 15 | 16 | Examples of usage can be found in the `web/editor` library 17 | 18 | ::: 19 | 20 | ## Root Store 21 | 22 | Even though Mobx provides options for separating stores (and which I use), I still use one root store. 23 | 24 | 25 | ::: tip Global Store 26 | 27 | The global store can be found in the `client` application 28 | 29 | ::: 30 | -------------------------------------------------------------------------------- /apps/docs/other-concepts/testing.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | Unfortunately, at the moment the project is not covered by testing (only `storybook` test-runner). 4 | If I continue to develop it, then it will be covered with testing. 5 | 6 | In general, I planned to do 5 types of tests: 7 | 8 | - Unit testing with [Vitest](https://vitest.dev/) ❌ 9 | - RTL tests (Integration and Unit testing) ❌ 10 | - e2e tests with [Cypress](https://www.cypress.io/) or [Playwright](https://playwright.dev/) [frontend] ❌ 11 | - e2e tests with supertest [backend] ❌ 12 | - storybook tests (storybook-test-runner) ✅ 13 | 14 | --- 15 | 16 | I wanted to try these technologies and test some components at the end of the project. 17 | But somehow it didn’t work out. ( ͡° ͜ʖ ͡°) 18 | -------------------------------------------------------------------------------- /apps/docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cg-docs" 3 | } 4 | -------------------------------------------------------------------------------- /apps/docs/public/logo-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearonix/code-gear/428293078745619b14bce932d30b9b73e5cce08c/apps/docs/public/logo-large.png -------------------------------------------------------------------------------- /apps/docs/public/overview/functionality-color-picker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearonix/code-gear/428293078745619b14bce932d30b9b73e5cce08c/apps/docs/public/overview/functionality-color-picker.png -------------------------------------------------------------------------------- /apps/docs/public/overview/functionality-ending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearonix/code-gear/428293078745619b14bce932d30b9b73e5cce08c/apps/docs/public/overview/functionality-ending.png -------------------------------------------------------------------------------- /apps/docs/public/overview/functionality-html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearonix/code-gear/428293078745619b14bce932d30b9b73e5cce08c/apps/docs/public/overview/functionality-html.png -------------------------------------------------------------------------------- /apps/docs/public/overview/functionality-intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearonix/code-gear/428293078745619b14bce932d30b9b73e5cce08c/apps/docs/public/overview/functionality-intro.png -------------------------------------------------------------------------------- /apps/docs/public/overview/functionality-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearonix/code-gear/428293078745619b14bce932d30b9b73e5cce08c/apps/docs/public/overview/functionality-login.png -------------------------------------------------------------------------------- /apps/docs/scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script should work only at the root of the project. 4 | 5 | source .local.env 6 | 7 | echo -e "deploy.sh" 8 | echo -e "BEGET_HOST: $BEGET_HOST" 9 | echo -e "WEBSITE_FOLDER: $WEBSITE_FOLDER" 10 | 11 | cd dist/docs 12 | 13 | zip -r _dist.zip . 14 | 15 | scp _dist.zip "$BEGET_HOST":~/"$WEBSITE_FOLDER"/public_html/code-gear/docs 16 | 17 | rm _dist.zip 18 | 19 | ssh "$BEGET_HOST" << EOF 20 | cd ~/$WEBSITE_FOLDER/public_html/code-gear/docs 21 | unzip -o _dist.zip && rm _dist.zip 22 | 23 | echo -e "[success] docs updated." 24 | EOF 25 | 26 | -------------------------------------------------------------------------------- /apps/docs/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | 3 | export default defineConfig({ 4 | server: { 5 | port: 4080 6 | } 7 | }) 8 | -------------------------------------------------------------------------------- /apps/server/gateway/.config/jest.ts: -------------------------------------------------------------------------------- 1 | import { createJestConfig } from 'cg-config/src/jest' 2 | 3 | export default createJestConfig({ 4 | displayName: 'server-gateway', 5 | layer: 'second' 6 | }) 7 | -------------------------------------------------------------------------------- /apps/server/gateway/.config/webpack.ts: -------------------------------------------------------------------------------- 1 | const { buildWebpackConfig } = require('cg-config/src/webpack') 2 | const { resolve } = require('path') 3 | 4 | module.exports = buildWebpackConfig({ 5 | rootDir: resolve(__dirname, '..'), 6 | layer: 'third' 7 | }) 8 | -------------------------------------------------------------------------------- /apps/server/gateway/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../../.eslintrc.js"], 3 | "ignorePatterns": ["!**/*"] 4 | } 5 | -------------------------------------------------------------------------------- /apps/server/gateway/.gitignore: -------------------------------------------------------------------------------- 1 | _schema.gql 2 | -------------------------------------------------------------------------------- /apps/server/gateway/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM --platform=linux/amd64 node:20.8.0-alpine as build 2 | WORKDIR /opt/app 3 | 4 | ## Installing dependencies ## 5 | 6 | COPY package.json yarn.lock .yarnrc.yml ./ 7 | COPY .yarn .yarn 8 | 9 | COPY packages/config/package.json packages/config/package.json 10 | 11 | RUN yarn install 12 | 13 | ## Copying source code ## 14 | 15 | COPY apps/server/gateway apps/server/gateway 16 | 17 | COPY packages packages 18 | 19 | RUN yarn install 20 | 21 | COPY . . 22 | 23 | ## Building app to produciton ## 24 | 25 | RUN yarn nx run gateway:build 26 | 27 | ## Entrypoint ## 28 | 29 | FROM --platform=linux/amd64 node:20.8.0-alpine 30 | WORKDIR /opt/app 31 | 32 | COPY --from=build /opt/app/dist/apps/server/gateway ./ 33 | 34 | RUN sed -i '/workspace:/d' package.json 35 | 36 | RUN npm install --omit="dev" --force 37 | 38 | RUN npx prisma generate 39 | 40 | ENTRYPOINT node ./main.js 41 | -------------------------------------------------------------------------------- /apps/server/gateway/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cg-server-gateway", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "cg-api-common": "workspace:^", 6 | "cg-api-contracts": "workspace:^" 7 | }, 8 | "devDependencies": { 9 | "cg-config": "workspace:^" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /apps/server/gateway/prisma/.gitignore: -------------------------------------------------------------------------------- 1 | migrations 2 | schema.prisma 3 | -------------------------------------------------------------------------------- /apps/server/gateway/prisma/concat-prisma-files.js: -------------------------------------------------------------------------------- 1 | const concat = require('concat-files') 2 | const path = require('path') 3 | 4 | const resolvePrisma = (...args) => path.join('prisma', ...args) 5 | 6 | const concatPrismaFiles = ({ config, models, dest }) => { 7 | concat( 8 | [ 9 | resolvePrisma('config', config), 10 | ...models.map((model) => resolvePrisma('models', `${model}.prisma`)) 11 | ], 12 | resolvePrisma(dest), 13 | (error) => { 14 | if (error) { 15 | throw error 16 | } 17 | 18 | console.log('Prisma files merged.') 19 | } 20 | ) 21 | } 22 | 23 | concatPrismaFiles({ 24 | config: 'base.prisma', 25 | models: ['users'], 26 | dest: 'schema.prisma' 27 | }) 28 | -------------------------------------------------------------------------------- /apps/server/gateway/prisma/config/base.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | } 4 | 5 | datasource database { 6 | provider = "mysql" 7 | url = env("DATABASE_URL") 8 | } 9 | -------------------------------------------------------------------------------- /apps/server/gateway/prisma/models/users.prisma: -------------------------------------------------------------------------------- 1 | // Users model 2 | 3 | model User { 4 | username String @id @database.VarChar(14) 5 | password String @database.VarChar(150) 6 | avatarUrl String? @database.VarChar(100) 7 | } 8 | -------------------------------------------------------------------------------- /apps/server/gateway/src/config/cors.ts: -------------------------------------------------------------------------------- 1 | import { clientUrl } from '@code-gear/config' 2 | import { CorsOptions } from '@nestjs/common/interfaces/external/cors-options.interface' 3 | 4 | export const corsConfig: CorsOptions = { 5 | origin: clientUrl, 6 | methods: ['POST', 'PUT', 'DELETE', 'GET'], 7 | credentials: true 8 | } 9 | -------------------------------------------------------------------------------- /apps/server/gateway/src/config/swagger.ts: -------------------------------------------------------------------------------- 1 | import { serverAppName } from '@code-gear/config' 2 | import { DocumentBuilder } from '@nestjs/swagger' 3 | import { OpenAPIObject } from '@nestjs/swagger' 4 | import { SwaggerModule } from '@nestjs/swagger' 5 | 6 | export const createSwaggerDocs = (app): OpenAPIObject => { 7 | const swagger = new DocumentBuilder() 8 | .setTitle(serverAppName) 9 | .setDescription('REST API documentation') 10 | .setVersion('1.0.0') 11 | .build() 12 | 13 | return SwaggerModule.createDocument(app, swagger) 14 | } 15 | -------------------------------------------------------------------------------- /apps/server/gateway/src/core/auth/auth.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common' 2 | 3 | import { AuthResolver } from './auth.resolver' 4 | import { KafkaModule } from '@code-gear/api/common' 5 | import { Microservice } from '@code-gear/api/common' 6 | 7 | @Module({ 8 | controllers: [], 9 | providers: [AuthResolver], 10 | imports: [KafkaModule.forRoot(Microservice.AUTH)], 11 | exports: [] 12 | }) 13 | export class AuthModule {} 14 | -------------------------------------------------------------------------------- /apps/server/gateway/src/core/code-executor/code-executor.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common' 2 | 3 | import { CodeExecutorController } from './code-executor.controller' 4 | import { KafkaModule } from '@code-gear/api/common' 5 | import { Microservice } from '@code-gear/api/common' 6 | 7 | @Module({ 8 | imports: [KafkaModule.forRoot(Microservice.CODE_EXECUTOR)], 9 | controllers: [CodeExecutorController], 10 | providers: [] 11 | }) 12 | export class CodeExecutorModule {} 13 | -------------------------------------------------------------------------------- /apps/server/gateway/src/core/code-executor/index.ts: -------------------------------------------------------------------------------- 1 | export { CodeExecutorModule } from './code-executor.module' 2 | -------------------------------------------------------------------------------- /apps/server/gateway/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["node"], 7 | "emitDecoratorMetadata": true, 8 | "target": "es2021", 9 | "baseUrl": "." 10 | }, 11 | "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"], 12 | "include": ["src/**/*.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /apps/server/gateway/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "cg-config/src/tsconfig/paths/third-layer.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.app.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "esModuleInterop": true, 15 | "resolveJsonModule": true, 16 | "strictNullChecks": true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /apps/server/gateway/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "src/**/*.test.ts", 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /apps/server/service-auth/.config/jest.ts: -------------------------------------------------------------------------------- 1 | import { createJestConfig } from 'cg-config/src/jest' 2 | 3 | export default createJestConfig({ 4 | displayName: 'service-auth', 5 | layer: 'second', 6 | }) 7 | -------------------------------------------------------------------------------- /apps/server/service-auth/.config/webpack.ts: -------------------------------------------------------------------------------- 1 | const { buildWebpackConfig } = require('cg-config/src/webpack') 2 | const { resolve } = require('path') 3 | 4 | module.exports = buildWebpackConfig({ 5 | rootDir: resolve(__dirname, '..'), 6 | layer: 'third', 7 | }) 8 | -------------------------------------------------------------------------------- /apps/server/service-auth/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['../../../.eslintrc.js'], 3 | ignorePatterns: ['!**/*'], 4 | } 5 | -------------------------------------------------------------------------------- /apps/server/service-auth/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM --platform=linux/amd64 node:20.8.0-alpine as build 2 | WORKDIR /opt/app 3 | 4 | ## Installing dependencies ## 5 | 6 | COPY package.json yarn.lock .yarnrc.yml ./ 7 | COPY .yarn .yarn 8 | 9 | COPY packages/config/package.json packages/config/package.json 10 | 11 | RUN yarn install 12 | 13 | ## Copying source code ## 14 | 15 | COPY apps/server/service-auth apps/server/service-auth 16 | 17 | COPY packages packages 18 | 19 | RUN yarn install 20 | 21 | COPY . . 22 | 23 | ## Building app to produciton ## 24 | 25 | RUN yarn nx run service-auth:build 26 | 27 | ## Entrypoint ## 28 | 29 | FROM --platform=linux/amd64 node:20.8.0-alpine 30 | WORKDIR /opt/app 31 | 32 | COPY --from=build /opt/app/dist/apps/server/service-auth ./ 33 | 34 | RUN sed -i '/workspace:/d' package.json 35 | 36 | RUN npm install --omit="dev" --force 37 | 38 | ENTRYPOINT node ./main.js 39 | -------------------------------------------------------------------------------- /apps/server/service-auth/README.md: -------------------------------------------------------------------------------- 1 | ## auth microservice 2 | 3 | generated by `tools/cg-global-generator` 4 | -------------------------------------------------------------------------------- /apps/server/service-auth/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cg-service-auth", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "cg-api-common": "workspace:^", 6 | "cg-api-contracts": "workspace:^" 7 | }, 8 | "devDependencies": { 9 | "cg-config": "workspace:^" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /apps/server/service-auth/src/auth.consumer.ts: -------------------------------------------------------------------------------- 1 | import { Controller } from '@nestjs/common' 2 | import { QueryBus } from '@nestjs/cqrs' 3 | import { User } from '@code-gear/api/common' 4 | import { MessagePattern } from '@nestjs/microservices' 5 | import { Payload } from '@nestjs/microservices' 6 | import { AccessTokenResponse } from '@code-gear/api/contracts' 7 | import { AuthTopic } from '@code-gear/api/contracts' 8 | import { AuthService } from './auth.service' 9 | 10 | @Controller() 11 | export class AuthConsumer { 12 | constructor( 13 | private readonly query: QueryBus, 14 | private readonly authService: AuthService 15 | ) {} 16 | 17 | @MessagePattern(AuthTopic.SIGN_IN) 18 | async signIn(@Payload() user: User): Promise { 19 | return this.authService.generateToken(user.username) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /apps/server/service-auth/src/lib/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearonix/code-gear/428293078745619b14bce932d30b9b73e5cce08c/apps/server/service-auth/src/lib/index.ts -------------------------------------------------------------------------------- /apps/server/service-auth/src/lib/types.ts: -------------------------------------------------------------------------------- 1 | import { UserResponse } from './responses' 2 | 3 | export type JwtTokenPayload = Pick 4 | -------------------------------------------------------------------------------- /apps/server/service-auth/src/repository/accounts.repository.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common' 2 | 3 | import { DatabaseService } from '@code-gear/api/common' 4 | import { User } from '@code-gear/api/common' 5 | import { SignIn } from '@code-gear/api/contracts' 6 | 7 | @Injectable() 8 | export class AccountsRepository { 9 | constructor(private prisma: DatabaseService) {} 10 | 11 | public getUserByUsername(username: string): User { 12 | return this.prisma.user.findUnique({ 13 | where: { 14 | username 15 | } 16 | }) 17 | } 18 | 19 | public createUser(user: SignIn): User { 20 | return this.prisma.user.create({ 21 | data: user 22 | }) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /apps/server/service-auth/src/strategies/jwt.strategy.ts: -------------------------------------------------------------------------------- 1 | import { jwtSecret } from '@code-gear/config' 2 | import { Injectable } from '@nestjs/common' 3 | import { PassportStrategy } from '@nestjs/passport' 4 | import { ExtractJwt } from 'passport-jwt' 5 | import { Strategy } from 'passport-jwt' 6 | 7 | import { JwtTokenPayload } from '../lib/types' 8 | import { AccountsRepository } from '@/repository/accounts.repository' 9 | 10 | @Injectable() 11 | export class JwtStrategy extends PassportStrategy(Strategy) { 12 | constructor(private readonly usersService: AccountsRepository) { 13 | super({ 14 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), 15 | ignoreExpiration: false, 16 | secretOrKey: jwtSecret 17 | }) 18 | } 19 | 20 | validate(payload: JwtTokenPayload) { 21 | return this.usersService.getUserByUsername(payload.username) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /apps/server/service-auth/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["node"], 7 | "emitDecoratorMetadata": true, 8 | "target": "es2021", 9 | "baseUrl": "." 10 | }, 11 | "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"], 12 | "include": ["src/**/*.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /apps/server/service-auth/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "cg-config/src/tsconfig/paths/third-layer.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.app.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "esModuleInterop": true, 15 | "resolveJsonModule": true, 16 | "strictNullChecks": true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /apps/server/service-auth/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "src/**/*.test.ts", 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /apps/server/service-code-executor/.config/jest.ts: -------------------------------------------------------------------------------- 1 | import { createJestConfig } from 'cg-config/src/jest' 2 | 3 | export default createJestConfig({ 4 | displayName: 'service-code-executor', 5 | layer: 'second' 6 | }) 7 | -------------------------------------------------------------------------------- /apps/server/service-code-executor/.config/webpack.ts: -------------------------------------------------------------------------------- 1 | const { buildWebpackConfig } = require('cg-config/src/webpack') 2 | const { resolve } = require('path') 3 | 4 | module.exports = buildWebpackConfig({ 5 | rootDir: resolve(__dirname, '..'), 6 | layer: 'third' 7 | }) 8 | -------------------------------------------------------------------------------- /apps/server/service-code-executor/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../../.eslintrc.js"], 3 | "ignorePatterns": ["!**/*"] 4 | } 5 | -------------------------------------------------------------------------------- /apps/server/service-code-executor/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM --platform=linux/amd64 node:20.8.0-alpine as build 2 | WORKDIR /opt/app 3 | 4 | ## Installing dependencies ## 5 | 6 | COPY package.json yarn.lock .yarnrc.yml ./ 7 | COPY .yarn .yarn 8 | 9 | COPY packages/config/package.json packages/config/package.json 10 | 11 | RUN yarn install 12 | 13 | ## Copying source code ## 14 | 15 | COPY apps/server/service-code-executor apps/server/service-code-executor 16 | 17 | COPY packages packages 18 | 19 | RUN yarn install 20 | 21 | COPY . . 22 | 23 | ## Building app to produciton ## 24 | 25 | RUN yarn nx run service-code-executor:build 26 | 27 | ## Entrypoint ## 28 | 29 | FROM --platform=linux/amd64 node:20.8.0-alpine 30 | WORKDIR /opt/app 31 | 32 | COPY --from=build /opt/app/dist/apps/server/service-code-executor ./ 33 | 34 | RUN sed -i '/workspace:/d' package.json 35 | 36 | RUN npm install --omit="dev" --force 37 | 38 | ENTRYPOINT node ./main.js 39 | -------------------------------------------------------------------------------- /apps/server/service-code-executor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cg-service-code-executor", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "cg-api-common": "workspace:^", 6 | "cg-api-contracts": "workspace:^" 7 | }, 8 | "devDependencies": { 9 | "cg-config": "workspace:^" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /apps/server/service-code-executor/src/code-executor.module.ts: -------------------------------------------------------------------------------- 1 | import { HttpModule } from '@nestjs/axios' 2 | import { Module } from '@nestjs/common' 3 | 4 | import { CodeExecutorConsumer } from './code-executor.consumer' 5 | import { EnvModule } from '@code-gear/api/common' 6 | import { ListenerModule } from '@code-gear/api/common' 7 | import { KafkaService } from '@code-gear/api/common' 8 | import { QueryHandlers } from '@/queries/handlers' 9 | import { CqrsModule } from '@nestjs/cqrs' 10 | 11 | @Module({ 12 | imports: [ 13 | HttpModule, 14 | EnvModule, 15 | CqrsModule, 16 | ListenerModule.forRoot({ 17 | isMicroservice: true 18 | }) 19 | ], 20 | providers: [KafkaService, ...QueryHandlers], 21 | controllers: [CodeExecutorConsumer], 22 | exports: [] 23 | }) 24 | export class CodeExecutorModule {} 25 | -------------------------------------------------------------------------------- /apps/server/service-code-executor/src/exceptions/failed-to-fetch.exception.ts: -------------------------------------------------------------------------------- 1 | import { RpcException } from '@nestjs/microservices' 2 | 3 | export class FailedToFetchException extends RpcException { 4 | constructor(status = 400) { 5 | super({ 6 | code: status, 7 | message: `Failed to get response from api.codex.jaagrav.in (${status}).` 8 | }) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/server/service-code-executor/src/exceptions/index.ts: -------------------------------------------------------------------------------- 1 | export { FailedToFetchException } from './failed-to-fetch.exception' 2 | -------------------------------------------------------------------------------- /apps/server/service-code-executor/src/lib/helpers/transform-language.ts: -------------------------------------------------------------------------------- 1 | import { ExecuteCodeApiDTO } from '@code-gear/api/common' 2 | import { ExecutorLanguages } from '@code-gear/api/common' 3 | import { ExecutorLanguagesValues } from '@code-gear/api/common' 4 | 5 | type TransformLanguage = Omit & { 6 | language: ExecutorLanguagesValues 7 | } 8 | 9 | export const transformLanguage = ( 10 | args: ExecuteCodeApiDTO 11 | ): TransformLanguage => { 12 | return { 13 | ...args, 14 | language: ExecutorLanguages[args.language] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /apps/server/service-code-executor/src/lib/type-guards.ts: -------------------------------------------------------------------------------- 1 | import { ExecutorApiResponse } from '@code-gear/api/common' 2 | import { ExecutorLanguagesValues } from '@code-gear/api/common' 3 | 4 | export const isExecutorApiResponse = ( 5 | res: unknown 6 | ): res is ExecutorApiResponse => { 7 | if (typeof res !== 'object' || res === null) { 8 | return false 9 | } 10 | 11 | if ( 12 | 'timeStamp' in res && 13 | typeof res.timeStamp === 'number' && 14 | 'output' in res && 15 | typeof res.output === 'string' && 16 | 'language' in res && 17 | typeof res.language === 'string' 18 | ) { 19 | return true 20 | } 21 | 22 | return false 23 | } 24 | -------------------------------------------------------------------------------- /apps/server/service-code-executor/src/queries/handlers/index.ts: -------------------------------------------------------------------------------- 1 | import { ExecuteCodeHandler } from './execute-code.handler' 2 | 3 | export const QueryHandlers = [ExecuteCodeHandler] 4 | -------------------------------------------------------------------------------- /apps/server/service-code-executor/src/queries/impl/execute-code.query.ts: -------------------------------------------------------------------------------- 1 | import { ExecuteCodeApiDTO } from '@code-gear/api/common' 2 | 3 | export class ExecuteCodeQuery { 4 | constructor(public readonly payload: ExecuteCodeApiDTO) {} 5 | } 6 | -------------------------------------------------------------------------------- /apps/server/service-code-executor/src/queries/impl/index.ts: -------------------------------------------------------------------------------- 1 | export * from './execute-code.query' 2 | -------------------------------------------------------------------------------- /apps/server/service-code-executor/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["node"], 7 | "emitDecoratorMetadata": true, 8 | "target": "es2021", 9 | "baseUrl": "." 10 | }, 11 | "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"], 12 | "include": ["src/**/*.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /apps/server/service-code-executor/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "cg-config/src/tsconfig/paths/third-layer.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.app.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "esModuleInterop": true, 15 | "resolveJsonModule": true, 16 | "strictNullChecks": true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /apps/server/service-code-executor/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "src/**/*.test.ts", 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | rules: { 4 | 'scope-case': [2, 'always', 'lower-case'], 5 | 'subject-case': [ 6 | 2, 7 | 'never', 8 | ['sentence-case', 'start-case', 'pascal-case'] 9 | ], 10 | 'subject-empty': [2, 'never'], 11 | 'subject-full-stop': [2, 'never', '.'], 12 | 'type-case': [2, 'always', 'lower-case'], 13 | 'type-empty': [2, 'never'], 14 | 'type-enum': [ 15 | 2, 16 | 'always', 17 | [ 18 | 'build', 19 | 'chore', 20 | 'ci', 21 | 'docs', 22 | 'feat', 23 | 'fix', 24 | 'refactor', 25 | 'style', 26 | 'test' 27 | ] 28 | ] 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import { getJestProjects } from '@nx/jest' 2 | 3 | export default { 4 | projects: getJestProjects(), 5 | } 6 | -------------------------------------------------------------------------------- /jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require('@nx/jest/preset').default 2 | 3 | module.exports = { ...nxPreset } 4 | -------------------------------------------------------------------------------- /packages/api/common/.config/jest.ts: -------------------------------------------------------------------------------- 1 | import { createJestConfig } from 'cg-config/src/jest' 2 | 3 | export default createJestConfig({ 4 | displayName: 'api-common', 5 | layer: 'third' 6 | }) 7 | -------------------------------------------------------------------------------- /packages/api/common/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "../../../.eslintrc.js" 4 | ], 5 | "ignorePatterns": [ 6 | "!**/*", 7 | "package.json", 8 | "jest.config.ts" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/api/common/README.md: -------------------------------------------------------------------------------- 1 | ## api-common 2 | 3 | Reusable modules for nestjs microservices. 4 | -------------------------------------------------------------------------------- /packages/api/common/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cg-api-common", 3 | "version": "1.0.0", 4 | "main": "./src/index.js", 5 | "devDependencies": { 6 | "cg-config": "workspace:^" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/api/common/src/consts/index.ts: -------------------------------------------------------------------------------- 1 | export { Microservice } from './microservices' 2 | -------------------------------------------------------------------------------- /packages/api/common/src/consts/microservices.ts: -------------------------------------------------------------------------------- 1 | export enum Microservice { 2 | CODE_EXECUTOR = 'codeExecutor', 3 | AUTH = 'auth' 4 | } 5 | -------------------------------------------------------------------------------- /packages/api/common/src/decorators/index.ts: -------------------------------------------------------------------------------- 1 | export { StringField } from './string-field.decorator' 2 | export { WithUser } from './user.decorator' 3 | -------------------------------------------------------------------------------- /packages/api/common/src/decorators/string-field.decorator.ts: -------------------------------------------------------------------------------- 1 | import { applyDecorators } from '@nestjs/common' 2 | import { Field } from '@nestjs/graphql' 3 | import { ApiProperty } from '@nestjs/swagger' 4 | import { IsString } from 'class-validator' 5 | import { MaxLength } from 'class-validator' 6 | import { MinLength } from 'class-validator' 7 | 8 | type StringFieldPayload = Partial<{ 9 | min: number 10 | max: number 11 | example: string 12 | }> 13 | 14 | export const StringField = ({ 15 | min = 6, 16 | max = 14, 17 | example 18 | }: StringFieldPayload) => { 19 | return applyDecorators( 20 | Field(), 21 | IsString(), 22 | MinLength(min), 23 | MaxLength(max), 24 | ApiProperty({ example }) 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /packages/api/common/src/decorators/user.decorator.ts: -------------------------------------------------------------------------------- 1 | import { createParamDecorator } from '@nestjs/common' 2 | import { ExecutionContext } from '@nestjs/common' 3 | import { GqlExecutionContext } from '@nestjs/graphql' 4 | 5 | import { User } from '@/types/_prisma' 6 | 7 | export const WithUser = createParamDecorator(( 8 | data: unknown, 9 | context: ExecutionContext 10 | ): User => { 11 | const ctx = GqlExecutionContext.create(context) 12 | return ctx.getContext().req.user 13 | }) 14 | -------------------------------------------------------------------------------- /packages/api/common/src/exception-filters/http-exception.filter.ts: -------------------------------------------------------------------------------- 1 | import { ArgumentsHost } from '@nestjs/common' 2 | import { Catch } from '@nestjs/common' 3 | import { ExceptionFilter } from '@nestjs/common' 4 | import { HttpException } from '@nestjs/common' 5 | import { Request } from 'express' 6 | import { Response } from 'express' 7 | 8 | @Catch(HttpException) 9 | export class HttpExceptionFilter implements ExceptionFilter { 10 | catch(exception: HttpException, host: ArgumentsHost) { 11 | const ctx = host.switchToHttp() 12 | const response = ctx.getResponse() 13 | const request = ctx.getRequest() 14 | const status = exception.getStatus() 15 | 16 | response.status(status).json({ 17 | statusCode: status, 18 | timestamp: new Date().toISOString(), 19 | path: request.url, 20 | message: exception.message 21 | }) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/api/common/src/exception-filters/index.ts: -------------------------------------------------------------------------------- 1 | export { HttpExceptionFilter } from './http-exception.filter' 2 | export { RpcExceptionFilter } from './rpc-exception.filter' 3 | -------------------------------------------------------------------------------- /packages/api/common/src/guards/gql-auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { graphqlArg } from '@code-gear/config' 2 | import { ExecutionContext } from '@nestjs/common' 3 | import { GqlExecutionContext } from '@nestjs/graphql' 4 | import { AuthGuard } from '@nestjs/passport' 5 | 6 | export class GqlAuthGuard extends AuthGuard('local') { 7 | // eslint-disable-next-line @typescript-eslint/no-useless-constructor 8 | constructor() { 9 | super() 10 | } 11 | 12 | getRequest(context: ExecutionContext) { 13 | const ctx = GqlExecutionContext.create(context) 14 | const gqlReq = ctx.getContext().req 15 | gqlReq.body = ctx.getArgs()[graphqlArg] 16 | 17 | return gqlReq 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/api/common/src/guards/gql-local-auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { ExecutionContext } from '@nestjs/common' 2 | import { Injectable } from '@nestjs/common' 3 | import { GqlExecutionContext } from '@nestjs/graphql' 4 | import { AuthGuard } from '@nestjs/passport' 5 | 6 | @Injectable() 7 | export class GqlLocalAuthGuard extends AuthGuard('local') { 8 | async canActivate(context: ExecutionContext): Promise { 9 | const ctxRequest = GqlExecutionContext.create(context).getContext().req 10 | return Boolean(ctxRequest) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/api/common/src/guards/index.ts: -------------------------------------------------------------------------------- 1 | export { GqlAuthGuard } from './gql-auth.guard' 2 | export { GqlLocalAuthGuard } from './gql-local-auth.guard' 3 | export { JwtAuthGuard } from './jwt-auth.guard' 4 | -------------------------------------------------------------------------------- /packages/api/common/src/guards/jwt-auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { ExecutionContext } from '@nestjs/common' 2 | import { GqlExecutionContext } from '@nestjs/graphql' 3 | import { AuthGuard } from '@nestjs/passport' 4 | 5 | export class JwtAuthGuard extends AuthGuard('jwt') { 6 | getRequest(context: ExecutionContext) { 7 | const ctx = GqlExecutionContext.create(context) 8 | return ctx.getContext().req 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/api/common/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './decorators' 2 | export * from './exception-filters' 3 | export * from './guards' 4 | export * from './pipes' 5 | export * from './types/_prisma' 6 | export * from './modules' 7 | export * from './consts' 8 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/database/database.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common' 2 | 3 | import { DatabaseService } from './database.service' 4 | 5 | @Module({ 6 | providers: [DatabaseService], 7 | exports: [DatabaseService] 8 | }) 9 | export class DatabaseModule {} 10 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/database/database.service.ts: -------------------------------------------------------------------------------- 1 | import { INestApplication } from '@nestjs/common' 2 | import { Injectable } from '@nestjs/common' 3 | import { OnModuleInit } from '@nestjs/common' 4 | import { PrismaClient } from '@prisma/client' 5 | 6 | @Injectable() 7 | export class DatabaseService extends PrismaClient implements OnModuleInit { 8 | async onModuleInit() { 9 | await this.$connect() 10 | } 11 | 12 | async enableShutdownHooks(app: INestApplication) { 13 | this.$on('beforeExit', async () => { 14 | await app.close() 15 | }) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/database/index.ts: -------------------------------------------------------------------------------- 1 | export { DatabaseModule } from './database.module' 2 | export { DatabaseService } from './database.service' 3 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/env/conf/database.config.ts: -------------------------------------------------------------------------------- 1 | import { registerAs } from '@nestjs/config' 2 | import { Env } from '../env.decorator' 3 | import { validateConfig } from '../../../utils/validators' 4 | 5 | class DatabaseValidator { 6 | @Env() 7 | DATABASE_URL: string 8 | } 9 | 10 | export interface DatabaseConfig { 11 | url: string 12 | } 13 | 14 | export const database = registerAs('database', () => { 15 | const conf = validateConfig(process.env, DatabaseValidator) 16 | 17 | return { 18 | url: conf.DATABASE_URL 19 | } 20 | }) 21 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/env/conf/index.ts: -------------------------------------------------------------------------------- 1 | export { misc } from './misc.config' 2 | export { database } from './database.config' 3 | export { server } from './server.config' 4 | export { kafka } from './kafka.config' 5 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/env/conf/misc.config.ts: -------------------------------------------------------------------------------- 1 | import { validateConfig } from '../../../utils/validators' 2 | import { registerAs } from '@nestjs/config' 3 | import { Env } from '../env.decorator' 4 | import { MiscConfig } from '../types' 5 | 6 | class MiscValidator { 7 | @Env() 8 | CODE_COMPILER_API_URL: string 9 | 10 | @Env() 11 | JWT_SECRET: string 12 | 13 | @Env() 14 | CLIENT_URL: string 15 | } 16 | 17 | export const misc = registerAs('misc', () => { 18 | const conf = validateConfig(process.env, MiscValidator) 19 | 20 | return { 21 | clientUrl: conf.CLIENT_URL, 22 | jwtSecret: conf.JWT_SECRET, 23 | codeExecutorUrl: conf.CODE_COMPILER_API_URL 24 | } 25 | }) 26 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/env/conf/server.config.ts: -------------------------------------------------------------------------------- 1 | import { IsNotEmpty } from 'class-validator' 2 | import { IsString } from 'class-validator' 3 | import { IsNumberString } from 'class-validator' 4 | import { validateConfig } from '../../../utils/validators' 5 | import { registerAs } from '@nestjs/config' 6 | import { Env } from '../env.decorator' 7 | import { ServerConfig } from '../types' 8 | 9 | class ServerValidator { 10 | @IsNumberString() 11 | @IsNotEmpty() 12 | SERVER_PORT: string 13 | 14 | @IsString() 15 | SERVER_PREFIX: string 16 | 17 | @Env() 18 | SERVER_URL: string 19 | } 20 | 21 | export const server = registerAs('server', () => { 22 | const conf = validateConfig(process.env, ServerValidator) 23 | 24 | return { 25 | prefix: conf.SERVER_PREFIX, 26 | port: Number(conf.SERVER_PORT), 27 | url: conf.SERVER_URL 28 | } 29 | }) 30 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/env/env.decorator.ts: -------------------------------------------------------------------------------- 1 | import { applyDecorators } from '@nestjs/common' 2 | import { IsNotEmpty } from 'class-validator' 3 | import { IsString } from 'class-validator' 4 | 5 | export const Env = () => { 6 | return applyDecorators(IsString(), IsNotEmpty()) 7 | } 8 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/env/env.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common' 2 | import { ConfigModule } from '@nestjs/config' 3 | import { database } from './conf' 4 | import { kafka } from './conf' 5 | import { misc } from './conf' 6 | import { server } from './conf' 7 | 8 | @Module({ 9 | imports: [ 10 | ConfigModule.forRoot({ 11 | load: [server, misc, database, kafka], 12 | isGlobal: true 13 | }) 14 | ] 15 | }) 16 | export class EnvModule {} 17 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/env/index.ts: -------------------------------------------------------------------------------- 1 | export { EnvModule } from './env.module' 2 | 3 | export { ServerConfig, MiscConfig, KafkaConfig, DatabaseConfig } from './types' 4 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/env/types/enviroment.interfaces.ts: -------------------------------------------------------------------------------- 1 | export interface DatabaseConfig { 2 | url: string 3 | } 4 | 5 | export interface KafkaConfig { 6 | brokers: string[] 7 | microservices: Record 8 | heartbeatInterval: number 9 | sessionTimeout: number 10 | } 11 | 12 | export interface MiscConfig { 13 | clientUrl: string 14 | jwtSecret: string 15 | codeExecutorUrl: string 16 | } 17 | 18 | export interface ServerConfig { 19 | prefix: string 20 | port: number 21 | url: string 22 | } 23 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/env/types/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | ServerConfig, 3 | MiscConfig, 4 | KafkaConfig, 5 | DatabaseConfig 6 | } from './enviroment.interfaces' 7 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/index.ts: -------------------------------------------------------------------------------- 1 | export * from './kafka' 2 | export * from './env' 3 | export * from './database' 4 | export * from './listener' 5 | export * from './jwt' 6 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/jwt/index.ts: -------------------------------------------------------------------------------- 1 | export { JwtModule } from './jwt.module' 2 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/jwt/jwt.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common' 2 | import { JwtModule as NestJwtModule } from '@nestjs/jwt' 3 | import { JwtService } from '@nestjs/jwt' 4 | import { jwtSecret } from '@code-gear/config' 5 | 6 | @Module({ 7 | imports: [ 8 | NestJwtModule.register({ 9 | secret: jwtSecret, 10 | signOptions: { 11 | expiresIn: '24h' 12 | } 13 | }) 14 | ], 15 | exports: [NestJwtModule] 16 | }) 17 | export class JwtModule {} 18 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/kafka/index.ts: -------------------------------------------------------------------------------- 1 | export { KafkaModule } from './kafka.module' 2 | export { KafkaService } from './kafka.service' 3 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/kafka/kafka.interface.ts: -------------------------------------------------------------------------------- 1 | import { KafkaOptions } from '@nestjs/microservices' 2 | import { Microservice } from '../../consts' 3 | 4 | export interface GetKafkaOptions { 5 | getKafkaOptions: (service: Microservice) => KafkaOptions 6 | } 7 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/listener/index.ts: -------------------------------------------------------------------------------- 1 | export { ListenerModule } from './listener.module' 2 | export { ListenerService } from './listener.service' 3 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/listener/listener.consts.ts: -------------------------------------------------------------------------------- 1 | export const NESTJS_FREE_PORT = 0 as const 2 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/listener/listener.interfaces.ts: -------------------------------------------------------------------------------- 1 | export interface ListenerModuleOptions { 2 | isMicroservice: boolean 3 | } 4 | 5 | export interface ListenerConfig { 6 | isMicroservice: boolean 7 | port: number 8 | } 9 | -------------------------------------------------------------------------------- /packages/api/common/src/modules/listener/listener.service.ts: -------------------------------------------------------------------------------- 1 | import { Inject } from '@nestjs/common' 2 | import { Injectable } from '@nestjs/common' 3 | import { ListenerConfig } from './listener.interfaces' 4 | 5 | @Injectable() 6 | export class ListenerService { 7 | private readonly isMicroservice: boolean 8 | private readonly port: number 9 | 10 | constructor( 11 | @Inject('ListenerServiceConfig') 12 | private readonly config: ListenerConfig 13 | ) { 14 | this.isMicroservice = config.isMicroservice 15 | this.port = config.port 16 | } 17 | 18 | getListenerCallback() { 19 | return () => { 20 | console.log('Server is running on port', this.port) 21 | } 22 | } 23 | 24 | get PORT() { 25 | return this.port 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/api/common/src/pipes/index.ts: -------------------------------------------------------------------------------- 1 | export { ValidationPipe } from './validation.pipe' 2 | -------------------------------------------------------------------------------- /packages/api/common/src/pipes/validation.pipe.ts: -------------------------------------------------------------------------------- 1 | import { ArgumentMetadata } from '@nestjs/common' 2 | import { BadRequestException } from '@nestjs/common' 3 | import { Injectable } from '@nestjs/common' 4 | import { PipeTransform } from '@nestjs/common' 5 | import { plainToClass } from 'class-transformer' 6 | import { validate } from 'class-validator' 7 | 8 | @Injectable() 9 | export class ValidationPipe implements PipeTransform { 10 | async transform(value: unknown, metadata: ArgumentMetadata) { 11 | const validationErrors = await validate( 12 | plainToClass(metadata.metatype, value) 13 | ) 14 | 15 | if (validationErrors.length > 0) { 16 | const messages = validationErrors.map((err) => { 17 | return `${err.property} - ${Object.values(err.constraints).join(', ')}` 18 | }) 19 | throw new BadRequestException(messages.join('. ')) 20 | } 21 | 22 | return value 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/api/common/src/types/_prisma.ts: -------------------------------------------------------------------------------- 1 | // AUTO GENERATED FILE BY @kalissaac/prisma-typegen 2 | // DO NOT EDIT 3 | 4 | export interface User { 5 | username: string 6 | password: string 7 | avatarUrl?: string 8 | } 9 | -------------------------------------------------------------------------------- /packages/api/common/src/types/guards/index.ts: -------------------------------------------------------------------------------- 1 | export * from './is-custom-rpc-exception' 2 | -------------------------------------------------------------------------------- /packages/api/common/src/types/guards/is-custom-rpc-exception.ts: -------------------------------------------------------------------------------- 1 | import { isObject } from '@grnx-utils/types' 2 | import { RpcException } from '@nestjs/microservices' 3 | 4 | export interface CustomRpcException extends RpcException { 5 | code: number 6 | } 7 | 8 | export const isCustomRpcException = ( 9 | rpcException: unknown 10 | ): rpcException is CustomRpcException => { 11 | return ( 12 | isObject(rpcException) && 13 | 'code' in rpcException && 14 | 'message' in rpcException 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /packages/api/common/src/utils/validators/env.validator.ts: -------------------------------------------------------------------------------- 1 | import { plainToClass } from 'class-transformer' 2 | import { validateSync } from 'class-validator' 3 | import { ClassConstructor } from 'class-transformer/types/interfaces' 4 | import { AnyObject } from '@grnx-utils/types' 5 | 6 | export const validateConfig = ( 7 | config: AnyObject, 8 | envVariablesClass: ClassConstructor 9 | ): T => { 10 | const validatedConfig = plainToClass(envVariablesClass, config, { 11 | enableImplicitConversion: true 12 | }) 13 | 14 | const errors = validateSync(validatedConfig, { 15 | skipMissingProperties: false 16 | }) 17 | 18 | if (errors.length > 0) { 19 | throw new Error(errors.toString()) 20 | } 21 | 22 | return validatedConfig 23 | } 24 | -------------------------------------------------------------------------------- /packages/api/common/src/utils/validators/index.ts: -------------------------------------------------------------------------------- 1 | export { validateConfig } from './env.validator' 2 | -------------------------------------------------------------------------------- /packages/api/common/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "cg-config/src/tsconfig/paths/third-layer.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "forceConsistentCasingInFileNames": true, 6 | "strict": true, 7 | "noImplicitOverride": true, 8 | "noPropertyAccessFromIndexSignature": false, 9 | "noImplicitReturns": true, 10 | "noFallthroughCasesInSwitch": true, 11 | "strictNullChecks": true, 12 | "strictPropertyInitialization": false 13 | }, 14 | "files": [], 15 | "include": [], 16 | "references": [ 17 | { 18 | "path": "./tsconfig.lib.json" 19 | }, 20 | { 21 | "path": "./tsconfig.spec.json" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /packages/api/common/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "declaration": true, 6 | "types": ["node"], 7 | "target": "es2021", 8 | "strictNullChecks": true, 9 | "noImplicitAny": true, 10 | "strictBindCallApply": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "baseUrl": "." 14 | }, 15 | "include": ["src/**/*.ts"], 16 | "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] 17 | } 18 | -------------------------------------------------------------------------------- /packages/api/common/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "src/**/*.test.ts", 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /packages/api/contracts/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "../../../.eslintrc.js" 4 | ], 5 | "ignorePatterns": [ 6 | "!**/*", 7 | "package.json", 8 | "jest.config.ts" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/api/contracts/README.md: -------------------------------------------------------------------------------- 1 | # api-contracts 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | -------------------------------------------------------------------------------- /packages/api/contracts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cg-api-contracts", 3 | "version": "1.0.0", 4 | "main": "./src/index.js", 5 | "devDependencies": { 6 | "cg-config": "workspace:^" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/api/contracts/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api-contracts", 3 | "$schema": "../../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "packages/api/contracts/src", 5 | "projectType": "library", 6 | "targets": { 7 | "lint": { 8 | "executor": "@nx/linter:eslint", 9 | "outputs": ["{options.outputFile}"], 10 | "options": { 11 | "lintFilePatterns": ["packages/api/contracts/**/*.ts"] 12 | } 13 | } 14 | }, 15 | "tags": [] 16 | } 17 | -------------------------------------------------------------------------------- /packages/api/contracts/src/dto/execute-code.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger' 2 | import { IsIn } from 'class-validator' 3 | import { IsOptional } from 'class-validator' 4 | import { IsString } from 'class-validator' 5 | import { CodeExecutorRequest } from './../interfaces' 6 | import { ExecutorLanguages } from './../interfaces' 7 | import { ExecutorLanguagesKeys } from './../interfaces' 8 | 9 | export class ExecuteCodeApiDTO implements CodeExecutorRequest { 10 | @IsString() 11 | @ApiProperty({ example: 'print("hello world")', description: 'Your code' }) 12 | readonly code: string 13 | 14 | @IsIn(Object.keys(ExecutorLanguages)) 15 | @ApiProperty({ example: 'python', description: 'Code language' }) 16 | readonly language: ExecutorLanguagesKeys 17 | 18 | @IsString() 19 | @IsOptional() 20 | readonly input?: string 21 | } 22 | -------------------------------------------------------------------------------- /packages/api/contracts/src/dto/index.ts: -------------------------------------------------------------------------------- 1 | export * from './execute-code.dto' 2 | -------------------------------------------------------------------------------- /packages/api/contracts/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './rpc' 2 | export * from './interfaces' 3 | export * from './dto' 4 | export * from './inputs' 5 | export * from './responses' 6 | -------------------------------------------------------------------------------- /packages/api/contracts/src/inputs/index.ts: -------------------------------------------------------------------------------- 1 | export * from './sign-in.input' 2 | -------------------------------------------------------------------------------- /packages/api/contracts/src/inputs/sign-in.input.ts: -------------------------------------------------------------------------------- 1 | import { StringField } from '@code-gear/api/common' 2 | import { InputType } from '@nestjs/graphql' 3 | 4 | @InputType() 5 | export class SignIn { 6 | @StringField({ example: 'user123' }) 7 | username: string 8 | 9 | @StringField({ example: 'password456' }) 10 | password: string 11 | } 12 | -------------------------------------------------------------------------------- /packages/api/contracts/src/interfaces/auth.interfaces.ts: -------------------------------------------------------------------------------- 1 | export interface AccessToken { 2 | accessToken: string 3 | } 4 | 5 | export interface WithUsername { 6 | username: string 7 | } 8 | 9 | export interface SignInForm extends WithUsername { 10 | password: string 11 | } 12 | 13 | export interface UserEntity extends WithUsername { 14 | avatarUrl: string 15 | } 16 | 17 | export interface SignInResponse { 18 | isError: boolean 19 | } 20 | -------------------------------------------------------------------------------- /packages/api/contracts/src/interfaces/execute-code.interfaces.ts: -------------------------------------------------------------------------------- 1 | import { HttpStatus } from '@nestjs/common' 2 | 3 | export interface CodeExecutorRequest { 4 | code: string 5 | language: string 6 | input?: string 7 | } 8 | 9 | export interface ExecutorApiResponse { 10 | timeStamp: number 11 | status: HttpStatus 12 | output: string 13 | error: string 14 | language: T 15 | info: string 16 | } 17 | 18 | export const ExecutorLanguages = { 19 | java: 'java', 20 | python: 'py', 21 | cpp: 'cpp', 22 | c: 'c', 23 | go: 'go', 24 | cs: 'cs', 25 | javascript: 'js' 26 | } as const 27 | 28 | export type ExecutorLanguagesKeys = keyof typeof ExecutorLanguages 29 | export type ExecutorLanguagesValues = 30 | (typeof ExecutorLanguages)[ExecutorLanguagesKeys] 31 | -------------------------------------------------------------------------------- /packages/api/contracts/src/interfaces/index.ts: -------------------------------------------------------------------------------- 1 | export * from './auth.interfaces' 2 | export * from './execute-code.interfaces' 3 | -------------------------------------------------------------------------------- /packages/api/contracts/src/responses/index.ts: -------------------------------------------------------------------------------- 1 | export { AccessTokenResponse } from './token.response' 2 | export { UserResponse } from './user.response' 3 | -------------------------------------------------------------------------------- /packages/api/contracts/src/responses/token.response.ts: -------------------------------------------------------------------------------- 1 | import { Field } from '@nestjs/graphql' 2 | import { ObjectType } from '@nestjs/graphql' 3 | import { ApiProperty } from '@nestjs/swagger' 4 | 5 | import { AccessToken as CommonAccessToken } from '@code-gear/api/common' 6 | 7 | @ObjectType() 8 | export class AccessTokenResponse implements CommonAccessToken { 9 | @Field() 10 | @ApiProperty({ description: 'Authorization token (jwt)' }) 11 | accessToken: string 12 | } 13 | -------------------------------------------------------------------------------- /packages/api/contracts/src/responses/user.response.ts: -------------------------------------------------------------------------------- 1 | import { Field } from '@nestjs/graphql' 2 | import { ObjectType } from '@nestjs/graphql' 3 | import { ApiProperty } from '@nestjs/swagger' 4 | 5 | import { User } from '@code-gear/api/common' 6 | 7 | @ObjectType() 8 | export class UserResponse implements Omit { 9 | @Field() 10 | @ApiProperty({ description: 'Username (used as userId)' }) 11 | username: string 12 | 13 | @Field({ nullable: true }) 14 | @ApiProperty({ description: 'User avatar location' }) 15 | avatarUrl: string 16 | } 17 | -------------------------------------------------------------------------------- /packages/api/contracts/src/rpc/auth.rpc.ts: -------------------------------------------------------------------------------- 1 | export const SIGN_IN = 'auth.sign-in' as const 2 | 3 | export const GET_PROFILE = 'auth.get-profile' as const 4 | -------------------------------------------------------------------------------- /packages/api/contracts/src/rpc/code-executor.rpc.ts: -------------------------------------------------------------------------------- 1 | export const EXECUTE_CODE = 'code-executor.execute-code' as const 2 | -------------------------------------------------------------------------------- /packages/api/contracts/src/rpc/index.ts: -------------------------------------------------------------------------------- 1 | export * as CodeExecutorTopic from './code-executor.rpc' 2 | export * as AuthTopic from './auth.rpc' 3 | -------------------------------------------------------------------------------- /packages/api/contracts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "cg-config/src/tsconfig/paths/third-layer.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "forceConsistentCasingInFileNames": true, 6 | "strict": true, 7 | "noImplicitOverride": true, 8 | "noPropertyAccessFromIndexSignature": false, 9 | "noImplicitReturns": true, 10 | "noFallthroughCasesInSwitch": true, 11 | "strictNullChecks": true, 12 | "strictPropertyInitialization": false 13 | }, 14 | "files": [], 15 | "include": [], 16 | "references": [ 17 | { 18 | "path": "./tsconfig.lib.json" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /packages/api/contracts/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "declaration": true, 6 | "types": ["node"], 7 | "target": "es2021", 8 | "strictNullChecks": true, 9 | "noImplicitAny": true, 10 | "strictBindCallApply": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "baseUrl": "." 14 | }, 15 | "include": ["src/**/*.ts"], 16 | "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] 17 | } 18 | -------------------------------------------------------------------------------- /packages/config/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.js"], 3 | "ignorePatterns": ["!**/*"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/config/README.md: -------------------------------------------------------------------------------- 1 | ## config 2 | 3 | Reusable configurations for all applications and libraries. 4 | -------------------------------------------------------------------------------- /packages/config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cg-config", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /packages/config/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "config", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "packages/config/src", 5 | "projectType": "library", 6 | "targets": { 7 | "lint": { 8 | "executor": "@nx/linter:eslint", 9 | "outputs": [ 10 | "{options.outputFile}" 11 | ], 12 | "options": { 13 | "lintFilePatterns": [ 14 | "packages/config/**/*.ts" 15 | ], 16 | "fix": true 17 | } 18 | } 19 | }, 20 | "tags": [] 21 | } 22 | -------------------------------------------------------------------------------- /packages/config/src/babel/vite.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@nx/react/babel", 5 | { 6 | "runtime": "automatic", 7 | "useBuiltIns": "usage" 8 | } 9 | ] 10 | ], 11 | "plugins": [ 12 | [ 13 | "styled-components", 14 | { 15 | "pure": true, 16 | "ssr": true 17 | } 18 | ] 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /packages/config/src/consts/client.ts: -------------------------------------------------------------------------------- 1 | export const clientUrl = process.env.CLIENT_URL ?? 'http://localhost:3000' 2 | 3 | export const appName = 'code_gear' 4 | -------------------------------------------------------------------------------- /packages/config/src/consts/server.ts: -------------------------------------------------------------------------------- 1 | export const serverPrefix = process.env.SERVER_PREFIX ?? '' 2 | 3 | export const serverPort = process.env.SERVER_PORT ?? 6868 4 | 5 | export const compilerApiUrl = 6 | process.env.CODE_COMPILER_API_URL ?? 'https://api.codex.jaagrav.in' 7 | 8 | export const serverUrl = process.env.SERVER_URL ?? 'http://localhost:6868' 9 | 10 | export const EndPoints = { 11 | CODE_EXECUTOR_API: 'execute', 12 | _GRAPHQL: 'graphql' 13 | } as const 14 | 15 | export const serverAppName = 'CodeGear API' 16 | 17 | export const serverDocsPrefix = 'docs' 18 | 19 | export const graphqlArg = '_graphql' 20 | 21 | export const jwtSecret = 22 | process.env.JWT_SECRET || 'I_WILL_REMOVE_THIS_AND_REWRITE_TO_CONFIG_SERVICE' 23 | -------------------------------------------------------------------------------- /packages/config/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './consts/client' 2 | export * from './consts/server' 3 | export { createPreviewDefaults, createStorybookConfig } from './storybook' 4 | -------------------------------------------------------------------------------- /packages/config/src/jest/create-jest-config.ts: -------------------------------------------------------------------------------- 1 | import { resolveRootPath } from '../lib' 2 | import { ProjectLayer } from '../types' 3 | 4 | interface CreateJestConfigPayload { 5 | layer: ProjectLayer 6 | displayName: string 7 | } 8 | 9 | export const createJestConfig = (options: CreateJestConfigPayload) => { 10 | const rootPath = resolveRootPath(options.layer) 11 | 12 | return { 13 | displayName: options.displayName, 14 | preset: `${rootPath}/jest.preset.js`, 15 | testEnvironment: 'node', 16 | transform: { 17 | '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }] 18 | }, 19 | moduleFileExtensions: ['ts', 'tsx'], 20 | coverageDirectory: `${rootPath}/coverage/apps/${options.displayName}` 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/config/src/jest/index.ts: -------------------------------------------------------------------------------- 1 | export { createJestConfig } from './create-jest-config' 2 | -------------------------------------------------------------------------------- /packages/config/src/lib.ts: -------------------------------------------------------------------------------- 1 | import { ProjectLayer } from './types' 2 | 3 | export const resolveRootPath = (layer: ProjectLayer) => { 4 | return layer === 'second' ? '../..' : '../../..' 5 | } 6 | -------------------------------------------------------------------------------- /packages/config/src/storybook/create-storybook-config.ts: -------------------------------------------------------------------------------- 1 | import type { StorybookConfig } from '@storybook/react-vite' 2 | 3 | interface StorybookConfigPayload { 4 | viteConfigPath: string 5 | viteFinal: (config: StorybookConfig) => StorybookConfig 6 | } 7 | 8 | type CreateStorybookConfig = (args: StorybookConfigPayload) => StorybookConfig 9 | 10 | export const createStorybookConfig: CreateStorybookConfig = ({ 11 | viteConfigPath, 12 | viteFinal 13 | }) => ({ 14 | stories: ['../../src/**/*.stories.@(js|jsx|ts|tsx)'], 15 | addons: [ 16 | '@storybook/addon-essentials', 17 | '@storybook/addon-interactions', 18 | '@storybook/addon-jest', 19 | '@storybook/addon-coverage', 20 | '@storybook/addon-actions' 21 | ], 22 | framework: { 23 | name: '@storybook/react-vite', 24 | options: { 25 | builder: { 26 | viteConfigPath 27 | } 28 | } 29 | }, 30 | viteFinal 31 | }) 32 | -------------------------------------------------------------------------------- /packages/config/src/storybook/index.ts: -------------------------------------------------------------------------------- 1 | export { createPreviewDefaults } from './create-preview-defaults' 2 | export { createStorybookConfig } from './create-storybook-config' 3 | -------------------------------------------------------------------------------- /packages/config/src/storybook/plugins/create-viewports.ts: -------------------------------------------------------------------------------- 1 | export const viewports = [600, 800, 1000, 1200, 1500] 2 | 3 | const widthToStr = (w: number) => w.toString() + 'px' 4 | 5 | 6 | const generateViewPort = (width: number) => { 7 | return { 8 | name: widthToStr(width), 9 | styles: { 10 | width: widthToStr(width), 11 | height: '1080px' 12 | } 13 | } 14 | } 15 | export const createViewPorts = () => { 16 | return Object.fromEntries( 17 | viewports.map((i) => [widthToStr(i), generateViewPort(i)]) 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /packages/config/src/tsconfig/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "sourceMap": true, 5 | "declaration": false, 6 | "moduleResolution": "node", 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "importHelpers": true, 10 | "target": "es2015", 11 | "module": "esnext", 12 | "lib": ["es2020", "dom"], 13 | "skipLibCheck": true, 14 | "skipDefaultLibCheck": true, 15 | "strictNullChecks": true 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/config/src/tsconfig/paths/second-layer.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./../base.json", 3 | "compilerOptions": { 4 | "paths": { 5 | "@/*": ["./src/*"], 6 | "@code-gear/api/common": ["../../packages/api/common/src/index.ts"], 7 | "@code-gear/api/contracts": ["../../packages/api/contracts/src/index.ts"], 8 | "@code-gear/api/services": ["../../packages/api/services/src/index.ts"], 9 | "@code-gear/web/editor": ["../../packages/web/editor/src/app/index.ts"], 10 | "@code-gear/web/shared": ["../../packages/web/shared/src/index.ts"], 11 | "@code-gear/web/ui": ["../../packages/web/ui/src/index.ts"], 12 | "@code-gear/config": ["../../packages/config/src/index.ts"] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/config/src/tsconfig/paths/third-layer.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./../base.json", 3 | "compilerOptions": { 4 | "paths": { 5 | "@/*": ["./src/*"], 6 | "@code-gear/api/common": ["../../../packages/api/common/src/index.ts"], 7 | "@code-gear/api/contracts": ["../../../packages/api/contracts/src/index.ts"], 8 | "@code-gear/api/services": ["../../../packages/api/services/src/index.ts"], 9 | "@code-gear/web/editor": ["../../../packages/web/editor/src/index.ts"], 10 | "@code-gear/web/shared": ["../../../packages/web/shared/src/index.ts"], 11 | "@code-gear/web/ui": ["../../../packages/web/ui/src/index.ts"], 12 | "@code-gear/config": ["../../../packages/config/src/index.ts"] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/config/src/types.ts: -------------------------------------------------------------------------------- 1 | export type ProjectLayer = 'second' | 'third' 2 | -------------------------------------------------------------------------------- /packages/config/src/vite/builders/aliases.ts: -------------------------------------------------------------------------------- 1 | import { AliasOptions } from 'vite' 2 | import { ResolveOptions } from 'vite' 3 | 4 | type DefineAliases = ResolveOptions & { alias: AliasOptions } 5 | 6 | export const defineAliases = (): DefineAliases => { 7 | return { 8 | preserveSymlinks: true, 9 | // Nx and Vite have issues with full support for yarn workspaces, 10 | // so i just will use tsconfig paths ;) 11 | 12 | alias: {} 13 | 14 | // alias: { 15 | // '@code-gear/client-shared': resolve( 16 | // __dirname, 17 | // resolvepackages('client-shared', 'src', 'index.js') 18 | // ) 19 | // } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/config/src/vite/builders/build.ts: -------------------------------------------------------------------------------- 1 | import { BuildOptions } from 'vite' 2 | 3 | import { CreateViteConfigOptions } from '../types' 4 | 5 | export const defineBuildOptions = ( 6 | options: CreateViteConfigOptions 7 | ): BuildOptions => { 8 | if (options.projectType === 'library') { 9 | return { 10 | lib: { 11 | entry: 'src/index.ts', 12 | name: options.projectName, 13 | fileName: 'index', 14 | formats: ['es', 'cjs'] 15 | }, 16 | rollupOptions: { 17 | external: [ 18 | 'react', 19 | 'react-dom', 20 | 'react/jsx-runtime', 21 | ...options.external 22 | ] 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/config/src/vite/builders/globals.ts: -------------------------------------------------------------------------------- 1 | export const defineGlobals = (): Record => { 2 | return { 3 | 'process.env': process.env, 4 | _isDev_: process.env.NODE_ENV === 'development' 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/config/src/vite/builders/index.ts: -------------------------------------------------------------------------------- 1 | export { defineAliases } from './aliases' 2 | export { defineBuildOptions } from './build' 3 | export { defineGlobals } from './globals' 4 | export { definePlugins } from './plugins' 5 | export { definePreviewOptions } from './preview' 6 | export { defineServerOptions } from './server' 7 | export { defineVitest } from './vitest' 8 | -------------------------------------------------------------------------------- /packages/config/src/vite/builders/plugins.ts: -------------------------------------------------------------------------------- 1 | // / 2 | import { join } from 'path' 3 | import { PluginOption } from 'vite' 4 | import dts from 'vite-plugin-dts' 5 | import viteTsConfigPaths from 'vite-tsconfig-paths' 6 | 7 | import { CreateViteConfigOptions } from '../types' 8 | 9 | export const definePlugins = ( 10 | options: CreateViteConfigOptions 11 | ): PluginOption[] => { 12 | const defaultPlugins: PluginOption[] = [viteTsConfigPaths()] 13 | 14 | if (options.projectType === 'library') { 15 | defaultPlugins.push([ 16 | dts({ 17 | entryRoot: 'src', 18 | tsConfigFilePath: join(options.rootDir, 'tsconfig.lib.json'), 19 | skipDiagnostics: true 20 | }) 21 | ]) 22 | } 23 | 24 | return [...defaultPlugins, ...options.plugins] 25 | } 26 | -------------------------------------------------------------------------------- /packages/config/src/vite/builders/preview.ts: -------------------------------------------------------------------------------- 1 | import { ServerOptions } from 'vite' 2 | 3 | import { CreateViteConfigOptions } from '../types' 4 | 5 | export const definePreviewOptions = ( 6 | options: CreateViteConfigOptions 7 | ): ServerOptions => { 8 | if (options.projectType === 'application') { 9 | return { 10 | port: 4200, 11 | host: 'localhost' 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/config/src/vite/builders/server.ts: -------------------------------------------------------------------------------- 1 | import { PreviewOptions } from 'vite' 2 | import { ServerOptions } from 'vite' 3 | 4 | import { CreateViteConfigOptions } from '../types' 5 | 6 | export const defineServerOptions = ( 7 | options: CreateViteConfigOptions 8 | ): ServerOptions => { 9 | if (options.projectType === 'application') { 10 | return { 11 | port: 3000, 12 | host: 'localhost', 13 | fs: { 14 | strict: false 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/config/src/vite/builders/vitest.ts: -------------------------------------------------------------------------------- 1 | import { InlineConfig } from 'vite' 2 | 3 | import { resolveRootPath } from '../../lib' 4 | import { CreateViteConfigOptions } from '../types' 5 | 6 | export const defineVitest = ( 7 | options: CreateViteConfigOptions 8 | ): InlineConfig => ({ 9 | globals: true, 10 | cache: { 11 | dir: `${resolveRootPath(options.layer)}/node_modules/.vitest` 12 | }, 13 | environment: 'jsdom', 14 | include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'] 15 | }) 16 | -------------------------------------------------------------------------------- /packages/config/src/vite/index.ts: -------------------------------------------------------------------------------- 1 | export { createViteConfig } from './create-vite-config' 2 | -------------------------------------------------------------------------------- /packages/config/src/vite/misc.ts: -------------------------------------------------------------------------------- 1 | import { resolveRootPath } from '../lib' 2 | import { CreateViteConfigOptions } from './types' 3 | 4 | export const getCacheDir = (options: CreateViteConfigOptions) => { 5 | return `${resolveRootPath(options.layer)}/node_modules/.vite/${ 6 | options.projectName 7 | }` 8 | } 9 | -------------------------------------------------------------------------------- /packages/config/src/vite/types.ts: -------------------------------------------------------------------------------- 1 | import { PluginOption } from 'vite' 2 | 3 | import { ProjectLayer } from '../types' 4 | 5 | export interface CreateViteConfigOptions { 6 | layer: ProjectLayer 7 | projectName: string 8 | projectType: 'library' | 'application' 9 | rootDir: string 10 | plugins: PluginOption[] 11 | external: string[] 12 | } 13 | -------------------------------------------------------------------------------- /packages/config/src/webpack/index.ts: -------------------------------------------------------------------------------- 1 | export { buildWebpackConfig } from './build-webpack-config' 2 | -------------------------------------------------------------------------------- /packages/config/src/webpack/resolvers/index.ts: -------------------------------------------------------------------------------- 1 | export { resolveTsconfigPaths } from './tsconfig-paths' 2 | -------------------------------------------------------------------------------- /packages/config/src/webpack/types.ts: -------------------------------------------------------------------------------- 1 | import { Configuration } from 'webpack' 2 | 3 | import { ProjectLayer } from '../types' 4 | 5 | export interface BuildWebpackConfigPayload { 6 | rootDir: string 7 | layer: ProjectLayer 8 | } 9 | 10 | export interface WebpackConfigOptions extends BuildWebpackConfigPayload { 11 | config: Configuration 12 | } 13 | -------------------------------------------------------------------------------- /packages/config/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "cg-config/src/tsconfig/paths/second-layer.json", 3 | "compilerOptions": { 4 | "allowJs": false, 5 | "esModuleInterop": false, 6 | "allowSyntheticDefaultImports": true, 7 | "module": "ESNext", 8 | "moduleResolution": "Node", 9 | "strictNullChecks": true 10 | }, 11 | "files": [], 12 | "include": ["src/**/*.ts"], 13 | "references": [ 14 | { 15 | "path": "./tsconfig.lib.json" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /packages/config/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "target": "ES2017", 5 | "module": "ESNext", 6 | "outDir": "../../dist/out-tsc", 7 | "declaration": true, 8 | "types": ["node"], 9 | "baseUrl": "." 10 | }, 11 | "include": ["src/**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/generator/README.md: -------------------------------------------------------------------------------- 1 | ## generator 2 | 3 | Library for generating small modules for applications. 4 | -------------------------------------------------------------------------------- /packages/generator/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cg-generator", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /packages/generator/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "packages/generator/src", 5 | "projectType": "library", 6 | "tags": [], 7 | "targets": { 8 | "new": { 9 | "command": "cross-env HYGEN_TMPLS=templates hygen _generator g --generator_name {args.name}", 10 | "options": { 11 | "cwd": "packages/generator" 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/generator/templates/_generator/g/README.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: templates/<%= generator_name %>/README.md 3 | --- 4 | 5 | ### Generator: <%= generator_name %> 6 | 7 | ### Methods 8 | 9 | --- 10 | 11 | 12 | 13 |
14 | new (default) 15 |
16 | 17 | - Arguments 18 | 19 | ```ts 20 | // module_name: string 21 | ``` 22 | 23 |
24 | 25 | ### Run 26 | 27 | `hygen <%= generator_name %> [method]` 28 | -------------------------------------------------------------------------------- /packages/generator/templates/_generator/g/new/index.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: templates/<%= generator_name %>/new/index.ejs 3 | --- 4 | 5 | --- 6 | to: /index.ts.template.template 7 | --- 8 | -------------------------------------------------------------------------------- /packages/generator/templates/_generator/g/prompt.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: templates/<%= generator_name %>/new/prompt.js 3 | --- 4 | 5 | module.exports = [ 6 | { 7 | type: 'input', 8 | name: 'module_name', 9 | message: "Module name:" 10 | } 11 | ] 12 | 13 | -------------------------------------------------------------------------------- /packages/generator/templates/_generator/g/prompt.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { 3 | type: 'input', 4 | name: 'generator_name', 5 | message: 'Generator name:' 6 | } 7 | ] 8 | -------------------------------------------------------------------------------- /packages/generator/templates/fsd-module/README.md: -------------------------------------------------------------------------------- 1 | ### Generator: fsd-module 2 | 3 | This generator creates a module using the 4 | [Feature-Sliced-Design](https://feature-sliced.design/ru/docs/get-started/overview) methodology. 5 | 6 | ### Methods 7 | 8 | --- 9 | 10 | - new (General case) 11 | 12 | ### Run 13 | 14 | `hygen fsd-module [method]` 15 | -------------------------------------------------------------------------------- /packages/generator/templates/fsd-module/new/hooks/index.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: <%= module_name %>/hooks/index.ts.template.template 3 | --- 4 | -------------------------------------------------------------------------------- /packages/generator/templates/fsd-module/new/index.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= module_name %>/index.ts.template.template 3 | --- 4 | export { <%= module_name.charAt(0).toUpperCase() + module_name.slice(1) %> } from './ui/<%= module_name %>' 5 | -------------------------------------------------------------------------------- /packages/generator/templates/fsd-module/new/lib/index.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: <%= module_name %>/lib/index.ts.template.template 3 | --- 4 | -------------------------------------------------------------------------------- /packages/generator/templates/fsd-module/new/prompt.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { 3 | type: 'input', 4 | name: 'module_name', 5 | message: 'Module name:' 6 | } 7 | ] 8 | -------------------------------------------------------------------------------- /packages/generator/templates/fsd-module/new/store/gitkeep.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: <%= module_name %>/store/.gitkeep 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /packages/generator/templates/fsd-module/new/ui/component.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: <%= module_name %>/ui/<%= module_name %>.tsx 3 | --- 4 | 5 | interface <%= module_name.charAt(0).toUpperCase() + module_name.slice(1) %>Props { 6 | 7 | } 8 | 9 | export const <%= module_name.charAt(0).toUpperCase() + module_name.slice(1) %> = () => { 10 | return null 11 | } 12 | 13 | -------------------------------------------------------------------------------- /packages/generator/templates/fsd-module/new/ui/component.styles.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: <%= module_name %>/ui/<%= module_name %>.styles.ts 3 | --- 4 | import styled from 'styled-components' 5 | 6 | export const <%= module_name.charAt(0).toUpperCase() + module_name.slice(1) %>Styles = styled.div` 7 | 8 | ` 9 | -------------------------------------------------------------------------------- /packages/generator/templates/ui/README.md: -------------------------------------------------------------------------------- 1 | ### Generator: ui 2 | 3 | ### Methods 4 | 5 | --- 6 | 7 |
8 | new (default) 9 |
10 | 11 | - Arguments 12 | 13 | ```ts 14 | // module_name: string 15 | ``` 16 | 17 |
18 | 19 | ### Run 20 | 21 | `hygen ui [method]` 22 | -------------------------------------------------------------------------------- /packages/generator/templates/ui/new/component.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= module_name %>/<%= module_name %>.tsx 3 | --- 4 | import { <%= h.changeCase.pascal(module_name) %>Styles } from './<%= module_name %>.styles' 5 | 6 | export interface <%= h.changeCase.pascal(module_name) %>Props { 7 | 8 | } 9 | 10 | export const <%= h.changeCase.pascal(module_name) %> = (props: <%= h.changeCase.pascal(module_name) %>Props) => { 11 | return
<%= module_name %>
12 | } 13 | 14 | -------------------------------------------------------------------------------- /packages/generator/templates/ui/new/component.styles.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= module_name %>/<%= module_name %>.styles.ts 3 | --- 4 | import styled from 'styled-components' 5 | 6 | export const <%= h.changeCase.pascal(module_name) %>Styles = styled.div` 7 | 8 | ` 9 | -------------------------------------------------------------------------------- /packages/generator/templates/ui/new/index.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= module_name %>/index.ts.template.template 3 | --- 4 | 5 | export { <%= h.changeCase.pascal(module_name) %> } from './<%= module_name %>' 6 | -------------------------------------------------------------------------------- /packages/generator/templates/ui/new/prompt.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { 3 | type: 'input', 4 | name: 'module_name', 5 | message: 'Module name:' 6 | } 7 | ] 8 | -------------------------------------------------------------------------------- /packages/web/editor/.babelrc: -------------------------------------------------------------------------------- 1 | {"extends": "cg-config/src/babel/vite.json"} 2 | -------------------------------------------------------------------------------- /packages/web/editor/.config/vite.ts: -------------------------------------------------------------------------------- 1 | // It is important to specify relative paths here. 2 | import { resolve } from 'path' 3 | import react from '@vitejs/plugin-react' 4 | import dynamicImport from 'vite-plugin-dynamic-import' 5 | 6 | import { createViteConfig } from '../../../config/src/vite' 7 | 8 | export default createViteConfig({ 9 | projectName: 'editor', 10 | projectType: 'library', 11 | rootDir: resolve(__dirname, '..'), 12 | layer: 'third', 13 | external: ['antd', 'react-router-dom', 'react-smooth-scrollbar'], 14 | plugins: [react(), dynamicImport()] 15 | }) 16 | -------------------------------------------------------------------------------- /packages/web/editor/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "../../../.eslintrc.js" 4 | ], 5 | "ignorePatterns": [ 6 | "!**/*" 7 | ], 8 | "parser": "@typescript-eslint/parser", 9 | "globals": { 10 | "FileSystemFileHandle": true, 11 | "OpenFilePickerOptions": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/web/editor/README.md: -------------------------------------------------------------------------------- 1 | # web-editor 2 | 3 | Code editor page. Logic core. 4 | -------------------------------------------------------------------------------- /packages/web/editor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cg-editor", 3 | "version": "0.0.1", 4 | "main": "./index.js", 5 | "types": "./index.d.ts", 6 | "exports": { 7 | ".": { 8 | "import": "./index.mjs", 9 | "require": "./index.js" 10 | } 11 | }, 12 | "devDependencies": { 13 | "cg-config": "workspace:^" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/web/editor/src/app/index.ts: -------------------------------------------------------------------------------- 1 | import { lazy } from 'react' 2 | 3 | const Editor = lazy(() => import('./editor')) 4 | 5 | export { Editor } 6 | 7 | export { 8 | EditorActions, 9 | EditorGetters, 10 | EditorStore, 11 | EditorStoreContext 12 | } from './providers/editor-store' 13 | export type { ModalsPayload, ModalsState } from './providers/modals-provider' 14 | export { ModalsContext } from './providers/modals-provider' 15 | export { useCustomTheme } from './providers/theme-loader' 16 | -------------------------------------------------------------------------------- /packages/web/editor/src/app/providers/editor-store/config/editor.services.ts: -------------------------------------------------------------------------------- 1 | import { makeAutoObservable } from 'mobx' 2 | 3 | import { ExecuteServices } from '@/widgets/header' 4 | 5 | import EditorActions from './editor.actions' 6 | import EditorGetters from './editor.getters' 7 | import EditorStore from './editor.store' 8 | 9 | class EditorServices { 10 | private state: EditorStore 11 | private readonly getters: EditorGetters 12 | private readonly actions: EditorActions 13 | readonly codeRunner: ExecuteServices 14 | 15 | constructor(root: EditorStore) { 16 | makeAutoObservable(this) 17 | 18 | this.state = root 19 | this.getters = root.getters 20 | this.actions = root.actions 21 | this.codeRunner = new ExecuteServices(root) 22 | } 23 | } 24 | 25 | export default EditorServices 26 | -------------------------------------------------------------------------------- /packages/web/editor/src/app/providers/editor-store/index.ts: -------------------------------------------------------------------------------- 1 | export { default as EditorActions } from './config/editor.actions' 2 | export { default as EditorGetters } from './config/editor.getters' 3 | export { default as EditorStore } from './config/editor.store' 4 | export { 5 | EditorStoreContext, 6 | default as EditorStoreProvider 7 | } from './ui/editor-store-provider' 8 | -------------------------------------------------------------------------------- /packages/web/editor/src/app/providers/editor-store/lib/default-code-template.ts: -------------------------------------------------------------------------------- 1 | import { LanguagesValues } from '@/shared/consts/languages' 2 | 3 | export const defaultCodeTemplate = `// Hello World! Here you can edit the code in 10 different languages. 😎 4 | 5 | const camel = 'I like apples' 6 | 7 | // Run the code and look in the terminal. 8 | console.log(camel) 9 | 10 | // You can edit and run the code in real time 11 | // and your friends will see it! Sign in if you want to see more features. 12 | ` 13 | export const defaultCodeLang: LanguagesValues = 'javascript' 14 | -------------------------------------------------------------------------------- /packages/web/editor/src/app/providers/editor-store/ui/editor-store-provider.tsx: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react' 2 | import { ReactNode } from 'react' 3 | 4 | import EditorStore from '../config/editor.store' 5 | 6 | export const EditorStoreContext = createContext({} as EditorStore) 7 | 8 | export const EditorStoreProvider = ({ children }: { children: ReactNode }) => { 9 | const root = new EditorStore() 10 | 11 | return ( 12 | 13 | {children} 14 | 15 | ) 16 | } 17 | 18 | export default EditorStoreProvider 19 | -------------------------------------------------------------------------------- /packages/web/editor/src/app/providers/modals-provider/index.ts: -------------------------------------------------------------------------------- 1 | export type { ModalsPayload, ModalsState } from './types' 2 | export { 3 | ModalsContext, 4 | default as ModalsContextProvider 5 | } from './ui/modals-context-provider' 6 | -------------------------------------------------------------------------------- /packages/web/editor/src/app/providers/modals-provider/types.ts: -------------------------------------------------------------------------------- 1 | import { AnyObject } from '@code-gear/web/shared' 2 | import { ReducerPayload } from '@code-gear/web/shared' 3 | import { ReactElement } from 'react' 4 | 5 | import { TerminalTabKeys } from '@/widgets/terminal' 6 | 7 | export interface ModalsState { 8 | isTerminalOpened: boolean 9 | isSettingsOpened: boolean 10 | isHtmlPreviewOpened: boolean 11 | isSignInOpened: boolean 12 | selectedTerminalTab: TerminalTabKeys 13 | ModalComponents: { 14 | SignIn: (props: AnyObject) => ReactElement 15 | } 16 | } 17 | 18 | export interface ModalsPayload extends ReducerPayload { 19 | toggle?: (prop: keyof ModalsState) => void 20 | } 21 | -------------------------------------------------------------------------------- /packages/web/editor/src/app/providers/theme-loader/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { useCustomTheme } from './use-custom-theme/use-custom-theme' 2 | export { useThemeLoader } from './use-theme-loader/use-theme-loader' 3 | -------------------------------------------------------------------------------- /packages/web/editor/src/app/providers/theme-loader/hooks/use-custom-theme/use-custom-theme.ts: -------------------------------------------------------------------------------- 1 | import { Hex } from '@code-gear/web/shared' 2 | import { useMonaco } from '@monaco-editor/react' 3 | 4 | import { CUSTOM_THEME } from '@/shared/consts/themes' 5 | 6 | interface CustomTheme { 7 | background: Hex 8 | color: Hex 9 | } 10 | 11 | export const useCustomTheme = () => { 12 | const monaco = useMonaco() 13 | 14 | return ({ background, color }: CustomTheme) => { 15 | monaco.editor.defineTheme(CUSTOM_THEME, { 16 | base: 'vs', 17 | inherit: true, 18 | rules: [], 19 | colors: { 20 | 'editor.background': background, 21 | 'editor.foreground': color 22 | } 23 | }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/web/editor/src/app/providers/theme-loader/hooks/use-theme-loader/assert-theme-object.ts: -------------------------------------------------------------------------------- 1 | import { isObject } from '@code-gear/web/shared' 2 | import { editor } from 'monaco-editor' 3 | 4 | import EditorErrors from '@/shared/exceptions' 5 | 6 | // eslint-disable-next-line prefer-arrow/prefer-arrow-functions 7 | export function assertThemeObject( 8 | value: unknown 9 | ): asserts value is editor.IStandaloneThemeData { 10 | if ( 11 | isObject(value) && 12 | 'base' in value && 13 | typeof value.base === 'string' && 14 | 'colors' in value && 15 | isObject(value.colors) 16 | ) { 17 | return 18 | } 19 | 20 | throw new Error(EditorErrors.WrongJsonObject('ThemeObject')) 21 | } 22 | -------------------------------------------------------------------------------- /packages/web/editor/src/app/providers/theme-loader/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks' 2 | export { default as ThemeLoader } from './ui/theme-loader' 3 | -------------------------------------------------------------------------------- /packages/web/editor/src/app/providers/theme-loader/ui/theme-loader.tsx: -------------------------------------------------------------------------------- 1 | import { Display } from '@code-gear/web/shared' 2 | import { WithChildren } from '@code-gear/web/shared' 3 | 4 | import { useThemeLoader } from '../hooks' 5 | 6 | const ThemeLoader = ({ children }: WithChildren) => { 7 | const isLoaded = useThemeLoader() 8 | return {children} 9 | } 10 | 11 | export default ThemeLoader 12 | -------------------------------------------------------------------------------- /packages/web/editor/src/app/styles/editor.styles.ts: -------------------------------------------------------------------------------- 1 | import { s } from '@code-gear/web/shared' 2 | import styled from 'styled-components' 3 | 4 | export const EditorStyles = styled.div` 5 | ${s.wh('100vw', '100vh')} 6 | ` 7 | 8 | export const EditorWrapper = styled.div` 9 | ${s.wh('100%', 'calc(100% - 45px)')}; 10 | display: flex; 11 | ` 12 | -------------------------------------------------------------------------------- /packages/web/editor/src/entities/editor-core/index.ts: -------------------------------------------------------------------------------- 1 | export { default as EditorCore } from './editor-core' 2 | -------------------------------------------------------------------------------- /packages/web/editor/src/entities/header-options/index.ts: -------------------------------------------------------------------------------- 1 | export { default as HeaderOptions } from './ui/header-options' 2 | -------------------------------------------------------------------------------- /packages/web/editor/src/entities/header-options/ui/header-options.styles.ts: -------------------------------------------------------------------------------- 1 | import { s } from '@code-gear/web/shared' 2 | import styled from 'styled-components' 3 | 4 | export const HeaderOptionsStyles = styled.div` 5 | ${s.wh('23%', '28px')} 6 | ${s.flex('flex-start', 'center')} 7 | gap: 25px; 8 | img { 9 | transition: transform 200ms; 10 | &:hover { 11 | transform: scale(1.1) rotate(3deg); 12 | } 13 | } 14 | ` 15 | 16 | export const Option = styled.span` 17 | color: ${({ theme }) => theme.light}; 18 | cursor: pointer; 19 | ` 20 | -------------------------------------------------------------------------------- /packages/web/editor/src/entities/header-right-section/index.ts: -------------------------------------------------------------------------------- 1 | export { default as HeaderRightSection } from './ui/header-right-section' 2 | -------------------------------------------------------------------------------- /packages/web/editor/src/entities/header-right-section/ui/header-right-section.styles.ts: -------------------------------------------------------------------------------- 1 | import { s } from '@code-gear/web/shared' 2 | import styled from 'styled-components' 3 | 4 | import { Icon } from '@/widgets/aside/ui/aside.styles' 5 | 6 | export const RightSection = styled.div` 7 | ${s.wh('23%', '100%')}; 8 | ${s.flex('flex-start', 'center')}; 9 | gap: 25px; 10 | ` 11 | 12 | interface HeaderIconProps { 13 | readonly $disabled: boolean 14 | } 15 | 16 | export const HeaderIcon = styled(Icon)` 17 | margin-top: 0; 18 | margin-left: 20px; 19 | svg { 20 | color: ${({ theme, $disabled }) => 21 | $disabled ? theme.secondaryGrey : theme.light}; 22 | } 23 | ` 24 | -------------------------------------------------------------------------------- /packages/web/editor/src/entities/key-buildings/index.ts: -------------------------------------------------------------------------------- 1 | export { default as KeyBuildings } from './key-buildings' 2 | -------------------------------------------------------------------------------- /packages/web/editor/src/entities/preview-editor/index.ts: -------------------------------------------------------------------------------- 1 | export { default as PreviewEditor } from './ui/preview-editor' 2 | -------------------------------------------------------------------------------- /packages/web/editor/src/entities/preview-editor/ui/preview-editor.styles.ts: -------------------------------------------------------------------------------- 1 | import { s } from '@code-gear/web/shared' 2 | import styled from 'styled-components' 3 | 4 | export const EditorContainer = styled.div` 5 | ${s.wh('33%', '100%')}; 6 | border-radius: 6px; 7 | ` 8 | 9 | export const EditorTitle = styled.h4` 10 | &:first-letter { 11 | text-transform: capitalize; 12 | } 13 | svg { 14 | margin-bottom: -3px; 15 | } 16 | color: ${s.color('light')}; 17 | margin: 9px 4px; 18 | margin-top: 5px; 19 | font-size: ${({ theme }) => theme.fz9}; 20 | ` 21 | -------------------------------------------------------------------------------- /packages/web/editor/src/entities/preview-i-frame/index.ts: -------------------------------------------------------------------------------- 1 | export { default as IFrame } from './ui/i-frame' 2 | -------------------------------------------------------------------------------- /packages/web/editor/src/entities/preview-i-frame/lib/create-html-template.ts: -------------------------------------------------------------------------------- 1 | import { PreviewState } from '@/components/html-preivew/types' 2 | 3 | export const createHtmlTemplate = ({ html, css, javascript }: PreviewState) => ` 4 | 5 | ${html} 6 | 7 | 8 | 15 | 16 | ` 17 | -------------------------------------------------------------------------------- /packages/web/editor/src/entities/terminal-output/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { useTerminalOutputAnimations } from './use-terminal-output-animations' 2 | -------------------------------------------------------------------------------- /packages/web/editor/src/entities/terminal-output/index.ts: -------------------------------------------------------------------------------- 1 | export type { TerminalOutputHandle } from './ui/terminal-output/terminal-output' 2 | export { default as TerminalOutput } from './ui/terminal-output/terminal-output' 3 | -------------------------------------------------------------------------------- /packages/web/editor/src/features/language-switcher/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { useMappedLanguages } from './use-mapped-languages' 2 | -------------------------------------------------------------------------------- /packages/web/editor/src/features/language-switcher/hooks/use-mapped-languages.ts: -------------------------------------------------------------------------------- 1 | import { languages } from '@/shared/consts/languages' 2 | 3 | export const useMappedLanguages = () => { 4 | const mapped = [...new Set(Object.values(languages))] 5 | 6 | return mapped.map((lang) => ({ 7 | value: lang, 8 | label: lang 9 | })) 10 | } 11 | -------------------------------------------------------------------------------- /packages/web/editor/src/features/language-switcher/index.ts: -------------------------------------------------------------------------------- 1 | export { default as LanguageSwitcher } from './ui/language-switcher' 2 | -------------------------------------------------------------------------------- /packages/web/editor/src/features/language-switcher/ui/language-switcher.tsx: -------------------------------------------------------------------------------- 1 | import { Select } from '@code-gear/web/ui' 2 | import { observer } from 'mobx-react-lite' 3 | 4 | import { LanguagesValues } from '@/shared/consts/languages' 5 | import { useGetters } from '@/shared/hooks' 6 | 7 | import { useMappedLanguages } from '../hooks' 8 | 9 | const LanguageSwitcher = observer(() => { 10 | const languages = useMappedLanguages() 11 | const getters = useGetters() 12 | const language = getters.getActiveLanguage() 13 | const activeTab = getters.getActiveTab() 14 | 15 | const handleChange = (newLanguage: LanguagesValues) => { 16 | activeTab.lang = newLanguage 17 | } 18 | 19 | return ( 20 | 21 | onChange={handleChange} 22 | value={language} 23 | options={languages} 24 | /> 25 | ) 26 | }) 27 | 28 | export default LanguageSwitcher 29 | -------------------------------------------------------------------------------- /packages/web/editor/src/features/switch-font-size/index.ts: -------------------------------------------------------------------------------- 1 | export { default as FontSizeSwitcher } from './ui/font-size-switcher' 2 | -------------------------------------------------------------------------------- /packages/web/editor/src/features/switch-font-size/ui/font-size-switcher.tsx: -------------------------------------------------------------------------------- 1 | import { Select } from '@code-gear/web/ui' 2 | import { observer } from 'mobx-react-lite' 3 | 4 | import { FontSizes } from '@/shared/consts/font-sizes' 5 | import { fontSizes } from '@/shared/consts/font-sizes' 6 | import { useActions } from '@/shared/hooks' 7 | import { useStore } from '@/shared/hooks' 8 | 9 | const FontSizeSwitcher = observer(() => { 10 | const actions = useActions() 11 | const { fontSize } = useStore() 12 | 13 | const handleChange = (fontSize: FontSizes) => { 14 | actions.changeFontSize(fontSize) 15 | } 16 | 17 | return ( 18 | 19 | onChange={handleChange} 20 | value={fontSize} 21 | options={fontSizes.map((value) => ({ 22 | value, 23 | label: `${value}px` 24 | }))} 25 | /> 26 | ) 27 | }) 28 | 29 | export default FontSizeSwitcher 30 | -------------------------------------------------------------------------------- /packages/web/editor/src/features/switch-tab-size/index.ts: -------------------------------------------------------------------------------- 1 | export { default as TabSizeSwitcher } from './ui/tab-size-switcher' 2 | -------------------------------------------------------------------------------- /packages/web/editor/src/features/switch-tab-size/ui/tab-size-switcher.tsx: -------------------------------------------------------------------------------- 1 | import { Select } from '@code-gear/web/ui' 2 | import { observer } from 'mobx-react-lite' 3 | 4 | import { TabSizes } from '@/shared/consts/font-sizes' 5 | import { tabSizes } from '@/shared/consts/font-sizes' 6 | import { useActions } from '@/shared/hooks' 7 | import { useStore } from '@/shared/hooks' 8 | 9 | const TabSizeSwitcher = observer(() => { 10 | const actions = useActions() 11 | const { tabSize } = useStore() 12 | 13 | const handleChange = (tabSize: TabSizes) => { 14 | actions.changeTabSize(tabSize) 15 | } 16 | 17 | return ( 18 | 19 | onChange={handleChange} 20 | value={tabSize} 21 | options={tabSizes.map((value) => ({ 22 | value, 23 | label: value 24 | }))} 25 | /> 26 | ) 27 | }) 28 | 29 | export default TabSizeSwitcher 30 | -------------------------------------------------------------------------------- /packages/web/editor/src/features/switch-theme/index.ts: -------------------------------------------------------------------------------- 1 | export { default as ThemeSwitcher } from './ui/theme-switcher' 2 | -------------------------------------------------------------------------------- /packages/web/editor/src/features/switch-theme/ui/theme-switcher.tsx: -------------------------------------------------------------------------------- 1 | import { Select } from '@code-gear/web/ui' 2 | import { observer } from 'mobx-react-lite' 3 | 4 | import { Themes } from '@/shared/consts/themes' 5 | import { themes } from '@/shared/consts/themes' 6 | import { useActions } from '@/shared/hooks' 7 | import { useStore } from '@/shared/hooks' 8 | 9 | const ThemeSwitcher = observer(() => { 10 | const actions = useActions() 11 | const { theme } = useStore() 12 | 13 | const handleChange = (theme: Themes) => { 14 | actions.changeTheme(theme) 15 | } 16 | 17 | return ( 18 | 19 | defaultValue="vs-dark" 20 | onChange={handleChange} 21 | value={theme} 22 | options={themes.map((theme) => ({ 23 | value: theme, 24 | label: theme 25 | }))} 26 | /> 27 | ) 28 | }) 29 | 30 | export default ThemeSwitcher 31 | -------------------------------------------------------------------------------- /packages/web/editor/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './app' 2 | -------------------------------------------------------------------------------- /packages/web/editor/src/shared/consts/font-sizes.ts: -------------------------------------------------------------------------------- 1 | import { Keys } from '@code-gear/web/shared' 2 | 3 | export const maxTabsLength = 9 as const 4 | 5 | export const fontSizes = [14, 16, 18, 20, 22, 24, 26] as const 6 | 7 | export type FontSizes = Keys 8 | 9 | export const tabSizes = [4, 2] as const 10 | 11 | export type TabSizes = Keys 12 | -------------------------------------------------------------------------------- /packages/web/editor/src/shared/consts/key-buildings.ts: -------------------------------------------------------------------------------- 1 | export enum KeyBuildings { 2 | O = 'O', 3 | S = 'S', 4 | N = 'N', 5 | T = 'T', 6 | P = 'P', 7 | J = 'J', 8 | Q = 'Q' 9 | } 10 | -------------------------------------------------------------------------------- /packages/web/editor/src/shared/consts/languages.ts: -------------------------------------------------------------------------------- 1 | import { ValueOf } from '@code-gear/web/shared' 2 | 3 | export const languages = { 4 | js: 'javascript', 5 | ts: 'typescript', 6 | tsx: 'typescript', 7 | jsx: 'typescript', 8 | html: 'html', 9 | htm: 'html', 10 | txt: 'text', 11 | css: 'css', 12 | py: 'python', 13 | cpp: 'cpp', 14 | go: 'go', 15 | c: 'c', 16 | java: 'java' 17 | } as const 18 | 19 | export type LanguagesValues = ValueOf 20 | 21 | export type LanguagesKeys = keyof typeof languages 22 | 23 | export const executorAllowedLanguages: LanguagesValues[] = [ 24 | 'java', 25 | 'python', 26 | 'cpp', 27 | 'c', 28 | 'go', 29 | 'javascript' 30 | ] 31 | -------------------------------------------------------------------------------- /packages/web/editor/src/shared/consts/themes.ts: -------------------------------------------------------------------------------- 1 | // Themes for code-editor 2 | 3 | export const CUSTOM_THEME = 'Custom' as const 4 | 5 | export const themes = [ 6 | 'vs-dark', 7 | 'Monokai', 8 | 'Dracula', 9 | 'Dreamweaver', 10 | 'GitHub', 11 | 'Nord', 12 | 'Twilight', 13 | 'IDLE', 14 | 'Eiffel', 15 | 'Tomorrow', 16 | CUSTOM_THEME 17 | ] as const 18 | 19 | export type Themes = (typeof themes)[number] 20 | -------------------------------------------------------------------------------- /packages/web/editor/src/shared/editor-config.ts: -------------------------------------------------------------------------------- 1 | import { editor } from 'monaco-editor' 2 | 3 | import { FontSizes } from '@/shared/consts/font-sizes' 4 | import { TabSizes } from '@/shared/consts/font-sizes' 5 | 6 | interface EditorConfigPayload { 7 | fontSize: FontSizes 8 | tabSize: TabSizes 9 | } 10 | 11 | type EditorConfig = ( 12 | payload: EditorConfigPayload 13 | ) => editor.IStandaloneEditorConstructionOptions 14 | 15 | export const editorConfig: EditorConfig = ({ fontSize, tabSize }) => ({ 16 | fontSize, 17 | tabSize, 18 | glyphMargin: false, 19 | lineNumbersMinChars: 2, 20 | lineDecorationsWidth: 0, 21 | minimap: { 22 | enabled: false 23 | }, 24 | scrollbar: { 25 | verticalScrollbarSize: 6 26 | } 27 | }) 28 | -------------------------------------------------------------------------------- /packages/web/editor/src/shared/exceptions.ts: -------------------------------------------------------------------------------- 1 | import { AnyFunction } from '@code-gear/web/shared' 2 | 3 | import { Themes } from '@/shared/consts/themes' 4 | 5 | const EditorErrors: Record> = { 6 | ThemeUpload: (theme: Themes) => { 7 | return `Unable to upload theme - ${theme}.json` 8 | }, 9 | NotSupportedByBrowser: () => { 10 | return 'Your browser does not support saving and opening files.' 11 | }, 12 | WrongJsonObject: (type: string) => { 13 | return `Incoming json object should be must be ${type} type.` 14 | }, 15 | WrongResponseType: (type: string) => { 16 | return `Incoming response object should be must be ${type} type.` 17 | } 18 | } 19 | 20 | export default EditorErrors 21 | -------------------------------------------------------------------------------- /packages/web/editor/src/shared/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-modals-context' 2 | export * from './use-store' 3 | -------------------------------------------------------------------------------- /packages/web/editor/src/shared/hooks/use-editor.ts: -------------------------------------------------------------------------------- 1 | import { useMonaco } from '@monaco-editor/react' 2 | import { editor } from 'monaco-editor' 3 | 4 | export const useEditor = () => { 5 | const monaco = useMonaco() 6 | 7 | return monaco.editor.getEditors()[0] as editor.ICodeEditor 8 | } 9 | -------------------------------------------------------------------------------- /packages/web/editor/src/shared/hooks/use-store.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | 3 | import { EditorStoreContext } from '@/app' 4 | 5 | export const useActions = () => { 6 | return useContext(EditorStoreContext).actions 7 | } 8 | 9 | export const useStore = () => { 10 | return useContext(EditorStoreContext) 11 | } 12 | 13 | export const useGetters = () => { 14 | return useContext(EditorStoreContext).getters 15 | } 16 | 17 | export const useServices = () => { 18 | return useContext(EditorStoreContext).services 19 | } 20 | 21 | export const useStorage = () => { 22 | return useContext(EditorStoreContext).storage 23 | } 24 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/aside/hooks/use-aside-animation.ts: -------------------------------------------------------------------------------- 1 | import { useAnimations } from '@code-gear/web/shared' 2 | 3 | export const useAsideAnimation = () => { 4 | const { Spring } = useAnimations() 5 | 6 | const spring = Spring.useSpring({ 7 | from: { 8 | x: -100 9 | }, 10 | to: { 11 | x: 0 12 | }, 13 | config: Spring.config.stiff 14 | }) 15 | 16 | return { 17 | animatedDiv: Spring.a.div, 18 | spring 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/aside/hooks/use-editor-actions.ts: -------------------------------------------------------------------------------- 1 | import { useEditor } from '@/shared/hooks/use-editor' 2 | 3 | export const useEditorActions = () => { 4 | const editor = useEditor() 5 | 6 | const find = async () => { 7 | await editor.getAction('actions.find')?.run() 8 | } 9 | 10 | const replace = async () => { 11 | await editor.getAction('editor.action.startFindReplaceAction')?.run() 12 | } 13 | 14 | return { 15 | find, 16 | replace 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/aside/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Aside } from './ui/aside' 2 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/aside/ui/aside.styles.ts: -------------------------------------------------------------------------------- 1 | import { s } from '@code-gear/web/shared' 2 | import styled from 'styled-components' 3 | 4 | export const AsideStyles = styled.div` 5 | background: ${({ theme }) => theme.grey}; 6 | border-right: 2px solid ${({ theme }) => theme.lightGrey}; 7 | box-sizing: border-box; 8 | ${s.wh('52px', '100%')}; 9 | ${s.flex('space-between', 'center', 'column')}; 10 | padding-bottom: 15px; 11 | z-index: 3; 12 | ` 13 | 14 | export const Icon = styled.div` 15 | ${s.wh('23px')} 16 | svg { 17 | ${s.wh()} 18 | color: ${({ theme }) => theme.secondaryGrey}; 19 | ${({ theme }) => s.hover(theme.light)} 20 | } 21 | transition: transform 200ms; 22 | &:hover { 23 | transform: scale(1.1); 24 | } 25 | margin-top: 20px; 26 | cursor: pointer; 27 | user-select: none; 28 | ` 29 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/editor-content/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { useAltNavigation } from './use-alt-navigation/use-alt-navigation' 2 | export { useFileService } from './use-file-service/use-file-service' 3 | export { useKeyboardManager } from './use-keyboard-manager/use-keyboard-manager' 4 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/editor-content/hooks/use-file-service/lib/consts.ts: -------------------------------------------------------------------------------- 1 | export const filePickerOptions: OpenFilePickerOptions = { 2 | types: [ 3 | { 4 | accept: { 5 | 'text/*': [ 6 | '.ts', 7 | '.tsx', 8 | '.js', 9 | '.jsx', 10 | '.vue', 11 | '.txt', 12 | '.py', 13 | '.yaml', 14 | '.yml' 15 | ] 16 | }, 17 | description: 'Text Files' 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/editor-content/hooks/use-file-service/lib/get-language-from-name.ts: -------------------------------------------------------------------------------- 1 | import { languages } from '@/shared/consts/languages' 2 | import { LanguagesKeys } from '@/shared/consts/languages' 3 | import { LanguagesValues } from '@/shared/consts/languages' 4 | 5 | export const getLanguageFromName = ( 6 | fileName: string 7 | ): [LanguagesValues, string] => { 8 | const ext = fileName.split('.').at(-1) as string 9 | if (isInLanguagesKeys(ext)) { 10 | return [languages[ext], ext] 11 | } 12 | return ['text', ext] 13 | } 14 | 15 | // eslint-disable-next-line prefer-arrow/prefer-arrow-functions 16 | function isInLanguagesKeys(ext: string): ext is LanguagesKeys { 17 | if (ext in languages) { 18 | return true 19 | } 20 | return false 21 | } 22 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/editor-content/hooks/use-file-service/use-file-saver.ts: -------------------------------------------------------------------------------- 1 | import { isFunction } from '@code-gear/web/shared' 2 | import { Nullable } from '@code-gear/web/shared' 3 | 4 | import EditorErrors from '@/shared/exceptions' 5 | 6 | export const useFileSaver = () => { 7 | return async ( 8 | fileHandle: Nullable, 9 | textContent: string 10 | ) => { 11 | try { 12 | let handle = fileHandle 13 | 14 | if (!isFunction(fileHandle?.createWritable)) { 15 | handle = await window.showSaveFilePicker() 16 | } 17 | 18 | const stream = await (handle as FileSystemFileHandle).createWritable() 19 | await stream.write(textContent) 20 | await stream.close() 21 | 22 | return handle 23 | } catch (error) { 24 | console.warn(EditorErrors.NotSupportedByBrowser()) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/editor-content/index.ts: -------------------------------------------------------------------------------- 1 | export { default as EditorContentActions } from './store/content.actions' 2 | export { default as EditorContent } from './ui/editor-content' 3 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/editor-content/store/content.actions.ts: -------------------------------------------------------------------------------- 1 | import { makeAutoObservable } from 'mobx' 2 | 3 | import { EditorGetters } from '@/app' 4 | import { EditorStore } from '@/app' 5 | 6 | class ContentActions { 7 | private state: EditorStore 8 | private getters: EditorGetters 9 | 10 | constructor(root: EditorStore) { 11 | makeAutoObservable(this) 12 | this.state = root 13 | this.getters = root.getters 14 | } 15 | 16 | saveContent(content: string, key?: string) { 17 | const activeTab = this.getters.getActiveTab(key) 18 | activeTab.content = content 19 | } 20 | } 21 | 22 | export default ContentActions 23 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/editor-content/types/guards/is-file-data.ts: -------------------------------------------------------------------------------- 1 | import { isObject } from '@code-gear/web/shared' 2 | 3 | import { FileHandlerData } from '../types' 4 | 5 | export const isFileData = (value: unknown): value is FileHandlerData => { 6 | if (!isObject(value)) { 7 | return false 8 | } 9 | 10 | if ( 11 | 'name' in value && 12 | typeof value.name === 'string' && 13 | 'type' in value && 14 | typeof value.type === 'string' && 15 | 'content' in value && 16 | typeof value.content === 'string' 17 | ) { 18 | return true 19 | } 20 | 21 | return false 22 | } 23 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/editor-content/types/index.ts: -------------------------------------------------------------------------------- 1 | export { isFileData } from './guards/is-file-data' 2 | export type { FileHandlerData } from './types' 3 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/editor-content/types/types.ts: -------------------------------------------------------------------------------- 1 | import { LanguagesValues } from '@/shared/consts/languages' 2 | 3 | export interface FileHandlerData { 4 | name: string 5 | type: string 6 | content: string 7 | fileHandle: FileSystemFileHandle 8 | language: LanguagesValues 9 | } 10 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/editor-content/ui/editor-content.styles.ts: -------------------------------------------------------------------------------- 1 | import { s } from '@code-gear/web/shared' 2 | import styled from 'styled-components' 3 | 4 | export const EditorContentStyles = styled.div` 5 | width: 100%; 6 | ` 7 | 8 | export const TabsWrapper = styled.div` 9 | ${s.flex('space-between')} 10 | ${s.wh('100%', '48px')} 11 | margin-bottom: 10px; 12 | ` 13 | export const TabsSelects = styled.div` 14 | width: 30%; 15 | display: flex; 16 | gap: 30px; 17 | align-items: flex-end; 18 | ` 19 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/header/errors.ts: -------------------------------------------------------------------------------- 1 | import { NotificationMessage } from './types' 2 | 3 | export const CodeExecutionErrors: Record = { 4 | NOT_SUPPORTED: { 5 | isError: true, 6 | message: 'This file type is not supported to execute' 7 | }, 8 | ERRORS_IN_CODE: { 9 | isError: true, 10 | message: 'It looks like there are some errors in your code.' 11 | }, 12 | SUCCESS: { 13 | isError: false, 14 | message: 'Code completed successfully!' 15 | }, 16 | NETWORK_ERROR: { 17 | isError: true, 18 | message: 'Something went wrong' 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/header/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { useCodeRunner } from './use-code-runner' 2 | export { useHeaderAnimation } from './use-header-animation' 3 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/header/hooks/use-code-runner.ts: -------------------------------------------------------------------------------- 1 | import { useNotifications } from '@code-gear/web/shared' 2 | 3 | import { useModalsContext } from '@/shared/hooks' 4 | import { useServices } from '@/shared/hooks' 5 | 6 | export const useCodeRunner = () => { 7 | const { codeRunner } = useServices() 8 | const modalsContext = useModalsContext() 9 | const notify = useNotifications() 10 | 11 | const runCode = async () => { 12 | const { isError, message } = await codeRunner.requestCodeExecution() 13 | 14 | modalsContext.update({ 15 | isTerminalOpened: true, 16 | selectedTerminalTab: 'terminal' 17 | }) 18 | 19 | notify.open({ 20 | message, 21 | type: isError ? 'error' : 'success' 22 | }) 23 | } 24 | 25 | return runCode 26 | } 27 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/header/hooks/use-header-animation.ts: -------------------------------------------------------------------------------- 1 | import { useAnimations } from '@code-gear/web/shared' 2 | import { useSpring } from '@react-spring/web' 3 | 4 | export const useHeaderAnimation = () => { 5 | const { Spring } = useAnimations() 6 | 7 | const spring = useSpring({ 8 | from: { 9 | x: -100 10 | }, 11 | to: { 12 | x: 0 13 | }, 14 | config: Spring.config.stiff 15 | }) 16 | 17 | return { 18 | animatedDiv: Spring.a.div, 19 | spring 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/header/index.ts: -------------------------------------------------------------------------------- 1 | export { default as HeaderOptions } from '../../entities/header-options/ui/header-options' 2 | export { default as HeaderRightSection } from '../../entities/header-right-section/ui/header-right-section' 3 | export { default as ExecuteServices } from './store/execute.services' 4 | export type { ExecutorRequest, ExecutorResponse } from './types' 5 | export { default as Header } from './ui/header' 6 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/header/types.ts: -------------------------------------------------------------------------------- 1 | export interface ExecutorRequest { 2 | code: string 3 | language: string 4 | input?: string 5 | } 6 | export interface ExecutorResponse { 7 | timeStamp: number 8 | status: number 9 | output: string 10 | error: string 11 | language: string 12 | info: string 13 | } 14 | 15 | export interface NotificationMessage { 16 | isError: boolean 17 | message: string 18 | } 19 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/header/ui/header.styles.ts: -------------------------------------------------------------------------------- 1 | import { s } from '@code-gear/web/shared' 2 | import styled from 'styled-components' 3 | 4 | export const HeaderStyles = styled.div` 5 | background: ${({ theme }) => theme.grey}; 6 | border-bottom: 2px solid ${({ theme }) => theme.lightGrey}; 7 | height: ${s.wh('100%', '42px')}; 8 | box-sizing: border-box; 9 | ${s.flex('space-between', 'center')} 10 | ${s.hPadding(23)} 11 | ` 12 | 13 | export const FileName = styled.h2` 14 | color: ${({ theme }) => theme.light}; 15 | ` 16 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/html-preview/context/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | default as HtmlPreviewProvider, 3 | usePreview 4 | } from './html-preview-provider' 5 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/html-preview/index.ts: -------------------------------------------------------------------------------- 1 | export { usePreview } from './context' 2 | export type { PreviewLanguages } from './types' 3 | export { default as HtmlPreview } from './ui/html-preview' 4 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/html-preview/types.ts: -------------------------------------------------------------------------------- 1 | import { LanguagesValues } from '@/shared/consts/languages' 2 | 3 | export type PreviewLanguages = Extract< 4 | LanguagesValues, 5 | 'html' | 'css' | 'javascript' 6 | > 7 | 8 | export interface PreviewState { 9 | html: string 10 | css: string 11 | javascript: string 12 | } 13 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/html-preview/ui/html-preview.styles.ts: -------------------------------------------------------------------------------- 1 | import { s } from '@code-gear/web/shared' 2 | import styled from 'styled-components' 3 | 4 | export const PreviewWrapper = styled.div` 5 | ${s.wh('100%', '750px')}; 6 | overflow-y: auto; 7 | scroll-behavior: smooth; 8 | margin-top: 10px; 9 | ${s.customScrollbar()}; 10 | ` 11 | 12 | export const EditorBlock = styled.div` 13 | ${s.wh('100%', '360px')}; 14 | display: flex; 15 | gap: 20px; 16 | ` 17 | 18 | export const PreviewBlock = styled.div` 19 | ${s.wh('100%', '50vh')}; 20 | iframe { 21 | background: ${s.color('grey')}; 22 | border-radius: 6px; 23 | margin-top: 8px; 24 | } 25 | ` 26 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/settings/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { useColorCallback } from './use-color-callback' 2 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/settings/hooks/use-color-callback.ts: -------------------------------------------------------------------------------- 1 | import { Hex } from '@code-gear/web/shared' 2 | import { useDebounce } from '@code-gear/web/shared' 3 | 4 | import { CUSTOM_THEME } from '@/shared/consts/themes' 5 | import { useActions } from '@/shared/hooks' 6 | import { useStore } from '@/shared/hooks' 7 | 8 | export const useColorCallback = (cb: (hex: Hex) => void) => { 9 | const { theme } = useStore() 10 | const actions = useActions() 11 | 12 | return useDebounce((_: unknown, hex: Hex) => { 13 | if (theme !== CUSTOM_THEME) { 14 | actions.changeTheme(CUSTOM_THEME) 15 | } 16 | 17 | return cb(hex) 18 | }, 300) 19 | } 20 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/settings/index.ts: -------------------------------------------------------------------------------- 1 | import { lazy } from 'react' 2 | 3 | export const Settings = lazy(() => import('./ui/settings')) 4 | 5 | export { KeyBuildingStyles, SettingsText } from './ui/settings.styles' 6 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/settings/ui/settings.styles.ts: -------------------------------------------------------------------------------- 1 | import { s } from '@code-gear/web/shared' 2 | import styled from 'styled-components' 3 | 4 | export const SettingsItem = styled.div` 5 | ${s.wh('100%', '70px')}; 6 | ${s.flex('space-between', 'flex-start')}; 7 | margin-bottom: 25px; 8 | ` 9 | 10 | export const KeyBuildingStyles = styled(SettingsItem)` 11 | height: 45px; 12 | width: 60%; 13 | margin: 0 auto; 14 | margin-bottom: 10px; 15 | gap: 30px; 16 | ` 17 | 18 | export const SettingsText = styled.div` 19 | margin-top: -5px; 20 | height: 100%; 21 | h4 { 22 | color: ${s.color('light')}; 23 | font-size: ${({ theme }) => theme.fz8}; 24 | } 25 | p { 26 | color: ${s.color('secondaryGrey')}; 27 | font-size: ${({ theme }) => theme.fz5}; 28 | margin-top: 10px; 29 | } 30 | ` 31 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/tabs/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { useConfirm } from './use-confirm' 2 | export { useMappedTabs } from './use-mapped-tabs' 3 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/tabs/hooks/use-confirm.ts: -------------------------------------------------------------------------------- 1 | import { AnyFunction } from '@code-gear/web/shared' 2 | import { Nullable } from '@code-gear/web/shared' 3 | import { useState } from 'react' 4 | 5 | export const useConfirm = () => { 6 | const [confirmKey, setConfirmKey] = useState>(null) 7 | 8 | return { 9 | protect: (callback: AnyFunction) => { 10 | return (...args: unknown[]) => { 11 | if (confirmKey) { 12 | return 13 | } 14 | callback(...args) 15 | } 16 | }, 17 | off: () => { 18 | setConfirmKey(null) 19 | }, 20 | on: (key: string) => { 21 | setConfirmKey(key) 22 | }, 23 | val: confirmKey 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/tabs/hooks/use-mapped-tabs.ts: -------------------------------------------------------------------------------- 1 | import { ContentTab } from '../index' 2 | 3 | export const useMappedTabs = (content: ContentTab[]) => { 4 | return content.map((tab) => ({ 5 | label: tab.label, 6 | key: tab.key 7 | })) 8 | } 9 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/tabs/index.ts: -------------------------------------------------------------------------------- 1 | export { default as TabsActions } from './store/tabs.actions' 2 | export type { ContentTab } from './types' 3 | export { default as Tabs } from './ui/tabs' 4 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/tabs/lib/helpers/generate-new-tab.ts: -------------------------------------------------------------------------------- 1 | import { v4 as generateId } from 'uuid' 2 | 3 | import { FileHandlerData } from '@/widgets/editor-content/types' 4 | import { ContentTab } from '@/widgets/tabs/types' 5 | 6 | type GenerateContentTabPayload = Partial<{ 7 | lastNumber: number 8 | fileData: FileHandlerData 9 | }> 10 | 11 | export const generateNewTab = ({ 12 | fileData, 13 | lastNumber 14 | }: GenerateContentTabPayload): ContentTab => ({ 15 | fileHandle: fileData?.fileHandle ?? null, 16 | content: fileData?.content ?? '', 17 | label: fileData?.name ?? 'Untitled', 18 | lang: fileData?.language ?? 'text', 19 | idx: lastNumber ? lastNumber + 1 : 0, 20 | key: generateId(), 21 | wasChanged: false 22 | }) 23 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/tabs/lib/helpers/is-max-tabs-length.ts: -------------------------------------------------------------------------------- 1 | import { maxTabsLength } from '@/shared/consts/font-sizes' 2 | 3 | import { ContentTab } from '../../index' 4 | 5 | export const isMaxTabsLength = (content: ContentTab[]) => { 6 | return content.length >= maxTabsLength 7 | } 8 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/tabs/lib/index.ts: -------------------------------------------------------------------------------- 1 | export { isMaxTabsLength } from './helpers/is-max-tabs-length' 2 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/tabs/types.ts: -------------------------------------------------------------------------------- 1 | import { Nullable } from '@code-gear/web/shared' 2 | 3 | import { LanguagesValues } from '@/shared/consts/languages' 4 | 5 | export interface ContentTab { 6 | key: string 7 | fileHandle: Nullable 8 | label: string 9 | content: string 10 | idx: number 11 | lang: LanguagesValues 12 | wasChanged: boolean 13 | } 14 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/tabs/ui/tabs.styles.ts: -------------------------------------------------------------------------------- 1 | import { s } from '@code-gear/web/shared' 2 | import { Tabs as AntdTabs } from 'antd' 3 | import styled from 'styled-components' 4 | 5 | export const TabsStyles = styled(AntdTabs)` 6 | color: ${s.antdColor('secondaryGrey')}; 7 | height: 50px; 8 | margin: 12px; 9 | min-width: 300px; 10 | .ant-tabs-nav::before { 11 | border-bottom: none; 12 | } 13 | .ant-tabs-tab { 14 | background: ${s.antdColor('grey')}; 15 | } 16 | .ant-tabs-tab-active { 17 | background: #2e3139 !important; 18 | } 19 | .ant-tabs-tab-btn { 20 | color: ${s.antdColor('secondaryGrey')}; 21 | } 22 | ` 23 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/terminal/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { useTerminalTabs } from './use-terminal-tabs' 2 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/terminal/hooks/use-terminal-tabs.ts: -------------------------------------------------------------------------------- 1 | import { useCallback } from 'react' 2 | 3 | import { useModalsContext } from '@/shared/hooks' 4 | 5 | export type TerminalTabKeys = 'terminal' | 'test_cases' 6 | 7 | interface TerminalTab { 8 | label: string 9 | key: TerminalTabKeys 10 | } 11 | 12 | const terminalTabs: TerminalTab[] = [ 13 | { label: 'Terminal', key: 'terminal' }, 14 | { label: 'Test cases', key: 'test_cases' } 15 | ] 16 | 17 | export const useTerminalTabs = () => { 18 | const modalsContext = useModalsContext() 19 | const activeKey = modalsContext.state.selectedTerminalTab 20 | 21 | const setActiveKey = useCallback( 22 | (key: TerminalTabKeys) => { 23 | modalsContext.update({ 24 | selectedTerminalTab: key 25 | }) 26 | }, 27 | [modalsContext] 28 | ) 29 | 30 | return { 31 | key: activeKey, 32 | set: setActiveKey, 33 | val: terminalTabs 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/terminal/index.ts: -------------------------------------------------------------------------------- 1 | export type { TerminalTabKeys } from './hooks/use-terminal-tabs' 2 | export { default as TerminalActions } from './store/terminal.actions' 3 | export type { ExecuteMessage } from './types' 4 | export { default as Terminal } from './ui/terminal' 5 | -------------------------------------------------------------------------------- /packages/web/editor/src/widgets/terminal/types.ts: -------------------------------------------------------------------------------- 1 | export interface ExecuteMessage { 2 | message: string 3 | isError: boolean 4 | fileName: string 5 | date: string 6 | } 7 | -------------------------------------------------------------------------------- /packages/web/editor/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "cg-config/src/tsconfig/paths/third-layer.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "allowJs": false, 6 | "esModuleInterop": false, 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true, 9 | "types": ["vite/client", "vitest"], 10 | "strictNullChecks": true 11 | }, 12 | "files": [], 13 | "include": [], 14 | "references": [ 15 | { 16 | "path": "./tsconfig.lib.json" 17 | }, 18 | { 19 | "path": "./tsconfig.spec.json" 20 | } 21 | ], 22 | } 23 | -------------------------------------------------------------------------------- /packages/web/editor/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "types": ["node", "vite/client", "@types/wicg-file-system-access"], 6 | "resolveJsonModule": true, 7 | "baseUrl": "." 8 | }, 9 | "files": [ 10 | "../../../node_modules/@nx/react/typings/cssmodule.d.ts", 11 | "../../../node_modules/@nx/react/typings/image.d.ts" 12 | ], 13 | "exclude": [ 14 | "**/*.spec.ts", 15 | "**/*.test.ts", 16 | "**/*.spec.tsx", 17 | "**/*.test.tsx", 18 | "**/*.spec.js", 19 | "**/*.test.js", 20 | "**/*.spec.jsx", 21 | "**/*.test.jsx" 22 | ], 23 | "include": ["src/**/*.ts", "src/**/*.tsx"] 24 | } 25 | -------------------------------------------------------------------------------- /packages/web/editor/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node"] 6 | }, 7 | "include": [ 8 | "vite.config.ts", 9 | "src/**/*.test.ts", 10 | "src/**/*.spec.ts", 11 | "src/**/*.test.tsx", 12 | "src/**/*.spec.tsx", 13 | "src/**/*.test.js", 14 | "src/**/*.spec.js", 15 | "src/**/*.test.jsx", 16 | "src/**/*.spec.jsx", 17 | "src/**/*.d.ts" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /packages/web/shared/.babelrc: -------------------------------------------------------------------------------- 1 | {"extends": "cg-config/src/babel/vite.json"} 2 | -------------------------------------------------------------------------------- /packages/web/shared/.config/vite.ts: -------------------------------------------------------------------------------- 1 | // It is important to specify relative paths here. 2 | import { resolve } from 'path' 3 | import react from '@vitejs/plugin-react' 4 | 5 | import { createViteConfig } from '../../../config/src/vite' 6 | 7 | export default createViteConfig({ 8 | projectName: 'web-shared', 9 | projectType: 'library', 10 | rootDir: resolve(__dirname, '..'), 11 | layer: 'third', 12 | external: ['react-smooth-scrollbar', 'antd', 'react-router-dom'], 13 | plugins: [react()] 14 | }) 15 | -------------------------------------------------------------------------------- /packages/web/shared/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "../../../.eslintrc.js" 4 | ], 5 | "ignorePatterns": [ 6 | "!**/*", 7 | "env.d.ts" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /packages/web/shared/README.md: -------------------------------------------------------------------------------- 1 | # web-shared 2 | 3 | Reusable modules for frontend applications. 4 | -------------------------------------------------------------------------------- /packages/web/shared/env.d.ts: -------------------------------------------------------------------------------- 1 | declare const _isDev_: string 2 | -------------------------------------------------------------------------------- /packages/web/shared/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cg-client-shared", 3 | "version": "0.0.1", 4 | "main": "src/index.ts", 5 | "exports": { 6 | ".": { 7 | "import": "./src/index.ts", 8 | "require": "./src/index.ts" 9 | } 10 | }, 11 | "devDependencies": { 12 | "cg-config": "workspace:^" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/web/shared/src/assets/index.ts: -------------------------------------------------------------------------------- 1 | import { default as logo } from './logo.png' 2 | import { default as svgLogo } from './logo.svg' 3 | 4 | export const Assets = { 5 | logo, 6 | svgLogo 7 | } 8 | -------------------------------------------------------------------------------- /packages/web/shared/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearonix/code-gear/428293078745619b14bce932d30b9b73e5cce08c/packages/web/shared/src/assets/logo.png -------------------------------------------------------------------------------- /packages/web/shared/src/config/axios.ts: -------------------------------------------------------------------------------- 1 | import { serverUrl } from '@code-gear/config' 2 | import axios from 'axios' 3 | 4 | const axiosInstance = axios.create({ 5 | baseURL: serverUrl, 6 | withCredentials: true 7 | }) 8 | 9 | export default axiosInstance 10 | -------------------------------------------------------------------------------- /packages/web/shared/src/config/index.ts: -------------------------------------------------------------------------------- 1 | export { default as apolloClient } from './apollo-client' 2 | export { default as httpService } from './axios' 3 | export { LocalStorage } from './local-storage' 4 | export { PrivatePaths, RoutePaths } from './paths' 5 | -------------------------------------------------------------------------------- /packages/web/shared/src/config/local-storage.ts: -------------------------------------------------------------------------------- 1 | export const LocalStorage = { 2 | EDITOR_THEME: 'EDITOR_THEME', 3 | EDITOR_CONTENT_DATA: 'EDITOR_CONTENT_DATA', 4 | EDITOR_EXECUTE_MESSAGES: 'EDITOR_EXECUTE_MESSAGES', 5 | EDITOR_FONT_SIZE: 'EDITOR_FONT_SIZE', 6 | EDITOR_TAB_SIZE: 'EDITOR_TAB_SIZE', 7 | EDITOR_CUSTOM_BACKGROUND: 'EDITOR_CUSTOM_BACKGROUND', 8 | EDITOR_CUSTOM_COLOR: 'EDITOR_CUSTOM_COLOR', 9 | EDITOR_HTML_PREVIEW: 'EDITOR_HTML_PREVIEW', 10 | AUTH_TOKEN: 'AUTH_TOKEN' 11 | } as const 12 | 13 | export type LocalStorageKeys = keyof typeof LocalStorage 14 | 15 | export type LocalStorageValue = 16 | (typeof LocalStorage)[T] 17 | -------------------------------------------------------------------------------- /packages/web/shared/src/config/paths.ts: -------------------------------------------------------------------------------- 1 | enum AppRoutes { 2 | MAIN = 'MAIN', 3 | EDITOR = 'EDITOR', 4 | ABOUT = 'ABOUT', 5 | PROFILE = 'PROFILE' 6 | } 7 | 8 | export const RoutePaths: Record = { 9 | [AppRoutes.MAIN]: '/', 10 | [AppRoutes.EDITOR]: '/edit', 11 | [AppRoutes.ABOUT]: '/about', 12 | [AppRoutes.PROFILE]: '/users' 13 | } 14 | 15 | export const PrivatePaths = [RoutePaths.PROFILE] 16 | -------------------------------------------------------------------------------- /packages/web/shared/src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { useNotifications } from './use-notifications' 2 | 3 | /** 4 | * @see https://www.npmjs.com/package/@grnx-utils/react-hooks 5 | */ 6 | 7 | export { 8 | useAltKeyDown, 9 | useAsyncEffect, 10 | useBooleanState, 11 | useDebounce, 12 | useFilteredEffect, 13 | useFullScreen, 14 | useOverflow 15 | } from '@grnx-utils/react-hooks' 16 | -------------------------------------------------------------------------------- /packages/web/shared/src/hooks/use-notifications.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | 3 | import { NotificationsContext } from '@/providers' 4 | import { NotificationsPayload } from '@/providers/notifications/notifications-provider' 5 | 6 | export const useNotifications = () => { 7 | return useContext(NotificationsContext) as NotificationsPayload 8 | } 9 | -------------------------------------------------------------------------------- /packages/web/shared/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './assets' 2 | export * from './config' 3 | export * from './hooks' 4 | export * from './lib/apollo' 5 | export * from './lib/components' 6 | export * from './lib/helpers' 7 | export * as Icons from './lib/icons' 8 | export * from './providers' 9 | export * from './storybook' 10 | export * as s from './styles' 11 | export * from './types' 12 | -------------------------------------------------------------------------------- /packages/web/shared/src/lib/apollo/index.ts: -------------------------------------------------------------------------------- 1 | export { ApolloMiddleware } from './apollo-middleware' 2 | -------------------------------------------------------------------------------- /packages/web/shared/src/lib/components/Display.ts: -------------------------------------------------------------------------------- 1 | import { WithChildren } from '@/types' 2 | 3 | type DisplayProps = WithChildren<{ when: T }> 4 | 5 | export const Display = ({ when, children }: DisplayProps) => { 6 | return when ? children : null 7 | } 8 | -------------------------------------------------------------------------------- /packages/web/shared/src/lib/components/index.ts: -------------------------------------------------------------------------------- 1 | export { Display } from './Display' 2 | export { 3 | default as AnimationProvider, 4 | useAnimations 5 | } from '@/providers/animations/animation-provider' 6 | -------------------------------------------------------------------------------- /packages/web/shared/src/lib/helpers/index.ts: -------------------------------------------------------------------------------- 1 | export { LocalStorageClient } from './local-storage' 2 | -------------------------------------------------------------------------------- /packages/web/shared/src/lib/icons.ts: -------------------------------------------------------------------------------- 1 | export { 2 | AiOutlineClose, 3 | AiOutlineHtml5, 4 | AiOutlineInfoCircle, 5 | AiOutlineSwap 6 | } from 'react-icons/ai' 7 | export { BsJournals, BsSearch } from 'react-icons/bs' 8 | export { GoTerminal } from 'react-icons/go' 9 | export { GrClear } from 'react-icons/gr' 10 | export { LuTestTube2 } from 'react-icons/lu' 11 | export { MdFindReplace } from 'react-icons/md' 12 | export { SlInfo, SlSizeFullscreen } from 'react-icons/sl' 13 | export { TfiSettings } from 'react-icons/tfi' 14 | export { VscPlay } from 'react-icons/vsc' 15 | -------------------------------------------------------------------------------- /packages/web/shared/src/providers/error-boundary/error-boundary.tsx: -------------------------------------------------------------------------------- 1 | import { useErrorBoundary } from 'preact/hooks' 2 | 3 | import { WithPreactChildren } from '@/types' 4 | 5 | import ErrorTemplate from './ui/error-template' 6 | 7 | const ErrorBoundary = ({ children }: WithPreactChildren) => { 8 | const [error] = useErrorBoundary() 9 | 10 | console.error(error) 11 | 12 | if (error) { 13 | return 14 | } 15 | 16 | return <>{children} 17 | } 18 | 19 | export default ErrorBoundary 20 | -------------------------------------------------------------------------------- /packages/web/shared/src/providers/error-boundary/ui/error-template.tsx: -------------------------------------------------------------------------------- 1 | const ErrorTemplate = () => { 2 | return ( 3 |
4 | Custom Error Boundary.
5 |
6 | ) 7 | } 8 | 9 | export default ErrorTemplate 10 | -------------------------------------------------------------------------------- /packages/web/shared/src/providers/index.ts: -------------------------------------------------------------------------------- 1 | export { default as AnimationProvider } from './animations/animation-provider' 2 | export { default as ErrorBoundary } from './error-boundary/error-boundary' 3 | export { 4 | NotificationsContext, 5 | default as NotificationsProvider 6 | } from './notifications/notifications-provider' 7 | export { GlobalStyles } from './styles' 8 | export { AntdConfig, DarkThemePalette, ThemeProvider } from './theme' 9 | -------------------------------------------------------------------------------- /packages/web/shared/src/providers/styles/app.styles.ts: -------------------------------------------------------------------------------- 1 | import { createGlobalStyle } from 'styled-components' 2 | 3 | import { customScrollbar } from '@/styles' 4 | import { font } from '@/styles' 5 | 6 | export const GlobalStyles = createGlobalStyle` 7 | body { 8 | background: ${({ theme }) => theme.default}; 9 | ${font('Poppins')} 10 | overflow-x: hidden; 11 | user-select: none; 12 | } 13 | 14 | p, h2, h3, h4 { 15 | font-size: ${({ theme }) => theme.fz6}; 16 | } 17 | h1, h2, h3, h4, h5, h6, p { 18 | font-weight: normal; 19 | margin: 0; 20 | } 21 | 22 | 23 | ${customScrollbar('body')} 24 | 25 | .ant-popconfirm { 26 | z-index: 2; 27 | } 28 | ` 29 | -------------------------------------------------------------------------------- /packages/web/shared/src/providers/styles/index.ts: -------------------------------------------------------------------------------- 1 | export { GlobalStyles } from './app.styles' 2 | -------------------------------------------------------------------------------- /packages/web/shared/src/providers/theme/config/antd-config.ts: -------------------------------------------------------------------------------- 1 | import { theme } from 'antd' 2 | import { ThemeConfig } from 'antd/es/config-provider' 3 | 4 | import { DarkThemePalette } from './themes' 5 | 6 | export const AntdConfig: ThemeConfig = { 7 | algorithm: theme.darkAlgorithm, 8 | token: { 9 | colorBgBase: DarkThemePalette.grey, 10 | colorTextBase: DarkThemePalette.light, 11 | colorBorder: DarkThemePalette.lightGrey, 12 | colorBgTextHover: DarkThemePalette.light, 13 | colorBgTextActive: DarkThemePalette.light, 14 | colorPrimary: DarkThemePalette.light 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/web/shared/src/providers/theme/config/themes.ts: -------------------------------------------------------------------------------- 1 | export const DarkThemePalette = { 2 | black: '#000', 3 | light: '#C4CBDA', 4 | white: '#fff', 5 | default: '#1E1E1E', 6 | grey: '#24272E', 7 | greyDark: '#3C3C4A', 8 | lightGrey: '#3C3C4A', 9 | secondaryGrey: '#9099AC', 10 | darkBlue: '#1F2228', 11 | fz5: '14px', 12 | fz6: '16px', 13 | fz7: '18px', 14 | fz8: '19px', 15 | fz9: '21px', 16 | f10: '28px' 17 | } 18 | -------------------------------------------------------------------------------- /packages/web/shared/src/providers/theme/index.ts: -------------------------------------------------------------------------------- 1 | export * from './config/antd-config' 2 | export * from './config/themes' 3 | export { default as ThemeProvider } from './ui/theme-provider' 4 | -------------------------------------------------------------------------------- /packages/web/shared/src/providers/theme/styled.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'styled-components' { 2 | export interface DefaultTheme { 3 | black: string 4 | light: string 5 | default: string 6 | grey: string 7 | greyDark: string 8 | lightGrey: string 9 | secondaryGrey: string 10 | darkBlue: string 11 | white: string 12 | fz6: string 13 | fz7: string 14 | f10: string 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/web/shared/src/providers/theme/ui/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | import { ConfigProvider as AntdConfigProvider } from 'antd' 2 | import { ThemeProvider as StyledThemeProvider } from 'styled-components' 3 | 4 | import { WithChildren } from '@/types' 5 | 6 | import { AntdConfig } from '../config/antd-config' 7 | import { DarkThemePalette } from '../config/themes' 8 | 9 | const ThemeProvider = ({ children }: WithChildren) => { 10 | return ( 11 | 12 | 13 | {children} 14 | 15 | 16 | ) 17 | } 18 | 19 | export default ThemeProvider 20 | -------------------------------------------------------------------------------- /packages/web/shared/src/storybook/decorators/animation.decorator.tsx: -------------------------------------------------------------------------------- 1 | import { Decorator } from '@storybook/react' 2 | 3 | import { AnimationProvider } from '@/lib/components' 4 | 5 | export const AnimationDecorator: Decorator = (story) => ( 6 | {story()} 7 | ) 8 | -------------------------------------------------------------------------------- /packages/web/shared/src/storybook/decorators/index.ts: -------------------------------------------------------------------------------- 1 | export { AnimationDecorator } from './animation.decorator' 2 | export { StylesDecorator } from './styles.decorator' 3 | export { ThemeDecorator } from './theme.decorator' 4 | -------------------------------------------------------------------------------- /packages/web/shared/src/storybook/decorators/styles.decorator.tsx: -------------------------------------------------------------------------------- 1 | import { Decorator } from '@storybook/react' 2 | 3 | import { GlobalStyles } from '@/providers' 4 | 5 | export const StylesDecorator: Decorator = (story) => ( 6 | <> 7 | {story()} 8 | 9 | 10 | ) 11 | -------------------------------------------------------------------------------- /packages/web/shared/src/storybook/decorators/theme.decorator.tsx: -------------------------------------------------------------------------------- 1 | import { Decorator } from '@storybook/react' 2 | 3 | import { ThemeProvider } from '@/providers/theme' 4 | 5 | export const ThemeDecorator: Decorator = (story) => ( 6 | {story()} 7 | ) 8 | 9 | -------------------------------------------------------------------------------- /packages/web/shared/src/storybook/index.ts: -------------------------------------------------------------------------------- 1 | export * from './decorators' 2 | export * from './lib' 3 | export * from './types' 4 | -------------------------------------------------------------------------------- /packages/web/shared/src/storybook/lib/create-storybook-variant.ts: -------------------------------------------------------------------------------- 1 | import { Decorator } from '@storybook/react' 2 | import { ComponentProps } from 'react' 3 | import { FC } from 'react' 4 | 5 | export const createStorybookVariant = ( 6 | defaultArgs: ComponentProps 7 | ) => { 8 | return ( 9 | additionalArgs: Partial> = {}, 10 | decorators: Decorator[] = [] 11 | ) => ({ 12 | args: { 13 | ...defaultArgs, 14 | ...additionalArgs 15 | }, 16 | decorators 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /packages/web/shared/src/storybook/lib/index.ts: -------------------------------------------------------------------------------- 1 | export { createStorybookVariant } from 'src/storybook/lib/create-storybook-variant' 2 | -------------------------------------------------------------------------------- /packages/web/shared/src/storybook/types.ts: -------------------------------------------------------------------------------- 1 | import { StoryObj } from '@storybook/react' 2 | import { FC } from 'react' 3 | 4 | import { CustomArguments } from '@/types' 5 | 6 | export type TestStory = CustomArguments['play']>[0] 7 | -------------------------------------------------------------------------------- /packages/web/shared/src/styles/index.ts: -------------------------------------------------------------------------------- 1 | export * from './mixins' 2 | export * from './variables' 3 | -------------------------------------------------------------------------------- /packages/web/shared/src/styles/variables.ts: -------------------------------------------------------------------------------- 1 | export const br = '1px solid' 2 | -------------------------------------------------------------------------------- /packages/web/shared/src/types/common/graphql.ts: -------------------------------------------------------------------------------- 1 | import { DocumentNode } from 'graphql/language' 2 | 3 | export interface ApolloOperation { 4 | gql: DocumentNode 5 | method: string 6 | } 7 | -------------------------------------------------------------------------------- /packages/web/shared/src/types/common/grnx.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @see https://www.npmjs.com/package/@grnx-utils/types 3 | */ 4 | 5 | export type { 6 | AnyFunction, 7 | AnyObject, 8 | Combine, 9 | CustomArguments, 10 | DeepNullable, 11 | Entries, 12 | Hex, 13 | Keys, 14 | Mutable, 15 | Nullable, 16 | ObjectNullable, 17 | ReplaceName, 18 | Required, 19 | TargetKey, 20 | Undefinable, 21 | ValueOf, 22 | Values, 23 | VoidFunction, 24 | WithChildren, 25 | WithFeatures, 26 | WithPreactChildren 27 | } from '@grnx-utils/types' 28 | export { isFunction, isNumber, isObject, isString } from '@grnx-utils/types' 29 | -------------------------------------------------------------------------------- /packages/web/shared/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './common/graphql' 2 | export * from './common/grnx' 3 | export * from './lib/animations' 4 | export * from './lib/context' 5 | -------------------------------------------------------------------------------- /packages/web/shared/src/types/lib/animations.ts: -------------------------------------------------------------------------------- 1 | export type SpringType = typeof import('@react-spring/web') 2 | export type GestureType = typeof import('@use-gesture/react') 3 | export type AnimatedDiv = typeof import('@react-spring/web').animated.div 4 | -------------------------------------------------------------------------------- /packages/web/shared/src/types/lib/context.ts: -------------------------------------------------------------------------------- 1 | import { Dispatch } from 'react' 2 | 3 | export type ReducerPayload = Partial<{ 4 | state: T 5 | update: Dispatch> 6 | }> 7 | -------------------------------------------------------------------------------- /packages/web/shared/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "cg-config/src/tsconfig/paths/third-layer.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "allowJs": false, 6 | "esModuleInterop": false, 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true, 9 | "types": ["vite/client", "vitest"], 10 | "strictNullChecks": true 11 | }, 12 | "files": [], 13 | "include": [], 14 | "references": [ 15 | { 16 | "path": "./tsconfig.lib.json" 17 | }, 18 | { 19 | "path": "./tsconfig.spec.json" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /packages/web/shared/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "types": ["node", "vite/client"], 6 | "baseUrl": "." 7 | }, 8 | "files": [ 9 | "../../../node_modules/@nx/react/typings/cssmodule.d.ts", 10 | "../../../node_modules/@nx/react/typings/image.d.ts" 11 | ], 12 | "exclude": [ 13 | "**/*.spec.ts", 14 | "**/*.test.ts", 15 | "**/*.spec.tsx", 16 | "**/*.test.tsx", 17 | "**/*.spec.js", 18 | "**/*.test.js", 19 | "**/*.spec.jsx", 20 | "**/*.test.jsx" 21 | ], 22 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] 23 | } 24 | -------------------------------------------------------------------------------- /packages/web/shared/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node"] 6 | }, 7 | "include": [ 8 | "vite.config.ts", 9 | "src/**/*.test.ts", 10 | "src/**/*.spec.ts", 11 | "src/**/*.test.tsx", 12 | "src/**/*.spec.tsx", 13 | "src/**/*.test.js", 14 | "src/**/*.spec.js", 15 | "src/**/*.test.jsx", 16 | "src/**/*.spec.jsx", 17 | "src/**/*.d.ts" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /packages/web/ui/.babelrc: -------------------------------------------------------------------------------- 1 | {"extends": "cg-config/src/babel/vite.json"} 2 | -------------------------------------------------------------------------------- /packages/web/ui/.config/storybook/main.ts: -------------------------------------------------------------------------------- 1 | import type { StorybookConfig } from '@storybook/react-vite' 2 | import { createStorybookConfig } from 'cg-config/src/storybook' 3 | import { mergeConfig } from 'vite' 4 | import viteTsConfigPaths from 'vite-tsconfig-paths' 5 | 6 | const config: StorybookConfig = createStorybookConfig({ 7 | viteConfigPath: 'packages/web/ui/.config/vite.ts', 8 | viteFinal: (config: StorybookConfig): StorybookConfig => { 9 | return mergeConfig(config, { 10 | define: { 11 | 'process.env': process.env 12 | }, 13 | plugins: [viteTsConfigPaths()] 14 | }) 15 | } 16 | }) 17 | 18 | export default config 19 | -------------------------------------------------------------------------------- /packages/web/ui/.config/storybook/preview.ts: -------------------------------------------------------------------------------- 1 | import { StylesDecorator, ThemeDecorator } from '@code-gear/web/shared' 2 | import { Preview } from '@storybook/react' 3 | import { createPreviewDefaults } from '@code-gear/config' 4 | 5 | const preview: Preview = createPreviewDefaults({ 6 | decorators: [StylesDecorator, ThemeDecorator] 7 | }) 8 | 9 | export default preview 10 | -------------------------------------------------------------------------------- /packages/web/ui/.config/storybook/test-runner.config.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearonix/code-gear/428293078745619b14bce932d30b9b73e5cce08c/packages/web/ui/.config/storybook/test-runner.config.ts -------------------------------------------------------------------------------- /packages/web/ui/.config/vite.ts: -------------------------------------------------------------------------------- 1 | // It is important to specify relative paths here. 2 | import { resolve } from 'path' 3 | import react from '@vitejs/plugin-react' 4 | 5 | import { createViteConfig } from '../../../config/src/vite' 6 | 7 | export default createViteConfig({ 8 | projectName: 'shared', 9 | projectType: 'library', 10 | rootDir: resolve(__dirname, '..'), 11 | layer: 'third', 12 | external: ['react-smooth-scrollbar', 'antd'], 13 | plugins: [react()] 14 | }) 15 | -------------------------------------------------------------------------------- /packages/web/ui/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "../../../.eslintrc.js" 4 | ], 5 | "ignorePatterns": [ 6 | "!**/*", 7 | ".storybook" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /packages/web/ui/README.md: -------------------------------------------------------------------------------- 1 | # web-ui 2 | 3 | Reusable ui-kit with storybook. 4 | -------------------------------------------------------------------------------- /packages/web/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cg-ui", 3 | "version": "0.0.1", 4 | "main": "./index.js", 5 | "types": "./index.d.ts", 6 | "exports": { 7 | ".": { 8 | "import": "./index.mjs", 9 | "require": "./index.js" 10 | } 11 | }, 12 | "dependencies": { 13 | "cg-client-shared": "workspace:^" 14 | }, 15 | "devDependencies": { 16 | "cg-config": "workspace:^", 17 | "cg-generator": "workspace:^" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/web/ui/src/color-button/color-button.tsx: -------------------------------------------------------------------------------- 1 | import { WithChildren } from '@code-gear/web/shared' 2 | import { Button } from 'antd' 3 | import { ConfigProvider } from 'antd' 4 | import { ButtonProps } from 'antd/es/button' 5 | 6 | export type ColorButtonProps = ButtonProps & 7 | WithChildren<{ 8 | override: string 9 | }> 10 | 11 | const ColorButton = ({ children, override, ...props }: ColorButtonProps) => { 12 | const modifiedTheme = { 13 | token: { colorPrimary: override } 14 | } 15 | 16 | return ( 17 | 18 | 24 | 25 | ) 26 | } 27 | 28 | export default ColorButton 29 | -------------------------------------------------------------------------------- /packages/web/ui/src/index.ts: -------------------------------------------------------------------------------- 1 | export { default as ColoredButton } from './color-button/color-button' 2 | export { Modal, ModalSeparator, ModalTitle } from './modal' 3 | export { Popover } from './popover' 4 | export { Select } from './select/select' 5 | -------------------------------------------------------------------------------- /packages/web/ui/src/modal/hooks/use-modal-transitions.ts: -------------------------------------------------------------------------------- 1 | export const useModalTransitions = () => { 2 | return { 3 | opacity: { 4 | from: () => ({ opacity: 0 }), 5 | to: () => ({ opacity: 1 }) 6 | }, 7 | transform: { 8 | from: () => ({ 9 | transform: 'scale(0.9) rotate(8deg)', 10 | x: -150 11 | }), 12 | to: (isOpen: boolean) => ({ 13 | transform: isOpen 14 | ? 'scale(1.0) rotate(0deg)' 15 | : 'scale(0.9) rotate(8deg)', 16 | x: isOpen ? 0 : -150 17 | }) 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/web/ui/src/modal/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Modal } from './ui/modal' 2 | export { ModalSeparator, ModalTitle } from './ui/modal.styles' 3 | -------------------------------------------------------------------------------- /packages/web/ui/src/popover/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { usePopoverAnimation } from './use-popover-animation' 2 | -------------------------------------------------------------------------------- /packages/web/ui/src/popover/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Popover } from './ui/popover' 2 | -------------------------------------------------------------------------------- /packages/web/ui/src/popover/ui/popover.styles.tsx: -------------------------------------------------------------------------------- 1 | import { s } from '@code-gear/web/shared' 2 | import styled from 'styled-components' 3 | 4 | interface PopoverStylesProps { 5 | readonly $bottom: number 6 | } 7 | 8 | export const PopoverStyles = styled.div` 9 | padding-left: 15px; 10 | z-index: 15; 11 | position: fixed; 12 | right: 0; 13 | height: calc(100vh + 100px); 14 | width: calc(100% - 54px); 15 | border-radius: 6px 6px 0; 16 | background: ${s.color('darkBlue')}; 17 | border-top: 2px solid ${s.color('lightGrey')}; 18 | touch-action: none; 19 | bottom: ${({ $bottom }) => `calc(-100vh + ${$bottom - 100}px)`}; 20 | overflow-y: auto; 21 | box-sizing: border-box; 22 | scroll-behavior: smooth; 23 | ${s.customScrollbar()}; 24 | ` 25 | -------------------------------------------------------------------------------- /packages/web/ui/src/select/select.tsx: -------------------------------------------------------------------------------- 1 | import { Select as AntdSelect } from 'antd' 2 | 3 | export interface SelectProps { 4 | onChange: (val: T) => void 5 | value: T 6 | options: { 7 | value: T 8 | label: string | number 9 | }[] 10 | defaultValue?: T 11 | } 12 | 13 | export const Select = ({ 14 | onChange, 15 | value, 16 | options, 17 | defaultValue 18 | }: SelectProps) => { 19 | return ( 20 | 29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /packages/web/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "cg-config/src/tsconfig/paths/third-layer.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "allowJs": false, 6 | "esModuleInterop": false, 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true, 9 | "types": [ 10 | "vite/client", 11 | "vitest" 12 | ], 13 | "strictNullChecks": true 14 | }, 15 | "files": [], 16 | "include": [], 17 | "references": [ 18 | { 19 | "path": "./tsconfig.lib.json" 20 | }, 21 | { 22 | "path": "./tsconfig.spec.json" 23 | }, 24 | { 25 | "path": "./tsconfig.storybook.json" 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /packages/web/ui/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "types": [ 6 | "node", 7 | "vite/client" 8 | ], 9 | "baseUrl": "." 10 | }, 11 | "files": [ 12 | "../../../node_modules/@nx/react/typings/cssmodule.d.ts", 13 | "../../../node_modules/@nx/react/typings/image.d.ts" 14 | ], 15 | "exclude": [ 16 | "**/*.spec.ts", 17 | "**/*.test.ts", 18 | "**/*.spec.tsx", 19 | "**/*.test.tsx", 20 | "**/*.spec.js", 21 | "**/*.test.js", 22 | "**/*.spec.jsx", 23 | "**/*.test.jsx", 24 | "**/*.stories.ts", 25 | "**/*.stories.js", 26 | ], 27 | "include": [ 28 | "**/*.js", 29 | "**/*.jsx", 30 | "**/*.ts", 31 | "**/*.tsx", 32 | "**/*.stories.tsx" 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /packages/web/ui/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node"] 6 | }, 7 | "include": [ 8 | "vite.config.ts", 9 | "src/**/*.test.ts", 10 | "src/**/*.spec.ts", 11 | "src/**/*.test.tsx", 12 | "src/**/*.spec.tsx", 13 | "src/**/*.test.js", 14 | "src/**/*.spec.js", 15 | "src/**/*.test.jsx", 16 | "src/**/*.spec.jsx", 17 | "src/**/*.d.ts" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /packages/web/ui/tsconfig.storybook.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "emitDecoratorMetadata": true, 5 | "outDir": "", 6 | }, 7 | "files": [ 8 | "../../../node_modules/@nx/react/typings/styled-jsx.d.ts", 9 | "../../../node_modules/@nx/react/typings/cssmodule.d.ts", 10 | "../../../node_modules/@nx/react/typings/image.d.ts" 11 | ], 12 | "exclude": [ 13 | "src/**/*.spec.ts", 14 | "src/**/*.test.ts", 15 | "src/**/*.spec.js", 16 | "src/**/*.test.js", 17 | "src/**/*.spec.tsx", 18 | "src/**/*.test.tsx", 19 | "src/**/*.spec.jsx", 20 | "src/**/*.test.js" 21 | ], 22 | "include": [ 23 | "src/**/*.stories.ts", 24 | "src/**/*.stories.js", 25 | "src/**/*.stories.jsx", 26 | "src/**/*.stories.tsx", 27 | "src/**/*.stories.mdx", 28 | ".storybook/*.js", 29 | ".storybook/*.ts" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /tools/database/dump.sql: -------------------------------------------------------------------------------- 1 | /*!40101 SET @saved_cs_client = @@character_set_client */; 2 | /*!50503 SET character_set_client = utf8mb4 */; 3 | CREATE TABLE `users` ( 4 | `username` varchar(14) NOT NULL, 5 | `password` varchar(14) NOT NULL, 6 | `registrationDate` date DEFAULT (curdate()) 7 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 8 | /*!40101 SET character_set_client = @saved_cs_client */; 9 | -------------------------------------------------------------------------------- /tools/dev/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cg-tools", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /tools/dev/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dev", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "tools/dev/src", 5 | "tags": [] 6 | } 7 | -------------------------------------------------------------------------------- /tools/dev/src/env/.gitignore: -------------------------------------------------------------------------------- 1 | !.env 2 | !.override.env 3 | -------------------------------------------------------------------------------- /tools/dev/src/env/.override.env: -------------------------------------------------------------------------------- 1 | ### THIS IS AN EXAMPLE .env FILE! ### 2 | 3 | ### override ### 4 | 5 | DATABASE_URL=mysql://grnx:cgroot@db:3306/codegeardb 6 | SERVER_KAFKA_BROKERS=kafka:9092 7 | -------------------------------------------------------------------------------- /tools/dev/src/img/architecture_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearonix/code-gear/428293078745619b14bce932d30b9b73e5cce08c/tools/dev/src/img/architecture_diagram.png -------------------------------------------------------------------------------- /tools/dev/src/img/git_flow_trunk_based.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearonix/code-gear/428293078745619b14bce932d30b9b73e5cce08c/tools/dev/src/img/git_flow_trunk_based.png -------------------------------------------------------------------------------- /tools/dev/src/img/microfrontend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearonix/code-gear/428293078745619b14bce932d30b9b73e5cce08c/tools/dev/src/img/microfrontend.png -------------------------------------------------------------------------------- /tools/dev/src/img/nestjs_folders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearonix/code-gear/428293078745619b14bce932d30b9b73e5cce08c/tools/dev/src/img/nestjs_folders.png -------------------------------------------------------------------------------- /tools/generators/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: './../../.eslintrc.js', 3 | ignorePatterns: ['!**/*', '*.json'] 4 | } 5 | -------------------------------------------------------------------------------- /tools/generators/generators.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "microservice": { 4 | "factory": "./src/microservice/generator", 5 | "schema": "./src/microservice/schema.json", 6 | "description": "microservice generator" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tools/generators/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cg-global-generator", 3 | "version": "0.0.1", 4 | "private": true, 5 | "type": "commonjs", 6 | "main": "./src/index.js", 7 | "typings": "./src/index.d.ts", 8 | "executors": "./executors.json", 9 | "generators": "./generators.json" 10 | } 11 | -------------------------------------------------------------------------------- /tools/generators/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "global-generator", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "tools/generators/src", 5 | "projectType": "library", 6 | "targets": { 7 | "lint": { 8 | "executor": "@nx/linter:eslint", 9 | "outputs": [ 10 | "{options.outputFile}" 11 | ], 12 | "options": { 13 | "lintFilePatterns": [ 14 | "tools/generators/**/**.ts", 15 | "tools/generators/package.json", 16 | "tools/generators/generators.json" 17 | ] 18 | } 19 | } 20 | }, 21 | "tags": [] 22 | } 23 | -------------------------------------------------------------------------------- /tools/generators/src/microservice/files/.config/jest.ts.template: -------------------------------------------------------------------------------- 1 | import { createJestConfig } from 'cg-config/src/jest' 2 | 3 | export default createJestConfig({ 4 | displayName: 'service-<%= name %>', 5 | layer: 'second', 6 | }) 7 | -------------------------------------------------------------------------------- /tools/generators/src/microservice/files/.config/webpack.ts.template: -------------------------------------------------------------------------------- 1 | const { buildWebpackConfig } = require('cg-config/src/webpack') 2 | const { resolve } = require('path') 3 | 4 | module.exports = buildWebpackConfig({ 5 | rootDir: resolve(__dirname, '..'), 6 | layer: 'third', 7 | }) 8 | -------------------------------------------------------------------------------- /tools/generators/src/microservice/files/.eslintrc.js.template: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['../../../.eslintrc.js'], 3 | ignorePatterns: ['!**/*'] 4 | } 5 | -------------------------------------------------------------------------------- /tools/generators/src/microservice/files/Dockerfile.template: -------------------------------------------------------------------------------- 1 | FROM --platform=linux/amd64 node:20.8.0-alpine as build 2 | WORKDIR /opt/app 3 | 4 | ## Installing dependencies ## 5 | 6 | COPY package.json yarn.lock .yarnrc.yml ./ 7 | COPY .yarn .yarn 8 | 9 | COPY packages/config/package.json packages/config/package.json 10 | 11 | RUN yarn install 12 | 13 | ## Copying source code ## 14 | 15 | COPY apps/server/service-<%= name %> apps/server/service-<%= name %> 16 | 17 | COPY packages packages 18 | 19 | RUN yarn install 20 | 21 | COPY . . 22 | 23 | ## Building app to produciton ## 24 | 25 | RUN yarn nx run service-<%= name %>:build 26 | 27 | ## Entrypoint ## 28 | 29 | FROM --platform=linux/amd64 node:20.8.0-alpine 30 | WORKDIR /opt/app 31 | 32 | COPY --from=build /opt/app/dist/apps/server/service-<%= name %> ./ 33 | 34 | RUN sed -i '/workspace:/d' package.json 35 | 36 | RUN npm install --omit="dev" --force 37 | 38 | ENTRYPOINT node ./main.js 39 | -------------------------------------------------------------------------------- /tools/generators/src/microservice/files/README.md.template: -------------------------------------------------------------------------------- 1 | ## <%= name %> microservice 2 | 3 | generated by `tools/cg-global-generator` 4 | -------------------------------------------------------------------------------- /tools/generators/src/microservice/files/package.json.template: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cg-service-<%= name %>", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "cg-api-common": "workspace:^", 6 | "cg-api-contracts": "workspace:^" 7 | }, 8 | "devDependencies": { 9 | "cg-config": "workspace:^" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tools/generators/src/microservice/files/src/__name__.consumer.ts.template: -------------------------------------------------------------------------------- 1 | import { Controller } from '@nestjs/common' 2 | import { QueryBus } from '@nestjs/cqrs' 3 | 4 | @Controller() 5 | export class TemplateConsumer { 6 | constructor(private readonly query: QueryBus) {} 7 | 8 | } 9 | -------------------------------------------------------------------------------- /tools/generators/src/microservice/files/src/__name__.module.ts.template: -------------------------------------------------------------------------------- 1 | import { HttpModule } from '@nestjs/axios' 2 | import { Module } from '@nestjs/common' 3 | 4 | import { TemplateConsumer } from './<%= name %>.consumer' 5 | import { EnvModule } from '@code-gear/api/common' 6 | import { ListenerModule } from '@code-gear/api/common' 7 | import { KafkaService } from '@code-gear/api/common' 8 | import { QueryHandlers } from '@/queries/handlers' 9 | import { CqrsModule } from '@nestjs/cqrs' 10 | 11 | @Module({ 12 | imports: [ 13 | HttpModule, 14 | EnvModule, 15 | CqrsModule, 16 | ListenerModule.forRoot({ 17 | isMicroservice: true, 18 | }), 19 | ], 20 | providers: [KafkaService, ...QueryHandlers], 21 | controllers: [TemplateConsumer], 22 | exports: [], 23 | }) 24 | export class TemplateModule {} 25 | -------------------------------------------------------------------------------- /tools/generators/src/microservice/files/src/lib/index.ts.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearonix/code-gear/428293078745619b14bce932d30b9b73e5cce08c/tools/generators/src/microservice/files/src/lib/index.ts.template -------------------------------------------------------------------------------- /tools/generators/src/microservice/files/src/queries/handlers/index.ts.template: -------------------------------------------------------------------------------- 1 | export const QueryHandlers = [] 2 | -------------------------------------------------------------------------------- /tools/generators/src/microservice/files/src/queries/impl/index.ts.template: -------------------------------------------------------------------------------- 1 | export * from './execute-code.query' 2 | -------------------------------------------------------------------------------- /tools/generators/src/microservice/files/tsconfig.app.json.template: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["node"], 7 | "emitDecoratorMetadata": true, 8 | "target": "es2021", 9 | "baseUrl": "." 10 | }, 11 | "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"], 12 | "include": ["src/**/*.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /tools/generators/src/microservice/files/tsconfig.json.template: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "cg-config/src/tsconfig/paths/third-layer.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.app.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "esModuleInterop": true, 15 | "resolveJsonModule": true, 16 | "strictNullChecks": true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tools/generators/src/microservice/files/tsconfig.spec.json.template: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "src/**/*.test.ts", 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /tools/generators/src/microservice/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "Microservice", 4 | "title": "microservice", 5 | "type": "object", 6 | "properties": { 7 | "name": { 8 | "type": "string", 9 | "description": "", 10 | "$default": { 11 | "$source": "argv", 12 | "index": 0 13 | }, 14 | "x-prompt": "What name would you like to use?" 15 | } 16 | }, 17 | "required": ["name"] 18 | } 19 | -------------------------------------------------------------------------------- /tools/generators/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs" 5 | }, 6 | "files": [], 7 | "include": [], 8 | "references": [ 9 | { 10 | "path": "./tsconfig.lib.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /tools/generators/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": ["node"] 7 | }, 8 | "include": ["src/**/*.ts"], 9 | "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /tools/scripts/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.js"], 3 | "ignorePatterns": ["!**/*"] 4 | } 5 | -------------------------------------------------------------------------------- /tools/scripts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cg-scripts", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "cg-config": "workspace:^" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tools/scripts/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scripts", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "tools/scripts/src", 5 | "tags": [], 6 | "projectType": "library", 7 | "targets": { 8 | "run": { 9 | "command": "ts-node -r tsconfig-paths/register src/ts-morph/{args.script}", 10 | "options": { 11 | "cwd": "tools/scripts" 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tools/scripts/src/lib/run-project-files.ts: -------------------------------------------------------------------------------- 1 | import { join } from 'path' 2 | import { Project } from 'ts-morph' 3 | import { SourceFile } from 'ts-morph' 4 | 5 | const resolveRoot = () => join(__dirname, '..', '..') 6 | 7 | const runProjectFiles = async (cb: (file: SourceFile) => void) => { 8 | const project = new Project({ 9 | tsConfigFilePath: join(resolveRoot(), 'tsconfig.base.json') 10 | }) 11 | 12 | project.addSourceFilesAtPaths('../../packages/**/*.ts') 13 | project.addSourceFilesAtPaths('../../packages/**/*.tsx') 14 | project.addSourceFilesAtPaths('../../apps/**/*.ts') 15 | project.addSourceFilesAtPaths('../../apps/**/*.tsx') 16 | 17 | const files = project.getSourceFiles() 18 | 19 | files.forEach(cb) 20 | 21 | return project 22 | } 23 | 24 | export { runProjectFiles } 25 | -------------------------------------------------------------------------------- /tools/scripts/src/ts-morph/check-uppercase-files.ts: -------------------------------------------------------------------------------- 1 | import { runProjectFiles } from '@/lib/helpers' 2 | 3 | runProjectFiles((sourceFile) => { 4 | const name = sourceFile.getBaseName() 5 | if (name !== name.toLowerCase()) { 6 | console.log(name) 7 | } 8 | }) 9 | -------------------------------------------------------------------------------- /tools/scripts/src/ts-morph/remove-all-console-logs.ts: -------------------------------------------------------------------------------- 1 | import { join } from 'path' 2 | import { Project } from 'ts-morph' 3 | import { SyntaxKind } from 'ts-morph' 4 | 5 | const resolveRoot = () => join(__dirname, '..', '..') 6 | 7 | const project = new Project({ 8 | tsConfigFilePath: join(resolveRoot(), 'tsconfig.base.json') 9 | }) 10 | 11 | const files = project.addSourceFilesFromTsConfig( 12 | '../../packages/editor/tsconfig.lib.json' 13 | ) 14 | 15 | console.log(`Success. Number of files: ${files.length}`) 16 | 17 | files.forEach((sourceFile) => { 18 | const callExpressions = sourceFile.getVariableDeclarations().flatMap((s) => { 19 | return s.getChildrenOfKind(SyntaxKind.CallExpression) 20 | }) 21 | 22 | callExpressions.forEach((expression) => { 23 | console.log(expression.getArguments()) 24 | }) 25 | }) 26 | 27 | // project.save() 28 | -------------------------------------------------------------------------------- /tools/scripts/src/ts-morph/rename-client-shared.ts: -------------------------------------------------------------------------------- 1 | import { runProjectFiles } from '@/lib/helpers' 2 | 3 | const isClientSharedPath = (value: string) => { 4 | const matcher = value.split('/') 5 | return matcher[0] === '$' && matcher[1] === 'shared' 6 | } 7 | 8 | runProjectFiles((sourceFile) => { 9 | const importDeclarations = sourceFile.getImportDeclarations() 10 | importDeclarations.forEach((declaration) => { 11 | const importPath = declaration.getModuleSpecifierValue() 12 | 13 | if (isClientSharedPath(importPath)) { 14 | declaration.setModuleSpecifier('@code-gear/web/shared') 15 | } 16 | }) 17 | }).then((project) => { 18 | project.save() 19 | }) 20 | -------------------------------------------------------------------------------- /tools/scripts/src/ts-morph/rename-imports/consts.ts: -------------------------------------------------------------------------------- 1 | export interface ProjectPath { 2 | target: string | string[] 3 | replacement: string 4 | } 5 | 6 | export const projectPaths: ProjectPath[] = [ 7 | { 8 | target: ['@code-gear/web/shared', '$/assets', '$/styles', '$/icons'], 9 | replacement: '@code-gear/web/shared' 10 | }, 11 | { 12 | target: '$/editor', 13 | replacement: '@code-gear/web/editor' 14 | }, 15 | { 16 | target: '$/ui', 17 | replacement: '@code-gear/web/ui' 18 | }, 19 | { 20 | target: ['$/common-types', '$/nest-common'], 21 | replacement: '@code-gear/api/common' 22 | }, 23 | { 24 | target: '$/services', 25 | replacement: '@code-gear/api/services' 26 | }, 27 | { 28 | target: '$/config', 29 | replacement: '@code-gear/config' 30 | } 31 | ] 32 | -------------------------------------------------------------------------------- /tools/scripts/src/ts-morph/rename-imports/script.ts: -------------------------------------------------------------------------------- 1 | import { runProjectFiles } from '../../lib/helpers' 2 | import { ProjectPath } from './consts' 3 | import { projectPaths } from './consts' 4 | 5 | const renameImports = async (projectPaths: ProjectPath[]) => { 6 | const project = await runProjectFiles((sourceFile) => { 7 | const importDeclarations = sourceFile.getImportDeclarations() 8 | importDeclarations.forEach((declaration) => { 9 | const importPath = declaration.getModuleSpecifierValue() 10 | const projectMatcher = projectPaths.find( 11 | (path) => path.target === importPath 12 | ) 13 | 14 | if (projectMatcher) { 15 | declaration.setModuleSpecifier(projectMatcher.replacement) 16 | } 17 | }) 18 | }) 19 | 20 | project.save() 21 | } 22 | 23 | renameImports(projectPaths) 24 | -------------------------------------------------------------------------------- /tools/scripts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "cg-config/src/tsconfig/paths/second-layer.json", 3 | "compilerOptions": { 4 | "outDir": "../dist/out-tsc/tools", 5 | "rootDir": ".", 6 | "baseUrl": ".", 7 | "module": "commonjs", 8 | "esModuleInterop": true, 9 | "target": "es5", 10 | "types": ["node"], 11 | "importHelpers": false 12 | }, 13 | "include": ["**/*.ts"] 14 | } 15 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "cg-config/src/tsconfig/base.json", 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "rootDir": ".", 6 | "baseUrl": ".", 7 | "skipLibCheck": true 8 | }, 9 | "exclude": ["node_modules", "tmp"] 10 | } 11 | --------------------------------------------------------------------------------