Compare commits

...

41 Commits

Author SHA1 Message Date
Corentin Thomasset
7a01af1c14 chore(release): 2.5.1 2022-06-02 01:00:49 +02:00
Corentin Thomasset
c2e1d59cb9 fix(title): trully reactive tool title 2022-06-02 00:59:42 +02:00
Corentin Thomasset
f48cd058cf fix: menu label key value was undefined 2022-06-02 00:57:17 +02:00
Corentin Thomasset
5ab4dd3d4a fix: tool sorting inconsistencies in home page 2022-06-02 00:44:23 +02:00
Corentin Thomasset
f05c8e1dc6 fix(lint): missing dangling comma 2022-06-02 00:30:43 +02:00
Corentin Thomasset
ba3b84c668 chore(release): 2.5.0 2022-06-02 00:26:10 +02:00
Corentin Thomasset
433ba2a3e5 feat(new-tool): math evaluator 2022-06-02 00:25:10 +02:00
Corentin Thomasset
8fb0e6af9c refactor: removed unused import 2022-06-02 00:11:49 +02:00
Corentin Thomasset
11720e6cde feat(tools): new badge for recently created tools 2022-06-02 00:11:49 +02:00
Corentin Thomasset
ac89490794 refactor: renammed Tool.ts to tool.ts 2022-06-02 00:11:49 +02:00
Corentin Thomasset
2f61c745f5 fix(config): updated env values loading 2022-06-01 09:08:46 +02:00
Corentin Thomasset
a9a6526e75 chore(deps): updated vitest version 2022-06-01 09:07:28 +02:00
Corentin Thomasset
af0b02d3a8 chore(release): 2.4.2 2022-06-01 08:50:10 +02:00
Corentin Thomasset
a46d125c19 refactor: set coerent head title for home page 2022-05-30 20:35:22 +02:00
Corentin Thomasset
6becdbb423 refactor(config): added config management with figue 2022-05-24 00:07:54 +02:00
Corentin Thomasset
5ce1262fb4 refactor(imports): removed useless defineProps import 2022-05-24 00:07:24 +02:00
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
59 changed files with 1099 additions and 444 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,100 @@
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.5.1](https://github.com/CorentinTh/it-tools/compare/v2.5.0...v2.5.1) (2022-06-01)
### Bug Fixes
* **lint:** missing dangling comma ([f05c8e1](https://github.com/CorentinTh/it-tools/commit/f05c8e1dc69275e529f4c8771ad55ba211e7fb5e))
* menu label key value was undefined ([f48cd05](https://github.com/CorentinTh/it-tools/commit/f48cd058cf3381f3bc92ea8fe37b565327707d1e))
* **title:** trully reactive tool title ([c2e1d59](https://github.com/CorentinTh/it-tools/commit/c2e1d59cb9d8dbb1bb072a46100192cb8c59f59b))
* tool sorting inconsistencies in home page ([5ab4dd3](https://github.com/CorentinTh/it-tools/commit/5ab4dd3d4a42c3609d72597c7ba91764170e6e96))
## [2.5.0](https://github.com/CorentinTh/it-tools/compare/v2.4.2...v2.5.0) (2022-06-01)
### Features
* **new-tool:** math evaluator ([433ba2a](https://github.com/CorentinTh/it-tools/commit/433ba2a3e5419eed0c96304b37693082224a1c73))
* **tools:** new badge for recently created tools ([11720e6](https://github.com/CorentinTh/it-tools/commit/11720e6cdefc1da4bdd638415813b609840f8462))
### Bug Fixes
* **config:** updated env values loading ([2f61c74](https://github.com/CorentinTh/it-tools/commit/2f61c745f57962cf3bb9e2c1db4a3176df042808))
### Refactors
* removed unused import ([8fb0e6a](https://github.com/CorentinTh/it-tools/commit/8fb0e6af9c3be708d3f1777a1661e1b38f197a3f))
* renammed Tool.ts to tool.ts ([ac89490](https://github.com/CorentinTh/it-tools/commit/ac89490794ee3c1c033859ffea31a962a13cc96d))
### [2.4.2](https://github.com/CorentinTh/it-tools/compare/v2.4.1...v2.4.2) (2022-06-01)
### Refactors
* **config:** added config management with figue ([6becdbb](https://github.com/CorentinTh/it-tools/commit/6becdbb42329e1bdecf158707e37ba9f13ba1d2c))
* **imports:** removed useless defineProps import ([5ce1262](https://github.com/CorentinTh/it-tools/commit/5ce1262fb44864b829dac09d5c0b9b68d522ceb7))
* set coerent head title for home page ([a46d125](https://github.com/CorentinTh/it-tools/commit/a46d125c19902c2f41f37c62c07bb7b548d9f6f0))
### [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) ### [2.3.1](https://github.com/CorentinTh/it-tools/compare/v2.3.0...v2.3.1) (2022-04-24)

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,12 +4,12 @@
<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" />
@@ -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>

400
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "it-tools", "name": "it-tools",
"version": "2.3.1", "version": "2.5.1",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "it-tools", "name": "it-tools",
"version": "2.3.1", "version": "2.5.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,7 +20,10 @@
"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",
"figue": "^1.2.0",
"highlight.js": "^11.5.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mathjs": "^10.6.0",
"naive-ui": "^2.28.0", "naive-ui": "^2.28.0",
"pinia": "^2.0.11", "pinia": "^2.0.11",
"plausible-tracker": "^0.3.5", "plausible-tracker": "^0.3.5",
@@ -58,7 +61,7 @@
"vite-plugin-md": "^0.12.4", "vite-plugin-md": "^0.12.4",
"vite-plugin-pwa": "^0.11.13", "vite-plugin-pwa": "^0.11.13",
"vite-svg-loader": "^3.2.0", "vite-svg-loader": "^3.2.0",
"vitest": "^0.5.0", "vitest": "^0.13.1",
"vue-tsc": "^0.31.4" "vue-tsc": "^0.31.4"
} }
}, },
@@ -1641,7 +1644,6 @@
"version": "7.17.9", "version": "7.17.9",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz",
"integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==",
"dev": true,
"dependencies": { "dependencies": {
"regenerator-runtime": "^0.13.4" "regenerator-runtime": "^0.13.4"
}, },
@@ -2122,9 +2124,9 @@
"dev": true "dev": true
}, },
"node_modules/@types/chai": { "node_modules/@types/chai": {
"version": "4.3.0", "version": "4.3.1",
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.0.tgz", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.1.tgz",
"integrity": "sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==", "integrity": "sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ==",
"dev": true "dev": true
}, },
"node_modules/@types/chai-subset": { "node_modules/@types/chai-subset": {
@@ -3101,6 +3103,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",
@@ -3472,7 +3480,7 @@
"node_modules/check-error": { "node_modules/check-error": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": "*" "node": "*"
@@ -3550,6 +3558,18 @@
"dot-prop": "^5.1.0" "dot-prop": "^5.1.0"
} }
}, },
"node_modules/complex.js": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.1.1.tgz",
"integrity": "sha512-8njCHOTtFFLtegk6zQo0kkVX1rngygb/KQI6z1qZxlFI3scluC+LVTCFbrkWjBv4vvLlbQ9t88IPMC6k95VTTg==",
"engines": {
"node": "*"
},
"funding": {
"type": "patreon",
"url": "https://www.patreon.com/infusion"
}
},
"node_modules/concat-map": { "node_modules/concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -4156,8 +4176,7 @@
"node_modules/decimal.js": { "node_modules/decimal.js": {
"version": "10.3.1", "version": "10.3.1",
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz",
"integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ=="
"dev": true
}, },
"node_modules/deep-eql": { "node_modules/deep-eql": {
"version": "3.0.1", "version": "3.0.1",
@@ -4459,12 +4478,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"
@@ -4948,6 +4967,11 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/escape-latex": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz",
"integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw=="
},
"node_modules/escape-string-regexp": { "node_modules/escape-string-regexp": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@@ -5514,6 +5538,17 @@
"reusify": "^1.0.4" "reusify": "^1.0.4"
} }
}, },
"node_modules/figue": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/figue/-/figue-1.2.0.tgz",
"integrity": "sha512-CXKr12kiNWjKtUK3X+YHeXKepn80s9Rg6pgZXoLQYEybgwaGJ9uGW4DrBrVK30ZWZf1mcvTbXF56AcovG7gLVw==",
"dependencies": {
"lodash": "^4.17.21"
},
"funding": {
"url": "https://github.com/sponsors/CorentinTh"
}
},
"node_modules/figures": { "node_modules/figures": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
@@ -5542,12 +5577,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": {
@@ -5630,6 +5686,18 @@
"node": ">=8.0.0" "node": ">=8.0.0"
} }
}, },
"node_modules/fraction.js": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
"integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==",
"engines": {
"node": "*"
},
"funding": {
"type": "patreon",
"url": "https://www.patreon.com/infusion"
}
},
"node_modules/from": { "node_modules/from": {
"version": "0.1.7", "version": "0.1.7",
"resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
@@ -5724,7 +5792,7 @@
"node_modules/get-func-name": { "node_modules/get-func-name": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
"integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": "*" "node": "*"
@@ -6704,12 +6772,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 +6804,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",
@@ -6779,6 +6841,11 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/javascript-natural-sort": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz",
"integrity": "sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k="
},
"node_modules/jest-diff": { "node_modules/jest-diff": {
"version": "27.5.1", "version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz",
@@ -7483,6 +7550,28 @@
"url": "https://github.com/fb55/entities?sponsor=1" "url": "https://github.com/fb55/entities?sponsor=1"
} }
}, },
"node_modules/mathjs": {
"version": "10.6.0",
"resolved": "https://registry.npmjs.org/mathjs/-/mathjs-10.6.0.tgz",
"integrity": "sha512-4oI0CSX7LtcyexTSLV8uo+llj8hB5LvVE9ApjN6rBjBplQaZ4/Gr3jh0zEla9+KaCig5wonZ9oFKD+GKXFL8hg==",
"dependencies": {
"@babel/runtime": "^7.17.9",
"complex.js": "^2.1.1",
"decimal.js": "^10.3.1",
"escape-latex": "^1.2.0",
"fraction.js": "^4.2.0",
"javascript-natural-sort": "^0.7.1",
"seedrandom": "^3.0.5",
"tiny-emitter": "^2.1.0",
"typed-function": "^2.1.0"
},
"bin": {
"mathjs": "bin/cli.js"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/mdn-data": { "node_modules/mdn-data": {
"version": "2.0.14", "version": "2.0.14",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
@@ -7835,9 +7924,9 @@
} }
}, },
"node_modules/nanoid": { "node_modules/nanoid": {
"version": "3.3.2", "version": "3.3.4",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.2.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
"integrity": "sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==", "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
"bin": { "bin": {
"nanoid": "bin/nanoid.cjs" "nanoid": "bin/nanoid.cjs"
}, },
@@ -8325,9 +8414,9 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.12", "version": "8.4.14",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.12.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
"integrity": "sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==", "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@@ -8339,7 +8428,7 @@
} }
], ],
"dependencies": { "dependencies": {
"nanoid": "^3.3.1", "nanoid": "^3.3.4",
"picocolors": "^1.0.0", "picocolors": "^1.0.0",
"source-map-js": "^1.0.2" "source-map-js": "^1.0.2"
}, },
@@ -8985,8 +9074,7 @@
"node_modules/regenerator-runtime": { "node_modules/regenerator-runtime": {
"version": "0.13.9", "version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
"dev": true
}, },
"node_modules/regenerator-transform": { "node_modules/regenerator-transform": {
"version": "0.15.0", "version": "0.15.0",
@@ -9253,6 +9341,11 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/seedrandom": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
"integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg=="
},
"node_modules/seemly": { "node_modules/seemly": {
"version": "0.3.3", "version": "0.3.3",
"resolved": "https://registry.npmjs.org/seemly/-/seemly-0.3.3.tgz", "resolved": "https://registry.npmjs.org/seemly/-/seemly-0.3.3.tgz",
@@ -9956,19 +10049,24 @@
"readable-stream": "3" "readable-stream": "3"
} }
}, },
"node_modules/tiny-emitter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
},
"node_modules/tinypool": { "node_modules/tinypool": {
"version": "0.1.2", "version": "0.1.3",
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.1.2.tgz", "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.1.3.tgz",
"integrity": "sha512-fvtYGXoui2RpeMILfkvGIgOVkzJEGediv8UJt7TxdAOY8pnvUkFg/fkvqTfXG9Acc9S17Cnn1S4osDc2164guA==", "integrity": "sha512-2IfcQh7CP46XGWGGbdyO4pjcKqsmVqFAPcXfPxcPXmOWt9cYkTP9HcDmGgsfijYoAEc4z9qcpM/BaBz46Y9/CQ==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=14.0.0" "node": ">=14.0.0"
} }
}, },
"node_modules/tinyspy": { "node_modules/tinyspy": {
"version": "0.3.0", "version": "0.3.2",
"resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-0.3.0.tgz", "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-0.3.2.tgz",
"integrity": "sha512-c5uFHqtUp74R2DJE3/Efg0mH5xicmgziaQXMm/LvuuZn3RdpADH32aEGDRyCzObXT1DNfwDMqRQ/Drh1MlO12g==", "integrity": "sha512-2+40EP4D3sFYy42UkgkFFB+kiX2Tg3URG/lVvAZFfLxgGpnWl5qQJuBw1gaLttq8UOS+2p3C0WrhJnQigLTT2Q==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=14.0.0" "node": ">=14.0.0"
@@ -10074,6 +10172,14 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/typed-function": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/typed-function/-/typed-function-2.1.0.tgz",
"integrity": "sha512-bctQIOqx2iVbWGDGPWwIm18QScpu2XRmkC19D8rQGFsjKSgteq/o1hTZvIG/wuDq8fanpBDrLkLq+aEN/6y5XQ==",
"engines": {
"node": ">= 10"
}
},
"node_modules/typedarray": { "node_modules/typedarray": {
"version": "0.0.6", "version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
@@ -10293,13 +10399,13 @@
"integrity": "sha512-nguyw8L6Un8eelg1vQ31vIU2ESxqid7EYmy8V+MDeMaHBqaRSkg3dTBToC1PR00D89UzS/SLkfYPnx0Wf23IQQ==" "integrity": "sha512-nguyw8L6Un8eelg1vQ31vIU2ESxqid7EYmy8V+MDeMaHBqaRSkg3dTBToC1PR00D89UzS/SLkfYPnx0Wf23IQQ=="
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "2.9.1", "version": "2.9.9",
"resolved": "https://registry.npmjs.org/vite/-/vite-2.9.1.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.9.tgz",
"integrity": "sha512-vSlsSdOYGcYEJfkQ/NeLXgnRv5zZfpAsdztkIrs7AZHV8RCMZQkwjo4DS5BnrYTqoWqLoUe1Cah4aVO4oNNqCQ==", "integrity": "sha512-ffaam+NgHfbEmfw/Vuh6BHKKlI/XIAhxE5QSS7gFLIngxg171mg1P3a4LSRME0z2ZU1ScxoKzphkipcYwSD5Ew==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"esbuild": "^0.14.27", "esbuild": "^0.14.27",
"postcss": "^8.4.12", "postcss": "^8.4.13",
"resolve": "^1.22.0", "resolve": "^1.22.0",
"rollup": "^2.59.0" "rollup": "^2.59.0"
}, },
@@ -10382,24 +10488,25 @@
} }
}, },
"node_modules/vitest": { "node_modules/vitest": {
"version": "0.5.9", "version": "0.13.1",
"resolved": "https://registry.npmjs.org/vitest/-/vitest-0.5.9.tgz", "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.13.1.tgz",
"integrity": "sha512-R8lRP9Q1yIbwr8pDf2gvw4PFe8H5YMyHhBcdyfnUh6toLfCR10jrdI/WkNxdo5I4H/9XrMX9t+SAavdJExNdKg==", "integrity": "sha512-CfSBf7YFw/i8HumSUQRtZKs0aV91DC9WU8nAgIJAlawKHaFuPHQohDwOTPIFgrxySiuFYUa0Yohf9gDFfBwjxA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/chai": "^4.3.0", "@types/chai": "^4.3.1",
"@types/chai-subset": "^1.3.3", "@types/chai-subset": "^1.3.3",
"chai": "^4.3.6", "chai": "^4.3.6",
"debug": "^4.3.4",
"local-pkg": "^0.4.1", "local-pkg": "^0.4.1",
"tinypool": "^0.1.2", "tinypool": "^0.1.3",
"tinyspy": "^0.3.0", "tinyspy": "^0.3.2",
"vite": "^2.7.10" "vite": "^2.9.9"
}, },
"bin": { "bin": {
"vitest": "vitest.mjs" "vitest": "vitest.mjs"
}, },
"engines": { "engines": {
"node": ">=14.14.0" "node": ">=v14.16.0"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/antfu" "url": "https://github.com/sponsors/antfu"
@@ -12391,7 +12498,6 @@
"version": "7.17.9", "version": "7.17.9",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz",
"integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==",
"dev": true,
"requires": { "requires": {
"regenerator-runtime": "^0.13.4" "regenerator-runtime": "^0.13.4"
} }
@@ -12776,9 +12882,9 @@
"dev": true "dev": true
}, },
"@types/chai": { "@types/chai": {
"version": "4.3.0", "version": "4.3.1",
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.0.tgz", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.1.tgz",
"integrity": "sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==", "integrity": "sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ==",
"dev": true "dev": true
}, },
"@types/chai-subset": { "@types/chai-subset": {
@@ -13541,6 +13647,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",
@@ -13831,7 +13943,7 @@
"check-error": { "check-error": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==",
"dev": true "dev": true
}, },
"check-more-types": { "check-more-types": {
@@ -13894,6 +14006,11 @@
"dot-prop": "^5.1.0" "dot-prop": "^5.1.0"
} }
}, },
"complex.js": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.1.1.tgz",
"integrity": "sha512-8njCHOTtFFLtegk6zQo0kkVX1rngygb/KQI6z1qZxlFI3scluC+LVTCFbrkWjBv4vvLlbQ9t88IPMC6k95VTTg=="
},
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -14377,8 +14494,7 @@
"decimal.js": { "decimal.js": {
"version": "10.3.1", "version": "10.3.1",
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz",
"integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ=="
"dev": true
}, },
"deep-eql": { "deep-eql": {
"version": "3.0.1", "version": "3.0.1",
@@ -14605,12 +14721,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": {
@@ -14877,6 +14993,11 @@
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
"dev": true "dev": true
}, },
"escape-latex": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz",
"integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw=="
},
"escape-string-regexp": { "escape-string-regexp": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@@ -15292,6 +15413,14 @@
"reusify": "^1.0.4" "reusify": "^1.0.4"
} }
}, },
"figue": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/figue/-/figue-1.2.0.tgz",
"integrity": "sha512-CXKr12kiNWjKtUK3X+YHeXKepn80s9Rg6pgZXoLQYEybgwaGJ9uGW4DrBrVK30ZWZf1mcvTbXF56AcovG7gLVw==",
"requires": {
"lodash": "^4.17.21"
}
},
"figures": { "figures": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
@@ -15311,12 +15440,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": {
@@ -15370,6 +15519,11 @@
"signal-exit": "^3.0.2" "signal-exit": "^3.0.2"
} }
}, },
"fraction.js": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
"integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA=="
},
"from": { "from": {
"version": "0.1.7", "version": "0.1.7",
"resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
@@ -15442,7 +15596,7 @@
"get-func-name": { "get-func-name": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
"integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==",
"dev": true "dev": true
}, },
"get-intrinsic": { "get-intrinsic": {
@@ -16167,12 +16321,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 +16341,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",
@@ -16220,6 +16368,11 @@
} }
} }
}, },
"javascript-natural-sort": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz",
"integrity": "sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k="
},
"jest-diff": { "jest-diff": {
"version": "27.5.1", "version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz",
@@ -16772,6 +16925,22 @@
} }
} }
}, },
"mathjs": {
"version": "10.6.0",
"resolved": "https://registry.npmjs.org/mathjs/-/mathjs-10.6.0.tgz",
"integrity": "sha512-4oI0CSX7LtcyexTSLV8uo+llj8hB5LvVE9ApjN6rBjBplQaZ4/Gr3jh0zEla9+KaCig5wonZ9oFKD+GKXFL8hg==",
"requires": {
"@babel/runtime": "^7.17.9",
"complex.js": "^2.1.1",
"decimal.js": "^10.3.1",
"escape-latex": "^1.2.0",
"fraction.js": "^4.2.0",
"javascript-natural-sort": "^0.7.1",
"seedrandom": "^3.0.5",
"tiny-emitter": "^2.1.0",
"typed-function": "^2.1.0"
}
},
"mdn-data": { "mdn-data": {
"version": "2.0.14", "version": "2.0.14",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
@@ -17043,9 +17212,9 @@
} }
}, },
"nanoid": { "nanoid": {
"version": "3.3.2", "version": "3.3.4",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.2.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
"integrity": "sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==" "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw=="
}, },
"natural-compare": { "natural-compare": {
"version": "1.4.0", "version": "1.4.0",
@@ -17393,11 +17562,11 @@
"integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==" "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw=="
}, },
"postcss": { "postcss": {
"version": "8.4.12", "version": "8.4.14",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.12.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
"integrity": "sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==", "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
"requires": { "requires": {
"nanoid": "^3.3.1", "nanoid": "^3.3.4",
"picocolors": "^1.0.0", "picocolors": "^1.0.0",
"source-map-js": "^1.0.2" "source-map-js": "^1.0.2"
} }
@@ -17907,8 +18076,7 @@
"regenerator-runtime": { "regenerator-runtime": {
"version": "0.13.9", "version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
"dev": true
}, },
"regenerator-transform": { "regenerator-transform": {
"version": "0.15.0", "version": "0.15.0",
@@ -18102,6 +18270,11 @@
"kind-of": "^6.0.0" "kind-of": "^6.0.0"
} }
}, },
"seedrandom": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
"integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg=="
},
"seemly": { "seemly": {
"version": "0.3.3", "version": "0.3.3",
"resolved": "https://registry.npmjs.org/seemly/-/seemly-0.3.3.tgz", "resolved": "https://registry.npmjs.org/seemly/-/seemly-0.3.3.tgz",
@@ -18648,16 +18821,21 @@
"readable-stream": "3" "readable-stream": "3"
} }
}, },
"tiny-emitter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
},
"tinypool": { "tinypool": {
"version": "0.1.2", "version": "0.1.3",
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.1.2.tgz", "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.1.3.tgz",
"integrity": "sha512-fvtYGXoui2RpeMILfkvGIgOVkzJEGediv8UJt7TxdAOY8pnvUkFg/fkvqTfXG9Acc9S17Cnn1S4osDc2164guA==", "integrity": "sha512-2IfcQh7CP46XGWGGbdyO4pjcKqsmVqFAPcXfPxcPXmOWt9cYkTP9HcDmGgsfijYoAEc4z9qcpM/BaBz46Y9/CQ==",
"dev": true "dev": true
}, },
"tinyspy": { "tinyspy": {
"version": "0.3.0", "version": "0.3.2",
"resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-0.3.0.tgz", "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-0.3.2.tgz",
"integrity": "sha512-c5uFHqtUp74R2DJE3/Efg0mH5xicmgziaQXMm/LvuuZn3RdpADH32aEGDRyCzObXT1DNfwDMqRQ/Drh1MlO12g==", "integrity": "sha512-2+40EP4D3sFYy42UkgkFFB+kiX2Tg3URG/lVvAZFfLxgGpnWl5qQJuBw1gaLttq8UOS+2p3C0WrhJnQigLTT2Q==",
"dev": true "dev": true
}, },
"to-fast-properties": { "to-fast-properties": {
@@ -18738,6 +18916,11 @@
"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
"dev": true "dev": true
}, },
"typed-function": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/typed-function/-/typed-function-2.1.0.tgz",
"integrity": "sha512-bctQIOqx2iVbWGDGPWwIm18QScpu2XRmkC19D8rQGFsjKSgteq/o1hTZvIG/wuDq8fanpBDrLkLq+aEN/6y5XQ=="
},
"typedarray": { "typedarray": {
"version": "0.0.6", "version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
@@ -18909,14 +19092,14 @@
"integrity": "sha512-nguyw8L6Un8eelg1vQ31vIU2ESxqid7EYmy8V+MDeMaHBqaRSkg3dTBToC1PR00D89UzS/SLkfYPnx0Wf23IQQ==" "integrity": "sha512-nguyw8L6Un8eelg1vQ31vIU2ESxqid7EYmy8V+MDeMaHBqaRSkg3dTBToC1PR00D89UzS/SLkfYPnx0Wf23IQQ=="
}, },
"vite": { "vite": {
"version": "2.9.1", "version": "2.9.9",
"resolved": "https://registry.npmjs.org/vite/-/vite-2.9.1.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.9.tgz",
"integrity": "sha512-vSlsSdOYGcYEJfkQ/NeLXgnRv5zZfpAsdztkIrs7AZHV8RCMZQkwjo4DS5BnrYTqoWqLoUe1Cah4aVO4oNNqCQ==", "integrity": "sha512-ffaam+NgHfbEmfw/Vuh6BHKKlI/XIAhxE5QSS7gFLIngxg171mg1P3a4LSRME0z2ZU1ScxoKzphkipcYwSD5Ew==",
"dev": true, "dev": true,
"requires": { "requires": {
"esbuild": "^0.14.27", "esbuild": "^0.14.27",
"fsevents": "~2.3.2", "fsevents": "~2.3.2",
"postcss": "^8.4.12", "postcss": "^8.4.13",
"resolve": "^1.22.0", "resolve": "^1.22.0",
"rollup": "^2.59.0" "rollup": "^2.59.0"
} }
@@ -18960,18 +19143,19 @@
} }
}, },
"vitest": { "vitest": {
"version": "0.5.9", "version": "0.13.1",
"resolved": "https://registry.npmjs.org/vitest/-/vitest-0.5.9.tgz", "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.13.1.tgz",
"integrity": "sha512-R8lRP9Q1yIbwr8pDf2gvw4PFe8H5YMyHhBcdyfnUh6toLfCR10jrdI/WkNxdo5I4H/9XrMX9t+SAavdJExNdKg==", "integrity": "sha512-CfSBf7YFw/i8HumSUQRtZKs0aV91DC9WU8nAgIJAlawKHaFuPHQohDwOTPIFgrxySiuFYUa0Yohf9gDFfBwjxA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/chai": "^4.3.0", "@types/chai": "^4.3.1",
"@types/chai-subset": "^1.3.3", "@types/chai-subset": "^1.3.3",
"chai": "^4.3.6", "chai": "^4.3.6",
"debug": "^4.3.4",
"local-pkg": "^0.4.1", "local-pkg": "^0.4.1",
"tinypool": "^0.1.2", "tinypool": "^0.1.3",
"tinyspy": "^0.3.0", "tinyspy": "^0.3.2",
"vite": "^2.7.10" "vite": "^2.9.9"
} }
}, },
"void-elements": { "void-elements": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "it-tools", "name": "it-tools",
"version": "2.3.1", "version": "2.5.1",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vue-tsc --noEmit && vite build", "build": "vue-tsc --noEmit && vite build",
@@ -25,7 +25,10 @@
"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",
"figue": "^1.2.0",
"highlight.js": "^11.5.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mathjs": "^10.6.0",
"naive-ui": "^2.28.0", "naive-ui": "^2.28.0",
"pinia": "^2.0.11", "pinia": "^2.0.11",
"plausible-tracker": "^0.3.5", "plausible-tracker": "^0.3.5",
@@ -63,7 +66,7 @@
"vite-plugin-md": "^0.12.4", "vite-plugin-md": "^0.12.4",
"vite-plugin-pwa": "^0.11.13", "vite-plugin-pwa": "^0.11.13",
"vite-svg-loader": "^3.2.0", "vite-svg-loader": "^3.2.0",
"vitest": "^0.5.0", "vitest": "^0.13.1",
"vue-tsc": "^0.31.4" "vue-tsc": "^0.31.4"
} }
} }

