├── .editorconfig ├── .gitignore ├── .idea └── .gitignore ├── .nvmrc ├── .vscode ├── extensions.json ├── launch.json └── tasks.json ├── LICENSE ├── README.md ├── angular.json ├── docs ├── devhunt_badge.png ├── dmp_1.png ├── dmp_s_1.png ├── dmp_s_2.png ├── dmp_s_3.png ├── dmp_s_4.png └── icon.png ├── package-lock.json ├── package.json ├── src ├── app │ ├── app-routing.module.ts │ ├── app.component.css │ ├── app.component.html │ ├── app.component.spec.ts │ ├── app.component.ts │ ├── app.module.ts │ ├── components │ │ ├── background │ │ │ ├── background.component.css │ │ │ ├── background.component.html │ │ │ ├── background.component.spec.ts │ │ │ └── background.component.ts │ │ ├── footer │ │ │ ├── footer.component.css │ │ │ ├── footer.component.html │ │ │ ├── footer.component.spec.ts │ │ │ └── footer.component.ts │ │ ├── form-checkbox │ │ │ ├── form-checkbox.component.css │ │ │ ├── form-checkbox.component.html │ │ │ ├── form-checkbox.component.spec.ts │ │ │ └── form-checkbox.component.ts │ │ ├── form-field │ │ │ ├── form-field.component.css │ │ │ ├── form-field.component.html │ │ │ ├── form-field.component.spec.ts │ │ │ └── form-field.component.ts │ │ ├── form-radio │ │ │ ├── form-radio.component.css │ │ │ ├── form-radio.component.html │ │ │ ├── form-radio.component.spec.ts │ │ │ └── form-radio.component.ts │ │ ├── form │ │ │ ├── form.component.css │ │ │ ├── form.component.html │ │ │ ├── form.component.spec.ts │ │ │ └── form.component.ts │ │ ├── header │ │ │ ├── header.component.css │ │ │ ├── header.component.html │ │ │ ├── header.component.spec.ts │ │ │ └── header.component.ts │ │ ├── markdown │ │ │ ├── md-code-snippet │ │ │ │ ├── md-code-snippet.component.css │ │ │ │ ├── md-code-snippet.component.html │ │ │ │ ├── md-code-snippet.component.spec.ts │ │ │ │ └── md-code-snippet.component.ts │ │ │ └── md-preview │ │ │ │ ├── md-preview.component.css │ │ │ │ ├── md-preview.component.html │ │ │ │ ├── md-preview.component.spec.ts │ │ │ │ └── md-preview.component.ts │ │ ├── multi-field │ │ │ ├── multi-field.component.css │ │ │ ├── multi-field.component.html │ │ │ ├── multi-field.component.spec.ts │ │ │ └── multi-field.component.ts │ │ ├── multi-picker │ │ │ ├── multi-picker.component.css │ │ │ ├── multi-picker.component.html │ │ │ ├── multi-picker.component.spec.ts │ │ │ └── multi-picker.component.ts │ │ ├── raw-code-snippet │ │ │ ├── raw-code-snippet.component.css │ │ │ ├── raw-code-snippet.component.html │ │ │ ├── raw-code-snippet.component.spec.ts │ │ │ └── raw-code-snippet.component.ts │ │ ├── repo │ │ │ ├── repo.component.css │ │ │ ├── repo.component.html │ │ │ ├── repo.component.spec.ts │ │ │ └── repo.component.ts │ │ ├── section-title │ │ │ ├── section-title.component.css │ │ │ ├── section-title.component.html │ │ │ ├── section-title.component.spec.ts │ │ │ └── section-title.component.ts │ │ └── svg-icon │ │ │ ├── svg-icon.component.css │ │ │ ├── svg-icon.component.html │ │ │ ├── svg-icon.component.spec.ts │ │ │ └── svg-icon.component.ts │ ├── enums │ │ └── license-type.enum.ts │ ├── interfaces │ │ ├── acknowledge-options.interface.ts │ │ ├── author-data.interface.ts │ │ ├── configuration-options.interface.ts │ │ ├── contribution-options.interface.ts │ │ ├── contributor-options.interface.ts │ │ ├── feature-options.interface.ts │ │ ├── github-options.interface.ts │ │ ├── installation-options.interface.ts │ │ ├── license-options.interface.ts │ │ ├── npm-options.interface.ts │ │ └── technology-options.interface.ts │ ├── pipes │ │ └── log.pipe.ts │ ├── services │ │ ├── markdown.service.ts │ │ ├── toast.service.ts │ │ └── utils.service.ts │ ├── store │ │ ├── actions │ │ │ ├── action-types.ts │ │ │ └── editor.actions.ts │ │ ├── reducers │ │ │ ├── editor.reducer.ts │ │ │ └── index.ts │ │ ├── selectors │ │ │ └── editor.selectors.ts │ │ └── state.interface.ts │ └── toast │ │ ├── toast.component.css │ │ ├── toast.component.html │ │ ├── toast.component.spec.ts │ │ └── toast.component.ts ├── assets │ ├── .gitkeep │ ├── beams.jpg │ ├── fonts │ │ ├── IBM Plex Sans Regular.woff2 │ │ ├── PP Agrandir Bold.woff2 │ │ ├── PP Agrandir Regular.woff2 │ │ ├── TN Light.woff2 │ │ ├── TN Medium.woff2 │ │ ├── TN Regular.woff2 │ │ └── iA Writter Quattro S Regular.woff2 │ ├── github-markdown.css │ ├── grid.svg │ └── images │ │ ├── devhunt_badge.png │ │ ├── dmp_1.png │ │ ├── dmp_2.png │ │ ├── dmp_s_1.png │ │ ├── dmp_s_2.png │ │ ├── dmp_s_3.png │ │ ├── dmp_s_4.png │ │ ├── github_corner.png │ │ └── icon.png ├── data │ ├── mock.ts │ ├── readme-demo.ts │ ├── tech-services.ts │ └── technologies.ts ├── favicon.ico ├── index.html ├── main.ts └── styles.css ├── tailwind.config.js ├── tsconfig.app.json ├── tsconfig.json └── tsconfig.spec.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://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 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.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 | /bazel-out 8 | 9 | # Node 10 | /node_modules 11 | npm-debug.log 12 | yarn-error.log 13 | 14 | # IDEs and editors 15 | .idea/ 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # Visual Studio Code 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | .history/* 30 | 31 | # Miscellaneous 32 | /.angular/cache 33 | .sass-cache/ 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | testem.log 38 | /typings 39 | 40 | # System files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v20.11.1 2 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 3 | "recommendations": ["angular.ng-template"] 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 3 | "version": "0.2.0", 4 | "configurations": [ 5 | { 6 | "name": "ng serve", 7 | "type": "chrome", 8 | "request": "launch", 9 | "preLaunchTask": "npm: start", 10 | "url": "http://localhost:4200/" 11 | }, 12 | { 13 | "name": "ng test", 14 | "type": "chrome", 15 | "request": "launch", 16 | "preLaunchTask": "npm: test", 17 | "url": "http://localhost:9876/debug.html" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 3 | "version": "2.0.0", 4 | "tasks": [ 5 | { 6 | "type": "npm", 7 | "script": "start", 8 | "isBackground": true, 9 | "problemMatcher": { 10 | "owner": "typescript", 11 | "pattern": "$tsc", 12 | "background": { 13 | "activeOnStart": true, 14 | "beginsPattern": { 15 | "regexp": "(.*?)" 16 | }, 17 | "endsPattern": { 18 | "regexp": "bundle generation complete" 19 | } 20 | } 21 | } 22 | }, 23 | { 24 | "type": "npm", 25 | "script": "test", 26 | "isBackground": true, 27 | "problemMatcher": { 28 | "owner": "typescript", 29 | "pattern": "$tsc", 30 | "background": { 31 | "activeOnStart": true, 32 | "beginsPattern": { 33 | "regexp": "(.*?)" 34 | }, 35 | "endsPattern": { 36 | "regexp": "bundle generation complete" 37 | } 38 | } 39 | } 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Luis Ventura 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | Document My Project 5 | 6 | 7 |

8 | 9 | 10 | 11 | 17 | 18 |

Contributors 19 | Forks 20 | Stargazers 21 | Issues


22 | 23 | 24 |
25 | 26 | 27 | Document My Project 28 | 29 | 30 | # Document My Project 31 | 32 | Easily create markdown documentation for your project 33 | 34 |
35 | 36 |

ℹ️ About the Project🏞 Showcase⭐️ Features🛠 Stack Tech⚙ ️Setup🏆 Acknowledgements👏🏻 Contributing👨🏻‍ About the Author📖 License

37 | 38 |

Main Image

