├── .github └── workflows │ ├── chromatic.yaml │ ├── dev_greenonsoftware-dev-api.yml │ ├── e2e.yaml │ ├── prod_greenonsoftware-api.yml │ └── units.yaml ├── .vscode ├── cb.code-snippets ├── cmp.code-snippets ├── csb.code-snippets ├── ex.code-snippets ├── hk.code-snippets ├── pg.code-snippets └── vfn.code-snippets ├── COMMANDS.md ├── CONTRIBUTION.md ├── FAQ.md ├── README.md ├── dotnet └── GreenOnSoftware │ ├── .editorconfig │ ├── .gitattributes │ ├── .gitignore │ ├── GreenOnSoftware.Api │ ├── Context │ │ ├── Context.cs │ │ ├── ContextAccessor.cs │ │ ├── ContextConfig.cs │ │ └── IdentityContext.cs │ ├── Controllers │ │ ├── AccountController.cs │ │ ├── ArticlesController.cs │ │ ├── ReviewsController.cs │ │ ├── SnippetsController.cs │ │ └── UsersController.cs │ ├── Filters │ │ └── LogAttribute.cs │ ├── GreenOnSoftware.Api.csproj │ ├── Middlewares │ │ ├── ExceptionHandlingMiddleware.cs │ │ └── LogUsernameMiddleware.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Startup │ │ ├── DbContextConfig.cs │ │ ├── IdentityConfig.cs │ │ └── InvalidModelStateResponseFactory.cs │ ├── appsettings.Development.json │ ├── appsettings.dev.json │ ├── appsettings.json │ └── appsettings.prod.json │ ├── GreenOnSoftware.Application │ ├── Account │ │ ├── ChangePasswordCommand │ │ │ ├── ChangePassword.cs │ │ │ ├── ChangePasswordHandler.cs │ │ │ └── ChangePasswordValidator.cs │ │ ├── ForgottenPasswordCommand │ │ │ ├── ForgottenPassword.cs │ │ │ ├── ForgottenPasswordHandler.cs │ │ │ └── ForgottenPasswordValidator.cs │ │ ├── GetAvatarNameQuery │ │ │ ├── GetAvatarName.cs │ │ │ └── GetAvatarNameHandler.cs │ │ ├── RegisterCommand │ │ │ ├── RegistarHandler.cs │ │ │ ├── Register.cs │ │ │ └── RegisterValidator.cs │ │ ├── ResetPasswordCommand │ │ │ ├── ResetPassword.cs │ │ │ ├── ResetPasswordHandler.cs │ │ │ └── ResetPasswordValidator.cs │ │ ├── SetAvatarNameCommand │ │ │ ├── SetAvatarName.cs │ │ │ ├── SetAvatarNameHandler.cs │ │ │ └── SetAvatarNameValidator.cs │ │ ├── SignInCommand │ │ │ ├── SignIn.cs │ │ │ └── SignInHandler.cs │ │ └── SignOutCommand │ │ │ ├── SignOut.cs │ │ │ └── SignOutHandler.cs │ ├── Articles │ │ ├── AcceptArticleCommand │ │ │ ├── AcceptArticle.cs │ │ │ └── AcceptArticleHandler.cs │ │ ├── AddArticleCommand │ │ │ ├── AddArticle.cs │ │ │ ├── AddArticleHandler.cs │ │ │ └── AddArticleValidator.cs │ │ ├── DeleteArticleCommand │ │ │ ├── DeleteArticle.cs │ │ │ └── DeleteArticleHandler.cs │ │ ├── GetArticleByIdQuery │ │ │ ├── ArticleDto.cs │ │ │ ├── CommentDto.cs │ │ │ ├── GetArticleById.cs │ │ │ └── GetArticleByIdHandler.cs │ │ ├── GetArticlesQuery │ │ │ ├── ArticleLookupDto.cs │ │ │ ├── GetArticles.cs │ │ │ ├── GetArticlesHandler.cs │ │ │ └── GetArticlesValidator.cs │ │ ├── RejectArticleCommand │ │ │ ├── RejectArticle.cs │ │ │ └── RejectArticleHandler.cs │ │ ├── SendForApprovalCommand │ │ │ ├── SendForApproval.cs │ │ │ └── SendForApprovalHandler.cs │ │ └── UpdateArticleCommand │ │ │ ├── UpdateArticle.cs │ │ │ ├── UpdateArticleHandler.cs │ │ │ └── UpdateArticleValidator.cs │ ├── DependencyInjection.cs │ ├── GreenOnSoftware.Application.csproj │ ├── Ratings │ │ ├── AddArticleRateCommand │ │ │ ├── AddArticleRate.cs │ │ │ ├── AddArticleRateHandler.cs │ │ │ └── AddArticleRateValidator.cs │ │ ├── GetArticleRatingQuery │ │ │ ├── GetArticleRatings.cs │ │ │ ├── GetArticleRatingsHandler.cs │ │ │ └── RatingsDto.cs │ │ ├── RemoveArticleRateCommand │ │ │ ├── RemoveArticleRate.cs │ │ │ └── RemoveArticleRateHandler.cs │ │ └── UpdateArticleRate │ │ │ ├── UpdateArticleRate.cs │ │ │ ├── UpdateArticleRateHandler.cs │ │ │ └── UpdateArticleRateValidator.cs │ ├── Reviews │ │ ├── AddReviewCommand │ │ │ ├── AddReview.cs │ │ │ ├── AddReviewHandler.cs │ │ │ └── AddReviewValidator.cs │ │ ├── DeleteReviewCommand │ │ │ ├── DeleteReview.cs │ │ │ └── DeleteReviewHandler.cs │ │ ├── GetAllReviewerReviewsQuery │ │ │ ├── GetAllReviewerReviews.cs │ │ │ └── GetAllReviewerReviewsHandler.cs │ │ ├── GetReviewByIdQuery │ │ │ ├── GetReviews.cs │ │ │ └── GetReviewsHandler.cs │ │ ├── GetReviewsQuery │ │ │ ├── GetReviews.cs │ │ │ └── GetReviewsHandler.cs │ │ └── UpdateReviewCommand │ │ │ ├── UpdateReview.cs │ │ │ ├── UpdateReviewHandler.cs │ │ │ └── UpdateReviewValidator.cs │ ├── Snippets │ │ ├── AddSnippetCommand │ │ │ ├── AddSnippet.cs │ │ │ ├── AddSnippetHandler.cs │ │ │ └── AddSnippetValidator.cs │ │ └── GetSnippetByIdQuery │ │ │ ├── GetSnippetById.cs │ │ │ ├── GetSnippetByIdHandler.cs │ │ │ ├── GetSnippetByIdValidator.cs │ │ │ └── SnippetDto.cs │ ├── Users │ │ ├── AddToRoleCommand │ │ │ ├── AddToRole.cs │ │ │ ├── AddToRoleHandler.cs │ │ │ └── AddToRoleValidator.cs │ │ ├── GetUsersQuery │ │ │ ├── GetUsers.cs │ │ │ ├── GetUsersHandler.cs │ │ │ ├── GetUsersValidator.cs │ │ │ └── UserLookupDto.cs │ │ └── RemoveFromRoleCommand │ │ │ ├── RemoveFromRole.cs │ │ │ ├── RemoveFromRoleHandler.cs │ │ │ └── RemoveFromRoleValidator.cs │ ├── _Configuration │ │ └── ApplicationConfiguration.cs │ ├── _Dtos │ │ ├── ICurrentUserReviewer.cs │ │ ├── ReviewDto.cs │ │ ├── ReviewLookupDto.cs │ │ └── UserReviewLookupDto.cs │ ├── _Mapper │ │ ├── ArticlesMapperProfile.cs │ │ ├── MappingActions │ │ │ └── ReviewDtoAction.cs │ │ ├── SnippetsMapperProfile.cs │ │ └── UsersMapperProfile.cs │ └── _Services │ │ ├── EmailService.cs │ │ ├── Interfaces │ │ ├── IBlobStorageService.cs │ │ ├── IEmailSenderService.cs │ │ ├── IEmailService.cs │ │ ├── IRatingsSessionService.cs │ │ └── IThumbnailService.cs │ │ ├── RatingsSessionService.cs │ │ └── ThumbnailService.cs │ ├── GreenOnSoftware.Commons │ ├── CQRS │ │ └── ISearchQuery.cs │ ├── Clock │ │ ├── Clock.cs │ │ └── IClock.cs │ ├── Consts │ │ └── Role.cs │ ├── Context │ │ ├── IContext.cs │ │ ├── IContextAccessor.cs │ │ └── IIdentityContext.cs │ ├── Dtos │ │ ├── ErrorMessage.cs │ │ ├── PagedResult.cs │ │ └── Result.cs │ ├── Extensions │ │ ├── EnumExtensions.cs │ │ ├── IdentityResultExtensions.cs │ │ ├── QueryableExtensions.cs │ │ └── StringExtensions.cs │ ├── GreenOnSoftware.Commons.csproj │ └── Resources │ │ ├── ErrorMessages.Designer.cs │ │ └── ErrorMessages.resx │ ├── GreenOnSoftware.Core │ ├── Enums │ │ ├── SnippetFrameAnimationType.cs │ │ └── Status.cs │ ├── GreenOnSoftware.Core.csproj │ ├── Identity │ │ ├── User.cs │ │ └── UserRole.cs │ └── Models │ │ ├── Article.cs │ │ ├── Comment.cs │ │ ├── Ratings │ │ ├── AnnonymousArticleRate.cs │ │ └── UserArticleRate.cs │ │ ├── Reviews │ │ └── Review.cs │ │ ├── Snippets │ │ ├── Snippet.cs │ │ └── SnippetFrame.cs │ │ └── _Entity.cs │ ├── GreenOnSoftware.DataAccess │ ├── Configuration │ │ ├── AnnonymousRateConfiguration.cs │ │ ├── ArticleConfiguration.cs │ │ ├── CommentConfiguration.cs │ │ ├── ReviewConfiguration.cs │ │ ├── SnippetConfiguration.cs │ │ ├── UserConfiguration.cs │ │ ├── UserRateConfiguration.cs │ │ └── UserRoleConfiguration.cs │ ├── Converters │ │ └── SnippetFramesValueConverter.cs │ ├── GreenOnSoftware.DataAccess.csproj │ ├── GreenOnSoftwareDbContext.cs │ └── Migrations │ │ ├── 20221104151505_Init.Designer.cs │ │ ├── 20221104151505_Init.cs │ │ ├── 20230531122339_AddSnippetsCreator.Designer.cs │ │ ├── 20230531122339_AddSnippetsCreator.cs │ │ ├── 20230603075206_SetSnippetGifUrlOptional.Designer.cs │ │ ├── 20230603075206_SetSnippetGifUrlOptional.cs │ │ └── GreenOnSoftwareDbContextModelSnapshot.cs │ ├── GreenOnSoftware.Infrastructure │ ├── BlobStorage │ │ ├── BlobStorageConfiguration.cs │ │ └── BlobStorageService.cs │ ├── DependencyInjection.cs │ ├── GreenOnSoftware.Infrastructure.csproj │ ├── Security │ │ ├── GreenOnSoftwareDatabaseInitializer.cs │ │ └── SecurityConfiguration.cs │ └── SendGrid │ │ ├── EmailSenderService.cs │ │ └── SendGridConfiguration.cs │ └── GreenOnSoftware.sln └── system ├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── .husky └── pre-commit ├── .prettierignore ├── .prettierrc ├── .vscode └── extensions.json ├── README.md ├── apps ├── .gitkeep ├── blog-creator-e2e │ ├── .eslintrc.json │ ├── cypress.config.ts │ ├── project.json │ ├── src │ │ ├── e2e │ │ │ └── app.cy.ts │ │ ├── fixtures │ │ │ └── example.json │ │ └── support │ │ │ ├── app.po.ts │ │ │ ├── commands.ts │ │ │ └── e2e.ts │ └── tsconfig.json ├── blog-creator │ ├── .babelrc │ ├── .eslintrc.json │ ├── jest.config.ts │ ├── project.json │ ├── src │ │ ├── app │ │ │ ├── app.spec.tsx │ │ │ └── app.tsx │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ └── main.tsx │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ └── webpack.config.js ├── blog-e2e │ ├── .eslintrc.json │ ├── cypress.config.ts │ ├── project.json │ ├── src │ │ ├── e2e │ │ │ └── app.cy.ts │ │ ├── fixtures │ │ │ └── example.json │ │ └── support │ │ │ ├── app.po.ts │ │ │ ├── commands.ts │ │ │ └── e2e.ts │ └── tsconfig.json ├── blog │ ├── .eslintrc.json │ ├── components │ │ ├── PageWrapper.tsx │ │ ├── index.tsx │ │ ├── link │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ └── link.tsx │ │ └── main-layout │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ └── main-layout.tsx │ ├── consts │ │ └── index.ts │ ├── content │ │ ├── en │ │ │ └── articles │ │ │ │ └── use-ref-hook.mdx │ │ └── pl │ │ │ └── articles │ │ │ └── use-ref-hook.mdx │ ├── dk │ │ ├── index.ts │ │ ├── lang.ts │ │ ├── tests │ │ │ ├── lang.test.ts │ │ │ └── use-lang.test.ts │ │ └── use-lang.ts │ ├── index.d.ts │ ├── jest.config.ts │ ├── models │ │ └── index.ts │ ├── next-env.d.ts │ ├── next.config.js │ ├── pages │ │ ├── _app.tsx │ │ ├── _document.tsx │ │ ├── en │ │ │ ├── articles │ │ │ │ ├── [id].tsx │ │ │ │ └── index.tsx │ │ │ └── index.tsx │ │ ├── index.tsx │ │ └── pl │ │ │ ├── articles │ │ │ ├── [id].tsx │ │ │ └── index.tsx │ │ │ └── index.tsx │ ├── project.json │ ├── public │ │ ├── .gitkeep │ │ └── fonts │ │ │ ├── LexendBold.ttf │ │ │ ├── LexendLight.ttf │ │ │ ├── LexendMedium.ttf │ │ │ └── LexendRegular.ttf │ ├── tsconfig.json │ ├── tsconfig.spec.json │ ├── utils │ │ ├── index.test.ts │ │ └── index.ts │ └── views │ │ └── home │ │ ├── defs.ts │ │ ├── home.view.tsx │ │ └── index.ts ├── jamjam-e2e │ ├── .eslintrc.json │ ├── cypress.config.ts │ ├── project.json │ ├── src │ │ ├── e2e │ │ │ └── guitar-notes-teacher.cy.ts │ │ ├── fixtures │ │ │ └── example.json │ │ └── support │ │ │ ├── app.po.ts │ │ │ ├── commands.ts │ │ │ └── e2e.ts │ └── tsconfig.json ├── jamjam │ ├── .eslintrc.json │ ├── components │ │ ├── guitar-fretboard │ │ │ ├── consts.ts │ │ │ ├── defs.ts │ │ │ ├── guitar-fretboard-strings.tsx │ │ │ ├── guitar-fretboard.tsx │ │ │ ├── index.ts │ │ │ ├── note-button.tsx │ │ │ └── tests │ │ │ │ ├── __snapshots__ │ │ │ │ └── guitar-fretboard-strings.test.tsx.snap │ │ │ │ ├── consts.test.ts │ │ │ │ ├── guitar-fretboard-strings.test.tsx │ │ │ │ ├── guitar-fretboard.test.tsx │ │ │ │ └── note-button.test.tsx │ │ └── index.ts │ ├── domain │ │ ├── index.ts │ │ └── music-theory │ │ │ ├── consts.ts │ │ │ ├── core.ts │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ └── tests │ │ │ ├── consts.test.ts │ │ │ └── core.test.ts │ ├── features │ │ └── guitar-notes-teacher │ │ │ ├── __snapshots__ │ │ │ └── guitar-notes-teacher.view.test.tsx.snap │ │ │ ├── components │ │ │ ├── index.ts │ │ │ └── links │ │ │ │ ├── __snapshots__ │ │ │ │ └── links.test.tsx.snap │ │ │ │ ├── index.ts │ │ │ │ ├── links.test.tsx │ │ │ │ └── links.tsx │ │ │ ├── guitar-notes-teacher.actions.test.ts │ │ │ ├── guitar-notes-teacher.actions.ts │ │ │ ├── guitar-notes-teacher.defs.ts │ │ │ ├── guitar-notes-teacher.feature.tsx │ │ │ ├── guitar-notes-teacher.selectors.ts │ │ │ ├── guitar-notes-teacher.view.test.tsx │ │ │ ├── guitar-notes-teacher.view.tsx │ │ │ ├── index.ts │ │ │ ├── use-guitar-notes-teacher.facade.test.ts │ │ │ └── use-guitar-notes-teacher.facade.ts │ ├── index.d.ts │ ├── jest.config.ts │ ├── next-env.d.ts │ ├── next.config.js │ ├── pages │ │ ├── _app.tsx │ │ ├── _document.tsx │ │ └── index.tsx │ ├── project.json │ ├── public │ │ ├── .gitkeep │ │ └── fonts │ │ │ ├── LexendBold.ttf │ │ │ ├── LexendLight.ttf │ │ │ ├── LexendMedium.ttf │ │ │ └── LexendRegular.ttf │ ├── specs │ │ └── index.spec.tsx │ ├── tsconfig.json │ ├── tsconfig.spec.json │ └── utils │ │ ├── index.test.ts │ │ └── index.ts ├── sparkle-flicks-e2e │ ├── .eslintrc.json │ ├── cypress.config.ts │ ├── project.json │ ├── src │ │ ├── e2e │ │ │ └── app.cy.ts │ │ ├── fixtures │ │ │ └── example.json │ │ └── support │ │ │ ├── commands.ts │ │ │ └── e2e.ts │ └── tsconfig.json └── sparkle-flicks │ ├── .eslintrc.json │ ├── index.d.ts │ ├── jest.config.ts │ ├── next-env.d.ts │ ├── next.config.js │ ├── pages │ ├── _app.tsx │ ├── _document.tsx │ └── index.tsx │ ├── project.json │ ├── public │ ├── .gitkeep │ └── fonts │ │ ├── LexendBold.ttf │ │ ├── LexendLight.ttf │ │ ├── LexendMedium.ttf │ │ └── LexendRegular.ttf │ ├── specs │ └── index.spec.tsx │ ├── tsconfig.json │ └── tsconfig.spec.json ├── assets └── fonts │ ├── LexendBold.ttf │ ├── LexendLight.ttf │ ├── LexendMedium.ttf │ └── LexendRegular.ttf ├── babel.config.json ├── build-storybook.log ├── jest.config.ts ├── jest.preset.js ├── libs ├── .gitkeep ├── blog-api │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── account.ts │ │ │ ├── articles.ts │ │ │ ├── index.ts │ │ │ └── instance.ts │ │ └── models │ │ │ ├── account.ts │ │ │ ├── articles.ts │ │ │ ├── general.ts │ │ │ └── index.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── figa-hooks │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── index.ts │ │ └── lib │ │ │ ├── use-click-outside │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ ├── use-click-outside.test.tsx │ │ │ └── use-click-outside.ts │ │ │ ├── use-client-effect │ │ │ ├── index.ts │ │ │ ├── use-client-effect.test.tsx │ │ │ └── use-client-effect.ts │ │ │ ├── use-client-layout-effect │ │ │ ├── index.ts │ │ │ ├── use-client-layout-effect.test.tsx │ │ │ └── use-client-layout-effect.tsx │ │ │ ├── use-intersection-observer │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ ├── use-intersection-observer.test.tsx │ │ │ └── use-intersection-observer.ts │ │ │ ├── use-portal │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ └── use-portal.tsx │ │ │ ├── use-scroll-y │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ ├── use-scroll-y.test.tsx │ │ │ └── use-scroll-y.ts │ │ │ ├── use-stepper │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ ├── use-stepper.test.tsx │ │ │ └── use-stepper.tsx │ │ │ └── use-toggle │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ └── use-toggle.tsx │ ├── tsconfig.json │ ├── tsconfig.lib.json │ ├── tsconfig.spec.json │ └── vite.config.ts ├── figa-ui │ ├── .eslintrc.json │ ├── .storybook │ │ ├── main.js │ │ ├── preview.tsx │ │ └── tsconfig.json │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── index.ts │ │ └── lib │ │ │ ├── article-layout │ │ │ ├── __snapshots__ │ │ │ │ └── article-layout.test.tsx.snap │ │ │ ├── article-layout.stories.tsx │ │ │ ├── article-layout.test.tsx │ │ │ ├── article-layout.tsx │ │ │ ├── defs.ts │ │ │ └── index.ts │ │ │ ├── blockquote │ │ │ ├── __snapshots__ │ │ │ │ └── blockquote.test.tsx.snap │ │ │ ├── blockquote.stories.tsx │ │ │ ├── blockquote.test.tsx │ │ │ ├── blockquote.tsx │ │ │ ├── defs.ts │ │ │ └── index.ts │ │ │ ├── box │ │ │ ├── __snapshots__ │ │ │ │ └── box.test.tsx.snap │ │ │ ├── box.stories.tsx │ │ │ ├── box.test.tsx │ │ │ ├── box.tsx │ │ │ ├── defs.ts │ │ │ └── index.ts │ │ │ ├── button │ │ │ ├── __snapshots__ │ │ │ │ └── button.test.tsx.snap │ │ │ ├── button.stories.tsx │ │ │ ├── button.test.tsx │ │ │ ├── button.tsx │ │ │ ├── consts.ts │ │ │ ├── defs.ts │ │ │ └── index.ts │ │ │ ├── code-block │ │ │ ├── __snapshots__ │ │ │ │ └── code-block.test.tsx.snap │ │ │ ├── code-block.stories.tsx │ │ │ ├── code-block.test.tsx │ │ │ ├── code-block.tsx │ │ │ ├── defs.ts │ │ │ └── index.ts │ │ │ ├── code │ │ │ ├── code.stories.tsx │ │ │ ├── code.test.tsx │ │ │ ├── code.tsx │ │ │ ├── consts.ts │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ ├── setup.test.ts │ │ │ └── setup.ts │ │ │ ├── emoji-picker │ │ │ ├── consts.ts │ │ │ ├── defs.ts │ │ │ ├── emoji-picker.stories.tsx │ │ │ ├── emoji-picker.test.tsx │ │ │ ├── emoji-picker.tsx │ │ │ └── index.ts │ │ │ ├── font │ │ │ ├── consts.ts │ │ │ ├── defs.ts │ │ │ ├── font.stories.tsx │ │ │ ├── font.tsx │ │ │ └── index.ts │ │ │ ├── footer │ │ │ ├── __snapshots__ │ │ │ │ └── footer.test.tsx.snap │ │ │ ├── defs.ts │ │ │ ├── footer.stories.tsx │ │ │ ├── footer.test.tsx │ │ │ ├── footer.tsx │ │ │ └── index.ts │ │ │ ├── icon │ │ │ ├── __snapshots__ │ │ │ │ └── icon.test.tsx.snap │ │ │ ├── defs.ts │ │ │ ├── icon.stories.tsx │ │ │ ├── icon.test.tsx │ │ │ ├── icon.tsx │ │ │ └── index.ts │ │ │ ├── input │ │ │ ├── __snapshots__ │ │ │ │ └── input.test.tsx.snap │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ ├── input.stories.tsx │ │ │ ├── input.test.tsx │ │ │ └── input.tsx │ │ │ ├── layout │ │ │ ├── __snapshots__ │ │ │ │ └── layout.test.tsx.snap │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ ├── layout.stories.tsx │ │ │ ├── layout.test.tsx │ │ │ └── layout.tsx │ │ │ ├── left-bar │ │ │ ├── __snapshots__ │ │ │ │ └── left-bar.test.tsx.snap │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ ├── left-bar.stories.tsx │ │ │ ├── left-bar.test.tsx │ │ │ └── left-bar.tsx │ │ │ ├── link │ │ │ ├── __snapshots__ │ │ │ │ └── link.test.tsx.snap │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ ├── link.stories.tsx │ │ │ ├── link.test.tsx │ │ │ └── link.tsx │ │ │ ├── list │ │ │ ├── __snapshots__ │ │ │ │ └── list.test.tsx.snap │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ ├── list.stories.tsx │ │ │ ├── list.test.tsx │ │ │ └── list.tsx │ │ │ ├── logo-graphic │ │ │ ├── __snapshots__ │ │ │ │ └── logo-graphic.test.tsx.snap │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ ├── logo-graphic.stories.tsx │ │ │ ├── logo-graphic.test.tsx │ │ │ └── logo-graphic.tsx │ │ │ ├── logo │ │ │ ├── __snapshots__ │ │ │ │ └── logo.test.tsx.snap │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ ├── logo.stories.tsx │ │ │ ├── logo.test.tsx │ │ │ └── logo.tsx │ │ │ ├── modal │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ ├── modal.stories.tsx │ │ │ └── modal.tsx │ │ │ ├── navigation │ │ │ ├── __snapshots__ │ │ │ │ └── navigation.test.tsx.snap │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ ├── navigation.stories.tsx │ │ │ ├── navigation.test.tsx │ │ │ └── navigation.tsx │ │ │ ├── popover │ │ │ ├── __snapshots__ │ │ │ │ └── popover.test.tsx.snap │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ ├── popover.stories.tsx │ │ │ ├── popover.test.tsx │ │ │ └── popover.tsx │ │ │ ├── progress-circle │ │ │ ├── __snapshots__ │ │ │ │ └── progress-circle.test.tsx.snap │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ ├── progress-circle.stories.tsx │ │ │ ├── progress-circle.test.tsx │ │ │ └── progress-circle.tsx │ │ │ ├── sandbox │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ └── sandbox.tsx │ │ │ ├── select │ │ │ ├── __snapshots__ │ │ │ │ └── select.test.tsx.snap │ │ │ ├── defs.ts │ │ │ ├── index.ts │ │ │ ├── select.stories.tsx │ │ │ ├── select.test.tsx │ │ │ └── select.tsx │ │ │ ├── shared │ │ │ ├── defs.ts │ │ │ ├── generators.ts │ │ │ └── index.ts │ │ │ └── theme-provider │ │ │ ├── defs.ts │ │ │ ├── global-style.ts │ │ │ ├── index.ts │ │ │ ├── theme-provider.tsx │ │ │ ├── themes.ts │ │ │ ├── viewport.test.ts │ │ │ └── viewport.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ ├── tsconfig.spec.json │ └── vite.config.ts └── utils │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ ├── index.ts │ └── lib │ │ ├── is-client.ts │ │ ├── is-server.ts │ │ ├── storage.ts │ │ └── tests │ │ ├── is-client.test.ts │ │ ├── is-server.test.ts │ │ └── storage.test.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── nx.json ├── package-lock.json ├── package.json ├── tools ├── generators │ └── .gitkeep └── tsconfig.tools.json └── tsconfig.base.json /.github/workflows/chromatic.yaml: -------------------------------------------------------------------------------- 1 | name: Chromatic 2 | 3 | on: 4 | pull_request: 5 | branches: ["develop", "main"] 6 | 7 | jobs: 8 | chromatic-deployment: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout repository 12 | uses: actions/checkout@v2 13 | with: 14 | fetch-depth: 0 15 | - name: Install dependencies 16 | run: | 17 | cd system 18 | npm install --legacy-peer-deps 19 | - name: Build storybook 20 | run: | 21 | cd system 22 | npm run build-storybook 23 | - name: Build storybook 24 | run: | 25 | cd system/dist/storybook/figa-ui 26 | npm run chromatic --project-token=${{ secrets.FIGA_UI_CHROMATIC_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/e2e.yaml: -------------------------------------------------------------------------------- 1 | name: Tests e2e 2 | 3 | on: 4 | pull_request: 5 | branches: ["develop", "main"] 6 | 7 | jobs: 8 | run-tests: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout repository 12 | uses: actions/checkout@v2 13 | with: 14 | fetch-depth: 0 15 | - name: Install dependencies 16 | run: | 17 | cd system 18 | npm install --legacy-peer-deps 19 | - name: Cypress e2e tests 20 | run: | 21 | cd system 22 | npm run e2e:checkAll -------------------------------------------------------------------------------- /.github/workflows/units.yaml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | pull_request: 5 | branches: ["develop", "main"] 6 | 7 | jobs: 8 | run-tests: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout repository 12 | uses: actions/checkout@v2 13 | with: 14 | fetch-depth: 0 15 | - name: Install dependencies 16 | run: | 17 | cd system 18 | npm install --legacy-peer-deps 19 | - name: Jest run test 20 | run: | 21 | cd system 22 | npm run test:checkAll -------------------------------------------------------------------------------- /.vscode/cb.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "ct": { 3 | "prefix": "ct", 4 | "body": [ 5 | "import { render, screen } from '@testing-library/react';", 6 | "import { ${1:example} } from './${2:example}';", 7 | "", 8 | "describe('${1:example} can be used when', () => {", 9 | " it('[FRAGILE] assigns classes', () => {", 10 | " const { container, asFragment } = render(", 11 | " <${1:example} className=\"my-class\">", 12 | " <>", 13 | " ", 14 | " );", 15 | "", 16 | " const component = container.querySelector('.${2:example}');", 17 | "", 18 | " expect(component?.className).toContain('${2:example} my-class');", 19 | " expect(asFragment()).toMatchSnapshot();", 20 | " });", 21 | "});", 22 | "" 23 | ], 24 | "description": "" 25 | } 26 | } -------------------------------------------------------------------------------- /.vscode/cmp.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "cmp": { 3 | "prefix": "cmp", 4 | "body": [ 5 | "import type { ${1:example}Props } from './defs';", 6 | "", 7 | "interface ${1:example}Props {", 8 | " ", 9 | "}", 10 | "", 11 | "export type { ${1:example}Props };", 12 | "", 13 | "const ${1:example}= ({ }: ${1:example}Props) => {", 14 | " return <${2:example}>", 15 | "};", 16 | "", 17 | "export { ${1:example}};", 18 | "" 19 | ], 20 | "description": "" 21 | } 22 | } -------------------------------------------------------------------------------- /.vscode/csb.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "csb": { 3 | "prefix": "csb", 4 | "body": [ 5 | "import type { Story, Meta } from '@storybook/react';", 6 | "", 7 | "import { ${1:example} } from './${2:example}';", 8 | "", 9 | "export default {", 10 | " component: ${1:example},", 11 | " title: '${1:example}',", 12 | "} as Meta;", 13 | "", 14 | "const Template: Story = () => {", 15 | " return (", 16 | "
", 17 | " ", 18 | "
", 19 | " );", 20 | "};", 21 | "", 22 | "export const Default = Template.bind({});", 23 | "Default.args = {};", 24 | "" 25 | ], 26 | "description": "" 27 | } 28 | } -------------------------------------------------------------------------------- /.vscode/ex.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "ex": { 3 | "prefix": "ex", 4 | "body": [ 5 | "export * from './${1:example}';", 6 | "export * from './defs';", 7 | "" 8 | ], 9 | "description": "" 10 | } 11 | } -------------------------------------------------------------------------------- /.vscode/hk.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "hk": { 3 | "prefix": "hk", 4 | "body": [ 5 | "import { useState } from 'react';", 6 | "", 7 | "interface ${3:example}{", 8 | "", 9 | "}", 10 | "", 11 | "interface ${4:example}{", 12 | "", 13 | "}", 14 | "", 15 | "type Use${1:example} = (payload: ${3:example}) => ${4:example};", 16 | "", 17 | "export type { ${3:example}, ${4:example}}", 18 | "", 19 | "const use${1:example} = (${2:example}: ${3:example}): ${4:example} => {", 20 | " const [value, setValue] = useState()", 21 | "", 22 | " const handleSm = () => {", 23 | "", 24 | " }", 25 | " ", 26 | " return {", 27 | "", 28 | " }", 29 | "}", 30 | "", 31 | "export { use${1:example} }" 32 | ], 33 | "description": "" 34 | } 35 | } -------------------------------------------------------------------------------- /.vscode/pg.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "pg": { 3 | "prefix": "pg", 4 | "body": [ 5 | "import { Font } from '@system/figa-ui';", 6 | "", 7 | "const ${1:example}= () => {", 8 | " return England;", 9 | "};", 10 | "", 11 | "export default ${1:example};", 12 | "" 13 | ], 14 | "description": "" 15 | } 16 | } -------------------------------------------------------------------------------- /.vscode/vfn.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "vfn": { 3 | "prefix": "vfn", 4 | "body": [ 5 | "const ${1:example} = (${2:example}: ${3:example}): void => {", 6 | "", 7 | "}" 8 | ], 9 | "description": "" 10 | } 11 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # CS8618: Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. 4 | dotnet_diagnostic.CS8618.severity = none 5 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Api/Context/Context.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Context; 2 | 3 | namespace GreenOnSoftware.Api.Context; 4 | 5 | public class Context : IContext 6 | { 7 | public IIdentityContext Identity { get; } 8 | 9 | public Context(HttpContext httpContext) 10 | { 11 | Identity = new IdentityContext(httpContext); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Api/Context/ContextAccessor.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Context; 2 | 3 | namespace GreenOnSoftware.Api.Context; 4 | 5 | public class ContextAccessor : IContextAccessor 6 | { 7 | private static readonly AsyncLocal Holder = new(); 8 | 9 | public IContext? Context 10 | { 11 | get => Holder.Value?.Context; 12 | set 13 | { 14 | var holder = Holder.Value; 15 | if (holder != null) 16 | { 17 | holder.Context = null; 18 | } 19 | 20 | if (value != null) 21 | { 22 | Holder.Value = new ContextHolder { Context = value }; 23 | } 24 | } 25 | } 26 | 27 | private class ContextHolder 28 | { 29 | public IContext? Context { get; set; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Api/Context/ContextConfig.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Context; 2 | 3 | namespace GreenOnSoftware.Api.Context; 4 | 5 | public static class ContextConfig 6 | { 7 | public static IServiceCollection AddIdentityContext(this IServiceCollection services) 8 | { 9 | services.AddSingleton(); 10 | services.AddScoped(s => s.GetRequiredService().Context!); 11 | 12 | return services; 13 | } 14 | 15 | public static IApplicationBuilder UseIdentityContext(this IApplicationBuilder app) 16 | { 17 | app.Use((ctx, next) => { 18 | ctx.RequestServices.GetRequiredService().Context = new Context(ctx); 19 | 20 | return next(); 21 | }); 22 | 23 | return app; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Api/Filters/LogAttribute.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc.Filters; 2 | using Serilog; 3 | 4 | namespace GreenOnSoftware.Api.Filters; 5 | 6 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] 7 | public class LogAttribute : ActionFilterAttribute 8 | { 9 | public override void OnActionExecuting(ActionExecutingContext context) 10 | { 11 | Log.Information($"Started processing request {context.HttpContext.Request.Path}"); 12 | } 13 | 14 | public override void OnActionExecuted(ActionExecutedContext context) 15 | { 16 | string message; 17 | 18 | if (context.HttpContext.Response.StatusCode >= StatusCodes.Status400BadRequest) 19 | { 20 | message = "Ended processing request with errors."; 21 | } 22 | else 23 | { 24 | message = "Ended processing request with success."; 25 | } 26 | Log.Information(message); 27 | } 28 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Api/Middlewares/LogUsernameMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Serilog.Context; 2 | 3 | namespace GreenOnSoftware.Api.Middlewares; 4 | 5 | public class LogUsernameMiddleware 6 | { 7 | private readonly RequestDelegate next; 8 | 9 | public LogUsernameMiddleware(RequestDelegate next) 10 | { 11 | this.next = next; 12 | } 13 | 14 | public async Task Invoke(HttpContext context) 15 | { 16 | LogContext.PushProperty("Username", context.User.Identity?.Name); 17 | 18 | await next(context); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Api/Startup/InvalidModelStateResponseFactory.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace GreenOnSoftware.Api.Startup; 5 | 6 | public static class InvalidModelStateResponseFactory 7 | { 8 | public static BadRequestObjectResult CustomErrorResponse(ActionContext actionContext) 9 | { 10 | var errors = actionContext.ModelState 11 | .Where(modelError => modelError.Value?.Errors.Count > 0) 12 | .ToDictionary(x => x.Key, x => x.Value?.Errors.FirstOrDefault()?.ErrorMessage ?? string.Empty); 13 | 14 | return new BadRequestObjectResult(new Result(errors)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Api/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "GreenOnSoftware": "Server=.;Database=GreenOnSoftware;Trusted_Connection=True;MultipleActiveResultSets=true" 4 | }, 5 | 6 | "Application": { 7 | "ResetPasswordUrl": "" 8 | }, 9 | 10 | "Security": { 11 | "AdminNames": "--secret--", 12 | "AdminPassword": "--secret--", 13 | "ResetPasswordUrl": "" 14 | }, 15 | 16 | "SendGrid": { 17 | "SenderEmailAddress": "greenonsoftware2022@gmail.com", 18 | "SenderName": "GreenOnSoftware - local", 19 | "ApiKey": "--secret--" 20 | }, 21 | "BlobStorage": { 22 | "ConnectionString": "--secret--", 23 | "Container": "dev" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Api/appsettings.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "GreenOnSoftware": "--secret--" 4 | }, 5 | 6 | "Application": { 7 | "ResetPasswordUrl": "" 8 | }, 9 | 10 | "Security": { 11 | "AdminNames": "--secret--", 12 | "AdminPassword": "--secret--", 13 | "ResetPasswordUrl": "" 14 | }, 15 | 16 | "SendGrid": { 17 | "SenderEmailAddress": "greenonsoftware2022@gmail.com", 18 | "SenderName": "GreenOnSoftware - dev", 19 | "ApiKey": "--secret--" 20 | }, 21 | 22 | "BlobStorage": { 23 | "ConnectionString": "--secret--", 24 | "Container": "dev" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Api/appsettings.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "GreenOnSoftware": "--secret--" 4 | }, 5 | 6 | "Application": { 7 | "ResetPasswordUrl": "" 8 | }, 9 | 10 | "Security": { 11 | "AdminNames": "--secret--", 12 | "AdminPassword": "--secret--", 13 | "ResetPasswordUrl": "" 14 | }, 15 | 16 | "SendGrid": { 17 | "SenderEmailAddress": "greenonsoftware2022@gmail.com", 18 | "SenderName": "GreenOnSoftware", 19 | "ApiKey": "--secret--" 20 | }, 21 | 22 | "BlobStorage": { 23 | "ConnectionString": "--secret--", 24 | "Container": "prod" 25 | }, 26 | 27 | "CorsOriginsUrls": [ 28 | "https://greenonsoftware.com" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Account/ChangePasswordCommand/ChangePassword.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Account.ChangePasswordCommand; 5 | 6 | public record ChangePassword(string CurrentPassword, string NewPassword, string ConfirmNewPassword) : IRequest; 7 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Account/ChangePasswordCommand/ChangePasswordValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | using GreenOnSoftware.Application.Account.ChangePasswordCommand; 3 | 4 | namespace GreenOnSoftware.Application.Account.ChangePasswordCommand; 5 | 6 | internal class ChangePasswordValidator : AbstractValidator 7 | { 8 | public ChangePasswordValidator() 9 | { 10 | 11 | RuleFor(x => x.CurrentPassword) 12 | .NotEmpty() 13 | .MaximumLength(100); 14 | 15 | RuleFor(x => x.NewPassword) 16 | .NotEmpty() 17 | .MaximumLength(100); 18 | 19 | RuleFor(x => x.ConfirmNewPassword) 20 | .NotEmpty() 21 | .MaximumLength(100) 22 | .Matches(x => x.NewPassword); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Account/ForgottenPasswordCommand/ForgottenPassword.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Account.ForgottenPasswordCommand; 5 | 6 | public record ForgottenPassword(string Login) : IRequest; 7 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Account/ForgottenPasswordCommand/ForgottenPasswordValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | using GreenOnSoftware.Application.Account.ForgottenPasswordCommand; 3 | 4 | namespace GreenOnSoftware.Application.Account.ForgottenPasswordCommand; 5 | 6 | internal class ForgottenPasswordValidator: AbstractValidator 7 | { 8 | public ForgottenPasswordValidator() 9 | { 10 | RuleFor(x => x.Login) 11 | .NotEmpty(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Account/GetAvatarNameQuery/GetAvatarName.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Account.GetAvatarNameQuery; 5 | 6 | public record GetAvatarName() : IRequest>; 7 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Account/GetAvatarNameQuery/GetAvatarNameHandler.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | using GreenOnSoftware.Commons.Context; 4 | using GreenOnSoftware.Application.Account.GetAvatarNameQuery; 5 | 6 | namespace GreenOnSoftware.Application.Account.GetAvatarNameQuery; 7 | 8 | internal class GetAvatarNameHandler : IRequestHandler> 9 | { 10 | private readonly IContext _context; 11 | 12 | public GetAvatarNameHandler(IContext context) 13 | { 14 | _context = context; 15 | } 16 | 17 | public Task> Handle(GetAvatarName query, CancellationToken cancellationToken) 18 | { 19 | var result = new Result(); 20 | 21 | result.SetData(_context.Identity.AvatarName); 22 | 23 | return Task.FromResult(result); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Account/RegisterCommand/Register.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Account.RegisterCommand; 5 | 6 | public record Register(string Login, string Email, string Password, string ConfirmPassword) : IRequest; 7 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Account/RegisterCommand/RegisterValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | using GreenOnSoftware.Application.Account.RegisterCommand; 3 | 4 | namespace GreenOnSoftware.Application.Account.RegisterCommand; 5 | 6 | internal class RegisterValidator : AbstractValidator 7 | { 8 | public RegisterValidator() 9 | { 10 | RuleFor(x => x.Login) 11 | .NotEmpty() 12 | .MaximumLength(100); 13 | 14 | RuleFor(x => x.Email) 15 | .NotEmpty() 16 | .EmailAddress(); 17 | 18 | RuleFor(x => x.Password) 19 | .NotEmpty() 20 | .MaximumLength(100); 21 | 22 | RuleFor(x => x.ConfirmPassword) 23 | .NotEmpty() 24 | .MaximumLength(100) 25 | .Matches(x => x.Password); 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Account/ResetPasswordCommand/ResetPassword.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Account.ResetPasswordCommand; 5 | public record ResetPassword(string NewPassword, string ConfirmNewPassword, string UserId, string Token) : IRequest; 6 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Account/ResetPasswordCommand/ResetPasswordValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | using GreenOnSoftware.Application.Account.ResetPasswordCommand; 3 | 4 | namespace GreenOnSoftware.Application.Account.ResetPasswordCommand; 5 | 6 | internal class ResetPasswordValidator : AbstractValidator 7 | { 8 | public ResetPasswordValidator() 9 | { 10 | RuleFor(x => x.UserId) 11 | .NotEmpty() 12 | .MaximumLength(36); 13 | 14 | RuleFor(x => x.Token) 15 | .NotEmpty() 16 | .MaximumLength(400); 17 | 18 | RuleFor(x => x.NewPassword) 19 | .NotEmpty() 20 | .MaximumLength(100); 21 | 22 | RuleFor(x => x.ConfirmNewPassword) 23 | .NotEmpty() 24 | .MaximumLength(100) 25 | .Matches(x => x.NewPassword); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Account/SetAvatarNameCommand/SetAvatarName.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Ratings.SetAvatarNameCommand; 5 | 6 | public record SetAvatarName(string AvatarName) : IRequest; 7 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Account/SetAvatarNameCommand/SetAvatarNameHandler.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Application.Services.Interfaces; 2 | using GreenOnSoftware.Commons.Dtos; 3 | using MediatR; 4 | 5 | namespace GreenOnSoftware.Application.Ratings.SetAvatarNameCommand; 6 | 7 | internal class SetAvatarNameHandler : IRequestHandler 8 | { 9 | private readonly IRatingsSessionService _ratingsSessionService; 10 | 11 | public SetAvatarNameHandler(IRatingsSessionService ratingsSessionService) 12 | { 13 | _ratingsSessionService = ratingsSessionService; 14 | } 15 | 16 | public Task Handle(SetAvatarName command, CancellationToken cancellationToken) 17 | { 18 | var result = new Result(); 19 | 20 | _ratingsSessionService.SetAvatarName(command.AvatarName); 21 | 22 | return Task.FromResult(result); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Account/SetAvatarNameCommand/SetAvatarNameValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | 3 | namespace GreenOnSoftware.Application.Ratings.SetAvatarNameCommand; 4 | 5 | internal class SetAvatarNameValidator : AbstractValidator 6 | { 7 | public SetAvatarNameValidator() 8 | { 9 | RuleFor(x => x.AvatarName) 10 | .NotEmpty() 11 | .MinimumLength(2) 12 | .MaximumLength(30); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Account/SignInCommand/SignIn.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Account.SignInCommand; 5 | 6 | public record SignIn(string Login, string Password) : IRequest; 7 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Account/SignOutCommand/SignOut.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Account.SignOutCommand; 5 | 6 | public record SignOut() : IRequest; 7 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Account/SignOutCommand/SignOutHandler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | using MediatR; 3 | using GreenOnSoftware.Commons.Dtos; 4 | using GreenOnSoftware.Application.Account.SignOutCommand; 5 | using GreenOnSoftware.Core.Identity; 6 | 7 | namespace GreenOnSoftware.Application.Account.SignOutCommand; 8 | 9 | internal class SignOutHandler : IRequestHandler 10 | { 11 | private readonly SignInManager _signInManager; 12 | 13 | public SignOutHandler(SignInManager signInManager) 14 | { 15 | _signInManager = signInManager; 16 | } 17 | 18 | public async Task Handle(SignOut command, CancellationToken cancellationToken) 19 | { 20 | var response = new Result(); 21 | await _signInManager.SignOutAsync(); 22 | 23 | return response; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Articles/AcceptArticleCommand/AcceptArticle.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Articles.AcceptArticleCommand; 5 | 6 | public record AcceptArticle(Guid Id) : IRequest; 7 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Articles/AddArticleCommand/AddArticle.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | using Microsoft.AspNetCore.Http; 4 | 5 | namespace GreenOnSoftware.Application.Articles.AddArticleCommand; 6 | 7 | public record AddArticle(string Title, string? Description, string Content, IFormFile? Thumbnail, string Url) : IRequest>; 8 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Articles/AddArticleCommand/AddArticleValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | 3 | namespace GreenOnSoftware.Application.Articles.AddArticleCommand; 4 | 5 | public class AddArticleValidator : AbstractValidator 6 | { 7 | public AddArticleValidator() 8 | { 9 | RuleFor(x => x.Title).NotEmpty(); 10 | RuleFor(x => x.Content).NotEmpty(); 11 | 12 | RuleFor(x => x.Title) 13 | .MaximumLength(200); 14 | RuleFor(x => x.Description) 15 | .MaximumLength(500); 16 | RuleFor(x => x.Url) 17 | .NotEmpty() 18 | .MaximumLength(300); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Articles/DeleteArticleCommand/DeleteArticle.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Articles.DeleteArticleCommand; 5 | 6 | public record DeleteArticle(Guid Id) : IRequest; 7 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Articles/GetArticleByIdQuery/ArticleDto.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Application.Articles.GetArticleByIdQuery; 2 | 3 | public class ArticleDto 4 | { 5 | public Guid Id { get; set; } 6 | public string Title { get; set; } 7 | public string? Description { get; set; } 8 | public string Content { get; set; } 9 | public string AuthorEmail { get; set; } 10 | public string AuthorName { get; set; } 11 | public string? ThumbnailUrl { get; set; } 12 | public string Status { get; set; } 13 | public string Url { get; set; } 14 | 15 | public DateTime CreatedDate { get; set; } 16 | public DateTime ModifiedDate { get; set; } 17 | } 18 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Articles/GetArticleByIdQuery/CommentDto.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Application.Articles.GetArticleByIdQuery; 2 | 3 | public class CommentDto 4 | { 5 | public Guid Id { get; set; } 6 | public DateTime CreatedDate { get; set; } 7 | public DateTime ModifiedDate { get; set; } 8 | public string Content { get; set; } 9 | public string Username { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Articles/GetArticleByIdQuery/GetArticleById.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Articles.GetArticleByIdQuery; 5 | 6 | public record GetArticleById(Guid Id) : IRequest>; 7 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Articles/GetArticlesQuery/ArticleLookupDto.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Application.Articles.GetArticlesQuery; 2 | 3 | public class ArticleLookupDto 4 | { 5 | public Guid Id { get; set; } 6 | public string Title { get; set; } 7 | public string? Description { get; set; } 8 | public string AuthorEmail { get; set; } 9 | public string AuthorName { get; set; } 10 | public string? ThumbnailUrl { get; set; } 11 | public string Status { get; set; } 12 | public string Url { get; set; } 13 | } 14 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Articles/GetArticlesQuery/GetArticles.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.CQRS; 2 | 3 | namespace GreenOnSoftware.Application.Articles.GetArticlesQuery; 4 | 5 | public record GetArticles(string[]? Status, string? Search, int? ItemsPerPage, int? CurrentPage) 6 | : ISearchQuery; 7 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Articles/RejectArticleCommand/RejectArticle.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Articles.RejectArticleCommand; 5 | 6 | public record RejectArticle(Guid Id) : IRequest; 7 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Articles/SendForApprovalCommand/SendForApproval.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Articles.SendForApprovalCommand; 5 | 6 | public record SendForApproval(Guid Id) : IRequest; 7 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Articles/UpdateArticleCommand/UpdateArticle.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Application.Reviews.AddReviewCommand; 2 | using GreenOnSoftware.Commons.Dtos; 3 | using GreenOnSoftware.Core.Models; 4 | using MediatR; 5 | using Microsoft.AspNetCore.Http; 6 | 7 | namespace GreenOnSoftware.Application.Articles.UpdateArticleCommand; 8 | 9 | public record UpdateArticle(string Title, string? Description, string Content, IFormFile? Thumbnail, string Url) : IRequest 10 | { 11 | internal Guid Id { get; private set; } 12 | 13 | public UpdateArticle BindId(Guid id) 14 | { 15 | Id = id; 16 | 17 | return this; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Articles/UpdateArticleCommand/UpdateArticleValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | 3 | namespace GreenOnSoftware.Application.Articles.UpdateArticleCommand; 4 | 5 | public class UpdateArticleValidator : AbstractValidator 6 | { 7 | public UpdateArticleValidator() 8 | { 9 | RuleFor(x => x.Title).NotEmpty(); 10 | RuleFor(x => x.Content).NotEmpty(); 11 | 12 | RuleFor(x => x.Title) 13 | .MaximumLength(200); 14 | RuleFor(x => x.Description) 15 | .MaximumLength(500); 16 | RuleFor(x => x.Url) 17 | .MaximumLength(300); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/DependencyInjection.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Application.Services; 2 | using GreenOnSoftware.Application.Services.Interfaces; 3 | using Microsoft.Extensions.DependencyInjection; 4 | 5 | namespace GreenOnSoftware.Application; 6 | 7 | public static class DependencyInjection 8 | { 9 | public static IServiceCollection AddApplication(this IServiceCollection services) 10 | { 11 | services.AddTransient(); 12 | services.AddTransient(); 13 | services.AddTransient(); 14 | 15 | return services; 16 | } 17 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Ratings/AddArticleRateCommand/AddArticleRate.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Ratings.AddArticleRateCommand; 5 | 6 | public record AddArticleRate(int Value) : IRequest 7 | { 8 | internal Guid ArticleId { get; private set; } 9 | 10 | public AddArticleRate BindArticleId(Guid articleId) 11 | { 12 | ArticleId = articleId; 13 | 14 | return this; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Ratings/AddArticleRateCommand/AddArticleRateValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | using GreenOnSoftware.Application.Reviews.AddReviewCommand; 3 | 4 | namespace GreenOnSoftware.Application.Ratings.AddArticleRateCommand; 5 | 6 | public class AddArticleRateValidator : AbstractValidator 7 | { 8 | public AddArticleRateValidator() 9 | { 10 | RuleFor(x => x.ArticleId) 11 | .NotEmpty(); 12 | 13 | RuleFor(x => x.Value) 14 | .InclusiveBetween(1, 5); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Ratings/GetArticleRatingQuery/GetArticleRatings.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Clock; 2 | using GreenOnSoftware.Commons.Dtos; 3 | using MediatR; 4 | 5 | namespace GreenOnSoftware.Application.Ratings.GetArticleRatingQuery; 6 | 7 | public record GetArticleRatings(Guid Id) : IRequest>; 8 | 9 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Ratings/GetArticleRatingQuery/RatingsDto.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Application.Ratings.GetArticleRatingQuery; 2 | 3 | public class RatingsDto 4 | { 5 | public RatingsDto(IEnumerable> averageRatingByAvatars, double averageRating, string? currentUserRateAvatar, int? currentUserRateValue) 6 | { 7 | AverageRatingByAvatars = averageRatingByAvatars; 8 | AverageRating = averageRating; 9 | CurrentUserRateAvatar = currentUserRateAvatar; 10 | CurrentUserRateValue = currentUserRateValue; 11 | } 12 | 13 | public IEnumerable> AverageRatingByAvatars { get; } 14 | public double AverageRating { get; } 15 | public string? CurrentUserRateAvatar { get; } 16 | public int? CurrentUserRateValue { get; } 17 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Ratings/RemoveArticleRateCommand/RemoveArticleRate.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Ratings.RemoveArticleRateCommand; 5 | 6 | public record RemoveArticleRate(Guid ArticleId) : IRequest; 7 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Ratings/UpdateArticleRate/UpdateArticleRate.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Ratings.UpdateArticleRate; 5 | 6 | public record UpdateArticleRate(int Value) : IRequest 7 | { 8 | internal Guid ArticleId { get; private set; } 9 | 10 | public UpdateArticleRate BindArticleId(Guid articleId) 11 | { 12 | ArticleId = articleId; 13 | 14 | return this; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Ratings/UpdateArticleRate/UpdateArticleRateValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | 3 | namespace GreenOnSoftware.Application.Ratings.UpdateArticleRate; 4 | 5 | public class UpdateArticleRateValidator : AbstractValidator 6 | { 7 | public UpdateArticleRateValidator() 8 | { 9 | RuleFor(x => x.ArticleId) 10 | .NotEmpty(); 11 | 12 | RuleFor(x => x.Value) 13 | .InclusiveBetween(1, 5); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Reviews/AddReviewCommand/AddReview.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Reviews.AddReviewCommand; 5 | 6 | public record AddReview(string Content) : IRequest 7 | { 8 | internal Guid ArticleId { get; private set; } 9 | 10 | public AddReview BindArticleId(Guid articleId) 11 | { 12 | ArticleId = articleId; 13 | 14 | return this; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Reviews/AddReviewCommand/AddReviewValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | 3 | namespace GreenOnSoftware.Application.Reviews.AddReviewCommand; 4 | 5 | public class AddReviewValidator : AbstractValidator 6 | { 7 | public AddReviewValidator() 8 | { 9 | RuleFor(x => x.Content) 10 | .NotEmpty() 11 | .MaximumLength(4000); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Reviews/DeleteReviewCommand/DeleteReview.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Reviews.DeleteReviewCommand; 5 | 6 | public record DeleteReview(Guid ArticleId, Guid ReviewId) : IRequest; 7 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Reviews/GetAllReviewerReviewsQuery/GetAllReviewerReviews.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Application.Dtos; 2 | using GreenOnSoftware.Commons.Dtos; 3 | using MediatR; 4 | 5 | namespace GreenOnSoftware.Application.Reviews.GetAllReviewerReviewsQuery; 6 | 7 | public record GetAllReviewerReviews() : IRequest>>; 8 | 9 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Reviews/GetReviewByIdQuery/GetReviews.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Application.Dtos; 2 | using GreenOnSoftware.Commons.Dtos; 3 | using MediatR; 4 | 5 | namespace GreenOnSoftware.Application.Reviews.GetReviewByIdQuery; 6 | 7 | public record GetReviewById(Guid ArticleId, Guid ReviewId) : IRequest>; 8 | 9 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Reviews/GetReviewsQuery/GetReviews.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Application.Dtos; 2 | using GreenOnSoftware.Commons.Dtos; 3 | using MediatR; 4 | 5 | namespace GreenOnSoftware.Application.Reviews.GetReviewsQuery; 6 | 7 | public record GetReviews(Guid ArticleId) : IRequest>>; 8 | 9 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Reviews/UpdateReviewCommand/UpdateReview.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using GreenOnSoftware.Core.Models; 3 | using MediatR; 4 | 5 | namespace GreenOnSoftware.Application.Reviews.UpdateReviewCommand; 6 | 7 | public record UpdateReview(string Content) : IRequest 8 | { 9 | internal Guid ArticleId { get; private set; } 10 | internal Guid ReviewId { get; private set; } 11 | 12 | public UpdateReview BindIds(Guid articleId, Guid reviewId) 13 | { 14 | ArticleId = articleId; 15 | ReviewId = reviewId; 16 | 17 | return this; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Reviews/UpdateReviewCommand/UpdateReviewValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | 3 | namespace GreenOnSoftware.Application.Reviews.UpdateReviewCommand; 4 | 5 | public class UpdateReviewValidator : AbstractValidator 6 | { 7 | public UpdateReviewValidator() 8 | { 9 | RuleFor(x => x.Content) 10 | .NotEmpty() 11 | .MaximumLength(4000); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Snippets/AddSnippetCommand/AddSnippet.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Application.Articles.UpdateArticleCommand; 2 | using GreenOnSoftware.Commons.Dtos; 3 | using MediatR; 4 | 5 | namespace GreenOnSoftware.Application.Snippets.AddSnippetCommand; 6 | 7 | public record AddSnippet(string Name, string Description, IList Frames, string? GifUrl): IRequest 8 | { 9 | public record SnippetFrame(string Code, string? Name, string? Description, SnippetFrame.SnippetFrameAnimation Animation) 10 | { 11 | public record SnippetFrameAnimation(string Type, int DisplayTime) 12 | { 13 | 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Snippets/GetSnippetByIdQuery/GetSnippetById.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Snippets.GetSnippetByIdQuery; 5 | 6 | public record GetSnippetById(Guid Id): IRequest 7 | { 8 | 9 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Snippets/GetSnippetByIdQuery/GetSnippetByIdValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | 3 | namespace GreenOnSoftware.Application.Snippets.GetSnippetByIdQuery; 4 | 5 | public sealed class GetSnippetByIdValidator: AbstractValidator 6 | { 7 | public GetSnippetByIdValidator() 8 | { 9 | RuleFor(x => x.Id) 10 | .NotEmpty(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Snippets/GetSnippetByIdQuery/SnippetDto.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Application.Snippets.GetSnippetByIdQuery; 2 | 3 | public class SnippetDto 4 | { 5 | public Guid Id { get; set; } 6 | 7 | public string Name { get; set; } 8 | 9 | public string Description { get; set; } 10 | 11 | public IList Frames { get; set; } 12 | 13 | public string GifUrl { get; private set; } 14 | 15 | public class SnippetFrameDto 16 | { 17 | public string Code { get; set; } 18 | public string? Name { get; set; } 19 | public string? Description { get; set; } 20 | 21 | public SnippetFrameAnimationDto Animation { get; set; } 22 | 23 | } 24 | 25 | public class SnippetFrameAnimationDto 26 | { 27 | public string Type { get; set; } 28 | public int DisplayTime { get; set; } 29 | } 30 | } 31 | 32 | 33 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Users/AddToRoleCommand/AddToRole.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Users.AddToRoleCommand; 5 | 6 | public record AddToRole(string Role) : IRequest 7 | { 8 | internal Guid UserId { get; private set; } 9 | 10 | public AddToRole BindId(Guid userId) 11 | { 12 | UserId = userId; 13 | 14 | return this; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Users/AddToRoleCommand/AddToRoleValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | using GreenOnSoftware.Commons.Consts; 3 | 4 | namespace GreenOnSoftware.Application.Users.AddToRoleCommand; 5 | 6 | public class AddToRoleValidator : AbstractValidator 7 | { 8 | public AddToRoleValidator() 9 | { 10 | RuleFor(x => x.Role) 11 | .Must(x => Role.All.Contains(x)) 12 | .WithMessage("Role must have valid value"); 13 | 14 | RuleFor(x => x.Role) 15 | .Must(x => x.ToLower() != Role.Admin.ToLower()) 16 | .WithMessage("Administrators cannot be change"); 17 | } 18 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Users/GetUsersQuery/GetUsers.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.CQRS; 2 | 3 | namespace GreenOnSoftware.Application.Users.GetUsersQuery; 4 | 5 | public record GetUsers(string[]? Roles, string? Search, int? ItemsPerPage, int? CurrentPage) 6 | : ISearchQuery; 7 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Users/GetUsersQuery/GetUsersValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | using GreenOnSoftware.Commons.Consts; 3 | using Microsoft.EntityFrameworkCore; 4 | 5 | namespace GreenOnSoftware.Application.Users.GetUsersQuery; 6 | 7 | public class GetUsersValidator : AbstractValidator 8 | { 9 | public GetUsersValidator() 10 | { 11 | RuleFor(x => x.Roles) 12 | .Must(x => x is null || x.All(s => Role.All.Contains(s))) 13 | .WithMessage("Roles must have valid values"); 14 | 15 | RuleFor(x => x.Search) 16 | .MaximumLength(100); 17 | 18 | RuleFor(x => x.ItemsPerPage) 19 | .LessThanOrEqualTo(50); 20 | 21 | RuleFor(x => x.CurrentPage) 22 | .LessThanOrEqualTo(1000); 23 | } 24 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Users/GetUsersQuery/UserLookupDto.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Application.Users.GetUsersQuery; 2 | 3 | public sealed class UserLookupDto 4 | { 5 | public Guid Id { get; set; } 6 | public string Name { get; set; } 7 | public string Email { get; set; } 8 | public string[] Roles { get; set; } 9 | } 10 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Users/RemoveFromRoleCommand/RemoveFromRole.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Application.Users.RemoveFromRoleCommand; 5 | 6 | public record RemoveFromRole(string Role) : IRequest 7 | { 8 | internal Guid UserId { get; private set; } 9 | 10 | public RemoveFromRole BindId(Guid userId) 11 | { 12 | UserId = userId; 13 | 14 | return this; 15 | } 16 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/Users/RemoveFromRoleCommand/RemoveFromRoleValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | using GreenOnSoftware.Application.Users.AddToRoleCommand; 3 | using GreenOnSoftware.Commons.Consts; 4 | 5 | namespace GreenOnSoftware.Application.Users.RemoveFromRoleCommand; 6 | 7 | public class RemoveFromRoleValidator : AbstractValidator 8 | { 9 | public RemoveFromRoleValidator() 10 | { 11 | RuleFor(x => x.Role) 12 | .Must(x => Role.All.Contains(x)) 13 | .WithMessage("Role must have valid value"); 14 | 15 | RuleFor(x => x.Role) 16 | .Must(x => x.ToLower() != Role.Admin.ToLower()) 17 | .WithMessage("Administrators cannot be change"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/_Configuration/ApplicationConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Application.Configuration; 2 | 3 | public class ApplicationConfiguration 4 | { 5 | public string ResetPasswordUrl { get; set; } 6 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/_Dtos/ICurrentUserReviewer.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Application.Dtos; 2 | 3 | public interface ICurrentUserReviewer 4 | { 5 | bool IsCurrentUserReviewer { get; set; } 6 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/_Dtos/ReviewDto.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Application.Dtos; 2 | 3 | public class ReviewDto : ICurrentUserReviewer 4 | { 5 | public Guid Id { get; set; } 6 | public DateTime CreatedDate { get; set; } 7 | public DateTime ModifiedDate { get; set; } 8 | public string? ReviewerName { get; set; } 9 | public string Content { get; set; } 10 | public bool IsCurrentUserReviewer { get; set; } 11 | public string? ArticleAuthorName { get; set; } 12 | public string ArticleTitle { get; set; } 13 | } 14 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/_Dtos/ReviewLookupDto.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Application.Dtos; 2 | 3 | public class ReviewLookupDto: ICurrentUserReviewer 4 | { 5 | public Guid Id { get; set; } 6 | public Guid ArticleId { get; set; } 7 | public DateTime CreatedDate { get; set; } 8 | public DateTime ModifiedDate { get; set; } 9 | public string? ReviewerName { get; set; } 10 | public bool IsCurrentUserReviewer { get; set; } 11 | } 12 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/_Dtos/UserReviewLookupDto.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Application.Dtos; 2 | 3 | public class UserReviewLookupDto 4 | { 5 | public Guid Id { get; set; } 6 | public Guid ArticleId { get; set; } 7 | public DateTime CreatedDate { get; set; } 8 | public DateTime ModifiedDate { get; set; } 9 | public string? ArticleAuthorName { get; set; } 10 | public string ArticleTitle { get; set; } 11 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/_Mapper/MappingActions/ReviewDtoAction.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using GreenOnSoftware.Application.Dtos; 3 | using GreenOnSoftware.Commons.Context; 4 | using GreenOnSoftware.Core.Models.Reviews; 5 | 6 | namespace GreenOnSoftware.Application.Mapper.MappingActions; 7 | 8 | internal sealed class CurrentUserReviewerAction : IMappingAction 9 | { 10 | private readonly IContext _context; 11 | 12 | public CurrentUserReviewerAction(IContext context) 13 | { 14 | _context = context; 15 | } 16 | 17 | public void Process(Review source, ICurrentUserReviewer destination, ResolutionContext context) 18 | { 19 | destination.IsCurrentUserReviewer = source.ReviewerId == _context.Identity.Id; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/_Mapper/SnippetsMapperProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using GreenOnSoftware.Application.Snippets.GetSnippetByIdQuery; 3 | using GreenOnSoftware.Core.Models.Snippets; 4 | 5 | namespace GreenOnSoftware.Application.Mapper; 6 | 7 | public class SnippetsMapperProfile : Profile 8 | { 9 | public SnippetsMapperProfile() 10 | { 11 | CreateMap(); 12 | CreateMap() 13 | .ForMember(x => x.Animation, opt => opt.MapFrom(mappingFunction: (src, dst) => new SnippetDto.SnippetFrameAnimationDto { 14 | DisplayTime = src.AnimationDisplayTime, 15 | Type = src.AnimationType.ToString() 16 | })); 17 | } 18 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/_Mapper/UsersMapperProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using GreenOnSoftware.Application.Users.GetUsersQuery; 3 | using GreenOnSoftware.Core.Identity; 4 | 5 | namespace GreenOnSoftware.Application.Mapper; 6 | 7 | public class UsersMapperProfile : Profile 8 | { 9 | public UsersMapperProfile() 10 | { 11 | CreateProjection() 12 | .ForMember(dest => dest.Name, o => o.MapFrom(src => src.UserName)) 13 | .ForMember(dest => dest.Roles, o => o.MapFrom(src => src.Roles.Select(x=>x.Role.Name).ToArray())); 14 | } 15 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/_Services/Interfaces/IBlobStorageService.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | 3 | namespace GreenOnSoftware.Application.Services.Interfaces; 4 | 5 | public interface IBlobStorageService 6 | { 7 | Task RemovePictureFromStorageAsync(string path); 8 | Task> UploadPictureAsync(MemoryStream pictureFileStream, string fileExtension); 9 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/_Services/Interfaces/IEmailSenderService.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | 3 | namespace GreenOnSoftware.Application.Services.Interfaces; 4 | 5 | public interface IEmailSenderService 6 | { 7 | Task SendEmailAsync(string recipient, string subject, string textContent); 8 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/_Services/Interfaces/IEmailService.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | 3 | namespace GreenOnSoftware.Application.Services.Interfaces; 4 | 5 | public interface IEmailService 6 | { 7 | string GetResetPasswordUrl(string token, Guid userId); 8 | Task SendResetPasswordEmailAsync(string email, string username, Guid userId, string token); 9 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/_Services/Interfaces/IRatingsSessionService.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Application.Services.Interfaces; 2 | 3 | public interface IRatingsSessionService 4 | { 5 | void SetAvatarName(string avatarName); 6 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/_Services/Interfaces/IThumbnailService.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using Microsoft.AspNetCore.Http; 3 | 4 | namespace GreenOnSoftware.Application.Services.Interfaces; 5 | 6 | public interface IThumbnailService 7 | { 8 | Task> UploadPicture(IFormFile pictureFile); 9 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Application/_Services/RatingsSessionService.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Application.Services.Interfaces; 2 | using Microsoft.AspNetCore.Http; 3 | 4 | namespace GreenOnSoftware.Application.Services; 5 | 6 | public class RatingsSessionService : IRatingsSessionService 7 | { 8 | private const string AvatarNameKey = "avatarName"; 9 | 10 | private readonly IHttpContextAccessor _httpContextAccessor; 11 | 12 | public RatingsSessionService(IHttpContextAccessor httpContextAccessor) 13 | { 14 | _httpContextAccessor = httpContextAccessor; 15 | } 16 | 17 | public void SetAvatarName(string avatarName) 18 | { 19 | _httpContextAccessor.HttpContext!.Session.SetString(AvatarNameKey, avatarName); 20 | } 21 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Commons/CQRS/ISearchQuery.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Commons.Dtos; 2 | using MediatR; 3 | 4 | namespace GreenOnSoftware.Commons.CQRS; 5 | 6 | public interface ISearchQuery: IRequest> 7 | { 8 | string? Search { get; init; } 9 | int? ItemsPerPage { get; init; } 10 | int? CurrentPage { get; init; } 11 | } 12 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Commons/Clock/Clock.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Commons.Clock; 2 | 3 | public class Clock : IClock 4 | { 5 | public DateTime UtcNow => DateTime.UtcNow; 6 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Commons/Clock/IClock.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Commons.Clock 2 | { 3 | public interface IClock 4 | { 5 | DateTime UtcNow { get; } 6 | } 7 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Commons/Consts/Role.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Commons.Consts; 2 | 3 | public static class Role 4 | { 5 | public readonly static string[] All = new[] { Admin, ContentEditor, GeneralUser }; 6 | 7 | public const string Admin = "Admin"; 8 | public const string ContentEditor = "ContentEditor"; 9 | public const string GeneralUser = "GeneralUser"; 10 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Commons/Context/IContext.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Commons.Context; 2 | 3 | public interface IContext 4 | { 5 | IIdentityContext Identity { get; } 6 | } 7 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Commons/Context/IContextAccessor.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Commons.Context; 2 | 3 | public interface IContextAccessor 4 | { 5 | IContext? Context { get; set; } 6 | } 7 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Commons/Context/IIdentityContext.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Commons.Context; 2 | 3 | public interface IIdentityContext 4 | { 5 | Guid Id { get; } 6 | string? Name { get; } 7 | bool IsAdmin { get; } 8 | bool IsContentEditor { get; } 9 | bool IsGeneralUser { get; } 10 | bool IsAuthenticated { get; } 11 | string? AvatarName { get; } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Commons/Dtos/ErrorMessage.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Commons.Dtos; 2 | 3 | public class ErrorMessage 4 | { 5 | public ErrorMessage(string key, string message) 6 | { 7 | Key = key; 8 | Message = message; 9 | } 10 | 11 | public string Key { get; set; } 12 | public string Message { get; set; } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Commons/Dtos/PagedResult.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Commons.Dtos; 2 | 3 | public class PagedResult : Result> 4 | { 5 | public int ItemsPerPage { get; private set; } 6 | public int TotalPages { get; private set; } 7 | public int CurrentPage { get; private set; } 8 | public int CurrentPageItemsNumber { get; private set; } 9 | 10 | public void SetData(IEnumerable items, int itemsPerPage, int currentPage, int currentPageItemsNumber, int totalPages) 11 | { 12 | SetData(items); 13 | ItemsPerPage = itemsPerPage; 14 | CurrentPage = currentPage; 15 | TotalPages = totalPages; 16 | CurrentPageItemsNumber = currentPageItemsNumber; 17 | } 18 | } 19 | 20 | 21 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Commons/Extensions/EnumExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace GreenOnSoftware.Commons.Extensions; 4 | 5 | public static class EnumExtensions 6 | { 7 | public static string Description(Enum item) 8 | { 9 | var enumValue = item.ToString(); 10 | var field = item.GetType().GetField(enumValue); 11 | var attribute = ((DescriptionAttribute[])field!.GetCustomAttributes(typeof(DescriptionAttribute), false)).FirstOrDefault(); 12 | 13 | return attribute?.Description ?? enumValue; 14 | } 15 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Commons/Extensions/IdentityResultExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | 3 | namespace GreenOnSoftware.Commons.Extensions; 4 | 5 | public static class IdentityResultExtensions 6 | { 7 | public static IEnumerable GetErrors(this IdentityResult identityResult) 8 | { 9 | return identityResult.Errors.Select(x => x.Description); 10 | } 11 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Commons/Extensions/QueryableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | 3 | namespace GreenOnSoftware.Commons.Extensions; 4 | 5 | public static class QueryableExtensions 6 | { 7 | public static IQueryable Where(this IQueryable entities, Func condition, Expression> predicate) 8 | where T: class 9 | { 10 | return condition() ? entities.Where(predicate) : entities; 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Commons/Extensions/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Commons.Extensions; 2 | 3 | public static class StringExtensions 4 | { 5 | public static T ToEnum(this string description) where T : Enum 6 | { 7 | return (T)Enum.Parse(typeof(T), description, ignoreCase: true); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Core/Enums/SnippetFrameAnimationType.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Core.Enums; 2 | 3 | public enum SnippetFrameAnimationType 4 | { 5 | SlideRight, 6 | SlideLeft, 7 | Opacity 8 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Core/Enums/Status.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Core.Enums; 2 | 3 | public enum Status 4 | { 5 | Draft = 0, 6 | WaitingForApproval = 1, 7 | NeedWork = 2, 8 | Accepted = 3 9 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Core/GreenOnSoftware.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Core/Identity/User.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | 3 | namespace GreenOnSoftware.Core.Identity; 4 | 5 | public class User : IdentityUser 6 | { 7 | public virtual ICollection Roles { get; set; } 8 | public virtual ICollection> Tokens { get; set; } 9 | } 10 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Core/Identity/UserRole.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | 3 | namespace GreenOnSoftware.Core.Identity; 4 | 5 | public class UserRole : IdentityUserRole 6 | { 7 | public virtual IdentityRole Role { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Core/Models/Snippets/Snippet.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace GreenOnSoftware.Core.Models.Snippets; 4 | 5 | public class Snippet : Entity 6 | { 7 | private Snippet() 8 | { 9 | 10 | } 11 | 12 | public Snippet(string name, string description, IList frames, string? gifUrl) 13 | { 14 | Id = Guid.NewGuid(); 15 | Name = name; 16 | Description = description; 17 | Frames = frames; 18 | GifUrl = gifUrl; 19 | } 20 | 21 | public string Name { get; private set; } 22 | 23 | public string Description { get; private set; } 24 | 25 | public IList Frames { get; private set; } 26 | 27 | public string? GifUrl { get; private set; } 28 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Core/Models/Snippets/SnippetFrame.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Core.Enums; 2 | using Newtonsoft.Json; 3 | 4 | namespace GreenOnSoftware.Core.Models.Snippets; 5 | 6 | public class SnippetFrame 7 | { 8 | private SnippetFrame() 9 | { 10 | 11 | } 12 | 13 | public SnippetFrame(string code, string? name, string? description, SnippetFrameAnimationType animationType, int animationDisplayTime) 14 | { 15 | Code = code; 16 | Name = name; 17 | Description = description; 18 | AnimationType = animationType; 19 | AnimationDisplayTime = animationDisplayTime; 20 | } 21 | 22 | public string Code { get; private set; } 23 | public string? Name { get; private set; } 24 | public string? Description { get; private set; } 25 | public SnippetFrameAnimationType AnimationType { get; private set; } 26 | public int AnimationDisplayTime { get; private set; } 27 | } 28 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Core/Models/_Entity.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | 3 | namespace GreenOnSoftware.Core.Models; 4 | 5 | public abstract class Entity 6 | { 7 | public Guid Id { get; protected set; } 8 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.DataAccess/Configuration/CommentConfiguration.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Core.Models; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace GreenOnSoftware.DataAccess.Configuration; 6 | 7 | public class CommentConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(x => x.Id); 12 | 13 | builder.Property(x => x.Content) 14 | .IsRequired(); 15 | 16 | builder.HasOne(x => x.Author) 17 | .WithMany() 18 | .HasForeignKey(x => x.AuthorId) 19 | .OnDelete(DeleteBehavior.SetNull); 20 | 21 | builder.HasOne(x => x.Article) 22 | .WithMany(x=>x.Comments) 23 | .HasForeignKey(x => x.ArticleId) 24 | .OnDelete(DeleteBehavior.SetNull); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.DataAccess/Configuration/UserConfiguration.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Core.Identity; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace GreenOnSoftware.DataAccess.Configuration; 6 | 7 | public class UserConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder 12 | .HasMany(e => e.Roles) 13 | .WithOne() 14 | .HasForeignKey(e => e.UserId) 15 | .IsRequired() 16 | .OnDelete(DeleteBehavior.Cascade); 17 | 18 | builder 19 | .HasMany(x => x.Tokens) 20 | .WithOne() 21 | .HasForeignKey(x => x.UserId) 22 | .IsRequired() 23 | .OnDelete(DeleteBehavior.Cascade); 24 | 25 | builder 26 | .ToTable("Users"); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.DataAccess/Configuration/UserRoleConfiguration.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Core.Identity; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace GreenOnSoftware.DataAccess.Configuration; 6 | 7 | public class UserRoleConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder 12 | .HasOne(e => e.Role) 13 | .WithMany() 14 | .HasForeignKey(e => e.RoleId) 15 | .IsRequired() 16 | .OnDelete(DeleteBehavior.Cascade); 17 | 18 | builder 19 | .ToTable("UserRoles"); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.DataAccess/Converters/SnippetFramesValueConverter.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Core.Models.Snippets; 2 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 3 | using Newtonsoft.Json; 4 | 5 | namespace GreenOnSoftware.DataAccess.Converters; 6 | 7 | internal class SnippetFramesValueConverter : ValueConverter, string> 8 | { 9 | private static JsonSerializerSettings _jsonSerializerSettings = new JsonSerializerSettings { 10 | TypeNameHandling = TypeNameHandling.Auto, 11 | NullValueHandling = NullValueHandling.Ignore, 12 | }; 13 | 14 | public SnippetFramesValueConverter() 15 | : base(frames => JsonConvert.SerializeObject(frames, _jsonSerializerSettings), 16 | json => JsonConvert.DeserializeObject>(json, _jsonSerializerSettings) ?? new List(), null) 17 | { 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Infrastructure/BlobStorage/BlobStorageConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Infrastructure.BlobStorage; 2 | 3 | public class BlobStorageConfiguration 4 | { 5 | public string Container { get; set; } 6 | public string ConnectionString { get; set; } 7 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Infrastructure/DependencyInjection.cs: -------------------------------------------------------------------------------- 1 | using GreenOnSoftware.Application.Services.Interfaces; 2 | using GreenOnSoftware.Infrastructure.BlobStorage; 3 | using GreenOnSoftware.Infrastructure.SendGrid; 4 | using Microsoft.Extensions.DependencyInjection; 5 | 6 | namespace GreenOnSoftware.Infrastructure; 7 | 8 | public static class DependencyInjection 9 | { 10 | public static IServiceCollection AddInfrastructure(this IServiceCollection services) 11 | { 12 | services.AddTransient(); 13 | services.AddTransient(); 14 | 15 | return services; 16 | } 17 | } -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Infrastructure/GreenOnSoftware.Infrastructure.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Infrastructure/Security/SecurityConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Infrastructure.Security; 2 | 3 | public class SecurityConfiguration 4 | { 5 | public string AdminNames { get; set; } 6 | public string AdminPassword { get; set; } 7 | } 8 | -------------------------------------------------------------------------------- /dotnet/GreenOnSoftware/GreenOnSoftware.Infrastructure/SendGrid/SendGridConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace GreenOnSoftware.Infrastructure.SendGrid; 2 | 3 | public class SendGridConfiguration 4 | { 5 | public string SenderName { get; set; } 6 | public string SenderEmailAddress { get; set; } 7 | public string ApiKey { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /system/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /system/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /system/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": ["**/*"], 4 | "plugins": ["@nrwl/nx"], 5 | "overrides": [ 6 | { 7 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 8 | "rules": { 9 | "@nrwl/nx/enforce-module-boundaries": [ 10 | "error", 11 | { 12 | "enforceBuildableLibDependency": true, 13 | "allow": [], 14 | "depConstraints": [ 15 | { 16 | "sourceTag": "*", 17 | "onlyDependOnLibsWithTags": ["*"] 18 | } 19 | ] 20 | } 21 | ] 22 | } 23 | }, 24 | { 25 | "files": ["*.ts", "*.tsx"], 26 | "extends": ["plugin:@nrwl/nx/typescript"], 27 | "rules": {} 28 | }, 29 | { 30 | "files": ["*.js", "*.jsx"], 31 | "extends": ["plugin:@nrwl/nx/javascript"], 32 | "rules": {} 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /system/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | dist 5 | tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | 41 | # Next.js 42 | .next 43 | 44 | # Environment 45 | *.env -------------------------------------------------------------------------------- /system/.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | . "$(dirname -- "$0")/_/husky.sh" 4 | 5 | cd system 6 | 7 | echo "Runnig linting and fix..." 8 | 9 | npm run test:checkAll 10 | npm run e2e:checkAll 11 | npm run lint:fixAll 12 | npm run format:fixAll 13 | git add . 14 | -------------------------------------------------------------------------------- /system/.prettierignore: -------------------------------------------------------------------------------- 1 | # Add files here to ignore them from prettier formatting 2 | 3 | /dist 4 | /coverage 5 | -------------------------------------------------------------------------------- /system/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /system/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "esbenp.prettier-vscode", 4 | "nrwl.angular-console", 5 | "firsttris.vscode-jest-runner", 6 | "dbaeumer.vscode-eslint" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /system/README.md: -------------------------------------------------------------------------------- 1 | # System 2 | 3 | 4 | 5 | ✨ **This workspace has been generated by [Nx, a Smart, fast and extensible build system.](https://nx.dev)** ✨ 6 | 7 | ## Development server 8 | 9 | Run `nx serve blog` for a dev server. Navigate to http://localhost:4200/. The app will automatically reload if you change any of the source files. 10 | 11 | ## Understand this workspace 12 | 13 | Run `nx graph` to see a diagram of the dependencies of the projects. 14 | 15 | ## Remote caching 16 | 17 | Run `npx nx connect-to-nx-cloud` to enable [remote caching](https://nx.app) and make CI faster. 18 | 19 | ## Further help 20 | 21 | Visit the [Nx Documentation](https://nx.dev) to learn more. 22 | -------------------------------------------------------------------------------- /system/apps/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/apps/.gitkeep -------------------------------------------------------------------------------- /system/apps/blog-creator-e2e/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:cypress/recommended", "../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /system/apps/blog-creator-e2e/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'cypress'; 2 | import { nxE2EPreset } from '@nrwl/cypress/plugins/cypress-preset'; 3 | 4 | export default defineConfig({ 5 | e2e: nxE2EPreset(__dirname), 6 | }); 7 | -------------------------------------------------------------------------------- /system/apps/blog-creator-e2e/src/e2e/app.cy.ts: -------------------------------------------------------------------------------- 1 | describe('blog-creator', () => { 2 | beforeEach(() => cy.visit('/')); 3 | 4 | it('should display welcome message', () => { 5 | cy.get('h1').contains('Headline1'); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /system/apps/blog-creator-e2e/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io" 4 | } 5 | -------------------------------------------------------------------------------- /system/apps/blog-creator-e2e/src/support/app.po.ts: -------------------------------------------------------------------------------- 1 | export const getGreeting = () => cy.get('h1'); 2 | -------------------------------------------------------------------------------- /system/apps/blog-creator-e2e/src/support/e2e.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands'; 18 | -------------------------------------------------------------------------------- /system/apps/blog-creator-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "sourceMap": false, 5 | "outDir": "../../dist/out-tsc", 6 | "allowJs": true, 7 | "types": ["cypress", "node"] 8 | }, 9 | "include": ["src/**/*.ts", "src/**/*.js", "cypress.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /system/apps/blog-creator/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@nrwl/react/babel", 5 | { 6 | "runtime": "automatic" 7 | } 8 | ] 9 | ], 10 | "plugins": [["styled-components", { "pure": true, "ssr": true }]] 11 | } 12 | -------------------------------------------------------------------------------- /system/apps/blog-creator/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /system/apps/blog-creator/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'blog-creator', 4 | preset: '../../jest.preset.js', 5 | transform: { 6 | '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest', 7 | '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nrwl/react/babel'] }], 8 | }, 9 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 10 | coverageDirectory: '../../coverage/apps/blog-creator', 11 | }; 12 | -------------------------------------------------------------------------------- /system/apps/blog-creator/src/app/app.spec.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react'; 2 | 3 | import { BrowserRouter } from 'react-router-dom'; 4 | 5 | import { App } from './app'; 6 | 7 | describe('App', () => { 8 | it('should render successfully', () => { 9 | const { baseElement } = render( 10 | 11 | 12 | 13 | ); 14 | expect(baseElement).toBeTruthy(); 15 | }); 16 | 17 | it('should have a greeting as the title', () => { 18 | const { getByText } = render( 19 | 20 | 21 | 22 | ); 23 | expect(getByText(/Headline1/gi)).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /system/apps/blog-creator/src/app/app.tsx: -------------------------------------------------------------------------------- 1 | import { Font } from '@system/figa-ui'; 2 | 3 | const App = () => { 4 | return Headline1; 5 | }; 6 | 7 | export { App }; 8 | -------------------------------------------------------------------------------- /system/apps/blog-creator/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/apps/blog-creator/src/assets/.gitkeep -------------------------------------------------------------------------------- /system/apps/blog-creator/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | }; 4 | -------------------------------------------------------------------------------- /system/apps/blog-creator/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // When building for production, this file is replaced with `environment.prod.ts`. 3 | 4 | export const environment = { 5 | production: false, 6 | }; 7 | -------------------------------------------------------------------------------- /system/apps/blog-creator/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/apps/blog-creator/src/favicon.ico -------------------------------------------------------------------------------- /system/apps/blog-creator/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BlogCreator 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /system/apps/blog-creator/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import * as ReactDOM from 'react-dom/client'; 3 | import { BrowserRouter } from 'react-router-dom'; 4 | 5 | import { App } from './app/app'; 6 | import { Sandbox, ThemeProvider } from '@system/figa-ui'; 7 | 8 | const root = ReactDOM.createRoot( 9 | document.getElementById('root') as HTMLElement 10 | ); 11 | 12 | root.render( 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ); 23 | -------------------------------------------------------------------------------- /system/apps/blog-creator/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": ["node"] 6 | }, 7 | "files": [ 8 | "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", 9 | "../../node_modules/@nrwl/react/typings/image.d.ts" 10 | ], 11 | "exclude": [ 12 | "jest.config.ts", 13 | "src/**/*.spec.ts", 14 | "src/**/*.test.ts", 15 | "src/**/*.spec.tsx", 16 | "src/**/*.test.tsx", 17 | "src/**/*.spec.js", 18 | "src/**/*.test.js", 19 | "src/**/*.spec.jsx", 20 | "src/**/*.test.jsx" 21 | ], 22 | "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"] 23 | } 24 | -------------------------------------------------------------------------------- /system/apps/blog-creator/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react-jsx", 4 | "allowJs": false, 5 | "esModuleInterop": false, 6 | "allowSyntheticDefaultImports": true, 7 | "strict": true 8 | }, 9 | "files": [], 10 | "include": [], 11 | "references": [ 12 | { 13 | "path": "./tsconfig.app.json" 14 | }, 15 | { 16 | "path": "./tsconfig.spec.json" 17 | } 18 | ], 19 | "extends": "../../tsconfig.base.json" 20 | } 21 | -------------------------------------------------------------------------------- /system/apps/blog-creator/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/**/*.test.tsx", 13 | "src/**/*.spec.tsx", 14 | "src/**/*.test.js", 15 | "src/**/*.spec.js", 16 | "src/**/*.test.jsx", 17 | "src/**/*.spec.jsx", 18 | "src/**/*.d.ts" 19 | ], 20 | "files": [ 21 | "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", 22 | "../../node_modules/@nrwl/react/typings/image.d.ts" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /system/apps/blog-creator/webpack.config.js: -------------------------------------------------------------------------------- 1 | const { composePlugins, withNx } = require('@nrwl/webpack'); 2 | const { withReact } = require('@nrwl/react'); 3 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 4 | const path = require('path'); 5 | 6 | const copyFonts = (config) => { 7 | config.plugins.push( 8 | new CopyWebpackPlugin({ 9 | patterns: [ 10 | { 11 | from: path.resolve(__dirname, '../../assets/fonts'), 12 | to: 'fonts', 13 | }, 14 | ], 15 | }) 16 | ); 17 | }; 18 | 19 | // Nx plugins for webpack. 20 | module.exports = composePlugins(withNx(), withReact(), (config) => { 21 | // Update the webpack config as needed here. 22 | // e.g. `config.plugins.push(new MyPlugin())` 23 | copyFonts(config); 24 | 25 | return config; 26 | }); 27 | -------------------------------------------------------------------------------- /system/apps/blog-e2e/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:cypress/recommended", "../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["src/plugins/index.js"], 11 | "rules": { 12 | "@typescript-eslint/no-var-requires": "off", 13 | "no-undef": "off" 14 | } 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /system/apps/blog-e2e/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'cypress'; 2 | import { nxE2EPreset } from '@nrwl/cypress/plugins/cypress-preset'; 3 | 4 | export default defineConfig({ 5 | e2e: nxE2EPreset(__dirname), 6 | }); 7 | -------------------------------------------------------------------------------- /system/apps/blog-e2e/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blog-e2e", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "apps/blog-e2e/src", 5 | "projectType": "application", 6 | "targets": { 7 | "e2e": { 8 | "executor": "@nrwl/cypress:cypress", 9 | "options": { 10 | "cypressConfig": "apps/blog-e2e/cypress.config.ts", 11 | "devServerTarget": "blog:serve:development", 12 | "testingType": "e2e" 13 | }, 14 | "configurations": { 15 | "production": { 16 | "devServerTarget": "blog:serve:production" 17 | } 18 | } 19 | }, 20 | "lint": { 21 | "executor": "@nrwl/linter:eslint", 22 | "outputs": ["{options.outputFile}"], 23 | "options": { 24 | "lintFilePatterns": ["apps/blog-e2e/**/*.{js,ts}"] 25 | } 26 | } 27 | }, 28 | "tags": [], 29 | "implicitDependencies": ["blog"] 30 | } 31 | -------------------------------------------------------------------------------- /system/apps/blog-e2e/src/e2e/app.cy.ts: -------------------------------------------------------------------------------- 1 | describe('blog', () => { 2 | beforeEach(() => { 3 | cy.visit('/'); 4 | }); 5 | 6 | it('should display welcome message', () => { 7 | cy.get('h5').contains('articles'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /system/apps/blog-e2e/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io" 4 | } 5 | -------------------------------------------------------------------------------- /system/apps/blog-e2e/src/support/app.po.ts: -------------------------------------------------------------------------------- 1 | export const getGreeting = () => cy.get('h1'); 2 | -------------------------------------------------------------------------------- /system/apps/blog-e2e/src/support/e2e.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands'; 18 | -------------------------------------------------------------------------------- /system/apps/blog-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "sourceMap": false, 5 | "outDir": "../../dist/out-tsc", 6 | "allowJs": true, 7 | "types": ["cypress", "node"] 8 | }, 9 | "include": ["src/**/*.ts", "src/**/*.js", "cypress.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /system/apps/blog/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "plugin:@nrwl/nx/react-typescript", 4 | "next", 5 | "next/core-web-vitals", 6 | "../../.eslintrc.json" 7 | ], 8 | "ignorePatterns": ["!**/*", ".next/**/*"], 9 | "overrides": [ 10 | { 11 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 12 | "rules": { 13 | "@next/next/no-html-link-for-pages": ["error", "apps/blog/pages"] 14 | } 15 | }, 16 | { 17 | "files": ["*.ts", "*.tsx"], 18 | "rules": {} 19 | }, 20 | { 21 | "files": ["*.js", "*.jsx"], 22 | "rules": {} 23 | } 24 | ], 25 | "rules": { 26 | "@next/next/no-html-link-for-pages": "off" 27 | }, 28 | "env": { 29 | "jest": true 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /system/apps/blog/components/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './PageWrapper'; 2 | export * from './main-layout'; 3 | export * from './link'; 4 | -------------------------------------------------------------------------------- /system/apps/blog/components/link/defs.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | interface LinkProps { 4 | href: string; 5 | children: ReactNode; 6 | } 7 | 8 | export type { LinkProps }; 9 | -------------------------------------------------------------------------------- /system/apps/blog/components/link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './defs'; 2 | export * from './link'; 3 | -------------------------------------------------------------------------------- /system/apps/blog/components/link/link.tsx: -------------------------------------------------------------------------------- 1 | import NextLink from 'next/link'; 2 | import type { LinkProps } from './defs'; 3 | 4 | const Link = ({ href, children }: LinkProps) => { 5 | return {children}; 6 | }; 7 | 8 | export { Link }; 9 | -------------------------------------------------------------------------------- /system/apps/blog/components/main-layout/defs.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | interface MainLayoutProps { 4 | children: ReactNode; 5 | } 6 | 7 | export type { MainLayoutProps }; 8 | -------------------------------------------------------------------------------- /system/apps/blog/components/main-layout/index.ts: -------------------------------------------------------------------------------- 1 | export * from './main-layout'; 2 | export * from './defs'; 3 | -------------------------------------------------------------------------------- /system/apps/blog/consts/index.ts: -------------------------------------------------------------------------------- 1 | const GREEN_ON_SOFTWARE_COMPANY = 'https://greenonsoftware.com/'; 2 | const GREEN_ON_SOFTWARE_LINKEDIN = 3 | 'https://www.linkedin.com/company/greenon-software/'; 4 | const GREEN_ON_SOFTWARE_AUTHOR = 5 | 'https://www.linkedin.com/in/adrian-po%C5%82ubi%C5%84ski-281ab2172/'; 6 | const GREEN_ON_SOFTWARE_DISCORD = 'https://discord.gg/PxXQayT3x3'; 7 | 8 | export { 9 | GREEN_ON_SOFTWARE_COMPANY, 10 | GREEN_ON_SOFTWARE_AUTHOR, 11 | GREEN_ON_SOFTWARE_LINKEDIN, 12 | GREEN_ON_SOFTWARE_DISCORD, 13 | }; 14 | -------------------------------------------------------------------------------- /system/apps/blog/content/pl/articles/use-ref-hook.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Siema' 3 | layout: 'post' 4 | --- 5 | 6 | Czesc 7 | 8 | - Raz 9 | - Dwa 10 | - Trzy 11 | 12 | -------------------------------------------------------------------------------- /system/apps/blog/dk/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lang'; 2 | export * from './use-lang'; 3 | -------------------------------------------------------------------------------- /system/apps/blog/dk/lang.ts: -------------------------------------------------------------------------------- 1 | import type { Lang } from '../models'; 2 | 3 | const isLang = (param: string): param is Lang => { 4 | return param === ('en' as Lang) || param === ('pl' as Lang); 5 | }; 6 | 7 | const getLang = (pathname: string): Lang => { 8 | const lang = pathname.split('/')[1]; 9 | 10 | return isLang(lang) ? lang : 'en'; 11 | }; 12 | 13 | export { isLang, getLang }; 14 | -------------------------------------------------------------------------------- /system/apps/blog/dk/tests/lang.test.ts: -------------------------------------------------------------------------------- 1 | import type { Lang } from '../../models'; 2 | import { getLang } from '../lang'; 3 | 4 | describe('Supported language is determined when: ', () => { 5 | it('returns default english language if not detected in pathname', () => { 6 | expect(getLang('/')).toBe('en' as Lang); 7 | }); 8 | 9 | it('takes language from pathname', () => { 10 | expect(getLang('/pl/articles/')).toBe('pl' as Lang); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /system/apps/blog/dk/tests/use-lang.test.ts: -------------------------------------------------------------------------------- 1 | import { renderHook } from '@testing-library/react'; 2 | import { useLang } from '../use-lang'; 3 | import type { Lang } from '../../models'; 4 | import { getLang } from '../lang'; 5 | import { useRouter } from 'next/router'; 6 | 7 | jest.mock('../lang', () => ({ 8 | getLang: jest.fn(), 9 | })); 10 | jest.mock('next/router', () => ({ 11 | useRouter: jest.fn(), 12 | })); 13 | 14 | describe('Language is detected when: ', () => { 15 | it('takes language from next routing system pathname', () => { 16 | (getLang as jest.Mock).mockReturnValueOnce('en' as Lang); 17 | (useRouter as jest.Mock).mockReturnValueOnce({ 18 | pathname: '/en/something/', 19 | }); 20 | 21 | const { result } = renderHook(() => useLang()); 22 | 23 | expect(result.current).toBe('en' as Lang); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /system/apps/blog/dk/use-lang.ts: -------------------------------------------------------------------------------- 1 | import { useRouter } from 'next/router'; 2 | import { useMemo } from 'react'; 3 | import { getLang } from './lang'; 4 | 5 | const useLang = () => { 6 | const router = useRouter(); 7 | 8 | return useMemo(() => getLang(router.pathname), [router]); 9 | }; 10 | 11 | export { useLang }; 12 | -------------------------------------------------------------------------------- /system/apps/blog/index.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | declare module '*.svg' { 3 | const content: any; 4 | export const ReactComponent: any; 5 | export default content; 6 | } 7 | -------------------------------------------------------------------------------- /system/apps/blog/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | export default { 4 | displayName: 'blog', 5 | preset: '../../jest.preset.js', 6 | transform: { 7 | '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest', 8 | '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nrwl/next/babel'] }], 9 | }, 10 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 11 | coverageDirectory: '../../coverage/apps/blog', 12 | }; 13 | -------------------------------------------------------------------------------- /system/apps/blog/models/index.ts: -------------------------------------------------------------------------------- 1 | import type { MDXRemoteSerializeResult } from 'next-mdx-remote'; 2 | 3 | interface ArticlePageProps { 4 | id: string; 5 | source: MDXRemoteSerializeResult; 6 | } 7 | 8 | interface ArticlePageParams { 9 | params: { 10 | id: string; 11 | }; 12 | } 13 | 14 | type Lang = 'pl' | 'en'; 15 | 16 | export type { ArticlePageParams, ArticlePageProps, Lang }; 17 | -------------------------------------------------------------------------------- /system/apps/blog/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /system/apps/blog/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import { ThemeProvider } from '@system/figa-ui'; 2 | import { AppProps } from 'next/app'; 3 | import Head from 'next/head'; 4 | 5 | const App = ({ Component, pageProps }: AppProps) => { 6 | return ( 7 | <> 8 | 9 | Welcome to blog! 10 | 11 | 12 | 13 | 14 | 15 | ); 16 | }; 17 | 18 | export default App; 19 | -------------------------------------------------------------------------------- /system/apps/blog/pages/en/articles/index.tsx: -------------------------------------------------------------------------------- 1 | import { Font } from '@system/figa-ui'; 2 | 3 | const ArticlesPage = () => { 4 | return ArticlesPage; 5 | }; 6 | 7 | export default ArticlesPage; 8 | -------------------------------------------------------------------------------- /system/apps/blog/pages/en/index.tsx: -------------------------------------------------------------------------------- 1 | import { Font } from '@system/figa-ui'; 2 | 3 | const Index = () => { 4 | return England; 5 | }; 6 | 7 | export default Index; 8 | -------------------------------------------------------------------------------- /system/apps/blog/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import type { GetStaticProps } from 'next'; 2 | import { HomeView, type HomeViewProps } from '../views/home'; 3 | import { getArticles } from '@system/blog-api'; 4 | 5 | export const getStaticProps: GetStaticProps = async () => { 6 | const response = await getArticles(); 7 | 8 | return { 9 | props: { 10 | articles: response.data, 11 | }, 12 | }; 13 | }; 14 | 15 | const HomePage = ({ articles }: HomeViewProps) => { 16 | return ; 17 | }; 18 | 19 | export default HomePage; 20 | -------------------------------------------------------------------------------- /system/apps/blog/pages/pl/articles/index.tsx: -------------------------------------------------------------------------------- 1 | import { Font } from '@system/figa-ui'; 2 | 3 | const ArticlesPage = () => { 4 | return ArticlesPage; 5 | }; 6 | 7 | export default ArticlesPage; 8 | -------------------------------------------------------------------------------- /system/apps/blog/pages/pl/index.tsx: -------------------------------------------------------------------------------- 1 | import { Font } from '@system/figa-ui'; 2 | 3 | const Index = () => { 4 | return Polska; 5 | }; 6 | 7 | export default Index; 8 | -------------------------------------------------------------------------------- /system/apps/blog/public/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/apps/blog/public/.gitkeep -------------------------------------------------------------------------------- /system/apps/blog/public/fonts/LexendBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/apps/blog/public/fonts/LexendBold.ttf -------------------------------------------------------------------------------- /system/apps/blog/public/fonts/LexendLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/apps/blog/public/fonts/LexendLight.ttf -------------------------------------------------------------------------------- /system/apps/blog/public/fonts/LexendMedium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/apps/blog/public/fonts/LexendMedium.ttf -------------------------------------------------------------------------------- /system/apps/blog/public/fonts/LexendRegular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/apps/blog/public/fonts/LexendRegular.ttf -------------------------------------------------------------------------------- /system/apps/blog/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "jsx": "preserve", 5 | "allowJs": true, 6 | "esModuleInterop": true, 7 | "allowSyntheticDefaultImports": true, 8 | "strict": false, 9 | "forceConsistentCasingInFileNames": true, 10 | "noEmit": true, 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "incremental": true, 14 | "types": ["jest", "node"] 15 | }, 16 | "include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "next-env.d.ts"], 17 | "exclude": [ 18 | "node_modules", 19 | "jest.config.ts", 20 | "src/**/*.spec.ts", 21 | "src/**/*.test.ts" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /system/apps/blog/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"], 7 | "jsx": "react" 8 | }, 9 | "include": [ 10 | "jest.config.ts", 11 | "src/**/*.test.ts", 12 | "src/**/*.spec.ts", 13 | "src/**/*.test.tsx", 14 | "src/**/*.spec.tsx", 15 | "src/**/*.test.js", 16 | "src/**/*.spec.js", 17 | "src/**/*.test.jsx", 18 | "src/**/*.spec.jsx", 19 | "src/**/*.d.ts" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /system/apps/blog/utils/index.ts: -------------------------------------------------------------------------------- 1 | import type { Lang } from '../models'; 2 | 3 | import { readdir } from 'fs'; 4 | import path from 'path'; 5 | 6 | export const createArticlePath = (lang: Lang, ...rest: string[]): string => 7 | path.join( 8 | process.cwd(), 9 | 'apps', 10 | 'blog', 11 | 'content', 12 | lang, 13 | 'articles', 14 | ...rest 15 | ); 16 | 17 | export const getArticlesIds = (lang: Lang): Promise => { 18 | return new Promise((resolve, reject) => { 19 | const dirPath = createArticlePath(lang); 20 | 21 | readdir(dirPath, { withFileTypes: true }, (err, files) => { 22 | if (err) { 23 | reject(err); 24 | } 25 | 26 | resolve( 27 | files 28 | .filter((file) => file.isFile()) 29 | .map((file) => file.name.replace('.mdx', '')) 30 | ); 31 | }); 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /system/apps/blog/views/home/defs.ts: -------------------------------------------------------------------------------- 1 | import type { ArticleDto } from '@system/blog-api'; 2 | 3 | interface HomeViewProps { 4 | articles: ArticleDto[]; 5 | } 6 | 7 | export type { HomeViewProps }; 8 | -------------------------------------------------------------------------------- /system/apps/blog/views/home/index.ts: -------------------------------------------------------------------------------- 1 | export * from './defs'; 2 | export * from './home.view'; 3 | -------------------------------------------------------------------------------- /system/apps/jamjam-e2e/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:cypress/recommended", "../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /system/apps/jamjam-e2e/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'cypress'; 2 | import { nxE2EPreset } from '@nrwl/cypress/plugins/cypress-preset'; 3 | 4 | export default defineConfig({ 5 | e2e: nxE2EPreset(__dirname), 6 | }); 7 | -------------------------------------------------------------------------------- /system/apps/jamjam-e2e/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jamjam-e2e", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "apps/jamjam-e2e/src", 5 | "projectType": "application", 6 | "targets": { 7 | "e2e": { 8 | "executor": "@nrwl/cypress:cypress", 9 | "options": { 10 | "cypressConfig": "apps/jamjam-e2e/cypress.config.ts", 11 | "devServerTarget": "jamjam:serve:development", 12 | "testingType": "e2e" 13 | }, 14 | "configurations": { 15 | "production": { 16 | "devServerTarget": "jamjam:serve:production" 17 | } 18 | } 19 | }, 20 | "lint": { 21 | "executor": "@nrwl/linter:eslint", 22 | "outputs": ["{options.outputFile}"], 23 | "options": { 24 | "lintFilePatterns": ["apps/jamjam-e2e/**/*.{js,ts}"] 25 | } 26 | } 27 | }, 28 | "tags": [], 29 | "implicitDependencies": ["jamjam"] 30 | } 31 | -------------------------------------------------------------------------------- /system/apps/jamjam-e2e/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io" 4 | } 5 | -------------------------------------------------------------------------------- /system/apps/jamjam-e2e/src/support/app.po.ts: -------------------------------------------------------------------------------- 1 | export const getGreeting = () => cy.get('h1'); 2 | -------------------------------------------------------------------------------- /system/apps/jamjam-e2e/src/support/e2e.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands'; 18 | -------------------------------------------------------------------------------- /system/apps/jamjam-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "sourceMap": false, 5 | "outDir": "../../dist/out-tsc", 6 | "allowJs": true, 7 | "types": ["cypress", "node"] 8 | }, 9 | "include": ["src/**/*.ts", "src/**/*.js", "cypress.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /system/apps/jamjam/components/guitar-fretboard/consts.ts: -------------------------------------------------------------------------------- 1 | import type { GuitarFret } from '../../domain'; 2 | 3 | const NOTES_COLORS = [ 4 | '#f08989', 5 | '#cc9d72', 6 | '#a4cc72', 7 | '#72cc76', 8 | '#72ccbc', 9 | '#72b1cc', 10 | '#729bcc', 11 | '#9a72cc', 12 | '#728bcc', 13 | '#7f72cc', 14 | '#c572cc', 15 | '#cc72a8', 16 | ] as const; 17 | 18 | const DEFAULT_FRETS_MARKERS: GuitarFret[] = [ 19 | 3, 5, 7, 9, 12, 15, 17, 19, 21, 24, 20 | ]; 21 | 22 | export { NOTES_COLORS, DEFAULT_FRETS_MARKERS }; 23 | -------------------------------------------------------------------------------- /system/apps/jamjam/components/guitar-fretboard/defs.ts: -------------------------------------------------------------------------------- 1 | import type { MouseEventHandler, ReactElement } from 'react'; 2 | 3 | import type { 4 | Guitar, 5 | GuitarFret, 6 | GuitarString, 7 | Note, 8 | NoteId, 9 | NoteNotation, 10 | NoteOctave, 11 | } from '../../domain'; 12 | 13 | interface NoteButtonProps { 14 | noteOctave: NoteOctave; 15 | noteId: NoteId; 16 | notation: NoteNotation; 17 | onClick: MouseEventHandler; 18 | } 19 | 20 | interface GuitarFretboardProps { 21 | className?: string; 22 | guitar: Guitar; 23 | fretsMarkers?: GuitarFret[]; 24 | notation: NoteNotation; 25 | NoteComponent?: (props: NoteButtonProps) => ReactElement; 26 | onNoteClick?: (note: Note) => void; 27 | } 28 | 29 | interface GuitarFretboardStringsProps { 30 | strings: GuitarString[]; 31 | } 32 | 33 | export type { 34 | GuitarFretboardProps, 35 | NoteButtonProps, 36 | GuitarFretboardStringsProps, 37 | }; 38 | -------------------------------------------------------------------------------- /system/apps/jamjam/components/guitar-fretboard/guitar-fretboard-strings.tsx: -------------------------------------------------------------------------------- 1 | import type { GuitarFretboardStringsProps } from './defs'; 2 | 3 | const GuitarFretboardStrings = ({ strings }: GuitarFretboardStringsProps) => { 4 | return ( 5 |
6 | {strings.map(({ number }, idx) => ( 7 |
8 |
12 |
13 | ))} 14 |
15 | ); 16 | }; 17 | 18 | export { GuitarFretboardStrings }; 19 | -------------------------------------------------------------------------------- /system/apps/jamjam/components/guitar-fretboard/index.ts: -------------------------------------------------------------------------------- 1 | export * from './guitar-fretboard'; 2 | export * from './note-button'; 3 | export * from './defs'; 4 | -------------------------------------------------------------------------------- /system/apps/jamjam/components/guitar-fretboard/tests/consts.test.ts: -------------------------------------------------------------------------------- 1 | import { NOTE_IDS } from '../../../domain'; 2 | import { NOTES_COLORS, DEFAULT_FRETS_MARKERS } from '../consts'; 3 | 4 | describe('creates default setup when', () => { 5 | it('number of colors are equal to number of notes', () => { 6 | expect(NOTES_COLORS.length).toBe(NOTE_IDS.length); 7 | }); 8 | 9 | it('markers are equal to default guitar markers positions', () => { 10 | expect(DEFAULT_FRETS_MARKERS).toEqual([3, 5, 7, 9, 12, 15, 17, 19, 21, 24]); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /system/apps/jamjam/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './guitar-fretboard'; 2 | -------------------------------------------------------------------------------- /system/apps/jamjam/domain/index.ts: -------------------------------------------------------------------------------- 1 | export * from './music-theory'; 2 | -------------------------------------------------------------------------------- /system/apps/jamjam/domain/music-theory/index.ts: -------------------------------------------------------------------------------- 1 | export * from './defs'; 2 | export * from './consts'; 3 | export * from './core'; 4 | -------------------------------------------------------------------------------- /system/apps/jamjam/features/guitar-notes-teacher/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './links'; 2 | -------------------------------------------------------------------------------- /system/apps/jamjam/features/guitar-notes-teacher/components/links/index.ts: -------------------------------------------------------------------------------- 1 | export * from './links'; 2 | -------------------------------------------------------------------------------- /system/apps/jamjam/features/guitar-notes-teacher/guitar-notes-teacher.feature.tsx: -------------------------------------------------------------------------------- 1 | import { useGuitarNotesTeacherFacade } from './use-guitar-notes-teacher.facade'; 2 | import { GuitarNotesTeacherView } from './guitar-notes-teacher.view'; 3 | 4 | const GuitarNotesTeacherFeature = () => { 5 | const machine = useGuitarNotesTeacherFacade(); 6 | 7 | return ; 8 | }; 9 | 10 | export { GuitarNotesTeacherFeature }; 11 | -------------------------------------------------------------------------------- /system/apps/jamjam/features/guitar-notes-teacher/guitar-notes-teacher.selectors.ts: -------------------------------------------------------------------------------- 1 | import { getNoteSymbol } from '../../domain'; 2 | 3 | import type { PlayingState, StartedState } from './guitar-notes-teacher.defs'; 4 | 5 | const getCurrentQuestion = ( 6 | state: S 7 | ) => { 8 | const { 9 | answers: { length }, 10 | } = state; 11 | const noteId = state.questions.at(state.answers.length); 12 | 13 | if (noteId === undefined) { 14 | throw Error( 15 | `Cannot find current question for ${noteId} and answer length ${length}` 16 | ); 17 | } 18 | 19 | return getNoteSymbol(noteId, state.settings.notation); 20 | }; 21 | 22 | export { getCurrentQuestion }; 23 | -------------------------------------------------------------------------------- /system/apps/jamjam/features/guitar-notes-teacher/index.ts: -------------------------------------------------------------------------------- 1 | export * from './guitar-notes-teacher.feature'; 2 | -------------------------------------------------------------------------------- /system/apps/jamjam/index.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | declare module '*.svg' { 3 | const content: any; 4 | export const ReactComponent: any; 5 | export default content; 6 | } 7 | -------------------------------------------------------------------------------- /system/apps/jamjam/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'jamjam', 4 | preset: '../../jest.preset.js', 5 | transform: { 6 | '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest', 7 | '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nrwl/next/babel'] }], 8 | }, 9 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 10 | coverageDirectory: '../../coverage/apps/jamjam', 11 | }; 12 | -------------------------------------------------------------------------------- /system/apps/jamjam/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /system/apps/jamjam/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import { ThemeProvider } from '@system/figa-ui'; 2 | import type { AppProps } from 'next/app'; 3 | import Head from 'next/head'; 4 | 5 | function CustomApp({ Component, pageProps }: AppProps) { 6 | return ( 7 | <> 8 | 9 | Welcome to jamjam! 10 | 11 | 12 | 13 | 14 | 15 | ); 16 | } 17 | 18 | export default CustomApp; 19 | -------------------------------------------------------------------------------- /system/apps/jamjam/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { GuitarNotesTeacherFeature } from '../features/guitar-notes-teacher'; 2 | 3 | const Index = () => { 4 | return ; 5 | }; 6 | 7 | export default Index; 8 | -------------------------------------------------------------------------------- /system/apps/jamjam/public/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/apps/jamjam/public/.gitkeep -------------------------------------------------------------------------------- /system/apps/jamjam/public/fonts/LexendBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/apps/jamjam/public/fonts/LexendBold.ttf -------------------------------------------------------------------------------- /system/apps/jamjam/public/fonts/LexendLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/apps/jamjam/public/fonts/LexendLight.ttf -------------------------------------------------------------------------------- /system/apps/jamjam/public/fonts/LexendMedium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/apps/jamjam/public/fonts/LexendMedium.ttf -------------------------------------------------------------------------------- /system/apps/jamjam/public/fonts/LexendRegular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/apps/jamjam/public/fonts/LexendRegular.ttf -------------------------------------------------------------------------------- /system/apps/jamjam/specs/index.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | 4 | import Index from '../pages/index'; 5 | 6 | describe('Index', () => { 7 | it('should render successfully', () => { 8 | const { baseElement } = render(); 9 | expect(baseElement).toBeTruthy(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /system/apps/jamjam/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"], 7 | "jsx": "react" 8 | }, 9 | "include": [ 10 | "jest.config.ts", 11 | "src/**/*.test.ts", 12 | "src/**/*.spec.ts", 13 | "src/**/*.test.tsx", 14 | "src/**/*.spec.tsx", 15 | "src/**/*.test.js", 16 | "src/**/*.spec.js", 17 | "src/**/*.test.jsx", 18 | "src/**/*.spec.jsx", 19 | "src/**/*.d.ts" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /system/apps/jamjam/utils/index.test.ts: -------------------------------------------------------------------------------- 1 | import { getLast } from '.'; 2 | 3 | describe('is able to return last element when', () => { 4 | it('for arrays returns first from right', () => { 5 | expect(getLast([1, 2, 3])).toBe(3); 6 | }); 7 | 8 | it('returns undefined for empty or not array types', () => { 9 | expect(getLast([])).toBe(undefined); 10 | }); 11 | 12 | it('original array is not changed', () => { 13 | const arr = [1, 2, 3]; 14 | 15 | getLast(arr); 16 | 17 | expect(arr.length).toBe(arr.length); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /system/apps/jamjam/utils/index.ts: -------------------------------------------------------------------------------- 1 | const getLast = (items: T[]): T | undefined => 2 | (Array.isArray(items) ? items : []).at(-1); 3 | 4 | export { getLast }; 5 | -------------------------------------------------------------------------------- /system/apps/sparkle-flicks-e2e/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:cypress/recommended", "../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /system/apps/sparkle-flicks-e2e/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'cypress'; 2 | import { nxE2EPreset } from '@nrwl/cypress/plugins/cypress-preset'; 3 | 4 | export default defineConfig({ 5 | e2e: nxE2EPreset(__dirname), 6 | }); 7 | -------------------------------------------------------------------------------- /system/apps/sparkle-flicks-e2e/src/e2e/app.cy.ts: -------------------------------------------------------------------------------- 1 | describe('home page', () => { 2 | beforeEach(() => { 3 | cy.visit('/'); 4 | }); 5 | 6 | it('should display welcome message', () => { 7 | cy.get('h5').contains('Sparkle flicks'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /system/apps/sparkle-flicks-e2e/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io" 4 | } 5 | -------------------------------------------------------------------------------- /system/apps/sparkle-flicks-e2e/src/support/e2e.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands'; 18 | -------------------------------------------------------------------------------- /system/apps/sparkle-flicks-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "sourceMap": false, 5 | "outDir": "../../dist/out-tsc", 6 | "allowJs": true, 7 | "types": ["cypress", "node"] 8 | }, 9 | "include": ["src/**/*.ts", "src/**/*.js", "cypress.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /system/apps/sparkle-flicks/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "plugin:@nrwl/nx/react-typescript", 4 | "next", 5 | "next/core-web-vitals", 6 | "../../.eslintrc.json" 7 | ], 8 | "ignorePatterns": ["!**/*", ".next/**/*"], 9 | "overrides": [ 10 | { 11 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 12 | "rules": { 13 | "@next/next/no-html-link-for-pages": [ 14 | "error", 15 | "apps/sparkle-flicks/pages" 16 | ] 17 | } 18 | }, 19 | { 20 | "files": ["*.ts", "*.tsx"], 21 | "rules": {} 22 | }, 23 | { 24 | "files": ["*.js", "*.jsx"], 25 | "rules": {} 26 | } 27 | ], 28 | "rules": { 29 | "@next/next/no-html-link-for-pages": "off" 30 | }, 31 | "env": { 32 | "jest": true 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /system/apps/sparkle-flicks/index.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | declare module '*.svg' { 3 | const content: any; 4 | export const ReactComponent: any; 5 | export default content; 6 | } 7 | -------------------------------------------------------------------------------- /system/apps/sparkle-flicks/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'sparkle-flicks', 4 | preset: '../../jest.preset.js', 5 | transform: { 6 | '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest', 7 | '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nrwl/next/babel'] }], 8 | }, 9 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 10 | coverageDirectory: '../../coverage/apps/sparkle-flicks', 11 | }; 12 | -------------------------------------------------------------------------------- /system/apps/sparkle-flicks/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /system/apps/sparkle-flicks/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import { ThemeProvider } from '@system/figa-ui'; 2 | import type { AppProps } from 'next/app'; 3 | import Head from 'next/head'; 4 | 5 | function CustomApp({ Component, pageProps }: AppProps) { 6 | return ( 7 | <> 8 | 9 | Welcome to sparkle-flicks! 10 | 11 |
12 | 13 | 14 | 15 |
16 | 17 | ); 18 | } 19 | 20 | export default CustomApp; 21 | -------------------------------------------------------------------------------- /system/apps/sparkle-flicks/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { Font } from '@system/figa-ui'; 2 | 3 | const IndexPage = () => { 4 | return Sparkle flicks; 5 | }; 6 | 7 | export default IndexPage; 8 | -------------------------------------------------------------------------------- /system/apps/sparkle-flicks/public/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/apps/sparkle-flicks/public/.gitkeep -------------------------------------------------------------------------------- /system/apps/sparkle-flicks/public/fonts/LexendBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/apps/sparkle-flicks/public/fonts/LexendBold.ttf -------------------------------------------------------------------------------- /system/apps/sparkle-flicks/public/fonts/LexendLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/apps/sparkle-flicks/public/fonts/LexendLight.ttf -------------------------------------------------------------------------------- /system/apps/sparkle-flicks/public/fonts/LexendMedium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/apps/sparkle-flicks/public/fonts/LexendMedium.ttf -------------------------------------------------------------------------------- /system/apps/sparkle-flicks/public/fonts/LexendRegular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/apps/sparkle-flicks/public/fonts/LexendRegular.ttf -------------------------------------------------------------------------------- /system/apps/sparkle-flicks/specs/index.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | 4 | import Index from '../pages/index'; 5 | 6 | describe('Index', () => { 7 | it('should render successfully', () => { 8 | const { baseElement } = render(); 9 | expect(baseElement).toBeTruthy(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /system/apps/sparkle-flicks/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"], 7 | "jsx": "react" 8 | }, 9 | "include": [ 10 | "jest.config.ts", 11 | "src/**/*.test.ts", 12 | "src/**/*.spec.ts", 13 | "src/**/*.test.tsx", 14 | "src/**/*.spec.tsx", 15 | "src/**/*.test.js", 16 | "src/**/*.spec.js", 17 | "src/**/*.test.jsx", 18 | "src/**/*.spec.jsx", 19 | "src/**/*.d.ts" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /system/assets/fonts/LexendBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/assets/fonts/LexendBold.ttf -------------------------------------------------------------------------------- /system/assets/fonts/LexendLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/assets/fonts/LexendLight.ttf -------------------------------------------------------------------------------- /system/assets/fonts/LexendMedium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/assets/fonts/LexendMedium.ttf -------------------------------------------------------------------------------- /system/assets/fonts/LexendRegular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/assets/fonts/LexendRegular.ttf -------------------------------------------------------------------------------- /system/babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "babelrcRoots": ["*"] 3 | } 4 | -------------------------------------------------------------------------------- /system/jest.config.ts: -------------------------------------------------------------------------------- 1 | import { getJestProjects } from '@nrwl/jest'; 2 | 3 | export default { 4 | projects: getJestProjects(), 5 | }; 6 | -------------------------------------------------------------------------------- /system/jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require('@nrwl/jest/preset').default; 2 | 3 | module.exports = { ...nxPreset }; 4 | -------------------------------------------------------------------------------- /system/libs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/libs/.gitkeep -------------------------------------------------------------------------------- /system/libs/blog-api/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /system/libs/blog-api/README.md: -------------------------------------------------------------------------------- 1 | # blog-api 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Building 6 | 7 | Run `nx build blog-api` to build the library. 8 | 9 | ## Running unit tests 10 | 11 | Run `nx test blog-api` to execute the unit tests via [Jest](https://jestjs.io). 12 | -------------------------------------------------------------------------------- /system/libs/blog-api/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'blog-api', 4 | preset: '../../jest.preset.js', 5 | globals: { 6 | 'ts-jest': { 7 | tsconfig: '/tsconfig.spec.json', 8 | }, 9 | }, 10 | transform: { 11 | '^.+\\.[tj]s$': 'ts-jest', 12 | }, 13 | moduleFileExtensions: ['ts', 'js', 'html'], 14 | coverageDirectory: '../../coverage/libs/blog-api', 15 | }; 16 | -------------------------------------------------------------------------------- /system/libs/blog-api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@system/blog-api", 3 | "version": "0.0.1", 4 | "type": "commonjs" 5 | } 6 | -------------------------------------------------------------------------------- /system/libs/blog-api/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './models'; 2 | export * from './lib'; 3 | -------------------------------------------------------------------------------- /system/libs/blog-api/src/lib/account.ts: -------------------------------------------------------------------------------- 1 | import type { SignOutResponse, SignInPayload, SignInResponse } from '../models'; 2 | import { pst } from './instance'; 3 | 4 | export const signOut = async (): Promise => { 5 | const { data } = await pst('Account/SignOut'); 6 | 7 | return data; 8 | }; 9 | 10 | export const signIn = async ( 11 | payload: SignInPayload 12 | ): Promise => { 13 | await pst('Account/SignIn', payload); 14 | }; 15 | -------------------------------------------------------------------------------- /system/libs/blog-api/src/lib/articles.ts: -------------------------------------------------------------------------------- 1 | import type { GetArticlesResponse, GetArticlesSearchParams } from '../models'; 2 | import { get } from './instance'; 3 | 4 | export const getArticles = async ( 5 | params?: GetArticlesSearchParams 6 | ): Promise => { 7 | const { data } = await get('Articles', { params }); 8 | 9 | return data; 10 | }; 11 | -------------------------------------------------------------------------------- /system/libs/blog-api/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './articles'; 2 | export * from './account'; 3 | -------------------------------------------------------------------------------- /system/libs/blog-api/src/lib/instance.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | declare const process: { 4 | env: { 5 | NEXT_PUBLIC_API_URL?: string; 6 | }; 7 | }; 8 | 9 | const getAPIUrl = () => { 10 | const url = process.env.NEXT_PUBLIC_API_URL; 11 | 12 | if (url === undefined) { 13 | throw Error('Lack of process.env.NEXT_PUBLIC_API_URL'); 14 | } 15 | 16 | return url; 17 | }; 18 | 19 | const { 20 | get, 21 | post: pst, 22 | put, 23 | patch: pch, 24 | delete: del, 25 | } = axios.create({ 26 | baseURL: getAPIUrl(), 27 | withCredentials: true, 28 | headers: { 29 | 'Content-Type': 'application/json', 30 | }, 31 | }); 32 | 33 | export { get, pst, put, pch, del }; 34 | -------------------------------------------------------------------------------- /system/libs/blog-api/src/models/account.ts: -------------------------------------------------------------------------------- 1 | import type { Login, Password } from './general'; 2 | 3 | type SignInResponse = void; 4 | interface SignInPayload { 5 | login: Login; 6 | password: Password; 7 | } 8 | 9 | type SignOutResponse = void; 10 | 11 | export type { SignInResponse, SignInPayload, SignOutResponse }; 12 | -------------------------------------------------------------------------------- /system/libs/blog-api/src/models/articles.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Description, 3 | Email, 4 | Id, 5 | Name, 6 | PaginatedResponse, 7 | Title, 8 | Url, 9 | } from './general'; 10 | 11 | type ArticleStatus = 'Draft' | 'WaitingForApproval' | 'NeedWork' | 'Accepted'; 12 | 13 | interface ArticleDto { 14 | id: Id; 15 | title: Title; 16 | description: Description; 17 | authorEmail: Email; 18 | authorName: Name; 19 | thumbnailUrl: Url; 20 | status: ArticleStatus; 21 | url: Url; 22 | } 23 | 24 | type GetArticlesResponse = PaginatedResponse; 25 | interface GetArticlesSearchParams { 26 | Search?: string; 27 | ItemsPerPage?: number; 28 | CurrentPage?: number; 29 | } 30 | 31 | export type { 32 | ArticleDto, 33 | ArticleStatus, 34 | GetArticlesResponse, 35 | GetArticlesSearchParams, 36 | }; 37 | -------------------------------------------------------------------------------- /system/libs/blog-api/src/models/general.ts: -------------------------------------------------------------------------------- 1 | type Description = string; 2 | type Id = string; 3 | type Title = string; 4 | type Email = string; 5 | type Name = string; 6 | type Url = string; 7 | type Login = string; 8 | type Password = string; 9 | type DateStamp = string; 10 | 11 | interface ResponseError { 12 | key: string; 13 | message: 'string'; 14 | } 15 | 16 | interface Response { 17 | success: boolean; 18 | hasErrors: boolean; 19 | errors: ResponseError[]; 20 | data: D; 21 | } 22 | 23 | interface PaginatedResponse extends Response { 24 | itemsPerPage: number; 25 | totalPages: number; 26 | currentPage: number; 27 | currentPageItemsNumber: number; 28 | } 29 | 30 | export type { 31 | Id, 32 | Description, 33 | Title, 34 | Name, 35 | Email, 36 | Url, 37 | Response, 38 | PaginatedResponse, 39 | Login, 40 | Password, 41 | DateStamp, 42 | }; 43 | -------------------------------------------------------------------------------- /system/libs/blog-api/src/models/index.ts: -------------------------------------------------------------------------------- 1 | export * from './account'; 2 | export * from './articles'; 3 | export * from './general'; 4 | -------------------------------------------------------------------------------- /system/libs/blog-api/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "forceConsistentCasingInFileNames": true, 6 | "strict": true, 7 | "noImplicitOverride": true, 8 | "noPropertyAccessFromIndexSignature": true, 9 | "noImplicitReturns": true, 10 | "noFallthroughCasesInSwitch": 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 | -------------------------------------------------------------------------------- /system/libs/blog-api/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 | -------------------------------------------------------------------------------- /system/libs/blog-api/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 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/README.md: -------------------------------------------------------------------------------- 1 | # figa-hooks 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test figa-hooks` to execute the unit tests via [Vitest](https://vitest.dev/). 8 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'figa-hooks', 4 | preset: '../../jest.preset.js', 5 | transform: { 6 | '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest', 7 | '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nrwl/react/babel'] }], 8 | }, 9 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 10 | coverageDirectory: '../../coverage/libs/figa-hooks', 11 | }; 12 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@system/figa-hooks", 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 | } 13 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/use-portal'; 2 | export * from './lib/use-toggle'; 3 | export * from './lib/use-intersection-observer'; 4 | export * from './lib/use-click-outside'; 5 | export * from './lib/use-stepper'; 6 | export * from './lib/use-scroll-y'; 7 | export * from './lib/use-client-effect'; 8 | export * from './lib/use-client-layout-effect'; 9 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/src/lib/use-click-outside/defs.ts: -------------------------------------------------------------------------------- 1 | import type { MutableRefObject } from 'react'; 2 | 3 | /** 4 | * We'll pass this config object to hook. 5 | */ 6 | interface UseClickOutsideConfig { 7 | /** 8 | * Function to call when clicked outside. 9 | */ 10 | onOutside: () => void; 11 | } 12 | 13 | /** 14 | * We'll return this object from hook. 15 | */ 16 | interface UseClickOutsideReturn { 17 | /** 18 | * Reference to any HTML element. 19 | * The @T parameter is the type of the element we'll 20 | * pass. It must extend from @HTMLElement type. 21 | */ 22 | ref: MutableRefObject; 23 | } 24 | 25 | export type { UseClickOutsideConfig, UseClickOutsideReturn }; 26 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/src/lib/use-click-outside/index.ts: -------------------------------------------------------------------------------- 1 | export * from './defs'; 2 | export * from './use-click-outside'; 3 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/src/lib/use-client-effect/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-client-effect'; 2 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/src/lib/use-client-effect/use-client-effect.ts: -------------------------------------------------------------------------------- 1 | import { type DependencyList, useEffect, type EffectCallback } from 'react'; 2 | 3 | import { isClient } from '@system/utils'; 4 | 5 | /** 6 | * Works exactly like useEffect hook but only on the client side. 7 | * 8 | * @param {cb} - Callback function to call if dependency changes. 9 | * @returns {deps} - List of deps. When one of them changes reference or value 10 | * it will trigger a callback. 11 | */ 12 | const useClientEffect = (cb: EffectCallback, deps: DependencyList = []) => { 13 | useEffect(() => { 14 | if (isClient()) { 15 | const cleanUp = cb(); 16 | 17 | return () => { 18 | cleanUp && cleanUp(); 19 | }; 20 | } 21 | // eslint-disable-next-line react-hooks/exhaustive-deps 22 | }, deps); 23 | }; 24 | 25 | export { useClientEffect }; 26 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/src/lib/use-client-layout-effect/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-client-layout-effect'; 2 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/src/lib/use-client-layout-effect/use-client-layout-effect.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | type DependencyList, 3 | useLayoutEffect, 4 | type EffectCallback, 5 | } from 'react'; 6 | 7 | import { isClient } from '@system/utils'; 8 | 9 | /** 10 | * Works exactly like useLayoutEffect hook but only on the client side. 11 | * 12 | * @param {cb} - Callback function to call if dependency changes. 13 | * @returns {deps} - List of deps. When one of them changes reference or value 14 | * it will trigger a callback. 15 | */ 16 | const useClientLayoutEffect = ( 17 | cb: EffectCallback, 18 | deps: DependencyList = [] 19 | ) => { 20 | useLayoutEffect(() => { 21 | if (isClient()) { 22 | const cleanUp = cb(); 23 | 24 | return () => { 25 | cleanUp && cleanUp(); 26 | }; 27 | } 28 | // eslint-disable-next-line react-hooks/exhaustive-deps 29 | }, deps); 30 | }; 31 | 32 | export { useClientLayoutEffect }; 33 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/src/lib/use-intersection-observer/defs.ts: -------------------------------------------------------------------------------- 1 | import type { MutableRefObject } from 'react'; 2 | 3 | /** 4 | * We'll pass this config object to hook. 5 | */ 6 | type IntersectionObserverConfig = IntersectionObserverInit; 7 | 8 | /** 9 | * We'll return this object from hook. 10 | */ 11 | interface IntersectionObserverReturn { 12 | /** 13 | * Reference to any HTML element. 14 | * The @T parameter is the type of the element we'll 15 | * pass. It must extend from @HTMLElement type. 16 | */ 17 | ref: MutableRefObject; 18 | /** 19 | * Indicates whether the item is visible. 20 | */ 21 | visible: boolean; 22 | } 23 | 24 | export type { IntersectionObserverConfig, IntersectionObserverReturn }; 25 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/src/lib/use-intersection-observer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './defs'; 2 | export * from './use-intersection-observer'; 3 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/src/lib/use-portal/defs.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode, ReactPortal } from 'react'; 2 | 3 | type RenderPortal = (children: ReactNode) => ReactPortal | null; 4 | 5 | type UsePortal = () => { 6 | render: RenderPortal; 7 | }; 8 | 9 | export type { UsePortal, RenderPortal }; 10 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/src/lib/use-portal/index.ts: -------------------------------------------------------------------------------- 1 | export * from './defs'; 2 | export * from './use-portal'; 3 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/src/lib/use-scroll-y/index.ts: -------------------------------------------------------------------------------- 1 | export * from './defs'; 2 | export * from './use-scroll-y'; 3 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/src/lib/use-stepper/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-stepper'; 2 | export * from './defs'; 3 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/src/lib/use-toggle/defs.ts: -------------------------------------------------------------------------------- 1 | interface UseToggleReturn { 2 | isOpen: boolean; 3 | open: () => void; 4 | close: () => void; 5 | toggle: () => void; 6 | } 7 | 8 | type UseTogglePayload = [boolean?]; 9 | 10 | export type { UseTogglePayload, UseToggleReturn }; 11 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/src/lib/use-toggle/index.ts: -------------------------------------------------------------------------------- 1 | export * from './defs'; 2 | export * from './use-toggle'; 3 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/src/lib/use-toggle/use-toggle.tsx: -------------------------------------------------------------------------------- 1 | import type { UseTogglePayload, UseToggleReturn } from './defs'; 2 | 3 | import { useState } from 'react'; 4 | 5 | const useToggle = (...payload: UseTogglePayload): UseToggleReturn => { 6 | const [initialOpen = false] = payload; 7 | const [isOpen, setIsOpen] = useState(initialOpen); 8 | 9 | const open = () => { 10 | setIsOpen(true); 11 | }; 12 | 13 | const close = () => { 14 | setIsOpen(false); 15 | }; 16 | 17 | const toggle = () => { 18 | setIsOpen((prev) => !prev); 19 | }; 20 | 21 | return { isOpen, open, close, toggle }; 22 | }; 23 | 24 | export { useToggle }; 25 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react-jsx", 4 | "allowJs": false, 5 | "esModuleInterop": false, 6 | "allowSyntheticDefaultImports": true, 7 | "strict": true, 8 | "types": ["vite/client"] 9 | }, 10 | "files": [], 11 | "include": [], 12 | "references": [ 13 | { 14 | "path": "./tsconfig.lib.json" 15 | }, 16 | { 17 | "path": "./tsconfig.spec.json" 18 | } 19 | ], 20 | "extends": "../../tsconfig.base.json" 21 | } 22 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": ["node"] 6 | }, 7 | "files": [ 8 | "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", 9 | "../../node_modules/@nrwl/react/typings/image.d.ts" 10 | ], 11 | "exclude": [ 12 | "**/*.spec.ts", 13 | "**/*.test.ts", 14 | "**/*.spec.tsx", 15 | "**/*.test.tsx", 16 | "**/*.spec.js", 17 | "**/*.test.js", 18 | "**/*.spec.jsx", 19 | "**/*.test.jsx" 20 | ], 21 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] 22 | } 23 | -------------------------------------------------------------------------------- /system/libs/figa-hooks/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/**/*.test.tsx", 13 | "src/**/*.spec.tsx", 14 | "src/**/*.test.js", 15 | "src/**/*.spec.js", 16 | "src/**/*.test.jsx", 17 | "src/**/*.spec.jsx", 18 | "src/**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /system/libs/figa-ui/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /system/libs/figa-ui/.storybook/main.js: -------------------------------------------------------------------------------- 1 | const { mergeConfig } = require('vite'); 2 | const viteTsConfigPaths = require('vite-tsconfig-paths').default; 3 | 4 | module.exports = { 5 | core: { builder: '@storybook/builder-vite' }, 6 | stories: [ 7 | '../src/lib/**/*.stories.mdx', 8 | '../src/lib/**/*.stories.@(js|jsx|ts|tsx)', 9 | ], 10 | addons: ['@storybook/addon-essentials'], 11 | staticDirs: [{ from: '../../../assets', to: '/' }], 12 | async viteFinal(config, { configType }) { 13 | return mergeConfig(config, { 14 | plugins: [ 15 | viteTsConfigPaths({ 16 | root: '../../../', 17 | }), 18 | ], 19 | }); 20 | }, 21 | }; 22 | 23 | // To customize your Vite configuration you can use the viteFinal field. 24 | // Check https://storybook.js.org/docs/react/builders/vite#configuration 25 | // and https://nx.dev/packages/storybook/documents/custom-builder-configs 26 | -------------------------------------------------------------------------------- /system/libs/figa-ui/.storybook/preview.tsx: -------------------------------------------------------------------------------- 1 | import type { DecoratorFunction } from '@storybook/addons'; 2 | import type { Story } from '@storybook/react'; 3 | import { ThemeProvider } from '../src/lib/theme-provider'; 4 | import { Sandbox } from '../src/lib/sandbox'; 5 | 6 | const withGlobalStyleDecorator: DecoratorFunction = ( 7 | StoryComponent: Story 8 | ) => ( 9 | 10 | 11 | 12 | 13 | 14 | ); 15 | 16 | const decorators = [withGlobalStyleDecorator]; 17 | 18 | export { decorators }; 19 | -------------------------------------------------------------------------------- /system/libs/figa-ui/.storybook/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "emitDecoratorMetadata": true, 5 | "outDir": "" 6 | }, 7 | "files": [ 8 | "../../../node_modules/@nrwl/react/typings/styled-jsx.d.ts", 9 | "../../../node_modules/@nrwl/react/typings/cssmodule.d.ts", 10 | "../../../node_modules/@nrwl/react/typings/image.d.ts" 11 | ], 12 | "exclude": [ 13 | "../**/*.spec.ts", 14 | "../**/*.spec.js", 15 | "../**/*.spec.tsx", 16 | "../**/*.spec.jsx" 17 | ], 18 | "include": [ 19 | "../src/**/*.stories.ts", 20 | "../src/**/*.stories.js", 21 | "../src/**/*.stories.jsx", 22 | "../src/**/*.stories.tsx", 23 | "../src/**/*.stories.mdx", 24 | "*.js", 25 | "preview.tsx" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /system/libs/figa-ui/README.md: -------------------------------------------------------------------------------- 1 | # figa-ui 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test figa-ui` to execute the unit tests via [Vitest](https://vitest.dev/). 8 | -------------------------------------------------------------------------------- /system/libs/figa-ui/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'figa-ui', 4 | preset: '../../jest.preset.js', 5 | transform: { 6 | '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest', 7 | '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nrwl/react/babel'] }], 8 | }, 9 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 10 | coverageDirectory: '../../coverage/libs/figa-ui', 11 | }; 12 | -------------------------------------------------------------------------------- /system/libs/figa-ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@system/figa-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 | } 13 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/font'; 2 | export * from './lib/theme-provider'; 3 | export * from './lib/sandbox'; 4 | export * from './lib/modal'; 5 | export * from './lib/button'; 6 | export * from './lib/select'; 7 | export * from './lib/navigation'; 8 | export * from './lib/logo'; 9 | export * from './lib/link'; 10 | export * from './lib/emoji-picker'; 11 | export * from './lib/progress-circle'; 12 | export * from './lib/input'; 13 | export * from './lib/footer'; 14 | export * from './lib/box'; 15 | export * from './lib/layout'; 16 | export * from './lib/article-layout'; 17 | export * from './lib/left-bar'; 18 | export * from './lib/popover'; 19 | export * from './lib/code-block'; 20 | export * from './lib/logo-graphic'; 21 | export * from './lib/list'; 22 | export * from './lib/blockquote'; 23 | export * from './lib/code'; 24 | export * from './lib/icon'; 25 | export * from './lib/shared'; 26 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/article-layout/__snapshots__/article-layout.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Article layout can be used when [FRAGILE] assigns classes 1`] = ` 4 | 5 |
8 | 9 | `; 10 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/article-layout/article-layout.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import { ArticleLayout } from './article-layout'; 3 | 4 | describe('Article layout can be used when', () => { 5 | it('[FRAGILE] assigns classes', () => { 6 | const { container, asFragment } = render( 7 | 8 | <> 9 | 10 | ); 11 | 12 | const articleLayout = container.querySelector('.article-layout'); 13 | 14 | expect(articleLayout?.className).toContain('article-layout my-class'); 15 | expect(asFragment()).toMatchSnapshot(); 16 | }); 17 | 18 | it('renders content', () => { 19 | render( 20 | 21 |
Content
22 |
23 | ); 24 | 25 | screen.getByText(/Content/); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/article-layout/defs.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | interface ArticleLayoutProps { 4 | className?: string; 5 | children: ReactNode; 6 | } 7 | 8 | export type { ArticleLayoutProps }; 9 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/article-layout/index.ts: -------------------------------------------------------------------------------- 1 | export * from './article-layout'; 2 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/blockquote/__snapshots__/blockquote.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Blockquote can be used when [FRAGILE] assigns classes 1`] = ` 4 | 5 |
8 |

11 | My text 12 |

13 |
14 |
15 | `; 16 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/blockquote/blockquote.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Story, Meta } from '@storybook/react'; 2 | 3 | import { Blockquote } from './blockquote'; 4 | import { Box } from '../box'; 5 | import { FONT_VARIANTS } from '../font'; 6 | 7 | export default { 8 | component: Blockquote, 9 | title: 'Blockquote', 10 | } as Meta; 11 | 12 | const Template: Story = () => { 13 | return ( 14 | 150)}> 15 | {FONT_VARIANTS.map((variant) => ( 16 |
17 | ))} 18 | 19 | ); 20 | }; 21 | 22 | export const Default = Template.bind({}); 23 | Default.args = {}; 24 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/blockquote/blockquote.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react'; 2 | import { Blockquote } from './blockquote'; 3 | 4 | describe('Blockquote can be used when', () => { 5 | it('[FRAGILE] assigns classes', () => { 6 | const { asFragment } = render( 7 |
8 | My text 9 |
10 | ); 11 | 12 | expect(asFragment()).toMatchSnapshot(); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/blockquote/blockquote.tsx: -------------------------------------------------------------------------------- 1 | import { Font } from '../font'; 2 | import type { BlockquoteProps } from './defs'; 3 | 4 | import c from 'classnames'; 5 | 6 | const Blockquote = ({ children, className, variant }: BlockquoteProps) => { 7 | return ( 8 |
9 | {children} 10 |
11 | ); 12 | }; 13 | 14 | export { Blockquote }; 15 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/blockquote/defs.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | import type { FontVariant } from '../font'; 3 | 4 | interface BlockquoteProps { 5 | className?: string; 6 | variant: FontVariant; 7 | children: ReactNode; 8 | } 9 | 10 | export type { BlockquoteProps }; 11 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/blockquote/index.ts: -------------------------------------------------------------------------------- 1 | export * from './blockquote'; 2 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/box/index.ts: -------------------------------------------------------------------------------- 1 | export * from './defs'; 2 | export * from './box'; 3 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/button/__snapshots__/button.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Button can be used when [FRAGILE] renders with default props 1`] = ` 4 | 5 | 16 | 17 | 18 | 19 |
20 | ); 21 | }; 22 | 23 | export const Default = Template.bind({}); 24 | Default.args = {}; 25 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/left-bar/left-bar.tsx: -------------------------------------------------------------------------------- 1 | import { useScrollY } from '@system/figa-hooks'; 2 | 3 | import c from 'classnames'; 4 | import type { LeftBarProps } from './defs'; 5 | 6 | const LeftBar = ({ children }: LeftBarProps) => { 7 | const { state } = useScrollY(); 8 | 9 | return ( 10 |
18 | {children} 19 |
20 | ); 21 | }; 22 | 23 | export { LeftBar }; 24 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/link/__snapshots__/link.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Link can be used when [FRAGILE] renders with default props 1`] = ` 4 | 5 | 8 | 11 | Link 12 | 13 | 14 | 15 | `; 16 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/link/defs.ts: -------------------------------------------------------------------------------- 1 | import type { FontProps } from '../font'; 2 | 3 | type LinkProps = Omit; 4 | 5 | export type { LinkProps }; 6 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './link'; 2 | export * from './defs'; 3 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/link/link.tsx: -------------------------------------------------------------------------------- 1 | import type { LinkProps } from './defs'; 2 | 3 | import c from 'classnames'; 4 | import { Font } from '../font'; 5 | 6 | const Link = (props: LinkProps) => { 7 | return ( 8 | 9 | ); 10 | }; 11 | 12 | export { Link }; 13 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/list/defs.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | interface ListProps { 4 | className?: string; 5 | children: ReactNode; 6 | ordered?: boolean; 7 | } 8 | 9 | interface ListItemProps { 10 | className?: string; 11 | children: ReactNode; 12 | } 13 | 14 | export type { ListProps, ListItemProps }; 15 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './list'; 2 | export * from './defs'; 3 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/list/list.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Story, Meta } from '@storybook/react'; 2 | 3 | import { List, ListItem } from './list'; 4 | import { Box } from '../box'; 5 | 6 | export default { 7 | component: List, 8 | title: 'List', 9 | } as Meta; 10 | 11 | const Template: Story = () => { 12 | return ( 13 | 14 | 15 | First item 16 | Second item 17 | Third item 18 | 19 | 20 | 21 | First item 22 | Second item 23 | Third item 24 | 25 | 26 | ); 27 | }; 28 | 29 | export const Default = Template.bind({}); 30 | Default.args = {}; 31 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/list/list.tsx: -------------------------------------------------------------------------------- 1 | import type { ListItemProps, ListProps } from './defs'; 2 | import c from 'classnames'; 3 | 4 | const ListItem = ({ className, children }: ListItemProps) => { 5 | return
  • {children}
  • ; 6 | }; 7 | 8 | const List = ({ className, children, ordered }: ListProps) => { 9 | const classes = c('list', className); 10 | 11 | if (ordered) { 12 | return
      {children}
    ; 13 | } 14 | 15 | return
      {children}
    ; 16 | }; 17 | 18 | export { List, ListItem }; 19 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/logo-graphic/defs.ts: -------------------------------------------------------------------------------- 1 | interface LogoGraphicProps { 2 | className?: string; 3 | size: number; 4 | } 5 | 6 | export type { LogoGraphicProps }; 7 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/logo-graphic/index.ts: -------------------------------------------------------------------------------- 1 | export * from './defs'; 2 | export * from './logo-graphic'; 3 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/logo-graphic/logo-graphic.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Story, Meta } from '@storybook/react'; 2 | 3 | import { LogoGraphic } from './logo-graphic'; 4 | import { Box } from '../box'; 5 | 6 | export default { 7 | component: LogoGraphic, 8 | title: 'LogoGraphic', 9 | } as Meta; 10 | 11 | const Template: Story = () => { 12 | return ( 13 | 14 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | 22 | export const Default = Template.bind({}); 23 | Default.args = {}; 24 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/logo-graphic/logo-graphic.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react'; 2 | 3 | import { LogoGraphic } from './logo-graphic'; 4 | 5 | describe('Logo graphic can be used when', () => { 6 | it('[FRAGILE] renders logo with size', () => { 7 | const { asFragment } = render( 8 | 9 | ); 10 | 11 | expect(asFragment()).toMatchSnapshot(); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/logo/defs.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | interface LogoProps { 4 | className?: string; 5 | graphic?: ReactNode; 6 | parts?: [string, string, string]; 7 | } 8 | 9 | export type { LogoProps }; 10 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/logo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './defs'; 2 | export * from './logo'; 3 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/logo/logo.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Story, Meta } from '@storybook/react'; 2 | 3 | import { Logo } from './logo'; 4 | 5 | export default { 6 | component: Logo, 7 | title: 'Logo', 8 | } as Meta; 9 | 10 | const Template: Story = () => { 11 | return ( 12 |
    13 | 14 | 15 |
    16 | ); 17 | }; 18 | 19 | export const Default = Template.bind({}); 20 | Default.args = {}; 21 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/logo/logo.tsx: -------------------------------------------------------------------------------- 1 | import { LogoGraphic } from '../logo-graphic'; 2 | import type { LogoProps } from './defs'; 3 | 4 | import c from 'classnames'; 5 | 6 | const Logo = ({ 7 | className, 8 | graphic = , 9 | parts = ['Green', 'On', 'Software'], 10 | }: LogoProps) => { 11 | return ( 12 |
    13 | {graphic} 14 |
    15 |
    16 | {parts[0]} 17 | {parts[1]} 18 |
    19 | {parts[2]} 20 |
    21 |
    22 | ); 23 | }; 24 | 25 | export { Logo }; 26 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/modal/defs.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | interface ModalProps { 4 | children: ReactNode; 5 | onClose?: () => void; 6 | } 7 | 8 | export type { ModalProps }; 9 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/modal/index.ts: -------------------------------------------------------------------------------- 1 | export * from './modal'; 2 | export * from './defs'; 3 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/modal/modal.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Story, Meta } from '@storybook/react'; 2 | import type { ModalProps } from './defs'; 3 | 4 | import { Modal } from './modal'; 5 | import { useState } from 'react'; 6 | 7 | export default { 8 | component: Modal, 9 | title: 'Modal', 10 | } as Meta; 11 | 12 | const Template: Story = (args) => { 13 | const [open, setOpen] = useState(false); 14 | 15 | return ( 16 | <> 17 | 18 | {open && setOpen(false)} />} 19 | 20 | ); 21 | }; 22 | 23 | export const Default = Template.bind({}); 24 | Default.args = { 25 | children: ( 26 |
    Content inside modal
    27 | ), 28 | }; 29 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/modal/modal.tsx: -------------------------------------------------------------------------------- 1 | import type { ModalProps } from './defs'; 2 | 3 | import { usePortal } from '@system/figa-hooks'; 4 | 5 | const Modal = ({ children, onClose }: ModalProps) => { 6 | const { render } = usePortal(); 7 | 8 | return render( 9 | <> 10 |
    11 |
    {children}
    12 | 13 | ); 14 | }; 15 | 16 | export { Modal }; 17 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/navigation/__snapshots__/navigation.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Navigation can be used when [FRAGILE] has the corresponding classes and DOM nodes generated 1`] = ` 4 | 5 | 41 | 42 | `; 43 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/navigation/defs.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | interface NavigationProps { 4 | className?: string; 5 | logo: ReactNode; 6 | action: ReactNode; 7 | links: ReactNode[]; 8 | } 9 | 10 | export type { NavigationProps }; 11 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/navigation/index.ts: -------------------------------------------------------------------------------- 1 | export * from './navigation'; 2 | export * from './defs'; 3 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/navigation/navigation.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | 3 | import { Navigation } from './navigation'; 4 | 5 | describe('Navigation can be used when', () => { 6 | const LINKS = [
    Link 1
    ,
    Link 2
    ]; 7 | const ACTION =
    Action
    ; 8 | const LOGO =
    Logo
    ; 9 | 10 | it('allows to render logo, links and action components as nodes', () => { 11 | render(); 12 | 13 | screen.getByText(/Link 1/); 14 | screen.getByText(/Link 2/); 15 | screen.getByText(/Logo/); 16 | screen.getByText(/Logo/); 17 | }); 18 | 19 | it('[FRAGILE] has the corresponding classes and DOM nodes generated', () => { 20 | const { asFragment } = render( 21 | 22 | ); 23 | 24 | expect(asFragment()).toMatchSnapshot(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/navigation/navigation.tsx: -------------------------------------------------------------------------------- 1 | import type { NavigationProps } from './defs'; 2 | 3 | import c from 'classnames'; 4 | 5 | const Navigation = ({ className, logo, links, action }: NavigationProps) => { 6 | return ( 7 | 18 | ); 19 | }; 20 | 21 | export { Navigation }; 22 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/popover/__snapshots__/popover.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Popover can be used when [FRAGILE] assigns classes 1`] = ` 4 | 5 |
    8 | 11 |
    12 |
    13 | `; 14 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/popover/defs.ts: -------------------------------------------------------------------------------- 1 | import type { UseToggleReturn } from '@system/figa-hooks'; 2 | import type { ReactNode } from 'react'; 3 | 4 | interface PopoverProps { 5 | className?: string; 6 | initialOpen?: boolean; 7 | children: (toggler: UseToggleReturn) => ReactNode; 8 | trigger: (toggler: UseToggleReturn) => ReactNode; 9 | } 10 | 11 | export type { PopoverProps }; 12 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/popover/index.ts: -------------------------------------------------------------------------------- 1 | export * from './defs'; 2 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/popover/popover.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Story, Meta } from '@storybook/react'; 2 | 3 | import { Popover } from './popover'; 4 | import { Button } from '../button'; 5 | import { Box } from '../box'; 6 | import { Font } from '../font'; 7 | 8 | export default { 9 | component: Popover, 10 | title: 'Popover', 11 | } as Meta; 12 | 13 | const Template: Story = () => { 14 | return ( 15 | ( 18 | 19 | )} 20 | > 21 | {({ close }) => ( 22 | 23 | Example header 24 | 25 | 26 | )} 27 | 28 | ); 29 | }; 30 | 31 | export const Default = Template.bind({}); 32 | Default.args = {}; 33 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/popover/popover.tsx: -------------------------------------------------------------------------------- 1 | import { useClickOutside, useToggle } from '@system/figa-hooks'; 2 | import type { PopoverProps } from './defs'; 3 | import c from 'classnames'; 4 | import { Box } from '../box'; 5 | 6 | const Popover = ({ 7 | className, 8 | children, 9 | trigger, 10 | initialOpen, 11 | }: PopoverProps) => { 12 | const toggler = useToggle(initialOpen); 13 | 14 | const { ref } = useClickOutside({ 15 | onOutside: toggler.close, 16 | }); 17 | 18 | return ( 19 |
    20 | {trigger(toggler)} 21 | 22 | {toggler.isOpen && ( 23 | 24 | {children(toggler)} 25 | 26 | )} 27 |
    28 | ); 29 | }; 30 | 31 | export { Popover }; 32 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/progress-circle/defs.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | type ProgressCircleMS = number; 4 | 5 | type ProgressCircleChildren = (ms: ProgressCircleMS) => ReactNode; 6 | 7 | interface ProgressCircleProps { 8 | className?: string; 9 | ms?: ProgressCircleMS; 10 | interval?: number; 11 | jump?: number; 12 | size?: number; 13 | onEnd?: () => void; 14 | children?: ProgressCircleChildren; 15 | } 16 | 17 | export type { ProgressCircleProps, ProgressCircleMS, ProgressCircleChildren }; 18 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/progress-circle/index.ts: -------------------------------------------------------------------------------- 1 | export * from './progress-circle'; 2 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/progress-circle/progress-circle.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Story, Meta } from '@storybook/react'; 2 | 3 | import { ProgressCircle } from './progress-circle'; 4 | 5 | export default { 6 | component: ProgressCircle, 7 | title: 'ProgressCircle', 8 | } as Meta; 9 | 10 | const Template: Story = () => { 11 | return ( 12 |
    13 | 14 | 15 | 16 | 17 |
    18 | ); 19 | }; 20 | 21 | export const Default = Template.bind({}); 22 | Default.args = {}; 23 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/sandbox/defs.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | interface SandboxProps { 4 | children: ReactNode; 5 | } 6 | 7 | export type { SandboxProps }; 8 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/sandbox/index.ts: -------------------------------------------------------------------------------- 1 | export * from './sandbox'; 2 | export * from './defs'; 3 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/select/defs.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | type SelectOptionKey = string; 4 | 5 | interface SelectOption { 6 | child: ReactNode; 7 | key: K; 8 | } 9 | 10 | interface SelectProps { 11 | className?: string; 12 | placeholder?: ReactNode; 13 | initialOpen?: boolean; 14 | value?: K; 15 | options: SelectOption[]; 16 | onChange: (key: K) => void; 17 | } 18 | 19 | export type { SelectProps, SelectOption, SelectOptionKey }; 20 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/select/index.ts: -------------------------------------------------------------------------------- 1 | export * from './select'; 2 | export * from './defs'; 3 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/shared/defs.ts: -------------------------------------------------------------------------------- 1 | type FontWeight = 300 | 400 | 500 | 700; 2 | type FontFamily = 3 | | 'LexendBold' 4 | | 'LexendMedium' 5 | | 'LexendRegular' 6 | | 'LexendLight'; 7 | type StrechablePosition = 'absolute' | 'fixed'; 8 | 9 | export type { FontWeight, FontFamily, StrechablePosition }; 10 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/shared/index.ts: -------------------------------------------------------------------------------- 1 | export * from './defs'; 2 | export * from './generators'; 3 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/theme-provider/index.ts: -------------------------------------------------------------------------------- 1 | export * from './theme-provider'; 2 | export * from './defs'; 3 | export * from './themes'; 4 | export * from './viewport'; 5 | -------------------------------------------------------------------------------- /system/libs/figa-ui/src/lib/theme-provider/viewport.test.ts: -------------------------------------------------------------------------------- 1 | import { getDownViewport, getUpViewport } from './viewport'; 2 | 3 | describe('Creates viewport when', () => { 4 | it('up media query is created based on given value', () => { 5 | expect(getUpViewport(100)).toBe('(min-width: 100px)'); 6 | }); 7 | 8 | it('down media query is created with one pixel less', () => { 9 | expect(getDownViewport(100)).toBe('(max-width: 99px)'); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /system/libs/figa-ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react-jsx", 4 | "allowJs": false, 5 | "esModuleInterop": false, 6 | "allowSyntheticDefaultImports": true, 7 | "strict": true, 8 | "types": ["vite/client"] 9 | }, 10 | "files": [], 11 | "include": [], 12 | "references": [ 13 | { 14 | "path": "./tsconfig.lib.json" 15 | }, 16 | { 17 | "path": "./tsconfig.spec.json" 18 | }, 19 | { 20 | "path": "./.storybook/tsconfig.json" 21 | } 22 | ], 23 | "extends": "../../tsconfig.base.json" 24 | } 25 | -------------------------------------------------------------------------------- /system/libs/figa-ui/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": ["node"] 6 | }, 7 | "files": [ 8 | "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", 9 | "../../node_modules/@nrwl/react/typings/image.d.ts" 10 | ], 11 | "exclude": [ 12 | "**/*.spec.ts", 13 | "**/*.test.ts", 14 | "**/*.spec.tsx", 15 | "**/*.test.tsx", 16 | "**/*.spec.js", 17 | "**/*.test.js", 18 | "**/*.spec.jsx", 19 | "**/*.test.jsx", 20 | "**/*.stories.ts", 21 | "**/*.stories.js", 22 | "**/*.stories.jsx", 23 | "**/*.stories.tsx" 24 | ], 25 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] 26 | } 27 | -------------------------------------------------------------------------------- /system/libs/figa-ui/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/**/*.test.tsx", 13 | "src/**/*.spec.tsx", 14 | "src/**/*.test.js", 15 | "src/**/*.spec.js", 16 | "src/**/*.test.jsx", 17 | "src/**/*.spec.jsx", 18 | "src/**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /system/libs/utils/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /system/libs/utils/README.md: -------------------------------------------------------------------------------- 1 | # utils 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Building 6 | 7 | Run `nx build utils` to build the library. 8 | 9 | ## Running unit tests 10 | 11 | Run `nx test utils` to execute the unit tests via [Jest](https://jestjs.io). 12 | -------------------------------------------------------------------------------- /system/libs/utils/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'utils', 4 | preset: '../../jest.preset.js', 5 | globals: { 6 | 'ts-jest': { 7 | tsconfig: '/tsconfig.spec.json', 8 | }, 9 | }, 10 | transform: { 11 | '^.+\\.[tj]s$': 'ts-jest', 12 | }, 13 | moduleFileExtensions: ['ts', 'js', 'html'], 14 | coverageDirectory: '../../coverage/libs/utils', 15 | }; 16 | -------------------------------------------------------------------------------- /system/libs/utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@system/utils", 3 | "version": "0.0.1", 4 | "type": "commonjs" 5 | } 6 | -------------------------------------------------------------------------------- /system/libs/utils/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/is-client'; 2 | export * from './lib/is-server'; 3 | export * from './lib/storage'; 4 | -------------------------------------------------------------------------------- /system/libs/utils/src/lib/is-client.ts: -------------------------------------------------------------------------------- 1 | import { isServer } from './is-server'; 2 | 3 | const isClient = (): boolean => !isServer(); 4 | 5 | export { isClient }; 6 | -------------------------------------------------------------------------------- /system/libs/utils/src/lib/is-server.ts: -------------------------------------------------------------------------------- 1 | const isServer = (): boolean => typeof window === 'undefined'; 2 | 3 | export { isServer }; 4 | -------------------------------------------------------------------------------- /system/libs/utils/src/lib/tests/is-client.test.ts: -------------------------------------------------------------------------------- 1 | import { isClient } from '../is-client'; 2 | 3 | describe('Client side is detected when: ', () => { 4 | it('window object is not equal to undefined', () => { 5 | expect(isClient()).toBe(true); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /system/libs/utils/src/lib/tests/is-server.test.ts: -------------------------------------------------------------------------------- 1 | import { isServer } from '../is-server'; 2 | 3 | describe('Server side is detected when: ', () => { 4 | const initialWindow = global.window; 5 | 6 | it('window object is undefined', () => { 7 | // It's required. We need to cast to any to be able 8 | // to modify the window. 9 | delete (global as never)['window']; 10 | 11 | expect(isServer()).toBe(true); 12 | 13 | global.window = initialWindow; 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /system/libs/utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "forceConsistentCasingInFileNames": true, 6 | "strict": true, 7 | "noImplicitOverride": true, 8 | "noPropertyAccessFromIndexSignature": true, 9 | "noImplicitReturns": true, 10 | "noFallthroughCasesInSwitch": 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 | -------------------------------------------------------------------------------- /system/libs/utils/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 | -------------------------------------------------------------------------------- /system/libs/utils/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 | -------------------------------------------------------------------------------- /system/tools/generators/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polubis/Dream-stack-for-React-dev/ecd07fa7b038fbd76351bb2d24c1f191995ab614/system/tools/generators/.gitkeep -------------------------------------------------------------------------------- /system/tools/tsconfig.tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "../dist/out-tsc/tools", 5 | "rootDir": ".", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": ["node"], 9 | "importHelpers": false 10 | }, 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /system/tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "importHelpers": true, 11 | "target": "es2015", 12 | "module": "esnext", 13 | "lib": ["es2017", "dom"], 14 | "skipLibCheck": true, 15 | "skipDefaultLibCheck": true, 16 | "baseUrl": ".", 17 | "paths": { 18 | "@system/blog-api": ["libs/blog-api/src/index.ts"], 19 | "@system/figa-hooks": ["libs/figa-hooks/src/index.ts"], 20 | "@system/figa-ui": ["libs/figa-ui/src/index.ts"], 21 | "@system/utils": ["libs/utils/src/index.ts"] 22 | } 23 | }, 24 | "exclude": ["node_modules", "tmp"] 25 | } 26 | --------------------------------------------------------------------------------