View File

@@ -39,16 +39,16 @@ createToolFile(
<style lang="less" scoped> <style lang="less" scoped>
</style> </style>
` `,
); );
createToolFile( createToolFile(
`index.ts`, `index.ts`,
` `
import { ArrowsShuffle } from '@vicons/tabler'; import { ArrowsShuffle } from '@vicons/tabler';
import type { ITool } from './../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
name: '${toolNameTitleCase}', name: '${toolNameTitleCase}',
path: '/${toolName}', path: '/${toolName}',
description: '', description: '',
@@ -56,7 +56,7 @@ export const tool: ITool = {
component: () => import('./${toolName}.vue'), component: () => import('./${toolName}.vue'),
icon: ArrowsShuffle, icon: ArrowsShuffle,
}; };
` `,
); );
createToolFile(`${toolName}.service.ts`, ``); createToolFile(`${toolName}.service.ts`, ``);
@@ -69,7 +69,7 @@ import { expect, describe, it } from 'vitest';
// describe('${toolName}', () => { // describe('${toolName}', () => {
// //
// }) // })
` `,
); );
const toolsIndex = join(toolsDir, 'index.ts'); const toolsIndex = join(toolsDir, 'index.ts');

View File

@@ -0,0 +1,36 @@
<template>
<div class="menu-icon-item">
<n-icon :component="tool.icon" />
<div v-if="tool.isNew" class="badge"></div>
</div>
</template>
<script setup lang="ts">
import type { ITool } from '@/tools/tool';
import { useThemeVars } from 'naive-ui';
import { toRefs } from 'vue';
const props = defineProps<{ tool: ITool }>();
const { tool } = toRefs(props);
const theme = useThemeVars();
</script>
<style lang="less" scoped>
.menu-icon-item {
position: relative;
.badge {
position: absolute;
background-color: v-bind('theme.primaryColor');
border-radius: 10px;
line-height: 1;
top: 3px;
left: -6px;
font-size: 10px;
height: 6px;
width: 6px;
}
}
</style>