39 | 40 | ## ️Table of Contents 41 | 42 |
43 | Open Contents 44 | 45 | - [Document My Project](#document-my-project) 46 | - [ℹ️ About the Project](#-about-the-project) 47 | - [🏞 Showcase](#-showcase) 48 | - [⭐️ Features](#-features) 49 | - [🛠 Stack Tech](#-stack-tech) 50 | - [⚙ ️Setup](#-setup) 51 | - [Installation](#installation) 52 | - [Usage](#usage) 53 | - [🏆 Acknowledgements](#-acknowledgements) 54 | - [👏🏻 Contributing](#-contributing) 55 | - [Ways to Contribute](#ways-to-contribute) 56 | - [Contribution Instructions](#contribution-instructions) 57 | - [Contributors](#contributors) 58 | - [👨🏻‍ About the Author](#-about-the-author) 59 | - [📖 License](#-license) 60 | 61 |
62 | 63 | ## ℹ️ About the Project 64 | 65 | Tired of manually writing README files? this tool simplifies the process of creating documentation for Github projects. 66 | With just a few clicks, you can generate comprehensive documentation that enhances the visibility and usability of your 67 | repositories in seconds. 68 | 69 | ## 🏞 Showcase 70 | 71 |
72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 |
83 | 84 |
85 | 86 | ## ⭐️ Features 87 | 88 | 1. **Template ready** 89 | 90 | Provide a clear and concise description of your project, highlight the main features, goals, and benefits of your 91 | project 92 | 93 | 2. **Ease fo use** 94 | 95 | Easily generate a well-structured README file for your GitHub project 96 | 97 | 3. **Preview** 98 | 99 | Preview the generated README (light/dark theme) file before committing it to your repository 100 | 101 | ## 🛠 Stack Tech 102 | 103 | - [![Angular][Angular-badge]][Angular-url] - A front-end web application framework 104 | 105 | [Angular-badge]: https://img.shields.io/badge/Angular-DD0031?style=for-the-badge&logo=angular 106 | 107 | [Angular-url]: } 108 | 109 | - [![NgRx][NgRx-badge]][NgRx-url] - Angular state management based on Redux 110 | 111 | [NgRx-badge]: https://img.shields.io/badge/NgRx-B7116E?style=for-the-badge&logo=ngrx 112 | 113 | [NgRx-url]: } 114 | 115 | - [![Tailwind CSS][Tailwind CSS-badge]][Tailwind CSS-url] - Utility-first CSS framework 116 | 117 | [Tailwind CSS-badge]: https://img.shields.io/badge/Tailwind%20CSS-38B2AC?style=for-the-badge&logo=tailwindcss 118 | 119 | [Tailwind CSS-url]: } 120 | 121 | - [![TypeScript][TypeScript-badge]][TypeScript-url] - A strict syntactical superset of JavaScript 122 | 123 | [TypeScript-badge]: https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript 124 | 125 | [TypeScript-url]: } 126 | 127 | ## ⚙ ️Setup 128 | 129 | ### Installation 130 | 131 | To install this project, follow these steps: 132 | 133 | 1. Install Node.js v16 or later 134 | 135 | 2. Install the required dependencies: 136 | 137 | 3. `npm install` 138 | 139 | ### Usage 140 | 141 | After installation, you can use the project by following these steps: 142 | 143 | 1. Open the project directory in your code editor 144 | 145 | 2. Run `npm run start` to start the development server 146 | 147 | ## 🏆 Acknowledgements 148 | 149 | - [ngx-markdown](https://www.npmjs.com/package/ngx-markdown) - Angular markdown component/directive/pipe/service to 150 | parse static, dynamic or remote content to HTML with syntax highlight and more 151 | - [Flowbite](https://flowbite.com/) - Build websites even faster with components on top of Tailwind CSS 152 | - [PrismJs](https://prismjs.com/) - Prism is a lightweight, extensible syntax highlighter, built with modern web 153 | standards in mind. It’s used in millions of websites, including some of those you visit daily. 154 | 155 | ## 👏🏻 Contributing 156 | 157 | We welcome contributions from the community! If you would like to contribute to this project, please follow the 158 | guidelines below. 159 | 160 | ### Ways to Contribute 161 | 162 | - Report bugs or issues by opening a new issue on our GitHub repository. 163 | - Suggest new features or improvements by opening a new issue on our GitHub repository. 164 | - Contribute code by forking the repository, making changes, and submitting a pull request. 165 | 166 | ### Contribution Instructions 167 | 168 | 1. Fork the repository. 169 | 2. Create a new branch for your feature or bug fix: `git checkout -b my-feature-branch`. 170 | 3. Make the necessary changes and commit them: `git commit -am 'Add my new feature'`. 171 | 4. Push your branch to your forked repository: `git push origin my-feature-branch`. 172 | 5. Open a pull request against the main repository, describing the changes you made and why they should be merged. 173 | 174 | ### Contributors 175 | 176 | - Luis Ventura (@luisvent) 177 | 178 | ## 👨🏻‍ About the Author 179 | 180 | **Luis Ventura** 181 | 182 | This project was created by Luis Ventura. Connect with me on [GitHub](https://github.com/luisvent) 183 | and [LinkedIn](https://www.linkedin.com/in/luisvent/) to learn more about my projects and professional background. 184 | 185 | ## 📖 License 186 | 187 | This project is licensed under the [MIT License](https://opensource.org/licenses/MIT). 188 | 189 | 190 |

Top ⬆️

191 | 192 | --- 193 |
Built with ❤️ with Document My Project
194 | 195 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "document_my_project": { 7 | "projectType": "application", 8 | "schematics": {}, 9 | "root": "", 10 | "sourceRoot": "src", 11 | "prefix": "app", 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:browser", 15 | "options": { 16 | "outputPath": "dist/document_my_project", 17 | "index": "src/index.html", 18 | "main": "src/main.ts", 19 | "polyfills": [ 20 | "zone.js" 21 | ], 22 | "tsConfig": "tsconfig.app.json", 23 | "assets": [ 24 | "src/favicon.ico", 25 | "src/assets" 26 | ], 27 | "styles": [ 28 | "src/styles.css", 29 | "node_modules/prismjs/themes/prism-okaidia.css", 30 | "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css" 31 | ], 32 | "scripts": [ 33 | "node_modules/marked/marked.min.js", 34 | "node_modules/prismjs/prism.js", 35 | "node_modules/prismjs/components/prism-css.min.js", 36 | "node_modules/prismjs/components/prism-json.min.js", 37 | "node_modules/prismjs/components/prism-shell-session.min.js", 38 | "node_modules/prismjs/components/prism-javascript.min.js", 39 | "node_modules/prismjs/components/prism-typescript.min.js", 40 | "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.js" 41 | ] 42 | }, 43 | "configurations": { 44 | "production": { 45 | "budgets": [ 46 | { 47 | "type": "initial", 48 | "maximumWarning": "500kb", 49 | "maximumError": "1mb" 50 | }, 51 | { 52 | "type": "anyComponentStyle", 53 | "maximumWarning": "2kb", 54 | "maximumError": "4kb" 55 | } 56 | ], 57 | "outputHashing": "all" 58 | }, 59 | "development": { 60 | "buildOptimizer": false, 61 | "optimization": false, 62 | "vendorChunk": true, 63 | "extractLicenses": false, 64 | "sourceMap": true, 65 | "namedChunks": true 66 | } 67 | }, 68 | "defaultConfiguration": "production" 69 | }, 70 | "serve": { 71 | "builder": "@angular-devkit/build-angular:dev-server", 72 | "configurations": { 73 | "production": { 74 | "browserTarget": "document_my_project:build:production" 75 | }, 76 | "development": { 77 | "browserTarget": "document_my_project:build:development" 78 | } 79 | }, 80 | "defaultConfiguration": "development" 81 | }, 82 | "extract-i18n": { 83 | "builder": "@angular-devkit/build-angular:extract-i18n", 84 | "options": { 85 | "browserTarget": "document_my_project:build" 86 | } 87 | }, 88 | "test": { 89 | "builder": "@angular-devkit/build-angular:karma", 90 | "options": { 91 | "polyfills": [ 92 | "zone.js", 93 | "zone.js/testing" 94 | ], 95 | "tsConfig": "tsconfig.spec.json", 96 | "assets": [ 97 | "src/favicon.ico", 98 | "src/assets" 99 | ], 100 | "styles": [ 101 | "src/styles.css" 102 | ], 103 | "scripts": [] 104 | } 105 | } 106 | } 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /docs/devhunt_badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/docs/devhunt_badge.png -------------------------------------------------------------------------------- /docs/dmp_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/docs/dmp_1.png -------------------------------------------------------------------------------- /docs/dmp_s_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/docs/dmp_s_1.png -------------------------------------------------------------------------------- /docs/dmp_s_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/docs/dmp_s_2.png -------------------------------------------------------------------------------- /docs/dmp_s_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/docs/dmp_s_3.png -------------------------------------------------------------------------------- /docs/dmp_s_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/docs/dmp_s_4.png -------------------------------------------------------------------------------- /docs/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/docs/icon.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "document-my-project", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "watch": "ng build --watch --configuration development", 9 | "test": "ng test" 10 | }, 11 | "private": true, 12 | "dependencies": { 13 | "@angular/animations": "^15.2.0", 14 | "@angular/common": "^15.2.0", 15 | "@angular/compiler": "^15.2.0", 16 | "@angular/core": "^15.2.0", 17 | "@angular/forms": "^15.2.0", 18 | "@angular/platform-browser": "^15.2.0", 19 | "@angular/platform-browser-dynamic": "^15.2.0", 20 | "@angular/router": "^15.2.0", 21 | "@ngrx/store": "^15.4.0", 22 | "@ngrx/effects": "^15.4.0", 23 | "@ngrx/store-devtools": "^15.4.0", 24 | "flowbite": "^2.3.0", 25 | "marked": "^4.0.17", 26 | "ngx-markdown": "^15.1.2", 27 | "prismjs": "^1.29.0", 28 | "rxjs": "~7.8.0", 29 | "tslib": "^2.3.0", 30 | "zone.js": "~0.12.0" 31 | }, 32 | "devDependencies": { 33 | "@angular-devkit/build-angular": "^15.2.11", 34 | "@angular/cli": "~15.2.11", 35 | "@angular/compiler-cli": "^15.2.0", 36 | "@tailwindcss/typography": "^0.5.12", 37 | "@types/jasmine": "~4.3.0", 38 | "@types/prismjs": "^1.26.3", 39 | "autoprefixer": "^10.4.19", 40 | "jasmine-core": "~4.5.0", 41 | "karma": "~6.4.0", 42 | "karma-chrome-launcher": "~3.1.0", 43 | "karma-coverage": "~2.2.0", 44 | "karma-jasmine": "~5.1.0", 45 | "karma-jasmine-html-reporter": "~2.0.0", 46 | "postcss": "^8.4.38", 47 | "tailwindcss": "^3.4.3", 48 | "typescript": "~4.9.4" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | 4 | const routes: Routes = []; 5 | 6 | @NgModule({ 7 | imports: [RouterModule.forRoot(routes)], 8 | exports: [RouterModule] 9 | }) 10 | export class AppRoutingModule { } 11 | -------------------------------------------------------------------------------- /src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/app/app.component.css -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |
8 |
9 | 12 |
13 | 20 |
21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async () => { 7 | await TestBed.configureTestingModule({ 8 | imports: [ 9 | RouterTestingModule 10 | ], 11 | declarations: [ 12 | AppComponent 13 | ], 14 | }).compileComponents(); 15 | }); 16 | 17 | it('should create the app', () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.componentInstance; 20 | expect(app).toBeTruthy(); 21 | }); 22 | 23 | it(`should have as title 'document_my_project'`, () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | const app = fixture.componentInstance; 26 | expect(app.title).toEqual('document_my_project'); 27 | }); 28 | 29 | it('should render title', () => { 30 | const fixture = TestBed.createComponent(AppComponent); 31 | fixture.detectChanges(); 32 | const compiled = fixture.nativeElement as HTMLElement; 33 | expect(compiled.querySelector('.content span')?.textContent).toContain('document_my_project app is running!'); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {Store} from "@ngrx/store"; 3 | import {selectGeneratedMarkdown} from "./store/selectors/editor.selectors"; 4 | import {AppState} from "./store/state.interface"; 5 | import {initFlowbite} from "flowbite"; 6 | import {MarkdownService} from "./services/markdown.service"; 7 | import {ToastService} from "./services/toast.service"; 8 | import {Actions} from "./store/actions/action-types"; 9 | import {testData} from "../data/mock"; 10 | 11 | @Component({ 12 | selector: 'app-root', 13 | templateUrl: './app.component.html', 14 | styleUrls: ['./app.component.css'] 15 | }) 16 | export class AppComponent implements OnInit { 17 | 18 | public generatedMarkdown$ = this.store.select(selectGeneratedMarkdown); 19 | 20 | constructor(private store: Store, private mdService: MarkdownService, 21 | public toastService: ToastService) { 22 | } 23 | 24 | ngOnInit(): void { 25 | initFlowbite(); 26 | // this.markdownData = this.mdService.test(); 27 | } 28 | 29 | GenerateMarkdown() { 30 | this.store.dispatch(Actions.generateMarkdown({generate: true})); 31 | window.scroll(0, 0); 32 | } 33 | 34 | 35 | LoadSample() { 36 | this.store.dispatch(Actions.setData({data: testData})); 37 | this.GenerateMarkdown(); 38 | this.toastService.success('Sample data loaded'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {BrowserModule} from '@angular/platform-browser'; 3 | import {AppRoutingModule} from './app-routing.module'; 4 | import {AppComponent} from './app.component'; 5 | import {StoreModule} from '@ngrx/store'; 6 | import {StoreDevtoolsModule} from "@ngrx/store-devtools"; 7 | import {reducers} from "./store/reducers"; 8 | import {MarkdownModule} from "ngx-markdown"; 9 | import {BackgroundComponent} from './components/background/background.component'; 10 | import {FormsModule, ReactiveFormsModule} from "@angular/forms"; 11 | import {ToastComponent} from './toast/toast.component'; 12 | import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; 13 | import {MdPreviewComponent} from "./components/markdown/md-preview/md-preview.component"; 14 | import {MultiPickerComponent} from "./components/multi-picker/multi-picker.component"; 15 | import {RawCodeSnippetComponent} from "./components/raw-code-snippet/raw-code-snippet.component"; 16 | import {MdCodeSnippetComponent} from "./components/markdown/md-code-snippet/md-code-snippet.component"; 17 | import {FormComponent} from './components/form/form.component'; 18 | import {FormCheckboxComponent} from './components/form-checkbox/form-checkbox.component'; 19 | import {FormFieldComponent} from './components/form-field/form-field.component'; 20 | import {SectionTitleComponent} from './components/section-title/section-title.component'; 21 | import {FormRadioComponent} from './components/form-radio/form-radio.component'; 22 | import {MultiFieldComponent} from './components/multi-field/multi-field.component'; 23 | import {LogPipe} from "./pipes/log.pipe"; 24 | import {SvgIconComponent} from './components/svg-icon/svg-icon.component'; 25 | import {HeaderComponent} from './components/header/header.component'; 26 | import {FooterComponent} from './components/footer/footer.component'; 27 | import {RepoComponent} from './components/repo/repo.component'; 28 | 29 | @NgModule({ 30 | declarations: [ 31 | AppComponent, 32 | MdPreviewComponent, 33 | BackgroundComponent, 34 | MultiPickerComponent, 35 | RawCodeSnippetComponent, 36 | MdCodeSnippetComponent, 37 | ToastComponent, 38 | FormComponent, 39 | FormCheckboxComponent, 40 | FormFieldComponent, 41 | SectionTitleComponent, 42 | FormRadioComponent, 43 | MultiFieldComponent, 44 | LogPipe, 45 | SvgIconComponent, 46 | HeaderComponent, 47 | FooterComponent, 48 | RepoComponent 49 | ], 50 | imports: [ 51 | BrowserModule, 52 | AppRoutingModule, 53 | StoreModule.forRoot(reducers), 54 | StoreDevtoolsModule.instrument({ 55 | maxAge: 25, 56 | logOnly: false, 57 | }), 58 | MarkdownModule.forRoot(), 59 | ReactiveFormsModule, 60 | BrowserAnimationsModule, 61 | FormsModule 62 | ], 63 | providers: [], 64 | bootstrap: [AppComponent] 65 | }) 66 | export class AppModule { 67 | } 68 | -------------------------------------------------------------------------------- /src/app/components/background/background.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/app/components/background/background.component.css -------------------------------------------------------------------------------- /src/app/components/background/background.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | -------------------------------------------------------------------------------- /src/app/components/background/background.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { BackgroundComponent } from './background.component'; 4 | 5 | describe('BackgroundComponent', () => { 6 | let component: BackgroundComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ BackgroundComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(BackgroundComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/components/background/background.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-background', 5 | templateUrl: './background.component.html', 6 | styleUrls: ['./background.component.css'], 7 | changeDetection: ChangeDetectionStrategy.OnPush 8 | }) 9 | export class BackgroundComponent { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/app/components/footer/footer.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/app/components/footer/footer.component.css -------------------------------------------------------------------------------- /src/app/components/footer/footer.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Made with ❤︎ by Luis Ventura

3 | 6 |
7 | -------------------------------------------------------------------------------- /src/app/components/footer/footer.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FooterComponent } from './footer.component'; 4 | 5 | describe('FooterComponent', () => { 6 | let component: FooterComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ FooterComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(FooterComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/components/footer/footer.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-footer', 5 | templateUrl: './footer.component.html', 6 | styleUrls: ['./footer.component.css'] 7 | }) 8 | export class FooterComponent { 9 | 10 | OpenProjectRepo() { 11 | window.open('https://github.com/luisvent/document_my_project', '_blank'); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/components/form-checkbox/form-checkbox.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/app/components/form-checkbox/form-checkbox.component.css -------------------------------------------------------------------------------- /src/app/components/form-checkbox/form-checkbox.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 9 | 13 | 14 | 15 | 16 | 28 | 29 | 30 |
31 | -------------------------------------------------------------------------------- /src/app/components/form-checkbox/form-checkbox.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FormCheckboxComponent } from './form-checkbox.component'; 4 | 5 | describe('FormCheckboxComponent', () => { 6 | let component: FormCheckboxComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ FormCheckboxComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(FormCheckboxComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/components/form-checkbox/form-checkbox.component.ts: -------------------------------------------------------------------------------- 1 | import {AfterViewInit, ChangeDetectionStrategy, Component, EventEmitter, Input, Output} from '@angular/core'; 2 | import {UtilsService} from "../../services/utils.service"; 3 | 4 | @Component({ 5 | selector: 'app-form-checkbox', 6 | templateUrl: './form-checkbox.component.html', 7 | styleUrls: ['./form-checkbox.component.css'], 8 | changeDetection: ChangeDetectionStrategy.OnPush 9 | }) 10 | export class FormCheckboxComponent implements AfterViewInit { 11 | 12 | @Input() 13 | disabled = false; 14 | 15 | @Input() 16 | toggle = true; 17 | 18 | @Input() 19 | title = ''; 20 | 21 | @Output() 22 | change = new EventEmitter(); 23 | 24 | @Input() 25 | value: boolean | undefined | null = false; 26 | 27 | id = ''; 28 | 29 | constructor(private utilsService: UtilsService) { 30 | this.id = `checkbox-${this.utilsService.guid()}`; 31 | } 32 | 33 | ngAfterViewInit(): void { 34 | if (this.value) { 35 | const toggleInput = document.querySelector(`#${this.id}`); 36 | toggleInput?.dispatchEvent(new Event('change', {bubbles: true})) 37 | } 38 | } 39 | 40 | checkboxChange(e: Event) { 41 | this.value = (e.target as HTMLInputElement).checked; 42 | e.stopPropagation(); 43 | e.preventDefault(); 44 | this.change.emit(e); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/app/components/form-field/form-field.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/app/components/form-field/form-field.component.css -------------------------------------------------------------------------------- /src/app/components/form-field/form-field.component.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 16 | 17 | -------------------------------------------------------------------------------- /src/app/components/form-field/form-field.component.spec.ts: -------------------------------------------------------------------------------- 1 | import {ComponentFixture, TestBed} from '@angular/core/testing'; 2 | 3 | import {FormFieldComponent} from './form-field.component'; 4 | 5 | describe('FormInputComponent', () => { 6 | let component: FormFieldComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [FormFieldComponent] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(FormFieldComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/components/form-field/form-field.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component, EventEmitter, Input, Output} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-form-field', 5 | templateUrl: './form-field.component.html', 6 | styleUrls: ['./form-field.component.css'], 7 | changeDetection: ChangeDetectionStrategy.OnPush 8 | }) 9 | export class FormFieldComponent { 10 | @Input() 11 | disabled = false; 12 | 13 | @Input() 14 | placeholder = ''; 15 | 16 | @Input() 17 | textarea = false; 18 | 19 | @Output() 20 | change = new EventEmitter(); 21 | 22 | @Input() value: string | null | undefined = ''; 23 | @Output() valueChange = new EventEmitter(); 24 | 25 | constructor() { 26 | } 27 | 28 | inputChange(e: Event) { 29 | e.stopPropagation(); 30 | e.preventDefault(); 31 | 32 | this.change.emit(e); 33 | this.valueChange.emit((e.target as HTMLInputElement).value); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/app/components/form-radio/form-radio.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/app/components/form-radio/form-radio.component.css -------------------------------------------------------------------------------- /src/app/components/form-radio/form-radio.component.html: -------------------------------------------------------------------------------- 1 |
    2 |
  • 4 |
    5 | 13 | 17 |
    18 |
  • 19 |
20 | -------------------------------------------------------------------------------- /src/app/components/form-radio/form-radio.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FormRadioComponent } from './form-radio.component'; 4 | 5 | describe('FormRadioComponent', () => { 6 | let component: FormRadioComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ FormRadioComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(FormRadioComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/components/form-radio/form-radio.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component, EventEmitter, Input, Output} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-form-radio', 5 | templateUrl: './form-radio.component.html', 6 | styleUrls: ['./form-radio.component.css'], 7 | changeDetection: ChangeDetectionStrategy.OnPush 8 | }) 9 | export class FormRadioComponent { 10 | 11 | @Input() 12 | options: { name: string; value: string; }[] = []; 13 | 14 | @Output() 15 | change = new EventEmitter(); 16 | 17 | @Input() 18 | value: string | undefined = ''; 19 | 20 | constructor() { 21 | } 22 | 23 | radioChange(e: Event) { 24 | this.value = (e.target as HTMLInputElement).value; 25 | e.stopPropagation(); 26 | e.preventDefault(); 27 | this.change.emit(e); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/app/components/form/form.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/app/components/form/form.component.css -------------------------------------------------------------------------------- /src/app/components/form/form.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | Information about your project 4 | 5 |
6 |
Title
7 | 12 |
13 | 14 |
15 |
Short Description
16 | 22 |
23 | 24 |
25 |
Description
26 | 32 |
33 | 34 | 35 | Documentation navigation 36 | 37 | 42 | 43 | 48 | 49 | 50 | 55 | 56 | 57 | Source code information 58 | 59 |
60 |
Repository
61 | 67 |
68 | 69 | 76 | 77 |
78 |
NPM Package
79 | 85 |
86 | 87 | 94 | 95 | 96 | Project showcase 97 | 98 |
99 |
Logo Url
100 | 105 |
106 | 107 |
108 |
Main Image
109 | 114 |
115 | 116 |
117 |
Screenshots Url
118 | 124 | 125 |
126 | 127 | 128 | 129 | 135 | 136 |
138 | 139 | 145 |
146 | 147 | 148 | Add instructions to run the project... 149 | 150 |
Installation
151 | 157 | 158 |
Usage
159 | 165 | 166 |
Parameters
167 | 172 | 173 | 174 | 179 | 180 | 181 | Who helped build the project 182 | 183 |
184 | 190 | 195 |
196 | 197 |
198 |
Add Contributors
199 | 205 | 206 | 212 |
213 | 214 | 215 | Who is the author 216 | 217 |
218 |
Name
219 | 224 | 225 |
226 | 227 |
228 |
Github
229 | 234 |
235 | 236 |
237 |
LinkedIn
238 | 243 |
244 | 245 | 246 | Add your project license 247 | 248 | 254 | 255 | 262 | 263 | 269 | 270 | 271 | Optional configuration for your readme file 272 | 273 | 279 | 280 | 286 | 287 |
288 | 302 |
303 | -------------------------------------------------------------------------------- /src/app/components/form/form.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FormComponent } from './form.component'; 4 | 5 | describe('FormComponent', () => { 6 | let component: FormComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ FormComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(FormComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/components/form/form.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, EventEmitter, OnInit, Output} from '@angular/core'; 2 | import {technologies} from "../../../data/technologies"; 3 | import {PickerItem} from "../multi-picker/multi-picker.component"; 4 | import {Actions} from "../../store/actions/action-types"; 5 | import {Store} from "@ngrx/store"; 6 | import {AppState} from "../../store/state.interface"; 7 | import {MarkdownService} from "../../services/markdown.service"; 8 | import {debounceTime, distinctUntilChanged, Observable, Subject} from "rxjs"; 9 | import {LicenseType} from "../../enums/license-type.enum"; 10 | import { 11 | editorSelector, 12 | selectAcknowledgment, 13 | selectAuthorGithubUsername, 14 | selectAuthorLinkedinUsername, 15 | selectAuthorName, 16 | selectBackToTop, 17 | selectContentTable, 18 | selectContribution, 19 | selectContributors, 20 | selectDescription, 21 | selectFeatures, 22 | selectGeneratingMarkdown, 23 | selectInstallSteps, 24 | selectLicense, 25 | selectLogo, 26 | selectMainImage, 27 | selectNavigationLinks, 28 | selectNpmBadges, 29 | selectNpmPackage, 30 | selectParameters, 31 | selectRepository, 32 | selectRepositoryBadges, 33 | selectScreenshots, 34 | selectSectionIcons, 35 | selectShortDescription, 36 | selectStackTech, 37 | selectTitle, 38 | selectUsageSteps 39 | } from "../../store/selectors/editor.selectors"; 40 | import {EditorState} from "../../store/reducers/editor.reducer"; 41 | import {LicenseOptions} from "../../interfaces/license-options.interface"; 42 | import {ContributorOptions} from "../../interfaces/contributor-options.interface"; 43 | import {ContributionOptions} from "../../interfaces/contribution-options.interface"; 44 | import {AcknowledgeOptions} from "../../interfaces/acknowledge-options.interface"; 45 | import {FeatureOptions} from "../../interfaces/feature-options.interface"; 46 | 47 | interface InputInteraction { 48 | type: string; 49 | value: any; 50 | } 51 | 52 | @Component({ 53 | selector: 'app-form', 54 | templateUrl: './form.component.html', 55 | styleUrls: ['./form.component.css'] 56 | }) 57 | export class FormComponent implements OnInit { 58 | @Output() 59 | generateMarkdown = new EventEmitter(); 60 | 61 | technologies = technologies; 62 | licenses: { name: string; value: string }[] = []; 63 | public debounceInput$ = new Subject(); 64 | public generating$ = this.store.select(selectGeneratingMarkdown); 65 | public state$ = this.store.select(editorSelector); 66 | 67 | public title$: Observable = this.store.select(selectTitle); 68 | public description$: Observable = this.store.select(selectDescription); 69 | public shortDescription$: Observable = this.store.select(selectShortDescription); 70 | public contentTable$: Observable = this.store.select(selectContentTable); 71 | public navigationLinks$: Observable = this.store.select(selectNavigationLinks); 72 | public features$: Observable = this.store.select(selectFeatures); 73 | public repository$: Observable = this.store.select(selectRepository); 74 | public repositoryBadges$: Observable = this.store.select(selectRepositoryBadges); 75 | public npmUrl$: Observable = this.store.select(selectNpmPackage); 76 | public npmBadges$: Observable = this.store.select(selectNpmBadges); 77 | public backToTop$: Observable = this.store.select(selectBackToTop); 78 | public sectionIcons$: Observable = this.store.select(selectSectionIcons); 79 | public logo$: Observable = this.store.select(selectLogo); 80 | public mainImage$: Observable = this.store.select(selectMainImage); 81 | public screenshots$: Observable = this.store.select(selectScreenshots); 82 | public stack$: Observable = this.store.select(selectStackTech); 83 | public installSteps$: Observable = this.store.select(selectInstallSteps); 84 | public usageSteps$: Observable = this.store.select(selectUsageSteps); 85 | public parameters$: Observable<{ 86 | field: string, 87 | description: string, 88 | default?: string | undefined 89 | }[]> = this.store.select(selectParameters); 90 | public acknowledgements$: Observable = this.store.select(selectAcknowledgment); 91 | public contribution$: Observable = this.store.select(selectContribution); 92 | public contributors$: Observable = this.store.select(selectContributors); 93 | public authorName$: Observable = this.store.select(selectAuthorName); 94 | public githubUsername$: Observable = this.store.select(selectAuthorGithubUsername); 95 | public linkedinUsername$: Observable = this.store.select(selectAuthorLinkedinUsername); 96 | public license$: Observable = this.store.select(selectLicense); 97 | protected readonly LicenseType = LicenseType; 98 | 99 | constructor(private store: Store, private mdService: MarkdownService) { 100 | this.getLicenses(); 101 | } 102 | 103 | ngOnInit(): void { 104 | this.debounceInput$.pipe( 105 | debounceTime(500), 106 | distinctUntilChanged()).subscribe(input => { 107 | this.processInput(input); 108 | }) 109 | 110 | this.state$.subscribe(state => { 111 | console.log(state) 112 | if (state.generateMarkdown) { 113 | console.log(state) 114 | this.BuildMarkdown(state); 115 | } 116 | }) 117 | } 118 | 119 | 120 | BuildMarkdown(state: EditorState) { 121 | const markdown = this.mdService.Build(state); 122 | console.log(markdown) 123 | this.store.dispatch(Actions.markdownGenerated({markdown})); 124 | } 125 | 126 | selectedTechnologies(technologies: PickerItem[]) { 127 | this.processInput({type: 'technologies', value: technologies}) 128 | } 129 | 130 | getLicenses() { 131 | this.licenses = Object.keys(LicenseType).map(key => { 132 | return { 133 | name: LicenseType[key as keyof typeof LicenseType], value: key 134 | } 135 | }) 136 | } 137 | 138 | generate() { 139 | this.generateMarkdown.emit(); 140 | } 141 | 142 | inputChange(type: string, target: EventTarget | null | boolean) { 143 | console.log('input change') 144 | this.debounceInput$.next({ 145 | type, 146 | value: (target as any).type === 'checkbox' ? (target as HTMLInputElement).checked : (target as HTMLInputElement).value 147 | }); 148 | } 149 | 150 | processInput(input: InputInteraction) { 151 | console.log(input) 152 | switch (input.type) { 153 | 154 | case 'title': 155 | this.store.dispatch(Actions.modifyTitle({title: input.value})); 156 | break; 157 | case 'short-description': 158 | this.store.dispatch(Actions.modifyShortDescription({shortDescription: input.value})); 159 | break; 160 | case 'description': 161 | this.store.dispatch(Actions.modifyDescription({description: input.value})); 162 | break; 163 | 164 | case 'content-table': 165 | this.store.dispatch(Actions.modifyContentTable({contentTable: input.value})); 166 | break; 167 | 168 | case 'navigation-links': 169 | this.store.dispatch(Actions.modifyNavigation({navigation: input.value})); 170 | break; 171 | 172 | case 'section-icons': 173 | this.store.dispatch(Actions.toggleSectionIcons({sectionIcons: input.value})); 174 | break; 175 | 176 | case 'back-to-top': 177 | this.store.dispatch(Actions.toggleBackToTop({backToTop: input.value})); 178 | break; 179 | 180 | case 'features': 181 | const features: any[] = []; 182 | 183 | (input.value as any[]).forEach(acknowledge => { 184 | features.push({title: acknowledge[0], description: acknowledge[1]}); 185 | }) 186 | 187 | this.store.dispatch(Actions.modifyFeatures({features: features})); 188 | break; 189 | 190 | case 'installation': 191 | this.store.dispatch(Actions.modifyInstallation({steps: input.value})); 192 | break; 193 | 194 | case 'usage': 195 | this.store.dispatch(Actions.modifyUsage({steps: input.value})); 196 | break; 197 | 198 | case 'repository-url': 199 | this.store.dispatch(Actions.modifyGithubUrl({url: input.value})); 200 | break; 201 | 202 | case 'repository-badges': 203 | this.store.dispatch(Actions.modifyGithubBadge({badge: input.value})); 204 | break; 205 | 206 | case 'npm-url': 207 | this.store.dispatch(Actions.modifyNpmUrl({url: input.value})); 208 | break; 209 | 210 | case 'npm-badges': 211 | this.store.dispatch(Actions.modifyNpmBadge({badge: input.value})); 212 | break; 213 | 214 | case 'logo-url': 215 | this.store.dispatch(Actions.modifyLogoUrl({logoUrl: input.value})); 216 | break; 217 | 218 | case 'main-img-url': 219 | this.store.dispatch(Actions.modifyMainImageUrl({mainImageUrl: input.value.replaceAll(' ', '')})); 220 | break; 221 | 222 | case 'screenshots-url': 223 | this.store.dispatch(Actions.modifyImages({images: input.value.replaceAll(' ', '').split(/[,\n]/)})); 224 | break; 225 | 226 | case 'technologies': 227 | this.store.dispatch(Actions.addTechnologies({technologies: [...input.value]})); 228 | break; 229 | 230 | case 'tech-stack': 231 | if (!input.value) { 232 | this.store.dispatch(Actions.removeTechnology()); 233 | } 234 | break; 235 | 236 | case 'acknowledge': 237 | 238 | const acknowledgements: any[] = []; 239 | 240 | (input.value as any[]).forEach(acknowledge => { 241 | acknowledgements.push({title: acknowledge[0], url: acknowledge[1], description: acknowledge[2]}); 242 | }) 243 | 244 | this.store.dispatch(Actions.modifyAcknowledgement({acknowledgements: acknowledgements})); 245 | break; 246 | 247 | case 'contribution': 248 | this.store.dispatch(Actions.modifyContribution({contribution: input.value})); 249 | break; 250 | 251 | case 'contributors-img': 252 | this.store.dispatch(Actions.toggleContributorsImg({contributorsImg: input.value})); 253 | break; 254 | 255 | case 'contribution-guideline': 256 | this.store.dispatch(Actions.modifyContributionGuideline({contributionGuidelinesLink: input.value})); 257 | break; 258 | 259 | case 'author-name': 260 | this.store.dispatch(Actions.modifyAuthorName({authorName: input.value})); 261 | break; 262 | 263 | case 'author-github': 264 | this.store.dispatch(Actions.modifyAuthorGithub({authorGithub: input.value})); 265 | break; 266 | 267 | case 'license': 268 | if (!input.value) { 269 | this.store.dispatch(Actions.removeLicense()); 270 | } 271 | break; 272 | 273 | case 'licenseType': 274 | this.store.dispatch(Actions.addLicense({license: {type: input.value}})); 275 | break; 276 | 277 | case 'custom-license': 278 | this.store.dispatch(Actions.modifyCustomLicense({customText: input.value})); 279 | break; 280 | 281 | } 282 | } 283 | 284 | } 285 | -------------------------------------------------------------------------------- /src/app/components/header/header.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/app/components/header/header.component.css -------------------------------------------------------------------------------- /src/app/components/header/header.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Document My Project

4 |

Easily create markdown documentation for your project

5 | 17 |
18 | -------------------------------------------------------------------------------- /src/app/components/header/header.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HeaderComponent } from './header.component'; 4 | 5 | describe('HeaderComponent', () => { 6 | let component: HeaderComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ HeaderComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(HeaderComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/components/header/header.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component, EventEmitter, Output} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-header', 5 | templateUrl: './header.component.html', 6 | styleUrls: ['./header.component.css'], 7 | changeDetection: ChangeDetectionStrategy.OnPush 8 | }) 9 | export class HeaderComponent { 10 | 11 | @Output() 12 | loadData = new EventEmitter(); 13 | 14 | LoadData() { 15 | this.loadData.emit(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/app/components/markdown/md-code-snippet/md-code-snippet.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/app/components/markdown/md-code-snippet/md-code-snippet.component.css -------------------------------------------------------------------------------- /src/app/components/markdown/md-code-snippet/md-code-snippet.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 | 6 | 19 | 20 |
21 | 31 | 32 | 41 | 42 | 52 | 53 | 62 | 63 | 73 | 74 | 83 | 84 |
85 |
86 | 99 |
100 |
101 | 102 |
103 | 118 | 119 | 120 | 137 | 138 |
139 |
140 |
141 |
142 |
143 |
144 |
    145 |
  • 146 | 151 |
  • 152 | 153 |
  • 154 | 160 |
  • 161 | 162 |
163 |
164 | 176 | 177 | 186 |
187 |
188 |
189 |
190 | 191 |
192 |
194 | {{ text }} 195 |
196 |
197 |
198 |
199 | -------------------------------------------------------------------------------- /src/app/components/markdown/md-code-snippet/md-code-snippet.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { MdCodeSnippetComponent } from './md-code-snippet.component'; 4 | 5 | describe('MdCodeSnippetComponent', () => { 6 | let component: MdCodeSnippetComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ MdCodeSnippetComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(MdCodeSnippetComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/components/markdown/md-code-snippet/md-code-snippet.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, EventEmitter, Input, Output} from '@angular/core'; 2 | import {UtilsService} from "../../../services/utils.service"; 3 | import {ToastService} from "../../../services/toast.service"; 4 | 5 | @Component({ 6 | selector: 'app-md-code-snippet', 7 | templateUrl: './md-code-snippet.component.html', 8 | styleUrls: ['./md-code-snippet.component.css'] 9 | }) 10 | export class MdCodeSnippetComponent { 11 | @Input() 12 | text: string = '' 13 | 14 | @Output() 15 | updateFileGenerated = new EventEmitter(); 16 | 17 | tabEnabled: 'preview' | 'raw' = 'preview'; 18 | theme: 'dark' | 'light' = 'light'; 19 | 20 | constructor(private utilsService: UtilsService, private toastService: ToastService) { 21 | } 22 | 23 | switchTab(tab: 'preview' | 'raw') { 24 | this.tabEnabled = tab; 25 | } 26 | 27 | copyCode() { 28 | this.utilsService.copyToClipboard(this.text); 29 | this.toastService.success('Copied!'); 30 | } 31 | 32 | switchTheme() { 33 | this.theme = this.theme === 'dark' ? 'light' : 'dark'; 34 | } 35 | 36 | downloadReadme() { 37 | this.utilsService.saveTextAsFile(this.text); 38 | this.toastService.success('File Downloaded!'); 39 | } 40 | 41 | updateFileRequest() { 42 | this.updateFileGenerated.emit(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/app/components/markdown/md-preview/md-preview.component.css: -------------------------------------------------------------------------------- 1 | img { 2 | margin: 0 !important; 3 | } 4 | -------------------------------------------------------------------------------- /src/app/components/markdown/md-preview/md-preview.component.html: -------------------------------------------------------------------------------- 1 |
3 | 4 | 8 | 9 |
10 | -------------------------------------------------------------------------------- /src/app/components/markdown/md-preview/md-preview.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { MdPreviewComponent } from './md-preview.component'; 4 | 5 | describe('MdPreviewComponent', () => { 6 | let component: MdPreviewComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ MdPreviewComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(MdPreviewComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/components/markdown/md-preview/md-preview.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, EventEmitter, Input, Output} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-md-preview', 5 | templateUrl: './md-preview.component.html', 6 | styleUrls: ['./md-preview.component.css'] 7 | }) 8 | export class MdPreviewComponent { 9 | 10 | @Input() text!: string; 11 | @Input() theme: 'dark' | 'light' = 'dark'; 12 | @Output() ready: EventEmitter = new EventEmitter(); 13 | 14 | constructor() { 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/app/components/multi-field/multi-field.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/app/components/multi-field/multi-field.component.css -------------------------------------------------------------------------------- /src/app/components/multi-field/multi-field.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 11 | 12 | 23 |
24 |
25 | 35 |
36 |
37 | -------------------------------------------------------------------------------- /src/app/components/multi-field/multi-field.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { MultiFieldComponent } from './multi-field.component'; 4 | 5 | describe('MultiFieldComponent', () => { 6 | let component: MultiFieldComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ MultiFieldComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(MultiFieldComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/components/multi-field/multi-field.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component, EventEmitter, Input, Output} from '@angular/core'; 2 | import {UtilsService} from "../../services/utils.service"; 3 | 4 | @Component({ 5 | selector: 'app-multi-field', 6 | templateUrl: './multi-field.component.html', 7 | styleUrls: ['./multi-field.component.css'], 8 | changeDetection: ChangeDetectionStrategy.OnPush 9 | }) 10 | export class MultiFieldComponent { 11 | 12 | @Input() 13 | fields: string[] = []; 14 | 15 | @Input() 16 | textarea: boolean = false; 17 | @Output() 18 | valueChange = new EventEmitter; 19 | 20 | entries: { id: string, name: string[] }[] = []; 21 | 22 | constructor(private utilsService: UtilsService) { 23 | } 24 | 25 | @Input() 26 | set value(values: any[] | null) { 27 | if (!values) return; 28 | 29 | this.entries = []; 30 | values.forEach(value => { 31 | console.log(typeof value) 32 | if (typeof value === 'string') { 33 | this.entries.push(this.generateFields([value])); 34 | } else if (typeof value === 'object') { 35 | this.entries.push(this.generateFields(Object.values(value))); 36 | } 37 | }) 38 | } 39 | 40 | addEntry() { 41 | this.entries.push(this.generateFields()); 42 | } 43 | 44 | generateFields(values: string[] = []) { 45 | const fields = []; 46 | 47 | for (let i = 0; i < this.fields.length; i++) { 48 | // const field = this.fields[i]; 49 | fields.push(values[i] ?? ''); 50 | } 51 | return {id: this.utilsService.guid(), name: fields}; 52 | } 53 | 54 | removeEntry(id: string) { 55 | this.entries = this.entries.filter(e => e.id !== id); 56 | this.emitChange(); 57 | } 58 | 59 | emitChange() { 60 | this.valueChange.emit(this.entries.map(e => e.name)) 61 | } 62 | 63 | assignValue(value: string, key: number, index: number) { 64 | this.entries[index].name[key] = value; 65 | this.emitChange() 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/app/components/multi-picker/multi-picker.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/app/components/multi-picker/multi-picker.component.css -------------------------------------------------------------------------------- /src/app/components/multi-picker/multi-picker.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
{{ title }}
4 | 16 |
17 | 18 |
19 | 22 | {{ selected.name }} 23 | 31 | 32 |
33 | 34 |
35 | 36 | 37 | 38 | 81 | -------------------------------------------------------------------------------- /src/app/components/multi-picker/multi-picker.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { MultiPickerComponent } from './multi-picker.component'; 4 | 5 | describe('MultiPickerComponent', () => { 6 | let component: MultiPickerComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ MultiPickerComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(MultiPickerComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/components/multi-picker/multi-picker.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges} from '@angular/core'; 2 | import {UtilsService} from "../../services/utils.service"; 3 | 4 | export interface PickerItem { 5 | name: string; 6 | value: string; 7 | description: string; 8 | } 9 | 10 | @Component({ 11 | selector: 'app-multi-picker', 12 | templateUrl: './multi-picker.component.html', 13 | styleUrls: ['./multi-picker.component.css'] 14 | }) 15 | export class MultiPickerComponent implements OnInit, OnChanges { 16 | 17 | @Input() 18 | items: PickerItem[] = []; 19 | 20 | @Input() 21 | title: string = 'items'; 22 | 23 | @Input() 24 | value: string[] = []; 25 | 26 | @Output() 27 | selectedItemsChange = new EventEmitter(); 28 | 29 | selectedItems: PickerItem[] = []; 30 | 31 | id = this.utilsService.guid(); 32 | 33 | constructor(private utilsService: UtilsService) { 34 | } 35 | 36 | ngOnChanges(changes: SimpleChanges): void { 37 | if (this.value.length === 0) { 38 | this.selectedItems = []; 39 | } 40 | } 41 | 42 | ngOnInit(): void { 43 | if (this.value.length > 0) { 44 | const items = this.items.filter(i => this.value.includes(i.value)); 45 | this.selectedItems = [...new Set(items)]; 46 | } 47 | } 48 | 49 | itemChange(event: Event, item: PickerItem) { 50 | const target = event.target as HTMLInputElement; 51 | if (target.checked) { 52 | this.addItem(item); 53 | } else { 54 | this.removeItem(item) 55 | } 56 | } 57 | 58 | addItem(item: PickerItem) { 59 | if (!this.selectedItems.find(i => i.name === item.name)) { 60 | this.selectedItems.push(item); 61 | this.emitSelectedEvent(); 62 | } 63 | } 64 | 65 | emitSelectedEvent() { 66 | this.selectedItemsChange.emit(this.selectedItems); 67 | } 68 | 69 | removeItem(item: PickerItem) { 70 | this.selectedItems = this.selectedItems.filter(i => i.name !== item.name); 71 | this.emitSelectedEvent(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/app/components/raw-code-snippet/raw-code-snippet.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/app/components/raw-code-snippet/raw-code-snippet.component.css -------------------------------------------------------------------------------- /src/app/components/raw-code-snippet/raw-code-snippet.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 10 |
11 |
12 | 13 |
14 | 25 |
26 |
27 |
28 |
29 | -------------------------------------------------------------------------------- /src/app/components/raw-code-snippet/raw-code-snippet.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RawCodeSnippetComponent } from './raw-code-snippet.component'; 4 | 5 | describe('RawCodeSnippetComponent', () => { 6 | let component: RawCodeSnippetComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ RawCodeSnippetComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(RawCodeSnippetComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/components/raw-code-snippet/raw-code-snippet.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, EventEmitter, Input, Output} from '@angular/core'; 2 | import {UtilsService} from "../../services/utils.service"; 3 | 4 | @Component({ 5 | selector: 'app-raw-code-snippet', 6 | templateUrl: './raw-code-snippet.component.html', 7 | styleUrls: ['./raw-code-snippet.component.css'] 8 | }) 9 | export class RawCodeSnippetComponent { 10 | 11 | @Input() 12 | code: string = '' 13 | 14 | @Output() 15 | codeCopied: EventEmitter = new EventEmitter(); 16 | 17 | constructor(private utilsService: UtilsService) { 18 | 19 | } 20 | 21 | copyCode() { 22 | this.utilsService.copyToClipboard(this.code); 23 | this.codeCopied.emit(this.code); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/app/components/repo/repo.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/app/components/repo/repo.component.css -------------------------------------------------------------------------------- /src/app/components/repo/repo.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /src/app/components/repo/repo.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RepoComponent } from './repo.component'; 4 | 5 | describe('RepoComponent', () => { 6 | let component: RepoComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ RepoComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(RepoComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/components/repo/repo.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-repo', 5 | templateUrl: './repo.component.html', 6 | styleUrls: ['./repo.component.css'] 7 | }) 8 | export class RepoComponent { 9 | 10 | OpenProjectRepo() { 11 | window.open('https://github.com/luisvent/document_my_project', '_blank'); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/components/section-title/section-title.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/app/components/section-title/section-title.component.css -------------------------------------------------------------------------------- /src/app/components/section-title/section-title.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |

4 | 5 | {{ title }} 6 |

7 |
8 | -------------------------------------------------------------------------------- /src/app/components/section-title/section-title.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SectionTitleComponent } from './section-title.component'; 4 | 5 | describe('SectionTitleComponent', () => { 6 | let component: SectionTitleComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ SectionTitleComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(SectionTitleComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/components/section-title/section-title.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; 2 | import {IconType} from "../svg-icon/svg-icon.component"; 3 | 4 | @Component({ 5 | selector: 'app-section-title', 6 | templateUrl: './section-title.component.html', 7 | styleUrls: ['./section-title.component.css'], 8 | changeDetection: ChangeDetectionStrategy.OnPush 9 | }) 10 | export class SectionTitleComponent { 11 | 12 | @Input() 13 | title = '' 14 | 15 | @Input() 16 | iconType?: IconType; 17 | 18 | constructor() { 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/app/components/svg-icon/svg-icon.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/app/components/svg-icon/svg-icon.component.css -------------------------------------------------------------------------------- /src/app/components/svg-icon/svg-icon.component.html: -------------------------------------------------------------------------------- 1 | 2 | 8 | 13 | 19 | 25 | 31 | 37 | 43 | 49 | 55 | 61 | 67 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /src/app/components/svg-icon/svg-icon.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SvgIconComponent } from './svg-icon.component'; 4 | 5 | describe('SvgIconComponent', () => { 6 | let component: SvgIconComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ SvgIconComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(SvgIconComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/components/svg-icon/svg-icon.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-svg-icon', 5 | templateUrl: './svg-icon.component.html', 6 | styleUrls: ['./svg-icon.component.css'], 7 | changeDetection: ChangeDetectionStrategy.OnPush 8 | }) 9 | export class SvgIconComponent { 10 | 11 | @Input() 12 | type: IconType | undefined; 13 | 14 | } 15 | 16 | export type IconType = 17 | 'info' | 18 | 'list' | 19 | 'github' | 20 | 'image' | 21 | 'layers' | 22 | 'rect-list' | 23 | 'star' | 24 | 'user-group' | 25 | 'user-circle' | 26 | 'award' | 27 | 'book' | 28 | 'adjustment' | 29 | 'none' 30 | -------------------------------------------------------------------------------- /src/app/enums/license-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum LicenseType { 2 | MIT = 'MIT', 3 | Apache2 = 'Apache-2.0', 4 | GPL3 = 'GPL-3.0', 5 | BSD3 = 'BSD-3-Clause', 6 | Custom = 'Custom' 7 | } 8 | -------------------------------------------------------------------------------- /src/app/interfaces/acknowledge-options.interface.ts: -------------------------------------------------------------------------------- 1 | export interface AcknowledgeOptions { title: string, url: string, description: string } 2 | -------------------------------------------------------------------------------- /src/app/interfaces/author-data.interface.ts: -------------------------------------------------------------------------------- 1 | export interface AuthorData { 2 | name: string, 3 | email: string, 4 | url: string, 5 | github: string, 6 | likedIn?: string, 7 | } 8 | -------------------------------------------------------------------------------- /src/app/interfaces/configuration-options.interface.ts: -------------------------------------------------------------------------------- 1 | export interface ConfigurationOptions { 2 | description: string, 3 | parameters: { 4 | field: string, description: string, default?: string 5 | }[] 6 | } 7 | -------------------------------------------------------------------------------- /src/app/interfaces/contribution-options.interface.ts: -------------------------------------------------------------------------------- 1 | export interface ContributionOptions { 2 | add: boolean, 3 | contributorsImg: boolean, 4 | contributionGuidelinesLink?: string | undefined 5 | } 6 | -------------------------------------------------------------------------------- /src/app/interfaces/contributor-options.interface.ts: -------------------------------------------------------------------------------- 1 | export interface ContributorOptions { 2 | name: string, 3 | username: string 4 | } 5 | -------------------------------------------------------------------------------- /src/app/interfaces/feature-options.interface.ts: -------------------------------------------------------------------------------- 1 | export interface FeatureOptions { title: string, description: string } 2 | -------------------------------------------------------------------------------- /src/app/interfaces/github-options.interface.ts: -------------------------------------------------------------------------------- 1 | export interface GitHubOptions { 2 | username: string, 3 | repo: string, 4 | badges: boolean 5 | } 6 | -------------------------------------------------------------------------------- /src/app/interfaces/installation-options.interface.ts: -------------------------------------------------------------------------------- 1 | export interface InstallationOptions { 2 | projectName: string; 3 | packageManager: string; 4 | dependencies: string[]; 5 | devDependencies: string[]; 6 | installationSteps: string[]; 7 | includeSetup?: boolean; 8 | setupSteps?: string[]; 9 | includeUsage?: boolean; 10 | usageSteps?: string[]; 11 | } 12 | -------------------------------------------------------------------------------- /src/app/interfaces/license-options.interface.ts: -------------------------------------------------------------------------------- 1 | import {LicenseType} from "../enums/license-type.enum"; 2 | 3 | export interface LicenseOptions { 4 | type?: LicenseType, 5 | customText?: string | undefined 6 | } 7 | -------------------------------------------------------------------------------- /src/app/interfaces/npm-options.interface.ts: -------------------------------------------------------------------------------- 1 | export interface NPMOptions { 2 | package?: string; 3 | url: string; 4 | badges: boolean 5 | } 6 | -------------------------------------------------------------------------------- /src/app/interfaces/technology-options.interface.ts: -------------------------------------------------------------------------------- 1 | export interface TechnologyOptions { 2 | name: string, 3 | description: string, 4 | value: string, 5 | mainColor: string, 6 | } 7 | -------------------------------------------------------------------------------- /src/app/pipes/log.pipe.ts: -------------------------------------------------------------------------------- 1 | import {Pipe, PipeTransform} from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'log' 5 | }) 6 | export class LogPipe implements PipeTransform { 7 | 8 | transform(value: any): unknown { 9 | console.log('log pipe:', value); 10 | return value; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/app/services/markdown.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from "@angular/core"; 2 | import {InstallationOptions} from "../interfaces/installation-options.interface"; 3 | import {AuthorData} from "../interfaces/author-data.interface"; 4 | import {GitHubOptions} from "../interfaces/github-options.interface"; 5 | import {TechnologyOptions} from "../interfaces/technology-options.interface"; 6 | import {FeatureOptions} from "../interfaces/feature-options.interface"; 7 | import {LicenseOptions} from "../interfaces/license-options.interface"; 8 | import {AcknowledgeOptions} from "../interfaces/acknowledge-options.interface"; 9 | import {ContributionOptions} from "../interfaces/contribution-options.interface"; 10 | import {EditorState} from "../store/reducers/editor.reducer"; 11 | import {ContributorOptions} from "../interfaces/contributor-options.interface"; 12 | 13 | @Injectable({ 14 | providedIn: 'root' 15 | }) 16 | export class MarkdownService { 17 | 18 | TABLE_CONTENT_PLACEHOLDER = ''; 19 | LINKS_PLACEHOLDER = ''; 20 | 21 | constructor() { 22 | } 23 | 24 | Build(state: EditorState) { 25 | 26 | const sections = [ 27 | this.generateReadmeInfo(), 28 | state.github.badges && this.generateGitHubBadges({ 29 | username: state.github.username, 30 | repo: state.github.repo, 31 | badges: true 32 | }), 33 | this.generateIntroductionSection(state.title, state.shortDescription, 34 | '', state.logoUrl), 35 | state.npm.badges && this.generateNpmBadges(state.npm.package!, { 36 | npmVersion: { 37 | color: '0470FF', 38 | logoColor: 'white' 39 | }, 40 | npmDownloads: { 41 | color: '67ACF3' 42 | }, 43 | bundleSize: { 44 | color: 'F9DBBC' 45 | } 46 | }), 47 | this.generateLinksPlaceholder(), 48 | state.mainImageUrl && this.generateCenteredImages([{url: state.mainImageUrl, alt: 'Main Image'}]), 49 | this.generateTableContentPlaceholder(), 50 | state.description && this.generateDescription([state.description], state.sectionIcons), 51 | state.images.length > 0 && this.generateShowcaseSection(state.images, state.sectionIcons), 52 | state.features.length > 0 && this.generateFeaturesSection(state.features, state.sectionIcons), 53 | state.technologies.length > 0 && this.generateTechStackSection(state.technologies, state.sectionIcons), 54 | // this.generateInstallSection({ 55 | // projectName: 'My Awesome Project', 56 | // packageManager: 'npm', 57 | // dependencies: ['react', 'react-dom', 'axios'], 58 | // devDependencies: ['eslint', 'prettier'], 59 | // installationSteps: ['Run the development server with `npm run dev`'], 60 | // includeSetup: true, 61 | // setupSteps: ['Install Node.js v12 or later', 'Install a code editor (e.g., Visual Studio Code)'], 62 | // includeUsage: true, 63 | // usageSteps: ['Open the project directory in your code editor', 'Run `npm start` to start the 64 | // development server'], }), 65 | // this.generateParametersTable([ 66 | // {fieldName: 'name', description: 'Name of the user', defaultValue: 'John Doe'}, 67 | // {fieldName: 'age', description: 'Age of the user'}, 68 | // {fieldName: 'isAdmin', description: 'Whether the user is an admin or not', defaultValue: 'false'} 69 | // ]), 70 | ...(state.installSteps.length > 0 || 71 | state.usageSteps.length > 0 || 72 | state.configuration.parameters.length > 0 ? 73 | [this.generateTitle(`${state.sectionIcons ? '⚙ ' : ''}️Setup`), 74 | this.generateInstallationSection(state.installSteps), 75 | this.generateUsageSection(state.usageSteps), 76 | this.generateParametersTable(state.configuration.parameters)] : []), 77 | state.acknowledgments.length > 0 && this.generateAcknowledgementsSection(state.acknowledgments, state.sectionIcons), 78 | state.contribution.add && this.generateContributionSection(state.contribution, state.contributors, state.github, state.sectionIcons), 79 | state.author.name.length > 0 && this.generateAuthorSection(state.author, state.sectionIcons), 80 | state.license.type && this.generateLicenseSection(state.license, state.sectionIcons), 81 | state.backToTop && this.generateBackToTop(state.sectionIcons), 82 | this.generateWatermark() 83 | ]; 84 | 85 | let result = ''; 86 | 87 | for (const section of sections) { 88 | result += section ? `${section}\n\n` : ''; 89 | } 90 | 91 | if (state.contentTable) { 92 | result = this.generateTableOfContentsFromMarkdown(result); 93 | } 94 | 95 | if (state.navigationLinks) { 96 | result = this.generateLinksSection(result); 97 | } 98 | 99 | return result; 100 | } 101 | 102 | generateSetupTitle(state: EditorState) { 103 | return state.installSteps.length > 0 || 104 | state.usageSteps.length > 0 || 105 | state.configuration.parameters.length > 0 ? 106 | '## Setup' : ''; 107 | } 108 | 109 | generateReadmeInfo() { 110 | const info = ` 111 | `; 117 | 118 | return info; 119 | } 120 | 121 | generateTableContentPlaceholder() { 122 | return this.TABLE_CONTENT_PLACEHOLDER; 123 | } 124 | 125 | generateParametersTable(properties: { 126 | field: string; 127 | description: string; 128 | default?: string; 129 | }[]): string { 130 | 131 | if (properties.length === 0) { 132 | return ''; 133 | } 134 | 135 | const tableHeader = '| Field Name | Description | Default Value |\n| --- | --- | --- |'; 136 | let tableBody = ''; 137 | 138 | for (const prop of properties) { 139 | const row = `| \`${prop.field}\` | ${prop.description} | ${prop.default || ''} |`; 140 | tableBody += `${row}\n`; 141 | } 142 | 143 | return `### Parameters\n\n${tableHeader}\n${tableBody}`; 144 | } 145 | 146 | generateNpmBadges( 147 | npmPackageName: string, 148 | options?: { 149 | npmVersion?: { 150 | logoColor?: string; 151 | color?: string; 152 | }; 153 | npmDownloads?: { 154 | color?: string; 155 | }; 156 | bundleSize?: { 157 | color?: string; 158 | }; 159 | } 160 | ): string { 161 | const npmVersionBadge = ` 162 | 163 | `; 164 | 165 | const npmDownloadsBadge = ` 166 | 167 | `; 168 | 169 | const bundleSizeBadge = ` 170 | 171 | `; 172 | 173 | const badges = `

174 | ${npmVersionBadge} 175 | ${npmDownloadsBadge} 176 | ${bundleSizeBadge} 177 |

`; 178 | 179 | return badges; 180 | } 181 | 182 | generateTableOfContentsFromMarkdown(markdownText: string, addTitleIcons = false): string { 183 | const headingRegex = /^(#{1,6})\s*(.*?)$/gm; 184 | const slugify = (text: string) => 185 | text 186 | .toLowerCase() 187 | .replace(/\s+/g, '-') 188 | .replace(/[^a-z0-9-]/g, ''); 189 | 190 | const headings: { text: string; level: number }[] = []; 191 | let match: RegExpExecArray | null; 192 | 193 | while ((match = headingRegex.exec(markdownText))) { 194 | const level = match[1].length; 195 | const text = match[2].trim(); 196 | headings.push({text, level}); 197 | } 198 | 199 | let tableOfContents = this.generateTitle(`${addTitleIcons ? '📝 ' : ''}️Table of Contents`) + '\n
\nOpen Contents\n\n'; 200 | 201 | headings.forEach((heading) => { 202 | const slug = slugify(heading.text); 203 | const indent = ' '.repeat(heading.level - 1); 204 | tableOfContents += `${indent}- [${heading.text}](#${slug})\n`; 205 | }); 206 | 207 | tableOfContents += '
'; 208 | 209 | return markdownText.replace(this.TABLE_CONTENT_PLACEHOLDER, tableOfContents); 210 | } 211 | 212 | generateAuthorSection(author: AuthorData, addTitleIcons = false) { 213 | const aboutAuthorSection = ` 214 | ${this.generateTitle(`${addTitleIcons ? '👨🏻‍ ' : ''}About the Author`)} 215 | 216 | **${author.name}** 217 | 218 | This project was created by ${author.name}. Connect with me on [GitHub](https://github.com/${author.github}) ${author.likedIn ? `and [LinkedIn](https://www.linkedin.com/in/${author.likedIn}/)` : ''} to learn more about my projects and professional background. 219 | `; 220 | 221 | return aboutAuthorSection; 222 | } 223 | 224 | generateGitHubBadges( 225 | github: GitHubOptions, 226 | badgeStyle: 'flat' | 'flat-square' | 'plastic' | 'for-the-badge' = 'for-the-badge' 227 | ): string { 228 | 229 | const badges = `

Contributors 230 | Forks 231 | Stargazers 232 | Issues


`; 233 | 234 | return badges; 235 | } 236 | 237 | generateBadge( 238 | label: string, 239 | url: string, 240 | color: string, 241 | logo?: string, 242 | description?: string, 243 | logoColor?: string, 244 | badgeStyle: 'flat' | 'flat-square' | 'plastic' | 'for-the-badge' = 'for-the-badge' 245 | ): string { 246 | const badgeUrl = `https://img.shields.io/badge/${encodeURIComponent(label)}-${color}?style=${badgeStyle}${ 247 | logo ? `&logo=${logo}` : '' 248 | }${logoColor ? `&logoColor=${logoColor}` : ''}`; 249 | 250 | return `[![${label}][${label}-badge]][${label}-url]${description ? ` - ${description}` : ''} 251 | 252 | [${label}-badge]: ${badgeUrl} 253 | [${label}-url]: ${url}`; 254 | } 255 | 256 | generateHeading(heading: { text: string; level: number; }): string { 257 | let markdownContent = ''; 258 | markdownContent += '#'.repeat(heading.level) + ' ' + heading.text + '\n\n'; 259 | return markdownContent; 260 | } 261 | 262 | generateDescription(descriptions: string[], addTitleIcons = false): string { 263 | let markdownContent = this.generateTitle(`${addTitleIcons ? 'ℹ️ ' : ''}About the Project`) + '\n\n'; 264 | descriptions.forEach(description => { 265 | markdownContent += description + '\n\n'; 266 | }); 267 | return markdownContent; 268 | } 269 | 270 | generateImages(images: { url: string; alt: string; }[]): string { 271 | let markdownContent = ''; 272 | images.forEach(image => { 273 | markdownContent += `![${image.alt}](${image.url})\n\n`; 274 | }); 275 | return markdownContent; 276 | } 277 | 278 | generateCenteredImages(images: { url: string; alt: string; }[]): string { 279 | let markdownContent = '

'; 280 | images.forEach(image => { 281 | markdownContent += `${image.alt}`; 282 | }); 283 | return markdownContent + '

'; 284 | } 285 | 286 | generateCodeBlock(codeBlocks: { language: string; code: string; }[]): string { 287 | let markdownContent = ''; 288 | codeBlocks.forEach(codeBlock => { 289 | markdownContent += '```' + codeBlock.language + '\n' + codeBlock.code + '\n```\n\n'; 290 | }); 291 | return markdownContent; 292 | } 293 | 294 | generateContributionSection(contribution: ContributionOptions, contributors: ContributorOptions[], 295 | github: GitHubOptions, addTitleIcons = false): string { 296 | const {contributionGuidelinesLink} = contribution; 297 | let contributionSection = `${this.generateTitle(`${addTitleIcons ? '👏🏻 ' : ''}Contributing`)}\n\nWe welcome contributions from the community! If you would like to contribute to this project, please follow the guidelines below.\n`; 298 | 299 | // Generic contribution information 300 | contributionSection += `\n### Ways to Contribute\n\n- Report bugs or issues by opening a new issue on our GitHub repository. 301 | - Suggest new features or improvements by opening a new issue on our GitHub repository. 302 | - Contribute code by forking the repository, making changes, and submitting a pull request.\n`; 303 | 304 | // Contribution instructions 305 | contributionSection += `\n### Contribution Instructions\n\n1. Fork the repository. 306 | 2. Create a new branch for your feature or bug fix: \`git checkout -b my-feature-branch\`. 307 | 3. Make the necessary changes and commit them: \`git commit -am 'Add my new feature'\`. 308 | 4. Push your branch to your forked repository: \`git push origin my-feature-branch\`. 309 | 5. Open a pull request against the main repository, describing the changes you made and why they should be merged.\n`; 310 | 311 | if (contributionGuidelinesLink) { 312 | contributionSection += `\nFor more information on how to contribute, please visit [Contribution Guidelines](${contributionGuidelinesLink}).\n`; 313 | } 314 | 315 | if (contributors.length > 0 || contribution.contributorsImg) { 316 | contributionSection += `### Contributors\n\n`; 317 | 318 | if (contribution.contributorsImg) { 319 | 320 | contributionSection += ` 321 | 322 | `; 323 | } else if (contributors.length > 0) { 324 | 325 | contributors.forEach(contributor => { 326 | contributionSection += `- ${contributor.name} (${contributor.username})\n`; 327 | }) 328 | } 329 | } 330 | 331 | return contributionSection; 332 | } 333 | 334 | generateAcknowledgementsSection(acknowledgements: AcknowledgeOptions[], addTitleIcons = false): string { 335 | let acknowledgementsSectionContent = this.generateTitle(`${addTitleIcons ? '🏆 ' : ''}Acknowledgements`) + '\n\n'; 336 | 337 | acknowledgements.forEach((item) => { 338 | const {title, url, description} = item; 339 | acknowledgementsSectionContent += `- [${title}](${url}) - ${description}\n`; 340 | }); 341 | 342 | return acknowledgementsSectionContent; 343 | } 344 | 345 | generateBackToTop(addIcon = true) { 346 | return `

${addIcon ? 'Top ⬆️' : '(Back to top)'}

`; 347 | } 348 | 349 | generateLicenseSection(licenseSection: LicenseOptions, addTitleIcons = false): string { 350 | const {type, customText} = licenseSection; 351 | let licenseSectionContent = this.generateTitle(`${addTitleIcons ? '📖 ' : ''}License`,) + '\n\n'; 352 | 353 | switch (type) { 354 | case 'MIT': 355 | licenseSectionContent += 'This project is licensed under the [MIT License](https://opensource.org/licenses/MIT).\n'; 356 | break; 357 | case 'Apache-2.0': 358 | licenseSectionContent += 'This project is licensed under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).\n'; 359 | break; 360 | case 'GPL-3.0': 361 | licenseSectionContent += 'This project is licensed under the [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html).\n'; 362 | break; 363 | case 'BSD-3-Clause': 364 | licenseSectionContent += 'This project is licensed under the [BSD 3-Clause License](https://opensource.org/licenses/BSD-3-Clause).\n'; 365 | break; 366 | case 'Custom': 367 | if (customText) { 368 | licenseSectionContent += `${customText}\n`; 369 | } else { 370 | licenseSectionContent += 'This project is licensed under a custom license.\n'; 371 | } 372 | break; 373 | default: 374 | licenseSectionContent += 'This project is licensed under an unspecified license.\n'; 375 | } 376 | 377 | return licenseSectionContent; 378 | } 379 | 380 | generateFeaturesSection(features: FeatureOptions[], addTitleIcons = false): string { 381 | let featuresSection = this.generateTitle(`${addTitleIcons ? '⭐️ ' : ''}Features`) + '\n\n'; 382 | 383 | features.forEach((feature, index) => { 384 | const {title, description} = feature; 385 | featuresSection += `${index + 1}. **${title}**\n\n${description}\n\n`; 386 | }); 387 | 388 | return featuresSection; 389 | } 390 | 391 | generateTitle(titleName: string) { 392 | return `## ${titleName}`; 393 | } 394 | 395 | generateIntroductionSection(title: string, description: string, url: string, imgUrl: string) { 396 | return ` 397 |
398 | 399 | ${imgUrl !== '' ? ` 400 | ${title} 401 | ` : ''} 402 | 403 | # ${title} 404 | 405 | ${description} 406 | 407 |
408 | ` 409 | } 410 | 411 | identifyTechnologies(description: string, technologies: TechnologyOptions[]): string[] { 412 | const foundTechnologies: string[] = []; 413 | 414 | technologies.forEach(tech => { 415 | if (new RegExp(`\\b(${tech.name}|${tech.value})\\b`, 'i').test(description)) { 416 | foundTechnologies.push(tech.name); 417 | } 418 | }); 419 | 420 | return foundTechnologies; 421 | } 422 | 423 | generateTechStackSection(technologies: TechnologyOptions[], addTitleIcons = false) { 424 | let stackSection = this.generateTitle(`${addTitleIcons ? '🛠 ' : ''}Stack Tech`) + '\n'; 425 | 426 | technologies.forEach(tech => { 427 | stackSection += `- ${this.generateBadge(tech.name, '', tech.mainColor.replace('#', ''), tech.value, tech.description)}}\n`; 428 | }); 429 | 430 | return stackSection; 431 | } 432 | 433 | /** 434 | * Generates the install section for a Markdown file. 435 | * @param options - An object containing options for generating the install section. 436 | * @returns The Markdown content for the install section. 437 | */ 438 | generateInstallSection(options: InstallationOptions): string { 439 | const { 440 | projectName, 441 | packageManager, 442 | dependencies, 443 | devDependencies, 444 | installationSteps, 445 | includeSetup = false, 446 | setupSteps = [], 447 | includeUsage = false, 448 | usageSteps = [], 449 | } = options; 450 | 451 | let installSection = `${this.generateTitle('Installation')}\n\nTo install ${projectName}, follow these steps:\n\n`; 452 | 453 | // Add setup section if requested 454 | if (includeSetup && setupSteps.length > 0) { 455 | installSection += `### Setup\n\nBefore installation, make sure you have the following prerequisites set up:\n\n`; 456 | setupSteps.forEach((step, index) => { 457 | installSection += `${index + 1}. ${step}\n\n`; 458 | }); 459 | } 460 | 461 | // Add step for installing dependencies 462 | if (dependencies.length > 0) { 463 | installSection += `1. Install the required dependencies:\n\n\`\`\`\n${packageManager} install ${dependencies.join(' ')}\n\`\`\`\n\n`; 464 | } 465 | 466 | // Add step for installing development dependencies 467 | if (devDependencies.length > 0) { 468 | installSection += `2. Install the development dependencies (if needed):\n\n\`\`\`\n${packageManager} install --dev ${devDependencies.join(' ')}\n\`\`\`\n\n`; 469 | } 470 | 471 | // Add additional installation steps 472 | if (installationSteps.length > 0) { 473 | installSection += `${dependencies.length > 0 || devDependencies.length > 0 ? '3. ' : '1. '}Additional steps:\n\n`; 474 | installationSteps.forEach((step, index) => { 475 | installSection += `${index + 1}. ${step}\n\n`; 476 | }); 477 | } 478 | 479 | // Add usage section if requested 480 | if (includeUsage && usageSteps.length > 0) { 481 | installSection += `${this.generateTitle('Usage')}\n\nAfter installation, you can use the project by following these steps:\n\n`; 482 | usageSteps.forEach((step, index) => { 483 | installSection += `${index + 1}. ${step}\n\n`; 484 | }); 485 | } 486 | 487 | return installSection; 488 | } 489 | 490 | generateInstallationSection(steps: string[]): string { 491 | 492 | if (steps.length === 0) { 493 | return ''; 494 | } 495 | 496 | let installSection = `### Installation\n\nTo install this project, follow these steps:\n\n`; 497 | 498 | steps.forEach((step, index) => { 499 | installSection += `${index + 1}. ${step}\n\n`; 500 | }); 501 | 502 | return installSection; 503 | } 504 | 505 | generateUsageSection(steps: string[]): string { 506 | 507 | if (steps.length === 0) { 508 | return ''; 509 | } 510 | 511 | let usageSection = `### Usage\n\nAfter installation, you can use the project by following these steps:\n\n`; 512 | 513 | steps.forEach((step, index) => { 514 | usageSection += `${index + 1}. ${step}\n\n`; 515 | }); 516 | 517 | return usageSection; 518 | } 519 | 520 | /** 521 | * Generates a links section for a Markdown file based on the headings. 522 | * @param markdownContent - The Markdown content of the file. 523 | * @returns The Markdown content for the links section. 524 | */ 525 | generateLinksSection(markdownContent: string): string { 526 | const headings = markdownContent.match(/\n## (.+)\n/g) || []; 527 | const links = headings.map((heading) => { 528 | const label = heading.replace(/\n## (.+)\n/, '$1'); 529 | const id = label.replace(/[^a-zA-Z0-9]+/g, '-').toLowerCase(); 530 | return {label, id}; 531 | }); 532 | 533 | if (links.length === 0) { 534 | return ''; 535 | } 536 | 537 | let linksSection = '

'; 538 | 539 | links.forEach((link, index) => { 540 | const {label, id} = link; 541 | const isLastLink = index === links.length - 1; 542 | 543 | linksSection += `${label}${isLastLink ? '' : ' • '}`; 544 | }); 545 | 546 | linksSection += '

'; 547 | 548 | return markdownContent.replace(this.LINKS_PLACEHOLDER, linksSection); 549 | } 550 | 551 | /** 552 | * Generates a showcase section with image URLs and links formatted as a table. 553 | * @param images - An array of image data objects with author and url properties. 554 | * @returns The formatted showcase section as a string. 555 | */ 556 | generateShowcaseSection(images: string[], addTitleIcons = false): string { 557 | if (images.length === 0) { 558 | return ''; 559 | } 560 | 561 | const columns = 2; 562 | let showcaseSection = `${this.generateTitle(`${addTitleIcons ? '🏞 ' : ''}Showcase`)}\n\n
\n\n\n`; 563 | 564 | const numRows = Math.ceil(images.length / columns); 565 | for (let i = 0; i < numRows; i++) { 566 | showcaseSection += '\n'; 567 | 568 | for (let j = 0; j < columns; j++) { 569 | const index = i * columns + j; 570 | if (index < images.length) { 571 | const url = images[index]; 572 | showcaseSection += `\n`; 573 | } else { 574 | showcaseSection += '\n'; 575 | } 576 | } 577 | 578 | showcaseSection += '\n'; 579 | } 580 | 581 | showcaseSection += '
\n\n
'; 582 | 583 | return showcaseSection; 584 | } 585 | 586 | generateLinksPlaceholder() { 587 | return this.LINKS_PLACEHOLDER; 588 | } 589 | 590 | generateWatermark() { 591 | return '---\n
Built with ❤️ with Document My Project
'; 592 | } 593 | } 594 | -------------------------------------------------------------------------------- /src/app/services/toast.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {BehaviorSubject} from "rxjs"; 3 | import {UtilsService} from "./utils.service"; 4 | 5 | export interface Toast { 6 | id: string; 7 | message: string; 8 | type: 'success' | 'error'; 9 | } 10 | 11 | @Injectable({ 12 | providedIn: 'root' 13 | }) 14 | export class ToastService { 15 | 16 | toasts: BehaviorSubject = new BehaviorSubject([]); 17 | 18 | constructor(private utilsService: UtilsService) { 19 | } 20 | 21 | success(message: string) { 22 | this.showtoast({message, type: 'success', id: this.utilsService.guid()}); 23 | } 24 | 25 | error(message: string) { 26 | this.showtoast({message, type: 'error', id: this.utilsService.guid()}); 27 | } 28 | 29 | close(id: string) { 30 | this.toasts.next([...this.toasts.value.filter(t => t.id !== id)]); 31 | } 32 | 33 | private showtoast(toast: Toast) { 34 | this.toasts.next([...this.toasts.value, toast]); 35 | this.removeToast(toast); // Remove toast after 2 seconds. 36 | } 37 | 38 | private removeToast(toast: Toast) { 39 | setTimeout(() => this.close(toast.id), 2000); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/app/services/utils.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | 3 | import {highlight, languages} from "prismjs"; 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class UtilsService { 9 | constructor() { 10 | } 11 | 12 | formatCode(text: string) { 13 | const html = highlight(text, languages['html'], 'html'); 14 | return html; 15 | } 16 | 17 | copyToClipboard(text: string) { 18 | const selBox = document.createElement('textarea'); 19 | selBox.style.position = 'fixed'; 20 | selBox.style.left = '0'; 21 | selBox.style.top = '0'; 22 | selBox.style.opacity = '0'; 23 | selBox.value = text; 24 | document.body.appendChild(selBox); 25 | selBox.focus(); 26 | selBox.select(); 27 | selBox.setSelectionRange(0, 99999); 28 | navigator.clipboard.writeText(selBox.value); 29 | document.body.removeChild(selBox); 30 | } 31 | 32 | guid() { 33 | return 'id-' + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); 34 | } 35 | 36 | /** 37 | * Saves the provided text as a file. 38 | * @param text - The text content to be saved. 39 | * @param fileName - The desired name for the file. 40 | * @param fileType - The file type or extension (e.g., '.txt', '.md', '.html'). 41 | */ 42 | saveTextAsFile(text: string, fileName: string = 'readme', fileType: string = 'md') { 43 | const blob = new Blob([text], {type: `text/${fileType.replace('.', '')}`}); 44 | const anchor = document.createElement('a'); 45 | anchor.download = `${fileName}.${fileType}`; 46 | anchor.href = window.URL.createObjectURL(blob); 47 | anchor.dataset['downloadedFilename'] = `${fileName}${fileType}`; 48 | document.body.appendChild(anchor); 49 | anchor.click(); 50 | document.body.removeChild(anchor); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/app/store/actions/action-types.ts: -------------------------------------------------------------------------------- 1 | import * as Actions from './editor.actions'; 2 | 3 | export {Actions} 4 | -------------------------------------------------------------------------------- /src/app/store/actions/editor.actions.ts: -------------------------------------------------------------------------------- 1 | import {createAction, props} from '@ngrx/store'; 2 | import {FeatureOptions} from "../../interfaces/feature-options.interface"; 3 | import {TechnologyOptions} from "../../interfaces/technology-options.interface"; 4 | import {AcknowledgeOptions} from "../../interfaces/acknowledge-options.interface"; 5 | import {LicenseOptions} from "../../interfaces/license-options.interface"; 6 | import {ContributorOptions} from "../../interfaces/contributor-options.interface"; 7 | import {EditorState} from "../reducers/editor.reducer"; 8 | 9 | export const modifyTitle = createAction( 10 | '[Form] Modify Title', 11 | props<{ title: string }>() 12 | ); 13 | 14 | export const modifyShortDescription = createAction( 15 | '[Form] Modify Short Description', 16 | props<{ shortDescription: string }>() 17 | ); 18 | 19 | export const modifyNavigation = createAction( 20 | '[Form] Modify Navigation Links', 21 | props<{ navigation: boolean }>() 22 | ); 23 | 24 | 25 | export const modifyContentTable = createAction( 26 | '[Form] Modify Content Table', 27 | props<{ contentTable: boolean }>() 28 | ); 29 | 30 | export const modifyGithubUrl = createAction( 31 | '[Form] Modify Github Url', 32 | props<{ url: string }>() 33 | ); 34 | 35 | export const modifyNpmUrl = createAction( 36 | '[Form] Modify NPM Url', 37 | props<{ url: string }>() 38 | ); 39 | 40 | export const modifyNpmBadge = createAction( 41 | '[Form] Modify NPM Badge', 42 | props<{ badge: boolean }>() 43 | ); 44 | 45 | export const modifyGithubBadge = createAction( 46 | '[Form] Modify Github Badge', 47 | props<{ badge: boolean }>() 48 | ); 49 | 50 | export const modifyLogoUrl = createAction( 51 | '[Form] Modify Logo Url', 52 | props<{ logoUrl: string }>() 53 | ); 54 | 55 | export const modifyMainImageUrl = createAction( 56 | '[Form] Modify Main Image Url', 57 | props<{ mainImageUrl: string }>() 58 | ); 59 | 60 | export const modifyImages = createAction( 61 | '[Form] Modify Images', 62 | props<{ images: string[] }>() 63 | ); 64 | 65 | export const addTechnologies = createAction( 66 | '[Form] Add Technology', 67 | props<{ technologies: TechnologyOptions[] }>() 68 | ); 69 | 70 | export const removeTechnology = createAction( 71 | '[Form] Remove Technology' 72 | ); 73 | 74 | 75 | export const modifyAcknowledgement = createAction( 76 | '[Form] Modify Acknowledgement', 77 | props<{ acknowledgements: AcknowledgeOptions[] }>() 78 | ); 79 | 80 | export const modifyContributors = createAction( 81 | '[Form] Modify Contributors', 82 | props<{ contributors: ContributorOptions[] }>() 83 | ); 84 | 85 | 86 | export const modifyContribution = createAction( 87 | '[Form] Modify Contribution', 88 | props<{ contribution: boolean }>() 89 | ); 90 | 91 | export const toggleContributorsImg = createAction( 92 | '[Form] Toggle Contributors Image', 93 | props<{ contributorsImg: boolean }>() 94 | ); 95 | 96 | export const modifyContributionGuideline = createAction( 97 | '[Form] Modify Contribution Guideline', 98 | props<{ contributionGuidelinesLink: string }>() 99 | ); 100 | 101 | 102 | export const modifyAuthorName = createAction( 103 | '[Form] Modify Author Name', 104 | props<{ authorName: string }>() 105 | ); 106 | 107 | 108 | export const modifyAuthorGithub = createAction( 109 | '[Form] Modify Author Github', 110 | props<{ authorGithub: string }>() 111 | ); 112 | 113 | 114 | export const modifyInstallation = createAction( 115 | '[Form] Modify Installation Steps', 116 | props<{ steps: string[] }>() 117 | ); 118 | 119 | export const modifyUsage = createAction( 120 | '[Form] Modify Usage Steps', 121 | props<{ steps: string[] }>() 122 | ); 123 | 124 | export const addLicense = createAction( 125 | '[Form] Add License', 126 | props<{ license: LicenseOptions }>() 127 | ); 128 | 129 | export const modifyCustomLicense = createAction( 130 | '[Form] Modify Custom License', 131 | props<{ customText: string }>() 132 | ); 133 | 134 | export const removeLicense = createAction( 135 | '[Form] Remove License' 136 | ); 137 | 138 | export const modifyFeatures = createAction( 139 | '[Form] Modify Features', 140 | props<{ features: FeatureOptions[] }>() 141 | ); 142 | 143 | export const modifyDescription = createAction( 144 | '[Form] Modify Description', 145 | props<{ description: string }>() 146 | ); 147 | 148 | export const displayMarkdownResult = createAction( 149 | '[Form] Display Markdown' 150 | ); 151 | 152 | export const hideMarkdownResult = createAction( 153 | '[Form] Hide Markdown' 154 | ); 155 | 156 | export const toggleBackToTop = createAction( 157 | '[Form] Toggle Back to top', 158 | props<{ backToTop: boolean }>() 159 | ); 160 | 161 | export const toggleSectionIcons = createAction( 162 | '[Form] Toggle Section Icons', 163 | props<{ sectionIcons: boolean }>() 164 | ); 165 | 166 | export const generateMarkdown = createAction( 167 | '[Form] Generate Markdown', 168 | props<{ generate: boolean }>() 169 | ); 170 | 171 | export const markdownGenerated = createAction( 172 | '[Form] Markdown Generated', 173 | props<{ markdown: string }>() 174 | ); 175 | 176 | export const setData = createAction( 177 | '[Form] Set Data', 178 | props<{ data: EditorState }>() 179 | ); 180 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /src/app/store/reducers/editor.reducer.ts: -------------------------------------------------------------------------------- 1 | import {createReducer, on} from '@ngrx/store'; 2 | import {Actions} from "../actions/action-types"; 3 | import {InstallationOptions} from "../../interfaces/installation-options.interface"; 4 | import {GitHubOptions} from "../../interfaces/github-options.interface"; 5 | import {NPMOptions} from "../../interfaces/npm-options.interface"; 6 | import {FeatureOptions} from "../../interfaces/feature-options.interface"; 7 | import {TechnologyOptions} from "../../interfaces/technology-options.interface"; 8 | import {AcknowledgeOptions} from "../../interfaces/acknowledge-options.interface"; 9 | import {ContributionOptions} from "../../interfaces/contribution-options.interface"; 10 | import {AuthorData} from "../../interfaces/author-data.interface"; 11 | import {LicenseOptions} from "../../interfaces/license-options.interface"; 12 | import {ContributorOptions} from "../../interfaces/contributor-options.interface"; 13 | import {ConfigurationOptions} from "../../interfaces/configuration-options.interface"; 14 | 15 | export interface EditorState { 16 | title: string, 17 | shortDescription: string; 18 | description: string, 19 | github: GitHubOptions, 20 | sectionIcons: boolean, 21 | backToTop: boolean, 22 | npm: NPMOptions, 23 | logoUrl: string; 24 | navigationLinks: boolean; 25 | contentTable: boolean; 26 | mainImageUrl: string; 27 | images: string[], 28 | features: FeatureOptions[], 29 | technologies: TechnologyOptions[], 30 | installation: InstallationOptions, 31 | installSteps: string[]; 32 | usageSteps: string[]; 33 | configuration: ConfigurationOptions, 34 | acknowledgments: AcknowledgeOptions[], 35 | contribution: ContributionOptions, 36 | contributors: ContributorOptions[], 37 | author: AuthorData, 38 | license: LicenseOptions, 39 | watermark: boolean, 40 | displayMarkdownResult: boolean, 41 | generateMarkdown: boolean, 42 | generatedMarkdown: string 43 | } 44 | 45 | const initialState: EditorState = { 46 | title: '', 47 | shortDescription: '', 48 | description: '', 49 | navigationLinks: false, 50 | sectionIcons: false, 51 | backToTop: true, 52 | contentTable: false, 53 | github: { 54 | username: '', 55 | repo: '', 56 | badges: false 57 | }, 58 | logoUrl: '', 59 | mainImageUrl: '', 60 | displayMarkdownResult: false, 61 | npm: { 62 | package: '', 63 | url: '', 64 | badges: false 65 | }, 66 | images: [], 67 | features: [], 68 | technologies: [], 69 | installation: { 70 | projectName: '', 71 | packageManager: '', 72 | dependencies: [], 73 | devDependencies: [], 74 | installationSteps: [], 75 | includeSetup: false, 76 | setupSteps: [], 77 | includeUsage: false, 78 | usageSteps: [], 79 | }, 80 | installSteps: [], 81 | usageSteps: [], 82 | acknowledgments: [], 83 | contribution: {add: false, contributorsImg: false, contributionGuidelinesLink: undefined}, 84 | contributors: [], 85 | configuration: { 86 | description: '', 87 | parameters: [] 88 | }, 89 | author: { 90 | name: '', 91 | email: '', 92 | url: '', 93 | github: '', 94 | likedIn: '', 95 | }, 96 | license: {type: undefined, customText: undefined}, 97 | watermark: true, 98 | generateMarkdown: false, 99 | generatedMarkdown: '' 100 | }; 101 | 102 | export const editorReducer = createReducer( 103 | initialState, 104 | 105 | on(Actions.modifyTitle, (state, action): EditorState => { 106 | console.log(action) 107 | return newState(state, {title: action.title}) 108 | }), 109 | 110 | on(Actions.modifyDescription, (state, action): EditorState => { 111 | return newState(state, {description: action.description}) 112 | }), 113 | 114 | on(Actions.modifyShortDescription, (state, action): EditorState => { 115 | return newState(state, {shortDescription: action.shortDescription}) 116 | }), 117 | 118 | on(Actions.modifyGithubUrl, (state, action): EditorState => { 119 | const github = newState(state.github, {url: action.url}) 120 | return newState(state, {github: github}) 121 | }), 122 | 123 | on(Actions.modifyNavigation, (state, action): EditorState => { 124 | return newState(state, {navigationLinks: action.navigation}) 125 | }), 126 | 127 | on(Actions.modifyContentTable, (state, action): EditorState => { 128 | return newState(state, {contentTable: action.contentTable}) 129 | }), 130 | 131 | on(Actions.modifyGithubBadge, (state, action): EditorState => { 132 | const github = newState(state.github, {badges: action.badge}) 133 | return newState(state, {github: github}) 134 | }), 135 | 136 | on(Actions.modifyNpmUrl, (state, action): EditorState => { 137 | const npm = newState(state.npm, {url: action.url}) 138 | return newState(state, {npm: npm}) 139 | }), 140 | 141 | on(Actions.modifyNpmBadge, (state, action): EditorState => { 142 | const npm = newState(state.npm, {badges: action.badge}) 143 | return newState(state, {npm: npm}) 144 | }), 145 | 146 | on(Actions.modifyLogoUrl, (state, action): EditorState => { 147 | return newState(state, {logoUrl: action.logoUrl}) 148 | }), 149 | 150 | on(Actions.modifyMainImageUrl, (state, action): EditorState => { 151 | return newState(state, {mainImageUrl: action.mainImageUrl}) 152 | }), 153 | 154 | on(Actions.modifyImages, (state, action): EditorState => { 155 | return newState(state, {images: action.images}) 156 | }), 157 | 158 | on(Actions.addTechnologies, (state, action): EditorState => { 159 | return newState(state, {technologies: action.technologies}) 160 | }), 161 | 162 | on(Actions.removeTechnology, (state, action): EditorState => { 163 | return newState(state, {technologies: []}) 164 | }), 165 | 166 | on(Actions.modifyAcknowledgement, (state, action): EditorState => { 167 | return newState(state, {acknowledgments: action.acknowledgements || []}) 168 | }), 169 | 170 | on(Actions.modifyContributors, (state, action): EditorState => { 171 | return newState(state, {contributors: action.contributors || []}) 172 | }), 173 | 174 | on(Actions.modifyContribution, (state, action): EditorState => { 175 | const contribution = newState(state.contribution, {add: action.contribution}) 176 | return newState(state, {contribution: contribution}) 177 | }), 178 | 179 | on(Actions.modifyContributionGuideline, (state, action): EditorState => { 180 | const contribution = newState(state.contribution, {contributionGuidelinesLink: action.contributionGuidelinesLink}) 181 | return newState(state, {contribution: contribution}) 182 | }), 183 | 184 | on(Actions.modifyAuthorName, (state, action): EditorState => { 185 | const author = newState(state.author, {name: action.authorName}) 186 | return newState(state, {author: author}) 187 | }), 188 | 189 | on(Actions.modifyAuthorGithub, (state, action): EditorState => { 190 | const author = newState(state.author, {github: action.authorGithub}) 191 | return newState(state, {author: author}) 192 | }), 193 | 194 | on(Actions.addLicense, (state, action): EditorState => { 195 | return newState(state, {license: action.license}) 196 | }), 197 | 198 | on(Actions.toggleBackToTop, (state, action): EditorState => { 199 | return newState(state, {backToTop: action.backToTop}) 200 | }), 201 | 202 | on(Actions.toggleContributorsImg, (state, action): EditorState => { 203 | const contribution = newState(state.contribution, {contributorsImg: action.contributorsImg}) 204 | return newState(state, {contribution}) 205 | }), 206 | 207 | on(Actions.toggleSectionIcons, (state, action): EditorState => { 208 | return newState(state, {sectionIcons: action.sectionIcons}) 209 | }), 210 | 211 | on(Actions.removeLicense, (state, action): EditorState => { 212 | const license = {type: undefined, customText: undefined}; 213 | return newState(state, {license: license}) 214 | }), 215 | 216 | on(Actions.modifyCustomLicense, (state, action): EditorState => { 217 | const license = newState(state.license, {customText: action.customText}) 218 | return newState(state, {license: license}) 219 | }), 220 | 221 | on(Actions.modifyFeatures, (state, action): EditorState => { 222 | return newState(state, {features: action.features || []}) 223 | }), 224 | 225 | on(Actions.modifyInstallation, (state, action): EditorState => { 226 | return newState(state, {installSteps: action.steps || []}) 227 | }), 228 | 229 | on(Actions.modifyUsage, (state, action): EditorState => { 230 | return newState(state, {installUsage: action.steps || []}) 231 | }), 232 | 233 | on(Actions.displayMarkdownResult, (state, action): EditorState => { 234 | return newState(state, {displayMarkdownResult: true}) 235 | }), 236 | 237 | on(Actions.hideMarkdownResult, (state, action): EditorState => { 238 | return newState(state, {displayMarkdownResult: false}) 239 | }), 240 | 241 | on(Actions.generateMarkdown, (state, action): EditorState => { 242 | return newState(state, {generateMarkdown: action.generate}) 243 | }), 244 | 245 | on(Actions.markdownGenerated, (state, action): EditorState => { 246 | return newState(state, { 247 | generateMarkdown: false, 248 | generatedMarkdown: action.markdown, 249 | displayMarkdownResult: true 250 | }) 251 | }), 252 | 253 | on(Actions.setData, (state, action): EditorState => { 254 | return newState(state, action.data) 255 | }), 256 | ); 257 | 258 | const newState = (oldState: any, newData: any): EditorState => { 259 | const newState = {...oldState, ...newData} 260 | console.log('calculating new state', newData, newState) 261 | return newState 262 | } 263 | -------------------------------------------------------------------------------- /src/app/store/reducers/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ActionReducerMap, 3 | } from '@ngrx/store'; 4 | import {AppState} from "../state.interface"; 5 | import {editorReducer} from "./editor.reducer"; 6 | 7 | export const reducers: ActionReducerMap = { 8 | editor: editorReducer 9 | }; 10 | 11 | -------------------------------------------------------------------------------- /src/app/store/selectors/editor.selectors.ts: -------------------------------------------------------------------------------- 1 | import {AppState} from "../state.interface"; 2 | import {createSelector} from "@ngrx/store"; 3 | import {EditorState} from "../reducers/editor.reducer"; 4 | 5 | export const editorSelector = (state: AppState) => state.editor; 6 | 7 | export const selectGeneratedMarkdown = createSelector( 8 | editorSelector, 9 | (state: EditorState) => state.generatedMarkdown) 10 | 11 | export const selectGeneratingMarkdown = createSelector( 12 | editorSelector, 13 | (state: EditorState) => state.generateMarkdown) 14 | export const selectDescription = createSelector( 15 | editorSelector, 16 | (state: EditorState) => state.description) 17 | export const selectTitle = createSelector( 18 | editorSelector, 19 | (state: EditorState) => state.title) 20 | 21 | export const selectShortDescription = createSelector( 22 | editorSelector, 23 | (state: EditorState) => state.shortDescription) 24 | 25 | export const selectContentTable = createSelector( 26 | editorSelector, 27 | (state: EditorState) => state.contentTable) 28 | 29 | export const selectNavigationLinks = createSelector( 30 | editorSelector, 31 | (state: EditorState) => state.navigationLinks) 32 | 33 | export const selectFeatures = createSelector( 34 | editorSelector, 35 | (state: EditorState) => state.features) 36 | 37 | 38 | export const selectRepository = createSelector( 39 | editorSelector, 40 | (state: EditorState) => state.github.repo) 41 | 42 | export const selectRepositoryBadges = createSelector( 43 | editorSelector, 44 | (state: EditorState) => state.github.badges) 45 | 46 | export const selectNpmPackage = createSelector( 47 | editorSelector, 48 | (state: EditorState) => state.npm.url) 49 | 50 | export const selectNpmBadges = createSelector( 51 | editorSelector, 52 | (state: EditorState) => state.npm.badges) 53 | 54 | export const selectBackToTop = createSelector( 55 | editorSelector, 56 | (state: EditorState) => state.backToTop) 57 | 58 | export const selectSectionIcons = createSelector( 59 | editorSelector, 60 | (state: EditorState) => state.sectionIcons) 61 | 62 | export const selectLogo = createSelector( 63 | editorSelector, 64 | (state: EditorState) => state.logoUrl) 65 | 66 | export const selectMainImage = createSelector( 67 | editorSelector, 68 | (state: EditorState) => state.mainImageUrl) 69 | 70 | export const selectScreenshots = createSelector( 71 | editorSelector, 72 | (state: EditorState) => state.images) 73 | 74 | export const selectStackTech = createSelector( 75 | editorSelector, 76 | (state: EditorState) => state.technologies.map(t => t.value)) 77 | 78 | export const selectInstallSteps = createSelector( 79 | editorSelector, 80 | (state: EditorState) => state.installSteps) 81 | 82 | export const selectUsageSteps = createSelector( 83 | editorSelector, 84 | (state: EditorState) => state.usageSteps) 85 | 86 | export const selectParameters = createSelector( 87 | editorSelector, 88 | (state: EditorState) => state.configuration.parameters) 89 | 90 | export const selectAcknowledgment = createSelector( 91 | editorSelector, 92 | (state: EditorState) => state.acknowledgments) 93 | 94 | export const selectContribution = createSelector( 95 | editorSelector, 96 | (state: EditorState) => state.contribution) 97 | 98 | export const selectContributors = createSelector( 99 | editorSelector, 100 | (state: EditorState) => state.contributors) 101 | 102 | export const selectAuthorName = createSelector( 103 | editorSelector, 104 | (state: EditorState) => state.author.name) 105 | 106 | export const selectAuthorGithubUsername = createSelector( 107 | editorSelector, 108 | (state: EditorState) => state.author.github) 109 | 110 | 111 | export const selectAuthorLinkedinUsername = createSelector( 112 | editorSelector, 113 | (state: EditorState) => state.author.likedIn ?? '') 114 | 115 | 116 | export const selectLicense = createSelector( 117 | editorSelector, 118 | (state: EditorState) => state.license) 119 | -------------------------------------------------------------------------------- /src/app/store/state.interface.ts: -------------------------------------------------------------------------------- 1 | import {EditorState} from "./reducers/editor.reducer"; 2 | 3 | export interface AppState { 4 | editor: EditorState, 5 | } 6 | -------------------------------------------------------------------------------- /src/app/toast/toast.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/app/toast/toast.component.css -------------------------------------------------------------------------------- /src/app/toast/toast.component.html: -------------------------------------------------------------------------------- 1 | 32 | -------------------------------------------------------------------------------- /src/app/toast/toast.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ToastComponent } from './toast.component'; 4 | 5 | describe('ToastComponent', () => { 6 | let component: ToastComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ ToastComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(ToastComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/toast/toast.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input} from '@angular/core'; 2 | import {UtilsService} from "../services/utils.service"; 3 | import {animate, style, transition, trigger} from "@angular/animations"; 4 | import {Toast, ToastService} from "../services/toast.service"; 5 | 6 | @Component({ 7 | selector: 'app-toast', 8 | templateUrl: './toast.component.html', 9 | styleUrls: ['./toast.component.css'], 10 | animations: [ 11 | trigger('fade', [ 12 | transition(':enter', [ 13 | style({transform: 'translateY(10%)', opacity: 0}), 14 | animate('400ms', style({transform: 'translateY(0)', opacity: 1})), 15 | ]), 16 | transition(':leave', [ 17 | style({transform: 'translateY(0)', opacity: 1}), 18 | animate('200ms', style({transform: 'translateY(-5%)', opacity: 0})), 19 | ]), 20 | ]), 21 | ] 22 | }) 23 | export class ToastComponent { 24 | 25 | @Input() 26 | toast!: Toast; 27 | 28 | 29 | constructor(private utilsService: UtilsService, private toastService: ToastService) { 30 | } 31 | 32 | close() { 33 | this.toastService.close(this.toast.id); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/assets/.gitkeep -------------------------------------------------------------------------------- /src/assets/beams.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/assets/beams.jpg -------------------------------------------------------------------------------- /src/assets/fonts/IBM Plex Sans Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/assets/fonts/IBM Plex Sans Regular.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/PP Agrandir Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/assets/fonts/PP Agrandir Bold.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/PP Agrandir Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/assets/fonts/PP Agrandir Regular.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/TN Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/assets/fonts/TN Light.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/TN Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/assets/fonts/TN Medium.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/TN Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/assets/fonts/TN Regular.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/iA Writter Quattro S Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/assets/fonts/iA Writter Quattro S Regular.woff2 -------------------------------------------------------------------------------- /src/assets/grid.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/assets/images/devhunt_badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/assets/images/devhunt_badge.png -------------------------------------------------------------------------------- /src/assets/images/dmp_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/assets/images/dmp_1.png -------------------------------------------------------------------------------- /src/assets/images/dmp_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/assets/images/dmp_2.png -------------------------------------------------------------------------------- /src/assets/images/dmp_s_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/assets/images/dmp_s_1.png -------------------------------------------------------------------------------- /src/assets/images/dmp_s_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/assets/images/dmp_s_2.png -------------------------------------------------------------------------------- /src/assets/images/dmp_s_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/assets/images/dmp_s_3.png -------------------------------------------------------------------------------- /src/assets/images/dmp_s_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/assets/images/dmp_s_4.png -------------------------------------------------------------------------------- /src/assets/images/github_corner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/assets/images/github_corner.png -------------------------------------------------------------------------------- /src/assets/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/assets/images/icon.png -------------------------------------------------------------------------------- /src/data/mock.ts: -------------------------------------------------------------------------------- 1 | import {EditorState} from "../app/store/reducers/editor.reducer"; 2 | import {LicenseType} from "../app/enums/license-type.enum"; 3 | 4 | export const testData: EditorState = { 5 | title: 'Document My Project', 6 | shortDescription: 'Easily create markdown documentation for your project', 7 | description: 'Tired of manually writing README files? this tool simplifies the process of creating documentation for Github projects. With just a few clicks, you can generate comprehensive documentation that enhances the visibility and usability of your repositories in seconds.', 8 | navigationLinks: true, 9 | sectionIcons: true, 10 | backToTop: true, 11 | installSteps: [ 12 | 'Install Node.js v16 or later', 13 | 'Install the required dependencies:', 14 | '`npm install`' 15 | ], 16 | usageSteps: [ 17 | 'Open the project directory in your code editor', 18 | 'Run `npm run start` to start the development server', 19 | ], 20 | contentTable: true, 21 | github: { 22 | username: 'luisvent', 23 | repo: 'document_my_project', 24 | badges: true 25 | }, 26 | logoUrl: '../assets/images/icon.png', 27 | mainImageUrl: '../assets/images/dmp_1.png', 28 | displayMarkdownResult: false, 29 | npm: { 30 | package: 'http-status-utility', 31 | url: 'https://www.npmjs.com/package/http-status-utility', 32 | badges: true 33 | }, 34 | images: [ 35 | '../assets/images/dmp_s_1.png', 36 | '../assets/images/dmp_s_2.png', 37 | '../assets/images/dmp_s_3.png', 38 | '../assets/images/dmp_s_4.png', 39 | ], 40 | features: [ 41 | { 42 | title: 'Template ready', 43 | description: 'Provide a clear and concise description of your project, highlight the main features, goals, and benefits of your project' 44 | }, 45 | { 46 | title: 'Ease fo use', 47 | description: 'Easily generate a well-structured README file for your GitHub project' 48 | }, 49 | { 50 | title: 'Preview', 51 | description: 'Preview the generated README (light/dark theme) file before committing it to your repository' 52 | } 53 | ], 54 | technologies: [ 55 | { 56 | name: 'Angular', 57 | value: 'angular', 58 | description: "A front-end web application framework", 59 | mainColor: "#DD0031" 60 | }, 61 | {name: 'NgRx', value: 'ngrx', description: "Angular state management based on Redux", mainColor: "#B7116E"}, 62 | {name: 'Tailwind CSS', value: 'tailwindcss', description: 'Utility-first CSS framework', mainColor: '#38B2AC'}, 63 | { 64 | name: 'TypeScript', 65 | value: 'typescript', 66 | description: "A strict syntactical superset of JavaScript", 67 | mainColor: "#3178C6" 68 | }, 69 | ], 70 | installation: { 71 | projectName: '', 72 | packageManager: '', 73 | dependencies: [], 74 | devDependencies: [], 75 | installationSteps: [], 76 | includeSetup: false, 77 | setupSteps: [], 78 | includeUsage: false, 79 | usageSteps: [], 80 | }, 81 | configuration: { 82 | description: 'Default values to configure', 83 | parameters: [] 84 | }, 85 | acknowledgments: [ 86 | { 87 | title: 'ngx-markdown', 88 | url: 'https://www.npmjs.com/package/ngx-markdown', 89 | description: 'Angular markdown component/directive/pipe/service to parse static, dynamic or remote content to HTML with syntax highlight and more' 90 | }, 91 | { 92 | title: 'Flowbite', 93 | url: 'https://flowbite.com/', 94 | description: 'Build websites even faster with components on top of Tailwind CSS' 95 | }, 96 | { 97 | title: 'PrismJs', 98 | url: 'https://prismjs.com/', 99 | description: 'Prism is a lightweight, extensible syntax highlighter, built with modern web standards in mind. It’s used in millions of websites, including some of those you visit daily.' 100 | } 101 | ], 102 | contribution: {add: true, contributorsImg: true, contributionGuidelinesLink: undefined}, 103 | contributors: [ 104 | { 105 | name: 'Luis Ventura', 106 | username: 'luisvent' 107 | } 108 | ], 109 | author: { 110 | name: 'Luis Ventura', 111 | email: 'luis.ventura@email.com', 112 | url: 'luisvent.com ', 113 | github: 'luisvent', 114 | likedIn: 'luisvent', 115 | }, 116 | license: {type: LicenseType.MIT, customText: undefined}, 117 | watermark: true, 118 | generateMarkdown: false, 119 | generatedMarkdown: '' 120 | }; 121 | -------------------------------------------------------------------------------- /src/data/tech-services.ts: -------------------------------------------------------------------------------- 1 | export const techService = [ 2 | {name: 'Continuous Integration', value: 'continuous-integration'}, 3 | {name: 'Continuous Deployment', value: 'continuous-deployment'}, 4 | {name: 'Continuous Delivery', value: 'continuous-delivery'}, 5 | {name: 'Microservices', value: 'microservices'}, 6 | {name: 'Serverless', value: 'serverless'}, 7 | {name: 'Containerization', value: 'containerization'}, 8 | {name: 'Virtualization', value: 'virtualization'}, 9 | {name: 'Infrastructure as Code', value: 'infrastructure-as-code'}, 10 | {name: 'Configuration Management', value: 'configuration-management'}, 11 | {name: 'Monitoring', value: 'monitoring'}, 12 | {name: 'Logging', value: 'logging'}, 13 | {name: 'Alerting', value: 'alerting'}, 14 | {name: 'Incident Management', value: 'incident-management'}, 15 | {name: 'Collaboration', value: 'collaboration'}, 16 | {name: 'Project Management', value: 'project-management'}, 17 | {name: 'Task Management', value: 'task-management'}, 18 | {name: 'Note-taking', value: 'note-taking'}, 19 | {name: 'Time Management', value: 'time-management'}, 20 | {name: 'Documentation', value: 'documentation'}, 21 | {name: 'Knowledge Management', value: 'knowledge-management'}, 22 | {name: 'Team Communication', value: 'team-communication'}, 23 | {name: 'Video Conferencing', value: 'video-conferencing'}, 24 | {name: 'Chat', value: 'chat'}, 25 | {name: 'Issue Tracking', value: 'issue-tracking'}, 26 | {name: 'Workflow Management', value: 'workflow-management'}, 27 | {name: 'Task Automation', value: 'task-automation'}, 28 | {name: 'Deployment Automation', value: 'deployment-automation'}, 29 | {name: 'CI/CD Pipeline', value: 'ci-cd-pipeline'}, 30 | {name: 'Observability', value: 'observability'}, 31 | {name: 'Dashboards', value: 'dashboards'}, 32 | {name: 'Performance Monitoring', value: 'performance-monitoring'}, 33 | {name: 'Error Tracking', value: 'error-tracking'}, 34 | {name: 'Event Monitoring', value: 'event-monitoring'}, 35 | {name: 'Infrastructure Monitoring', value: 'infrastructure-monitoring'}, 36 | {name: 'Log Management', value: 'log-management'}, 37 | {name: 'Application Performance Monitoring', value: 'application-performance-monitoring'}, 38 | {name: 'Transaction Monitoring', value: 'transaction-monitoring'}, 39 | {name: 'User Monitoring', value: 'user-monitoring'}, 40 | {name: 'Business Monitoring', value: 'business-monitoring'}, 41 | {name: 'AIOps', value: 'aiops'}, 42 | {name: 'Site Reliability Engineering (SRE)', value: 'sre'}, 43 | {name: 'IT Operations', value: 'it-operations'}, 44 | {name: 'DevSecOps', value: 'devsecops'}, 45 | {name: 'GitOps', value: 'gitops'}, 46 | {name: 'Cloud Computing', value: 'cloud-computing'}, 47 | {name: 'Networking', value: 'networking'}, 48 | {name: 'Cybersecurity', value: 'cybersecurity'}, 49 | {name: 'Identity and Access Management (IAM)', value: 'iam'}, 50 | {name: 'Encryption', value: 'encryption'}, 51 | {name: 'Firewalls', value: 'firewalls'}, 52 | {name: 'Intrusion Detection and Prevention Systems (IDPS)', value: 'idps'}, 53 | {name: 'Data Loss Prevention (DLP)', value: 'dlp'}, 54 | {name: 'Antivirus', value: 'antivirus'}, 55 | {name: 'Security Information and Event Management (SIEM)', value: 'siem'}, 56 | {name: 'Vulnerability Management', value: 'vulnerability-management'}, 57 | {name: 'Penetration Testing', value: 'penetration-testing'}, 58 | {name: 'Security Operations Center (SOC)', value: 'soc'}, 59 | {name: 'Security Orchestration, Automation, and Response (SOAR)', value: 'soar'}, 60 | {name: 'Compliance', value: 'compliance'}, 61 | {name: 'GDPR', value: 'gdpr'}, 62 | {name: 'HIPAA', value: 'hipaa'}, 63 | {name: 'PCI DSS', value: 'pci-dss'}, 64 | {name: 'ISO 27001', value: 'iso-27001'}, 65 | {name: 'NIST', value: 'nist'}, 66 | {name: 'CIS Controls', value: 'cis-controls'}, 67 | {name: 'OWASP', value: 'owasp'}, 68 | {name: 'Zero Trust', value: 'zero-trust'}, 69 | {name: 'Multi-factor Authentication (MFA)', value: 'mfa'}, 70 | {name: 'Single Sign-On (SSO)', value: 'sso'}, 71 | {name: 'Role-based Access Control (RBAC)', value: 'rbac'}, 72 | {name: 'Privileged Access Management (PAM)', value: 'pam'}, 73 | {name: 'Security Information Sharing', value: 'security-information-sharing'}, 74 | {name: 'Threat Intelligence', value: 'threat-intelligence'}, 75 | {name: 'Security Awareness Training', value: 'security-awareness-training'}, 76 | {name: 'Phishing Simulation', value: 'phishing-simulation'}, 77 | {name: 'Security Policies and Procedures', value: 'security-policies-procedures'}, 78 | {name: 'Incident Response Plan', value: 'incident-response-plan'}, 79 | {name: 'Business Continuity Plan (BCP)', value: 'business-continuity-plan'}, 80 | {name: 'Disaster Recovery Plan (DRP)', value: 'disaster-recovery-plan'}, 81 | {name: 'Security Risk Assessment', value: 'security-risk-assessment'}, 82 | {name: 'Security Controls', value: 'security-controls'}, 83 | {name: 'Patch Management', value: 'patch-management'}, 84 | {name: 'Asset Management', value: 'asset-management'}, 85 | {name: 'Configuration Management', value: 'configuration-management'}, 86 | {name: 'Change Management', value: 'change-management'}, 87 | {name: 'Access Control', value: 'access-control'}, 88 | {name: 'Network Security', value: 'network-security'}, 89 | {name: 'Endpoint Security', value: 'endpoint-security'}, 90 | {name: 'Data Security', value: 'data-security'}, 91 | {name: 'Application Security', value: 'application-security'}, 92 | {name: 'Cloud Security', value: 'cloud-security'}, 93 | {name: 'Mobile Security', value: 'mobile-security'}, 94 | {name: 'IoT Security', value: 'iot-security'}, 95 | {name: 'Blockchain Security', value: 'blockchain-security'}, 96 | {name: 'AI/ML Security', value: 'ai-ml-security'}, 97 | {name: 'Deception Technology', value: 'deception-technology'}, 98 | {name: 'Security Operations', value: 'security-operations'}, 99 | {name: 'Forensics', value: 'forensics'}, 100 | {name: 'Cyber Threat Hunting', value: 'cyber-threat-hunting'}, 101 | {name: 'Cyber Threat Intelligence', value: 'cyber-threat-intelligence'}, 102 | {name: 'Malware Analysis', value: 'malware-analysis'}, 103 | {name: 'Digital Forensics', value: 'digital-forensics'}, 104 | {name: 'Network Forensics', value: 'network-forensics'}, 105 | {name: 'Incident Response', value: 'incident-response'}, 106 | {name: 'Security Incident Management', value: 'security-incident-management'}, 107 | {name: 'Fraud Detection', value: 'fraud-detection'}, 108 | {name: 'Identity Theft Protection', value: 'identity-theft-protection'}, 109 | {name: 'Data Breach Prevention', value: 'data-breach-prevention'}, 110 | {name: 'Zero-Day Exploit Prevention', value: 'zero-day-exploit-prevention'}, 111 | {name: 'Insider Threat Detection', value: 'insider-threat-detection'}, 112 | {name: 'External Threat Intelligence', value: 'external-threat-intelligence'}, 113 | {name: 'Internal Threat Intelligence', value: 'internal-threat-intelligence'}, 114 | {name: 'Third-party Risk Management', value: 'third-party-risk-management'}, 115 | {name: 'Compliance Management', value: 'compliance-management'}, 116 | {name: 'Security Awareness', value: 'security-awareness'}, 117 | {name: 'Privacy', value: 'privacy'}, 118 | {name: 'Identity Management', value: 'identity-management'}, 119 | {name: 'Access Management', value: 'access-management'}, 120 | {name: 'Directory Services', value: 'directory-services'}, 121 | {name: 'Authentication', value: 'authentication'}, 122 | {name: 'Authorization', value: 'authorization'}, 123 | ]; 124 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisvent/document_my_project/941ff74a3ca51797886cfd2580f4da0d563034f0/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document My Project 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 2 | 3 | import { AppModule } from './app/app.module'; 4 | 5 | 6 | platformBrowserDynamic().bootstrapModule(AppModule) 7 | .catch(err => console.error(err)); 8 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | @font-face { 7 | font-family: Writter; 8 | src: url('./assets/fonts/iA Writter Quattro S Regular.woff2') format("woff2"); 9 | } 10 | @font-face { 11 | font-family: Agrandir; 12 | src: url('./assets/fonts/PP Agrandir Regular.woff2') format("woff2"); 13 | } 14 | @font-face { 15 | font-family: TN; 16 | src: url('./assets/fonts/TN Medium.woff2') format("woff2"); 17 | } 18 | } 19 | 20 | body { 21 | @apply text-slate-600 font-writter 22 | } 23 | 24 | p { 25 | @apply text-lg font-normal text-gray-500 lg:text-xl dark:text-gray-400 26 | } 27 | 28 | h1 { 29 | @apply mb-4 text-4xl font-extrabold leading-none tracking-tight text-gray-900 md:text-5xl lg:text-6xl dark:text-white text-slate-600 30 | } 31 | 32 | h2 { 33 | @apply text-5xl font-bold dark:text-white mb-2 mt-3 text-slate-600 34 | } 35 | 36 | h3 { 37 | @apply text-3xl font-bold dark:text-white mb-2 mt-3 text-slate-600 38 | } 39 | 40 | h4 { 41 | @apply text-2xl font-bold dark:text-white mb-2 mt-3 text-slate-600 42 | } 43 | 44 | h5 { 45 | @apply text-xl font-bold dark:text-white mb-2 mt-3 text-slate-600 46 | } 47 | 48 | 49 | h6 { 50 | @apply text-sm font-bold dark:text-white mb-2 mt-3 text-slate-600 51 | } 52 | 53 | small { 54 | @apply text-[12px] text-slate-500 55 | } 56 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | import defaultTheme from 'tailwindcss/defaultTheme' 3 | 4 | module.exports = { 5 | content: [ 6 | "./src/**/*.{html,ts}", 7 | "./node_modules/flowbite/**/*.js" 8 | ], 9 | theme: { 10 | extend: { 11 | height: { 12 | '100vh-h-7': 'calc(100vh - 12rem)', 13 | }, 14 | fontFamily: { 15 | writter: ["Writter", ...defaultTheme.fontFamily.sans], 16 | agrandir: ["Agrandir", ...defaultTheme.fontFamily.sans], 17 | tn: ["TN", ...defaultTheme.fontFamily.sans], 18 | }, 19 | }, 20 | }, 21 | plugins: [ 22 | require("@tailwindcss/typography"), 23 | require('flowbite/plugin') 24 | ], 25 | } 26 | 27 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "noImplicitOverride": true, 10 | "noPropertyAccessFromIndexSignature": true, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "sourceMap": true, 14 | "declaration": false, 15 | "downlevelIteration": true, 16 | "experimentalDecorators": true, 17 | "moduleResolution": "node", 18 | "importHelpers": true, 19 | "target": "ES2022", 20 | "module": "ES2022", 21 | "useDefineForClassFields": false, 22 | "lib": [ 23 | "ES2022", 24 | "dom" 25 | ] 26 | }, 27 | "angularCompilerOptions": { 28 | "enableI18nLegacyMessageIdFormat": false, 29 | "strictInjectionParameters": true, 30 | "strictInputAccessModifiers": true, 31 | "strictTemplates": true 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "include": [ 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | --------------------------------------------------------------------------------