Compare commits

..

27 Commits

Author SHA1 Message Date
Corentin Thomasset
d591a73ce7 chore(release): 2.4.1 2022-05-15 11:34:19 +02:00
Corentin Thomasset
a88e4a9289 fix(seo): wrong url in share metas 2022-05-15 11:31:17 +02:00
Corentin Thomasset
d4ea393c1d refactor(seo): changed title string 2022-05-15 11:29:36 +02:00
Corentin Thomasset
048bc4ae94 refactor(json-viewer): add clear button 2022-05-14 16:29:50 +02:00
Corentin Thomasset
3aefe83a31 chore(release): 2.4.0 2022-05-14 12:48:43 +02:00
Corentin Thomasset
c3b6132c26 refactor(seo): changed title string 2022-05-14 12:45:33 +02:00
Corentin Thomasset
69f564e6fe chore: added pull request template 2022-05-11 17:37:39 +02:00
Evo Stamatov
e9cc499ed8 feat(hash-text): compute all hashes at the same time (#242)
* compute all hashes at the same time instead of using a select

* add prettier config

* Revert "add prettier config"

This reverts commit fd374ff6fd.

Prettier config is in `.eslintrc.cjs`. Should run the lint script or
should use ESLint's VS Code extension.

* fix: address requested changes

 - rename hashedText to hashText since it's a function and no longer a variable
 - rename to list to algoNames
 - rename to type to AlgoName

removed unused import

* revert back to allow empty value to be hashed; lint
2022-05-11 16:29:55 +02:00
Corentin Thomasset
383d975695 refactor(base-layout): renammed one letter variable 2022-05-11 15:09:48 +02:00
Corentin Thomasset
347144bfe8 chore(deps): npm audit fix 2022-05-11 14:39:51 +02:00
Corentin Thomasset
4c4da16970 docs: added producthunt banners 2022-05-11 14:35:45 +02:00
Corentin Thomasset
9450537bae chore: added eslint in recommended extensions 2022-05-11 14:14:29 +02:00
Evo Stamatov
1d7032d026 fix: update recommended extension ids (#244) 2022-05-11 14:08:39 +02:00
Evo Stamatov
d2c767f092 refactor(date-converter): mutualised and dry-ed code 2022-05-11 14:06:39 +02:00
Corentin Thomasset
0cc7af6b1d chore(ci): run ci on PR 2022-05-11 10:12:21 +02:00
Corentin Thomasset
34bc6a57a7 feat(seo): added cannonical meta 2022-05-10 09:12:11 +02:00
Corentin Thomasset
d356b1488f feat(new-tool): json viewer 2022-05-09 17:41:42 +02:00
Corentin Thomasset
a60f64f744 feat: catch throw on validation 2022-05-09 17:40:29 +02:00
Corentin Thomasset
b89db3c8d0 refactor: updated description 2022-05-09 17:19:12 +02:00
Corentin Thomasset
3cfc5f8bc2 fix(lint): missing new lines 2022-05-09 15:25:48 +02:00
Corentin Thomasset
9da56da096 chore(release): 2.3.2 2022-05-09 14:45:47 +02:00
Corentin Thomasset
9755e51fe2 fix(typo): misspelings 2022-05-09 14:38:54 +02:00
Corentin Thomasset
0b0cbd55c3 fix(base-converter): responsive input 2022-04-24 23:22:52 +02:00
Corentin Thomasset
e21230bbd9 refactor(responsive): row layout for multicards on big screens 2022-04-24 23:09:12 +02:00
Corentin Thomasset
84cf1bb964 fix(base64-converter): async onUpload callback 2022-04-24 22:33:40 +02:00
Corentin Thomasset
b64839cb73 chore(release): 2.3.1 2022-04-24 19:43:01 +02:00
Corentin Thomasset
608ec3a81d refactor: changed twitter account handler 2022-04-24 19:26:28 +02:00
33 changed files with 495 additions and 256 deletions

View File

@@ -0,0 +1,25 @@
<!-- Thank you for contributing! -->
### Description
<!-- Please insert your description here and provide especially info about the "what" this PR is solving -->
### Additional context
<!-- e.g. is there anything you'd like reviewers to focus on? -->
---
### What is the purpose of this pull request? <!-- (put an "X" next to an item) -->
- [ ] Bug fix
- [ ] New Feature
- [ ] Documentation update
- [ ] Other
### Before submitting the PR, please make sure you do the following
- [ ] Submit the PR against the `dev` branch.
- [ ] Check that there isn't already a PR that solves the problem the same way to avoid creating a duplicate.
- [ ] Provide a description in this PR that addresses **what** the PR is solving, or reference the issue that it solves (e.g. `fixes #123`).
- [ ] Ideally, include relevant tests that fail without this PR but pass with it.

View File

@@ -1,6 +1,6 @@
name: ci name: ci
on: push on: [push, pull_request]
jobs: jobs:
ci: ci:

View File

@@ -1,3 +1,3 @@
{ {
"recommendations": ["johnsoncodehk.volar", "johnsoncodehk.vscode-typescript-vue-plugin"] "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin", "dbaeumer.vscode-eslint"]
} }

View File

@@ -2,6 +2,69 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [2.4.1](https://github.com/CorentinTh/it-tools/compare/v2.4.0...v2.4.1) (2022-05-15)
### Bug Fixes
* **seo:** wrong url in share metas ([a88e4a9](https://github.com/CorentinTh/it-tools/commit/a88e4a9289e7d8cc80190f60f2fe08fe2ba08ee6))
### Refactors
* **json-viewer:** add clear button ([048bc4a](https://github.com/CorentinTh/it-tools/commit/048bc4ae943509dea2946764efaa69f845b6c478))
* **seo:** changed title string ([d4ea393](https://github.com/CorentinTh/it-tools/commit/d4ea393c1df87ae958a06ed66a11e36b081282d4))
## [2.4.0](https://github.com/CorentinTh/it-tools/compare/v2.3.2...v2.4.0) (2022-05-14)
### Features
* catch throw on validation ([a60f64f](https://github.com/CorentinTh/it-tools/commit/a60f64f74417f811204121f97c16cdb4754afc3b))
* **hash-text:** compute all hashes at the same time ([#242](https://github.com/CorentinTh/it-tools/issues/242)) ([e9cc499](https://github.com/CorentinTh/it-tools/commit/e9cc499ed87ba926086323223c7eca4f6658b3f0))
* **new-tool:** json viewer ([d356b14](https://github.com/CorentinTh/it-tools/commit/d356b1488fc640a4f5b65d62e0f2f368f5941996))
* **seo:** added cannonical meta ([34bc6a5](https://github.com/CorentinTh/it-tools/commit/34bc6a57a7bab98ff2a630d02034c342084e0af9))
### Bug Fixes
* **lint:** missing new lines ([3cfc5f8](https://github.com/CorentinTh/it-tools/commit/3cfc5f8bc27b66e6fbb6054f3c909818083ebc37))
* update recommended extension ids ([#244](https://github.com/CorentinTh/it-tools/issues/244)) ([1d7032d](https://github.com/CorentinTh/it-tools/commit/1d7032d0268220f594de6d837a303fc1e63cbd9f))
### Documentation
* added producthunt banners ([4c4da16](https://github.com/CorentinTh/it-tools/commit/4c4da16970e1dbb13705d8b6c020cd40cd2b5e0d))
### Refactors
* **base-layout:** renammed one letter variable ([383d975](https://github.com/CorentinTh/it-tools/commit/383d97569580c4f31448c07cb97e3778bc97a8af))
* **date-converter:** mutualised and dry-ed code ([d2c767f](https://github.com/CorentinTh/it-tools/commit/d2c767f0922e9b93172c3167226ad3db5499b9f6))
* **seo:** changed title string ([c3b6132](https://github.com/CorentinTh/it-tools/commit/c3b6132c261bd5952bafb1ff1e576eb13d2d0a7d))
* updated description ([b89db3c](https://github.com/CorentinTh/it-tools/commit/b89db3c8d0de601fecbd2f9f79492dff1b461bd8))
### [2.3.2](https://github.com/CorentinTh/it-tools/compare/v2.3.1...v2.3.2) (2022-05-09)
### Bug Fixes
* **base-converter:** responsive input ([0b0cbd5](https://github.com/CorentinTh/it-tools/commit/0b0cbd55c3809ded2eedfa0b2238bc950b01516a))
* **base64-converter:** async onUpload callback ([84cf1bb](https://github.com/CorentinTh/it-tools/commit/84cf1bb9645c5ae31579098df59471f7d99f6f0c))
* **typo:** misspelings ([9755e51](https://github.com/CorentinTh/it-tools/commit/9755e51fe216e5e25c56417152e70cb5bce26b11))
### Refactors
* **responsive:** row layout for multicards on big screens ([e21230b](https://github.com/CorentinTh/it-tools/commit/e21230bbd9550ba3315607b021a60a4f9f9e1b61))
### [2.3.1](https://github.com/CorentinTh/it-tools/compare/v2.3.0...v2.3.1) (2022-04-24)
### Refactors
* changed twitter account handler ([608ec3a](https://github.com/CorentinTh/it-tools/commit/608ec3a81db6583c8a2bf126b3868afd043c6981))
## [2.3.0](https://github.com/CorentinTh/it-tools/compare/v2.2.0...v2.3.0) (2022-04-22) ## [2.3.0](https://github.com/CorentinTh/it-tools/compare/v2.2.0...v2.3.0) (2022-04-22)

View File

@@ -68,6 +68,12 @@ Coded with ❤️ by [Corentin Thomasset](//corentin-thomasset.fr).
This project is continuously deployed using [vercel.com](https://vercel.com). This project is continuously deployed using [vercel.com](https://vercel.com).
<a href="https://www.producthunt.com/posts/it-tools?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-it&#0045;tools" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=345793&theme=light" alt="IT&#0032;Tools - Collection&#0032;of&#0032;handy&#0032;online&#0032;tools&#0032;for&#0032;devs&#0044;&#0032;with&#0032;great&#0032;UX | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
<a href="https://www.producthunt.com/posts/it-tools?utm_source=badge-top-post-badge&utm_medium=badge&utm_souce=badge-it&#0045;tools" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=345793&theme=light&period=daily" alt="IT&#0032;Tools - Collection&#0032;of&#0032;handy&#0032;online&#0032;tools&#0032;for&#0032;devs&#0044;&#0032;with&#0032;great&#0032;UX | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
## License ## License
This project is under the [MIT license](LICENSE). This project is under the [MIT license](LICENSE).

View File

@@ -4,13 +4,13 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Aggregated set of useful tools that every developer may need once in a while." /> <title>IT Tools - Handy online tools for developers</title>
<title>IT Tools</title> <meta itemprop="name" content="IT Tools - Handy online tools for developers" />
<meta itemprop="name" content="IT-Tools" /> <meta name="description" content="Collection of handy online tools for developers, with great UX. IT Tools is a free and open-source collection of handy online tools for developers & people working in IT." />
<meta name="description" content="Aggregated set of useful tools that every developer may need once in a while." /> <meta itemprop="description" content="Collection of handy online tools for developers, with great UX. IT Tools is a free and open-source collection of handy online tools for developers & people working in IT." />
<meta itemprop="description" content="Aggregated set of useful tools that every developer may need once in a while." />
<link rel="author" href="/humans.txt" /> <link rel="author" href="/humans.txt" />
<link rel=canonical href="https://it-tools.tech">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" /> <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" /> <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" /> <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
@@ -18,17 +18,17 @@
<meta name="msapplication-TileColor" content="#da532c" /> <meta name="msapplication-TileColor" content="#da532c" />
<meta name="theme-color" content="#ffffff" /> <meta name="theme-color" content="#ffffff" />
<meta property="og:url" content="https://dev.it-tools.tech/" /> <meta property="og:url" content="https://it-tools.tech/" />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:title" content="IT-Tools" /> <meta property="og:title" content="IT Tools - Handy online tools for developers" />
<meta property="og:description" content="Aggregated set of useful tools that every developer may need once in a while." /> <meta property="og:description" content="Collection of handy online tools for developers, with great UX. IT Tools is a free and open-source collection of handy online tools for developers & people working in IT." />
<meta property="og:image" content="/banner.png" /> <meta property="og:image" content="/banner.png" />
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />
<meta property="twitter:domain" content="dev.it-tools.tech" /> <meta property="twitter:domain" content="it-tools.tech" />
<meta property="twitter:url" content="https://dev.it-tools.tech/" /> <meta property="twitter:url" content="https://it-tools.tech/" />
<meta name="twitter:title" content="IT-Tools" /> <meta name="twitter:title" content="IT Tools - Handy online tools for developers" />
<meta name="twitter:description" content="Aggregated set of useful tools that every developer may need once in a while." /> <meta name="twitter:description" content="Collection of handy online tools for developers, with great UX. IT Tools is a free and open-source collection of handy online tools for developers & people working in IT." />
<meta name="twitter:image" content="/banner.png" /> <meta name="twitter:image" content="/banner.png" />
</head> </head>
<body> <body>

118
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "it-tools", "name": "it-tools",
"version": "2.3.0", "version": "2.4.1",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "it-tools", "name": "it-tools",
"version": "2.3.0", "version": "2.4.1",
"dependencies": { "dependencies": {
"@it-tools/bip39": "^0.0.4", "@it-tools/bip39": "^0.0.4",
"@vicons/material": "^0.12.0", "@vicons/material": "^0.12.0",
@@ -20,6 +20,7 @@
"cronstrue": "^2.2.0", "cronstrue": "^2.2.0",
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
"date-fns": "^2.28.0", "date-fns": "^2.28.0",
"highlight.js": "^11.5.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"naive-ui": "^2.28.0", "naive-ui": "^2.28.0",
"pinia": "^2.0.11", "pinia": "^2.0.11",
@@ -3101,6 +3102,12 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/async": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz",
"integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==",
"dev": true
},
"node_modules/async-validator": { "node_modules/async-validator": {
"version": "4.0.7", "version": "4.0.7",
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.0.7.tgz", "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.0.7.tgz",
@@ -4459,12 +4466,12 @@
"dev": true "dev": true
}, },
"node_modules/ejs": { "node_modules/ejs": {
"version": "3.1.6", "version": "3.1.7",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.7.tgz",
"integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==", "integrity": "sha512-BIar7R6abbUxDA3bfXrO4DSgwo8I+fB5/1zgujl3HLLjwd6+9iOnrT+t3grn2qbk9vOgBubXOFwX2m9axoFaGw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"jake": "^10.6.1" "jake": "^10.8.5"
}, },
"bin": { "bin": {
"ejs": "bin/cli.js" "ejs": "bin/cli.js"
@@ -5542,12 +5549,33 @@
} }
}, },
"node_modules/filelist": { "node_modules/filelist": {
"version": "1.0.2", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.3.tgz",
"integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==", "integrity": "sha512-LwjCsruLWQULGYKy7TX0OPtrL9kLpojOFKc5VCTxdFTV7w5zbsgqVKfnkKG7Qgjtq50gKfO56hJv88OfcGb70Q==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"minimatch": "^3.0.4" "minimatch": "^5.0.1"
}
},
"node_modules/filelist/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/filelist/node_modules/minimatch": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
"integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
"dev": true,
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=10"
} }
}, },
"node_modules/fill-range": { "node_modules/fill-range": {
@@ -6704,12 +6732,12 @@
} }
}, },
"node_modules/jake": { "node_modules/jake": {
"version": "10.8.4", "version": "10.8.5",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.4.tgz", "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz",
"integrity": "sha512-MtWeTkl1qGsWUtbl/Jsca/8xSoK3x0UmS82sNbjqxxG/de/M/3b1DntdjHgPMC50enlTNwXOCRqPXLLt5cCfZA==", "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"async": "0.9.x", "async": "^3.2.3",
"chalk": "^4.0.2", "chalk": "^4.0.2",
"filelist": "^1.0.1", "filelist": "^1.0.1",
"minimatch": "^3.0.4" "minimatch": "^3.0.4"
@@ -6736,12 +6764,6 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1" "url": "https://github.com/chalk/ansi-styles?sponsor=1"
} }
}, },
"node_modules/jake/node_modules/async": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
"integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=",
"dev": true
},
"node_modules/jake/node_modules/chalk": { "node_modules/jake/node_modules/chalk": {
"version": "4.1.2", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -13541,6 +13563,12 @@
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
"dev": true "dev": true
}, },
"async": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz",
"integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==",
"dev": true
},
"async-validator": { "async-validator": {
"version": "4.0.7", "version": "4.0.7",
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.0.7.tgz", "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.0.7.tgz",
@@ -14605,12 +14633,12 @@
"dev": true "dev": true
}, },
"ejs": { "ejs": {
"version": "3.1.6", "version": "3.1.7",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.7.tgz",
"integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==", "integrity": "sha512-BIar7R6abbUxDA3bfXrO4DSgwo8I+fB5/1zgujl3HLLjwd6+9iOnrT+t3grn2qbk9vOgBubXOFwX2m9axoFaGw==",
"dev": true, "dev": true,
"requires": { "requires": {
"jake": "^10.6.1" "jake": "^10.8.5"
} }
}, },
"electron-to-chromium": { "electron-to-chromium": {
@@ -15311,12 +15339,32 @@
} }
}, },
"filelist": { "filelist": {
"version": "1.0.2", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.3.tgz",
"integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==", "integrity": "sha512-LwjCsruLWQULGYKy7TX0OPtrL9kLpojOFKc5VCTxdFTV7w5zbsgqVKfnkKG7Qgjtq50gKfO56hJv88OfcGb70Q==",
"dev": true, "dev": true,
"requires": { "requires": {
"minimatch": "^3.0.4" "minimatch": "^5.0.1"
},
"dependencies": {
"brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0"
}
},
"minimatch": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
"integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
"dev": true,
"requires": {
"brace-expansion": "^2.0.1"
}
}
} }
}, },
"fill-range": { "fill-range": {
@@ -16167,12 +16215,12 @@
} }
}, },
"jake": { "jake": {
"version": "10.8.4", "version": "10.8.5",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.4.tgz", "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz",
"integrity": "sha512-MtWeTkl1qGsWUtbl/Jsca/8xSoK3x0UmS82sNbjqxxG/de/M/3b1DntdjHgPMC50enlTNwXOCRqPXLLt5cCfZA==", "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==",
"dev": true, "dev": true,
"requires": { "requires": {
"async": "0.9.x", "async": "^3.2.3",
"chalk": "^4.0.2", "chalk": "^4.0.2",
"filelist": "^1.0.1", "filelist": "^1.0.1",
"minimatch": "^3.0.4" "minimatch": "^3.0.4"
@@ -16187,12 +16235,6 @@
"color-convert": "^2.0.1" "color-convert": "^2.0.1"
} }
}, },
"async": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
"integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=",
"dev": true
},
"chalk": { "chalk": {
"version": "4.1.2", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",

View File

@@ -1,6 +1,6 @@
{ {
"name": "it-tools", "name": "it-tools",
"version": "2.3.0", "version": "2.4.1",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vue-tsc --noEmit && vite build", "build": "vue-tsc --noEmit && vite build",
@@ -25,6 +25,7 @@
"cronstrue": "^2.2.0", "cronstrue": "^2.2.0",
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
"date-fns": "^2.28.0", "date-fns": "^2.28.0",
"highlight.js": "^11.5.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"naive-ui": "^2.28.0", "naive-ui": "^2.28.0",
"pinia": "^2.0.11", "pinia": "^2.0.11",

View File

@@ -23,7 +23,7 @@
circle circle
quaternary quaternary
tag="a" tag="a"
href="https://twitter.com/cthmsst" href="https://twitter.com/ittoolsdottech"
rel="noopener" rel="noopener"
target="_blank" target="_blank"
> >

View File

@@ -5,6 +5,14 @@ type UseValidationRule<T> = {
message: string; message: string;
}; };
function isFalsyOrHasThrown(cb: () => boolean) {
try {
return !cb();
} catch (_) {
return true;
}
}
export function useValidation<T>({ source, rules }: { source: Ref<T>; rules: UseValidationRule<T>[] }) { export function useValidation<T>({ source, rules }: { source: Ref<T>; rules: UseValidationRule<T>[] }) {
const state = reactive<{ const state = reactive<{
message: string; message: string;
@@ -19,7 +27,7 @@ export function useValidation<T>({ source, rules }: { source: Ref<T>; rules: Use
state.status = undefined; state.status = undefined;
for (const rule of rules) { for (const rule of rules) {
if (!rule.validator(source.value)) { if (isFalsyOrHasThrown(() => rule.validator(source.value))) {
state.message = rule.message; state.message = rule.message;
state.status = 'error'; state.status = 'error';
} }

View File

@@ -19,7 +19,7 @@ const commitSha = import.meta.env.GIT_SHORT_SHA;
const makeLabel = (text: string, to: string) => () => h(RouterLink, { to }, { default: () => text }); const makeLabel = (text: string, to: string) => () => h(RouterLink, { to }, { default: () => text });
const makeIcon = (icon: Component) => () => h(NIcon, null, { default: () => h(icon) }); const makeIcon = (icon: Component) => () => h(NIcon, null, { default: () => h(icon) });
const m = toolsByCategory.map((category) => ({ const menuOptions = toolsByCategory.map((category) => ({
label: category.name, label: category.name,
key: category.name, key: category.name,
type: 'group', type: 'group',
@@ -53,7 +53,7 @@ const m = toolsByCategory.map((category) => ({
:value="(route.name as string)" :value="(route.name as string)"
:collapsed-width="64" :collapsed-width="64"
:collapsed-icon-size="22" :collapsed-icon-size="22"
:options="m" :options="menuOptions"
:indent="20" :indent="20"
/> />

View File

@@ -33,20 +33,36 @@ useHead(head);
{{ route.meta.description }} {{ route.meta.description }}
</div> </div>
</div> </div>
</div>
<div class="tool-content">
<slot /> <slot />
</div> </div>
</base-layout> </base-layout>
</template> </template>
<style lang="less" scoped> <style lang="less" scoped>
.tool-content {
display: flex;
flex-direction: row;
justify-content: center;
align-items: flex-start;
flex-wrap: wrap;
gap: 16px;
::v-deep(& > *) {
flex: 0 1 600px;
}
}
.tool-layout { .tool-layout {
max-width: 700px; max-width: 600px;
margin: 0 auto; margin: 0 auto;
box-sizing: border-box; box-sizing: border-box;
.tool-header { .tool-header {
padding: 40px 0; padding: 40px 0;
width: 100%;
.n-h1 { .n-h1 {
opacity: 0.9; opacity: 0.9;

View File

@@ -50,9 +50,11 @@ import {
NImage, NImage,
NScrollbar, NScrollbar,
NGradientText, NGradientText,
NCode,
} from 'naive-ui'; } from 'naive-ui';
const components = [ const components = [
NCode,
NGradientText, NGradientText,
NScrollbar, NScrollbar,
NImage, NImage,

View File

@@ -40,7 +40,7 @@ const fileInput = ref() as Ref<File>;
const { base64: fileBase64 } = useBase64(fileInput); const { base64: fileBase64 } = useBase64(fileInput);
const { copy: copyFileBase64 } = useCopy({ source: fileBase64, text: 'Base64 string copied to the clipboard' }); const { copy: copyFileBase64 } = useCopy({ source: fileBase64, text: 'Base64 string copied to the clipboard' });
function onUpload({ file: { file } }: { file: UploadFileInfo }) { async function onUpload({ file: { file } }: { file: UploadFileInfo }) {
if (file) { if (file) {
fileList.value = []; fileList.value = [];
fileInput.value = file; fileInput.value = file;
@@ -50,8 +50,7 @@ function onUpload({ file: { file } }: { file: UploadFileInfo }) {
<style lang="less" scoped> <style lang="less" scoped>
.n-input, .n-input,
.n-upload, .n-upload {
.n-card {
margin-bottom: 15px; margin-bottom: 15px;
} }

View File

@@ -5,7 +5,7 @@ export const tool: ITool = {
name: 'Base64 converter', name: 'Base64 converter',
path: '/base64-converter', path: '/base64-converter',
description: "Convert string, files or images into a it's base64 representation.", description: "Convert string, files or images into a it's base64 representation.",
keywords: ['base64', 'converter', 'upload', 'image', 'file', 'convertion', 'web', 'data', 'format'], keywords: ['base64', 'converter', 'upload', 'image', 'file', 'conversion', 'web', 'data', 'format'],
component: () => import('./base64-converter.vue'), component: () => import('./base64-converter.vue'),
icon: FileDigit, icon: FileDigit,
redirectFrom: ['/file-to-base64', '/base64-string-converter'], redirectFrom: ['/file-to-base64', '/base64-string-converter'],

View File

@@ -22,7 +22,6 @@
</n-space> </n-space>
</n-card> </n-card>
<br />
<n-card title="Compare string with hash"> <n-card title="Compare string with hash">
<n-form label-width="120"> <n-form label-width="120">
<n-form-item label="Your string: " label-placement="left"> <n-form-item label="Your string: " label-placement="left">

View File

@@ -28,7 +28,6 @@
</n-form> </n-form>
</n-space> </n-space>
</n-card> </n-card>
<br />
<n-card> <n-card>
<pre> <pre>
[optional] seconds (0 - 59) [optional] seconds (0 - 59)

View File

@@ -83,46 +83,54 @@ function onDateInputChanged(value: string) {
} }
} }
const formats = [ type Format = {
name: string;
fromDate: (date: Date) => string;
toDate: (value: string) => Date;
};
const toDate: Format['toDate'] = (date) => new Date(date);
const formats: Format[] = [
{ {
name: 'JS locale date string', name: 'JS locale date string',
fromDate: (date: Date) => date.toString(), fromDate: (date) => date.toString(),
toDate: (date: string) => new Date(date), toDate,
}, },
{ {
name: 'ISO 8601', name: 'ISO 8601',
fromDate: (date: Date) => formatISO(date), fromDate: formatISO,
toDate: (date: string) => parseISO(date), toDate: parseISO,
}, },
{ {
name: 'ISO 9075', name: 'ISO 9075',
fromDate: (date: Date) => formatISO9075(date), fromDate: formatISO9075,
toDate: (date: string) => parseISO(date), toDate: parseISO,
}, },
{ {
name: 'RFC 3339', name: 'RFC 3339',
fromDate: (date: Date) => formatRFC3339(date), fromDate: formatRFC3339,
toDate: (date: string) => new Date(date), toDate,
}, },
{ {
name: 'RFC 7231', name: 'RFC 7231',
fromDate: (date: Date) => formatRFC7231(date), fromDate: formatRFC7231,
toDate: (date: string) => new Date(date), toDate,
}, },
{ {
name: 'Timestamp', name: 'Timestamp',
fromDate: (date: Date) => String(getTime(date)), fromDate: (date) => String(getTime(date)),
toDate: (ms: string) => parseJSON(+ms), toDate: (ms) => parseJSON(+ms),
}, },
{ {
name: 'Unix timestamp', name: 'Unix timestamp',
fromDate: (date: Date) => String(getUnixTime(date)), fromDate: (date) => String(getUnixTime(date)),
toDate: (sec: string) => fromUnixTime(+sec), toDate: (sec) => fromUnixTime(+sec),
}, },
{ {
name: 'UTC format', name: 'UTC format',
fromDate: (date: Date) => date.toUTCString(), fromDate: (date) => date.toUTCString(),
toDate: (date: string) => new Date(date), toDate,
}, },
]; ];
</script> </script>

View File

@@ -5,7 +5,7 @@ export const tool: ITool = {
name: 'Date-time converter', name: 'Date-time converter',
path: '/date-converter', path: '/date-converter',
description: 'Convert date and time into the various different formats', description: 'Convert date and time into the various different formats',
keywords: ['date', 'time', 'converter', 'iso', 'utc', 'timezone', 'year', 'mounth', 'day', 'minute', 'seconde'], keywords: ['date', 'time', 'converter', 'iso', 'utc', 'timezone', 'year', 'month', 'day', 'minute', 'seconde'],
component: () => import('./date-time-converter.vue'), component: () => import('./date-time-converter.vue'),
icon: Calendar, icon: Calendar,
}; };

View File

@@ -1,5 +1,5 @@
<template> <template>
<n-card v-for="{ name, information } in sections" :key="name" :title="name" style="margin-bottom: 15px"> <n-card v-for="{ name, information } in sections" :key="name" :title="name">
<n-grid cols="1 400:2" x-gap="12" y-gap="12"> <n-grid cols="1 400:2" x-gap="12" y-gap="12">
<n-gi v-for="{ label, value } in information" :key="label" class="information"> <n-gi v-for="{ label, value } in information" :key="label" class="information">
<n-card :bordered="false" embedded> <n-card :bordered="false" embedded>
@@ -66,7 +66,7 @@ const sections = [
value: computed(() => navigator.languages.join(', ')), value: computed(() => navigator.languages.join(', ')),
}, },
{ {
label: 'Plateform', label: 'Platform',
value: computed(() => navigator.platform), value: computed(() => navigator.platform),
}, },
{ {

View File

@@ -1,81 +1,78 @@
<template> <template>
<div> <n-card title="Encrypt">
<n-card title="Encrypt"> <n-space item-style="flex: 1 1 0">
<n-space item-style="flex: 1 1 0"> <n-form-item label="Your text:" :show-feedback="false">
<n-form-item label="Your text:" :show-feedback="false">
<n-input
v-model:value="cypherInput"
type="textarea"
placeholder="The string to cypher"
:autosize="{ minRows: 4 }"
/>
</n-form-item>
<n-space vertical>
<n-form-item label="Your secret key:" :show-feedback="false">
<n-input v-model:value="cypherSecret" />
</n-form-item>
<n-form-item label="Encryption algorithm:" :show-feedback="false">
<n-select
v-model:value="cypherAlgo"
:options="Object.keys(algos).map((label) => ({ label, value: label }))"
/>
</n-form-item>
</n-space>
</n-space>
<br />
<n-form-item label="Yout text encrypted:" :show-feedback="false">
<n-input <n-input
:value="cypherOutput" v-model:value="cypherInput"
type="textarea" type="textarea"
placeholder="Your string hash" placeholder="The string to cypher"
:autosize="{ minRows: 2 }" :autosize="{ minRows: 4 }"
readonly
autocomplete="off"
autocorrect="off"
autocapitalize="off"
spellcheck="false"
/> />
</n-form-item> </n-form-item>
</n-card> <n-space vertical>
<n-form-item label="Your secret key:" :show-feedback="false">
<n-input v-model:value="cypherSecret" />
</n-form-item>
<n-form-item label="Encryption algorithm:" :show-feedback="false">
<n-select
v-model:value="cypherAlgo"
:options="Object.keys(algos).map((label) => ({ label, value: label }))"
/>
</n-form-item>
</n-space>
</n-space>
<br /> <br />
<n-card title="Decrypt"> <n-form-item label="Your text encrypted:" :show-feedback="false">
<n-space item-style="flex: 1 1 0"> <n-input
<n-form-item label="Your encrypted text:" :show-feedback="false"> :value="cypherOutput"
<n-input type="textarea"
v-model:value="decryptInput" placeholder="Your string hash"
type="textarea" :autosize="{ minRows: 2 }"
placeholder="The string to cypher" readonly
:autosize="{ minRows: 4 }" autocomplete="off"
/> autocorrect="off"
</n-form-item> autocapitalize="off"
<n-space vertical> spellcheck="false"
<n-form-item label="Your secret key:" :show-feedback="false"> />
<n-input v-model:value="decryptSecret" /> </n-form-item>
</n-form-item> </n-card>
<n-form-item label="Encryption algorithm:" :show-feedback="false"> <n-card title="Decrypt">
<n-select <n-space item-style="flex: 1 1 0">
v-model:value="decryptAlgo" <n-form-item label="Your encrypted text:" :show-feedback="false">
:options="Object.keys(algos).map((label) => ({ label, value: label }))"
/>
</n-form-item>
</n-space>
</n-space>
<br />
<n-form-item label="Yout decrypted text:" :show-feedback="false">
<n-input <n-input
:value="decryptOutput" v-model:value="decryptInput"
type="textarea" type="textarea"
placeholder="Your string hash" placeholder="The string to cypher"
:autosize="{ minRows: 2 }" :autosize="{ minRows: 4 }"
readonly
autocomplete="off"
autocorrect="off"
autocapitalize="off"
spellcheck="false"
/> />
</n-form-item> </n-form-item>
</n-card> <n-space vertical>
</div> <n-form-item label="Your secret key:" :show-feedback="false">
<n-input v-model:value="decryptSecret" />
</n-form-item>
<n-form-item label="Encryption algorithm:" :show-feedback="false">
<n-select
v-model:value="decryptAlgo"
:options="Object.keys(algos).map((label) => ({ label, value: label }))"
/>
</n-form-item>
</n-space>
</n-space>
<br />
<n-form-item label="Your decrypted text:" :show-feedback="false">
<n-input
:value="decryptOutput"
type="textarea"
placeholder="Your string hash"
:autosize="{ minRows: 2 }"
readonly
autocomplete="off"
autocorrect="off"
autocapitalize="off"
spellcheck="false"
/>
</n-form-item>
</n-card>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">

View File

@@ -5,7 +5,7 @@ export const tool: ITool = {
name: 'Encrypt / decrypt text', name: 'Encrypt / decrypt text',
path: '/encryption', path: '/encryption',
description: 'Encrypt and decrypt text clear text using crypto algorithm like AES, TripleDES, Rabbit or RC4.', description: 'Encrypt and decrypt text clear text using crypto algorithm like AES, TripleDES, Rabbit or RC4.',
keywords: ['cypher', 'uncypher', 'text', 'AES', 'TripleDES', 'Rabbit', 'RC4'], keywords: ['cypher', 'encipher', 'text', 'AES', 'TripleDES', 'Rabbit', 'RC4'],
component: () => import('./encryption.vue'), component: () => import('./encryption.vue'),
icon: Lock, icon: Lock,
redirectFrom: ['/cypher'], redirectFrom: ['/cypher'],

View File

@@ -5,8 +5,8 @@ export const tool: ITool = {
name: 'Git cheatsheet', name: 'Git cheatsheet',
path: '/git-memo', path: '/git-memo',
description: description:
'Git is a decentralized version management sofware. With this cheatsheet you will have a quick acces to the most common git commands.', 'Git is a decentralized version management software. With this cheatsheet you will have a quick access to the most common git commands.',
keywords: ['git', 'push', 'force', 'pull', 'commit', 'ammend', 'rebase', 'merge', 'reset', 'soft', 'hard', 'lease'], keywords: ['git', 'push', 'force', 'pull', 'commit', 'amend', 'rebase', 'merge', 'reset', 'soft', 'hard', 'lease'],
component: () => import('./git-memo.vue'), component: () => import('./git-memo.vue'),
icon: BrandGit, icon: BrandGit,
}; };

View File

@@ -2,35 +2,22 @@
<div> <div>
<n-card> <n-card>
<n-input v-model:value="clearText" type="textarea" placeholder="Your string..." :autosize="{ minRows: 3 }" /> <n-input v-model:value="clearText" type="textarea" placeholder="Your string..." :autosize="{ minRows: 3 }" />
<br />
<br />
<n-select v-model:value="algo" :options="Object.keys(algos).map((label) => ({ label, value: label }))" />
<br /> <n-divider />
<n-input
style="text-align: center" <div v-for="algo in algoNames" :key="algo" style="margin: 5px 0">
:value="hashedText" <n-input-group>
type="textarea" <n-input-group-label style="flex: 0 0 120px"> {{ algo }} </n-input-group-label>
placeholder="Your string hash" <input-copyable :value="hashText(algo, clearText)" readonly />
:autosize="{ minRows: 1 }" </n-input-group>
readonly </div>
autocomplete="off"
autocorrect="off"
autocapitalize="off"
spellcheck="false"
/>
<br />
<br />
<n-space justify="center">
<n-button secondary autofocus @click="copy"> Copy </n-button>
</n-space>
</n-card> </n-card>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useCopy } from '@/composable/copy'; import InputCopyable from '../../components/InputCopyable.vue';
import { ref, computed } from 'vue'; import { ref } from 'vue';
import { MD5, SHA1, SHA256, SHA224, SHA512, SHA384, SHA3, RIPEMD160 } from 'crypto-js'; import { MD5, SHA1, SHA256, SHA224, SHA512, SHA384, SHA3, RIPEMD160 } from 'crypto-js';
const algos = { const algos = {
@@ -44,11 +31,11 @@ const algos = {
RIPEMD160, RIPEMD160,
} as const; } as const;
type AlgoNames = keyof typeof algos;
const algoNames = Object.keys(algos) as AlgoNames[];
const clearText = ref( const clearText = ref(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lacus metus blandit dolor lacus natoque ad fusce aliquam velit.', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lacus metus blandit dolor lacus natoque ad fusce aliquam velit.',
); );
const algo = ref<keyof typeof algos>('SHA256'); const hashText = (algo: AlgoNames, value: string) => algos[algo](value).toString();
const hashedText = computed(() => algos[algo.value](clearText.value).toString());
const { copy } = useCopy({ source: hashedText, text: 'Hash copied to the clipboard' });
</script> </script>

View File

@@ -23,7 +23,6 @@
<n-button secondary @click="copyEscaped"> Copy </n-button> <n-button secondary @click="copyEscaped"> Copy </n-button>
</n-space> </n-space>
</n-card> </n-card>
<br />
<n-card title="Unescape html entities"> <n-card title="Unescape html entities">
<n-form-item label="Your escaped string :"> <n-form-item label="Your escaped string :">
<n-input <n-input

View File

@@ -1,6 +1,7 @@
import { LockOpen } from '@vicons/tabler'; import { LockOpen } from '@vicons/tabler';
import type { ToolCategory } from './Tool'; import type { ToolCategory } from './Tool';
import { tool as jsonViewer } from './json-viewer';
import { tool as htmlEntities } from './html-entities'; import { tool as htmlEntities } from './html-entities';
import { tool as urlParser } from './url-parser'; import { tool as urlParser } from './url-parser';
import { tool as deviceInformation } from './device-information'; import { tool as deviceInformation } from './device-information';
@@ -50,7 +51,7 @@ export const toolsByCategory: ToolCategory[] = [
{ {
name: 'Development', name: 'Development',
icon: LockOpen, icon: LockOpen,
components: [gitMemo, randomPortGenerator, crontabGenerator], components: [gitMemo, randomPortGenerator, crontabGenerator, jsonViewer],
}, },
{ {
name: 'Text', name: 'Text',

View File

@@ -4,8 +4,8 @@ import type { ITool } from '../Tool';
export const tool: ITool = { export const tool: ITool = {
name: 'Integer base converter', name: 'Integer base converter',
path: '/base-converter', path: '/base-converter',
description: 'Convert numver between different bases (decimal, hexadecimal, binary, octale, base64, ...)', description: 'Convert number between different bases (decimal, hexadecimal, binary, octal, base64, ...)',
keywords: ['integer', 'number', 'base', 'convertion', 'decimal', 'hexadecimal', 'binary', 'octale', 'base64'], keywords: ['integer', 'number', 'base', 'conversion', 'decimal', 'hexadecimal', 'binary', 'octal', 'base64'],
component: () => import('./integer-base-converter.vue'), component: () => import('./integer-base-converter.vue'),
icon: ArrowsLeftRight, icon: ArrowsLeftRight,
}; };

View File

@@ -1,27 +1,37 @@
<template> <template>
<div> <div>
<n-card> <n-card>
<n-input-group> <div v-if="styleStore.isSmallScreen">
<n-input-group-label style="width: 200px"> Input number: </n-input-group-label> <n-input-group>
<n-input-number v-model:value="inputNumber" min="0" /> <n-input-group-label style="flex: 0 0 120px"> Input number: </n-input-group-label>
<n-input-number v-model:value="inputNumber" min="0" style="width: 100%" />
</n-input-group>
<n-input-group>
<n-input-group-label style="flex: 0 0 120px"> Input base: </n-input-group-label>
<n-input-number v-model:value="inputBase" max="64" min="2" style="width: 100%" />
</n-input-group>
</div>
<n-input-group-label style="width: 200px"> Input base: </n-input-group-label> <n-input-group v-else>
<n-input-number v-model:value="inputBase" max="64" min="2" style="width: 100px" /> <n-input-group-label style="flex: 0 0 120px"> Input number: </n-input-group-label>
<n-input-number v-model:value="inputNumber" min="0" />
<n-input-group-label style="flex: 0 0 120px"> Input base: </n-input-group-label>
<n-input-number v-model:value="inputBase" max="64" min="2" />
</n-input-group> </n-input-group>
<n-divider /> <n-divider />
<n-input-group> <n-input-group>
<n-input-group-label style="width: 200px"> Binary (2): </n-input-group-label> <n-input-group-label style="flex: 0 0 170px"> Binary (2): </n-input-group-label>
<input-copyable :value="convertBase({ value: String(inputNumber), fromBase: inputBase, toBase: 2 })" readonly /> <input-copyable :value="convertBase({ value: String(inputNumber), fromBase: inputBase, toBase: 2 })" readonly />
</n-input-group> </n-input-group>
<n-input-group> <n-input-group>
<n-input-group-label style="width: 200px"> Octale (8): </n-input-group-label> <n-input-group-label style="flex: 0 0 170px"> Octal (8): </n-input-group-label>
<input-copyable :value="convertBase({ value: String(inputNumber), fromBase: inputBase, toBase: 8 })" readonly /> <input-copyable :value="convertBase({ value: String(inputNumber), fromBase: inputBase, toBase: 8 })" readonly />
</n-input-group> </n-input-group>
<n-input-group> <n-input-group>
<n-input-group-label style="width: 200px"> Decimal (10): </n-input-group-label> <n-input-group-label style="flex: 0 0 170px"> Decimal (10): </n-input-group-label>
<input-copyable <input-copyable
:value="convertBase({ value: String(inputNumber), fromBase: inputBase, toBase: 10 })" :value="convertBase({ value: String(inputNumber), fromBase: inputBase, toBase: 10 })"
readonly readonly
@@ -29,7 +39,7 @@
</n-input-group> </n-input-group>
<n-input-group> <n-input-group>
<n-input-group-label style="width: 200px"> Hexadecimal (16): </n-input-group-label> <n-input-group-label style="flex: 0 0 170px"> Hexadecimal (16): </n-input-group-label>
<input-copyable <input-copyable
:value="convertBase({ value: String(inputNumber), fromBase: inputBase, toBase: 16 })" :value="convertBase({ value: String(inputNumber), fromBase: inputBase, toBase: 16 })"
readonly readonly
@@ -37,15 +47,15 @@
</n-input-group> </n-input-group>
<n-input-group> <n-input-group>
<n-input-group-label style="width: 200px"> Base64 (64): </n-input-group-label> <n-input-group-label style="flex: 0 0 170px"> Base64 (64): </n-input-group-label>
<input-copyable <input-copyable
:value="convertBase({ value: String(inputNumber), fromBase: inputBase, toBase: 64 })" :value="convertBase({ value: String(inputNumber), fromBase: inputBase, toBase: 64 })"
readonly readonly
/> />
</n-input-group> </n-input-group>
<n-input-group> <n-input-group>
<n-input-group-label style="width: 90px"> Custom: </n-input-group-label> <n-input-group-label style="flex: 0 0 85px"> Custom: </n-input-group-label>
<n-input-number v-model:value="outputBase" style="width: 110px" max="64" min="2" /> <n-input-number v-model:value="outputBase" style="flex: 0 0 86px" max="64" min="2" />
<input-copyable <input-copyable
:value="convertBase({ value: String(inputNumber), fromBase: inputBase, toBase: outputBase })" :value="convertBase({ value: String(inputNumber), fromBase: inputBase, toBase: outputBase })"
readonly readonly
@@ -59,6 +69,9 @@
import { ref } from 'vue'; import { ref } from 'vue';
import { convertBase } from './integer-base-converter.model'; import { convertBase } from './integer-base-converter.model';
import InputCopyable from '../../components/InputCopyable.vue'; import InputCopyable from '../../components/InputCopyable.vue';
import { useStyleStore } from '@/stores/style.store';
const styleStore = useStyleStore();
const inputNumber = ref(42); const inputNumber = ref(42);
const inputBase = ref(10); const inputBase = ref(10);

View File

@@ -0,0 +1,11 @@
import { Braces } from '@vicons/tabler';
import type { ITool } from './../Tool';
export const tool: ITool = {
name: 'JSON viewer',
path: '/json-viewer',
description: 'Prettify JSON string to a human friendly readable format.',
keywords: ['json', 'viewer', 'prettify', 'format'],
component: () => import('./json-viewer.vue'),
icon: Braces,
};

View File

@@ -0,0 +1,66 @@
<template>
<n-card>
<n-form-item
label="Your raw json:"
:feedback="rawJsonValidation.message"
:validation-status="rawJsonValidation.status"
>
<n-input
v-model:value="rawJson"
class="json-input"
type="textarea"
placeholder="Paste your raw json here..."
autocomplete="off"
autocorrect="off"
autocapitalize="off"
spellcheck="false"
/>
</n-form-item>
<n-space justify="center">
<n-button secondary @click="rawJson = ''">Clear</n-button>
</n-space>
</n-card>
<n-card v-if="cleanJson.length > 0">
<n-scrollbar :x-scrollable="true">
<n-config-provider :hljs="hljs">
<n-code :code="cleanJson" language="json" />
</n-config-provider>
</n-scrollbar>
</n-card>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import hljs from 'highlight.js/lib/core';
import json from 'highlight.js/lib/languages/json';
import { useValidation } from '@/composable/validation';
hljs.registerLanguage('json', json);
const rawJson = ref('');
const cleanJson = computed(() => {
try {
return JSON.stringify(JSON.parse(rawJson.value), null, 3);
} catch (_) {
return '';
}
});
const rawJsonValidation = useValidation({
source: rawJson,
rules: [
{
validator: (v) => v === '' || JSON.parse(v),
message: 'Invalid json string',
},
],
});
</script>
<style lang="less" scoped>
.json-input ::v-deep(.n-input-wrapper) {
resize: both !important;
}
</style>

View File

@@ -5,7 +5,7 @@ export const tool: ITool = {
name: 'Random port generator', name: 'Random port generator',
path: '/random-port-generator', path: '/random-port-generator',
description: 'Generate random port numbers outside of the range of "known" ports (0-1023).', description: 'Generate random port numbers outside of the range of "known" ports (0-1023).',
keywords: ['system', 'port', 'lan', 'generator', 'random', 'developement', 'computer'], keywords: ['system', 'port', 'lan', 'generator', 'random', 'development', 'computer'],
component: () => import('./random-port-generator.vue'), component: () => import('./random-port-generator.vue'),
icon: Server, icon: Server,
}; };

View File

@@ -1,63 +1,60 @@
<template> <template>
<div> <n-card title="Encode">
<n-card title="Encode"> <n-form-item
<n-form-item label="Your string :"
label="Your string :" :feedback="encodedValidation.message"
:feedback="encodedValidation.message" :validation-status="encodedValidation.status"
:validation-status="encodedValidation.status" >
> <n-input
<n-input v-model:value="encodeInput"
v-model:value="encodeInput" type="textarea"
type="textarea" placeholder="The string to encode"
placeholder="The string to encode" :autosize="{ minRows: 2 }"
:autosize="{ minRows: 2 }" />
/> </n-form-item>
</n-form-item>
<n-form-item label="Your string encoded :"> <n-form-item label="Your string encoded :">
<n-input <n-input
:value="encodeOutput" :value="encodeOutput"
type="textarea" type="textarea"
readonly readonly
placeholder="Your string encoded" placeholder="Your string encoded"
:autosize="{ minRows: 2 }" :autosize="{ minRows: 2 }"
/> />
</n-form-item> </n-form-item>
<n-space justify="center"> <n-space justify="center">
<n-button secondary @click="copyEncoded"> Copy </n-button> <n-button secondary @click="copyEncoded"> Copy </n-button>
</n-space> </n-space>
</n-card> </n-card>
<br /> <n-card title="Decode">
<n-card title="Decode"> <n-form-item
<n-form-item label="Your encoded string :"
label="Your encoded string :" :feedback="decodeValidation.message"
:feedback="decodeValidation.message" :validation-status="decodeValidation.status"
:validation-status="decodeValidation.status" >
> <n-input
<n-input v-model:value="decodeInput"
v-model:value="decodeInput" type="textarea"
type="textarea" placeholder="The string to decode"
placeholder="The string to decode" :autosize="{ minRows: 2 }"
:autosize="{ minRows: 2 }" />
/> </n-form-item>
</n-form-item>
<n-form-item label="Your string decoded :"> <n-form-item label="Your string decoded :">
<n-input <n-input
:value="decodeOutput" :value="decodeOutput"
type="textarea" type="textarea"
readonly readonly
placeholder="Your string decoded" placeholder="Your string decoded"
:autosize="{ minRows: 2 }" :autosize="{ minRows: 2 }"
/> />
</n-form-item> </n-form-item>
<n-space justify="center"> <n-space justify="center">
<n-button secondary @click="copyDecoded"> Copy </n-button> <n-button secondary @click="copyDecoded"> Copy </n-button>
</n-space> </n-space>
</n-card> </n-card>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">

View File

@@ -5,7 +5,7 @@ export const tool: ITool = {
name: 'Url parser', name: 'Url parser',
path: '/url-parser', path: '/url-parser',
description: description:
'Parse an url string to get all the differents parts (protocol, origin, params, port, username-password, ...)', 'Parse an url string to get all the different parts (protocol, origin, params, port, username-password, ...)',
keywords: ['url', 'parser', 'protocol', 'origin', 'params', 'port', 'username', 'password', 'href'], keywords: ['url', 'parser', 'protocol', 'origin', 'params', 'port', 'username', 'password', 'href'],
component: () => import('./url-parser.vue'), component: () => import('./url-parser.vue'),
icon: Unlink, icon: Unlink,