View File

@@ -1,10 +1,24 @@
<template> <template>
<router-link :to="tool.path"> <router-link :to="tool.path">
<n-card class="tool-card"> <n-card class="tool-card">
<n-space justify="space-between" align="center">
<n-icon class="icon" size="40" :component="tool.icon" /> <n-icon class="icon" size="40" :component="tool.icon" />
<n-tag
v-if="tool.isNew"
size="small"
class="badge-new"
round
type="success"
:bordered="false"
:color="{ color: theme.primaryColor, textColor: theme.tagColor }"
>
New
</n-tag>
</n-space>
<n-h3 class="title"> <n-h3 class="title">
<n-ellipsis>{{ tool.name }}</n-ellipsis> <n-ellipsis>{{ tool.name }}</n-ellipsis>
</n-h3> </n-h3>
<div class="description"> <div class="description">
<n-ellipsis :line-clamp="2" :tooltip="false"> <n-ellipsis :line-clamp="2" :tooltip="false">
{{ tool.description }} {{ tool.description }}
@@ -15,11 +29,13 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { ITool } from '@/tools/Tool'; import type { ITool } from '@/tools/tool';
import { toRefs, defineProps } from 'vue'; import { useThemeVars } from 'naive-ui';
import { toRefs } from 'vue';
const props = defineProps<{ tool: ITool & { category: string } }>(); const props = defineProps<{ tool: ITool & { category: string } }>();
const { tool } = toRefs(props); const { tool } = toRefs(props);
const theme = useThemeVars();
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

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';
} }

