mirror of
				https://github.com/CorentinTh/it-tools.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	Compare commits
	
		
			5 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					85ef199145 | ||
| 
						 | 
					908994acea | ||
| 
						 | 
					e7c589a033 | ||
| 
						 | 
					625b43e436 | ||
| 
						 | 
					a970df5c02 | 
							
								
								
									
										30
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -3,36 +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.6.0
 | 
			
		||||
- [feat] [BIP39 generator](https://it-tools.tech/bip39-generator)
 | 
			
		||||
- [feat] [Base 64 converter](https://it-tools.tech/base64-string-converter)
 | 
			
		||||
 | 
			
		||||
## 1.5.2
 | 
			
		||||
- [feat] [humans.txt](https://it-tools.tech/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](https://it-tools.tech/qrcode-generator)
 | 
			
		||||
 | 
			
		||||
## 1.4.0
 | 
			
		||||
- [ui] condensed + colored sidenav
 | 
			
		||||
- [feat] added [git memo](https://it-tools.tech/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](https://it-tools.tech/markdown-editor)
 | 
			
		||||
- [feat] added [lorem ipsum generator](https://it-tools.tech/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 
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										41
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								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,23 +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
 | 
			
		||||
- [x] Bip39 pass-phrase generator
 | 
			
		||||
- [ ] Base 64 string converter
 | 
			
		||||
- [ ] 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!
 | 
			
		||||
 | 
			
		||||
@@ -54,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).
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										68
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										68
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "it-tools",
 | 
			
		||||
  "version": "1.6.0",
 | 
			
		||||
  "version": "1.2.0",
 | 
			
		||||
  "lockfileVersion": 1,
 | 
			
		||||
  "requires": true,
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
@@ -2483,24 +2483,6 @@
 | 
			
		||||
        "file-uri-to-path": "1.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "bip39": {
 | 
			
		||||
      "version": "3.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.2.tgz",
 | 
			
		||||
      "integrity": "sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ==",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "@types/node": "11.11.6",
 | 
			
		||||
        "create-hash": "^1.1.0",
 | 
			
		||||
        "pbkdf2": "^3.0.9",
 | 
			
		||||
        "randombytes": "^2.0.1"
 | 
			
		||||
      },
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@types/node": {
 | 
			
		||||
          "version": "11.11.6",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz",
 | 
			
		||||
          "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ=="
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "bluebird": {
 | 
			
		||||
      "version": "3.7.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
 | 
			
		||||
@@ -3041,6 +3023,7 @@
 | 
			
		||||
      "version": "1.0.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
 | 
			
		||||
      "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "inherits": "^2.0.1",
 | 
			
		||||
        "safe-buffer": "^5.0.1"
 | 
			
		||||
@@ -3156,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",
 | 
			
		||||
@@ -3699,6 +3676,7 @@
 | 
			
		||||
      "version": "1.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "cipher-base": "^1.0.1",
 | 
			
		||||
        "inherits": "^2.0.1",
 | 
			
		||||
@@ -3711,6 +3689,7 @@
 | 
			
		||||
      "version": "1.1.7",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
 | 
			
		||||
      "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "cipher-base": "^1.0.3",
 | 
			
		||||
        "create-hash": "^1.1.0",
 | 
			
		||||
@@ -4394,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",
 | 
			
		||||
@@ -6240,6 +6214,7 @@
 | 
			
		||||
      "version": "3.0.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz",
 | 
			
		||||
      "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "inherits": "^2.0.1",
 | 
			
		||||
        "safe-buffer": "^5.0.1"
 | 
			
		||||
@@ -6278,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",
 | 
			
		||||
@@ -6647,7 +6628,8 @@
 | 
			
		||||
    "inherits": {
 | 
			
		||||
      "version": "2.0.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
 | 
			
		||||
      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
 | 
			
		||||
      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "inquirer": {
 | 
			
		||||
      "version": "7.1.0",
 | 
			
		||||
@@ -7931,9 +7913,9 @@
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "lodash": {
 | 
			
		||||
      "version": "4.17.19",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
 | 
			
		||||
      "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
 | 
			
		||||
      "version": "4.17.15",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
 | 
			
		||||
      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "lodash._reinterpolate": {
 | 
			
		||||
@@ -8121,15 +8103,11 @@
 | 
			
		||||
        "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",
 | 
			
		||||
      "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "hash-base": "^3.0.0",
 | 
			
		||||
        "inherits": "^2.0.1",
 | 
			
		||||
@@ -9106,6 +9084,7 @@
 | 
			
		||||
      "version": "3.0.17",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz",
 | 
			
		||||
      "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "create-hash": "^1.1.2",
 | 
			
		||||
        "create-hmac": "^1.1.4",
 | 
			
		||||
@@ -10001,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",
 | 
			
		||||
@@ -10044,6 +10018,7 @@
 | 
			
		||||
      "version": "2.1.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
 | 
			
		||||
      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "safe-buffer": "^5.1.0"
 | 
			
		||||
      }
 | 
			
		||||
@@ -10476,6 +10451,7 @@
 | 
			
		||||
      "version": "2.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
 | 
			
		||||
      "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "hash-base": "^3.0.0",
 | 
			
		||||
        "inherits": "^2.0.1"
 | 
			
		||||
@@ -10522,7 +10498,8 @@
 | 
			
		||||
    "safe-buffer": {
 | 
			
		||||
      "version": "5.1.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
 | 
			
		||||
      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
 | 
			
		||||
      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "safe-regex": {
 | 
			
		||||
      "version": "1.1.0",
 | 
			
		||||
@@ -10783,6 +10760,7 @@
 | 
			
		||||
      "version": "2.4.11",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
 | 
			
		||||
      "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "inherits": "^2.0.1",
 | 
			
		||||
        "safe-buffer": "^5.0.1"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "it-tools",
 | 
			
		||||
  "description": "",
 | 
			
		||||
  "version": "1.6.0",
 | 
			
		||||
  "version": "1.2.0",
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "serve": "vue-cli-service serve",
 | 
			
		||||
@@ -10,13 +10,9 @@
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "axios": "^0.19.2",
 | 
			
		||||
    "bip39": "^3.0.2",
 | 
			
		||||
    "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>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										66
									
								
								src/App.vue
									
									
									
									
									
								
							
							
						
						
									
										66
									
								
								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'"
 | 
			
		||||
            :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,16 +46,9 @@ const toolsComponents = [
 | 
			
		||||
                icon: 'fa-lock',
 | 
			
		||||
                text: 'Cypher/uncypher text',
 | 
			
		||||
                path: '/cypher',
 | 
			
		||||
                component: () => import('./routes/tools/TextCypher'),
 | 
			
		||||
                component: TextCypher,
 | 
			
		||||
                keywords: ['aes', 'tripledes', 'rabbit', 'rabbitlegacy', 'rc4']
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                icon: 'fa-file-word',
 | 
			
		||||
                text: 'BIP39 passphrase generator',
 | 
			
		||||
                path: '/bip39-generator',
 | 
			
		||||
                component: () => import('./routes/tools/BIP39Generator'),
 | 
			
		||||
                keywords: []
 | 
			
		||||
            },
 | 
			
		||||
        ],
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
@@ -54,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']
 | 
			
		||||
            },
 | 
			
		||||
        ],
 | 
			
		||||
@@ -80,72 +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
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                icon: 'fa-file-alt',
 | 
			
		||||
                text: 'Base64 string converter',
 | 
			
		||||
                path: '/base64-string-converter',
 | 
			
		||||
                component: () => import('./routes/tools/StringToBase64')
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        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']
 | 
			
		||||
            },
 | 
			
		||||
        ],
 | 
			
		||||
    }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@@ -171,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%;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,99 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <v-card class="single-card">
 | 
			
		||||
        <v-card-title>BIP39 passphrase generator</v-card-title>
 | 
			
		||||
        <v-card-text>
 | 
			
		||||
            <v-select
 | 
			
		||||
                    outlined
 | 
			
		||||
                    label="Language"
 | 
			
		||||
                    @change="languageChanged"
 | 
			
		||||
                    :items="languageList"
 | 
			
		||||
                    v-model="language"
 | 
			
		||||
            />
 | 
			
		||||
            <v-text-field
 | 
			
		||||
                    outlined
 | 
			
		||||
                    v-model="entropy"
 | 
			
		||||
                    label="Entropy"
 | 
			
		||||
                    append-icon="fa-clipboard"
 | 
			
		||||
                    @click:append="copy(entropy)"
 | 
			
		||||
                    :rules="rules.entropy"
 | 
			
		||||
                    ref="entropy"
 | 
			
		||||
            />
 | 
			
		||||
            <v-text-field
 | 
			
		||||
                    outlined
 | 
			
		||||
                    v-model="passphrase"
 | 
			
		||||
                    label="Passphrase"
 | 
			
		||||
                    append-icon="fa-clipboard"
 | 
			
		||||
                    @click:append="copy(passphrase)"
 | 
			
		||||
                    :rules="rules.passphrase"
 | 
			
		||||
                    ref="passphrase"
 | 
			
		||||
            />
 | 
			
		||||
            <div class="text-center">
 | 
			
		||||
                <v-btn @click="refresh">refresh</v-btn>
 | 
			
		||||
            </div>
 | 
			
		||||
        </v-card-text>
 | 
			
		||||
    </v-card>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    import * as bip39 from "bip39";
 | 
			
		||||
    import {copyable} from "../../mixins/copyable.mixin";
 | 
			
		||||
 | 
			
		||||
    const shuffle = (str) => str.split('').sort(() => 0.5 - Math.random()).join('');
 | 
			
		||||
 | 
			
		||||
    const getRandomBuffer = () => {
 | 
			
		||||
        return Buffer.from(shuffle('0123456789abcdef'.repeat(16)).substring(0, 32), 'hex');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    export default {
 | 
			
		||||
        name: 'BIP39Generator',
 | 
			
		||||
        mixins: [copyable],
 | 
			
		||||
        data: () => ({
 | 
			
		||||
            buffer: getRandomBuffer(),
 | 
			
		||||
            languageList: Object.keys(bip39.wordlists).filter(k => !k.match(/[A-Z]{2}/)).map(k => ({text: k.split('_').map(k => k.charAt(0).toUpperCase() + k.slice(1)).join(' '), value:k})),
 | 
			
		||||
            language: 'english',
 | 
			
		||||
            rules: {
 | 
			
		||||
                passphrase: [
 | 
			
		||||
                    v => (!!v && bip39.validateMnemonic(v)) || 'Invalid mnemonic.'
 | 
			
		||||
                ],
 | 
			
		||||
                entropy: [
 | 
			
		||||
                    v => (!!v && !!v.match(/[0-9a-fA-F]{32}/)) || 'Invalid entropy.'
 | 
			
		||||
                ]
 | 
			
		||||
            }
 | 
			
		||||
        }),
 | 
			
		||||
        methods:{
 | 
			
		||||
            refresh(){
 | 
			
		||||
                this.buffer = getRandomBuffer();
 | 
			
		||||
            },
 | 
			
		||||
            languageChanged(){
 | 
			
		||||
                bip39.setDefaultWordlist(this.language);
 | 
			
		||||
                this.passphrase = bip39.entropyToMnemonic(this.buffer)
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        computed: {
 | 
			
		||||
            entropy: {
 | 
			
		||||
                get() {
 | 
			
		||||
                    return this.buffer.toString('hex')
 | 
			
		||||
                },
 | 
			
		||||
                set(value) {
 | 
			
		||||
                    if(this.$refs.entropy.validate()) {
 | 
			
		||||
                        this.buffer = Buffer.from(value, 'hex')
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            passphrase: {
 | 
			
		||||
                get() {
 | 
			
		||||
                    return bip39.entropyToMnemonic(this.buffer)
 | 
			
		||||
                },
 | 
			
		||||
                set(value) {
 | 
			
		||||
                    if(this.$refs.passphrase.validate()){
 | 
			
		||||
                        this.buffer = Buffer.from(bip39.mnemonicToEntropy(value), 'hex')
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
@@ -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>
 | 
			
		||||
@@ -1,66 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <v-card class="single-card">
 | 
			
		||||
        <v-card-title>Base64 string converter</v-card-title>
 | 
			
		||||
        <v-card-text>
 | 
			
		||||
            <v-textarea
 | 
			
		||||
                    outlined
 | 
			
		||||
                    v-model="clear"
 | 
			
		||||
                    label="Clear text"
 | 
			
		||||
            ></v-textarea>
 | 
			
		||||
 | 
			
		||||
            <v-textarea
 | 
			
		||||
                    outlined
 | 
			
		||||
                    v-model="base64"
 | 
			
		||||
                    label="Base64 text"
 | 
			
		||||
                    :rules="rules.base64"
 | 
			
		||||
                    ref="base64"
 | 
			
		||||
            ></v-textarea>
 | 
			
		||||
            <div class="text-center">
 | 
			
		||||
                <v-btn class="mr-1" depressed @click="copy(clear)">Copy clear</v-btn>
 | 
			
		||||
                <v-btn class="ml-1" depressed @click="copy(base64)">Copy base64</v-btn>
 | 
			
		||||
            </div>
 | 
			
		||||
        </v-card-text>
 | 
			
		||||
    </v-card>
 | 
			
		||||
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    import {copyable} from "../../mixins/copyable.mixin";
 | 
			
		||||
 | 
			
		||||
    export default {
 | 
			
		||||
        name: "StringToBase64",
 | 
			
		||||
        mixins: [copyable],
 | 
			
		||||
        data() {
 | 
			
		||||
            return {
 | 
			
		||||
                clear: 'Lorem ipsum dolor sit amet.',
 | 
			
		||||
                rules:{
 | 
			
		||||
                    base64: [
 | 
			
		||||
                        v => {
 | 
			
		||||
                            try{
 | 
			
		||||
                                return btoa(atob(v)) === v || 'Input is not base64.'
 | 
			
		||||
                            }catch (e) {
 | 
			
		||||
                                return 'Input is not base64.'
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        computed: {
 | 
			
		||||
            base64: {
 | 
			
		||||
                get(){
 | 
			
		||||
                    return btoa(this.clear)
 | 
			
		||||
                },
 | 
			
		||||
                set(value){
 | 
			
		||||
                    if(this.$refs.base64.validate()){
 | 
			
		||||
                        this.clear = atob(value)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
 | 
			
		||||
</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
 | 
			
		||||
 | 
			
		||||
                return Array.from({length: this.quantity}, generateUuid).join('\n');
 | 
			
		||||
                } else {
 | 
			
		||||
                    return '';
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</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