Compare commits
25 Commits
card-hover
...
renovate/a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d275661e5a | ||
|
|
02e68d3f56 | ||
|
|
00562ed5e8 | ||
|
|
4365226d01 | ||
|
|
57ecda1623 | ||
|
|
d8d7a3b9ab | ||
|
|
d36b18f193 | ||
|
|
eea9f91276 | ||
|
|
ebb4ec4165 | ||
|
|
84a4a646f6 | ||
|
|
a2b53c2e38 | ||
|
|
35563b8457 | ||
|
|
720201aa7b | ||
|
|
b2ad4f7a27 | ||
|
|
b408df82c1 | ||
|
|
88b881880c | ||
|
|
ee4c853b9f | ||
|
|
cbf58fdd28 | ||
|
|
a757a5155a | ||
|
|
025f556023 | ||
|
|
2d2dffb14a | ||
|
|
5c4d775e2d | ||
|
|
557b30426f | ||
|
|
4972159aa7 | ||
|
|
e371ef702e |
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -11,9 +11,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 16
|
||||
cache: 'pnpm'
|
||||
|
||||
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
||||
18
.github/workflows/docker-nightly-release.yml
vendored
18
.github/workflows/docker-nightly-release.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
outputs:
|
||||
should_run: ${{ steps.should_run.outputs.should_run }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
|
||||
- name: print latest_commit
|
||||
run: echo ${{ github.sha }}
|
||||
|
||||
@@ -28,9 +28,9 @@ jobs:
|
||||
if: ${{ needs.check_date.outputs.should_run != 'false' }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 16
|
||||
cache: 'pnpm'
|
||||
@@ -54,29 +54,29 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
|
||||
6
.github/workflows/e2e-tests.yml
vendored
6
.github/workflows/e2e-tests.yml
vendored
@@ -6,17 +6,17 @@ on:
|
||||
- main
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
timeout-minutes: 10
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
shard: [1/3, 2/3, 3/3]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
|
||||
|
||||
- run: corepack enable
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 16
|
||||
cache: 'pnpm'
|
||||
|
||||
16
.github/workflows/releases.yml
vendored
16
.github/workflows/releases.yml
vendored
@@ -13,29 +13,29 @@ jobs:
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
@@ -55,11 +55,11 @@ jobs:
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
|
||||
|
||||
- run: corepack enable
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 16
|
||||
cache: 'pnpm'
|
||||
|
||||
@@ -105,12 +105,20 @@ pnpm run script:create-new-tool my-tool-name
|
||||
|
||||
It will create a directory in `src/tools` with the correct files, and a the import in `src/tools/index.ts`. You will just need to add the imported tool in the proper category and develop the tool.
|
||||
|
||||
## Contributors
|
||||
|
||||
Big thanks to all the people who have already contributed!
|
||||
|
||||
[](https://github.com/corentinth/it-tools/graphs/contributors)
|
||||
|
||||
## Credits
|
||||
|
||||
Coded with ❤️ by [Corentin Thomasset](//corentin-thomasset.fr).
|
||||
|
||||
This project is continuously deployed using [vercel.com](https://vercel.com).
|
||||
|
||||
Contributor graph is generated using [contrib.rocks](https://contrib.rocks/preview?repo=corentinth/it-tools).
|
||||
|
||||
<a href="https://www.producthunt.com/posts/it-tools?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-it-tools" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=345793&theme=light" alt="IT Tools - Collection of handy online tools for devs, with great 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-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 Tools - Collection of handy online tools for devs, with great UX | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
|
||||
|
||||
|
||||
6
_templates/generator/ui-component/component.demo.ejs.t
Normal file
6
_templates/generator/ui-component/component.demo.ejs.t
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
to: src/ui/<%= h.changeCase.param(name) %>/<%= h.changeCase.param(name) %>.demo.vue
|
||||
---
|
||||
<template>
|
||||
<<%= h.changeCase.param(name) %> />
|
||||
</template>
|
||||
13
_templates/generator/ui-component/component.ejs.t
Normal file
13
_templates/generator/ui-component/component.ejs.t
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
to: src/ui/<%= h.changeCase.param(name) %>/<%= h.changeCase.param(name) %>.vue
|
||||
---
|
||||
<script lang="ts" setup>
|
||||
const props = withDefaults(defineProps<{ prop?: string }>(), { prop: '' });
|
||||
const { prop } = toRefs(props);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
{{ prop }}
|
||||
</div>
|
||||
</template>
|
||||
9
components.d.ts
vendored
9
components.d.ts
vendored
@@ -25,6 +25,8 @@ declare module '@vue/runtime-core' {
|
||||
CaseConverter: typeof import('./src/tools/case-converter/case-converter.vue')['default']
|
||||
CButton: typeof import('./src/ui/c-button/c-button.vue')['default']
|
||||
'CButton.demo': typeof import('./src/ui/c-button/c-button.demo.vue')['default']
|
||||
CButtonsSelect: typeof import('./src/ui/c-buttons-select/c-buttons-select.vue')['default']
|
||||
'CButtonsSelect.demo': typeof import('./src/ui/c-buttons-select/c-buttons-select.demo.vue')['default']
|
||||
CCard: typeof import('./src/ui/c-card/c-card.vue')['default']
|
||||
'CCard.demo': typeof import('./src/ui/c-card/c-card.demo.vue')['default']
|
||||
CDiffEditor: typeof import('./src/ui/c-diff-editor/c-diff-editor.vue')['default']
|
||||
@@ -47,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']
|
||||
@@ -88,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']
|
||||
@@ -176,6 +182,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']
|
||||
@@ -183,6 +190,8 @@ declare module '@vue/runtime-core' {
|
||||
TomlToYaml: typeof import('./src/tools/toml-to-yaml/toml-to-yaml.vue')['default']
|
||||
'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']
|
||||
|
||||
@@ -1,4 +1,51 @@
|
||||
home:
|
||||
categories:
|
||||
newestTools: Newest tools
|
||||
|
||||
favoriteTools: 'Your favorite tools'
|
||||
allTools: 'All the tools'
|
||||
subtitle: 'Handy tools for developers'
|
||||
toggleMenu: 'Toggle menu'
|
||||
home: Home
|
||||
uiLib: 'UI Lib'
|
||||
buyMeACoffee: 'Buy me a coffee'
|
||||
follow:
|
||||
title: 'You like it-tools?'
|
||||
p1: 'Give us a star on'
|
||||
githubRepository: 'IT-Tools GitHub repository'
|
||||
p2: 'or follow us on'
|
||||
twitterAccount: 'IT-Tools Twitter account'
|
||||
thankYou: 'Thank you !'
|
||||
nav:
|
||||
github: 'GitHub repository'
|
||||
githubRepository: 'IT-Tools GitHub repository'
|
||||
twitter: 'Twitter account'
|
||||
twitterAccount: 'IT Tools Twitter account'
|
||||
about: 'About IT-Tools'
|
||||
aboutLabel: 'About'
|
||||
darkMode: 'Dark mode'
|
||||
lightMode: 'Light mode'
|
||||
mode: 'Toggle dark/light mode'
|
||||
about:
|
||||
h1: 'About IT-Tools'
|
||||
h1p1: 'This wonderful website, made with ❤ by'
|
||||
h1p2: ', 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!'
|
||||
h1p3: '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'
|
||||
h1p4: 'sponsoring me'
|
||||
h2: Technologies
|
||||
h2p1: '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'
|
||||
h2p2: 'file of the repository.'
|
||||
h3: 'Found a bug? A tool is missing?'
|
||||
h3p1: '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'
|
||||
h3p2: 'issues section'
|
||||
h3p3: 'in the GitHub repository.'
|
||||
h3p4: 'And if you found a bug, or something doesn''''t work as expected, please file a bug report in the'
|
||||
h3p5: 'issues section'
|
||||
h3p6: 'in the GitHub repository.'
|
||||
404:
|
||||
notFound: '404 Not Found'
|
||||
sorry: 'Sorry, this page does not seem to exist'
|
||||
maybe: 'Maybe the cache is doing tricky things, try force-refreshing?'
|
||||
backHome: 'Back home'
|
||||
toolCard:
|
||||
new: New
|
||||
|
||||
@@ -30,13 +30,14 @@
|
||||
"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": {
|
||||
"@it-tools/bip39": "^0.0.4",
|
||||
"@it-tools/oggen": "^1.3.0",
|
||||
"@sindresorhus/slugify": "^2.2.0",
|
||||
"@sindresorhus/slugify": "^2.2.1",
|
||||
"@tiptap/pm": "^2.1.6",
|
||||
"@tiptap/starter-kit": "^2.1.6",
|
||||
"@tiptap/vue-3": "^2.0.3",
|
||||
@@ -66,7 +67,7 @@
|
||||
"lodash": "^4.17.21",
|
||||
"mathjs": "^11.9.1",
|
||||
"mime-types": "^2.1.35",
|
||||
"monaco-editor": "^0.41.0",
|
||||
"monaco-editor": "^0.43.0",
|
||||
"naive-ui": "^2.34.3",
|
||||
"netmask": "^2.0.2",
|
||||
"node-forge": "^1.3.1",
|
||||
@@ -77,6 +78,7 @@
|
||||
"randombytes": "^2.1.0",
|
||||
"sql-formatter": "^13.0.0",
|
||||
"ua-parser-js": "^1.0.35",
|
||||
"ulid": "^2.3.0",
|
||||
"unicode-emoji-json": "^0.4.0",
|
||||
"unplugin-auto-import": "^0.16.4",
|
||||
"uuid": "^9.0.0",
|
||||
@@ -116,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",
|
||||
|
||||
369
pnpm-lock.yaml
generated
369
pnpm-lock.yaml
generated
@@ -12,8 +12,8 @@ dependencies:
|
||||
specifier: ^1.3.0
|
||||
version: 1.3.0
|
||||
'@sindresorhus/slugify':
|
||||
specifier: ^2.2.0
|
||||
version: 2.2.0
|
||||
specifier: ^2.2.1
|
||||
version: 2.2.1
|
||||
'@tiptap/pm':
|
||||
specifier: ^2.1.6
|
||||
version: 2.1.6
|
||||
@@ -102,8 +102,8 @@ dependencies:
|
||||
specifier: ^2.1.35
|
||||
version: 2.1.35
|
||||
monaco-editor:
|
||||
specifier: ^0.41.0
|
||||
version: 0.41.0
|
||||
specifier: ^0.43.0
|
||||
version: 0.43.0
|
||||
naive-ui:
|
||||
specifier: ^2.34.3
|
||||
version: 2.34.3(vue@3.3.4)
|
||||
@@ -134,6 +134,9 @@ dependencies:
|
||||
ua-parser-js:
|
||||
specifier: ^1.0.35
|
||||
version: 1.0.35
|
||||
ulid:
|
||||
specifier: ^2.3.0
|
||||
version: 2.3.0
|
||||
unicode-emoji-json:
|
||||
specifier: ^0.4.0
|
||||
version: 0.4.0
|
||||
@@ -247,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
|
||||
@@ -2517,8 +2523,8 @@ packages:
|
||||
resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
|
||||
dev: true
|
||||
|
||||
/@sindresorhus/slugify@2.2.0:
|
||||
resolution: {integrity: sha512-9Vybc/qX8Kj6pxJaapjkFbiUJPk7MAkCh/GFCxIBnnsuYCFPIXKvnLidG8xlepht3i24L5XemUmGtrJ3UWrl6w==}
|
||||
/@sindresorhus/slugify@2.2.1:
|
||||
resolution: {integrity: sha512-MkngSCRZ8JdSOCHRaYd+D01XhvU3Hjy6MGl06zhOk614hp9EOAp5gIkBeQg7wtmxpitU6eAL4kdiRMcJa2dlrw==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
'@sindresorhus/transliterate': 1.6.0
|
||||
@@ -2915,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
|
||||
@@ -3269,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:
|
||||
@@ -3851,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
|
||||
@@ -3931,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'}
|
||||
@@ -4066,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
|
||||
@@ -4074,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
|
||||
@@ -4119,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'}
|
||||
@@ -4165,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:
|
||||
@@ -4236,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:
|
||||
@@ -4299,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:
|
||||
@@ -4315,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:
|
||||
@@ -4399,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:
|
||||
@@ -4622,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'}
|
||||
@@ -4639,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'}
|
||||
@@ -4721,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:
|
||||
@@ -4771,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'}
|
||||
@@ -5480,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'}
|
||||
@@ -5750,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:
|
||||
@@ -5837,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:
|
||||
@@ -5858,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'}
|
||||
@@ -5888,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:
|
||||
@@ -6033,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
|
||||
@@ -6124,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:
|
||||
@@ -6455,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:
|
||||
@@ -6659,8 +6873,8 @@ packages:
|
||||
pkg-types: 1.0.3
|
||||
ufo: 1.1.2
|
||||
|
||||
/monaco-editor@0.41.0:
|
||||
resolution: {integrity: sha512-1o4olnZJsiLmv5pwLEAmzHTE/5geLKQ07BrGxlF4Ri/AXAc2yyDGZwHjiTqD8D/ROKUZmwMA28A+yEowLNOEcA==}
|
||||
/monaco-editor@0.43.0:
|
||||
resolution: {integrity: sha512-cnoqwQi/9fml2Szamv1XbSJieGJ1Dc8tENVMD26Kcfl7xGQWp7OBKMjlwKVGYFJ3/AXJjSOGvcqK7Ry/j9BM1Q==}
|
||||
dev: false
|
||||
|
||||
/moo@0.5.2:
|
||||
@@ -6744,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:
|
||||
@@ -6916,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
|
||||
@@ -6973,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:
|
||||
@@ -7019,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:
|
||||
@@ -7026,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:
|
||||
@@ -7432,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'}
|
||||
@@ -7545,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'}
|
||||
@@ -7681,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:
|
||||
@@ -7758,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:
|
||||
@@ -7901,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'}
|
||||
@@ -7982,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
|
||||
@@ -8072,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'}
|
||||
@@ -8246,6 +8550,11 @@ packages:
|
||||
/ufo@1.1.2:
|
||||
resolution: {integrity: sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==}
|
||||
|
||||
/ulid@2.3.0:
|
||||
resolution: {integrity: sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==}
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/unbox-primitive@1.0.2:
|
||||
resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
|
||||
dependencies:
|
||||
@@ -8519,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:
|
||||
@@ -8782,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}
|
||||
@@ -8875,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'}
|
||||
@@ -9244,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'}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import { FavoriteFilled } from '@vicons/material';
|
||||
|
||||
import { useToolStore } from '@/tools/tools.store';
|
||||
import type { Tool } from '@/tools/tools.types';
|
||||
|
||||
@@ -26,18 +24,15 @@ function toggleFavorite(event: MouseEvent) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<c-button
|
||||
variant="text"
|
||||
circle
|
||||
:type="buttonType"
|
||||
:style="{ opacity: isFavorite ? 1 : 0.2 }"
|
||||
@click="toggleFavorite"
|
||||
>
|
||||
<n-icon :component="FavoriteFilled" />
|
||||
</c-button>
|
||||
</template>
|
||||
{{ isFavorite ? 'Remove from favorites' : 'Add to favorites' }}
|
||||
</n-tooltip>
|
||||
<c-tooltip :tooltip="isFavorite ? 'Remove from favorites' : 'Add to favorites' ">
|
||||
<c-button
|
||||
variant="text"
|
||||
circle
|
||||
:type="buttonType"
|
||||
:style="{ opacity: isFavorite ? 1 : 0.2 }"
|
||||
@click="toggleFavorite"
|
||||
>
|
||||
<icon-mdi-heart />
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
</template>
|
||||
|
||||
@@ -13,14 +13,11 @@ const tooltipText = computed(() => isJustCopied.value ? 'Copied!' : 'Copy to cli
|
||||
<template>
|
||||
<c-input-text v-model:value="value">
|
||||
<template #suffix>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<c-button circle variant="text" size="small" @click="copy()">
|
||||
<icon-mdi-content-copy />
|
||||
</c-button>
|
||||
</template>
|
||||
{{ tooltipText }}
|
||||
</n-tooltip>
|
||||
<c-tooltip :tooltip="tooltipText">
|
||||
<c-button circle variant="text" size="small" @click="copy()">
|
||||
<icon-mdi-content-copy />
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
</template>
|
||||
</c-input-text>
|
||||
</template>
|
||||
|
||||
@@ -7,56 +7,43 @@ const { isDarkTheme } = toRefs(styleStore);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<c-button
|
||||
circle
|
||||
variant="text"
|
||||
href="https://github.com/CorentinTh/it-tools"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="IT-Tools' GitHub repository"
|
||||
>
|
||||
<n-icon size="25" :component="BrandGithub" />
|
||||
</c-button>
|
||||
</template>
|
||||
Github repository
|
||||
</n-tooltip>
|
||||
<c-tooltip :tooltip="$t('home.nav.github')" position="bottom">
|
||||
<c-button
|
||||
circle
|
||||
variant="text"
|
||||
href="https://github.com/CorentinTh/it-tools"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
:aria-label="$t('home.nav.githubRepository')"
|
||||
>
|
||||
<n-icon size="25" :component="BrandGithub" />
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<c-button
|
||||
circle
|
||||
variant="text"
|
||||
href="https://twitter.com/ittoolsdottech"
|
||||
rel="noopener"
|
||||
target="_blank"
|
||||
aria-label="IT Tools' Twitter account"
|
||||
>
|
||||
<n-icon size="25" :component="BrandTwitter" />
|
||||
</c-button>
|
||||
</template>
|
||||
IT Tools' Twitter account
|
||||
</n-tooltip>
|
||||
<c-tooltip :tooltip="$t('home.nav.twitter')" position="bottom">
|
||||
<c-button
|
||||
circle
|
||||
variant="text"
|
||||
href="https://twitter.com/ittoolsdottech"
|
||||
rel="noopener"
|
||||
target="_blank"
|
||||
:aria-label="$t('home.nav.twitterAccount')"
|
||||
>
|
||||
<n-icon size="25" :component="BrandTwitter" />
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<c-button circle variant="text" to="/about" aria-label="About">
|
||||
<n-icon size="25" :component="InfoCircle" />
|
||||
</c-button>
|
||||
</template>
|
||||
About
|
||||
</n-tooltip>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<c-button circle variant="text" aria-label="Toggle dark/light mode" @click="() => styleStore.toggleDark()">
|
||||
<n-icon v-if="isDarkTheme" size="25" :component="Sun" />
|
||||
<n-icon v-else size="25" :component="Moon" />
|
||||
</c-button>
|
||||
</template>
|
||||
<span v-if="isDarkTheme">Light mode</span>
|
||||
<span v-else>Dark mode</span>
|
||||
</n-tooltip>
|
||||
<c-tooltip :tooltip="$t('home.nav.about')" position="bottom">
|
||||
<c-button circle variant="text" to="/about" :aria-label="$t('home.nav.aboutLabel')">
|
||||
<n-icon size="25" :component="InfoCircle" />
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
<c-tooltip :tooltip="isDarkTheme ? $t('home.nav.lightMode') : $t('home.nav.darkMode')" position="bottom">
|
||||
<c-button circle variant="text" :aria-label="$t('home.nav.mode')" @click="() => styleStore.toggleDark()">
|
||||
<n-icon v-if="isDarkTheme" size="25" :component="Sun" />
|
||||
<n-icon v-else size="25" :component="Moon" />
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -11,17 +11,7 @@ const tooltipText = computed(() => isJustCopied.value ? 'Copied!' : initialText)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<span class="value" @click="copy()">{{ value }}</span>
|
||||
</template>
|
||||
{{ tooltipText }}
|
||||
</n-tooltip>
|
||||
<c-tooltip :tooltip="tooltipText">
|
||||
<span cursor-pointer font-mono @click="copy()">{{ value }}</span>
|
||||
</c-tooltip>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
.value {
|
||||
cursor: pointer;
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -40,7 +40,7 @@ const tooltipText = computed(() => isJustCopied.value ? 'Copied!' : copyMessage.
|
||||
|
||||
<template>
|
||||
<div style="overflow-x: hidden; width: 100%">
|
||||
<c-card class="result-card">
|
||||
<c-card relative>
|
||||
<n-scrollbar
|
||||
x-scrollable
|
||||
trigger="none"
|
||||
@@ -50,16 +50,13 @@ const tooltipText = computed(() => isJustCopied.value ? 'Copied!' : copyMessage.
|
||||
<n-code :code="value" :language="language" :trim="false" data-test-id="area-content" />
|
||||
</n-config-provider>
|
||||
</n-scrollbar>
|
||||
<n-tooltip v-if="value" trigger="hover">
|
||||
<template #trigger>
|
||||
<div class="copy-button" :class="[copyPlacement]">
|
||||
<c-button circle important:h-10 important:w-10 @click="copy()">
|
||||
<n-icon size="22" :component="Copy" />
|
||||
</c-button>
|
||||
</div>
|
||||
</template>
|
||||
<span>{{ tooltipText }}</span>
|
||||
</n-tooltip>
|
||||
<div absolute right-10px top-10px>
|
||||
<c-tooltip v-if="value" :tooltip="tooltipText" position="left">
|
||||
<c-button circle important:h-10 important:w-10 @click="copy()">
|
||||
<n-icon size="22" :component="Copy" />
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
</div>
|
||||
</c-card>
|
||||
<div v-if="copyPlacement === 'outside'" mt-4 flex justify-center>
|
||||
<c-button @click="copy()">
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -26,7 +26,7 @@ const appTheme = useAppTheme();
|
||||
:bordered="false"
|
||||
:color="{ color: theme.primaryColor, textColor: theme.tagColor }"
|
||||
>
|
||||
New
|
||||
{{ $t('toolCard.new') }}
|
||||
</n-tag>
|
||||
|
||||
<FavoriteButton :tool="tool" />
|
||||
|
||||
@@ -41,7 +41,7 @@ const tools = computed<ToolCategory[]>(() => [
|
||||
</div>
|
||||
<div class="divider" />
|
||||
<div class="subtitle">
|
||||
Handy tools for developers
|
||||
{{ $t('home.subtitle') }}
|
||||
</div>
|
||||
</div>
|
||||
</RouterLink>
|
||||
@@ -88,24 +88,23 @@ const tools = computed<ToolCategory[]>(() => [
|
||||
<c-button
|
||||
circle
|
||||
variant="text"
|
||||
aria-label="Toggle menu"
|
||||
:aria-label="$t('home.toggleMenu')"
|
||||
@click="styleStore.isMenuCollapsed = !styleStore.isMenuCollapsed"
|
||||
>
|
||||
<NIcon size="25" :component="Menu2" />
|
||||
</c-button>
|
||||
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<c-button to="/" circle variant="text" aria-label="Home">
|
||||
<NIcon size="25" :component="Home2" />
|
||||
</c-button>
|
||||
</template>
|
||||
Home
|
||||
</n-tooltip>
|
||||
<c-tooltip tooltip="Home" position="bottom">
|
||||
<c-button to="/" circle variant="text" :aria-label="$t('home.home')">
|
||||
<NIcon size="25" :component="Home2" />
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
|
||||
<c-button v-if="config.app.env === 'development'" to="/c-lib" circle variant="text" aria-label="UI Lib">
|
||||
<icon-mdi:brush-variant text-20px />
|
||||
</c-button>
|
||||
<c-tooltip tooltip="UI Lib" position="bottom">
|
||||
<c-button v-if="config.app.env === 'development'" to="/c-lib" circle variant="text" :aria-label="$t('home.uiLib')">
|
||||
<icon-mdi:brush-variant text-20px />
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
|
||||
<command-palette />
|
||||
|
||||
@@ -113,23 +112,20 @@ const tools = computed<ToolCategory[]>(() => [
|
||||
<NavbarButtons v-if="!styleStore.isSmallScreen" />
|
||||
</div>
|
||||
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<c-button
|
||||
round
|
||||
href="https://www.buymeacoffee.com/cthmsst"
|
||||
rel="noopener"
|
||||
target="_blank"
|
||||
class="support-button"
|
||||
:bordered="false"
|
||||
@click="() => tracker.trackEvent({ eventName: 'Support button clicked' })"
|
||||
>
|
||||
Buy me a coffee
|
||||
<NIcon v-if="!styleStore.isSmallScreen" :component="Heart" ml-2 />
|
||||
</c-button>
|
||||
</template>
|
||||
❤ Support IT Tools development !
|
||||
</n-tooltip>
|
||||
<c-tooltip position="bottom" tooltip="Support IT Tools development">
|
||||
<c-button
|
||||
round
|
||||
href="https://www.buymeacoffee.com/cthmsst"
|
||||
rel="noopener"
|
||||
target="_blank"
|
||||
class="support-button"
|
||||
:bordered="false"
|
||||
@click="() => tracker.trackEvent({ eventName: 'Support button clicked' })"
|
||||
>
|
||||
{{ $t('home.buyMeACoffee') }}
|
||||
<NIcon v-if="!styleStore.isSmallScreen" :component="Heart" ml-2 />
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
</div>
|
||||
<slot />
|
||||
</template>
|
||||
|
||||
@@ -11,17 +11,17 @@ useHead({ title: 'Page not found - IT Tools' });
|
||||
</span>
|
||||
|
||||
<h1 m-0 mt-3>
|
||||
404 Not Found
|
||||
{{ $t('404.notFound') }}
|
||||
</h1>
|
||||
<div mt-4 op-60>
|
||||
Sorry, this page does not seem to exist
|
||||
{{ $t('404.sorry') }}
|
||||
</div>
|
||||
<div mb-8 op-60>
|
||||
Maybe the cache is doing tricky things, try force-refreshing?
|
||||
{{ $t('404.maybe') }}
|
||||
</div>
|
||||
|
||||
<c-button to="/">
|
||||
Back home
|
||||
{{ $t('404.backHome') }}
|
||||
</c-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -7,79 +7,57 @@ const { tracker } = useTracker();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="about-page">
|
||||
<n-h1>About</n-h1>
|
||||
<n-p>
|
||||
This wonderful website, made with ❤ by
|
||||
<div mx-auto mt-50px max-w-600px>
|
||||
<h1>{{ $t('about.h1') }}</h1>
|
||||
<p text-justify>
|
||||
{{ $t('about.h1p1') }}
|
||||
<c-link href="https://github.com/CorentinTh" target="_blank" rel="noopener">
|
||||
Corentin Thomasset
|
||||
</c-link>,
|
||||
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!
|
||||
</n-p>
|
||||
<n-p>
|
||||
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
|
||||
</c-link>{{ $t('about.h1p2') }}
|
||||
</p>
|
||||
<p text-justify>
|
||||
{{ $t('about.h1p3') }}
|
||||
<c-link
|
||||
href="https://www.buymeacoffee.com/cthmsst"
|
||||
rel="noopener"
|
||||
target="_blank"
|
||||
@click="() => tracker.trackEvent({ eventName: 'Support button clicked' })"
|
||||
>
|
||||
sponsoring me
|
||||
{{ $t('about.h1p4') }}
|
||||
</c-link>.
|
||||
</n-p>
|
||||
</p>
|
||||
|
||||
<n-h2>Technologies</n-h2>
|
||||
<n-p>
|
||||
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
|
||||
<h2>{{ $t('about.h2') }}</h2>
|
||||
<p text-justify>
|
||||
{{ $t('about.h2p1') }}
|
||||
<c-link href="https://github.com/CorentinTh/it-tools/blob/main/package.json" rel="noopener" target="_blank">
|
||||
package.json
|
||||
</c-link>
|
||||
file of the repository.
|
||||
</n-p>
|
||||
{{ $t('about.h2p2') }}
|
||||
</p>
|
||||
|
||||
<n-h2>Found a bug? A tool is missing?</n-h2>
|
||||
<n-p>
|
||||
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
|
||||
<h2>{{ $t('about.h3') }}</h2>
|
||||
<p text-justify>
|
||||
{{ $t('about.h3p1') }}
|
||||
<c-link
|
||||
href="https://github.com/CorentinTh/it-tools/issues/new/choose"
|
||||
rel="noopener"
|
||||
target="_blank"
|
||||
>
|
||||
issues section
|
||||
{{ $t('about.h3p2') }}
|
||||
</c-link>
|
||||
in the GitHub repository.
|
||||
</n-p>
|
||||
<n-p>
|
||||
And if you found a bug, or something doesn't work as expected, please file a bug report in the
|
||||
{{ $t('about.h3p3') }}
|
||||
</p>
|
||||
<p text-justify>
|
||||
{{ $t('about.h3p4') }}
|
||||
<c-link
|
||||
href="https://github.com/CorentinTh/it-tools/issues/new/choose"
|
||||
rel="noopener"
|
||||
target="_blank"
|
||||
>
|
||||
issues section
|
||||
{{ $t('about.h3p5') }}
|
||||
</c-link>
|
||||
in the GitHub repository.
|
||||
</n-p>
|
||||
{{ $t('about.h3p6') }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
.about-page {
|
||||
max-width: 600px;
|
||||
margin: 50px auto;
|
||||
box-sizing: border-box;
|
||||
|
||||
.n-h2 {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.n-p {
|
||||
text-align: justify;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -17,21 +17,21 @@ const { t } = useI18n();
|
||||
<div class="grid-wrapper">
|
||||
<n-grid v-if="config.showBanner" x-gap="12" y-gap="12" cols="1 400:2 800:3 1200:4 2000:8">
|
||||
<n-gi>
|
||||
<ColoredCard title="You like it-tools?" :icon="Heart">
|
||||
Give us a star on
|
||||
<ColoredCard :title="$t('home.follow.title')" :icon="Heart">
|
||||
{{ $t('home.follow.p1') }}
|
||||
<a
|
||||
href="https://github.com/CorentinTh/it-tools"
|
||||
rel="noopener"
|
||||
target="_blank"
|
||||
aria-label="IT-Tools' GitHub repository"
|
||||
:aria-label="$t('home.follow.githubRepository')"
|
||||
>GitHub</a>
|
||||
or follow us on
|
||||
{{ $t('home.follow.p2') }}
|
||||
<a
|
||||
href="https://twitter.com/ittoolsdottech"
|
||||
rel="noopener"
|
||||
target="_blank"
|
||||
aria-label="IT-Tools' Twitter account"
|
||||
>Twitter</a>! Thank you
|
||||
:aria-label="$t('home.follow.twitterAccount')"
|
||||
>Twitter</a>{{ $t('home.follow.thankYou') }}
|
||||
<n-icon :component="Heart" />
|
||||
</ColoredCard>
|
||||
</n-gi>
|
||||
@@ -39,7 +39,7 @@ const { t } = useI18n();
|
||||
|
||||
<transition name="height">
|
||||
<div v-if="toolStore.favoriteTools.length > 0">
|
||||
<n-h3>Your favorite tools</n-h3>
|
||||
<n-h3>{{ $t('home.categories.favoriteTools') }}</n-h3>
|
||||
<n-grid x-gap="12" y-gap="12" cols="1 400:2 800:3 1200:4 2000:8">
|
||||
<n-gi v-for="tool in toolStore.favoriteTools" :key="tool.name">
|
||||
<ToolCard :tool="tool" />
|
||||
@@ -57,7 +57,7 @@ const { t } = useI18n();
|
||||
</n-grid>
|
||||
</div>
|
||||
|
||||
<n-h3>All the tools</n-h3>
|
||||
<n-h3>{{ $t('home.categories.allTools') }}</n-h3>
|
||||
<n-grid x-gap="12" y-gap="12" cols="1 400:2 800:3 1200:4 2000:8">
|
||||
<n-gi v-for="tool in toolStore.tools" :key="tool.name">
|
||||
<transition>
|
||||
|
||||
@@ -29,3 +29,9 @@ export const i18nPlugin: Plugin = {
|
||||
app.use(i18n);
|
||||
},
|
||||
};
|
||||
|
||||
export const translate = function (localeKey: string) {
|
||||
// @ts-expect-error global
|
||||
const hasKey = i18n.global.te(localeKey, i18n.global.locale);
|
||||
return hasKey ? i18n.global.t(localeKey) : localeKey;
|
||||
};
|
||||
|
||||
@@ -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() {
|
||||
</c-button>
|
||||
</div>
|
||||
|
||||
<n-table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ header.position }}</th>
|
||||
<th>{{ header.title }}</th>
|
||||
<th>{{ header.size }}</th>
|
||||
<th>{{ header.mean }}</th>
|
||||
<th>{{ header.variance }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="{ title, size, mean, variance, position } of results" :key="title">
|
||||
<td>{{ position }}</td>
|
||||
<td>{{ title }}</td>
|
||||
<td>{{ size }}</td>
|
||||
<td>{{ mean }}</td>
|
||||
<td>{{ variance }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</n-table>
|
||||
<c-table :data="results" :headers="header" />
|
||||
|
||||
<div mt-5 flex justify-center gap-3>
|
||||
<c-button @click="copyAsMarkdown()">
|
||||
Copy as markdown table
|
||||
|
||||
@@ -39,14 +39,11 @@ function onInputEnter(index: number) {
|
||||
autofocus
|
||||
@keydown.enter="onInputEnter(index)"
|
||||
/>
|
||||
<n-tooltip>
|
||||
<template #trigger>
|
||||
<c-button circle variant="text" @click="values.splice(index, 1)">
|
||||
<n-icon :component="Trash" depth="3" size="18" />
|
||||
</c-button>
|
||||
</template>
|
||||
Delete value
|
||||
</n-tooltip>
|
||||
<c-tooltip tooltip="Delete this value">
|
||||
<c-button circle variant="text" @click="values.splice(index, 1)">
|
||||
<n-icon :component="Trash" depth="3" size="18" />
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
</div>
|
||||
|
||||
<c-button @click="addValue">
|
||||
|
||||
@@ -167,34 +167,8 @@ const cronValidationRules = [
|
||||
</div>
|
||||
</c-card>
|
||||
</div>
|
||||
<n-table v-else size="small">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-left" scope="col">
|
||||
Symbol
|
||||
</th>
|
||||
<th class="text-left" scope="col">
|
||||
Meaning
|
||||
</th>
|
||||
<th class="text-left" scope="col">
|
||||
Example
|
||||
</th>
|
||||
<th class="text-left" scope="col">
|
||||
Equivalent
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="{ symbol, meaning, example, equivalent } in helpers" :key="symbol">
|
||||
<td>{{ symbol }}</td>
|
||||
<td>{{ meaning }}</td>
|
||||
<td>
|
||||
<code>{{ example }}</code>
|
||||
</td>
|
||||
<td>{{ equivalent }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</n-table>
|
||||
|
||||
<c-table v-else :data="helpers" />
|
||||
</c-card>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -6,13 +6,9 @@ const { icon, title, action, isActive } = toRefs(props);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<c-button circle variant="text" :type="isActive?.() ? 'primary' : 'default'" @click="action">
|
||||
<n-icon :component="icon" />
|
||||
</c-button>
|
||||
</template>
|
||||
|
||||
{{ title }}
|
||||
</n-tooltip>
|
||||
<c-tooltip :tooltip="title">
|
||||
<c-button circle variant="text" :type="isActive?.() ? 'primary' : 'default'" @click="action">
|
||||
<n-icon :component="icon" />
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
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 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';
|
||||
import { tool as textDiff } from './text-diff';
|
||||
@@ -74,7 +76,7 @@ import { tool as xmlFormatter } from './xml-formatter';
|
||||
export const toolsByCategory: ToolCategory[] = [
|
||||
{
|
||||
name: 'Crypto',
|
||||
components: [tokenGenerator, hashText, bcrypt, uuidGenerator, cypher, bip39, hmacGenerator, rsaKeyPairGenerator, passwordStrengthAnalyser],
|
||||
components: [tokenGenerator, hashText, bcrypt, uuidGenerator, ulidGenerator, cypher, bip39, hmacGenerator, rsaKeyPairGenerator, passwordStrengthAnalyser],
|
||||
},
|
||||
{
|
||||
name: 'Converter',
|
||||
@@ -87,6 +89,7 @@ export const toolsByCategory: ToolCategory[] = [
|
||||
colorConverter,
|
||||
caseConverter,
|
||||
textToNatoAlphabet,
|
||||
textToBinary,
|
||||
yamlToJson,
|
||||
yamlToToml,
|
||||
jsonToYaml,
|
||||
|
||||
@@ -61,19 +61,16 @@ const secretValidationRules = [
|
||||
:validation-rules="secretValidationRules"
|
||||
>
|
||||
<template #suffix>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<c-button circle variant="text" size="small" @click="refreshSecret">
|
||||
<icon-mdi-refresh />
|
||||
</c-button>
|
||||
</template>
|
||||
Generate secret token
|
||||
</n-tooltip>
|
||||
<c-tooltip tooltip="Generate a new random secret">
|
||||
<c-button circle variant="text" size="small" @click="refreshSecret">
|
||||
<icon-mdi-refresh />
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
</template>
|
||||
</c-input-text>
|
||||
|
||||
<div>
|
||||
<TokenDisplay :tokens="tokens" style="margin-top: 2px" />
|
||||
<TokenDisplay :tokens="tokens" />
|
||||
|
||||
<n-progress :percentage="(100 * interval) / 30" :color="theme.primaryColor" :show-indicator="false" />
|
||||
<div style="text-align: center">
|
||||
|
||||
@@ -11,7 +11,7 @@ const { tokens } = toRefs(props);
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="labels" w-full flex items-center>
|
||||
<div mb-5px w-full flex items-center>
|
||||
<div flex-1 text-left>
|
||||
Previous
|
||||
</div>
|
||||
@@ -22,60 +22,24 @@ const { tokens } = toRefs(props);
|
||||
Next
|
||||
</div>
|
||||
</div>
|
||||
<n-input-group>
|
||||
<n-tooltip trigger="hover" placement="bottom">
|
||||
<template #trigger>
|
||||
<c-button important:h-12 data-test-id="previous-otp" @click.prevent="copyPrevious(tokens.previous)">
|
||||
{{ tokens.previous }}
|
||||
</c-button>
|
||||
</template>
|
||||
<div>{{ previousCopied ? 'Copied !' : 'Copy previous OTP' }}</div>
|
||||
</n-tooltip>
|
||||
<n-tooltip trigger="hover" placement="bottom">
|
||||
<template #trigger>
|
||||
<c-button
|
||||
data-test-id="current-otp"
|
||||
class="current-otp"
|
||||
important:h-12
|
||||
@click.prevent="copyCurrent(tokens.current)"
|
||||
>
|
||||
{{ tokens.current }}
|
||||
</c-button>
|
||||
</template>
|
||||
<div>{{ currentCopied ? 'Copied !' : 'Copy current OTP' }}</div>
|
||||
</n-tooltip>
|
||||
<n-tooltip trigger="hover" placement="bottom">
|
||||
<template #trigger>
|
||||
<c-button important:h-12 data-test-id="next-otp" @click.prevent="copyNext(tokens.next)">
|
||||
{{
|
||||
tokens.next
|
||||
}}
|
||||
</c-button>
|
||||
</template>
|
||||
<div>{{ nextCopied ? 'Copied !' : 'Copy next OTP' }}</div>
|
||||
</n-tooltip>
|
||||
</n-input-group>
|
||||
<div flex items-center>
|
||||
<c-tooltip :tooltip="previousCopied ? 'Copied !' : 'Copy previous OTP'" position="bottom" flex-1>
|
||||
<c-button data-test-id="previous-otp" w-full important:h-12 important:rounded-r-none important:font-mono @click.prevent="copyPrevious(tokens.previous)">
|
||||
{{ tokens.previous }}
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
<c-tooltip :tooltip="currentCopied ? 'Copied !' : 'Copy current OTP'" position="bottom" flex-1 flex-basis-5xl>
|
||||
<c-button
|
||||
data-test-id="current-otp" w-full important:border-x="1px solid gray op-40" important:h-12 important:rounded-0 important:text-22px @click.prevent="copyCurrent(tokens.current)"
|
||||
>
|
||||
{{ tokens.current }}
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
<c-tooltip :tooltip="nextCopied ? 'Copied !' : 'Copy next OTP'" position="bottom" flex-1>
|
||||
<c-button data-test-id="next-otp" w-full important:h-12 important:rounded-l-none @click.prevent="copyNext(tokens.next)">
|
||||
{{ tokens.next }}
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
.current-otp {
|
||||
font-size: 22px;
|
||||
flex: 1 0 35% !important;
|
||||
}
|
||||
|
||||
.n-button {
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
.labels {
|
||||
div {
|
||||
padding: 0 2px 6px 2px;
|
||||
line-height: 1.25;
|
||||
}
|
||||
}
|
||||
|
||||
.n-input-group > * {
|
||||
flex: 1 0 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
12
src/tools/text-to-binary/index.ts
Normal file
12
src/tools/text-to-binary/index.ts
Normal file
@@ -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'),
|
||||
});
|
||||
25
src/tools/text-to-binary/text-to-binary.e2e.spec.ts
Normal file
25
src/tools/text-to-binary/text-to-binary.e2e.spec.ts
Normal file
@@ -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');
|
||||
});
|
||||
});
|
||||
32
src/tools/text-to-binary/text-to-binary.models.test.ts
Normal file
32
src/tools/text-to-binary/text-to-binary.models.test.ts
Normal file
@@ -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');
|
||||
});
|
||||
});
|
||||
});
|
||||
22
src/tools/text-to-binary/text-to-binary.models.ts
Normal file
22
src/tools/text-to-binary/text-to-binary.models.ts
Normal file
@@ -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('');
|
||||
}
|
||||
42
src/tools/text-to-binary/text-to-binary.vue
Normal file
42
src/tools/text-to-binary/text-to-binary.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<script setup lang="ts">
|
||||
import { convertAsciiBinaryToText, convertTextToAsciiBinary } from './text-to-binary.models';
|
||||
import { withDefaultOnError } from '@/utils/defaults';
|
||||
import { useCopy } from '@/composable/copy';
|
||||
import { isNotThrowing } from '@/utils/boolean';
|
||||
|
||||
const inputText = ref('');
|
||||
const binaryFromText = computed(() => convertTextToAsciiBinary(inputText.value));
|
||||
const { copy: copyBinary } = useCopy({ source: binaryFromText });
|
||||
|
||||
const inputBinary = ref('');
|
||||
const textFromBinary = computed(() => withDefaultOnError(() => convertAsciiBinaryToText(inputBinary.value), ''));
|
||||
const inputBinaryValidationRules = [
|
||||
{
|
||||
validator: (value: string) => isNotThrowing(() => convertAsciiBinaryToText(value)),
|
||||
message: 'Binary should be a valid ASCII binary string with multiples of 8 bits',
|
||||
},
|
||||
];
|
||||
const { copy: copyText } = useCopy({ source: textFromBinary });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<c-card title="Text to ASCII binary">
|
||||
<c-input-text v-model:value="inputText" multiline placeholder="e.g. 'Hello world'" label="Enter text to convert to binary" autosize autofocus raw-text test-id="text-to-binary-input" />
|
||||
<c-input-text v-model:value="binaryFromText" label="Binary from your text" multiline raw-text readonly mt-2 placeholder="The binary representation of your text will be here" test-id="text-to-binary-output" />
|
||||
<div mt-2 flex justify-center>
|
||||
<c-button :disabled="!binaryFromText" @click="copyBinary()">
|
||||
Copy binary to clipboard
|
||||
</c-button>
|
||||
</div>
|
||||
</c-card>
|
||||
|
||||
<c-card title="ASCII binary to text">
|
||||
<c-input-text v-model:value="inputBinary" multiline placeholder="e.g. '01001000 01100101 01101100 01101100 01101111'" label="Enter binary to convert to text" autosize raw-text :validation-rules="inputBinaryValidationRules" test-id="binary-to-text-input" />
|
||||
<c-input-text v-model:value="textFromBinary" label="Text from your binary" multiline raw-text readonly mt-2 placeholder="The text representation of your binary will be here" test-id="binary-to-text-output" />
|
||||
<div mt-2 flex justify-center>
|
||||
<c-button :disabled="!textFromBinary" @click="copyText()">
|
||||
Copy text to clipboard
|
||||
</c-button>
|
||||
</div>
|
||||
</c-card>
|
||||
</template>
|
||||
@@ -1,11 +1,11 @@
|
||||
import { ArrowsShuffle } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: 'Token generator',
|
||||
name: translate('tools.token-generator.title'),
|
||||
path: '/token-generator',
|
||||
description:
|
||||
'Generate random string with the chars you want: uppercase or lowercase letters, numbers and/or symbols.',
|
||||
description: translate('tools.token-generator.description'),
|
||||
keywords: ['token', 'random', 'string', 'alphanumeric', 'symbols', 'number', 'letters', 'lowercase', 'uppercase'],
|
||||
component: () => import('./token-generator.tool.vue'),
|
||||
icon: ArrowsShuffle,
|
||||
|
||||
@@ -6,4 +6,10 @@ tools:
|
||||
uppercase: Uppercase (ABC...)
|
||||
lowercase: Lowercase (abc...)
|
||||
numbers: Numbers (123...)
|
||||
symbols: Symbols (!-;...)
|
||||
symbols: Symbols (!-;...)
|
||||
length: Length
|
||||
tokenPlaceholder: 'The token...'
|
||||
copied: Token copied to the clipboard
|
||||
button:
|
||||
copy: Copy
|
||||
refresh: Refresh
|
||||
@@ -21,7 +21,7 @@ const [token, refreshToken] = computedRefreshable(() =>
|
||||
}),
|
||||
);
|
||||
|
||||
const { copy } = useCopy({ source: token, text: 'Token copied to the clipboard' });
|
||||
const { copy } = useCopy({ source: token, text: t('tools.token-generator.copied') });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -51,14 +51,14 @@ const { copy } = useCopy({ source: token, text: 'Token copied to the clipboard'
|
||||
</div>
|
||||
</n-form>
|
||||
|
||||
<n-form-item :label="`Length (${length})`" label-placement="left">
|
||||
<n-form-item :label="`${t('tools.token-generator.length')} (${length})`" label-placement="left">
|
||||
<n-slider v-model:value="length" :step="1" :min="1" :max="512" />
|
||||
</n-form-item>
|
||||
|
||||
<c-input-text
|
||||
v-model:value="token"
|
||||
multiline
|
||||
placeholder="The token..."
|
||||
:placeholder="t('tools.token-generator.tokenPlaceholder')"
|
||||
readonly
|
||||
rows="3"
|
||||
autosize
|
||||
@@ -67,10 +67,10 @@ const { copy } = useCopy({ source: token, text: 'Token copied to the clipboard'
|
||||
|
||||
<div mt-5 flex justify-center gap-3>
|
||||
<c-button @click="copy()">
|
||||
Copy
|
||||
{{ t('tools.token-generator.button.copy') }}
|
||||
</c-button>
|
||||
<c-button @click="refreshToken">
|
||||
Refresh
|
||||
{{ t('tools.token-generator.button.refresh') }}
|
||||
</c-button>
|
||||
</div>
|
||||
</c-card>
|
||||
|
||||
12
src/tools/ulid-generator/index.ts
Normal file
12
src/tools/ulid-generator/index.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { SortDescendingNumbers } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: 'ULID generator',
|
||||
path: '/ulid-generator',
|
||||
description: 'Generate random Universally Unique Lexicographically Sortable Identifier (ULID).',
|
||||
keywords: ['ulid', 'generator', 'random', 'id', 'alphanumeric', 'identity', 'token', 'string', 'identifier', 'unique'],
|
||||
component: () => import('./ulid-generator.vue'),
|
||||
icon: SortDescendingNumbers,
|
||||
createdAt: new Date('2023-09-11'),
|
||||
});
|
||||
23
src/tools/ulid-generator/ulid-generator.e2e.spec.ts
Normal file
23
src/tools/ulid-generator/ulid-generator.e2e.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
const ULID_REGEX = /[0-9A-Z]{26}/;
|
||||
|
||||
test.describe('Tool - ULID generator', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/ulid-generator');
|
||||
});
|
||||
|
||||
test('Has correct title', async ({ page }) => {
|
||||
await expect(page).toHaveTitle('ULID generator - IT Tools');
|
||||
});
|
||||
|
||||
test('the refresh button generates a new ulid', async ({ page }) => {
|
||||
const ulid = await page.getByTestId('ulids').textContent();
|
||||
expect(ulid?.trim()).toMatch(ULID_REGEX);
|
||||
|
||||
await page.getByTestId('refresh').click();
|
||||
const newUlid = await page.getByTestId('ulids').textContent();
|
||||
expect(ulid?.trim()).not.toBe(newUlid?.trim());
|
||||
expect(newUlid?.trim()).toMatch(ULID_REGEX);
|
||||
});
|
||||
});
|
||||
46
src/tools/ulid-generator/ulid-generator.vue
Normal file
46
src/tools/ulid-generator/ulid-generator.vue
Normal file
@@ -0,0 +1,46 @@
|
||||
<script setup lang="ts">
|
||||
import { ulid } from 'ulid';
|
||||
import _ from 'lodash';
|
||||
import { computedRefreshable } from '@/composable/computedRefreshable';
|
||||
import { useCopy } from '@/composable/copy';
|
||||
|
||||
const amount = useStorage('ulid-generator-amount', 1);
|
||||
const formats = [{ label: 'Raw', value: 'raw' }, { label: 'JSON', value: 'json' }] as const;
|
||||
const format = useStorage<typeof formats[number]['value']>('ulid-generator-format', formats[0].value);
|
||||
|
||||
const [ulids, refreshUlids] = computedRefreshable(() => {
|
||||
const ids = _.times(amount.value, () => ulid());
|
||||
|
||||
if (format.value === 'json') {
|
||||
return JSON.stringify(ids, null, 2);
|
||||
}
|
||||
|
||||
return ids.join('\n');
|
||||
});
|
||||
|
||||
const { copy } = useCopy({ source: ulids, text: 'ULIDs copied to the clipboard' });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div flex flex-col justify-center gap-2>
|
||||
<div flex items-center>
|
||||
<label w-75px> Quantity:</label>
|
||||
<n-input-number v-model:value="amount" min="1" max="100" flex-1 />
|
||||
</div>
|
||||
|
||||
<c-buttons-select v-model:value="format" :options="formats" label="Format: " label-width="75px" />
|
||||
|
||||
<c-card mt-5 flex data-test-id="ulids">
|
||||
<pre m-0 m-x-auto>{{ ulids }}</pre>
|
||||
</c-card>
|
||||
|
||||
<div flex justify-center gap-2>
|
||||
<c-button data-test-id="refresh" @click="refreshUlids()">
|
||||
Refresh
|
||||
</c-button>
|
||||
<c-button @click="copy()">
|
||||
Copy
|
||||
</c-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -14,25 +14,18 @@ const { userAgentInfo, sections } = toRefs(props);
|
||||
<n-grid :x-gap="12" :y-gap="8" cols="1 s:2" responsive="screen">
|
||||
<n-gi v-for="{ heading, icon, content } in sections" :key="heading">
|
||||
<c-card h-full>
|
||||
<n-page-header>
|
||||
<template #title>
|
||||
{{ heading }}
|
||||
</template>
|
||||
<template v-if="icon" #avatar>
|
||||
<n-icon size="30" :component="icon" :depth="3" />
|
||||
</template>
|
||||
</n-page-header>
|
||||
<div flex items-center gap-3>
|
||||
<n-icon size="30" :component="icon" :depth="3" />
|
||||
<span text-lg>{{ heading }}</span>
|
||||
</div>
|
||||
|
||||
<div mt-5 flex gap-2>
|
||||
<span v-for="{ label, getValue } in content" :key="label">
|
||||
<n-tooltip v-if="getValue(userAgentInfo)" trigger="hover">
|
||||
<template #trigger>
|
||||
<n-tag type="success" size="large" round :bordered="false">
|
||||
{{ getValue(userAgentInfo) }}
|
||||
</n-tag>
|
||||
</template>
|
||||
{{ label }}
|
||||
</n-tooltip>
|
||||
<c-tooltip v-if="getValue(userAgentInfo)" :tooltip="label">
|
||||
<n-tag type="success" size="large" round :bordered="false">
|
||||
{{ getValue(userAgentInfo) }}
|
||||
</n-tag>
|
||||
</c-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
<div flex flex-col>
|
||||
|
||||
14
src/ui/c-buttons-select/c-buttons-select.demo.vue
Normal file
14
src/ui/c-buttons-select/c-buttons-select.demo.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
const optionsA = [
|
||||
{ label: 'Option A', value: 'a' },
|
||||
{ label: 'Option B', value: 'b', tooltip: 'This is a tooltip' },
|
||||
{ label: 'Option C', value: 'c' },
|
||||
];
|
||||
const valueA = ref('a');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<c-buttons-select v-model:value="valueA" :options="optionsA" label="Label: " />
|
||||
<c-buttons-select v-model:value="valueA" :options="optionsA" label="Label: " label-position="left" mt-2 />
|
||||
<c-buttons-select v-model:value="valueA" :options="optionsA" label="Label: " label-position="left" mt-2 />
|
||||
</template>
|
||||
5
src/ui/c-buttons-select/c-buttons-select.types.ts
Normal file
5
src/ui/c-buttons-select/c-buttons-select.types.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import type { CSelectOption } from '../c-select/c-select.types';
|
||||
|
||||
export type CButtonSelectOption<T> = CSelectOption<T> & {
|
||||
tooltip?: string
|
||||
};
|
||||
59
src/ui/c-buttons-select/c-buttons-select.vue
Normal file
59
src/ui/c-buttons-select/c-buttons-select.vue
Normal file
@@ -0,0 +1,59 @@
|
||||
<script setup lang="ts" generic="T extends unknown">
|
||||
import type { CLabelProps } from '../c-label/c-label.types';
|
||||
import type { CButtonSelectOption } from './c-buttons-select.types';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
options?: CButtonSelectOption<T>[] | string[]
|
||||
value?: T
|
||||
size?: 'small' | 'medium' | 'large'
|
||||
} & CLabelProps >(),
|
||||
{
|
||||
options: () => [],
|
||||
value: undefined,
|
||||
labelPosition: 'left',
|
||||
size: 'medium',
|
||||
},
|
||||
);
|
||||
|
||||
const emits = defineEmits(['update:value']);
|
||||
|
||||
const { options: rawOptions, size } = toRefs(props);
|
||||
|
||||
const options = computed(() => {
|
||||
return rawOptions.value.map((option: string | CButtonSelectOption<T>) => {
|
||||
if (typeof option === 'string') {
|
||||
return { label: option, value: option };
|
||||
}
|
||||
|
||||
return option;
|
||||
});
|
||||
});
|
||||
|
||||
const value = useVModel(props, 'value', emits);
|
||||
|
||||
function selectOption(option: CButtonSelectOption<T>) {
|
||||
// @ts-expect-error vue template generic is a bit flacky thanks to withDefaults
|
||||
value.value = option.value;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<c-label v-bind="props">
|
||||
<div class="flex gap-2">
|
||||
<c-tooltip
|
||||
v-for="option in options" :key="option.value"
|
||||
:tooltip="option.tooltip"
|
||||
>
|
||||
<c-button
|
||||
:test-id="option.value"
|
||||
:size="size"
|
||||
:type="option.value === value ? 'primary' : 'default'"
|
||||
@click="selectOption(option)"
|
||||
>
|
||||
{{ option.label }}
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
</div>
|
||||
</c-label>
|
||||
</template>
|
||||
20
src/ui/c-table/c-table.demo.vue
Normal file
20
src/ui/c-table/c-table.demo.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<script lang="ts" setup>
|
||||
const data = ref([
|
||||
{ name: 'John', age: 20 },
|
||||
{ name: 'Jane', age: 24 },
|
||||
{ name: 'Joe', age: 30 },
|
||||
]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<c-table :data="data" mb-2 />
|
||||
<c-table :data="data" hide-headers mb-2 />
|
||||
<c-table :data="data" :headers="['age', 'name']" mb-2 />
|
||||
<c-table :data="data" :headers="['age', { key: 'name', label: 'Full name' }]" mb-2 />
|
||||
<c-table :data="data" :headers="{ name: 'full name' }" mb-2 />
|
||||
<c-table :data="data" :headers="['age', 'name']">
|
||||
<template #age="{ value }">
|
||||
{{ value }}yo
|
||||
</template>
|
||||
</c-table>
|
||||
</template>
|
||||
4
src/ui/c-table/c-table.types.ts
Normal file
4
src/ui/c-table/c-table.types.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export type HeaderConfiguration = (string | {
|
||||
key: string
|
||||
label?: string
|
||||
})[] | Record<string, string>;
|
||||
65
src/ui/c-table/c-table.vue
Normal file
65
src/ui/c-table/c-table.vue
Normal file
@@ -0,0 +1,65 @@
|
||||
<script lang="ts" setup>
|
||||
import _ from 'lodash';
|
||||
import type { HeaderConfiguration } from './c-table.types';
|
||||
|
||||
const props = withDefaults(defineProps<{ data?: Record<string, unknown>[]; headers?: HeaderConfiguration ; hideHeaders?: boolean; description?: string }>(), { data: () => [], headers: undefined, hideHeaders: false, description: 'Data table' });
|
||||
const { data, headers: rawHeaders, hideHeaders } = toRefs(props);
|
||||
|
||||
const headers = computed(() => {
|
||||
if (rawHeaders.value) {
|
||||
if (Array.isArray(rawHeaders.value)) {
|
||||
return rawHeaders.value.map((value) => {
|
||||
if (typeof value === 'string') {
|
||||
return { key: value, label: value };
|
||||
}
|
||||
|
||||
const { key, label } = value;
|
||||
|
||||
return {
|
||||
key,
|
||||
label: label ?? key,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return _.map(rawHeaders.value, (value, key) => ({
|
||||
key, label: value,
|
||||
}));
|
||||
}
|
||||
|
||||
return _.chain(data.value)
|
||||
.map(row => Object.keys(row))
|
||||
.flatten()
|
||||
.uniq()
|
||||
.map(key => ({ key, label: key }))
|
||||
.value();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative overflow-x-auto rounded">
|
||||
<table class="w-full border-collapse text-left text-sm text-gray-500 dark:text-gray-400" role="table" :aria-label="description">
|
||||
<thead v-if="!hideHeaders" class="bg-#ffffff uppercase text-gray-700 dark:bg-#333333 dark:text-gray-400">
|
||||
<tr>
|
||||
<th v-for="header in headers" :key="header.key" scope="col" class="px-6 py-3 text-xs">
|
||||
{{ header.label }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="(row, i) in data" :key="i" border-b="1px solid dark:#282828 #efeff5" class="bg-white dark:bg-#232323"
|
||||
:class="{
|
||||
'important:border-b-none': i === data.length - 1,
|
||||
}"
|
||||
>
|
||||
<td v-for="header in headers" :key="header.key" class="px-6 py-4">
|
||||
<slot :name="header" :row="row" :headers="headers" :value="row[header.key]">
|
||||
{{ row[header.key] }}
|
||||
</slot>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,3 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
const positions = ['top', 'bottom', 'left', 'right'] as const;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<c-tooltip>
|
||||
@@ -14,4 +18,18 @@
|
||||
Hover me
|
||||
</c-tooltip>
|
||||
</div>
|
||||
|
||||
<div mt-5>
|
||||
<h2>Tooltip positions</h2>
|
||||
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<div v-for="position in positions" :key="position">
|
||||
<c-tooltip :position="position" :tooltip="`Tooltip ${position}`">
|
||||
<c-button>
|
||||
{{ position }}
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,22 +1,30 @@
|
||||
<script setup lang="ts">
|
||||
const props = withDefaults(defineProps<{ tooltip?: string }>(), { tooltip: '' });
|
||||
const { tooltip } = toRefs(props);
|
||||
const props = withDefaults(defineProps<{ tooltip?: string; position?: 'top' | 'bottom' | 'left' | 'right' }>(), {
|
||||
tooltip: undefined,
|
||||
position: 'top',
|
||||
});
|
||||
const { tooltip, position } = toRefs(props);
|
||||
|
||||
const targetRef = ref();
|
||||
const isTargetHovered = useElementHover(targetRef);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative" inline-block>
|
||||
<div relative inline-block>
|
||||
<div ref="targetRef">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="absolute bottom-100% left-50% z-10 mb-5px whitespace-nowrap rounded bg-black px-12px py-6px text-sm text-white shadow-lg transition transition transition-duration-0.2s -translate-x-1/2"
|
||||
v-if="tooltip || $slots.tooltip"
|
||||
class="absolute z-10 whitespace-nowrap rounded bg-black px-12px py-6px text-sm text-white shadow-lg transition transition transition-duration-0.2s"
|
||||
:class="{
|
||||
'op-0 scale-0': isTargetHovered === false,
|
||||
'op-100 scale-100': isTargetHovered,
|
||||
'bottom-100% left-50% -translate-x-1/2 mb-5px': position === 'top',
|
||||
'top-100% left-50% -translate-x-1/2 mt-5px': position === 'bottom',
|
||||
'right-100% top-50% -translate-y-1/2 mr-5px': position === 'left',
|
||||
'left-100% top-50% -translate-y-1/2 ml-5px': position === 'right',
|
||||
}"
|
||||
>
|
||||
<slot
|
||||
|
||||
@@ -20,5 +20,6 @@ export default defineConfig({
|
||||
shortcuts: {
|
||||
'pretty-scrollbar': 'scrollbar scrollbar-rounded scrollbar-thumb-color-gray-300 scrollbar-track-color-gray-100 dark:scrollbar-thumb-color-#424242 dark:scrollbar-track-color-#686868',
|
||||
'divider': 'h-1px bg-current op-10',
|
||||
'bg-surface': 'bg-#ffffff dark:bg-#232323',
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user