65
src/config.ts Normal file
View File

@@ -0,0 +1,65 @@
import { figue } from 'figue';
export const config = figue({
app: {
version: {
doc: 'Application current version',
format: 'string',
default: '0.0.0',
env: 'PACKAGE_VERSION',
},
lastCommitSha: {
doc: 'Application last commit SHA version',
format: 'string',
default: '',
env: 'VITE_VERCEL_GIT_COMMIT_SHA',
},
baseUrl: {
doc: 'Application base url',
format: 'string',
default: '/',
env: 'BASE_URL',
},
env: {
doc: 'Application current env',
format: 'enum',
values: ['production', 'development', 'test'],
default: 'development',
env: 'MODE',
},
},
plausible: {
domain: {
doc: 'Plausible current domain',
format: 'string',
default: '',
env: 'VITE_PLAUSIBLE_DOMAIN',
},
apiHost: {
doc: 'Plausible remote api host',
format: 'string',
default: '',
env: 'VITE_PLAUSIBLE_API_HOST',
},
trackLocalhost: {
doc: 'Enable or disable localhost tracking by plausible',
format: 'boolean',
default: false,
},
},
tools: {
newTools: {
doc: 'Tool names for tools flagged a as new',
format: 'array',
default: [],
env: 'VITE_NEW_TOOLS',
},
},
})
.loadEnv({
...import.meta.env,
// Because the string 'import.meta.env.PACKAGE_VERSION' is statically replaced during build time (see 'define' in vite.config.ts)
PACKAGE_VERSION: import.meta.env.PACKAGE_VERSION,
})
.validate()
.getConfig();

