mirror of
				https://github.com/CorentinTh/it-tools.git
				synced 2025-10-31 12:03:48 +00:00 
			
		
		
		
	Compare commits
	
		
			5 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 85ef199145 | ||
|  | 908994acea | ||
|  | e7c589a033 | ||
|  | 625b43e436 | ||
|  | a970df5c02 | 
							
								
								
									
										26
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -3,32 +3,6 @@ All notable changes to this project will be documented in this file. | ||||
| The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | ||||
| and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | ||||
|  | ||||
| ## 1.5.2 | ||||
| - [feat] [humans.txt](/humans.txt) | ||||
| - [feat] pwa auto update on new changes | ||||
|  | ||||
| ## 1.5.1 | ||||
| - [feat] switched back to history mode (no more '#' in url) | ||||
|  | ||||
| ## 1.5.0 | ||||
| - [feat] added [qr-code generator](/#/qrcode-generator) | ||||
|  | ||||
| ## 1.4.0 | ||||
| - [ui] condensed + colored sidenav | ||||
| - [feat] added [git memo](/#/git-memo) | ||||
| - [refactor] changed app title | ||||
|  | ||||
| ## 1.3.0 | ||||
| - [fix] [GithubContributors] ordered contributors by contribution count | ||||
| - [refactor] used vue-typecasting for number inputs | ||||
| - [feat] lazy loading tools routes | ||||
| - [feat] added [markdown editor](/#/markdown-editor) | ||||
| - [feat] added [lorem ipsum generator](/#/lorem-ipsum-generator) | ||||
|  | ||||
| ## 1.2.1 | ||||
| - [fix] [UuidGenerator] added quantity validation rules | ||||
| - [refactor] better isInt checker | ||||
|  | ||||
| ## 1.2.0 | ||||
| - [feat] [UuidGenerator] can generate multiple uuids  | ||||
|  | ||||
|   | ||||
							
								
								
									
										38
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								README.md
									
									
									
									
									
								
							| @@ -2,7 +2,7 @@ | ||||
|  | ||||
| Aggregated set of useful tools that every developer may need once in a while. Available [here](https://it-tools.tech). | ||||
|  | ||||
| ## Functionalities roadmap | ||||
| ## Functionality/roadmap | ||||
| Here is an unordered list of the current functionalities, and some that may come.  | ||||
|  | ||||
| - [x] Token generator | ||||
| @@ -15,22 +15,15 @@ Here is an unordered list of the current functionalities, and some that may come | ||||
| - [x] Url encoder | ||||
| - [x] Base 64 generator | ||||
| - [x] Text information | ||||
| - [x] Markdown editor | ||||
| - [x] Lorem ipsum text generator | ||||
| - [x] Git memo (cheat sheet) | ||||
| - [x] QR code generator | ||||
| - [ ] CSS memo (cheat sheet) | ||||
| - [ ] REGEX memo (cheat sheet) + tester? | ||||
| - [ ] Minify/un-minify | ||||
| - [ ] Lorem ipsum text generator | ||||
| - [ ] Image exif editor/remover | ||||
| - [ ] QR code generator | ||||
| - [ ] Bip39 pass-phrase generator | ||||
| - [ ] Crontab friendly generator | ||||
| - [ ] Image format converter? | ||||
| - [ ] Image cropper  | ||||
| - [ ] Image resizer  | ||||
| - [ ] HTTP client (w/ axios + cors proxy) | ||||
| - [ ] Math expression evaluator | ||||
| - [ ] Math expression graph | ||||
| - [ ] HTTP client (w/ axios) | ||||
|  | ||||
| You have an idea of a tool? Submit a feature request! | ||||
|  | ||||
| @@ -53,29 +46,6 @@ npm run lint | ||||
| ## Contribute | ||||
| **Pull requests are welcome !** Feel free to contribute. | ||||
|  | ||||
| ### Add a tool | ||||
| To add a tool you just have to create a vue component in [src/routes/tools](./src/routes/tools), example: | ||||
| ```vue | ||||
| <template> | ||||
|     <v-card class="single-card"> | ||||
|         <v-card-title>My component</v-card-title> | ||||
|         <v-card-text>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</v-card-text> | ||||
|     </v-card> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|     export default { | ||||
|         name: "My component" | ||||
|     } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="less"> | ||||
| </style> | ||||
| ``` | ||||
|  | ||||
| Then, update the file [router.js](./src/router.js) specifying info of the component. | ||||
| Use [fontawesome 5](https://fontawesome.com/icons?d=gallery&m=free) for icons. | ||||
|  | ||||
| ## Credits | ||||
| Coded with ❤️ by [Corentin Thomasset](//corentin-thomasset.fr). | ||||
|  | ||||
|   | ||||
							
								
								
									
										29
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										29
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "it-tools", | ||||
|   "version": "1.5.2", | ||||
|   "version": "1.2.0", | ||||
|   "lockfileVersion": 1, | ||||
|   "requires": true, | ||||
|   "dependencies": { | ||||
| @@ -3139,12 +3139,6 @@ | ||||
|           "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", | ||||
|           "dev": true | ||||
|         }, | ||||
|         "highlight.js": { | ||||
|           "version": "9.18.1", | ||||
|           "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.1.tgz", | ||||
|           "integrity": "sha512-OrVKYz70LHsnCgmbXctv/bfuvntIKDz177h0Co37DQ5jamGZLVmoCVMtjMtNZY3X9DrCcKfklHPNeA0uPZhSJg==", | ||||
|           "dev": true | ||||
|         }, | ||||
|         "supports-color": { | ||||
|           "version": "7.1.0", | ||||
|           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", | ||||
| @@ -4379,11 +4373,6 @@ | ||||
|         "domelementtype": "1" | ||||
|       } | ||||
|     }, | ||||
|     "dompurify": { | ||||
|       "version": "2.0.11", | ||||
|       "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.0.11.tgz", | ||||
|       "integrity": "sha512-qVoGPjIW9IqxRij7klDQQ2j6nSe4UNWANBhZNLnsS7ScTtLb+3YdxkRY8brNTpkUiTtcXsCJO+jS0UCDfenLuA==" | ||||
|     }, | ||||
|     "domutils": { | ||||
|       "version": "1.7.0", | ||||
|       "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", | ||||
| @@ -6264,6 +6253,12 @@ | ||||
|       "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "highlight.js": { | ||||
|       "version": "9.18.1", | ||||
|       "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.1.tgz", | ||||
|       "integrity": "sha512-OrVKYz70LHsnCgmbXctv/bfuvntIKDz177h0Co37DQ5jamGZLVmoCVMtjMtNZY3X9DrCcKfklHPNeA0uPZhSJg==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "hmac-drbg": { | ||||
|       "version": "1.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", | ||||
| @@ -8108,11 +8103,6 @@ | ||||
|         "object-visit": "^1.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "marked": { | ||||
|       "version": "1.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/marked/-/marked-1.1.0.tgz", | ||||
|       "integrity": "sha512-EkE7RW6KcXfMHy2PA7Jg0YJE1l8UPEZE8k45tylzmZM30/r1M1MUXWQfJlrSbsTeh7m/XTwHbWUENvAJZpp1YA==" | ||||
|     }, | ||||
|     "md5.js": { | ||||
|       "version": "1.3.5", | ||||
|       "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", | ||||
| @@ -9990,11 +9980,6 @@ | ||||
|       "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "qrcode.vue": { | ||||
|       "version": "1.7.0", | ||||
|       "resolved": "https://registry.npmjs.org/qrcode.vue/-/qrcode.vue-1.7.0.tgz", | ||||
|       "integrity": "sha512-R7t6Y3fDDtcU7L4rtqwGUDP9xD64gJhIwpfjhRCTKmBoYF6SS49PIJHRJ048cse6OI7iwTwgyy2C46N9Ygoc6g==" | ||||
|     }, | ||||
|     "qs": { | ||||
|       "version": "6.5.2", | ||||
|       "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| { | ||||
|   "name": "it-tools", | ||||
|   "description": "", | ||||
|   "version": "1.5.2", | ||||
|   "version": "1.2.0", | ||||
|   "private": true, | ||||
|   "scripts": { | ||||
|     "serve": "vue-cli-service serve", | ||||
| @@ -13,9 +13,6 @@ | ||||
|     "color-convert": "^2.0.1", | ||||
|     "color-name": "^1.1.4", | ||||
|     "core-js": "^3.6.4", | ||||
|     "dompurify": "^2.0.11", | ||||
|     "marked": "^1.1.0", | ||||
|     "qrcode.vue": "^1.7.0", | ||||
|     "register-service-worker": "^1.7.1", | ||||
|     "roboto-fontface": "*", | ||||
|     "vue": "^2.6.11", | ||||
|   | ||||
| @@ -1,5 +0,0 @@ | ||||
| /* TEAM */ | ||||
| Developer: Corentin Thomasset | ||||
| Site: https://github.com/CorentinTh | ||||
| Twitter: @cthmsst | ||||
|  | ||||
| @@ -5,8 +5,7 @@ | ||||
|     <meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||||
|     <meta name="viewport" content="width=device-width,initial-scale=1.0"> | ||||
|     <link rel="icon" href="<%= BASE_URL %>favicon.ico"> | ||||
|     <title>IT Tools - Set of handy developer tools</title> | ||||
|     <link rel="canonical" href="https://it-tools.tech"> | ||||
|     <title><%= htmlWebpackPlugin.options.title %></title> | ||||
|     <meta itemprop="name" content="IT-Tools"> | ||||
|     <meta property="og:title" content="IT-Tools"> | ||||
|     <meta name="twitter:title" content="IT-Tools"> | ||||
| @@ -17,7 +16,6 @@ | ||||
|     <meta itemprop="image" content="/img/banner.png"> | ||||
|     <meta property="og:image" content="/img/banner.png"> | ||||
|     <meta name="twitter:image" content="/img/banner.png"> | ||||
|     <link rel="author" href="humans.txt" /> | ||||
|   </head> | ||||
|   <body> | ||||
|     <noscript> | ||||
|   | ||||
							
								
								
									
										72
									
								
								src/App.vue
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								src/App.vue
									
									
									
									
									
								
							| @@ -1,24 +1,23 @@ | ||||
| <template> | ||||
|     <v-app id="inspire"> | ||||
|         <vue-headful | ||||
|                 :title="currentRoute ? `${currentRoute.text} - IT Tools` : 'IT Tools - Set of handy developer tools'" | ||||
|                 :description="currentRoute ? currentRoute.description: 'Aggregated set of useful tools that every developer may need once in a while.'" | ||||
|                 :keywords="currentRoute ? currentRoute.keywords: null" | ||||
|                 image="/img/banner.png" | ||||
|             :title="currentRoute ? `${currentRoute.text} - IT-Tools` : 'IT-Tools'" | ||||
|             :description="currentRoute ? currentRoute.description: 'Aggregated set of useful tools that every developer may need once in a while.'" | ||||
|             :keywords="currentRoute ? currentRoute.keywords: null" | ||||
|             image="/img/banner.png" | ||||
|         /> | ||||
|         <v-navigation-drawer v-model="drawer" app clipped> | ||||
|             <template v-slot:prepend> | ||||
|                 <SearchBar class="hidden-sm-and-up"/> | ||||
|             </template> | ||||
|  | ||||
|             <v-list dense id="navigation-list"> | ||||
|             <SearchBar class="hidden-sm-and-up" /> | ||||
|  | ||||
|             <v-list dense> | ||||
|  | ||||
|                 <div v-for="section in items" :key="section.title"> | ||||
|                     <v-subheader class="mt-4 pl-4">{{section.title}}</v-subheader> | ||||
|  | ||||
|                     <v-list-item v-for="item in section.child" :key="item.text" :to="item.path"> | ||||
|                         <v-list-item-action> | ||||
|                             <v-icon style="width: 1.25em">{{ item.icon }}</v-icon> | ||||
|                             <v-icon>{{ item.icon }}</v-icon> | ||||
|                         </v-list-item-action> | ||||
|                         <v-list-item-content> | ||||
|                             <v-list-item-title> | ||||
| @@ -100,7 +99,7 @@ | ||||
|             appVersion: 'v' + process.env.APPLICATION_VERSION, | ||||
|             drawer: null, | ||||
|             items: toolsComponents, | ||||
|             currentRoute: {} | ||||
|             currentRoute:{} | ||||
|         }), | ||||
|         mounted() { | ||||
|             this.setTitle() | ||||
| @@ -108,14 +107,14 @@ | ||||
|         created() { | ||||
|             this.$vuetify.theme.dark = true | ||||
|         }, | ||||
|         methods: { | ||||
|             setTitle() { | ||||
|         methods:{ | ||||
|             setTitle(){ | ||||
|                 const path = this.$router.currentRoute.path; | ||||
|                 this.currentRoute = toolsComponents.map(p => p.child).flat().find(p => p.path === path) | ||||
|             } | ||||
|         }, | ||||
|         watch: { | ||||
|             '$route'() { | ||||
|         watch:{ | ||||
|             '$route'(){ | ||||
|                 this.setTitle() | ||||
|             } | ||||
|         } | ||||
| @@ -126,51 +125,6 @@ | ||||
|     html { | ||||
|         overflow-y: auto !important; | ||||
|     } | ||||
|     code{ | ||||
|         background-color: rgba(0, 0, 0, 0.15) !important; | ||||
|         box-shadow: none !important; | ||||
|         color: #9a9a9a !important; | ||||
|         font-weight: normal !important; | ||||
|     } | ||||
|     .pretty-scrollbar{ | ||||
|         &::-webkit-scrollbar { | ||||
|             width: 5px!important; | ||||
|             height: 5px !important; | ||||
|         } | ||||
|  | ||||
|         /* Track */ | ||||
|         &::-webkit-scrollbar-track { | ||||
|             opacity: 0 !important; | ||||
|         } | ||||
|  | ||||
|         /* Handle */ | ||||
|         &::-webkit-scrollbar-thumb { | ||||
|             background: rgba(241, 241, 241, 0.10) !important; | ||||
|             border-radius: 10px; | ||||
|         } | ||||
|  | ||||
|         /* Handle on hover */ | ||||
|         &::-webkit-scrollbar-thumb:hover { | ||||
|             background: rgba(241, 241, 241, 0.20)!important; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #navigation-list{ | ||||
|         div:first-child .v-subheader{ | ||||
|                 margin-top: 0 !important; | ||||
|         } | ||||
|  | ||||
|         .v-list-item__action{ | ||||
|             margin: 8px 25px 8px 0; | ||||
|             .v-icon{ | ||||
|                 color: #4CAF50 !important; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     .v-navigation-drawer__content{ | ||||
|         .pretty-scrollbar; | ||||
|     } | ||||
|  | ||||
|     .single-card { | ||||
|         width: 100%; | ||||
|   | ||||
| @@ -4,9 +4,7 @@ | ||||
|         <p class="text-justify"> | ||||
|             Welcome to <strong>IT-Tools</strong>! This wonderful website, originally created with ❤ by | ||||
|             <a href="//corentin-thomasset.fr">Corentin Thomasset</a>, aggregate a set of useful tools | ||||
|             that every developer may need once in a while. And don't forget to add <strong>IT-Tools</strong> to your | ||||
|             shortcut bar (press <code>{{ isMacOS ? 'Cmd' : 'Ctrl' }} + | ||||
|             D</code>). | ||||
|             that every developer may need once in a while. | ||||
|         </p> | ||||
|  | ||||
|  | ||||
| @@ -32,10 +30,7 @@ | ||||
|  | ||||
| <script> | ||||
|     export default { | ||||
|         name: "Abstract", | ||||
|         data: () => ({ | ||||
|             isMacOS: navigator.platform.toUpperCase().indexOf('MAC') >= 0 | ||||
|         }) | ||||
|         name: "Abstract" | ||||
|     } | ||||
| </script> | ||||
|  | ||||
|   | ||||
| @@ -1,58 +0,0 @@ | ||||
| <template> | ||||
|     <v-text-field v-model="color" hide-details class="ma-0 pa-0" outlined :label="label" v-on:input="$emit('input', color)"> | ||||
|         <template v-slot:append> | ||||
|             <v-menu v-model="menu" top nudge-bottom="101" nudge-left="16" :close-on-content-click="false"> | ||||
|                 <template v-slot:activator="{ on }"> | ||||
|                     <div :style="swatchStyle" v-on="on" /> | ||||
|                 </template> | ||||
|                 <v-card> | ||||
|                     <v-card-text class="pa-0"> | ||||
|                         <v-color-picker v-model="color" flat v-on:input="$emit('input', color)"/> | ||||
|                     </v-card-text> | ||||
|                 </v-card> | ||||
|             </v-menu> | ||||
|         </template> | ||||
|     </v-text-field> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|     // From: https://codepen.io/JamieCurnow/pen/KKPjraK | ||||
|  | ||||
|     export default { | ||||
|         name: "ColorInput", | ||||
|         props:{ | ||||
|             value: { | ||||
|                 type: String, | ||||
|                 default: '#FFFFFF' | ||||
|             }, | ||||
|             label:String | ||||
|         }, | ||||
|         data: () => ({ | ||||
|             menu: false, | ||||
|             color:'' | ||||
|         }), | ||||
|         mounted() { | ||||
|             this.color = this.value | ||||
|         }, | ||||
|         computed: { | ||||
|             swatchStyle() { | ||||
|                 const { color, menu } = this | ||||
|                 return { | ||||
|                     backgroundColor: color, | ||||
|                     cursor: 'pointer', | ||||
|                     height: '30px', | ||||
|                     width: '30px', | ||||
|                     borderRadius: menu ? '50%' : '4px', | ||||
|                     transition: 'border-radius 200ms ease-in-out' | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="less"> | ||||
|     ::v-deep .v-input__append-inner{ | ||||
|         margin-top: 13px; | ||||
|     } | ||||
|  | ||||
| </style> | ||||
| @@ -1,43 +0,0 @@ | ||||
| <template> | ||||
|     <div class="copyable-code-content" @click="copy($slots.default[0].text)"> | ||||
|         <pre class="pretty-scrollbar"><slot></slot></pre> | ||||
|         <v-icon>far fa-copy</v-icon> | ||||
|     </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|     import {copyable} from "../mixins/copyable.mixin"; | ||||
|  | ||||
|     export default { | ||||
|         name: "CopyableCodeContent", | ||||
|         mixins: [copyable] | ||||
|     } | ||||
| </script> | ||||
|  | ||||
| <style lang="less" scoped> | ||||
|     .copyable-code-content { | ||||
|         cursor: pointer; | ||||
|         background-color: rgba(0, 0, 0, 0.1); | ||||
|         border-radius: 4px; | ||||
|         padding: 8px 15px; | ||||
|         display: flex; | ||||
|         flex-direction: row; | ||||
|         align-items: center; | ||||
|         justify-content: center; | ||||
|  | ||||
|         pre { | ||||
|             flex: 1; | ||||
|             overflow-x: auto; | ||||
|         } | ||||
|  | ||||
|         .v-icon { | ||||
|             opacity: 0; | ||||
|         } | ||||
|  | ||||
|         &:hover { | ||||
|             .v-icon { | ||||
|                 opacity: 1; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| </style> | ||||
| @@ -36,7 +36,7 @@ | ||||
|             axios | ||||
|                 .get(url) | ||||
|                 .then(({data}) => { | ||||
|                     this.contributors = data.sort((a, b) => b.contributions - a.contributions) | ||||
|                     this.contributors = data.sort((a, b) => a.contributions - b.contributions) | ||||
|                     this.loading = false | ||||
|                 }) | ||||
|                 .catch(() => this.hasError = true) | ||||
|   | ||||
| @@ -1,73 +0,0 @@ | ||||
| <template> | ||||
|     <div class="memo-viewer" v-bind:style="{ columns: `auto ${colWidth}` }"> | ||||
|         <div class="section" v-for="(group,i) in memo" :key="i"> | ||||
|             <h2>{{group.section}}</h2> | ||||
|  | ||||
|             <div class="tip" v-for="(tips,i) in group.child" :key="i"> | ||||
|                 <v-card> | ||||
|                     <v-card-text> | ||||
|                         <template v-for="tip in (Array.isArray(tips) ? tips : [tips])"> | ||||
|                             <p :key="tip.text">{{tip.text}}</p> | ||||
|                             <CopyableCodeContent class="code" :key="tip.code">{{tip.code}}</CopyableCodeContent> | ||||
|                         </template> | ||||
|                     </v-card-text> | ||||
|                 </v-card> | ||||
|                 </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|     import CopyableCodeContent from "./CopyableCodeContent"; | ||||
|  | ||||
|     export default { | ||||
|         name: "MemoViewer", | ||||
|         props: { | ||||
|             memo: Array, | ||||
|             colWidth: { | ||||
|                 type: String, | ||||
|                 default: '400px' | ||||
|             } | ||||
|         }, | ||||
|         components: { | ||||
|             CopyableCodeContent | ||||
|         } | ||||
|     } | ||||
| </script> | ||||
|  | ||||
| <style lang="less" scoped> | ||||
|     .memo-viewer { | ||||
|         column-gap: 30px; | ||||
|         column-rule: 1px solid #37373961; | ||||
|         column-fill: auto; | ||||
|  | ||||
|     } | ||||
|     .section { | ||||
|         break-inside: avoid-column; | ||||
|         display: inline-block; | ||||
|         margin-bottom: 20px; | ||||
|         width: 100%; | ||||
|  | ||||
|         h2 { | ||||
|             margin: 25px 0 15px; | ||||
|             display: inline-block; | ||||
|         } | ||||
|  | ||||
|         .tip { | ||||
|             margin: 20px 0; | ||||
|  | ||||
|             .v-card{ | ||||
|                 background-color: rgba(47, 46, 46, 0.44); | ||||
|             } | ||||
|  | ||||
|             p { | ||||
|                 margin-bottom: 10px; | ||||
|  | ||||
|                 &:not(:first-child){ | ||||
|                     margin-top: 16px; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| </style> | ||||
| @@ -1,10 +0,0 @@ | ||||
| import {copyToClipboard} from "../utils/helpers"; | ||||
|  | ||||
| export const copyable = { | ||||
|     methods: { | ||||
|         copy(text, toastText = 'Copied to clipboard !'){ | ||||
|             copyToClipboard(text); | ||||
|             this.$toast.success(toastText) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -5,12 +5,6 @@ import router from "../router"; | ||||
| if(process.env.VUE_APP_GANALYTICS){ | ||||
|     Vue.use(VueAnalytics, { | ||||
|         id: process.env.VUE_APP_GANALYTICS, | ||||
|         router, | ||||
|         set:[ | ||||
|             { | ||||
|                 field: 'dimension1', | ||||
|                 value: process.env.APPLICATION_VERSION | ||||
|             } | ||||
|         ] | ||||
|         router | ||||
|     }) | ||||
| } | ||||
|   | ||||
| @@ -20,8 +20,7 @@ if (process.env.NODE_ENV === 'production') { | ||||
|       console.log('New content is downloading.') | ||||
|     }, | ||||
|     updated () { | ||||
|       console.log('New content is available; hard refresh.'); | ||||
|       window.location.reload(true); | ||||
|       console.log('New content is available; please refresh.') | ||||
|     }, | ||||
|     offline () { | ||||
|       console.log('No internet connection found. App is running in offline mode.') | ||||
|   | ||||
| @@ -1,9 +1,20 @@ | ||||
| import Vue from 'vue' | ||||
| import VueRouter from 'vue-router' | ||||
| import Home from './routes/Home.vue' | ||||
| import TokenGenerator from "./routes/tools/TokenGenerator"; | ||||
| import Hash from "./routes/tools/Hash"; | ||||
| import DateConverter from "./routes/tools/DateConverter"; | ||||
| import UrlEncoder from "./routes/tools/UrlEncoder"; | ||||
| import FileToBase64 from "./routes/tools/FileToBase64"; | ||||
| import TextCypher from "./routes/tools/TextCypher"; | ||||
| import TextStats from "./routes/tools/TextStats"; | ||||
| import BaseConverter from "./routes/tools/BaseConverter"; | ||||
| import UuidGenerator from "./routes/tools/UuidGenerator"; | ||||
| import ColorConverter from "./routes/tools/ColorConverter"; | ||||
|  | ||||
| Vue.use(VueRouter) | ||||
|  | ||||
|  | ||||
| const toolsComponents = [ | ||||
|     { | ||||
|         title: 'Crypto', | ||||
| @@ -12,7 +23,7 @@ const toolsComponents = [ | ||||
|                 icon: 'fa-key', | ||||
|                 text: 'Token generator', | ||||
|                 path: '/token-generator', | ||||
|                 component: () => import('./routes/tools/TokenGenerator'), | ||||
|                 component: TokenGenerator, | ||||
|                 keywords: ['token', 'random', 'string', 'alphanumeric'], | ||||
|                 description: 'Generate random tokens.' | ||||
|             }, | ||||
| @@ -20,14 +31,14 @@ const toolsComponents = [ | ||||
|                 icon: 'fa-fingerprint', | ||||
|                 text: 'Uuid generator', | ||||
|                 path: '/uuid-generator', | ||||
|                 component: () => import('./routes/tools/UuidGenerator'), | ||||
|                 component: UuidGenerator, | ||||
|                 keywords: ['token', 'v4', 'string', 'alphanumeric'] | ||||
|             }, | ||||
|             { | ||||
|                 icon: 'fa-font', | ||||
|                 text: 'Hash text', | ||||
|                 path: '/hash', | ||||
|                 component: () => import('./routes/tools/Hash'), | ||||
|                 component: Hash, | ||||
|                 keywords: ['md5', 'sha1', 'sha256', 'sha224', 'sha512', 'sha384', 'sha3', 'ripemd160', 'random'] | ||||
|  | ||||
|             }, | ||||
| @@ -35,7 +46,7 @@ const toolsComponents = [ | ||||
|                 icon: 'fa-lock', | ||||
|                 text: 'Cypher/uncypher text', | ||||
|                 path: '/cypher', | ||||
|                 component: () => import('./routes/tools/TextCypher'), | ||||
|                 component: TextCypher, | ||||
|                 keywords: ['aes', 'tripledes', 'rabbit', 'rabbitlegacy', 'rc4'] | ||||
|             }, | ||||
|         ], | ||||
| @@ -47,21 +58,21 @@ const toolsComponents = [ | ||||
|                 icon: 'fa-calendar', | ||||
|                 text: 'Date/Time converter', | ||||
|                 path: '/date-converter', | ||||
|                 component: () => import('./routes/tools/DateConverter'), | ||||
|                 component: DateConverter, | ||||
|                 keywords: ['locale', 'format', 'iso 8601', 'utc', 'timestamp', 'unix', 'year', 'month', 'day', 'hours', 'minutes', 'seconds'] | ||||
|             }, | ||||
|             { | ||||
|                 icon: 'fa-exchange-alt', | ||||
|                 text: 'Base converter', | ||||
|                 path: '/base-converter', | ||||
|                 component: () => import('./routes/tools/BaseConverter'), | ||||
|                 component: BaseConverter, | ||||
|                 keywords: ['binary', 'hexadecimal', 'decimal'] | ||||
|             }, | ||||
|             { | ||||
|                 icon: 'fa-palette', | ||||
|                 text: 'Color picker/converter', | ||||
|                 path: '/color-picker-converter', | ||||
|                 component: () => import('./routes/tools/ColorConverter'), | ||||
|                 component: ColorConverter, | ||||
|                 keywords: ['rgb', 'rgba', 'hexadecimal', 'hsla', 'red', 'green', 'blue', 'alpha'] | ||||
|             }, | ||||
|         ], | ||||
| @@ -73,66 +84,28 @@ const toolsComponents = [ | ||||
|                 icon: 'fa-link', | ||||
|                 text: 'URL encode/decode', | ||||
|                 path: '/url-encoder', | ||||
|                 component: () => import('./routes/tools/UrlEncoder'), | ||||
|                 component: UrlEncoder, | ||||
|                 keywords: ['%20'] | ||||
|             }, | ||||
|             { | ||||
|                 icon: 'fa-file-export', | ||||
|                 text: 'File to Base64', | ||||
|                 path: '/file-to-base64', | ||||
|                 component: () => import('./routes/tools/FileToBase64') | ||||
|                 component: FileToBase64 | ||||
|             }, | ||||
|         ], | ||||
|     }, | ||||
|     { | ||||
|         title: 'Text', | ||||
|         child: [ | ||||
|             { | ||||
|                 icon: 'fa-align-left', | ||||
|                 text: 'Text stats', | ||||
|                 path: '/text-stats', | ||||
|                 component: () => import('./routes/tools/TextStats'), | ||||
|                 keywords: ['word', 'count', 'size', 'bytes', 'length'] | ||||
|             }, | ||||
|             { | ||||
|                 icon: 'fab fa-markdown', | ||||
|                 text: 'Markdown editor', | ||||
|                 path: '/markdown-editor', | ||||
|                 component: () => import('./routes/tools/MarkdownEditor'), | ||||
|                 keywords: ['text', 'html', 'markdown'] | ||||
|             }, | ||||
|             { | ||||
|                 icon: 'fa-align-justify', | ||||
|                 text: 'Lorem ipsum generator', | ||||
|                 path: '/lorem-ipsum-generator', | ||||
|                 component: () => import('./routes/tools/LoremIpsumGenerator'), | ||||
|                 keywords: ['text', 'dolor', 'sit', 'placeholder', 'fill', 'dummy'] | ||||
|             } | ||||
|         ], | ||||
|     }, | ||||
|     { | ||||
|         title: 'Memos', | ||||
|         child: [ | ||||
|             { | ||||
|                 text: 'Git memo', | ||||
|                 path: '/git-memo', | ||||
|                 icon: 'fa-code-branch', | ||||
|                 component: () => import('./routes/tools/GitMemo'), | ||||
|                 keywords: ['git', 'push', 'rebase', 'merge', 'tag', 'commit', 'checkout'] | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         title: 'Miscellaneous', | ||||
|         child: [ | ||||
|             { | ||||
|                 text: 'QR Code generator', | ||||
|                 path: '/qrcode-generator', | ||||
|                 icon: 'fa-qrcode', | ||||
|                 component: () => import('./routes/tools/QRCodeGenerator'), | ||||
|                 keywords: [] | ||||
|             } | ||||
|         ] | ||||
|                 icon: 'fa-align-left\n', | ||||
|                 text: 'Text stats', | ||||
|                 path: '/text-stats', | ||||
|                 component: TextStats, | ||||
|                 keywords: ['word', 'count', 'size', 'bytes', 'length'] | ||||
|             }, | ||||
|         ], | ||||
|     } | ||||
| ]; | ||||
|  | ||||
| @@ -158,7 +131,6 @@ const routes = [ | ||||
|  | ||||
| const router = new VueRouter({ | ||||
|     base: process.env.BASE_URL, | ||||
|     mode: 'history', | ||||
|     routes | ||||
| }); | ||||
|  | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
|             </v-col> | ||||
|  | ||||
|         </v-row> | ||||
|         <v-row justify="center"> | ||||
|         <v-row justify="center" > | ||||
|             <v-col cols="12" md="5" sm="12"> | ||||
|                 <v-card> | ||||
|                     <v-card-title>Contributors</v-card-title> | ||||
| @@ -22,7 +22,12 @@ | ||||
|                 <v-card> | ||||
|                     <v-card-title>Changelog</v-card-title> | ||||
|                     <v-card-text> | ||||
|                         <div v-html="changelog" class="changelog"> | ||||
|                         <div v-for="(section, i) in changelog" :key="i"> | ||||
|                             <h2>{{section.title}}</h2> | ||||
|                             <ul> | ||||
|                                 <li v-for="(log, i) in section.logs" :key="i"> {{log}}</li> | ||||
|                             </ul> | ||||
|                             <br> | ||||
|                         </div> | ||||
|                     </v-card-text> | ||||
|                 </v-card> | ||||
| @@ -34,8 +39,6 @@ | ||||
|     import Abstract from "../components/Abstract"; | ||||
|     import GithubContributors from "../components/GithubContributors"; | ||||
|     import changelog from "../../CHANGELOG.md" | ||||
|     import marked from 'marked' | ||||
|     import DOMPurify from 'dompurify'; | ||||
|  | ||||
|     export default { | ||||
|         name: "About", | ||||
| @@ -43,7 +46,24 @@ | ||||
|             changelog: [] | ||||
|         }), | ||||
|         mounted() { | ||||
|             this.changelog = DOMPurify.sanitize(marked('##' + changelog.replace(/^(.*?)##/s, ''))); | ||||
|  | ||||
|             this.changelog = ('##' + changelog.replace(/^(.*?)##/s, '')) | ||||
|                 .split('\n') | ||||
|                 .filter(v => v !== '') | ||||
|                 .reduce((sections, v) => { | ||||
|                     v = v.trim(); | ||||
|                     if(v.startsWith('##')){ | ||||
|                         sections.push({ | ||||
|                             title: v.replace(/^##/, '').trim(), | ||||
|                             logs: [] | ||||
|                         }) | ||||
|                     }else { | ||||
|                         sections.slice(-1)[0].logs.push(v.replace(/^-/, '').trim()) | ||||
|                     } | ||||
|  | ||||
|                     return sections | ||||
|                 }, []); | ||||
|             console.log(this.changelog); | ||||
|         }, | ||||
|         components: { | ||||
|             Abstract, | ||||
| @@ -51,13 +71,3 @@ | ||||
|         }, | ||||
|     } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="less"> | ||||
|     ::v-deep { | ||||
|         .changelog { | ||||
|             h2 { | ||||
|                 margin-top: 10px; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| </style> | ||||
| @@ -9,7 +9,9 @@ | ||||
|                     </v-card-text> | ||||
|                 </v-card> | ||||
|             </v-col> | ||||
|             <v-col cols="12" lg="5" md="12"> | ||||
|         </v-row> | ||||
|         <v-row justify="center" align="center"> | ||||
|             <v-col cols="12" lg="8" md="12"> | ||||
|                 <v-card class="card-auto"> | ||||
|                     <v-card-text> | ||||
|                         <div class="card-wrapper "> | ||||
| @@ -54,7 +56,7 @@ | ||||
|         flex-wrap: wrap; | ||||
|  | ||||
|         div { | ||||
|             flex: 0 1 33%; | ||||
|             flex: 0 1 20%; | ||||
|  | ||||
|             @media only screen and (max-width: 800px) { | ||||
|                 flex: 0 1 33%; | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
|                             label="Input base" | ||||
|                             outlined | ||||
|                             type="number" | ||||
|                             v-model.number="inputBase" | ||||
|                             v-model="inputBase" | ||||
|                             ref="inputBase" | ||||
|                             hide-details="auto" | ||||
|                             :rules="baseRules" | ||||
| @@ -33,7 +33,7 @@ | ||||
|                             label="Output base" | ||||
|                             outlined | ||||
|                             type="number" | ||||
|                             v-model.number="outputBase" | ||||
|                             v-model="outputBase" | ||||
|                             ref="outputBase" | ||||
|                             :rules="baseRules" | ||||
|                     /> | ||||
|   | ||||
| @@ -1,154 +0,0 @@ | ||||
| <template> | ||||
|     <v-row> | ||||
|         <v-col cols="12" xl="12"> | ||||
|             <v-card> | ||||
|                 <v-card-title>Git Memo</v-card-title> | ||||
|                 <v-card-text> | ||||
|                     <MemoViewer :memo="tips"/> | ||||
|                 </v-card-text> | ||||
|             </v-card> | ||||
|         </v-col> | ||||
|     </v-row> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|     import MemoViewer from "../../components/MemoViewer"; | ||||
|  | ||||
|     export default { | ||||
|         name: "GitMemo", | ||||
|         data: () => ({ | ||||
|             tips: [ | ||||
|                 { | ||||
|                     section: 'Get started', | ||||
|                     child: [ | ||||
|                         { | ||||
|                             text: 'Create a git repo', | ||||
|                             code: 'git init' | ||||
|                         }, | ||||
|                         { | ||||
|                             text: 'Clone an existing repository', | ||||
|                             code: 'git clone [repo url]' | ||||
|                         }, | ||||
|                         { | ||||
|                             text: 'Add current files to next commit', | ||||
|                             code: 'git add .' | ||||
|                         }, | ||||
|                         { | ||||
|                             text: 'Commit tracked files changes', | ||||
|                             code: 'git commit -am "[commit message]"' | ||||
|                         }, | ||||
|                         { | ||||
|                             text: 'List files that has changed', | ||||
|                             code: 'git status' | ||||
|                         }, | ||||
|                         { | ||||
|                             text: 'List changes in tracked files', | ||||
|                             code: 'git diff' | ||||
|                         } | ||||
|                     ] | ||||
|                 }, | ||||
|                 { | ||||
|                     section: 'Basic configuration', | ||||
|                     child: [ | ||||
|                         { | ||||
|                             text: 'Set the name that will be associated to every operation', | ||||
|                             code: 'git config --global user.name "[nom]"' | ||||
|                         }, | ||||
|                         { | ||||
|                             text: 'Set the email address that will be associated to every operation', | ||||
|                             code: 'git config --global user.email "[email]"' | ||||
|                         }, | ||||
|                         { | ||||
|                             text: 'Tell git to always push tags', | ||||
|                             code: 'git config --global push.followTags true' | ||||
|                         } | ||||
|                     ] | ||||
|                 }, | ||||
|                 { | ||||
|                     section: 'I\'ve made a mistake', | ||||
|                     child: [ | ||||
|                         { | ||||
|                             text: 'Change last commit message', | ||||
|                             code: 'git commit --amend' | ||||
|                         }, | ||||
|                         { | ||||
|                             text: 'Undo most recent commit and keep changes', | ||||
|                             code: 'git reset HEAD~1' | ||||
|                         }, | ||||
|                         { | ||||
|                             text: 'Undo most recent commit and get rid of changes', | ||||
|                             code: 'git reset HEAD~1 --hard' | ||||
|                         }, | ||||
|                         { | ||||
|                             text: 'Reset branch to remote state', | ||||
|                             code: 'git fetch origin\ngit reset --hard origin/[branch-name]' | ||||
|                         } | ||||
|                     ] | ||||
|                 }, | ||||
|                 { | ||||
|                     section: 'Setup SSH', | ||||
|                     child: [ | ||||
|                         [ | ||||
|                             { | ||||
|                                 text: '1). Generate an SSH key.', | ||||
|                                 code: 'ssh-keygen -t rsa -b 4096 -C "[email]"' | ||||
|                             }, | ||||
|                             { | ||||
|                                 text: '2). Start the ssh-agent in the background.', | ||||
|                                 code: 'eval "$(ssh-agent -s)"' | ||||
|                             }, | ||||
|                             { | ||||
|                                 text: '3). Add your SSH private key to the ssh-agent.', | ||||
|                                 code: 'ssh-add ~/.ssh/id_rsa' | ||||
|                             }, | ||||
|                             { | ||||
|                                 text: '4). Add your SSH public key to your git server (for github: Settings -> SSH and GPG keys)', | ||||
|                                 code: 'cat ~/.ssh/id_rsa.pub' | ||||
|                             }, | ||||
|                             { | ||||
|                                 text: '5). (Optional) Testing your SSH connection', | ||||
|                                 code: 'ssh -T git@github.com' | ||||
|                             }, | ||||
|  | ||||
|                         ] | ||||
|                     ] | ||||
|                 }, | ||||
|                 { | ||||
|                     section: 'Merge and rebase', | ||||
|                     child: [ | ||||
|                         { | ||||
|                             text: 'Merge a branch into the current', | ||||
|                             code: 'git merge [branch]' | ||||
|                         }, | ||||
|                         { | ||||
|                             text: 'Abort merge (conflicts)', | ||||
|                             code: 'git merge --abort' | ||||
|                         }, | ||||
|                         { | ||||
|                             text: 'Continue merge after resolving conflicts', | ||||
|                             code: 'git merge --continue' | ||||
|                         }, | ||||
|                         { | ||||
|                             text: 'Rebase a branch into the current', | ||||
|                             code: 'git rebase [branch]' | ||||
|                         }, | ||||
|                         { | ||||
|                             text: 'Rebase merge (conflicts)', | ||||
|                             code: 'git merge --abort' | ||||
|                         }, | ||||
|                         { | ||||
|                             text: 'Continue rebase after resolving conflicts', | ||||
|                             code: 'git merge --continue' | ||||
|                         }, | ||||
|                     ] | ||||
|                 }, | ||||
|             ] | ||||
|         }), | ||||
|         components: { | ||||
|             MemoViewer | ||||
|         } | ||||
|     } | ||||
| </script> | ||||
|  | ||||
| <style lang="less" scoped> | ||||
| </style> | ||||
| @@ -1,94 +0,0 @@ | ||||
| <template> | ||||
|     <v-row justify="center" align="center" class="lorem-ipsum-generator"> | ||||
|         <v-col cols="12" xl="5" lg="6" md="12"> | ||||
|             <v-card> | ||||
|                 <v-card-title>Lorem ipsum generator</v-card-title> | ||||
|                 <v-card-text> | ||||
|                     <v-slider v-model="paragraphs" min="1" max="20" label="Paragraphs" thumb-label/> | ||||
|                     <v-range-slider v-model="sentencePerParagraph" min="1" max="50" label="Sentences per paragraph" | ||||
|                                     thumb-label/> | ||||
|                     <v-range-slider v-model="wordPerSentence" min="1" max="50" label="Words per sentence" thumb-label hide-details/> | ||||
|                     <v-checkbox v-model="startWithLoremIpsum" label="Start with 'Lorem ipsum ...'" hide-details/> | ||||
|                     <v-checkbox v-model="asHTML" label="As HTML" hide-details/> | ||||
|                 </v-card-text> | ||||
|             </v-card> | ||||
|         </v-col> | ||||
|         <v-col cols="12" xl="5" lg="6" md="12"> | ||||
|             <v-card> | ||||
|                 <v-card-text> | ||||
|                     <v-textarea outlined readonly hide-details="auto" v-model="loremIpsum" rows="15" | ||||
|                                 class="text-justify"></v-textarea> | ||||
|                     <div class="text-center mt-4"> | ||||
|                         <v-btn depressed @click="copy()">Copy</v-btn> | ||||
|                     </div> | ||||
|                 </v-card-text> | ||||
|             </v-card> | ||||
|         </v-col> | ||||
|     </v-row> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|     import {copyToClipboard, randFromArray, randIntFromInterval} from "../../utils/helpers"; | ||||
|  | ||||
|     const vocabulary = ['a', 'ac', 'accumsan', 'ad', 'adipiscing', 'aenean', 'aliquam', 'aliquet', 'amet', 'ante', 'aptent', 'arcu', 'at', 'auctor', 'bibendum', 'blandit', 'class', 'commodo', 'condimentum', 'congue', 'consectetur', 'consequat', 'conubia', 'convallis', 'cras', 'cubilia', 'cum', 'curabitur', 'curae', 'dapibus', 'diam', 'dictum', 'dictumst', 'dignissim', 'dolor', 'donec', 'dui', 'duis', 'egestas', 'eget', 'eleifend', 'elementum', 'elit', 'enim', 'erat', 'eros', 'est', 'et', 'etiam', 'eu', 'euismod', 'facilisi', 'faucibus', 'felis', 'fermentum', 'feugiat', 'fringilla', 'fusce', 'gravida', 'habitant', 'habitasse', 'hac', 'hendrerit', 'himenaeos', 'iaculis', 'id', 'imperdiet', 'in', 'inceptos', 'integer', 'interdum', 'ipsum', 'justo', 'lacinia', 'lacus', 'laoreet', 'lectus', 'leo', 'ligula', 'litora', 'lobortis', 'lorem', 'luctus', 'maecenas', 'magna', 'magnis', 'malesuada', 'massa', 'mattis', 'mauris', 'metus', 'mi', 'molestie', 'mollis', 'montes', 'morbi', 'mus', 'nam', 'nascetur', 'natoque', 'nec', 'neque', 'netus', 'nisi', 'nisl', 'non', 'nostra', 'nulla', 'nullam', 'nunc', 'odio', 'orci', 'ornare', 'parturient', 'pellentesque', 'penatibus', 'per', 'pharetra', 'phasellus', 'placerat', 'platea', 'porta', 'porttitor', 'posuere', 'potenti', 'praesent', 'pretium', 'primis', 'proin', 'pulvinar', 'purus', 'quam', 'quis', 'quisque', 'rhoncus', 'ridiculus', 'risus', 'rutrum', 'sagittis', 'sapien', 'scelerisque', 'sed', 'sem', 'semper', 'senectus', 'sit', 'sociis', 'sociosqu', 'sodales', 'sollicitudin', 'suscipit', 'suspendisse', 'taciti', 'tellus', 'tempor', 'tempus', 'tincidunt', 'torquent', 'tortor', 'turpis', 'ullamcorper', 'ultrices', 'ultricies', 'urna', 'varius', 'vehicula', 'vel', 'velit', 'venenatis', 'vestibulum', 'vitae', 'vivamus', 'viverra', 'volutpat', 'vulputate']; | ||||
|     const firstSentence = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'; | ||||
|  | ||||
|     const generateSentence = (length) => { | ||||
|         let sentence = Array.from({length}).map(() => randFromArray(vocabulary)).join(' ') | ||||
|         sentence = sentence.charAt(0).toUpperCase() + sentence.slice(1) + '.' | ||||
|         return sentence | ||||
|     } | ||||
|  | ||||
|  | ||||
|     export default { | ||||
|         name: "LoremIpsumGenerator", | ||||
|         data: () => ({ | ||||
|             paragraphs: 1, | ||||
|             sentencePerParagraph: [3, 8], | ||||
|             wordPerSentence: [8, 15], | ||||
|             startWithLoremIpsum: true, | ||||
|             asHTML: false | ||||
|         }), | ||||
|         methods:{ | ||||
|             copy(){ | ||||
|                 copyToClipboard(this.loremIpsum) | ||||
|                 this.$toast.success('Copied to clipboard.') | ||||
|             } | ||||
|         }, | ||||
|         computed: { | ||||
|             loremIpsum: function () { | ||||
|                 const lorem = Array | ||||
|                     .from({length: this.paragraphs}) | ||||
|                     .map(() => { | ||||
|                         const length = randIntFromInterval(...this.sentencePerParagraph); | ||||
|  | ||||
|                         return Array.from({length}).map(() => { | ||||
|                             const wordCount = randIntFromInterval(...this.wordPerSentence); | ||||
|                             return generateSentence(wordCount); | ||||
|                         }) | ||||
|                     }); | ||||
|  | ||||
|                 if (this.startWithLoremIpsum) { | ||||
|                     lorem[0][0] = firstSentence | ||||
|                 } | ||||
|  | ||||
|                 let result; | ||||
|                 if(this.asHTML){ | ||||
|                     result = `<p>${lorem.map(s => s.join(' ')).join('</p>\n\n<p>')}</p>` | ||||
|                 }else{ | ||||
|                     result = lorem.map(s => s.join(' ')).join('\n\n') | ||||
|                 } | ||||
|  | ||||
|                 return result; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="less"> | ||||
|     ::v-deep { | ||||
|         .v-label{ | ||||
|             min-width: 200px !important; | ||||
|         } | ||||
|     } | ||||
| </style> | ||||
| @@ -1,71 +0,0 @@ | ||||
| <template> | ||||
|     <v-row justify="center" align="center"> | ||||
|         <v-col cols="12" xl="5" lg="6" md="12"> | ||||
|             <v-card> | ||||
|                 <v-card-text> | ||||
|                     <v-textarea v-model="markdown" auto-grow outlined label="Markdown editor"/> | ||||
|                     <div class="text-center"> | ||||
|                         <v-btn @click="copy(markdown)">copy markdown</v-btn> | ||||
|                     </div> | ||||
|                 </v-card-text> | ||||
|             </v-card> | ||||
|         </v-col> | ||||
|         <v-col cols="12" xl="5" lg="6" md="12"> | ||||
|             <v-card> | ||||
|                 <v-card-text > | ||||
|                     <div class="preview" v-html="html"></div> | ||||
|                     <div class="text-center"> | ||||
|                         <v-divider /> | ||||
|                         <br> | ||||
|                         <v-btn @click="copy(html)">copy html</v-btn> | ||||
|                     </div> | ||||
|                 </v-card-text> | ||||
|             </v-card> | ||||
|         </v-col> | ||||
|     </v-row> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|     // import {debounce} from "../../utils/helpers"; | ||||
|     import marked from 'marked' | ||||
|     import DOMPurify from 'dompurify'; | ||||
|     import {copyToClipboard} from "../../utils/helpers"; | ||||
|  | ||||
|     export default { | ||||
|         name: "MarkdownEditor", | ||||
|         data: () => ({ | ||||
|             markdown: '# Hello, World!\nLorem ipsum **dolor** sit *amet*, consectetur adipisicing elit. A aspernatur commodi consequuntur distinctio dolore doloribus eaque earum est ipsum nobis numquam pariatur perspiciatis quasi quis, sed, sunt tempore tenetur, veniam!\n', | ||||
|         }), | ||||
|         methods: { | ||||
|             copy(text){ | ||||
|                 copyToClipboard(text) | ||||
|                 this.$toast.success('Copied to clipboard.') | ||||
|             } | ||||
|         }, | ||||
|         computed: { | ||||
|             html() { | ||||
|                 return DOMPurify.sanitize(marked(this.markdown)) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="less"> | ||||
|     ::v-deep { | ||||
|         .preview { | ||||
|             padding: 20px; | ||||
|  | ||||
|             h1{ | ||||
|                 margin-bottom: 15px; | ||||
|             } | ||||
|             pre { | ||||
|                 width: 100%; | ||||
|  | ||||
|                 code { | ||||
|                     width: 100% !important; | ||||
|                     padding: 10px; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| </style> | ||||
| @@ -1,137 +0,0 @@ | ||||
| <template> | ||||
|     <v-card class="single-card"> | ||||
|         <v-card-title>QR-code generator</v-card-title> | ||||
|         <v-card-text> | ||||
|             <v-row justify="center" align="center"> | ||||
|                 <v-col cols="12" lg="6" sm="12"> | ||||
|                     <v-text-field | ||||
|                             outlined | ||||
|                             v-model="value" | ||||
|                             label="Data" | ||||
|                             :rules="rules.value" | ||||
|                     /> | ||||
|                     <v-slider v-model="size" min="100" max="1920" label="Size (preview will not change): " thumb-label/> | ||||
|                     <v-select | ||||
|                             outlined | ||||
|                             v-model="level" | ||||
|                             :items="levels" | ||||
|                             label="Error resistance" | ||||
|                     /> | ||||
|                     <v-row> | ||||
|                         <v-col cols="12" md="6" sm="12"> | ||||
|                             <ColorInput v-model="fgcolor" label="Foreground color"/> | ||||
|                         </v-col> | ||||
|                         <v-col cols="12" md="6" sm="12"> | ||||
|                             <ColorInput v-model="bgcolor" label="Background color"/> | ||||
|                         </v-col> | ||||
|                     </v-row> | ||||
|  | ||||
|                 </v-col> | ||||
|  | ||||
|                 <v-col cols="12" lg="6" sm="12" class="text-center"> | ||||
|                     <qrcode-vue | ||||
|                             :value="input" | ||||
|                             :size="size" | ||||
|                             :level="level" | ||||
|                             :background="bgcolor" | ||||
|                             :foreground="fgcolor" | ||||
|                             render-as="svg" | ||||
|                             class-name="qrcode-wrapper" | ||||
|                     /> | ||||
|                 </v-col> | ||||
|             </v-row> | ||||
|  | ||||
|             <div class="text-center mt-3 mb-sm-2"> | ||||
|                 <v-btn @click="download('png')" class="mr-1" color="primary">download as png</v-btn> | ||||
|                 <v-btn @click="download('svg')" class="ml-1" color="primary">download as svg</v-btn> | ||||
|             </div> | ||||
|         </v-card-text> | ||||
|     </v-card> | ||||
|  | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|     import QrcodeVue from 'qrcode.vue' | ||||
|     import colors from "color-name"; | ||||
|     import ColorInput from "../../components/ColorInput"; | ||||
|     import {downloadBase64File} from "../../utils/helpers"; | ||||
|  | ||||
|     export default { | ||||
|         name: "QRCodeGenerator", | ||||
|         data: () => ({ | ||||
|             value: 'https://it-tools.tech', | ||||
|             size: 300, | ||||
|             level: 'M', | ||||
|             bgcolor: '#ffffff', | ||||
|             fgcolor: '#000000', | ||||
|             levels: [ | ||||
|                 {text: 'Low', value: 'L'}, | ||||
|                 {text: 'Medium', value: 'M'}, | ||||
|                 {text: 'Quartile', value: 'Q'}, | ||||
|                 {text: 'High', value: 'H'} | ||||
|             ], | ||||
|             rules: { | ||||
|                 value: [ | ||||
|                     v => v.length > 0 || 'Value is needed' | ||||
|                 ], | ||||
|                 color: [ | ||||
|                     v => { | ||||
|                         v = v.trim() | ||||
|                         const isFFFFFF = /^#(?:[0-9a-fA-F]{6})$/.test(v); | ||||
|                         const isFFF = /^#(?:[0-9a-fA-F]{3})$/.test(v); | ||||
|                         const isRGB = /^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/.test(v); | ||||
|                         const isHSL = /^hsl\((\d+),\s*(\d+)%,\s*(\d+)%\)$/.test(v); | ||||
|                         const isKeyword = v in colors; | ||||
|                         const isTransparent = v === 'transparent'; | ||||
|  | ||||
|                         return isFFFFFF || isFFF || isKeyword || isTransparent || isRGB || isHSL || 'Incorrect color.' | ||||
|                     } | ||||
|                 ] | ||||
|             } | ||||
|         }), | ||||
|         methods: { | ||||
|             download(type) { | ||||
|                 const svgEl = this.$el.querySelector('.qrcode-wrapper svg'); | ||||
|                 const svgString = new XMLSerializer().serializeToString(svgEl); | ||||
|                 const svgUrl = `data:image/svg+xml;base64,${btoa(svgString)}`; | ||||
|  | ||||
|                 if (type === 'png') { | ||||
|                     const canvas = document.createElement("canvas"); | ||||
|                     canvas.width = this.size; | ||||
|                     canvas.height = this.size; | ||||
|                     const ctx = canvas.getContext("2d"); | ||||
|  | ||||
|                     const image = new Image(); | ||||
|                     image.onload = function () { | ||||
|                         ctx.drawImage(image, 0, 0); | ||||
|                         const result = canvas.toDataURL(); | ||||
|  | ||||
|                         downloadBase64File(result, 'qr-code'); | ||||
|                     }; | ||||
|                     image.src = svgUrl; | ||||
|                 } else { | ||||
|                     downloadBase64File(svgUrl, 'qr-code'); | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         computed: { | ||||
|             input() { | ||||
|                 return this.value | ||||
|  | ||||
|             } | ||||
|         }, | ||||
|         components: { | ||||
|             QrcodeVue, | ||||
|             ColorInput | ||||
|         } | ||||
|     } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="less"> | ||||
|     ::v-deep .qrcode-wrapper { | ||||
|         & > * { | ||||
|             width: 300px !important; | ||||
|             height: 300px !important; | ||||
|         } | ||||
|     } | ||||
| </style> | ||||
| @@ -3,18 +3,8 @@ | ||||
|         <v-card-title>Uuid v4 generator</v-card-title> | ||||
|  | ||||
|         <v-card-text> | ||||
|             <v-text-field | ||||
|                     outlined | ||||
|                     v-model.number="quantity" | ||||
|                     ref="quantity" | ||||
|                     type="number" | ||||
|                     label="Quantity" | ||||
|                     dense | ||||
|                     class="quantity" | ||||
|                     :rules="rules.quantity" | ||||
|             /> | ||||
|             <v-textarea outlined v-model="token" class="centered-input" :rows="quantity <= 10 ? quantity : 10" | ||||
|                         readonly/> | ||||
|             <v-text-field outlined v-model="quantity" type="number" label="Quantity" dense class="quantity"/> | ||||
|             <v-textarea outlined v-model="token" class="centered-input" :rows="quantity <= 10 ? quantity : 10" readonly/> | ||||
|  | ||||
|             <div class="text-center"> | ||||
|                 <v-btn @click="refreshBool = !refreshBool" depressed class="mr-4">Refresh</v-btn> | ||||
| @@ -25,7 +15,7 @@ | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|     import {copyToClipboard, isInt} from "../../utils/helpers"; | ||||
|     import {copyToClipboard} from "../../utils/helpers"; | ||||
|  | ||||
|     const noop = () => { | ||||
|     }; | ||||
| @@ -36,19 +26,8 @@ | ||||
|         name: "UuidGenerator", | ||||
|         data: () => ({ | ||||
|             refreshBool: true, | ||||
|             quantity: 1, | ||||
|             rules: { | ||||
|                 quantity: [ | ||||
|                     v => !!v || 'Quantity is required', | ||||
|                     v => (v > 0 && v <= 50 ) || 'Quantity should be > 0 and <= 50', | ||||
|                     v => isInt(v) || 'Quantity should be an integer' | ||||
|                 ] | ||||
|             }, | ||||
|             isMounted:false | ||||
|             quantity: 1 | ||||
|         }), | ||||
|         mounted() { | ||||
|             this.isMounted = true; | ||||
|         }, | ||||
|         methods: { | ||||
|             copyToken() { | ||||
|                 copyToClipboard(this.token); | ||||
| @@ -57,25 +36,21 @@ | ||||
|         }, | ||||
|         computed: { | ||||
|             token() { | ||||
|                 if (this.isMounted && this.$refs.quantity.validate()) { | ||||
|                     if (this.refreshBool) noop(); // To force recomputation | ||||
|                 if (this.refreshBool) noop(); // To force recomputation | ||||
|  | ||||
|                     return Array.from({length: this.quantity}, generateUuid).join('\n'); | ||||
|                 } else { | ||||
|                     return ''; | ||||
|                 } | ||||
|                 return Array.from({length: this.quantity}, generateUuid).join('\n'); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="less"> | ||||
|     .quantity { | ||||
|     .quantity{ | ||||
|         width: 100px; | ||||
|         margin: auto; | ||||
|         text-align: center; | ||||
|  | ||||
|         ::v-deep input { | ||||
|         ::v-deep input{ | ||||
|             text-align: center; | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -25,36 +25,12 @@ const formatBytes = (bytes, decimals = 2) => { | ||||
| } | ||||
|  | ||||
| const isInt = (value) => { | ||||
|     return Number.isInteger(value); | ||||
| } | ||||
|  | ||||
| const debounce = (callback, delay = 300) => { | ||||
|     let timer; | ||||
|  | ||||
|     return function(...args) { | ||||
|         clearTimeout(timer); | ||||
|         timer = setTimeout(() => callback(...args), delay); | ||||
|     } | ||||
| } | ||||
|  | ||||
| const randFromArray = (array) => array[Math.floor(Math.random() * array.length)]; | ||||
|  | ||||
| const randIntFromInterval = (min, max) => Math.floor(Math.random() * (max - min) + min) | ||||
|  | ||||
| const downloadBase64File = (dataUrl, name = 'file') => { | ||||
|     const a = document.createElement("a"); | ||||
|     a.href = dataUrl; | ||||
|     a.download = name; | ||||
|     a.click(); | ||||
|     return !isNaN(value) && ((x) => (x | 0) === x)(parseFloat(value)) | ||||
| } | ||||
|  | ||||
| export { | ||||
|     copyToClipboard, | ||||
|     fileIsImage, | ||||
|     formatBytes, | ||||
|     isInt, | ||||
|     debounce, | ||||
|     randFromArray, | ||||
|     randIntFromInterval, | ||||
|     downloadBase64File | ||||
|     isInt | ||||
| } | ||||
| @@ -1,7 +0,0 @@ | ||||
| { | ||||
|   "version": 2, | ||||
|   "routes": [ | ||||
|     { "handle": "filesystem" }, | ||||
|     { "src": "/.*", "dest": "/index.html" } | ||||
|   ] | ||||
| } | ||||
| @@ -19,11 +19,5 @@ module.exports = { | ||||
|         }) | ||||
|       ] | ||||
|     } | ||||
|   }, | ||||
|   pwa: { | ||||
|     workboxOptions: { | ||||
|       skipWaiting: true, | ||||
|       clientsClaim: true, | ||||
|     } | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user