diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml
index 3c089ad7..b5b04096 100644
--- a/.github/workflows/e2e-tests.yml
+++ b/.github/workflows/e2e-tests.yml
@@ -6,7 +6,7 @@ on:
- main
jobs:
test:
- timeout-minutes: 60
+ timeout-minutes: 10
runs-on: ubuntu-latest
strategy:
matrix:
diff --git a/_templates/generator/ui-component/component.demo.ejs.t b/_templates/generator/ui-component/component.demo.ejs.t
new file mode 100644
index 00000000..7f9b473f
--- /dev/null
+++ b/_templates/generator/ui-component/component.demo.ejs.t
@@ -0,0 +1,6 @@
+---
+to: src/ui/<%= h.changeCase.param(name) %>/<%= h.changeCase.param(name) %>.demo.vue
+---
+
+ <<%= h.changeCase.param(name) %> />
+
diff --git a/_templates/generator/ui-component/component.ejs.t b/_templates/generator/ui-component/component.ejs.t
new file mode 100644
index 00000000..43acd4d1
--- /dev/null
+++ b/_templates/generator/ui-component/component.ejs.t
@@ -0,0 +1,13 @@
+---
+to: src/ui/<%= h.changeCase.param(name) %>/<%= h.changeCase.param(name) %>.vue
+---
+
+
+
+
+ {{ prop }}
+
+
diff --git a/components.d.ts b/components.d.ts
index 349539f0..91f8fe08 100644
--- a/components.d.ts
+++ b/components.d.ts
@@ -49,6 +49,8 @@ declare module '@vue/runtime-core' {
CrontabGenerator: typeof import('./src/tools/crontab-generator/crontab-generator.vue')['default']
CSelect: typeof import('./src/ui/c-select/c-select.vue')['default']
'CSelect.demo': typeof import('./src/ui/c-select/c-select.demo.vue')['default']
+ CTable: typeof import('./src/ui/c-table/c-table.vue')['default']
+ 'CTable.demo': typeof import('./src/ui/c-table/c-table.demo.vue')['default']
CTextCopyable: typeof import('./src/ui/c-text-copyable/c-text-copyable.vue')['default']
'CTextCopyable.demo': typeof import('./src/ui/c-text-copyable/c-text-copyable.demo.vue')['default']
CTooltip: typeof import('./src/ui/c-tooltip/c-tooltip.vue')['default']
@@ -90,6 +92,8 @@ declare module '@vue/runtime-core' {
IconMdiDownload: typeof import('~icons/mdi/download')['default']
IconMdiEye: typeof import('~icons/mdi/eye')['default']
IconMdiEyeOff: typeof import('~icons/mdi/eye-off')['default']
+ IconMdiFavoriteFilled: typeof import('~icons/mdi/favorite-filled')['default']
+ IconMdiHeart: typeof import('~icons/mdi/heart')['default']
IconMdiPause: typeof import('~icons/mdi/pause')['default']
IconMdiPlay: typeof import('~icons/mdi/play')['default']
IconMdiRecord: typeof import('~icons/mdi/record')['default']
@@ -179,6 +183,7 @@ declare module '@vue/runtime-core' {
TextareaCopyable: typeof import('./src/components/TextareaCopyable.vue')['default']
TextDiff: typeof import('./src/tools/text-diff/text-diff.vue')['default']
TextStatistics: typeof import('./src/tools/text-statistics/text-statistics.vue')['default']
+ TextToBinary: typeof import('./src/tools/text-to-binary/text-to-binary.vue')['default']
TextToNatoAlphabet: typeof import('./src/tools/text-to-nato-alphabet/text-to-nato-alphabet.vue')['default']
TokenDisplay: typeof import('./src/tools/otp-code-generator-and-validator/token-display.vue')['default']
'TokenGenerator.tool': typeof import('./src/tools/token-generator/token-generator.tool.vue')['default']
@@ -187,6 +192,7 @@ declare module '@vue/runtime-core' {
'Tool.layout': typeof import('./src/layouts/tool.layout.vue')['default']
ToolCard: typeof import('./src/components/ToolCard.vue')['default']
UlidGenerator: typeof import('./src/tools/ulid-generator/ulid-generator.vue')['default']
+ Unnamed: typeof import('./src/ui/unnamed/unnamed.vue')['default']
UrlEncoder: typeof import('./src/tools/url-encoder/url-encoder.vue')['default']
UrlParser: typeof import('./src/tools/url-parser/url-parser.vue')['default']
UserAgentParser: typeof import('./src/tools/user-agent-parser/user-agent-parser.vue')['default']
diff --git a/package.json b/package.json
index d3ec93bf..4ba8fbb1 100644
--- a/package.json
+++ b/package.json
@@ -30,7 +30,8 @@
"coverage": "vitest run --coverage",
"typecheck": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false",
"lint": "eslint src --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --ignore-path .gitignore",
- "script:create-new-tool": "node scripts/create-tool.mjs",
+ "script:create:tool": "node scripts/create-tool.mjs",
+ "script:create:ui": "hygen generator ui-component",
"release": "node ./scripts/release.mjs"
},
"dependencies": {
@@ -117,6 +118,7 @@
"c8": "^8.0.0",
"consola": "^3.0.2",
"eslint": "^8.47.0",
+ "hygen": "^6.2.11",
"jsdom": "^22.0.0",
"less": "^4.1.3",
"prettier": "^3.0.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 65579a34..76cf9f1b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -250,6 +250,9 @@ devDependencies:
eslint:
specifier: ^8.47.0
version: 8.47.0
+ hygen:
+ specifier: ^6.2.11
+ version: 6.2.11
jsdom:
specifier: ^22.0.0
version: 22.0.0
@@ -2918,6 +2921,10 @@ packages:
'@types/node': 18.15.11
dev: true
+ /@types/node@17.0.45:
+ resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==}
+ dev: true
+
/@types/node@18.15.11:
resolution: {integrity: sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==}
dev: true
@@ -3272,7 +3279,7 @@ packages:
dependencies:
'@unhead/dom': 0.5.1
'@unhead/schema': 0.5.1
- '@vueuse/shared': 10.4.1(vue@3.3.4)
+ '@vueuse/shared': 10.5.0(vue@3.3.4)
unhead: 0.5.1
vue: 3.3.4
transitivePeerDependencies:
@@ -3854,10 +3861,10 @@ packages:
- vue
dev: false
- /@vueuse/shared@10.4.1(vue@3.3.4):
- resolution: {integrity: sha512-vz5hbAM4qA0lDKmcr2y3pPdU+2EVw/yzfRsBdu+6+USGa4PxqSQRYIUC9/NcT06y+ZgaTsyURw2I9qOFaaXHAg==}
+ /@vueuse/shared@10.5.0(vue@3.3.4):
+ resolution: {integrity: sha512-18iyxbbHYLst9MqU1X1QNdMHIjks6wC7XTVf0KNOv5es/Ms6gjVFCAAWTVP2JStuGqydg3DT+ExpFORUEi9yhg==}
dependencies:
- vue-demi: 0.14.5(vue@3.3.4)
+ vue-demi: 0.14.6(vue@3.3.4)
transitivePeerDependencies:
- '@vue/composition-api'
- vue
@@ -3934,6 +3941,11 @@ packages:
uri-js: 4.4.1
dev: true
+ /ansi-colors@4.1.3:
+ resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
+ engines: {node: '>=6'}
+ dev: true
+
/ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
@@ -4069,6 +4081,10 @@ packages:
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+ /base64-js@1.5.1:
+ resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+ dev: true
+
/bcryptjs@2.4.3:
resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==}
dev: false
@@ -4077,6 +4093,14 @@ packages:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'}
+ /bl@4.1.0:
+ resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
+ dependencies:
+ buffer: 5.7.1
+ inherits: 2.0.4
+ readable-stream: 3.6.2
+ dev: true
+
/boolbase@1.0.0:
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
dev: true
@@ -4122,6 +4146,13 @@ packages:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
dev: true
+ /buffer@5.7.1:
+ resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
+ dependencies:
+ base64-js: 1.5.1
+ ieee754: 1.2.1
+ dev: true
+
/builtin-modules@3.3.0:
resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
engines: {node: '>=6'}
@@ -4168,6 +4199,13 @@ packages:
engines: {node: '>=6'}
dev: true
+ /camel-case@3.0.0:
+ resolution: {integrity: sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==}
+ dependencies:
+ no-case: 2.3.2
+ upper-case: 1.1.3
+ dev: true
+
/camel-case@4.1.2:
resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==}
dependencies:
@@ -4239,6 +4277,29 @@ packages:
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
dev: true
+ /change-case@3.1.0:
+ resolution: {integrity: sha512-2AZp7uJZbYEzRPsFoa+ijKdvp9zsrnnt6+yFokfwEpeJm0xuJDVoxiRCAaTzyJND8GJkofo2IcKWaUZ/OECVzw==}
+ dependencies:
+ camel-case: 3.0.0
+ constant-case: 2.0.0
+ dot-case: 2.1.1
+ header-case: 1.0.1
+ is-lower-case: 1.1.3
+ is-upper-case: 1.1.2
+ lower-case: 1.1.4
+ lower-case-first: 1.0.2
+ no-case: 2.3.2
+ param-case: 2.1.1
+ pascal-case: 2.0.1
+ path-case: 2.1.1
+ sentence-case: 2.1.1
+ snake-case: 2.1.0
+ swap-case: 1.1.2
+ title-case: 2.1.1
+ upper-case: 1.1.3
+ upper-case-first: 1.1.2
+ dev: true
+
/change-case@4.1.2:
resolution: {integrity: sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==}
dependencies:
@@ -4302,6 +4363,18 @@ packages:
escape-string-regexp: 1.0.5
dev: true
+ /cli-cursor@3.1.0:
+ resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
+ engines: {node: '>=8'}
+ dependencies:
+ restore-cursor: 3.1.0
+ dev: true
+
+ /cli-spinners@2.9.1:
+ resolution: {integrity: sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==}
+ engines: {node: '>=6'}
+ dev: true
+
/cliui@6.0.0:
resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
dependencies:
@@ -4318,6 +4391,11 @@ packages:
wrap-ansi: 7.0.0
dev: true
+ /clone@1.0.4:
+ resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
+ engines: {node: '>=0.8'}
+ dev: true
+
/color-convert@1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
dependencies:
@@ -4402,6 +4480,13 @@ packages:
engines: {node: ^14.18.0 || >=16.10.0}
dev: true
+ /constant-case@2.0.0:
+ resolution: {integrity: sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==}
+ dependencies:
+ snake-case: 2.1.0
+ upper-case: 1.1.3
+ dev: true
+
/constant-case@3.0.4:
resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==}
dependencies:
@@ -4625,6 +4710,12 @@ packages:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
+ /defaults@1.0.4:
+ resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
+ dependencies:
+ clone: 1.0.4
+ dev: true
+
/define-lazy-prop@2.0.0:
resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==}
engines: {node: '>=8'}
@@ -4642,6 +4733,12 @@ packages:
resolution: {integrity: sha512-+uO4+qr7msjNNWKYPHqN/3+Dx3NFkmIzayk2L1MyZQlvgZb/J1A0fo410dpKrN2SnqFjt8n4JL8fDJE0wIgjFQ==}
dev: true
+ /degit@2.8.4:
+ resolution: {integrity: sha512-vqYuzmSA5I50J882jd+AbAhQtgK6bdKUJIex1JNfEUPENCgYsxugzKVZlFyMwV4i06MmnV47/Iqi5Io86zf3Ng==}
+ engines: {node: '>=8.0.0'}
+ hasBin: true
+ dev: true
+
/delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
@@ -4724,6 +4821,12 @@ packages:
domhandler: 5.0.3
dev: true
+ /dot-case@2.1.1:
+ resolution: {integrity: sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==}
+ dependencies:
+ no-case: 2.3.2
+ dev: true
+
/dot-case@3.0.4:
resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==}
dependencies:
@@ -4774,6 +4877,14 @@ packages:
resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==}
dev: false
+ /enquirer@2.4.1:
+ resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==}
+ engines: {node: '>=8.6'}
+ dependencies:
+ ansi-colors: 4.1.3
+ strip-ansi: 6.0.1
+ dev: true
+
/entities@3.0.1:
resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==}
engines: {node: '>=0.12'}
@@ -5483,6 +5594,21 @@ packages:
resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==}
dev: true
+ /front-matter@4.0.2:
+ resolution: {integrity: sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==}
+ dependencies:
+ js-yaml: 3.14.1
+ dev: true
+
+ /fs-extra@10.1.0:
+ resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ graceful-fs: 4.2.11
+ jsonfile: 6.1.0
+ universalify: 2.0.0
+ dev: true
+
/fs-extra@11.1.1:
resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==}
engines: {node: '>=14.14'}
@@ -5753,6 +5879,13 @@ packages:
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
dev: false
+ /header-case@1.0.1:
+ resolution: {integrity: sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==}
+ dependencies:
+ no-case: 2.3.2
+ upper-case: 1.1.3
+ dev: true
+
/header-case@2.0.4:
resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==}
dependencies:
@@ -5840,6 +5973,28 @@ packages:
ms: 2.1.3
dev: false
+ /hygen@6.2.11:
+ resolution: {integrity: sha512-t6/zLI2XozP5gvV74nnl8LZSbwpVNFUkUs/O9DwuOdiiBbws5k4AQNVwKZ9FGzcKjdJ5EBBYkVzlcUHkLyY0FQ==}
+ hasBin: true
+ dependencies:
+ '@types/node': 17.0.45
+ chalk: 4.1.2
+ change-case: 3.1.0
+ debug: 4.3.4
+ degit: 2.8.4
+ ejs: 3.1.9
+ enquirer: 2.4.1
+ execa: 5.1.1
+ front-matter: 4.0.2
+ fs-extra: 10.1.0
+ ignore-walk: 4.0.1
+ inflection: 1.13.4
+ ora: 5.4.1
+ yargs-parser: 21.1.1
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
/iarna-toml-esm@3.0.5:
resolution: {integrity: sha512-CgeDbPohnFG827UoRaCqKxJ8idiIDZDWlcHf5hUReQnZ8jHnNnhN4QJFiY12fKvr0LvuDuKAimqQfrmQnacbtw==}
dependencies:
@@ -5861,6 +6016,17 @@ packages:
resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==}
dev: true
+ /ieee754@1.2.1:
+ resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+ dev: true
+
+ /ignore-walk@4.0.1:
+ resolution: {integrity: sha512-rzDQLaW4jQbh2YrOFlJdCtX8qgJTehFRYiUB2r1osqTeDzV/3+Jh8fz1oAPzUThf3iku8Ds4IDqawI5d8mUiQw==}
+ engines: {node: '>=10'}
+ dependencies:
+ minimatch: 3.1.2
+ dev: true
+
/ignore@5.2.4:
resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
engines: {node: '>= 4'}
@@ -5891,6 +6057,11 @@ packages:
engines: {node: '>=8'}
dev: true
+ /inflection@1.13.4:
+ resolution: {integrity: sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw==}
+ engines: {'0': node >= 0.4.0}
+ dev: true
+
/inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
dependencies:
@@ -6036,6 +6207,17 @@ packages:
resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==}
dev: true
+ /is-interactive@1.0.0:
+ resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /is-lower-case@1.1.3:
+ resolution: {integrity: sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==}
+ dependencies:
+ lower-case: 1.1.4
+ dev: true
+
/is-module@1.0.0:
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
dev: true
@@ -6127,6 +6309,17 @@ packages:
which-typed-array: 1.1.11
dev: true
+ /is-unicode-supported@0.1.0:
+ resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /is-upper-case@1.1.2:
+ resolution: {integrity: sha512-GQYSJMgfeAmVwh9ixyk888l7OIhNAGKtY6QA+IrWlu9MDTCaXmeozOZ2S9Knj7bQwBO/H6J2kb+pbyTUiMNbsw==}
+ dependencies:
+ upper-case: 1.1.3
+ dev: true
+
/is-weakref@1.0.2:
resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
dependencies:
@@ -6458,12 +6651,30 @@ packages:
/lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+ /log-symbols@4.1.0:
+ resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
+ engines: {node: '>=10'}
+ dependencies:
+ chalk: 4.1.2
+ is-unicode-supported: 0.1.0
+ dev: true
+
/loupe@2.3.6:
resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==}
dependencies:
get-func-name: 2.0.0
dev: true
+ /lower-case-first@1.0.2:
+ resolution: {integrity: sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==}
+ dependencies:
+ lower-case: 1.1.4
+ dev: true
+
+ /lower-case@1.1.4:
+ resolution: {integrity: sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==}
+ dev: true
+
/lower-case@2.0.2:
resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
dependencies:
@@ -6747,6 +6958,12 @@ packages:
engines: {node: '>= 0.4.0'}
dev: false
+ /no-case@2.3.2:
+ resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==}
+ dependencies:
+ lower-case: 1.1.4
+ dev: true
+
/no-case@3.0.4:
resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
dependencies:
@@ -6919,6 +7136,21 @@ packages:
type-check: 0.4.0
dev: true
+ /ora@5.4.1:
+ resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ bl: 4.1.0
+ chalk: 4.1.2
+ cli-cursor: 3.1.0
+ cli-spinners: 2.9.1
+ is-interactive: 1.0.0
+ is-unicode-supported: 0.1.0
+ log-symbols: 4.1.0
+ strip-ansi: 6.0.1
+ wcwidth: 1.0.1
+ dev: true
+
/orderedmap@2.1.1:
resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==}
dev: false
@@ -6976,6 +7208,12 @@ packages:
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
engines: {node: '>=6'}
+ /param-case@2.1.1:
+ resolution: {integrity: sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==}
+ dependencies:
+ no-case: 2.3.2
+ dev: true
+
/param-case@3.0.4:
resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==}
dependencies:
@@ -7022,6 +7260,13 @@ packages:
entities: 4.5.0
dev: true
+ /pascal-case@2.0.1:
+ resolution: {integrity: sha512-qjS4s8rBOJa2Xm0jmxXiyh1+OFf6ekCWOvUaRgAQSktzlTbMotS0nmG9gyYAybCWBcuP4fsBeRCKNwGBnMe2OQ==}
+ dependencies:
+ camel-case: 3.0.0
+ upper-case-first: 1.1.2
+ dev: true
+
/pascal-case@3.1.2:
resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==}
dependencies:
@@ -7029,6 +7274,12 @@ packages:
tslib: 2.5.0
dev: false
+ /path-case@2.1.1:
+ resolution: {integrity: sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==}
+ dependencies:
+ no-case: 2.3.2
+ dev: true
+
/path-case@3.0.4:
resolution: {integrity: sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==}
dependencies:
@@ -7435,6 +7686,15 @@ packages:
type-fest: 0.6.0
dev: true
+ /readable-stream@3.6.2:
+ resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
+ engines: {node: '>= 6'}
+ dependencies:
+ inherits: 2.0.4
+ string_decoder: 1.3.0
+ util-deprecate: 1.0.2
+ dev: true
+
/readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
@@ -7548,6 +7808,14 @@ packages:
supports-preserve-symlinks-flag: 1.0.0
dev: true
+ /restore-cursor@3.1.0:
+ resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
+ engines: {node: '>=8'}
+ dependencies:
+ onetime: 5.1.2
+ signal-exit: 3.0.7
+ dev: true
+
/ret@0.1.15:
resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==}
engines: {node: '>=0.12'}
@@ -7684,6 +7952,13 @@ packages:
lru-cache: 6.0.0
dev: true
+ /sentence-case@2.1.1:
+ resolution: {integrity: sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==}
+ dependencies:
+ no-case: 2.3.2
+ upper-case-first: 1.1.2
+ dev: true
+
/sentence-case@3.0.4:
resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==}
dependencies:
@@ -7761,6 +8036,12 @@ packages:
engines: {node: '>=12'}
dev: true
+ /snake-case@2.1.0:
+ resolution: {integrity: sha512-FMR5YoPFwOLuh4rRz92dywJjyKYZNLpMn1R5ujVpIYkbA9p01fq8RMg0FkO4M+Yobt4MjHeLTJVm5xFFBHSV2Q==}
+ dependencies:
+ no-case: 2.3.2
+ dev: true
+
/snake-case@3.0.4:
resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==}
dependencies:
@@ -7904,6 +8185,12 @@ packages:
es-abstract: 1.22.1
dev: true
+ /string_decoder@1.3.0:
+ resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: true
+
/stringify-object@3.3.0:
resolution: {integrity: sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==}
engines: {node: '>=4'}
@@ -7985,6 +8272,13 @@ packages:
picocolors: 1.0.0
dev: true
+ /swap-case@1.1.2:
+ resolution: {integrity: sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==}
+ dependencies:
+ lower-case: 1.1.4
+ upper-case: 1.1.3
+ dev: true
+
/symbol-tree@3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
dev: true
@@ -8075,6 +8369,13 @@ packages:
'@popperjs/core': 2.11.8
dev: false
+ /title-case@2.1.1:
+ resolution: {integrity: sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==}
+ dependencies:
+ no-case: 2.3.2
+ upper-case: 1.1.3
+ dev: true
+
/to-fast-properties@2.0.0:
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
engines: {node: '>=4'}
@@ -8527,12 +8828,22 @@ packages:
escalade: 3.1.1
picocolors: 1.0.0
+ /upper-case-first@1.1.2:
+ resolution: {integrity: sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==}
+ dependencies:
+ upper-case: 1.1.3
+ dev: true
+
/upper-case-first@2.0.2:
resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==}
dependencies:
tslib: 2.5.0
dev: false
+ /upper-case@1.1.3:
+ resolution: {integrity: sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==}
+ dev: true
+
/upper-case@2.0.2:
resolution: {integrity: sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==}
dependencies:
@@ -8790,6 +9101,21 @@ packages:
vue: 3.3.4
dev: false
+ /vue-demi@0.14.6(vue@3.3.4):
+ resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==}
+ engines: {node: '>=12'}
+ hasBin: true
+ requiresBuild: true
+ peerDependencies:
+ '@vue/composition-api': ^1.0.0-rc.1
+ vue: ^3.0.0-0 || ^2.6.0
+ peerDependenciesMeta:
+ '@vue/composition-api':
+ optional: true
+ dependencies:
+ vue: 3.3.4
+ dev: false
+
/vue-eslint-parser@9.3.1(eslint@8.47.0):
resolution: {integrity: sha512-Clr85iD2XFZ3lJ52/ppmUDG/spxQu6+MAeHXjjyI4I1NUYZ9xmenQp4N0oaHJhrA8OOxltCVxMRfANGa70vU0g==}
engines: {node: ^14.17.0 || >=16.0.0}
@@ -8883,6 +9209,12 @@ packages:
xml-name-validator: 4.0.0
dev: true
+ /wcwidth@1.0.1:
+ resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
+ dependencies:
+ defaults: 1.0.4
+ dev: true
+
/web-streams-polyfill@3.2.1:
resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==}
engines: {node: '>= 8'}
@@ -9252,6 +9584,11 @@ packages:
engines: {node: '>=10'}
dev: true
+ /yargs-parser@21.1.1:
+ resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
+ engines: {node: '>=12'}
+ dev: true
+
/yargs@15.4.1:
resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
engines: {node: '>=8'}
diff --git a/src/components/FavoriteButton.vue b/src/components/FavoriteButton.vue
index ef180a65..c3f0aaad 100644
--- a/src/components/FavoriteButton.vue
+++ b/src/components/FavoriteButton.vue
@@ -1,6 +1,4 @@
-
-
-
-
-
-
- {{ isFavorite ? 'Remove from favorites' : 'Add to favorites' }}
-
+
+
+
+
+
diff --git a/src/components/InputCopyable.vue b/src/components/InputCopyable.vue
index ed678954..a69a039a 100644
--- a/src/components/InputCopyable.vue
+++ b/src/components/InputCopyable.vue
@@ -13,14 +13,11 @@ const tooltipText = computed(() => isJustCopied.value ? 'Copied!' : 'Copy to cli
-
-
-
-
-
-
- {{ tooltipText }}
-
+
+
+
+
+
diff --git a/src/components/NavbarButtons.vue b/src/components/NavbarButtons.vue
index 5b1a3a4e..653afdd2 100644
--- a/src/components/NavbarButtons.vue
+++ b/src/components/NavbarButtons.vue
@@ -7,56 +7,43 @@ const { isDarkTheme } = toRefs(styleStore);
-
-
-
-
-
-
- Github repository
-
+
+
+
+
+
-
-
-
-
-
-
- IT Tools' Twitter account
-
+
+
+
+
+
-
-
-
-
-
-
- About
-
-
-
- styleStore.toggleDark()">
-
-
-
-
- Light mode
- Dark mode
-
+
+
+
+
+
+
+ styleStore.toggleDark()">
+
+
+
+
diff --git a/src/components/TextareaCopyable.vue b/src/components/TextareaCopyable.vue
index b349d041..8b0aae61 100644
--- a/src/components/TextareaCopyable.vue
+++ b/src/components/TextareaCopyable.vue
@@ -40,7 +40,7 @@ const tooltipText = computed(() => isJustCopied.value ? 'Copied!' : copyMessage.
-
+
isJustCopied.value ? 'Copied!' : copyMessage.
-
-
-
-
-
-
-
-
- {{ tooltipText }}
-
+
+
+
+
+
+
+
@@ -74,25 +71,4 @@ const tooltipText = computed(() => isJustCopied.value ? 'Copied!' : copyMessage.
padding-bottom: 10px;
margin-bottom: -10px;
}
-.result-card {
- position: relative;
- .copy-button {
- position: absolute;
- opacity: 1;
-
- &.top-right {
- top: 10px;
- right: 10px;
- }
-
- &.bottom-right {
- bottom: 10px;
- right: 10px;
- }
- &.outside,
- &.none {
- display: none;
- }
- }
-}
diff --git a/src/layouts/base.layout.vue b/src/layouts/base.layout.vue
index 2b697cfc..4f9e4cd1 100644
--- a/src/layouts/base.layout.vue
+++ b/src/layouts/base.layout.vue
@@ -94,18 +94,17 @@ const tools = computed(() => [
-
-
-
-
-
-
- Home
-
+
+
+
+
+
-
-
-
+
+
+
+
+
@@ -113,23 +112,20 @@ const tools = computed(() => [
-
-
- tracker.trackEvent({ eventName: 'Support button clicked' })"
- >
- Buy me a coffee
-
-
-
- ❤ Support IT Tools development !
-
+
+ tracker.trackEvent({ eventName: 'Support button clicked' })"
+ >
+ Buy me a coffee
+
+
+
diff --git a/src/pages/About.vue b/src/pages/About.vue
index 3fada35e..8e6b1aad 100644
--- a/src/pages/About.vue
+++ b/src/pages/About.vue
@@ -7,17 +7,17 @@ const { tracker } = useTracker();
-
-
About
-
+
+
About IT-Tools
+
This wonderful website, made with ❤ by
Corentin Thomasset
,
aggregates useful tools for developer and people working in IT. If you find it useful, please feel free to share
it to people you think may find it useful too and don't forget to bookmark it in your shortcut bar!
-
-
+
+
IT Tools is open-source (under the MIT license) and free, and will always be, but it costs me money to host and
renew the domain name. If you want to support my work, and encourage me to add more tools, please consider
supporting by
@@ -29,20 +29,20 @@ const { tracker } = useTracker();
>
sponsoring me
.
-
+
-
Technologies
-
+ Technologies
+
IT Tools is made in Vue.js (Vue 3) with the the Naive UI component library and is hosted and continuously deployed
by Vercel. Third-party open-source libraries are used in some tools, you may find the complete list in the
package.json
file of the repository.
-
+
-
Found a bug? A tool is missing?
-
+ Found a bug? A tool is missing?
+
If you need a tool that is currently not present here, and you think can be useful, you are welcome to submit a
feature request in the
in the GitHub repository.
-
-
+
+
And if you found a bug, or something doesn't work as expected, please file a bug report in the
in the GitHub repository.
-
+
-
-
diff --git a/src/tools/benchmark-builder/benchmark-builder.vue b/src/tools/benchmark-builder/benchmark-builder.vue
index 7922791c..93911428 100644
--- a/src/tools/benchmark-builder/benchmark-builder.vue
+++ b/src/tools/benchmark-builder/benchmark-builder.vue
@@ -51,11 +51,11 @@ const results = computed(() => {
const { copy } = useCopy({ createToast: false });
const header = {
+ position: 'Position',
title: 'Suite',
size: 'Samples',
mean: 'Mean',
variance: 'Variance',
- position: 'Position',
};
function copyAsMarkdown() {
@@ -131,26 +131,8 @@ function copyAsBulletList() {
-
-
-
- {{ header.position }} |
- {{ header.title }} |
- {{ header.size }} |
- {{ header.mean }} |
- {{ header.variance }} |
-
-
-
-
- {{ position }} |
- {{ title }} |
- {{ size }} |
- {{ mean }} |
- {{ variance }} |
-
-
-
+
+
Copy as markdown table
diff --git a/src/tools/benchmark-builder/dynamic-values.vue b/src/tools/benchmark-builder/dynamic-values.vue
index 975a545c..e048ef99 100644
--- a/src/tools/benchmark-builder/dynamic-values.vue
+++ b/src/tools/benchmark-builder/dynamic-values.vue
@@ -39,14 +39,11 @@ function onInputEnter(index: number) {
autofocus
@keydown.enter="onInputEnter(index)"
/>
-
-
-
-
-
-
- Delete value
-
+
+
+
+
+
diff --git a/src/tools/crontab-generator/crontab-generator.vue b/src/tools/crontab-generator/crontab-generator.vue
index 28683ce5..97503e7d 100644
--- a/src/tools/crontab-generator/crontab-generator.vue
+++ b/src/tools/crontab-generator/crontab-generator.vue
@@ -167,34 +167,8 @@ const cronValidationRules = [
-
-
-
-
- Symbol
- |
-
- Meaning
- |
-
- Example
- |
-
- Equivalent
- |
-
-
-
-
- {{ symbol }} |
- {{ meaning }} |
-
- {{ example }}
- |
- {{ equivalent }} |
-
-
-
+
+
diff --git a/src/tools/html-wysiwyg-editor/editor/menu-bar-item.vue b/src/tools/html-wysiwyg-editor/editor/menu-bar-item.vue
index 9a4cf1bd..5be23292 100644
--- a/src/tools/html-wysiwyg-editor/editor/menu-bar-item.vue
+++ b/src/tools/html-wysiwyg-editor/editor/menu-bar-item.vue
@@ -6,13 +6,9 @@ const { icon, title, action, isActive } = toRefs(props);
-
-
-
-
-
-
-
- {{ title }}
-
+
+
+
+
+
diff --git a/src/tools/index.ts b/src/tools/index.ts
index d4284960..22db0770 100644
--- a/src/tools/index.ts
+++ b/src/tools/index.ts
@@ -2,6 +2,7 @@ import { tool as base64FileConverter } from './base64-file-converter';
import { tool as base64StringConverter } from './base64-string-converter';
import { tool as basicAuthGenerator } from './basic-auth-generator';
import { tool as macAddressGenerator } from './mac-address-generator';
+import { tool as textToBinary } from './text-to-binary';
import { tool as ulidGenerator } from './ulid-generator';
import { tool as ibanValidatorAndParser } from './iban-validator-and-parser';
import { tool as stringObfuscator } from './string-obfuscator';
@@ -89,6 +90,7 @@ export const toolsByCategory: ToolCategory[] = [
colorConverter,
caseConverter,
textToNatoAlphabet,
+ textToBinary,
yamlToJson,
yamlToToml,
jsonToYaml,
diff --git a/src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue b/src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue
index 7b26a098..6bd881c0 100644
--- a/src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue
+++ b/src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue
@@ -61,19 +61,16 @@ const secretValidationRules = [
:validation-rules="secretValidationRules"
>
-
-
-
-
-
-
- Generate secret token
-
+
+
+
+
+
-
+
diff --git a/src/tools/otp-code-generator-and-validator/token-display.vue b/src/tools/otp-code-generator-and-validator/token-display.vue
index 5313b0be..317f0831 100644
--- a/src/tools/otp-code-generator-and-validator/token-display.vue
+++ b/src/tools/otp-code-generator-and-validator/token-display.vue
@@ -11,7 +11,7 @@ const { tokens } = toRefs(props);
-
+
Previous
@@ -22,60 +22,24 @@ const { tokens } = toRefs(props);
Next
-
-
-
-
- {{ tokens.previous }}
-
-
- {{ previousCopied ? 'Copied !' : 'Copy previous OTP' }}
-
-
-
-
- {{ tokens.current }}
-
-
- {{ currentCopied ? 'Copied !' : 'Copy current OTP' }}
-
-
-
-
- {{
- tokens.next
- }}
-
-
- {{ nextCopied ? 'Copied !' : 'Copy next OTP' }}
-
-
+
+
+
+ {{ tokens.previous }}
+
+
+
+
+ {{ tokens.current }}
+
+
+
+
+ {{ tokens.next }}
+
+
+
-
-
diff --git a/src/tools/text-to-binary/index.ts b/src/tools/text-to-binary/index.ts
new file mode 100644
index 00000000..40ac93d6
--- /dev/null
+++ b/src/tools/text-to-binary/index.ts
@@ -0,0 +1,12 @@
+import { Binary } from '@vicons/tabler';
+import { defineTool } from '../tool';
+
+export const tool = defineTool({
+ name: 'Text to ASCII binary',
+ path: '/text-to-binary',
+ description: 'Convert text to its ASCII binary representation and vice versa.',
+ keywords: ['text', 'to', 'binary', 'converter', 'encode', 'decode', 'ascii'],
+ component: () => import('./text-to-binary.vue'),
+ icon: Binary,
+ createdAt: new Date('2023-10-15'),
+});
diff --git a/src/tools/text-to-binary/text-to-binary.e2e.spec.ts b/src/tools/text-to-binary/text-to-binary.e2e.spec.ts
new file mode 100644
index 00000000..2b4e4313
--- /dev/null
+++ b/src/tools/text-to-binary/text-to-binary.e2e.spec.ts
@@ -0,0 +1,25 @@
+import { expect, test } from '@playwright/test';
+
+test.describe('Tool - Text to ASCII binary', () => {
+ test.beforeEach(async ({ page }) => {
+ await page.goto('/text-to-binary');
+ });
+
+ test('Has correct title', async ({ page }) => {
+ await expect(page).toHaveTitle('Text to ASCII binary - IT Tools');
+ });
+
+ test('Text to binary conversion', async ({ page }) => {
+ await page.getByTestId('text-to-binary-input').fill('it-tools');
+ const binary = await page.getByTestId('text-to-binary-output').inputValue();
+
+ expect(binary).toEqual('01101001 01110100 00101101 01110100 01101111 01101111 01101100 01110011');
+ });
+
+ test('Binary to text conversion', async ({ page }) => {
+ await page.getByTestId('binary-to-text-input').fill('01101001 01110100 00101101 01110100 01101111 01101111 01101100 01110011');
+ const text = await page.getByTestId('binary-to-text-output').inputValue();
+
+ expect(text).toEqual('it-tools');
+ });
+});
diff --git a/src/tools/text-to-binary/text-to-binary.models.test.ts b/src/tools/text-to-binary/text-to-binary.models.test.ts
new file mode 100644
index 00000000..e4269b50
--- /dev/null
+++ b/src/tools/text-to-binary/text-to-binary.models.test.ts
@@ -0,0 +1,32 @@
+import { describe, expect, it } from 'vitest';
+import { convertAsciiBinaryToText, convertTextToAsciiBinary } from './text-to-binary.models';
+
+describe('text-to-binary', () => {
+ describe('convertTextToAsciiBinary', () => {
+ it('a text string is converted to its ascii binary representation', () => {
+ expect(convertTextToAsciiBinary('A')).toBe('01000001');
+ expect(convertTextToAsciiBinary('hello')).toBe('01101000 01100101 01101100 01101100 01101111');
+ expect(convertTextToAsciiBinary('')).toBe('');
+ });
+ it('the separator between octets can be changed', () => {
+ expect(convertTextToAsciiBinary('hello', { separator: '' })).toBe('0110100001100101011011000110110001101111');
+ });
+ });
+
+ describe('convertAsciiBinaryToText', () => {
+ it('an ascii binary string is converted to its text representation', () => {
+ expect(convertAsciiBinaryToText('01101000 01100101 01101100 01101100 01101111')).toBe('hello');
+ expect(convertAsciiBinaryToText('01000001')).toBe('A');
+ expect(convertTextToAsciiBinary('')).toBe('');
+ });
+
+ it('the given binary string is cleaned before conversion', () => {
+ expect(convertAsciiBinaryToText(' 01000 001garbage')).toBe('A');
+ });
+
+ it('throws an error if the given binary string as no complete octet', () => {
+ expect(() => convertAsciiBinaryToText('010000011')).toThrow('Invalid binary string');
+ expect(() => convertAsciiBinaryToText('1')).toThrow('Invalid binary string');
+ });
+ });
+});
diff --git a/src/tools/text-to-binary/text-to-binary.models.ts b/src/tools/text-to-binary/text-to-binary.models.ts
new file mode 100644
index 00000000..ad9699af
--- /dev/null
+++ b/src/tools/text-to-binary/text-to-binary.models.ts
@@ -0,0 +1,22 @@
+export { convertTextToAsciiBinary, convertAsciiBinaryToText };
+
+function convertTextToAsciiBinary(text: string, { separator = ' ' }: { separator?: string } = {}): string {
+ return text
+ .split('')
+ .map(char => char.charCodeAt(0).toString(2).padStart(8, '0'))
+ .join(separator);
+}
+
+function convertAsciiBinaryToText(binary: string): string {
+ const cleanBinary = binary.replace(/[^01]/g, '');
+
+ if (cleanBinary.length % 8) {
+ throw new Error('Invalid binary string');
+ }
+
+ return cleanBinary
+ .split(/(\d{8})/)
+ .filter(Boolean)
+ .map(binary => String.fromCharCode(Number.parseInt(binary, 2)))
+ .join('');
+}
diff --git a/src/tools/text-to-binary/text-to-binary.vue b/src/tools/text-to-binary/text-to-binary.vue
new file mode 100644
index 00000000..37aa9bea
--- /dev/null
+++ b/src/tools/text-to-binary/text-to-binary.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+ Copy binary to clipboard
+
+
+
+
+
+
+
+
+
+ Copy text to clipboard
+
+
+
+
diff --git a/src/tools/user-agent-parser/user-agent-result-cards.vue b/src/tools/user-agent-parser/user-agent-result-cards.vue
index ed4724cb..77502df0 100644
--- a/src/tools/user-agent-parser/user-agent-result-cards.vue
+++ b/src/tools/user-agent-parser/user-agent-result-cards.vue
@@ -14,25 +14,18 @@ const { userAgentInfo, sections } = toRefs(props);
-
-
- {{ heading }}
-
-
-
-
-
+
+
+ {{ heading }}
+
-
-
-
- {{ getValue(userAgentInfo) }}
-
-
- {{ label }}
-
+
+
+ {{ getValue(userAgentInfo) }}
+
+
diff --git a/src/ui/c-table/c-table.demo.vue b/src/ui/c-table/c-table.demo.vue
new file mode 100644
index 00000000..b2cf8a77
--- /dev/null
+++ b/src/ui/c-table/c-table.demo.vue
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+ {{ value }}yo
+
+
+
diff --git a/src/ui/c-table/c-table.types.ts b/src/ui/c-table/c-table.types.ts
new file mode 100644
index 00000000..6c658f34
--- /dev/null
+++ b/src/ui/c-table/c-table.types.ts
@@ -0,0 +1,4 @@
+export type HeaderConfiguration = (string | {
+ key: string
+ label?: string
+})[] | Record
;
diff --git a/src/ui/c-table/c-table.vue b/src/ui/c-table/c-table.vue
new file mode 100644
index 00000000..9354cc9a
--- /dev/null
+++ b/src/ui/c-table/c-table.vue
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+ {{ header.label }}
+ |
+
+
+
+
+
+
+ {{ row[header.key] }}
+
+ |
+
+
+
+
+
diff --git a/src/ui/c-tooltip/c-tooltip.demo.vue b/src/ui/c-tooltip/c-tooltip.demo.vue
index d3852573..edd1364a 100644
--- a/src/ui/c-tooltip/c-tooltip.demo.vue
+++ b/src/ui/c-tooltip/c-tooltip.demo.vue
@@ -1,3 +1,7 @@
+
+
@@ -14,4 +18,18 @@
Hover me
+
+
+
Tooltip positions
+
+
+
+
+
+ {{ position }}
+
+
+
+
+
diff --git a/src/ui/c-tooltip/c-tooltip.vue b/src/ui/c-tooltip/c-tooltip.vue
index 095315fb..0f47e711 100644
--- a/src/ui/c-tooltip/c-tooltip.vue
+++ b/src/ui/c-tooltip/c-tooltip.vue
@@ -1,23 +1,30 @@
-