View File

@@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { NIcon, useThemeVars } from 'naive-ui'; import { NIcon, useThemeVars, type MenuGroupOption } from 'naive-ui';
import { h, type Component } from 'vue'; import { h } from 'vue';
import { RouterLink, useRoute } from 'vue-router'; import { RouterLink, useRoute } from 'vue-router';
import { Heart, Menu2, Home2 } from '@vicons/tabler'; import { Heart, Menu2, Home2 } from '@vicons/tabler';
import { toolsByCategory } from '@/tools'; import { toolsByCategory } from '@/tools';
@@ -9,24 +9,27 @@ import { useStyleStore } from '@/stores/style.store';
import HeroGradient from '../assets/hero-gradient.svg?component'; import HeroGradient from '../assets/hero-gradient.svg?component';
import MenuLayout from '../components/MenuLayout.vue'; import MenuLayout from '../components/MenuLayout.vue';
import NavbarButtons from '../components/NavbarButtons.vue'; import NavbarButtons from '../components/NavbarButtons.vue';
import { config } from '@/config';
import MenuIconItem from '@/components/MenuIconItem.vue';
import type { ITool } from '@/tools/tool';
const themeVars = useThemeVars(); const themeVars = useThemeVars();
const route = useRoute(); const route = useRoute();
const styleStore = useStyleStore(); const styleStore = useStyleStore();
const version = import.meta.env.PACKAGE_VERSION; const version = config.app.version;
const commitSha = import.meta.env.GIT_SHORT_SHA; const commitSha = config.app.lastCommitSha.slice(0, 7);
const makeLabel = (text: string, to: string) => () => h(RouterLink, { to }, { default: () => text }); const makeLabel = (tool: ITool) => () => h(RouterLink, { to: tool.path }, { default: () => tool.name });
const makeIcon = (icon: Component) => () => h(NIcon, null, { default: () => h(icon) }); const makeIcon = (tool: ITool) => () => h(MenuIconItem, { tool });
const m = toolsByCategory.map((category) => ({ const menuOptions: MenuGroupOption[] = toolsByCategory.map((category) => ({
label: category.name, label: category.name,
key: category.name, key: category.name,
type: 'group', type: 'group',
children: category.components.map(({ name, path, icon }) => ({ children: category.components.map((tool) => ({
label: makeLabel(name, path), label: makeLabel(tool),
icon: makeIcon(icon), icon: makeIcon(tool),
key: name, key: tool.name,
})), })),
})); }));
</script> </script>
@@ -53,7 +56,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"
/> />
@@ -217,6 +220,11 @@ const m = toolsByCategory.map((category) => ({
} }
} }
// ::v-deep(.n-menu-item-content-header) {
// overflow: visible !important;
// // overflow-x: hidden !important;
// }
.navigation { .navigation {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@@ -3,11 +3,13 @@ import { useRoute } from 'vue-router';
import BaseLayout from './base.layout.vue'; import BaseLayout from './base.layout.vue';
import { useHead } from '@vueuse/head'; import { useHead } from '@vueuse/head';
import type { HeadObject } from '@vueuse/head'; import type { HeadObject } from '@vueuse/head';
import { reactive } from 'vue'; import { computed } from 'vue';
import { useThemeVars } from 'naive-ui';
const route = useRoute(); const route = useRoute();
const theme = useThemeVars();
const head = reactive<HeadObject>({ const head = computed<HeadObject>(() => ({
title: `${route.meta.name} - IT Tools`, title: `${route.meta.name} - IT Tools`,
meta: [ meta: [
{ {
@@ -19,7 +21,7 @@ const head = reactive<HeadObject>({
content: route.meta.keywords, content: route.meta.keywords,
}, },
], ],
}); }));
useHead(head); useHead(head);
</script> </script>
@@ -27,26 +29,56 @@ useHead(head);
<base-layout> <base-layout>
<div class="tool-layout"> <div class="tool-layout">
<div class="tool-header"> <div class="tool-header">
<n-h1>{{ route.meta.name }}</n-h1> <n-h1>
{{ route.meta.name }}
<n-tag
v-if="route.meta.isNew"
round
type="success"
:bordered="false"
:color="{ color: theme.primaryColor, textColor: theme.tagColor }"
>
New tool
</n-tag>
<!-- <span class="new-tool-badge">New !</span> -->
</n-h1>
<div class="separator" /> <div class="separator" />
<div class="description"> <div class="description">
{{ 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

@@ -3,13 +3,19 @@ import { toolsWithCategory } from '@/tools';
import ToolCard from '../components/ToolCard.vue'; import ToolCard from '../components/ToolCard.vue';
import { useHead } from '@vueuse/head'; import { useHead } from '@vueuse/head';
useHead({ title: 'IT Tools' }); useHead({ title: 'IT Tools - Handy online tools for developers' });
</script> </script>
<template> <template>
<div class="home-page"> <div class="home-page">
<n-grid x-gap="12" y-gap="12" cols="1 400:2 800:3 1200:4 2000:8"> <n-grid x-gap="12" y-gap="12" cols="1 400:2 800:3 1200:4 2000:8">
<n-gi v-for="tool in toolsWithCategory" :key="tool.name"> <n-gi
v-for="tool in [
...toolsWithCategory.filter(({ isNew }) => isNew),
...toolsWithCategory.filter(({ isNew }) => !isNew),
]"
:key="tool.name"
>
<tool-card :tool="tool" /> <tool-card :tool="tool" />
</n-gi> </n-gi>
</n-grid> </n-grid>

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

@@ -1,15 +1,10 @@
import Plausible, { type PlausibleOptions } from 'plausible-tracker'; import { config } from '@/config';
import Plausible from 'plausible-tracker';
import type { App } from 'vue'; import type { App } from 'vue';
const options: PlausibleOptions = {
domain: import.meta.env.VITE_PLAUSIBLE_DOMAIN,
apiHost: import.meta.env.VITE_PLAUSIBLE_API_HOST,
trackLocalhost: false,
};
export const plausible = { export const plausible = {
install: (app: App) => { install: (app: App) => {
const plausible = Plausible(options); const plausible = Plausible(config.plausible);
plausible.enableAutoPageviews(); plausible.enableAutoPageviews();
app.config.globalProperties.$plausible = plausible; app.config.globalProperties.$plausible = plausible;

View File

@@ -3,6 +3,7 @@ import { createRouter, createWebHistory } from 'vue-router';
import HomePage from './pages/Home.page.vue'; import HomePage from './pages/Home.page.vue';
import NotFound from './pages/404.page.vue'; import NotFound from './pages/404.page.vue';
import { tools } from './tools'; import { tools } from './tools';
import { config } from './config';
const toolsRoutes = tools.map(({ path, name, component, ...config }) => ({ const toolsRoutes = tools.map(({ path, name, component, ...config }) => ({
path, path,
@@ -17,7 +18,7 @@ const toolsRedirectRoutes = tools
); );
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(config.app.baseUrl),
routes: [ routes: [
{ {
path: '/', path: '/',

View File

@@ -1,17 +0,0 @@
import type { Component } from 'vue';
export interface ITool {
name: string;
path: string;
description: string;
keywords: string[];
component: () => Promise<Component>;
icon: Component;
redirectFrom?: string[];
}
export interface ToolCategory {
name: string;
icon: Component;
components: ITool[];
}

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

@@ -1,12 +1,12 @@
import { FileDigit } from '@vicons/tabler'; import { FileDigit } from '@vicons/tabler';
import type { ITool } from './../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
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

@@ -1,7 +1,7 @@
import { LockSquare } from '@vicons/tabler'; import { LockSquare } from '@vicons/tabler';
import type { ITool } from './../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
name: 'Bcrypt', name: 'Bcrypt',
path: '/bcrypt', path: '/bcrypt',
description: description:
@@ -9,4 +9,4 @@ export const tool: ITool = {
keywords: ['bcrypt', 'hash', 'compare', 'password', 'salt', 'round', 'storage', 'crypto'], keywords: ['bcrypt', 'hash', 'compare', 'password', 'salt', 'round', 'storage', 'crypto'],
component: () => import('./bcrypt.vue'), component: () => import('./bcrypt.vue'),
icon: LockSquare, icon: LockSquare,
}; });

View File

@@ -1,11 +1,11 @@
import { AlignJustified } from '@vicons/tabler'; import { AlignJustified } from '@vicons/tabler';
import type { ITool } from '../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
name: 'BIP39 passphrase generator', name: 'BIP39 passphrase generator',
path: '/bip39-generator', path: '/bip39-generator',
description: 'Generate BIP39 passphrase from existing or random mnemonic, or get the mnemonic from the passphrase.', description: 'Generate BIP39 passphrase from existing or random mnemonic, or get the mnemonic from the passphrase.',
keywords: ['BIP39', 'passphrase', 'generator', 'mnemonic', 'entropy'], keywords: ['BIP39', 'passphrase', 'generator', 'mnemonic', 'entropy'],
component: () => import('./bip39-generator.vue'), component: () => import('./bip39-generator.vue'),
icon: AlignJustified, icon: AlignJustified,
}; });

View File

@@ -1,7 +1,7 @@
import { LetterCaseToggle } from '@vicons/tabler'; import { LetterCaseToggle } from '@vicons/tabler';
import type { ITool } from './../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
name: 'Case converter', name: 'Case converter',
path: '/case-converter', path: '/case-converter',
description: 'Change the case of a string and chose between different formats', description: 'Change the case of a string and chose between different formats',
@@ -22,4 +22,4 @@ export const tool: ITool = {
], ],
component: () => import('./case-converter.vue'), component: () => import('./case-converter.vue'),
icon: LetterCaseToggle, icon: LetterCaseToggle,
}; });

View File

@@ -1,7 +1,7 @@
import { Palette } from '@vicons/tabler'; import { Palette } from '@vicons/tabler';
import type { ITool } from './../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
name: 'Color converter', name: 'Color converter',
path: '/color-converter', path: '/color-converter',
description: 'Convert color between the different formats (hex, rgb, hsl and css name)', description: 'Convert color between the different formats (hex, rgb, hsl and css name)',
@@ -9,4 +9,4 @@ export const tool: ITool = {
component: () => import('./color-converter.vue'), component: () => import('./color-converter.vue'),
icon: Palette, icon: Palette,
redirectFrom: ['/color-picker-converter'], redirectFrom: ['/color-picker-converter'],
}; });

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

@@ -1,7 +1,7 @@
import { Alarm } from '@vicons/tabler'; import { Alarm } from '@vicons/tabler';
import type { ITool } from './../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
name: 'Crontab generator', name: 'Crontab generator',
path: '/crontab-generator', path: '/crontab-generator',
description: 'Validate and generate crontab and get the human readable description of the cron schedule.', description: 'Validate and generate crontab and get the human readable description of the cron schedule.',
@@ -22,4 +22,4 @@ export const tool: ITool = {
], ],
component: () => import('./crontab-generator.vue'), component: () => import('./crontab-generator.vue'),
icon: Alarm, icon: Alarm,
}; });

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

@@ -1,11 +1,11 @@
import { Calendar } from '@vicons/tabler'; import { Calendar } from '@vicons/tabler';
import type { ITool } from '../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
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,7 +1,7 @@
import { DeviceDesktop } from '@vicons/tabler'; import { DeviceDesktop } from '@vicons/tabler';
import type { ITool } from './../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
name: 'Device information', name: 'Device information',
path: '/device-information', path: '/device-information',
description: 'Get information about your current device (screen size, pixel-ratio, user agent, ...)', description: 'Get information about your current device (screen size, pixel-ratio, user agent, ...)',
@@ -20,4 +20,4 @@ export const tool: ITool = {
], ],
component: () => import('./device-information.vue'), component: () => import('./device-information.vue'),
icon: DeviceDesktop, icon: DeviceDesktop,
}; });

View File

@@ -1,5 +1,4 @@
<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">
@@ -23,7 +22,7 @@
</n-space> </n-space>
</n-space> </n-space>
<br /> <br />
<n-form-item label="Yout text encrypted:" :show-feedback="false"> <n-form-item label="Your text encrypted:" :show-feedback="false">
<n-input <n-input
:value="cypherOutput" :value="cypherOutput"
type="textarea" type="textarea"
@@ -37,7 +36,6 @@
/> />
</n-form-item> </n-form-item>
</n-card> </n-card>
<br />
<n-card title="Decrypt"> <n-card title="Decrypt">
<n-space item-style="flex: 1 1 0"> <n-space item-style="flex: 1 1 0">
<n-form-item label="Your encrypted text:" :show-feedback="false"> <n-form-item label="Your encrypted text:" :show-feedback="false">
@@ -61,7 +59,7 @@
</n-space> </n-space>
</n-space> </n-space>
<br /> <br />
<n-form-item label="Yout decrypted text:" :show-feedback="false"> <n-form-item label="Your decrypted text:" :show-feedback="false">
<n-input <n-input
:value="decryptOutput" :value="decryptOutput"
type="textarea" type="textarea"
@@ -75,7 +73,6 @@
/> />
</n-form-item> </n-form-item>
</n-card> </n-card>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">

View File

@@ -1,12 +1,12 @@
import { Lock } from '@vicons/tabler'; import { Lock } from '@vicons/tabler';
import type { ITool } from '../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
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

@@ -1,12 +1,12 @@
import { BrandGit } from '@vicons/tabler'; import { BrandGit } from '@vicons/tabler';
import type { ITool } from '../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
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

@@ -1,7 +1,7 @@
import { EyeOff } from '@vicons/tabler'; import { EyeOff } from '@vicons/tabler';
import type { ITool } from '../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
name: 'Hash text', name: 'Hash text',
path: '/hash-text', path: '/hash-text',
description: description:
@@ -24,4 +24,4 @@ export const tool: ITool = {
component: () => import('./hash-text.vue'), component: () => import('./hash-text.vue'),
icon: EyeOff, icon: EyeOff,
redirectFrom: ['/hash'], redirectFrom: ['/hash'],
}; });

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,11 +1,11 @@
import { Code } from '@vicons/tabler'; import { Code } from '@vicons/tabler';
import type { ITool } from './../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
name: 'Escape html entities', name: 'Escape html entities',
path: '/html-entities', path: '/html-entities',
description: 'Escape or unescape html entities (replace <,>, &, " and \' to their html version)', description: 'Escape or unescape html entities (replace <,>, &, " and \' to their html version)',
keywords: ['html', 'entities', 'escape', 'unescape', 'special', 'characters', 'tags'], keywords: ['html', 'entities', 'escape', 'unescape', 'special', 'characters', 'tags'],
component: () => import('./html-entities.vue'), component: () => import('./html-entities.vue'),
icon: Code, icon: Code,
}; });

View File

@@ -1,6 +1,8 @@
import { LockOpen } from '@vicons/tabler'; import { LockOpen } from '@vicons/tabler';
import type { ToolCategory } from './Tool'; import type { ToolCategory } from './tool';
import { tool as mathEvaluator } from './math-evaluator';
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 +52,12 @@ export const toolsByCategory: ToolCategory[] = [
{ {
name: 'Development', name: 'Development',
icon: LockOpen, icon: LockOpen,
components: [gitMemo, randomPortGenerator, crontabGenerator], components: [gitMemo, randomPortGenerator, crontabGenerator, jsonViewer],
},
{
name: 'Math',
icon: LockOpen,
components: [mathEvaluator],
}, },
{ {
name: 'Text', name: 'Text',

View File

@@ -1,11 +1,11 @@
import { ArrowsLeftRight } from '@vicons/tabler'; import { ArrowsLeftRight } from '@vicons/tabler';
import type { ITool } from '../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
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>
<div v-if="styleStore.isSmallScreen">
<n-input-group> <n-input-group>
<n-input-group-label style="width: 200px"> Input number: </n-input-group-label> <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-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 { defineTool } from '../tool';
export const tool = defineTool({
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

@@ -1,7 +1,7 @@
import { AlignJustified } from '@vicons/tabler'; import { AlignJustified } from '@vicons/tabler';
import type { ITool } from '../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
name: 'Lorem ipsum generator', name: 'Lorem ipsum generator',
path: '/lorem-ipsum-generator', path: '/lorem-ipsum-generator',
description: description:
@@ -9,4 +9,4 @@ export const tool: ITool = {
keywords: ['lorem', 'ipsum', 'dolor', 'sit', 'amet', 'placeholder', 'text', 'filler', 'random', 'generator'], keywords: ['lorem', 'ipsum', 'dolor', 'sit', 'amet', 'placeholder', 'text', 'filler', 'random', 'generator'],
component: () => import('./lorem-ipsum-generator.vue'), component: () => import('./lorem-ipsum-generator.vue'),
icon: AlignJustified, icon: AlignJustified,
}; });

View File

@@ -0,0 +1,39 @@
import { Math } from '@vicons/tabler';
import { defineTool } from '../tool';
export const tool = defineTool({
name: 'Math evaluator',
path: '/math-evaluator',
description: `Evaluate math expression, like a calculator on steroid (you can use function like sqrt, cos, sin, abs, ...)`,
keywords: [
'math',
'evaluator',
'acos',
'acosh',
'acot',
'acoth',
'acsc',
'acsch',
'asec',
'asech',
'asin',
'asinh',
'atan',
'atan2',
'atanh',
'cos',
'cosh',
'cot',
'coth',
'csc',
'csch',
'sec',
'sech',
'sin',
'sinh',
'tan',
'tanh',
],
component: () => import('./math-evaluator.vue'),
icon: Math,
});

View File

@@ -0,0 +1,38 @@
<template>
<div>
<n-input
v-model:value="expression"
rows="1"
type="textarea"
placeholder="Your math expression (ex: 2*sqrt(6) )..."
size="large"
autocomplete="off"
autocorrect="off"
autocapitalize="off"
spellcheck="false"
/>
<br />
<br />
<n-card v-if="result !== ''" title="Result ">
{{ result }}
</n-card>
</div>
</template>
<script setup lang="ts">
import { evaluate } from 'mathjs';
import { computed, ref } from 'vue';
const expression = ref('');
const result = computed(() => {
try {
return evaluate(expression.value) ?? '';
} catch (_) {
return '';
}
});
</script>
<style lang="less" scoped></style>

View File

@@ -1,7 +1,7 @@
import { Qrcode } from '@vicons/tabler'; import { Qrcode } from '@vicons/tabler';
import type { ITool } from './../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
name: 'QR Code generator', name: 'QR Code generator',
path: '/qrcode-generator', path: '/qrcode-generator',
description: description:
@@ -9,4 +9,4 @@ export const tool: ITool = {
keywords: ['qr', 'code', 'generator', 'square', 'color', 'link', 'low', 'medium', 'quartile', 'high', 'transparent'], keywords: ['qr', 'code', 'generator', 'square', 'color', 'link', 'low', 'medium', 'quartile', 'high', 'transparent'],
component: () => import('./qr-code-generator.vue'), component: () => import('./qr-code-generator.vue'),
icon: Qrcode, icon: Qrcode,
}; });

View File

@@ -1,11 +1,11 @@
import { Server } from '@vicons/tabler'; import { Server } from '@vicons/tabler';
import type { ITool } from '../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
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,11 +1,11 @@
import { LetterX } from '@vicons/tabler'; import { LetterX } from '@vicons/tabler';
import type { ITool } from '../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
name: 'Roman numeral converter', name: 'Roman numeral converter',
path: '/roman-numeral-converter', path: '/roman-numeral-converter',
description: 'Convert Roman numerals to numbers and convert numbers to Roman numerals.', description: 'Convert Roman numerals to numbers and convert numbers to Roman numerals.',
keywords: ['roman', 'arabic', 'converter', 'X', 'I', 'V', 'L', 'C', 'D', 'M'], keywords: ['roman', 'arabic', 'converter', 'X', 'I', 'V', 'L', 'C', 'D', 'M'],
component: () => import('./roman-numeral-converter.vue'), component: () => import('./roman-numeral-converter.vue'),
icon: LetterX, icon: LetterX,
}; });

View File

@@ -1,7 +1,7 @@
import { FileText } from '@vicons/tabler'; import { FileText } from '@vicons/tabler';
import type { ITool } from './../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
name: 'Text statistics', name: 'Text statistics',
path: '/text-statistics', path: '/text-statistics',
description: "Get information about a text, the amount of characters, the amount of words, it's size, ...", description: "Get information about a text, the amount of characters, the amount of words, it's size, ...",
@@ -9,4 +9,4 @@ export const tool: ITool = {
component: () => import('./text-statistics.vue'), component: () => import('./text-statistics.vue'),
icon: FileText, icon: FileText,
redirectFrom: ['/text-stats'], redirectFrom: ['/text-stats'],
}; });

View File

@@ -1,7 +1,7 @@
import { ArrowsShuffle } from '@vicons/tabler'; import { ArrowsShuffle } from '@vicons/tabler';
import type { ITool } from './../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
name: 'Token generator', name: 'Token generator',
path: '/token-generator', path: '/token-generator',
description: description:
@@ -9,4 +9,4 @@ export const tool: ITool = {
keywords: ['token', 'random', 'string', 'alphanumeric', 'symbols', 'number', 'letters', 'lowercase', 'uppercase'], keywords: ['token', 'random', 'string', 'alphanumeric', 'symbols', 'number', 'letters', 'lowercase', 'uppercase'],
component: () => import('./token-generator.tool.vue'), component: () => import('./token-generator.tool.vue'),
icon: ArrowsShuffle, icon: ArrowsShuffle,
}; });

33
src/tools/tool.ts Normal file
View File

@@ -0,0 +1,33 @@
import { config } from '@/config';
import type { Component } from 'vue';
export interface ITool {
name: string;
path: string;
description: string;
keywords: string[];
component: () => Promise<Component>;
icon: Component;
redirectFrom?: string[];
isNew: boolean;
}
export interface ToolCategory {
name: string;
icon: Component;
components: ITool[];
}
type WithOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
export function defineTool(
tool: WithOptional<ITool, 'isNew'>,
{ newTools }: { newTools: string[] } = { newTools: config.tools.newTools },
) {
const isNew = newTools.includes(tool.name);
return {
isNew,
...tool,
};
}

View File

@@ -1,11 +1,11 @@
import { Link } from '@vicons/tabler'; import { Link } from '@vicons/tabler';
import type { ITool } from '../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
name: 'Encode/decode url formatted strings', name: 'Encode/decode url formatted strings',
path: '/url-encoder', path: '/url-encoder',
description: 'Encode to url-encoded format (also known as "percent-encoded") or decode from it.', description: 'Encode to url-encoded format (also known as "percent-encoded") or decode from it.',
keywords: ['url', 'encode', 'decode', 'percent', '%20', 'format'], keywords: ['url', 'encode', 'decode', 'percent', '%20', 'format'],
component: () => import('./url-encoder.vue'), component: () => import('./url-encoder.vue'),
icon: Link, icon: Link,
}; });

View File

@@ -1,5 +1,4 @@
<template> <template>
<div>
<n-card title="Encode"> <n-card title="Encode">
<n-form-item <n-form-item
label="Your string :" label="Your string :"
@@ -28,7 +27,6 @@
<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 :"
@@ -57,7 +55,6 @@
<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

@@ -1,12 +1,12 @@
import { Unlink } from '@vicons/tabler'; import { Unlink } from '@vicons/tabler';
import type { ITool } from './../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
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,
}; });

View File

@@ -1,7 +1,7 @@
import { Fingerprint } from '@vicons/tabler'; import { Fingerprint } from '@vicons/tabler';
import type { ITool } from '../Tool'; import { defineTool } from '../tool';
export const tool: ITool = { export const tool = defineTool({
name: 'UUIDs v4 generator', name: 'UUIDs v4 generator',
path: '/uuid-generator', path: '/uuid-generator',
description: description:
@@ -9,4 +9,4 @@ export const tool: ITool = {
keywords: ['uuid', 'v4', 'random', 'id', 'alphanumeric', 'identity', 'token', 'string', 'identifier', 'unique'], keywords: ['uuid', 'v4', 'random', 'id', 'alphanumeric', 'identity', 'token', 'string', 'identifier', 'unique'],
component: () => import('./uuid-generator.vue'), component: () => import('./uuid-generator.vue'),
icon: Fingerprint, icon: Fingerprint,
}; });

View File

@@ -61,6 +61,5 @@ export default defineConfig({
}, },
define: { define: {
'import.meta.env.PACKAGE_VERSION': JSON.stringify(process.env.npm_package_version), 'import.meta.env.PACKAGE_VERSION': JSON.stringify(process.env.npm_package_version),
'import.meta.env.GIT_SHORT_SHA': JSON.stringify((process?.env?.VITE_VERCEL_GIT_COMMIT_SHA ?? '').slice(0, 7)),
}, },
}); });