mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-05-07 14:57:12 -04:00
feat: Synchronous Update
This commit is contained in:
commit
e7ccf65fe5
95 changed files with 8870 additions and 5322 deletions
34
.github/ISSUE_TEMPLATE/bug-report.md
vendored
34
.github/ISSUE_TEMPLATE/bug-report.md
vendored
|
@ -1,34 +0,0 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve our tools
|
||||
title: '[BUG] '
|
||||
labels: bug
|
||||
assignees: CorentinTh
|
||||
---
|
||||
|
||||
**Which tool is impacted?**
|
||||
Example: the token generator
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Configuration (please complete the following information):**
|
||||
|
||||
- Device: [e.g. iPhone6, ]
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
48
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
48
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
name: 🐞 Bug Report
|
||||
description: File a bug report.
|
||||
labels: ['bug', 'triage']
|
||||
assignees:
|
||||
- CorentinTh
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
|
||||
- type: textarea
|
||||
id: bug-description
|
||||
attributes:
|
||||
label: Describe the bug
|
||||
description: A clear and concise description of what the bug is. If you intend to submit a PR for this issue, tell us in the description. Thanks!
|
||||
placeholder: Bug description
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: Also tell us, what did you expect to happen? If you have a screenshot, you can paste it here.
|
||||
placeholder: Tell us what you see!
|
||||
value: 'A bug happened!'
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: version
|
||||
attributes:
|
||||
label: System information
|
||||
description: What is you environment? You can use the `npx envinfo --system --browsers` command to get this information.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: app-type
|
||||
attributes:
|
||||
label: Where did you encounter the bug?
|
||||
options:
|
||||
- Public app (it-tools.tech)
|
||||
- A self hosted
|
||||
- Other (installations, docker, etc.)
|
||||
validations:
|
||||
required: true
|
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
blank_issues_enabled: false
|
56
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
56
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
|
@ -0,0 +1,56 @@
|
|||
name: 🚀 New feature proposal
|
||||
description: Propose a new feature/enhancement or tool idea for IT-Tools
|
||||
labels: ['enhancement', 'triage']
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for your interest in the project and taking the time to fill out this feature report!
|
||||
|
||||
- type: dropdown
|
||||
id: request-type
|
||||
attributes:
|
||||
label: What type of request is this?
|
||||
options:
|
||||
- New tool idea
|
||||
- New feature for an existing tool
|
||||
- Deployment or CI/CD improvement
|
||||
- Self-hosting improvement
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: feature-description
|
||||
attributes:
|
||||
label: Clear and concise description of the feature you are proposing
|
||||
description: A clear and concise description of what the feature is.
|
||||
placeholder: 'Example: a token generator tool'
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: alternative
|
||||
attributes:
|
||||
label: Is their example of this tool in the wild?
|
||||
description: Provide link to already existing tool (like websites, apps, cli, ...) or npm packages that could be used or provide inspiration for the feature.
|
||||
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Any other context or screenshots about the feature request here.
|
||||
|
||||
- type: checkboxes
|
||||
id: checkboxes
|
||||
attributes:
|
||||
label: Validations
|
||||
description: Before submitting the issue, please make sure you do the following
|
||||
options:
|
||||
- label: Check the feature is not already implemented in the project.
|
||||
required: true
|
||||
- label: Check that there isn't already an issue that request the same feature to avoid creating a duplicate.
|
||||
required: true
|
||||
- label: Check that the feature can be implemented in a client side only app (IT-Tools is client side only, no server).
|
||||
required: true
|
19
.github/ISSUE_TEMPLATE/new-tool-request.md
vendored
19
.github/ISSUE_TEMPLATE/new-tool-request.md
vendored
|
@ -1,19 +0,0 @@
|
|||
---
|
||||
name: New tool request
|
||||
about: Suggest a new tool idea
|
||||
title: '[NEW TOOL]'
|
||||
labels: new tool
|
||||
assignees: CorentinTh
|
||||
---
|
||||
|
||||
**What tool do you want?**
|
||||
Example: a token generator
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Is their example of this tool in the wild?**
|
||||
Provide link to already existing tool or npm packages if any exists
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the feature request here.
|
13
.github/ISSUE_TEMPLATE/other-request.md
vendored
13
.github/ISSUE_TEMPLATE/other-request.md
vendored
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
name: Other request
|
||||
about: Any request that does not concern a tool creation, a new feature request on a tool or a bug
|
||||
title: '[OTHER] '
|
||||
labels:
|
||||
assignees: CorentinTh
|
||||
---
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the feature request here.
|
13
.github/ISSUE_TEMPLATE/tool-improvement.md
vendored
13
.github/ISSUE_TEMPLATE/tool-improvement.md
vendored
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
name: Tool improvement
|
||||
about: Improvement on an existing tool
|
||||
title: '[TOOL IMPROVEMENT]'
|
||||
labels: enhancement
|
||||
assignees: CorentinTh
|
||||
---
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the feature request here.
|
11
.github/fern-banner.svg
vendored
Normal file
11
.github/fern-banner.svg
vendored
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 62 KiB |
BIN
.github/logo-dark.png
vendored
Normal file
BIN
.github/logo-dark.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
BIN
.github/logo-white.png
vendored
Normal file
BIN
.github/logo-white.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 39 KiB |
BIN
.github/logo.png
vendored
BIN
.github/logo.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 7.8 KiB |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
@ -15,7 +15,7 @@ jobs:
|
|||
- run: corepack enable
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
|
|
69
.github/workflows/codeql-analysis.yml
vendored
69
.github/workflows/codeql-analysis.yml
vendored
|
@ -1,69 +0,0 @@
|
|||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ dev ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ dev ]
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more:
|
||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
2
.github/workflows/docker-nightly-release.yml
vendored
2
.github/workflows/docker-nightly-release.yml
vendored
|
@ -32,7 +32,7 @@ jobs:
|
|||
- run: corepack enable
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
|
|
2
.github/workflows/e2e-tests.yml
vendored
2
.github/workflows/e2e-tests.yml
vendored
|
@ -18,7 +18,7 @@ jobs:
|
|||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Get Playwright version
|
||||
|
|
2
.github/workflows/releases.yml
vendored
2
.github/workflows/releases.yml
vendored
|
@ -61,7 +61,7 @@ jobs:
|
|||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
|
|
83
CHANGELOG.md
83
CHANGELOG.md
|
@ -2,9 +2,51 @@
|
|||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
## Version 2024.05.13-a0bc346
|
||||
|
||||
### Features
|
||||
- **i18n**: added German translation (#1038) (2c2fb21)
|
||||
- **new tool**: Outlook Safelink Decoder (#911) (d3b32cc)
|
||||
- **new tool**: ascii art generator (#886) (fe349ad)
|
||||
- **i18n**: get locales on build (#880) (dc04615)
|
||||
- **i18n**: added vi tools translations (#876) (079aa21)
|
||||
- **i18n**: added zh tools translations (#874) (9c6b122)
|
||||
- **i18n**: added missing locale files in tools (#863) (7f5fa00)
|
||||
- **i18n**: added vietnamese language (#859) (1334bff)
|
||||
- **i18n**: added spanish language (#854) (85b50bb)
|
||||
- **i18n**: added portuguese language (#813) (c65ffb6)
|
||||
- **i18n**: added ukrainian language (#827) (693f362)
|
||||
- **new-tool**: yaml formater (#779) (fc06f01)
|
||||
- **new-tool**: added unicode conversion utilities (#858) (c46207f)
|
||||
|
||||
### Bug fixes
|
||||
- **language**: English language cleanup (#1036) (221ddfa)
|
||||
- **url-encoder, validation**: typo in validation of url-encoder.vue #1024 (cb5b462)
|
||||
- **integer base converter**: support bigint (#872) (9eac9cb)
|
||||
- **bcrypt tool**: allow salt rounds up to 100 (#987) (23f82d9)
|
||||
|
||||
### Refactoring
|
||||
- **lint**: removed extra semi (33e5294)
|
||||
- **auto-imports**: regen auto imports (1242842)
|
||||
- **home**: lightened tool cards (#882) (a07806c)
|
||||
- **home**: removed n-grid to prevent layout shift (#881) (10e56b3)
|
||||
- **i18n**: added locales per tool (#861) (95698cb)
|
||||
|
||||
### Chores
|
||||
- **issues**: prevent empty issues (#1078) (a0bc346)
|
||||
- **issues**: removed old issue templates (#1077) (5a7b0f9)
|
||||
- **node**: upgraded node version in CI workflows (b59942a)
|
||||
- **version**: release 2024.05.10-33e5294 (38d5687)
|
||||
- **issues**: improved issues template (2852c30)
|
||||
- **issues**: improved bug issue template (#1046) (a799234)
|
||||
|
||||
### Documentation
|
||||
- **changelog**: update changelog for 2024.05.10-33e5294 (9dfd347)
|
||||
|
||||
## Version 2023.12.21-5ed3693
|
||||
|
||||
### Features
|
||||
|
||||
- **i18n**: improve chinese i18n (#757) (2e56641)
|
||||
- **i18n**: add tooltip and favoriteButton i18n (#756) (a1037cf)
|
||||
- **i18n**: add Chinese translation base (#718) (8f99eb6)
|
||||
|
@ -12,6 +54,7 @@ All notable changes to this project will be documented in this file. See [standa
|
|||
- **new tool**: numeronym generator (#729) (e07e2ae)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- **jwt-parser**: jwt claim array support (#799) (5ed3693)
|
||||
- **camera-recorder**: stop camera on navigation (#782) (80e46c9)
|
||||
- **doc**: updated create new tool command in readme (#762) (7a70dbb)
|
||||
|
@ -20,6 +63,7 @@ All notable changes to this project will be documented in this file. See [standa
|
|||
- **eta**: corrected example (#737) (821cbea)
|
||||
|
||||
### Refactoring
|
||||
|
||||
- **about, i18n**: improved i18n dx with markdown (#753) (bd3edcb)
|
||||
- **token, i18n**: complete fr translation (#752) (de1ee69)
|
||||
- **uuid generator**: uuid version picker (#751) (38586ca)
|
||||
|
@ -29,6 +73,7 @@ All notable changes to this project will be documented in this file. See [standa
|
|||
- **bcrypt**: fix input label align (#721) (093ff31)
|
||||
|
||||
### Chores
|
||||
|
||||
- **deps**: switched from oui to oui-data for mac address lookup (#693) (0fe9a20)
|
||||
- **deps**: update unocss monorepo to ^0.57.0 (#638) (2e396d8)
|
||||
- **docker**: added armv7 plateform for docker releases (#722) (fe1de8c)
|
||||
|
@ -36,19 +81,23 @@ All notable changes to this project will be documented in this file. See [standa
|
|||
## Version 2023.11.02-7d94e11
|
||||
|
||||
### Features
|
||||
|
||||
- **i18n**: language selector (#710) (e86fd96)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- **dockerfile**: revert replacement of nginx image with non-privileged one (#716) (7d94e11)
|
||||
- **encryption**: alert on decryption error (#711) (02b0d0d)
|
||||
|
||||
### Refactoring
|
||||
|
||||
- **math-evaluator**: improved description (e87f4b1)
|
||||
- **math-evaluator**: improved search and UX (#713) (58de897)
|
||||
|
||||
## Version 2023.11.01-e164afb
|
||||
|
||||
### Features
|
||||
|
||||
- **command-palette**: clear prompt on palette close (#708) (d013696)
|
||||
- **command-palette**: added about page in command palette (99b1eb9)
|
||||
- **new tool**: random MAC address generator (#657) (cc3425d)
|
||||
|
@ -67,11 +116,13 @@ All notable changes to this project will be documented in this file. See [standa
|
|||
- **new tool**: text diff and comparator (#588) (81bfe57)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- **deps**: fix issue on slugify (#593) (#673) (720201a)
|
||||
- **deps**: update dependency monaco-editor to ^0.43.0 (#620) (e371ef7)
|
||||
- **deps**: update dependency sql-formatter to v13 (#606) (c7d4562)
|
||||
|
||||
### Refactoring
|
||||
|
||||
- **ui**: better ui demo preview menu (#664) (015c673)
|
||||
- **color-converter**: improved color-converter UX (#701) (abb8335)
|
||||
- **docker**: improved docker config (#700) (020e9cb)
|
||||
|
@ -88,6 +139,7 @@ All notable changes to this project will be documented in this file. See [standa
|
|||
- **bcrypt**: fix typo (#604) (e18bae1)
|
||||
|
||||
### Chores
|
||||
|
||||
- **deps**: clean unused dependencies (#709) (e164afb)
|
||||
- **deps**: update docker/setup-qemu-action action to v3 (#627) (4365226)
|
||||
- **deps**: update docker/setup-buildx-action action to v3 (#626) (57ecda1)
|
||||
|
@ -102,19 +154,23 @@ All notable changes to this project will be documented in this file. See [standa
|
|||
- **deps**: update dependency typescript to ~5.2.0 (#587) (f3e14fc)
|
||||
|
||||
### Doc
|
||||
|
||||
- **readme**: added contributors list (#622) (557b304)
|
||||
- **hosting**: added cloudron in the other hosting solutions section (#589) (06c3547)
|
||||
|
||||
## Version 2023.08.21-6f93cba
|
||||
|
||||
### Features
|
||||
|
||||
- **copy**: support legacy copy to clipboard for older browser (#581) (6f93cba)
|
||||
- **new tool**: string obfuscator (#575) (c58d6e3)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- **deps**: update dependency sql-formatter to v12 (#520) (2bcb77a)
|
||||
|
||||
### Chores
|
||||
|
||||
- **deps**: switched to fucking typescript v5 (#501) (76b2761)
|
||||
- **deps**: update dependency @antfu/eslint-config to ^0.40.0 (#552) (6ff9a01)
|
||||
- **deps**: update dependency prettier to v3 (#564) (a2b9b15)
|
||||
|
@ -124,6 +180,7 @@ All notable changes to this project will be documented in this file. See [standa
|
|||
## Version 2023.08.16-9bd4ad4
|
||||
|
||||
### Features
|
||||
|
||||
- **Case Converter**: Add lowercase and uppercase (#534) (7b6232a)
|
||||
- **new tool**: emoji picker (#551) (93f7cf0)
|
||||
- **ui**: added c-select in the ui lib (#550) (dfa1ba8)
|
||||
|
@ -144,6 +201,7 @@ All notable changes to this project will be documented in this file. See [standa
|
|||
- **base64-string-converter**: switch to encode and decode url safe base64 strings (#392) (0b20f1c)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- **deps**: update dependency uuid to v9 (#566) (5e12991)
|
||||
- **deps**: update dependency mathjs to v11 (#519) (7924456)
|
||||
- **deps**: update dependency @vueuse/router to v10 (#516) (ea0f27c)
|
||||
|
@ -163,6 +221,7 @@ All notable changes to this project will be documented in this file. See [standa
|
|||
- **ipv4-converter**: removed readonly on input (7aed9c5)
|
||||
|
||||
### Refactoring
|
||||
|
||||
- **navbar**: consistent spacing in navbar buttons (#507) (30f88fc)
|
||||
- **ui**: remove n-text (#506) (72c98a3)
|
||||
- **ui**: replaced some n-input to c-input (#505) (05ea545)
|
||||
|
@ -175,6 +234,7 @@ All notable changes to this project will be documented in this file. See [standa
|
|||
- **ui**: replaced some n-input with c-input-text (f7fc779)
|
||||
|
||||
### Chores
|
||||
|
||||
- **deps**: update dependency vitest to ^0.34.0 (#562) (9bd4ad4)
|
||||
- **deps**: update dependency node to v18.17.1 (#560) (65a9474)
|
||||
- **deps**: update dependency unocss to ^0.55.0 (#561) (85cc7a8)
|
||||
|
@ -215,47 +275,58 @@ All notable changes to this project will be documented in this file. See [standa
|
|||
- **lint**: switched to a better lint config (33c9b66)
|
||||
|
||||
### Refacor
|
||||
|
||||
- **transformers**: use monospace font for JSON and SQL text areas (#476) (ba4876d)
|
||||
|
||||
### Documentation
|
||||
|
||||
- **ide**: updated vscode extensions settings (#472) (847323c)
|
||||
|
||||
### Chors
|
||||
|
||||
- **deps**: updated vueuse dependency version (8515c24)
|
||||
|
||||
## Version 2023.05.14-77f2efc
|
||||
|
||||
### Features
|
||||
|
||||
- **list-converter**: a small converter who deals with column based data and do some stuff with it (#387) (83a7b3b)
|
||||
- **new tool**: phone parser and normalizer (ce3150c)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- **phone-parser**: use default country code (a43c546)
|
||||
- **home**: prevent weird blue border on card (3f6c8f0)
|
||||
|
||||
### Refactoring
|
||||
|
||||
- **ui**: replaced some n-input with c-input-text (77f2efc)
|
||||
|
||||
### Chores
|
||||
|
||||
- **issues**: updated new tool request issue template (edae4c6)
|
||||
|
||||
### Ui-lib
|
||||
|
||||
- **new-component**: added text input component in the c-lib (aad8d84)
|
||||
- **button**: size variants (401f13f)
|
||||
|
||||
## Version 2023.04.23-92bd835
|
||||
|
||||
### Features
|
||||
|
||||
- **ui-lib**: demo pages for c-lib components (92bd835)
|
||||
- **new-tool**: diff of two json objects (362f2fa)
|
||||
- **ipv4-range-expander**: expands a given IPv4 start and end address to a valid IPv4 subnet (#366) (df989e2)
|
||||
- **date converter**: auto focus main input (6d22025)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- **ts**: cleaned legacy typechecking warning (e88c1d5)
|
||||
- **mac-address-lookup**: added copy handler on button click (c311e38)
|
||||
|
||||
### Refactoring
|
||||
|
||||
- **ui-lib**: prevent c-button to shrink (61ece23)
|
||||
- **ui**: replaced naive ui cards with custom ones (f080933)
|
||||
- **clean**: removed unused lodash import (bb32513)
|
||||
|
@ -265,48 +336,60 @@ All notable changes to this project will be documented in this file. See [standa
|
|||
## Version 2023.04.14-dbad773
|
||||
|
||||
### Features
|
||||
|
||||
- **new-tool**: http status codes (8355bd2)
|
||||
|
||||
### Refactoring
|
||||
|
||||
- **uuid-generator**: prevent NaN in quantity (6fb4994)
|
||||
|
||||
### Chores
|
||||
|
||||
- **release**: create a github release on new version (dbad773)
|
||||
- **version**: reset CHANGELOG content to support new format (85cb0ff)
|
||||
|
||||
## Version 2023.04.14-f9b77b7
|
||||
|
||||
### Features
|
||||
|
||||
- **new-tool**: http status codes (8355bd2)
|
||||
|
||||
### Refactoring
|
||||
|
||||
- **uuid-generator**: prevent NaN in quantity (6fb4994)
|
||||
|
||||
### Chores
|
||||
|
||||
- **release**: create a github release on new version (f9b77b7)
|
||||
- **version**: reset CHANGELOG content to support new format (85cb0ff)
|
||||
|
||||
## Version 2023.04.14-2f0d239
|
||||
|
||||
### Features
|
||||
|
||||
- **new-tool**: http status codes (8355bd2)
|
||||
|
||||
### Refactoring
|
||||
|
||||
- **uuid-generator**: prevent NaN in quantity (6fb4994)
|
||||
|
||||
### Chores
|
||||
|
||||
- **release**: create a github release on new version (2f0d239)
|
||||
- **version**: reset CHANGELOG content to support new format (85cb0ff)
|
||||
|
||||
## Version 2023.04.14-474cae4
|
||||
|
||||
### Features
|
||||
|
||||
- **new-tool**: http status codes (8355bd2)
|
||||
|
||||
### Refactoring
|
||||
|
||||
- **uuid-generator**: prevent NaN in quantity (6fb4994)
|
||||
|
||||
### Chores
|
||||
|
||||
- **release**: create a github release on new version (474cae4)
|
||||
- **version**: reset CHANGELOG content to support new format (85cb0ff)
|
||||
|
||||
|
|
12
README.md
12
README.md
|
@ -1,7 +1,15 @@
|
|||

|
||||
<picture>
|
||||
<source srcset="./.github/logo-dark.png" media="(prefers-color-scheme: light)">
|
||||
<source srcset="./.github/logo-white.png" media="(prefers-color-scheme: dark)">
|
||||
<img src="./.github/logo-dark.png" alt="logo">
|
||||
</picture>
|
||||
|
||||
Useful tools for developer and people working in IT. [Have a look !](https://it-tools.tech).
|
||||
|
||||
## Sponsors
|
||||
|
||||
[](https://bit.ly/3zBl7DG)
|
||||
|
||||
## Functionalities and roadmap
|
||||
|
||||
Please check the [issues](https://github.com/CorentinTh/it-tools/issues) to see if some feature listed to be implemented.
|
||||
|
@ -113,7 +121,7 @@ Big thanks to all the people who have already contributed!
|
|||
|
||||
## Credits
|
||||
|
||||
Coded with ❤️ by [Corentin Thomasset](//corentin-thomasset.fr).
|
||||
Coded with ❤️ by [Corentin Thomasset](https://corentin.tech?utm_source=it-tools&utm_medium=readme).
|
||||
|
||||
This project is continuously deployed using [vercel.com](https://vercel.com).
|
||||
|
||||
|
|
15
components.d.ts
vendored
15
components.d.ts
vendored
|
@ -72,6 +72,7 @@ declare module '@vue/runtime-core' {
|
|||
DockerRunToDockerComposeConverter: typeof import('./src/tools/docker-run-to-docker-compose-converter/docker-run-to-docker-compose-converter.vue')['default']
|
||||
DynamicValues: typeof import('./src/tools/benchmark-builder/dynamic-values.vue')['default']
|
||||
Editor: typeof import('./src/tools/html-wysiwyg-editor/editor/editor.vue')['default']
|
||||
EmailNormalizer: typeof import('./src/tools/email-normalizer/email-normalizer.vue')['default']
|
||||
EmojiCard: typeof import('./src/tools/emoji-picker/emoji-card.vue')['default']
|
||||
EmojiGrid: typeof import('./src/tools/emoji-picker/emoji-grid.vue')['default']
|
||||
EmojiPicker: typeof import('./src/tools/emoji-picker/emoji-picker.vue')['default']
|
||||
|
@ -92,6 +93,7 @@ declare module '@vue/runtime-core' {
|
|||
IbanValidatorAndParser: typeof import('./src/tools/iban-validator-and-parser/iban-validator-and-parser.vue')['default']
|
||||
'IconMdi:brushVariant': typeof import('~icons/mdi/brush-variant')['default']
|
||||
'IconMdi:kettleSteamOutline': typeof import('~icons/mdi/kettle-steam-outline')['default']
|
||||
IconMdiArrowDown: typeof import('~icons/mdi/arrow-down')['default']
|
||||
IconMdiCamera: typeof import('~icons/mdi/camera')['default']
|
||||
IconMdiChevronDown: typeof import('~icons/mdi/chevron-down')['default']
|
||||
IconMdiChevronRight: typeof import('~icons/mdi/chevron-right')['default']
|
||||
|
@ -119,6 +121,7 @@ declare module '@vue/runtime-core' {
|
|||
JsonMinify: typeof import('./src/tools/json-minify/json-minify.vue')['default']
|
||||
JsonToCsv: typeof import('./src/tools/json-to-csv/json-to-csv.vue')['default']
|
||||
JsonToToml: typeof import('./src/tools/json-to-toml/json-to-toml.vue')['default']
|
||||
JsonToXml: typeof import('./src/tools/json-to-xml/json-to-xml.vue')['default']
|
||||
JsonToYaml: typeof import('./src/tools/json-to-yaml-converter/json-to-yaml.vue')['default']
|
||||
JsonViewer: typeof import('./src/tools/json-viewer/json-viewer.vue')['default']
|
||||
JwtParser: typeof import('./src/tools/jwt-parser/jwt-parser.vue')['default']
|
||||
|
@ -128,6 +131,7 @@ declare module '@vue/runtime-core' {
|
|||
LoremIpsumGenerator: typeof import('./src/tools/lorem-ipsum-generator/lorem-ipsum-generator.vue')['default']
|
||||
MacAddressGenerator: typeof import('./src/tools/mac-address-generator/mac-address-generator.vue')['default']
|
||||
MacAddressLookup: typeof import('./src/tools/mac-address-lookup/mac-address-lookup.vue')['default']
|
||||
MarkdownToHtml: typeof import('./src/tools/markdown-to-html/markdown-to-html.vue')['default']
|
||||
MathEvaluator: typeof import('./src/tools/math-evaluator/math-evaluator.vue')['default']
|
||||
MenuBar: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar.vue')['default']
|
||||
MenuBarItem: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar-item.vue')['default']
|
||||
|
@ -136,6 +140,8 @@ declare module '@vue/runtime-core' {
|
|||
MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default']
|
||||
MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default']
|
||||
NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default']
|
||||
NButton: typeof import('naive-ui')['NButton']
|
||||
NCheckbox: typeof import('naive-ui')['NCheckbox']
|
||||
NCode: typeof import('naive-ui')['NCode']
|
||||
NCollapseTransition: typeof import('naive-ui')['NCollapseTransition']
|
||||
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
|
||||
|
@ -149,12 +155,13 @@ declare module '@vue/runtime-core' {
|
|||
NH3: typeof import('naive-ui')['NH3']
|
||||
NIcon: typeof import('naive-ui')['NIcon']
|
||||
NInputNumber: typeof import('naive-ui')['NInputNumber']
|
||||
NLabel: typeof import('naive-ui')['NLabel']
|
||||
NLayout: typeof import('naive-ui')['NLayout']
|
||||
NLayoutSider: typeof import('naive-ui')['NLayoutSider']
|
||||
NMenu: typeof import('naive-ui')['NMenu']
|
||||
NScrollbar: typeof import('naive-ui')['NScrollbar']
|
||||
NSpace: typeof import('naive-ui')['NSpace']
|
||||
NSpin: typeof import('naive-ui')['NSpin']
|
||||
NSwitch: typeof import('naive-ui')['NSwitch']
|
||||
NTable: typeof import('naive-ui')['NTable']
|
||||
NTag: typeof import('naive-ui')['NTag']
|
||||
NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default']
|
||||
|
@ -166,6 +173,11 @@ declare module '@vue/runtime-core' {
|
|||
PhoneParserAndFormatter: typeof import('./src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue')['default']
|
||||
QrCodeGenerator: typeof import('./src/tools/qr-code-generator/qr-code-generator.vue')['default']
|
||||
RandomPortGenerator: typeof import('./src/tools/random-port-generator/random-port-generator.vue')['default']
|
||||
RegexMemo: typeof import('./src/tools/regex-memo/regex-memo.vue')['default']
|
||||
'RegexMemo.content': typeof import('./src/tools/regex-memo/regex-memo.content.md')['default']
|
||||
'RegexMemo.content.fr': typeof import('./src/tools/regex-memo/regex-memo.content.fr.md')['default']
|
||||
'RegexMemo.content.zh': typeof import('./src/tools/regex-memo/regex-memo.content.zh.md')['default']
|
||||
RegexTester: typeof import('./src/tools/regex-tester/regex-tester.vue')['default']
|
||||
ResultRow: typeof import('./src/tools/ipv4-range-expander/result-row.vue')['default']
|
||||
RomanNumeralConverter: typeof import('./src/tools/roman-numeral-converter/roman-numeral-converter.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
|
@ -198,6 +210,7 @@ declare module '@vue/runtime-core' {
|
|||
UuidGenerator: typeof import('./src/tools/uuid-generator/uuid-generator.vue')['default']
|
||||
WifiQrCodeGenerator: typeof import('./src/tools/wifi-qr-code-generator/wifi-qr-code-generator.vue')['default']
|
||||
XmlFormatter: typeof import('./src/tools/xml-formatter/xml-formatter.vue')['default']
|
||||
XmlToJson: typeof import('./src/tools/xml-to-json/xml-to-json.vue')['default']
|
||||
YamlToJson: typeof import('./src/tools/yaml-to-json-converter/yaml-to-json.vue')['default']
|
||||
YamlToToml: typeof import('./src/tools/yaml-to-toml/yaml-to-toml.vue')['default']
|
||||
YamlViewer: typeof import('./src/tools/yaml-viewer/yaml-viewer.vue')['default']
|
||||
|
|
455
locales/de.yml
Normal file
455
locales/de.yml
Normal file
|
@ -0,0 +1,455 @@
|
|||
'404':
|
||||
notFound: 404 Nicht gefunden
|
||||
sorry: Entschuldigung, diese Seite scheint nicht zu existieren
|
||||
maybe: >-
|
||||
Vielleicht macht der Cache etwas Seltsames. Mit einem erzwungenen Neuladen
|
||||
versuchen?
|
||||
backHome: Zurück zur Startseite
|
||||
home:
|
||||
categories:
|
||||
newestTools: Neueste Tools
|
||||
favoriteTools: Deine Lieblingstools
|
||||
allTools: Alle Tools
|
||||
subtitle: Praktische Tools für Entwickler
|
||||
toggleMenu: Menü umschalten
|
||||
home: Startseite
|
||||
uiLib: UI-Bibliothek
|
||||
support: Unterstütze die Entwicklung von IT-Tools
|
||||
buyMeACoffee: Kauf mir einen Kaffee
|
||||
follow:
|
||||
title: Magst du IT-Tools?
|
||||
p1: Gib uns einen Stern auf
|
||||
githubRepository: IT-Tools GitHub-Repository
|
||||
p2: oder folge uns auf
|
||||
twitterAccount: IT-Tools Twitter-Konto
|
||||
thankYou: Vielen Dank!
|
||||
nav:
|
||||
github: GitHub-Repository
|
||||
githubRepository: IT-Tools GitHub-Repository
|
||||
twitter: Twitter-Konto
|
||||
twitterAccount: IT-Tools Twitter-Konto
|
||||
about: Über IT-Tools
|
||||
aboutLabel: Über
|
||||
darkMode: Dunkelmodus
|
||||
lightMode: Hellmodus
|
||||
mode: Wechseln zwischen dunklem/hellem Modus
|
||||
about:
|
||||
content: >
|
||||
# Über IT-Tools
|
||||
|
||||
Diese wunderbare Website, erstellt mit ❤ von [Corentin
|
||||
Thomasset](https://corentin.tech?utm_source=it-tools&utm_medium=about), sammelt nützliche Tools für
|
||||
Entwickler und Menschen, die in der IT arbeiten. Wenn du sie nützlich
|
||||
findest, teile sie gerne mit Personen, von denen du denkst, dass sie sie
|
||||
ebenfalls nützlich finden könnten, und vergiss nicht, sie in deiner
|
||||
Lesezeichenleiste zu speichern!
|
||||
|
||||
IT-Tools ist Open Source (unter der MIT-Lizenz) und kostenlos und wird es
|
||||
immer sein, aber es kostet mich Geld, die Website zu hosten und den
|
||||
Domainnamen zu erneuern. Wenn du meine Arbeit unterstützen möchtest und mich
|
||||
ermutigen möchtest, mehr Tools hinzuzufügen, überlege bitte, mich durch
|
||||
[Sponsoring](https://www.buymeacoffee.com/cthmsst) zu unterstützen.
|
||||
|
||||
## Technologien
|
||||
|
||||
IT-Tools wurde mit Vue.js (Vue 3) und der Naive UI-Komponentenbibliothek
|
||||
erstellt und wird von Vercel gehostet und kontinuierlich bereitgestellt. In
|
||||
einigen Tools werden Drittanbieter-Open-Source-Bibliotheken verwendet. Du
|
||||
findest die vollständige Liste in der
|
||||
[package.json](https://github.com/CorentinTh/it-tools/blob/main/package.json)-Datei
|
||||
des Repositorys.
|
||||
|
||||
## Einen Fehler gefunden? Ein Tool fehlt?
|
||||
|
||||
Wenn du ein Tool benötigst, das hier noch nicht vorhanden ist, und du
|
||||
denkst, dass es nützlich sein könnte, bist du herzlich eingeladen, einen
|
||||
Feature-Request im
|
||||
[Issues-Bereich](https://github.com/CorentinTh/it-tools/issues/new/choose)
|
||||
im GitHub-Repository einzureichen.
|
||||
|
||||
Und wenn du einen Fehler gefunden hast oder etwas nicht wie erwartet
|
||||
funktioniert, melde bitte einen Fehler im
|
||||
[Issues-Bereich](https://github.com/CorentinTh/it-tools/issues/new/choose)
|
||||
im GitHub-Repository.
|
||||
favoriteButton:
|
||||
remove: Aus Favoriten entfernen
|
||||
add: Zu Favoriten hinzufügen
|
||||
toolCard:
|
||||
new: Neu
|
||||
search:
|
||||
label: Suche
|
||||
tools:
|
||||
categories:
|
||||
favorite-tools: Deine Lieblingstools
|
||||
crypto: Krypto
|
||||
converter: Konverter
|
||||
web: Web
|
||||
images and videos: Bilder & Videos
|
||||
development: Entwicklung
|
||||
network: Netzwerk
|
||||
math: Mathematik
|
||||
measurement: Messung
|
||||
text: Text
|
||||
data: Daten
|
||||
password-strength-analyser:
|
||||
title: Passwortstärken-Analysator
|
||||
description: >-
|
||||
Ermittle die Stärke deines Passworts mit diesem Client-seitigen
|
||||
Passwortstärken-Analysator und Tool zur Schätzung der Knackzeit.
|
||||
chronometer:
|
||||
title: Chronometer
|
||||
description: >-
|
||||
Überwache die Dauer einer Sache. Im Grunde ein Chronometer mit einfachen
|
||||
Chronometerfunktionen.
|
||||
token-generator:
|
||||
title: Token-Generator
|
||||
description: >-
|
||||
Generiere eine zufällige Zeichenfolge mit den von dir gewünschten Zeichen,
|
||||
Groß- oder Kleinbuchstaben, Zahlen und/oder Symbolen.
|
||||
uppercase: Großbuchstaben (ABC...)
|
||||
lowercase: Kleinbuchstaben (abc...)
|
||||
numbers: Zahlen (123...)
|
||||
symbols: Symbole (!-;...)
|
||||
length: Länge
|
||||
tokenPlaceholder: Der Token ...
|
||||
copied: Token in die Zwischenablage kopiert
|
||||
button:
|
||||
copy: Kopieren
|
||||
refresh: Aktualisieren
|
||||
percentage-calculator:
|
||||
title: Prozentrechner
|
||||
description: >-
|
||||
Berechne einfach Prozentsätze von einem Wert zu einem anderen Wert oder
|
||||
von einem Prozentsatz zu einem Wert.
|
||||
svg-placeholder-generator:
|
||||
title: SVG-Platzhalter-Generator
|
||||
description: >-
|
||||
Generiere SVG-Bilder, die als Platzhalter in deinen Anwendungen verwendet
|
||||
werden können.
|
||||
json-to-csv:
|
||||
title: JSON zu CSV
|
||||
description: Konvertiere JSON mit automatischer Headererkennung in CSV.
|
||||
camera-recorder:
|
||||
title: Kamera-Rekorder
|
||||
description: Mache ein Foto oder nimm ein Video von deiner Webcam oder Kamera auf.
|
||||
keycode-info:
|
||||
title: Keycode-Info
|
||||
description: >-
|
||||
Finde den JavaScript-Keycode, den Code, den Standort und die Modifikatoren
|
||||
einer beliebigen gedrückten Taste.
|
||||
emoji-picker:
|
||||
title: Emoji-Picker
|
||||
description: >-
|
||||
Einfaches Kopieren und Einfügen von Emojis. Erhalte außerdem den Unicode-
|
||||
und Codepunkt-Wert jedes Emojis.
|
||||
color-converter:
|
||||
title: Farbkonverter
|
||||
description: >-
|
||||
Konvertiere Farben zwischen den verschiedenen Formaten (Hex, RGB, HSL und
|
||||
CSS-Name).
|
||||
bcrypt:
|
||||
title: Bcrypt
|
||||
description: >-
|
||||
Hashen und Vergleichen von Strings mit bcrypt. Bcrypt ist eine auf der
|
||||
Blowfish-Chiffre basierende Hash-Funktion.
|
||||
crontab-generator:
|
||||
title: Crontab-Generator
|
||||
description: >-
|
||||
Überprüfe und generiere Crontab und erhalte die menschenlesbare
|
||||
Beschreibung des Cron-Zeitplans.
|
||||
http-status-codes:
|
||||
title: HTTP-Statuscodes
|
||||
description: Liste aller HTTP-Statuscodes, ihrer Namen und ihrer Bedeutung.
|
||||
sql-prettify:
|
||||
title: SQL verschönern und formatieren
|
||||
description: >-
|
||||
Formatiere und verschönere deine SQL-Abfragen online (unterstützt
|
||||
verschiedene SQL-Dialekte).
|
||||
benchmark-builder:
|
||||
title: Benchmark-Builder
|
||||
description: >-
|
||||
Vergleiche ganz einfach die Ausführungszeit von Aufgaben mit diesem sehr
|
||||
einfachen Online-Benchmark-Builder.
|
||||
git-memo:
|
||||
title: Git-Spickzettel
|
||||
description: >-
|
||||
Git ist eine dezentrale Versionsverwaltungssoftware. Mit diesem
|
||||
Spickzettel hast du schnellen Zugriff auf die gängigsten Git-Befehle.
|
||||
slugify-string:
|
||||
title: Slugify String
|
||||
description: Mache einen String URL-, Dateinamen- und ID-sicher.
|
||||
encryption:
|
||||
title: Text verschlüsseln / entschlüsseln
|
||||
description: >-
|
||||
Verschlüssele und entschlüssele Klartext mithilfe von Kryptoalgorithmen
|
||||
wie AES, TripleDES, Rabbit oder RC4.
|
||||
random-port-generator:
|
||||
title: Zufälliger Port-Generator
|
||||
description: >-
|
||||
Generiere zufällige Portnummern außerhalb des Bereichs der "bekannten"
|
||||
Ports (0-1023).
|
||||
yaml-prettify:
|
||||
title: YAML verschönern und formatieren
|
||||
description: Verschönere deinen YAML-String in ein menschenlesbares Format.
|
||||
eta-calculator:
|
||||
title: ETA-Rechner
|
||||
description: >-
|
||||
Ein ETA (Estimated Time of Arrival)-Rechner, um die ungefähre Endzeit
|
||||
einer Aufgabe zu erfahren, z. B. den Zeitpunkt des Endes eines Downloads.
|
||||
roman-numeral-converter:
|
||||
title: Römische Zahlen Konverter
|
||||
description: >-
|
||||
Konvertiere römische Zahlen in Dezimalzahlen und Dezimalzahlen in römische
|
||||
Zahlen.
|
||||
hmac-generator:
|
||||
title: HMAC-Generator
|
||||
description: >-
|
||||
Berechnet einen hashbasierten Nachrichtenauthentifizierungscode (HMAC)
|
||||
unter Verwendung eines geheimen Schlüssels und deiner bevorzugten
|
||||
Hash-Funktion.
|
||||
bip39-generator:
|
||||
title: BIP39-Passphrasengenerator
|
||||
description: >-
|
||||
Generiere BIP39-Passphrasen aus vorhandener oder zufälliger Mnemonik oder
|
||||
erhalte die Mnemonik aus der Passphrase.
|
||||
base64-file-converter:
|
||||
title: Base64-Dateikonverter
|
||||
description: Konvertiere Strings, Dateien oder Bilder in ihre Base64-Repräsentation.
|
||||
list-converter:
|
||||
title: Listenkonverter
|
||||
description: >-
|
||||
Dieses Tool kann spaltenbasierte Daten verarbeiten und verschiedene
|
||||
Änderungen (transponieren, Präfix und Suffix hinzufügen, Liste umkehren,
|
||||
Liste sortieren, Werte in Kleinbuchstaben umwandeln, Werte abschneiden)
|
||||
auf jede Zeile anwenden.
|
||||
base64-string-converter:
|
||||
title: Base64-String-Encoder/Decoder
|
||||
description: Codiere und decodiere Strings einfach in ihre Base64-Repräsentation.
|
||||
toml-to-yaml:
|
||||
title: TOML zu YAML
|
||||
description: Parse und konvertiere TOML zu YAML.
|
||||
math-evaluator:
|
||||
title: Mathematischer Auswerter
|
||||
description: >-
|
||||
Ein Taschenrechner zum Auswerten mathematischer Ausdrücke. Du kannst
|
||||
Funktionen wie sqrt, cos, sin, abs usw. verwenden.
|
||||
json-to-yaml-converter:
|
||||
title: JSON zu YAML
|
||||
description: Konvertiere JSON einfach in YAML mit diesem Live-Online-Konverter.
|
||||
url-parser:
|
||||
title: URL-Parser
|
||||
description: >-
|
||||
Parse eine URL-Zeichenfolge, um alle verschiedenen Teile (Protokoll,
|
||||
Ursprung, Parameter, Port, Benutzername-Passwort usw.) zu erhalten.
|
||||
iban-validator-and-parser:
|
||||
title: IBAN-Validator und -Parser
|
||||
description: >-
|
||||
Validiere und parse IBAN-Nummern. Überprüfe, ob die IBAN gültig ist, und
|
||||
erhalte das Land, BBAN, ob es sich um eine QR-IBAN handelt und das
|
||||
IBAN-freundliche Format.
|
||||
user-agent-parser:
|
||||
title: User-Agent-Parser
|
||||
description: >-
|
||||
Erkenne und parse Browser, Engine, Betriebssystem, CPU und
|
||||
Gerätetyp/-modell aus einer User-Agent-Zeichenfolge.
|
||||
numeronym-generator:
|
||||
title: Numeronym-Generator
|
||||
description: >-
|
||||
Ein Numeronym ist ein Wort, bei dem eine Zahl verwendet wird, um eine
|
||||
Abkürzung zu bilden. Zum Beispiel ist "i18n" ein Numeronym für
|
||||
"internationalization", wobei 18 für die Anzahl der Buchstaben zwischen
|
||||
dem ersten "i" und dem letzten "n" im Wort steht.
|
||||
case-converter:
|
||||
title: Fall-Konverter
|
||||
description: >-
|
||||
Ändere den Fall eines Strings und wähle zwischen verschiedenen Formaten
|
||||
aus.
|
||||
html-entities:
|
||||
title: HTML-Entity-Escape
|
||||
description: >-
|
||||
Escape oder unescape HTML-Entitäten (ersetze <, >, &, " und ' durch ihre
|
||||
HTML-Version).
|
||||
json-prettify:
|
||||
title: JSON verschönern und formatieren
|
||||
description: Verschönere deinen JSON-String in ein menschenlesbares Format.
|
||||
docker-run-to-docker-compose-converter:
|
||||
title: Docker run zu Docker compose Konverter
|
||||
description: Wandle docker run-Befehle in docker-compose-Dateien um!
|
||||
mac-address-lookup:
|
||||
title: MAC-Adressensuche
|
||||
description: Finde den Anbieter und Hersteller eines Geräts anhand seiner MAC-Adresse.
|
||||
mime-types:
|
||||
title: MIME-Typen
|
||||
description: Konvertiere MIME-Typen in Erweiterungen und umgekehrt.
|
||||
toml-to-json:
|
||||
title: TOML zu JSON
|
||||
description: Parse und konvertiere TOML zu JSON.
|
||||
lorem-ipsum-generator:
|
||||
title: Lorem Ipsum Generator
|
||||
description: >-
|
||||
Lorem Ipsum ist ein Platzhaltertext, der häufig verwendet wird, um die
|
||||
visuelle Form eines Dokuments oder einer Schriftart ohne Verwendung von
|
||||
bedeutendem Inhalt zu demonstrieren.
|
||||
qrcode-generator:
|
||||
title: QR-Code-Generator
|
||||
description: >-
|
||||
Generiere und downloade QR-Codes für eine URL oder einfach einen Text und
|
||||
passe die Hintergrund- und Vordergrundfarben an.
|
||||
wifi-qrcode-generator:
|
||||
title: WLAN-QR-Code-Generator
|
||||
description: >-
|
||||
Generiere und lade QR-Codes für schnelle Verbindungen zu WLAN-Netzwerken
|
||||
herunter.
|
||||
xml-formatter:
|
||||
title: XML-Formatter
|
||||
description: Verschönere deinen XML-String in ein menschenlesbares Format.
|
||||
temperature-converter:
|
||||
title: Temperaturkonverter
|
||||
description: >-
|
||||
Temperaturgradumrechnungen für Kelvin, Celsius, Fahrenheit, Rankine,
|
||||
Delisle, Newton, Réaumur und Rømer.
|
||||
chmod-calculator:
|
||||
title: Chmod-Rechner
|
||||
description: >-
|
||||
Berechne deine Chmod-Berechtigungen und -Befehle mit diesem
|
||||
Online-Chmod-Rechner.
|
||||
rsa-key-pair-generator:
|
||||
title: RSA-Schlüsselpaar-Generator
|
||||
description: Generiere neue zufällige RSA-Private- und Public-Key-PEM-Zertifikate.
|
||||
html-wysiwyg-editor:
|
||||
title: HTML-WYSIWYG-Editor
|
||||
description: >-
|
||||
Online-HTML-Editor mit funktionsreichem WYSIWYG-Editor, erhalte sofort den
|
||||
Quellcode des Inhalts.
|
||||
yaml-to-toml:
|
||||
title: YAML zu TOML
|
||||
description: Parse und konvertiere YAML zu TOML.
|
||||
mac-address-generator:
|
||||
title: MAC-Adressen-Generator
|
||||
description: >-
|
||||
Gebe die Menge und das Präfix ein. MAC-Adressen werden in deiner gewählten
|
||||
Schreibweise (Groß- oder Kleinbuchstaben) generiert.
|
||||
json-diff:
|
||||
title: JSON-Unterschied
|
||||
description: Vergleiche zwei JSON-Objekte und erhalte die Unterschiede zwischen ihnen.
|
||||
jwt-parser:
|
||||
title: JWT-Parser
|
||||
description: >-
|
||||
Parse und decodiere deinen JSON-Web-Token (JWT) und zeige dessen Inhalt
|
||||
an.
|
||||
date-converter:
|
||||
title: Datum-Uhrzeit-Konverter
|
||||
description: Konvertiere Datum und Uhrzeit in verschiedene Formate.
|
||||
phone-parser-and-formatter:
|
||||
title: Telefonnummer-Parser und -Formatter
|
||||
description: >-
|
||||
Parse, validiere und formatiere Telefonnummern. Erhalte Informationen zur
|
||||
Telefonnummer, wie z. B. die Landesvorwahl, den Typ usw.
|
||||
ipv4-subnet-calculator:
|
||||
title: IPv4-Subnetzrechner
|
||||
description: >-
|
||||
Parse deine IPv4-CIDR-Blöcke und erhalte alle Informationen, die du über
|
||||
dein Subnetz benötigst.
|
||||
og-meta-generator:
|
||||
title: Open Graph Meta-Generator
|
||||
description: Generiere Open Graph- und Social-HTML-Metatags für deine Website.
|
||||
ipv6-ula-generator:
|
||||
title: IPv6-ULA-Generator
|
||||
description: >-
|
||||
Generiere deine eigenen lokalen, nicht routbaren IP-Adressen in deinem
|
||||
Netzwerk gemäß RFC4193.
|
||||
hash-text:
|
||||
title: Text hashen
|
||||
description: >-
|
||||
Hashe einen Text-String mit der von dir benötigten Funktion: MD5, SHA1,
|
||||
SHA256, SHA224, SHA512, SHA384, SHA3 oder RIPEMD160
|
||||
json-to-toml:
|
||||
title: JSON zu TOML
|
||||
description: Parse und konvertiere JSON zu TOML.
|
||||
device-information:
|
||||
title: Geräteinformationen
|
||||
description: >-
|
||||
Informationen zu deinem aktuellen Gerät (Bildschirmgröße, Pixelverhältnis,
|
||||
Benutzeragent, ...) erhalten.
|
||||
pdf-signature-checker:
|
||||
title: PDF-Signaturprüfer
|
||||
description: >-
|
||||
Überprüfe die Signaturen einer PDF-Datei. Eine signierte PDF-Datei enthält
|
||||
eine oder mehrere Signaturen, die verwendet werden können, um
|
||||
festzustellen, ob der Inhalt der Datei seit dem Zeitpunkt der Signierung
|
||||
geändert wurde.
|
||||
json-minify:
|
||||
title: JSON minifizieren
|
||||
description: >-
|
||||
Minifiziere und komprimiere dein JSON, indem unnötige Leerzeichen entfernt
|
||||
werden.
|
||||
ulid-generator:
|
||||
title: ULID-Generator
|
||||
description: >-
|
||||
Generiere zufällige Universally Unique Lexicographically Sortable
|
||||
Identifier (ULID).
|
||||
string-obfuscator:
|
||||
title: String-Verschleierer
|
||||
description: >-
|
||||
Verschleiere einen String (wie ein Secret, eine IBAN oder ein Token), um
|
||||
ihn weitergeben zu können und identifizierbar zu machen, ohne seinen
|
||||
Inhalt preiszugeben.
|
||||
base-converter:
|
||||
title: Ganzzahl-Basiskonverter
|
||||
description: >-
|
||||
Konvertiere Zahlen zwischen verschiedenen Basen (Dezimal, Hexadezimal,
|
||||
Binär, Oktal, Base64, ...).
|
||||
yaml-to-json-converter:
|
||||
title: YAML zu JSON
|
||||
description: Konvertiere YAML einfach in JSON mit diesem Live-Online-Konverter.
|
||||
uuid-generator:
|
||||
title: UUID-Generator
|
||||
description: >-
|
||||
Ein Universally Unique Identifier (UUID) ist eine 128-Bit-Nummer, die zur
|
||||
Identifizierung von Informationen in Computersystemen verwendet wird. Die
|
||||
Anzahl der möglichen UUIDs beträgt 16^32, was 2^128 oder etwa 3,4x10^38
|
||||
entspricht (was ziemlich viel ist!).
|
||||
ipv4-address-converter:
|
||||
title: IPv4-Adresskonverter
|
||||
description: >-
|
||||
Konvertiere eine IP-Adresse in Dezimal, Binär, Hexadezimal oder sogar in
|
||||
IPv6.
|
||||
text-statistics:
|
||||
title: Textstatistiken
|
||||
description: >-
|
||||
Informationen zu einem Text erhalten, wie die Anzahl der Zeichen, die
|
||||
Anzahl der Wörter, die Größe usw.
|
||||
text-to-nato-alphabet:
|
||||
title: Text zu NATO-Alphabet
|
||||
description: >-
|
||||
Wandle Text in das NATO-Phonetik-Alphabet für die mündliche Übermittlung
|
||||
um.
|
||||
basic-auth-generator:
|
||||
title: Basic-Auth-Generator
|
||||
description: >-
|
||||
Generiere einen Base64-Basic-Auth-Header aus einem Benutzernamen und einem
|
||||
Passwort.
|
||||
text-to-unicode:
|
||||
title: Text zu Unicode
|
||||
description: Parse und konvertiere Text in Unicode und umgekehrt.
|
||||
ipv4-range-expander:
|
||||
title: IPv4-Bereichserweiterer
|
||||
description: >-
|
||||
Bei Angabe einer Start- und End-IPv4-Adresse berechnet dieses Tool ein
|
||||
gültiges IPv4-Netzwerk mit seiner CIDR-Notation.
|
||||
text-diff:
|
||||
title: Textunterschied
|
||||
description: Vergleiche zwei Texte und sieh die Unterschiede zwischen ihnen.
|
||||
otp-generator:
|
||||
title: OTP-Code-Generator
|
||||
description: >-
|
||||
Generiere und validiere zeitbasierte OTPs (Einmalpasswörter) für
|
||||
Multi-Faktor-Authentifizierung.
|
||||
url-encoder:
|
||||
title: Kodieren/Decodieren von URL-formatierten Zeichenfolgen
|
||||
description: >-
|
||||
Kodiere zum URL-kodierten Format (auch als "prozentkodiert" bekannt) oder
|
||||
decodiere es.
|
||||
text-to-binary:
|
||||
title: Text zu ASCII-Binär
|
||||
description: Konvertiere Text in seine ASCII-Binärrepräsentation und umgekehrt.
|
|
@ -7,7 +7,7 @@ home:
|
|||
toggleMenu: 'Toggle menu'
|
||||
home: Home
|
||||
uiLib: 'UI Lib'
|
||||
support: 'Support IT Tools development'
|
||||
support: 'Support IT-Tools development'
|
||||
buyMeACoffee: 'Buy me a coffee'
|
||||
follow:
|
||||
title: 'You like it-tools?'
|
||||
|
@ -30,7 +30,7 @@ about:
|
|||
content: >
|
||||
# About IT-Tools
|
||||
|
||||
This wonderful website, made with ❤ by [Corentin Thomasset](https://github.com/CorentinTh) , 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!
|
||||
This wonderful website, made with ❤ by [Corentin Thomasset](https://corentin.tech?utm_source=it-tools&utm_medium=about) , aggregates useful tools for developer and people working in IT. If you find it useful, please feel free to share it to people you think may find it useful too and don't forget to bookmark it in your shortcut bar!
|
||||
|
||||
IT Tools is open-source (under the MIT license) and free, and will always be, but it costs me money to host and renew the domain name. If you want to support my work, and encourage me to add more tools, please consider supporting by [sponsoring me](https://www.buymeacoffee.com/cthmsst).
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ about:
|
|||
content: >
|
||||
# Sobre IT-Tools
|
||||
|
||||
Este maravilloso sitio web, hecho con ❤ por [Corentin Thomasset](https://github.com/CorentinTh) , agrega herramientas útiles para desarrolladores y personas que trabajan en IT. Si lo encuentra útil, no dude en compartirlo con las personas que crea que también pueden encontrarlo útil y ¡no olvide marcarlo como favorito en su barra de accesos directos!
|
||||
Este maravilloso sitio web, hecho con ❤ por [Corentin Thomasset](https://corentin.tech?utm_source=it-tools&utm_medium=about) , agrega herramientas útiles para desarrolladores y personas que trabajan en IT. Si lo encuentra útil, no dude en compartirlo con las personas que crea que también pueden encontrarlo útil y ¡no olvide marcarlo como favorito en su barra de accesos directos!
|
||||
|
||||
IT Tools es de código abierto (under the MIT license) y gratis, y siempre lo será, pero me cuesta dinero alojar y renovar el nombre de dominio. Si desea apoyar mi trabajo y animarme a agregar más herramientas, considere apoyarme a través de[sponsoring me](https://www.buymeacoffee.com/cthmsst).
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ about:
|
|||
content: >
|
||||
# À propos de IT-Tools
|
||||
|
||||
Ce merveilleux site, fait avec ❤ par [Corentin Thomasset](https://github.com/CorentinTh), regroupe des outils utiles pour les développeurs et les personnes travaillant dans l'informatique. Si vous le trouvez utile, n'hésitez pas à le partager et n'oubliez pas de le mettre dans vos favoris !
|
||||
Ce merveilleux site, fait avec ❤ par [Corentin Thomasset](https://corentin.tech?utm_source=it-tools&utm_medium=about), regroupe des outils utiles pour les développeurs et les personnes travaillant dans l'informatique. Si vous le trouvez utile, n'hésitez pas à le partager et n'oubliez pas de le mettre dans vos favoris !
|
||||
|
||||
IT Tools est open-source (sous licence MIT) et gratuit, et le restera toujours, mais cela me coûte de l'argent pour l'héberger et renouveler le nom de domaine. Si vous voulez soutenir mon travail, et m'encourager à ajouter plus d'outils, n'hésitez pas à me [soutenir](https://www.buymeacoffee.com/cthmsst).
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ about:
|
|||
content: >
|
||||
# Sobre o IT-Tools
|
||||
|
||||
Este site maravilhoso, feito com ❤ por [Corentin Thomasset](https://github.com/CorentinTh), junta ferramentas úteis para desenvolvedores e outras pessoas que trabalham com TI. Se você achar o site útil, fique à vontade para compartilhar com quem também possa gostar e não esqueça de salvar o bookmark na sua barra de atalhos!
|
||||
Este site maravilhoso, feito com ❤ por [Corentin Thomasset](https://corentin.tech?utm_source=it-tools&utm_medium=about), junta ferramentas úteis para desenvolvedores e outras pessoas que trabalham com TI. Se você achar o site útil, fique à vontade para compartilhar com quem também possa gostar e não esqueça de salvar o bookmark na sua barra de atalhos!
|
||||
|
||||
O IT Tools é código aberto (sob a licença MIT), é gratuito, e sempre será, mas custa dinheiro para hospedar e renovar o domínio. Se quiser apoiar meu trabalho e me encorajar a adicionar mais ferramentas, por favor considere [ser patrocinador](https://www.buymeacoffee.com/cthmsst).
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ about:
|
|||
content: >
|
||||
# Про IT-Tools
|
||||
|
||||
Цей чудовий вебсайт, створений з ❤ [Corentin Thomasset](https://github.com/CorentinTh), агрегує корисні інструменти для розробників і людей, які працюють в сфері IT. Якщо вам це корисно, будь ласка, поділіться цим з людьми, які, на вашу думку, також можуть знайти його корисним, і не забудьте додати його до закладок у вашій панелі швидкого доступу!
|
||||
Цей чудовий вебсайт, створений з ❤ [Corentin Thomasset](https://corentin.tech?utm_source=it-tools&utm_medium=about), агрегує корисні інструменти для розробників і людей, які працюють в сфері IT. Якщо вам це корисно, будь ласка, поділіться цим з людьми, які, на вашу думку, також можуть знайти його корисним, і не забудьте додати його до закладок у вашій панелі швидкого доступу!
|
||||
|
||||
IT Tools є відкритим програмним забезпеченням (під ліцензією MIT) і безкоштовним, і завжди буде таким, але мені коштує гроші для хостингу і продовження доменного імені. Якщо ви хочете підтримати мою роботу і підтримати мене у додаванні нових інструментів, розгляньте можливість підтримки, [спонсоруючи мене](https://www.buymeacoffee.com/cthmsst).
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ about:
|
|||
content: >
|
||||
# Về IT-Tools
|
||||
|
||||
Website tuyệt vời này, được tạo ra bằng ❤ bởi [Corentin Thomasset](https://github.com/CorentinTh), tổng hợp các công cụ hữu ích cho nhà phát triển và những người làm việc trong lĩnh vực IT. Nếu bạn thấy nó hữu ích, xin đừng ngần ngại chia sẻ cho những người mà bạn nghĩ sẽ thấy nó hữu ích và đừng quên đánh dấu nó trong thanh lối tắt của bạn!
|
||||
Website tuyệt vời này, được tạo ra bằng ❤ bởi [Corentin Thomasset](https://corentin.tech?utm_source=it-tools&utm_medium=about), tổng hợp các công cụ hữu ích cho nhà phát triển và những người làm việc trong lĩnh vực IT. Nếu bạn thấy nó hữu ích, xin đừng ngần ngại chia sẻ cho những người mà bạn nghĩ sẽ thấy nó hữu ích và đừng quên đánh dấu nó trong thanh lối tắt của bạn!
|
||||
|
||||
IT Tools là mã nguồn mở (dưới giấy phép MIT) và miễn phí, và sẽ luôn như vậy, nhưng tôi phải trả tiền để lưu trữ và gia hạn tên miền. Nếu bạn muốn hỗ trợ công việc của tôi, và khích lệ tôi thêm nhiều công cụ hơn, hãy xem xét hỗ trợ bằng cách [tài trợ cho tôi](https://www.buymeacoffee.com/cthmsst).
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ about:
|
|||
content: >
|
||||
# 关于 IT-Tools
|
||||
|
||||
IT-Tools 由 [Corentin Thomasset](https://github.com/CorentinTh) 用 ❤ 开发,汇集了对开发人员和 IT 从业者有用的工具。如果对您有帮助,请将其分享给您的朋友,并且添加到收藏夹中!
|
||||
IT-Tools 由 [Corentin Thomasset](https://corentin.tech?utm_source=it-tools&utm_medium=about) 用 ❤ 开发,汇集了对开发人员和 IT 从业者有用的工具。如果对您有帮助,请将其分享给您的朋友,并且添加到收藏夹中!
|
||||
|
||||
IT-Tools 永久免费且开源(MIT 许可证),但需要资金用于托管和续订域名。如果您想支持我的工作,并鼓励我添加更多工具,请考虑通过 [赞助我](https://www.buymeacoffee.com/cthmsst) 进行支持。
|
||||
|
||||
|
|
23
package.json
23
package.json
|
@ -1,7 +1,14 @@
|
|||
{
|
||||
"name": "it-tools",
|
||||
"version": "2023.12.21-5ed3693",
|
||||
"version": "2024.5.13-a0bc346",
|
||||
"packageManager": "pnpm@8.15.3",
|
||||
"description": "Collection of handy online tools for developers, with great UX. ",
|
||||
"author": "Corentin Th <corentin.thomasset74+it-tools@gmail.com> (https://corentin.tech)",
|
||||
"license": "GNU GPLv3",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/CorentinTh/it-tools"
|
||||
},
|
||||
"keywords": [
|
||||
"productivity",
|
||||
"converter",
|
||||
|
@ -13,12 +20,6 @@
|
|||
"developer-tools",
|
||||
"developer-productivity"
|
||||
],
|
||||
"author": "Corentin Th <corentin.thomasset74+it-tools@gmail.com> (https://github.com/CorentinTh)",
|
||||
"license": "GNU GPLv3",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/CorentinTh/it-tools"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc --noEmit && NODE_OPTIONS=--max_old_space_size=4096 vite build",
|
||||
|
@ -37,11 +38,13 @@
|
|||
"dependencies": {
|
||||
"@it-tools/bip39": "^0.0.4",
|
||||
"@it-tools/oggen": "^1.3.0",
|
||||
"@regexper/render": "^1.0.0",
|
||||
"@sindresorhus/slugify": "^2.2.1",
|
||||
"@tiptap/pm": "2.1.6",
|
||||
"@tiptap/starter-kit": "2.1.6",
|
||||
"@tiptap/vue-3": "2.0.3",
|
||||
"@types/figlet": "^1.5.8",
|
||||
"@types/markdown-it": "^13.0.7",
|
||||
"@vicons/material": "^0.12.0",
|
||||
"@vicons/tabler": "^0.12.0",
|
||||
"@vueuse/core": "^10.3.0",
|
||||
|
@ -57,6 +60,7 @@
|
|||
"crypto-js": "^4.1.1",
|
||||
"date-fns": "^2.29.3",
|
||||
"dompurify": "^3.0.6",
|
||||
"email-normalizer": "^1.0.0",
|
||||
"emojilib": "^3.0.10",
|
||||
"figlet": "^1.7.0",
|
||||
"figue": "^1.2.0",
|
||||
|
@ -64,10 +68,12 @@
|
|||
"highlight.js": "^11.7.0",
|
||||
"iarna-toml-esm": "^3.0.5",
|
||||
"ibantools": "^4.3.3",
|
||||
"js-base64": "^3.7.6",
|
||||
"json5": "^2.2.3",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"libphonenumber-js": "^1.10.28",
|
||||
"lodash": "^4.17.21",
|
||||
"markdown-it": "^14.0.0",
|
||||
"marked": "^10.0.0",
|
||||
"mathjs": "^11.9.1",
|
||||
"mime-types": "^2.1.35",
|
||||
|
@ -80,6 +86,7 @@
|
|||
"pinia": "^2.0.34",
|
||||
"plausible-tracker": "^0.3.8",
|
||||
"qrcode": "^1.5.1",
|
||||
"randexp": "^0.5.3",
|
||||
"sql-formatter": "^13.0.0",
|
||||
"ua-parser-js": "^1.0.35",
|
||||
"ulid": "^2.3.0",
|
||||
|
@ -89,8 +96,10 @@
|
|||
"vue": "^3.3.4",
|
||||
"vue-i18n": "^9.9.1",
|
||||
"vue-router": "^4.1.6",
|
||||
"vue-shadow-dom": "^4.2.0",
|
||||
"vue-tsc": "^1.8.1",
|
||||
"xml-formatter": "^3.3.2",
|
||||
"xml-js": "^1.6.11",
|
||||
"yaml": "^2.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -9,7 +9,7 @@ const useWebServer = process.env.NO_WEB_SERVER !== 'true';
|
|||
*/
|
||||
export default defineConfig({
|
||||
testDir: './src',
|
||||
testMatch: /.*\.e2e\.(spec\.)?ts/,
|
||||
testMatch: /\.e2e\.(spec\.)?ts$/,
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: true,
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
|
@ -57,7 +57,7 @@ export default defineConfig({
|
|||
&& {
|
||||
webServer: {
|
||||
command: 'npm run preview',
|
||||
url: 'http://127.0.0.1:5050',
|
||||
url: 'http://localhost:5050',
|
||||
reuseExistingServer: !isCI,
|
||||
},
|
||||
}
|
||||
|
|
11059
pnpm-lock.yaml
generated
11059
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
@ -49,7 +49,7 @@ const output = computed(() => transformer.value(input.value));
|
|||
monospace
|
||||
/>
|
||||
|
||||
<div>
|
||||
<div overflow-auto>
|
||||
<div mb-5px>
|
||||
{{ outputLabel }}
|
||||
</div>
|
||||
|
|
|
@ -7,6 +7,7 @@ import sqlHljs from 'highlight.js/lib/languages/sql';
|
|||
import xmlHljs from 'highlight.js/lib/languages/xml';
|
||||
import yamlHljs from 'highlight.js/lib/languages/yaml';
|
||||
import iniHljs from 'highlight.js/lib/languages/ini';
|
||||
import markdownHljs from 'highlight.js/lib/languages/markdown';
|
||||
import { useCopy } from '@/composable/copy';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
|
@ -31,6 +32,7 @@ hljs.registerLanguage('html', xmlHljs);
|
|||
hljs.registerLanguage('xml', xmlHljs);
|
||||
hljs.registerLanguage('yaml', yamlHljs);
|
||||
hljs.registerLanguage('toml', iniHljs);
|
||||
hljs.registerLanguage('markdown', markdownHljs);
|
||||
|
||||
const { value, language, followHeightOf, copyPlacement, copyMessage } = toRefs(props);
|
||||
const { height } = followHeightOf.value ? useElementSize(followHeightOf) : { height: ref(null) };
|
||||
|
|
21
src/composable/debouncedref.ts
Normal file
21
src/composable/debouncedref.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import _ from 'lodash';
|
||||
|
||||
function useDebouncedRef<T>(initialValue: T, delay: number, immediate: boolean = false) {
|
||||
const state = ref(initialValue);
|
||||
const debouncedRef = customRef((track, trigger) => ({
|
||||
get() {
|
||||
track();
|
||||
return state.value;
|
||||
},
|
||||
set: _.debounce(
|
||||
(value) => {
|
||||
state.value = value;
|
||||
trigger();
|
||||
},
|
||||
delay,
|
||||
{ leading: immediate },
|
||||
),
|
||||
}));
|
||||
return debouncedRef;
|
||||
}
|
||||
export default useDebouncedRef;
|
|
@ -1,8 +1,13 @@
|
|||
import { extension as getExtensionFromMime } from 'mime-types';
|
||||
import { extension as getExtensionFromMimeType, extension as getMimeTypeFromExtension } from 'mime-types';
|
||||
import type { Ref } from 'vue';
|
||||
import _ from 'lodash';
|
||||
|
||||
export { getMimeTypeFromBase64, useDownloadFileFromBase64 };
|
||||
export {
|
||||
getMimeTypeFromBase64,
|
||||
getMimeTypeFromExtension, getExtensionFromMimeType,
|
||||
useDownloadFileFromBase64, useDownloadFileFromBase64Refs,
|
||||
previewImageFromBase64,
|
||||
};
|
||||
|
||||
const commonMimeTypesSignatures = {
|
||||
'JVBERi0': 'application/pdf',
|
||||
|
@ -36,30 +41,78 @@ function getFileExtensionFromMimeType({
|
|||
defaultExtension?: string
|
||||
}) {
|
||||
if (mimeType) {
|
||||
return getExtensionFromMime(mimeType) ?? defaultExtension;
|
||||
return getExtensionFromMimeType(mimeType) ?? defaultExtension;
|
||||
}
|
||||
|
||||
return defaultExtension;
|
||||
}
|
||||
|
||||
function useDownloadFileFromBase64({ source, filename }: { source: Ref<string>; filename?: string }) {
|
||||
return {
|
||||
download() {
|
||||
if (source.value === '') {
|
||||
function downloadFromBase64({ sourceValue, filename, extension, fileMimeType }:
|
||||
{ sourceValue: string; filename?: string; extension?: string; fileMimeType?: string }) {
|
||||
if (sourceValue === '') {
|
||||
throw new Error('Base64 string is empty');
|
||||
}
|
||||
|
||||
const { mimeType } = getMimeTypeFromBase64({ base64String: source.value });
|
||||
const base64String = mimeType
|
||||
? source.value
|
||||
: `data:text/plain;base64,${source.value}`;
|
||||
const defaultExtension = extension ?? 'txt';
|
||||
const { mimeType } = getMimeTypeFromBase64({ base64String: sourceValue });
|
||||
let base64String = sourceValue;
|
||||
if (!mimeType) {
|
||||
const targetMimeType = fileMimeType ?? getMimeTypeFromExtension(defaultExtension);
|
||||
base64String = `data:${targetMimeType};base64,${sourceValue}`;
|
||||
}
|
||||
|
||||
const cleanFileName = filename ?? `file.${getFileExtensionFromMimeType({ mimeType })}`;
|
||||
const cleanExtension = extension ?? getFileExtensionFromMimeType(
|
||||
{ mimeType, defaultExtension });
|
||||
let cleanFileName = filename ?? `file.${cleanExtension}`;
|
||||
if (extension && !cleanFileName.endsWith(`.${extension}`)) {
|
||||
cleanFileName = `${cleanFileName}.${cleanExtension}`;
|
||||
}
|
||||
|
||||
const a = document.createElement('a');
|
||||
a.href = base64String;
|
||||
a.download = cleanFileName;
|
||||
a.click();
|
||||
}
|
||||
|
||||
function useDownloadFileFromBase64(
|
||||
{ source, filename, extension, fileMimeType }:
|
||||
{ source: Ref<string>; filename?: string; extension?: string; fileMimeType?: string }) {
|
||||
return {
|
||||
download() {
|
||||
downloadFromBase64({ sourceValue: source.value, filename, extension, fileMimeType });
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function useDownloadFileFromBase64Refs(
|
||||
{ source, filename, extension }:
|
||||
{ source: Ref<string>; filename?: Ref<string>; extension?: Ref<string> }) {
|
||||
return {
|
||||
download() {
|
||||
downloadFromBase64({ sourceValue: source.value, filename: filename?.value, extension: extension?.value });
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function previewImageFromBase64(base64String: string): HTMLImageElement {
|
||||
if (base64String === '') {
|
||||
throw new Error('Base64 string is empty');
|
||||
}
|
||||
|
||||
const img = document.createElement('img');
|
||||
img.src = base64String;
|
||||
|
||||
const container = document.createElement('div');
|
||||
container.appendChild(img);
|
||||
|
||||
const previewContainer = document.getElementById('previewContainer');
|
||||
if (previewContainer) {
|
||||
previewContainer.innerHTML = '';
|
||||
previewContainer.appendChild(container);
|
||||
}
|
||||
else {
|
||||
throw new Error('Preview container element not found');
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { useRouteQuery } from '@vueuse/router';
|
||||
import { computed } from 'vue';
|
||||
import { useStorage } from '@vueuse/core';
|
||||
|
||||
export { useQueryParam };
|
||||
export { useQueryParam, useQueryParamOrStorage };
|
||||
|
||||
const transformers = {
|
||||
number: {
|
||||
|
@ -16,6 +17,12 @@ const transformers = {
|
|||
fromQuery: (value: string) => value.toLowerCase() === 'true',
|
||||
toQuery: (value: boolean) => (value ? 'true' : 'false'),
|
||||
},
|
||||
object: {
|
||||
fromQuery: (value: string) => {
|
||||
return JSON.parse(value);
|
||||
},
|
||||
toQuery: (value: object) => JSON.stringify(value),
|
||||
},
|
||||
};
|
||||
|
||||
function useQueryParam<T>({ name, defaultValue }: { name: string; defaultValue: T }) {
|
||||
|
@ -33,3 +40,27 @@ function useQueryParam<T>({ name, defaultValue }: { name: string; defaultValue:
|
|||
},
|
||||
});
|
||||
}
|
||||
|
||||
function useQueryParamOrStorage<T>({ name, storageName, defaultValue }: { name: string; storageName: string; defaultValue: T }) {
|
||||
const type = typeof defaultValue;
|
||||
const transformer = transformers[type as keyof typeof transformers] ?? transformers.string;
|
||||
|
||||
const storageRef = useStorage(storageName, defaultValue);
|
||||
const proxyDefaultValue = transformer.toQuery(defaultValue as never);
|
||||
const proxy = useRouteQuery(name, proxyDefaultValue);
|
||||
|
||||
const r = ref(defaultValue);
|
||||
|
||||
watch(r,
|
||||
(value) => {
|
||||
proxy.value = transformer.toQuery(value as never);
|
||||
storageRef.value = value as never;
|
||||
},
|
||||
{ deep: true });
|
||||
|
||||
r.value = (proxy.value && proxy.value !== proxyDefaultValue
|
||||
? transformer.fromQuery(proxy.value) as unknown as T
|
||||
: storageRef.value as T) as never;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -3,9 +3,11 @@ import _ from 'lodash';
|
|||
import { type Ref, reactive, watch } from 'vue';
|
||||
|
||||
type ValidatorReturnType = unknown;
|
||||
type GetErrorMessageReturnType = string;
|
||||
|
||||
export interface UseValidationRule<T> {
|
||||
validator: (value: T) => ValidatorReturnType
|
||||
getErrorMessage?: (value: T) => GetErrorMessageReturnType
|
||||
message: string
|
||||
}
|
||||
|
||||
|
@ -24,6 +26,15 @@ export function isFalsyOrHasThrown(cb: () => ValidatorReturnType): boolean {
|
|||
}
|
||||
}
|
||||
|
||||
export function getErrorMessageOrThrown(cb: () => GetErrorMessageReturnType): string {
|
||||
try {
|
||||
return cb() || '';
|
||||
}
|
||||
catch (e: any) {
|
||||
return e.toString();
|
||||
}
|
||||
}
|
||||
|
||||
export interface ValidationAttrs {
|
||||
feedback: string
|
||||
validationStatus: string | undefined
|
||||
|
@ -61,7 +72,13 @@ export function useValidation<T>({
|
|||
|
||||
for (const rule of get(rules)) {
|
||||
if (isFalsyOrHasThrown(() => rule.validator(source.value))) {
|
||||
if (rule.getErrorMessage) {
|
||||
const getErrorMessage = rule.getErrorMessage;
|
||||
state.message = rule.message.replace('{0}', getErrorMessageOrThrown(() => getErrorMessage(source.value)));
|
||||
}
|
||||
else {
|
||||
state.message = rule.message;
|
||||
}
|
||||
state.status = 'error';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,12 @@ export const config = figue({
|
|||
default: false,
|
||||
env: 'VITE_SHOW_BANNER',
|
||||
},
|
||||
showSponsorBanner: {
|
||||
doc: 'Show the sponsor banner',
|
||||
format: 'boolean',
|
||||
default: false,
|
||||
env: 'VITE_SHOW_SPONSOR_BANNER',
|
||||
},
|
||||
})
|
||||
.loadEnv({
|
||||
...import.meta.env,
|
||||
|
|
|
@ -81,7 +81,7 @@ const tools = computed<ToolCategory[]>(() => [
|
|||
</div>
|
||||
<div>
|
||||
© {{ new Date().getFullYear() }}
|
||||
<c-link target="_blank" rel="noopener" href="https://github.com/CorentinTh">
|
||||
<c-link target="_blank" rel="noopener" href="https://corentin.tech?utm_source=it-tools&utm_medium=footer">
|
||||
Corentin Thomasset
|
||||
</c-link>
|
||||
</div>
|
||||
|
|
|
@ -3,6 +3,7 @@ import { createPinia } from 'pinia';
|
|||
import { createHead } from '@vueuse/head';
|
||||
|
||||
import { registerSW } from 'virtual:pwa-register';
|
||||
import shadow from 'vue-shadow-dom';
|
||||
import { plausible } from './plugins/plausible.plugin';
|
||||
|
||||
import 'virtual:uno.css';
|
||||
|
@ -23,5 +24,6 @@ app.use(i18nPlugin);
|
|||
app.use(router);
|
||||
app.use(naive);
|
||||
app.use(plausible);
|
||||
app.use(shadow);
|
||||
|
||||
app.mount('#app');
|
||||
|
|
|
@ -3,6 +3,7 @@ const { availableLocales, locale } = useI18n();
|
|||
|
||||
const localesLong: Record<string, string> = {
|
||||
en: 'English',
|
||||
de: 'Deutsch',
|
||||
es: 'Español',
|
||||
fr: 'Français',
|
||||
pt: 'Português',
|
||||
|
|
|
@ -15,8 +15,8 @@ const { t } = useI18n();
|
|||
<template>
|
||||
<div class="pt-50px">
|
||||
<div class="grid-wrapper">
|
||||
<div v-if="config.showBanner" class="grid grid-cols-1 gap-12px lg:grid-cols-3 md:grid-cols-3 sm:grid-cols-2 xl:grid-cols-4">
|
||||
<ColoredCard :title="$t('home.follow.title')" :icon="Heart">
|
||||
<div class="grid grid-cols-1 gap-12px lg:grid-cols-3 md:grid-cols-3 sm:grid-cols-2 xl:grid-cols-4">
|
||||
<ColoredCard v-if="config.showBanner" :title="$t('home.follow.title')" :icon="Heart">
|
||||
{{ $t('home.follow.p1') }}
|
||||
<a
|
||||
href="https://github.com/CorentinTh/it-tools"
|
||||
|
@ -34,6 +34,32 @@ const { t } = useI18n();
|
|||
{{ $t('home.follow.thankYou') }}
|
||||
<n-icon :component="Heart" />
|
||||
</ColoredCard>
|
||||
|
||||
<a href="https://bit.ly/3zBl7DG" target="_blank" rel="noopener" class="text-current decoration-none">
|
||||
<c-card v-if="config.showSponsorBanner" class="cursor-pointer !border-2px !hover:border-primary">
|
||||
<div class="dark:hidden">
|
||||
<svg width="40" height="40" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M458.592 250.639C425.688 222.824 376.118 211.673 332.186 244.145C330.164 245.615 327.651 243.103 329.183 241.143C339.6 227.725 351.67 213.266 361.413 198.746C371.339 183.858 386.167 173.198 403.262 167.99C494.253 140.42 466.925 6 466.925 6C466.925 6 326.365 15.0675 343.705 136.315C346.585 156.594 341.193 177.241 328.509 193.354C312.946 213.021 294.87 231.83 281.758 245.431C279.001 248.25 274.344 245.554 275.447 241.755C288.13 199.052 297.383 133.007 253.45 90.4259L191.625 39.0842L179.738 54.7685C144.384 101.393 154.739 167.132 201.429 202.422C228.205 222.64 240.337 244.635 238.438 268.774C237.274 283.233 230.718 296.773 220.914 307.495C202.471 327.713 185.253 349.402 171.957 374.521C170.119 378.013 164.788 376.665 164.972 372.683C166.871 331.205 162.888 237.712 93.037 204.321L14.8527 174.117L8.78665 192.19C-10.882 250.517 21.2863 312.825 79.557 332.614C130.23 349.83 148.305 382.486 136.112 431.438C135.561 433.215 126.737 483.638 127.963 506H184.15C186.049 471.323 222.446 448.532 254.001 462.684C262.886 466.667 272.016 472.364 281.39 479.717C331.634 519.295 405.652 509.921 445.173 459.621L456.447 445.284L385.371 394.249C336.597 355.896 271.525 373.234 223.365 406.074C219.321 408.831 214.174 404.419 216.441 400.008C274.65 285.806 350.322 286.051 379.979 311.416C415.946 342.172 470.418 336.658 500.932 300.572L509.694 290.218L458.531 250.639H458.592Z" fill="#aaaaaa" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="hidden dark:block">
|
||||
<svg width="40" height="40" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M458.592 250.639C425.688 222.824 376.118 211.673 332.186 244.145C330.164 245.615 327.651 243.103 329.183 241.143C339.6 227.725 351.67 213.266 361.413 198.746C371.339 183.858 386.167 173.198 403.262 167.99C494.253 140.42 466.925 6 466.925 6C466.925 6 326.365 15.0675 343.705 136.315C346.585 156.594 341.193 177.241 328.509 193.354C312.946 213.021 294.87 231.83 281.758 245.431C279.001 248.25 274.344 245.554 275.447 241.755C288.13 199.052 297.383 133.007 253.45 90.4259L191.625 39.0842L179.738 54.7685C144.384 101.393 154.739 167.132 201.429 202.422C228.205 222.64 240.337 244.635 238.438 268.774C237.274 283.233 230.718 296.773 220.914 307.495C202.471 327.713 185.253 349.402 171.957 374.521C170.119 378.013 164.788 376.665 164.972 372.683C166.871 331.205 162.888 237.712 93.037 204.321L14.8527 174.117L8.78665 192.19C-10.882 250.517 21.2863 312.825 79.557 332.614C130.23 349.83 148.305 382.486 136.112 431.438C135.561 433.215 126.737 483.638 127.963 506H184.15C186.049 471.323 222.446 448.532 254.001 462.684C262.886 466.667 272.016 472.364 281.39 479.717C331.634 519.295 405.652 509.921 445.173 459.621L456.447 445.284L385.371 394.249C336.597 355.896 271.525 373.234 223.365 406.074C219.321 408.831 214.174 404.419 216.441 400.008C274.65 285.806 350.322 286.051 379.979 311.416C415.946 342.172 470.418 336.658 500.932 300.572L509.694 290.218L458.531 250.639H458.592Z" fill="#505050" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="my-5px flex items-baseline gap-4 text-lg text-black dark:text-white">
|
||||
Fern <div class="rounded-full bg-#eeeeee px-10px py-2px text-xs text-black dark:bg-#333333 dark:text-white">
|
||||
Sponsor
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-neutral-500 dark:text-neutral-400">
|
||||
Offer developer documentation that looks as good as Stripe's using Fern. <a href="https://bit.ly/3zBl7DG" target="_blank" rel="noopener" class="font-bold text-current transition hover:text-primary">Request a preview</a> of your docs on Fern.
|
||||
</div>
|
||||
</c-card>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<transition name="height">
|
||||
|
|
|
@ -2,14 +2,21 @@
|
|||
import { useBase64 } from '@vueuse/core';
|
||||
import type { Ref } from 'vue';
|
||||
import { useCopy } from '@/composable/copy';
|
||||
import { useDownloadFileFromBase64 } from '@/composable/downloadBase64';
|
||||
import { getExtensionFromMimeType, getMimeTypeFromBase64, previewImageFromBase64, useDownloadFileFromBase64Refs } from '@/composable/downloadBase64';
|
||||
import { useValidation } from '@/composable/validation';
|
||||
import { isValidBase64 } from '@/utils/base64';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const fileName = ref('file');
|
||||
const fileExtension = ref('');
|
||||
const base64Input = ref('');
|
||||
const { download } = useDownloadFileFromBase64({ source: base64Input });
|
||||
const { download } = useDownloadFileFromBase64Refs(
|
||||
{
|
||||
source: base64Input,
|
||||
filename: fileName,
|
||||
extension: fileExtension,
|
||||
});
|
||||
const base64InputValidation = useValidation({
|
||||
source: base64Input,
|
||||
rules: [
|
||||
|
@ -20,6 +27,35 @@ const base64InputValidation = useValidation({
|
|||
],
|
||||
});
|
||||
|
||||
watch(
|
||||
base64Input,
|
||||
(newValue, _) => {
|
||||
const { mimeType } = getMimeTypeFromBase64({ base64String: newValue });
|
||||
if (mimeType) {
|
||||
fileExtension.value = getExtensionFromMimeType(mimeType) || fileExtension.value;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
function previewImage() {
|
||||
if (!base64InputValidation.isValid) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const image = previewImageFromBase64(base64Input.value);
|
||||
image.style.maxWidth = '100%';
|
||||
image.style.maxHeight = '400px';
|
||||
const previewContainer = document.getElementById('previewContainer');
|
||||
if (previewContainer) {
|
||||
previewContainer.innerHTML = '';
|
||||
previewContainer.appendChild(image);
|
||||
}
|
||||
}
|
||||
catch (_) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
function downloadFile() {
|
||||
if (!base64InputValidation.isValid) {
|
||||
return;
|
||||
|
@ -46,6 +82,24 @@ async function onUpload(file: File) {
|
|||
|
||||
<template>
|
||||
<c-card :title="t('tools.base64-file-converter.base64ToFile.title')">
|
||||
<n-grid cols="3" x-gap="12">
|
||||
<n-gi span="2">
|
||||
<c-input-text
|
||||
v-model:value="fileName"
|
||||
:label="t('tools.base64-file-converter.base64ToFile.fileName')"
|
||||
:placeholder="t('tools.base64-file-converter.base64ToFile.downloadFilename')"
|
||||
mb-2
|
||||
/>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<c-input-text
|
||||
v-model:value="fileExtension"
|
||||
:label="t('tools.base64-file-converter.base64ToFile.extension')"
|
||||
:placeholder="t('tools.base64-file-converter.base64ToFile.extension')"
|
||||
mb-2
|
||||
/>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
<c-input-text
|
||||
v-model:value="base64Input"
|
||||
multiline
|
||||
|
@ -55,7 +109,14 @@ async function onUpload(file: File) {
|
|||
mb-2
|
||||
/>
|
||||
|
||||
<div flex justify-center>
|
||||
<div flex justify-center py-2>
|
||||
<div id="previewContainer" />
|
||||
</div>
|
||||
|
||||
<div flex justify-center gap-3>
|
||||
<c-button :disabled="base64Input === '' || !base64InputValidation.isValid" @click="previewImage()">
|
||||
{{ t('tools.base64-file-converter.buttons.previewImage') }}
|
||||
</c-button>
|
||||
<c-button :disabled="base64Input === '' || !base64InputValidation.isValid" @click="downloadFile()">
|
||||
{{ t('tools.base64-file-converter.buttons.downloadFile') }}
|
||||
</c-button>
|
||||
|
|
|
@ -6,11 +6,15 @@ tools:
|
|||
base64ToFile:
|
||||
title: Base64 to file
|
||||
placeholder: Put your base64 file string here...
|
||||
fileName: File Name
|
||||
downloadFilename: Download filename
|
||||
extension: Extension
|
||||
fileToBase64:
|
||||
title: File to base64
|
||||
placeholder: File in base64 will be here
|
||||
uploadTip: Drag and drop a file here, or click to select a file
|
||||
buttons:
|
||||
previewImage: Preview image
|
||||
downloadFile: Download file
|
||||
copy: Copy
|
||||
|
||||
|
|
|
@ -6,11 +6,15 @@ tools:
|
|||
base64ToFile:
|
||||
title: 'Base64 vers fichier'
|
||||
placeholder: 'Mettez votre chaîne de fichier base64 ici...'
|
||||
fileName: 'Nom de fichier'
|
||||
downloadFilename: 'Télécharger le nom du fichier'
|
||||
extension: 'Extension'
|
||||
fileToBase64:
|
||||
title: 'Fichier vers base64'
|
||||
placeholder: 'Le fichier en base64 sera ici'
|
||||
uploadTip: 'Glissez-déposez un fichier ici, ou cliquez pour sélectionner un fichier'
|
||||
buttons:
|
||||
previewImage: "Image d'aperçu"
|
||||
downloadFile: 'Télécharger le fichier'
|
||||
copy: 'Copier'
|
||||
|
||||
|
|
|
@ -6,11 +6,15 @@ tools:
|
|||
base64ToFile:
|
||||
title: Base64 转文件
|
||||
placeholder: 在此处放置您的 base64 文件字符串...
|
||||
fileName: 文件名
|
||||
downloadFilename: 下载文件名
|
||||
extension: 拓展名
|
||||
fileToBase64:
|
||||
title: 文件转 base64
|
||||
placeholder: base64 文件将在此处
|
||||
uploadTip: 拖放文件到此处,或点击选择文件
|
||||
buttons:
|
||||
previewImage: 预览图片
|
||||
downloadFile: 下载文件
|
||||
copy: 复制
|
||||
|
||||
|
|
|
@ -28,14 +28,8 @@ const compareMatch = computed(() => compareSync(compareString.value, compareHash
|
|||
label-width="120px"
|
||||
mb-2
|
||||
/>
|
||||
<n-form-item :label="t('tools.bcrypt.hash.saltCount')" label-placement="left" label-width="120">
|
||||
<n-input-number
|
||||
v-model:value="saltCount"
|
||||
:placeholder="t('tools.bcrypt.hash.saltCountPlaceholder')"
|
||||
:max="10"
|
||||
:min="0"
|
||||
w-full
|
||||
/>
|
||||
<n-form-item label="t('tools.bcrypt.hash.saltCount')" label-placement="left" label-width="120">
|
||||
<n-input-number v-model:value="saltCount" placeholder="t('tools.bcrypt.hash.saltCountPlaceholder')" :max="100" :min="0" w-full />
|
||||
</n-form-item>
|
||||
|
||||
<c-input-text :value="hashed" readonly text-center />
|
||||
|
|
66
src/tools/email-normalizer/email-normalizer.vue
Normal file
66
src/tools/email-normalizer/email-normalizer.vue
Normal file
|
@ -0,0 +1,66 @@
|
|||
<script setup lang="ts">
|
||||
import { normalizeEmail } from 'email-normalizer';
|
||||
import { withDefaultOnError } from '@/utils/defaults';
|
||||
import { useCopy } from '@/composable/copy';
|
||||
|
||||
const { t } = useI18n();
|
||||
const emails = ref('');
|
||||
const normalizedEmails = computed(() => {
|
||||
if (!emails.value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return emails.value
|
||||
.split('\n')
|
||||
.map((email) => {
|
||||
return withDefaultOnError(() => normalizeEmail({ email }), `${t('tools.email-normalizer.invalidMessage')} ${email}`);
|
||||
})
|
||||
.join('\n');
|
||||
});
|
||||
|
||||
const { copy } = useCopy({ source: normalizedEmails, text: t('tools.email-normalizer.copied'), createToast: true });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="mb-2">
|
||||
{{ t('tools.email-normalizer.inputTitle') }}
|
||||
</div>
|
||||
<c-input-text
|
||||
v-model:value="emails"
|
||||
:placeholder="t('tools.email-normalizer.inputPlaceholder')"
|
||||
rows="3"
|
||||
multiline
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
autocapitalize="off"
|
||||
spellcheck="false"
|
||||
autofocus
|
||||
monospace
|
||||
/>
|
||||
|
||||
<div class="mb-2 mt-4">
|
||||
{{ t('tools.email-normalizer.outputTitle') }}
|
||||
</div>
|
||||
<c-input-text
|
||||
:value="normalizedEmails"
|
||||
:placeholder="t('tools.email-normalizer.outputPlaceholder')"
|
||||
rows="3"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
autocapitalize="off"
|
||||
spellcheck="false"
|
||||
multiline
|
||||
readonly
|
||||
monospace
|
||||
/>
|
||||
<div class="mt-4 flex justify-center gap-2">
|
||||
<c-button @click="emails = ''">
|
||||
{{ t('tools.email-normalizer.buttons.clear') }}
|
||||
</c-button>
|
||||
<c-button :disabled="!normalizedEmails" @click="copy()">
|
||||
{{ t('tools.email-normalizer.buttons.copy') }}
|
||||
</c-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
13
src/tools/email-normalizer/index.ts
Normal file
13
src/tools/email-normalizer/index.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { Mail } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: t('tools.email-normalizer.title'),
|
||||
path: '/email-normalizer',
|
||||
description: t('tools.email-normalizer.description'),
|
||||
keywords: ['email', 'normalizer'],
|
||||
component: () => import('./email-normalizer.vue'),
|
||||
icon: Mail,
|
||||
createdAt: new Date('2024-08-15'),
|
||||
});
|
16
src/tools/email-normalizer/locales/en.yml
Normal file
16
src/tools/email-normalizer/locales/en.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
tools:
|
||||
email-normalizer:
|
||||
title: Email normalizer
|
||||
description: Normalize email addresses to a standard format for easier comparison. Useful for deduplication and data cleaning.
|
||||
|
||||
inputTitle: 'Raw emails to normalize:'
|
||||
inputPlaceholder: 'Put your emails here (one per line)...'
|
||||
outputTitle: 'Normalized emails:'
|
||||
outputPlaceholder: 'Normalized emails will appear here...'
|
||||
|
||||
buttons:
|
||||
clear: 'Clear emails'
|
||||
copy: 'Copy normalized emails'
|
||||
|
||||
invalidMessage: 'Unable to parse email: '
|
||||
copied: 'Normalized emails copied to the clipboard'
|
16
src/tools/email-normalizer/locales/fr.yml
Normal file
16
src/tools/email-normalizer/locales/fr.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
tools:
|
||||
email-normalizer:
|
||||
title: Normalisateur d'e-mails
|
||||
description: Normalisez les adresses e-mail dans un format standard pour faciliter la comparaison. Utile pour la déduplication et le nettoyage des données.
|
||||
|
||||
inputTitle: 'E-mails bruts à normaliser :'
|
||||
inputPlaceholder: 'Placez vos e-mails ici (un par ligne)...'
|
||||
outputTitle: 'E-mails normalisés :'
|
||||
outputPlaceholder: 'Les e-mails normalisés apparaîtront ici...'
|
||||
|
||||
buttons:
|
||||
clear: 'Effacer les e-mails'
|
||||
copy: 'Copier les e-mails normalisés'
|
||||
|
||||
invalidMessage: "Impossible d'analyser l'e-mail : "
|
||||
copied: 'E-mails normalisés copiés dans le presse-papiers'
|
16
src/tools/email-normalizer/locales/zh.yml
Normal file
16
src/tools/email-normalizer/locales/zh.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
tools:
|
||||
email-normalizer:
|
||||
title: 邮件地址规范化器
|
||||
description: 将电子邮件地址规范化为标准格式,以便更容易进行比较。 用于去重和数据清洗。
|
||||
|
||||
inputTitle: '要规范化的原始电子邮件:'
|
||||
inputPlaceholder: '在此处输入您的电子邮件(每行一个)...'
|
||||
outputTitle: '规范化的电子邮件:'
|
||||
outputPlaceholder: '规范化的电子邮件将显示在这里...'
|
||||
|
||||
buttons:
|
||||
clear: '清除电子邮件'
|
||||
copy: '复制规范化的电子邮件'
|
||||
|
||||
invalidMessage: '无法解析电子邮件:'
|
||||
copied: '规范化的电子邮件已复制到剪贴板'
|
|
@ -4,6 +4,7 @@ import emojiKeywords from 'emojilib';
|
|||
import _ from 'lodash';
|
||||
import type { EmojiInfo } from './emoji.types';
|
||||
import { useFuzzySearch } from '@/composable/fuzzySearch';
|
||||
import useDebouncedRef from '@/composable/debouncedref';
|
||||
|
||||
const { t } = useI18n();
|
||||
const escapeUnicode = ({ emoji }: { emoji: string }) => emoji.split('').map(unit => `\\u${unit.charCodeAt(0).toString(16).padStart(4, '0')}`).join('');
|
||||
|
@ -24,7 +25,7 @@ const emojisGroups: { emojiInfos: EmojiInfo[]; group: string }[] = _
|
|||
.map((emojiInfos, group) => ({ group, emojiInfos }))
|
||||
.value();
|
||||
|
||||
const searchQuery = ref('');
|
||||
const searchQuery = useDebouncedRef('', 500);
|
||||
|
||||
const { searchResult } = useFuzzySearch({
|
||||
search: searchQuery,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import { useThemeVars } from 'naive-ui';
|
||||
import Memo from './git-memo.content.md';
|
||||
import MemoZH from './git-memo.content.zh.md';
|
||||
import MemoFR from './git-memo.content.fr.md';
|
||||
|
||||
const themeVars = useThemeVars();
|
||||
const { locale } = useI18n();
|
||||
|
@ -10,6 +11,7 @@ const { locale } = useI18n();
|
|||
<template>
|
||||
<div>
|
||||
<MemoZH v-if="locale === 'zh'" />
|
||||
<MemoFR v-else-if="locale === 'fr'" />
|
||||
<Memo v-else />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
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 emailNormalizer } from './email-normalizer';
|
||||
|
||||
import { tool as asciiTextDrawer } from './ascii-text-drawer';
|
||||
|
||||
import { tool as textToUnicode } from './text-to-unicode';
|
||||
import { tool as safelinkDecoder } from './safelink-decoder';
|
||||
import { tool as xmlToJson } from './xml-to-json';
|
||||
import { tool as jsonToXml } from './json-to-xml';
|
||||
import { tool as regexTester } from './regex-tester';
|
||||
import { tool as regexMemo } from './regex-memo';
|
||||
import { tool as markdownToHtml } from './markdown-to-html';
|
||||
import { tool as pdfSignatureChecker } from './pdf-signature-checker';
|
||||
import { tool as numeronymGenerator } from './numeronym-generator';
|
||||
import { tool as macAddressGenerator } from './mac-address-generator';
|
||||
|
@ -107,6 +113,9 @@ export const toolsByCategory: ToolCategory[] = [
|
|||
jsonToToml,
|
||||
tomlToJson,
|
||||
tomlToYaml,
|
||||
xmlToJson,
|
||||
jsonToXml,
|
||||
markdownToHtml,
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -148,6 +157,9 @@ export const toolsByCategory: ToolCategory[] = [
|
|||
dockerRunToDockerComposeConverter,
|
||||
xmlFormatter,
|
||||
yamlViewer,
|
||||
emailNormalizer,
|
||||
regexTester,
|
||||
regexMemo,
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
@ -11,6 +11,9 @@ describe('integer-base-converter', () => {
|
|||
expect(convertBase({ value: '10100101', fromBase: 2, toBase: 16 })).toEqual('a5');
|
||||
expect(convertBase({ value: '192654', fromBase: 10, toBase: 8 })).toEqual('570216');
|
||||
expect(convertBase({ value: 'zz', fromBase: 64, toBase: 10 })).toEqual('2275');
|
||||
expect(convertBase({ value: '42540766411283223938465490632011909384', fromBase: 10, toBase: 10 })).toEqual('42540766411283223938465490632011909384');
|
||||
expect(convertBase({ value: '42540766411283223938465490632011909384', fromBase: 10, toBase: 16 })).toEqual('20010db8000085a300000000ac1f8908');
|
||||
expect(convertBase({ value: '20010db8000085a300000000ac1f8908', fromBase: 16, toBase: 10 })).toEqual('42540766411283223938465490632011909384');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,16 +7,16 @@ export function convertBase({ value, fromBase, toBase }: { value: string; fromBa
|
|||
let decValue = value
|
||||
.split('')
|
||||
.reverse()
|
||||
.reduce((carry: number, digit: string, index: number) => {
|
||||
.reduce((carry: bigint, digit: string, index: number) => {
|
||||
if (!fromRange.includes(digit)) {
|
||||
throw new Error(t('tools.base-converter.invalidMessage', { digit, fromBase }));
|
||||
}
|
||||
return (carry += fromRange.indexOf(digit) * fromBase ** index);
|
||||
}, 0);
|
||||
return (carry += BigInt(fromRange.indexOf(digit)) * BigInt(fromBase) ** BigInt(index));
|
||||
}, 0n);
|
||||
let newValue = '';
|
||||
while (decValue > 0) {
|
||||
newValue = toRange[decValue % toBase] + newValue;
|
||||
decValue = (decValue - (decValue % toBase)) / toBase;
|
||||
newValue = toRange[Number(decValue % BigInt(toBase))] + newValue;
|
||||
decValue = (decValue - (decValue % BigInt(toBase))) / BigInt(toBase);
|
||||
}
|
||||
return newValue || '0';
|
||||
}
|
||||
|
|
13
src/tools/json-to-xml/index.ts
Normal file
13
src/tools/json-to-xml/index.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { Braces } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: t('tools.json-to-xml.title'),
|
||||
path: '/json-to-xml',
|
||||
description: t('tools.json-to-xml.description'),
|
||||
keywords: ['json', 'xml'],
|
||||
component: () => import('./json-to-xml.vue'),
|
||||
icon: Braces,
|
||||
createdAt: new Date('2024-08-09'),
|
||||
});
|
33
src/tools/json-to-xml/json-to-xml.vue
Normal file
33
src/tools/json-to-xml/json-to-xml.vue
Normal file
|
@ -0,0 +1,33 @@
|
|||
<script setup lang="ts">
|
||||
import convert from 'xml-js';
|
||||
import JSON5 from 'json5';
|
||||
import { withDefaultOnError } from '@/utils/defaults';
|
||||
import type { UseValidationRule } from '@/composable/validation';
|
||||
|
||||
const { t } = useI18n();
|
||||
const defaultValue = '{"a":{"_attributes":{"x":"1.234","y":"It\'s"}}}';
|
||||
function transformer(value: string) {
|
||||
return withDefaultOnError(() => {
|
||||
return convert.js2xml(JSON5.parse(value), { compact: true });
|
||||
}, '');
|
||||
}
|
||||
|
||||
const rules: UseValidationRule<string>[] = [
|
||||
{
|
||||
validator: (v: string) => v === '' || JSON5.parse(v),
|
||||
message: t('tools.json-to-xml.invalidMessage'),
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<format-transformer
|
||||
:input-label="t('tools.json-to-xml.inputLabel')"
|
||||
:input-default="defaultValue"
|
||||
:input-placeholder="t('tools.json-to-xml.inputPlaceholder')"
|
||||
:output-label="t('tools.json-to-xml.outputLabel')"
|
||||
output-language="xml"
|
||||
:transformer="transformer"
|
||||
:input-validation-rules="rules"
|
||||
/>
|
||||
</template>
|
10
src/tools/json-to-xml/locales/en.yml
Normal file
10
src/tools/json-to-xml/locales/en.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
tools:
|
||||
json-to-xml:
|
||||
title: JSON to XML
|
||||
description: Convert JSON to XML.
|
||||
|
||||
inputLabel: Your JSON content
|
||||
inputPlaceholder: Paste your JSON content here...
|
||||
outputLabel: Converted XML
|
||||
|
||||
invalidMessage: Provided JSON is not valid.
|
10
src/tools/json-to-xml/locales/fr.yml
Normal file
10
src/tools/json-to-xml/locales/fr.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
tools:
|
||||
json-to-xml:
|
||||
title: JSON vers XML
|
||||
description: Convertir JSON en XML.
|
||||
|
||||
inputLabel: Votre contenu JSON
|
||||
inputPlaceholder: Collez votre contenu JSON ici...
|
||||
outputLabel: XML converti
|
||||
|
||||
invalidMessage: Le JSON fourni n'est pas valide.
|
10
src/tools/json-to-xml/locales/zh.yml
Normal file
10
src/tools/json-to-xml/locales/zh.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
tools:
|
||||
json-to-xml:
|
||||
title: JSON 转 XML
|
||||
description: 将 JSON 转换为 XML。
|
||||
|
||||
inputLabel: 您的 JSON 内容
|
||||
inputPlaceholder: 在此粘贴您的 JSON 内容...
|
||||
outputLabel: 转换后的 XML
|
||||
|
||||
invalidMessage: 提供的 JSON 不是有效的。
|
|
@ -41,7 +41,7 @@ const validation = useValidation({
|
|||
{{ section.title }}
|
||||
</th>
|
||||
<tr v-for="{ claim, claimDescription, friendlyValue, value } in decodedJWT[section.key]" :key="claim + value">
|
||||
<td class="claims">
|
||||
<td class="claims" style="vertical-align: top;">
|
||||
<span font-bold>
|
||||
{{ claim }}
|
||||
</span>
|
||||
|
@ -49,7 +49,7 @@ const validation = useValidation({
|
|||
({{ claimDescription }})
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<td style="word-wrap: break-word;word-break: break-all;">
|
||||
<span>{{ value }}</span>
|
||||
<span v-if="friendlyValue" ml-2 op-70>
|
||||
({{ friendlyValue }})
|
||||
|
|
|
@ -12,3 +12,4 @@ tools:
|
|||
|
||||
copyBtn: Copy
|
||||
copied: Lorem ipsum copied to the clipboard
|
||||
refresh: Refresh
|
||||
|
|
|
@ -12,3 +12,4 @@ tools:
|
|||
|
||||
copyBtn: Copier
|
||||
copied: Lorem ipsum copié dans le presse-papiers
|
||||
refresh: Rafraîchir
|
||||
|
|
|
@ -12,3 +12,4 @@ tools:
|
|||
|
||||
copyBtn: 复制
|
||||
copied: Lorem Ipsum 已复制到剪贴板
|
||||
refresh: 刷新
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import { generateLoremIpsum } from './lorem-ipsum-generator.service';
|
||||
import { useCopy } from '@/composable/copy';
|
||||
import { randIntFromInterval } from '@/utils/random';
|
||||
import { computedRefreshable } from '@/composable/computedRefreshable';
|
||||
|
||||
const { t } = useI18n();
|
||||
const paragraphs = ref(1);
|
||||
|
@ -10,7 +11,7 @@ const words = ref([8, 15]);
|
|||
const startWithLoremIpsum = ref(true);
|
||||
const asHTML = ref(false);
|
||||
|
||||
const loremIpsumText = computed(() =>
|
||||
const [loremIpsumText, refreshLoremIpsum] = computedRefreshable(() =>
|
||||
generateLoremIpsum({
|
||||
paragraphCount: paragraphs.value,
|
||||
asHTML: asHTML.value,
|
||||
|
@ -42,10 +43,13 @@ const { copy } = useCopy({ source: loremIpsumText, text: t('tools.lorem-ipsum-ge
|
|||
|
||||
<c-input-text :value="loremIpsumText" multiline :placeholder="t('tools.lorem-ipsum-generator.loremIpsumText')" readonly mt-5 rows="5" />
|
||||
|
||||
<div mt-5 flex justify-center>
|
||||
<div mt-5 flex justify-center gap-3>
|
||||
<c-button autofocus @click="copy()">
|
||||
{{ t('tools.lorem-ipsum-generator.copyBtn') }}
|
||||
</c-button>
|
||||
<c-button @click="refreshLoremIpsum">
|
||||
{{ t('tools.lorem-ipsum-generator.refresh') }}
|
||||
</c-button>
|
||||
</div>
|
||||
</c-card>
|
||||
</template>
|
||||
|
|
13
src/tools/markdown-to-html/index.ts
Normal file
13
src/tools/markdown-to-html/index.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { Markdown } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: t('tools.markdown-to-html.title'),
|
||||
path: '/markdown-to-html',
|
||||
description: t('tools.markdown-to-html.description'),
|
||||
keywords: ['markdown', 'html', 'converter', 'pdf'],
|
||||
component: () => import('./markdown-to-html.vue'),
|
||||
icon: Markdown,
|
||||
createdAt: new Date('2024-08-25'),
|
||||
});
|
10
src/tools/markdown-to-html/locales/en.yml
Normal file
10
src/tools/markdown-to-html/locales/en.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
tools:
|
||||
markdown-to-html:
|
||||
title: Markdown to HTML
|
||||
description: Convert Markdown to Html and allow to print (as PDF).
|
||||
|
||||
inputLabel: 'Your Markdown to convert:'
|
||||
inputPlaceholder: 'Your Markdown content...'
|
||||
outputLabel: 'Output HTML:'
|
||||
|
||||
printAsPDF: 'Print as PDF'
|
10
src/tools/markdown-to-html/locales/fr.yml
Normal file
10
src/tools/markdown-to-html/locales/fr.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
tools:
|
||||
markdown-to-html:
|
||||
title: Markdown vers HTML
|
||||
description: Convertir Markdown en Html et permettre l'impression (en PDF).
|
||||
|
||||
inputLabel: 'Votre Markdown à convertir:'
|
||||
inputPlaceholder: 'Votre contenu Markdown...'
|
||||
outputLabel: 'HTML de sortie:'
|
||||
|
||||
printAsPDF: 'Imprimer en PDF'
|
10
src/tools/markdown-to-html/locales/zh.yml
Normal file
10
src/tools/markdown-to-html/locales/zh.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
tools:
|
||||
markdown-to-html:
|
||||
title: Markdown 转 HTML
|
||||
description: '将 Markdown 转换为 Html 并允许打印(作为 PDF)。'
|
||||
|
||||
inputLabel: '要转换的 Markdown:'
|
||||
inputPlaceholder: '您的 Markdown 内容...'
|
||||
outputLabel: '输出 HTML:'
|
||||
|
||||
printAsPDF: '作为 PDF 打印'
|
45
src/tools/markdown-to-html/markdown-to-html.vue
Normal file
45
src/tools/markdown-to-html/markdown-to-html.vue
Normal file
|
@ -0,0 +1,45 @@
|
|||
<script setup lang="ts">
|
||||
import markdownit from 'markdown-it';
|
||||
import TextareaCopyable from '@/components/TextareaCopyable.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const inputMarkdown = ref('');
|
||||
const outputHtml = computed(() => {
|
||||
const md = markdownit();
|
||||
return md.render(inputMarkdown.value);
|
||||
});
|
||||
|
||||
function printHtml() {
|
||||
const w = window.open();
|
||||
if (w === null) {
|
||||
return;
|
||||
}
|
||||
w.document.body.innerHTML = outputHtml.value;
|
||||
w.print();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<c-input-text
|
||||
v-model:value="inputMarkdown"
|
||||
multiline raw-text
|
||||
:placeholder="t('tools.markdown-to-html.inputPlaceholder')"
|
||||
rows="8"
|
||||
autofocus
|
||||
:label="t('tools.markdown-to-html.inputLabel')"
|
||||
/>
|
||||
|
||||
<n-divider />
|
||||
|
||||
<n-form-item :label="t('tools.markdown-to-html.outputLabel')">
|
||||
<TextareaCopyable :value="outputHtml" :word-wrap="true" language="html" />
|
||||
</n-form-item>
|
||||
|
||||
<div flex justify-center>
|
||||
<n-button @click="printHtml">
|
||||
{{ t('tools.markdown-to-html.printAsPDF') }}
|
||||
</n-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
13
src/tools/regex-memo/index.ts
Normal file
13
src/tools/regex-memo/index.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { BrandJavascript } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: t('tools.regex-memo.title'),
|
||||
path: '/regex-memo',
|
||||
description: t('tools.regex-memo.description'),
|
||||
keywords: ['regex', 'regular', 'expression', 'javascript', 'memo', 'cheatsheet'],
|
||||
component: () => import('./regex-memo.vue'),
|
||||
icon: BrandJavascript,
|
||||
createdAt: new Date('2024-09-20'),
|
||||
});
|
4
src/tools/regex-memo/locales/en.yml
Normal file
4
src/tools/regex-memo/locales/en.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
tools:
|
||||
regex-memo:
|
||||
title: Regex cheatsheet
|
||||
description: Javascript Regex/Regular Expression cheatsheet.
|
4
src/tools/regex-memo/locales/fr.yml
Normal file
4
src/tools/regex-memo/locales/fr.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
tools:
|
||||
regex-memo:
|
||||
title: Feuille de triche Regex
|
||||
description: Feuille de triche Javascript Regex/Expression régulière.
|
4
src/tools/regex-memo/locales/zh.yml
Normal file
4
src/tools/regex-memo/locales/zh.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
tools:
|
||||
regex-memo:
|
||||
title: 正则表达式速查表
|
||||
description: Javascript 正则表达式速查表。
|
121
src/tools/regex-memo/regex-memo.content.fr.md
Normal file
121
src/tools/regex-memo/regex-memo.content.fr.md
Normal file
|
@ -0,0 +1,121 @@
|
|||
### Caractères normaux
|
||||
|
||||
Expression | Description
|
||||
:--|:--
|
||||
`.` ou `[^\n\r]` | tout caractère *sauf* un saut de ligne ou retour chariot
|
||||
`[A-Za-z]` | alphabet
|
||||
`[a-z]` | alphabet minuscule
|
||||
`[A-Z]` | alphabet majuscule
|
||||
`\d` ou `[0-9]` | chiffre
|
||||
`\D` ou `[^0-9]` | non-chiffre
|
||||
`_` | soulignement
|
||||
`\w` ou `[A-Za-z0-9_]` | alphabet, chiffre ou soulignement
|
||||
`\W` ou `[^A-Za-z0-9_]` | inverse de `\w`
|
||||
`\S` | inverse de `\s`
|
||||
|
||||
### Caractères d'espace
|
||||
|
||||
Expression | Description
|
||||
:--|:--
|
||||
` ` | espace
|
||||
`\t` | tabulation
|
||||
`\n` | saut de ligne
|
||||
`\r` | retour chariot
|
||||
`\s` | espace, tabulation, saut de ligne ou retour chariot
|
||||
|
||||
### Ensemble de caractères
|
||||
|
||||
Expression | Description
|
||||
:--|:--
|
||||
`[xyz]` | soit `x`, `y` ou `z`
|
||||
`[^xyz]` | ni `x`, ni `y`, ni `z`
|
||||
`[1-3]` | soit `1`, `2` ou `3`
|
||||
`[^1-3]` | ni `1`, ni `2`, ni `3`
|
||||
|
||||
- Pensez à un ensemble de caractères comme une opération `OU` sur les caractères simples qui sont enfermés entre crochets.
|
||||
- Utilisez `^` après le `[` d'ouverture pour "négation" de l'ensemble de caractères.
|
||||
- Dans un ensemble de caractères, `.` signifie un point littéral.
|
||||
|
||||
### Caractères nécessitant un échappement
|
||||
|
||||
#### En dehors d'un ensemble de caractères
|
||||
|
||||
Expression | Description
|
||||
:--|:--
|
||||
`\.` | point
|
||||
`\^` | accent circonflexe
|
||||
`\$` | signe dollar
|
||||
`\|` | barre verticale
|
||||
`\\` | barre oblique inverse
|
||||
`\/` | barre oblique
|
||||
`\(` | parenthèse ouvrante
|
||||
`\)` | parenthèse fermante
|
||||
`\[` | crochet ouvrant
|
||||
`\]` | crochet fermant
|
||||
`\{` | accolade ouvrante
|
||||
`\}` | accolade fermante
|
||||
|
||||
#### À l'intérieur d'un ensemble de caractères
|
||||
|
||||
Expression | Description
|
||||
:--|:--
|
||||
`\\` | barre oblique inverse
|
||||
`\]` | crochet fermant
|
||||
|
||||
- Un `^` doit être échappé uniquement s'il se produit immédiatement après le `[` d'ouverture de l'ensemble de caractères.
|
||||
- Un `-` doit être échappé uniquement s'il se produit entre deux alphabets ou deux chiffres.
|
||||
|
||||
### Quantificateurs
|
||||
|
||||
Expression | Description
|
||||
:--|:--
|
||||
`{2}` | exactement 2
|
||||
`{2,}` | au moins 2
|
||||
`{2,7}` | au moins 2 mais pas plus de 7
|
||||
`*` | 0 ou plus
|
||||
`+` | 1 ou plus
|
||||
`?` | exactement 0 ou 1
|
||||
|
||||
- Le quantificateur va *après* l'expression à quantifier.
|
||||
|
||||
### Limites
|
||||
|
||||
Expression | Description
|
||||
:--|:--
|
||||
`^` | début de chaîne
|
||||
`$` | fin de chaîne
|
||||
`\b` | limite de mot
|
||||
|
||||
- Comment fonctionne la correspondance des limites de mots :
|
||||
- Au début de la chaîne si le premier caractère est `\w`.
|
||||
- Entre deux caractères adjacents dans la chaîne, si le premier caractère est `\w` et le deuxième caractère est `\W`.
|
||||
- À la fin de la chaîne si le dernier caractère est `\w`.
|
||||
|
||||
### Correspondance
|
||||
|
||||
Expression | Description
|
||||
:--|:--
|
||||
`foo\|bar` | correspond soit à `foo` soit à `bar`
|
||||
`foo(?=bar)` | correspond à `foo` s'il est avant `bar`
|
||||
`foo(?!bar)` | correspond à `foo` s'il n'est *pas* avant `bar`
|
||||
`(?<=bar)foo` | correspond à `foo` s'il est après `bar`
|
||||
`(?<!bar)foo` | correspond à `foo` s'il n'est *pas* après `bar`
|
||||
|
||||
### Regroupement et capture
|
||||
|
||||
Expression | Description
|
||||
:--|:--
|
||||
`(foo)` | groupe de capture ; correspond et capture `foo`
|
||||
`(?:foo)` | groupe non-capturant ; correspond à `foo` mais *sans* capturer `foo`
|
||||
`(foo)bar\1` | `\1` est une référence inverse au 1er groupe de capture ; correspond à `foobarfoo`
|
||||
|
||||
- Les groupes de capture ne sont pertinents que dans les méthodes suivantes :
|
||||
- `string.match(regexp)`
|
||||
- `string.matchAll(regexp)`
|
||||
- `string.replace(regexp, callback)`
|
||||
- `\N` est une référence inverse au groupe de capture `Nth`. Les groupes de capture sont numérotés à partir de 1.
|
||||
|
||||
## Références et outils
|
||||
|
||||
- [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)
|
||||
- [RegExplained](https://leaverou.github.io/regexplained/)
|
121
src/tools/regex-memo/regex-memo.content.md
Normal file
121
src/tools/regex-memo/regex-memo.content.md
Normal file
|
@ -0,0 +1,121 @@
|
|||
### Normal characters
|
||||
|
||||
Expression | Description
|
||||
:--|:--
|
||||
`.` or `[^\n\r]` | any character *excluding* a newline or carriage return
|
||||
`[A-Za-z]` | alphabet
|
||||
`[a-z]` | lowercase alphabet
|
||||
`[A-Z]` | uppercase alphabet
|
||||
`\d` or `[0-9]` | digit
|
||||
`\D` or `[^0-9]` | non-digit
|
||||
`_` | underscore
|
||||
`\w` or `[A-Za-z0-9_]` | alphabet, digit or underscore
|
||||
`\W` or `[^A-Za-z0-9_]` | inverse of `\w`
|
||||
`\S` | inverse of `\s`
|
||||
|
||||
### Whitespace characters
|
||||
|
||||
Expression | Description
|
||||
:--|:--
|
||||
` ` | space
|
||||
`\t` | tab
|
||||
`\n` | newline
|
||||
`\r` | carriage return
|
||||
`\s` | space, tab, newline or carriage return
|
||||
|
||||
### Character set
|
||||
|
||||
Expression | Description
|
||||
:--|:--
|
||||
`[xyz]` | either `x`, `y` or `z`
|
||||
`[^xyz]` | neither `x`, `y` nor `z`
|
||||
`[1-3]` | either `1`, `2` or `3`
|
||||
`[^1-3]` | neither `1`, `2` nor `3`
|
||||
|
||||
- Think of a character set as an `OR` operation on the single characters that are enclosed between the square brackets.
|
||||
- Use `^` after the opening `[` to “negate” the character set.
|
||||
- Within a character set, `.` means a literal period.
|
||||
|
||||
### Characters that require escaping
|
||||
|
||||
#### Outside a character set
|
||||
|
||||
Expression | Description
|
||||
:--|:--
|
||||
`\.` | period
|
||||
`\^` | caret
|
||||
`\$` | dollar sign
|
||||
`\|` | pipe
|
||||
`\\` | back slash
|
||||
`\/` | forward slash
|
||||
`\(` | opening bracket
|
||||
`\)` | closing bracket
|
||||
`\[` | opening square bracket
|
||||
`\]` | closing square bracket
|
||||
`\{` | opening curly bracket
|
||||
`\}` | closing curly bracket
|
||||
|
||||
#### Inside a character set
|
||||
|
||||
Expression | Description
|
||||
:--|:--
|
||||
`\\` | back slash
|
||||
`\]` | closing square bracket
|
||||
|
||||
- A `^` must be escaped only if it occurs immediately after the opening `[` of the character set.
|
||||
- A `-` must be escaped only if it occurs between two alphabets or two digits.
|
||||
|
||||
### Quantifiers
|
||||
|
||||
Expression | Description
|
||||
:--|:--
|
||||
`{2}` | exactly 2
|
||||
`{2,}` | at least 2
|
||||
`{2,7}` | at least 2 but no more than 7
|
||||
`*` | 0 or more
|
||||
`+` | 1 or more
|
||||
`?` | exactly 0 or 1
|
||||
|
||||
- The quantifier goes *after* the expression to be quantified.
|
||||
|
||||
### Boundaries
|
||||
|
||||
Expression | Description
|
||||
:--|:--
|
||||
`^` | start of string
|
||||
`$` | end of string
|
||||
`\b` | word boundary
|
||||
|
||||
- How word boundary matching works:
|
||||
- At the beginning of the string if the first character is `\w`.
|
||||
- Between two adjacent characters within the string, if the first character is `\w` and the second character is `\W`.
|
||||
- At the end of the string if the last character is `\w`.
|
||||
|
||||
### Matching
|
||||
|
||||
Expression | Description
|
||||
:--|:--
|
||||
`foo\|bar` | match either `foo` or `bar`
|
||||
`foo(?=bar)` | match `foo` if it’s before `bar`
|
||||
`foo(?!bar)` | match `foo` if it’s *not* before `bar`
|
||||
`(?<=bar)foo` | match `foo` if it’s after `bar`
|
||||
`(?<!bar)foo` | match `foo` if it’s *not* after `bar`
|
||||
|
||||
### Grouping and capturing
|
||||
|
||||
Expression | Description
|
||||
:--|:--
|
||||
`(foo)` | capturing group; match and capture `foo`
|
||||
`(?:foo)` | non-capturing group; match `foo` but *without* capturing `foo`
|
||||
`(foo)bar\1` | `\1` is a backreference to the 1st capturing group; match `foobarfoo`
|
||||
|
||||
- Capturing groups are only relevant in the following methods:
|
||||
- `string.match(regexp)`
|
||||
- `string.matchAll(regexp)`
|
||||
- `string.replace(regexp, callback)`
|
||||
- `\N` is a backreference to the `Nth` capturing group. Capturing groups are numbered starting from 1.
|
||||
|
||||
## References and tools
|
||||
|
||||
- [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)
|
||||
- [RegExplained](https://leaverou.github.io/regexplained/)
|
121
src/tools/regex-memo/regex-memo.content.zh.md
Normal file
121
src/tools/regex-memo/regex-memo.content.zh.md
Normal file
|
@ -0,0 +1,121 @@
|
|||
### 普通字符
|
||||
|
||||
表达式 | 描述
|
||||
:--|:--
|
||||
`.` 或 `[^\n\r]` | 任何字符 *不包括* 换行或回车
|
||||
`[A-Za-z]` | 字母
|
||||
`[a-z]` | 小写字母
|
||||
`[A-Z]` | 大写字母
|
||||
`\d` 或 `[0-9]` | 数字
|
||||
`\D` 或 `[^0-9]` | 非数字
|
||||
`_` | 下划线
|
||||
`\w` 或 `[A-Za-z0-9_]` | 字母、数字或下划线
|
||||
`\W` 或 `[^A-Za-z0-9_]` | `\w` 的反义
|
||||
`\S` | `\s` 的反义
|
||||
|
||||
### 空白字符
|
||||
|
||||
表达式 | 描述
|
||||
:--|:--
|
||||
` ` | 空格
|
||||
`\t` | 制表符
|
||||
`\n` | 换行
|
||||
`\r` | 回车
|
||||
`\s` | 空格、制表符、换行或回车
|
||||
|
||||
### 字符集
|
||||
|
||||
表达式 | 描述
|
||||
:--|:--
|
||||
`[xyz]` | `x`、`y` 或 `z` 中的任意一个
|
||||
`[^xyz]` | 既不是 `x`、`y` 也不是 `z`
|
||||
`[1-3]` | `1`、`2` 或 `3` 中的任意一个
|
||||
`[^1-3]` | 既不是 `1`、`2` 也不是 `3`
|
||||
|
||||
- 将字符集视为对方括号内单个字符的 `OR` 操作。
|
||||
- 在开括号 `[` 后使用 `^` 来“否定”字符集。
|
||||
- 在字符集中,`.` 表示字面上的句号。
|
||||
|
||||
### 需要转义的字符
|
||||
|
||||
#### 在字符集外
|
||||
|
||||
表达式 | 描述
|
||||
:--|:--
|
||||
`\.` | 句号
|
||||
`\^` | 脱字符
|
||||
`\$` | 美元符号
|
||||
`\|` | 竖线
|
||||
`\\` | 反斜杠
|
||||
`\/` | 斜线
|
||||
`\(` | 开括号
|
||||
`\)` | 闭括号
|
||||
`\[` | 开方括号
|
||||
`\]` | 闭方括号
|
||||
`\{` | 开花括号
|
||||
`\}` | 闭花括号
|
||||
|
||||
#### 在字符集内
|
||||
|
||||
表达式 | 描述
|
||||
:--|:--
|
||||
`\\` | 反斜杠
|
||||
`\]` | 闭方括号
|
||||
|
||||
- 只有当 `^` 紧接在字符集的开括号 `[` 后面时才需要转义。
|
||||
- 只有当 `-` 出现在两个字母或两个数字之间时才需要转义。
|
||||
|
||||
### 量词
|
||||
|
||||
表达式 | 描述
|
||||
:--|:--
|
||||
`{2}` | 精确 2 次
|
||||
`{2,}` | 至少 2 次
|
||||
`{2,7}` | 至少 2 次但不超过 7 次
|
||||
`*` | 0 次或更多
|
||||
`+` | 1 次或更多
|
||||
`?` | 精确 0 次或 1 次
|
||||
|
||||
- 量词位于待量词化的表达式 *之后*。
|
||||
|
||||
### 边界
|
||||
|
||||
表达式 | 描述
|
||||
:--|:--
|
||||
`^` | 字符串开始
|
||||
`$` | 字符串结束
|
||||
`\b` | 单词边界
|
||||
|
||||
- 单词边界匹配的工作原理:
|
||||
- 在字符串开始时,如果第一个字符是 `\w`。
|
||||
- 在字符串中两个相邻字符之间,如果第一个字符是 `\w`,而第二个字符是 `\W`。
|
||||
- 在字符串结束时,如果最后一个字符是 `\w`。
|
||||
|
||||
### 匹配
|
||||
|
||||
表达式 | 描述
|
||||
:--|:--
|
||||
`foo\|bar` | 匹配 `foo` 或 `bar`
|
||||
`foo(?=bar)` | 如果 `foo` 在 `bar` 前面则匹配 `foo`
|
||||
`foo(?!bar)` | 如果 `foo` *不* 在 `bar` 前面则匹配 `foo`
|
||||
`(?<=bar)foo` | 如果 `foo` 在 `bar` 后面则匹配 `foo`
|
||||
`(?<!bar)foo` | 如果 `foo` *不* 在 `bar` 后面则匹配 `foo`
|
||||
|
||||
### 分组与捕获
|
||||
|
||||
表达式 | 描述
|
||||
:--|:--
|
||||
`(foo)` | 捕获组;匹配并捕获 `foo`
|
||||
`(?:foo)` | 非捕获组;匹配 `foo` 但 *不* 捕获 `foo`
|
||||
`(foo)bar\1` | `\1` 是对第 1 个捕获组的回参考;匹配 `foobarfoo`
|
||||
|
||||
- 捕获组仅在以下方法中相关:
|
||||
- `string.match(regexp)`
|
||||
- `string.matchAll(regexp)`
|
||||
- `string.replace(regexp, callback)`
|
||||
- `\N` 是对第 `N` 个捕获组的回参考。捕获组的编号从 1 开始。
|
||||
|
||||
## 参考文献和工具
|
||||
|
||||
- [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)
|
||||
- [RegExplained](https://leaverou.github.io/regexplained/)
|
37
src/tools/regex-memo/regex-memo.vue
Normal file
37
src/tools/regex-memo/regex-memo.vue
Normal file
|
@ -0,0 +1,37 @@
|
|||
<script setup lang="ts">
|
||||
import { useThemeVars } from 'naive-ui';
|
||||
import Memo from './regex-memo.content.md';
|
||||
import MemoZH from './regex-memo.content.zh.md';
|
||||
import MemoFR from './regex-memo.content.fr.md';
|
||||
|
||||
const themeVars = useThemeVars();
|
||||
const { locale } = useI18n();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<MemoZH v-if="locale === 'zh'" />
|
||||
<MemoFR v-else-if="locale === 'fr'" />
|
||||
<Memo v-else />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
::v-deep(pre) {
|
||||
margin: 0;
|
||||
padding: 15px 22px;
|
||||
background-color: v-bind('themeVars.cardColor');
|
||||
border-radius: 4px;
|
||||
overflow: auto;
|
||||
}
|
||||
::v-deep(table) {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
::v-deep(table), ::v-deep(td), ::v-deep(th) {
|
||||
border: 1px solid v-bind('themeVars.textColor1');
|
||||
padding: 5px;
|
||||
}
|
||||
::v-deep(a) {
|
||||
color: v-bind('themeVars.textColor1');
|
||||
}
|
||||
</style>
|
13
src/tools/regex-tester/index.ts
Normal file
13
src/tools/regex-tester/index.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { Language } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: t('tools.regex-tester.title'),
|
||||
path: '/regex-tester',
|
||||
description: t('tools.regex-tester.description'),
|
||||
keywords: ['regex', 'tester', 'sample', 'expression'],
|
||||
component: () => import('./regex-tester.vue'),
|
||||
icon: Language,
|
||||
createdAt: new Date('2024-09-20'),
|
||||
});
|
36
src/tools/regex-tester/locales/en.yml
Normal file
36
src/tools/regex-tester/locales/en.yml
Normal file
|
@ -0,0 +1,36 @@
|
|||
tools:
|
||||
regex-tester:
|
||||
title: Regex Tester
|
||||
description: Test your regular expressions with sample text.
|
||||
|
||||
inputTitle: 'Regex'
|
||||
inputLabel: 'Regex to test:'
|
||||
inputPlaceholder: 'Put the regex to test'
|
||||
outputLabel: 'Text to match:'
|
||||
outputPlaceholder: 'Put the text to match'
|
||||
|
||||
helpTip: 'See Regular Expression Cheatsheet'
|
||||
globalTitle: 'Global search'
|
||||
globalLabel: 'Global search.'
|
||||
ignoreCaseTitle: 'Case-insensitive search'
|
||||
ignoreCaseLabel: 'Case-insensitive search.'
|
||||
multilineTitle: 'Allows ^ and $ to match next to newline characters.'
|
||||
multilineLabel: 'Multiline'
|
||||
dotAllTitle: 'Allows . to match newline characters.'
|
||||
dotAllLabel: 'Singleline'
|
||||
unicodeTitle: 'Unicode; treat a pattern as a sequence of Unicode code points.'
|
||||
unicodeLabel: 'Unicode'
|
||||
unicodeSetsTitle: 'An upgrade to the u mode with more Unicode features.'
|
||||
unicodeSetsLabel: 'Unicode Sets'
|
||||
|
||||
matches: 'Matches'
|
||||
index: 'Index in text'
|
||||
value: 'Value'
|
||||
captures: 'Captures'
|
||||
groups: 'Groups'
|
||||
noMatch: 'No match'
|
||||
|
||||
sampleMatchingText: 'Sample matching text'
|
||||
regexDiagram: 'Regex Diagram'
|
||||
|
||||
invalidRegex: 'Invalid regex: {0}'
|
36
src/tools/regex-tester/locales/fr.yml
Normal file
36
src/tools/regex-tester/locales/fr.yml
Normal file
|
@ -0,0 +1,36 @@
|
|||
tools:
|
||||
regex-tester:
|
||||
title: Testeur Regex
|
||||
description: Testez vos expressions régulières avec un texte d'exemple.
|
||||
|
||||
inputTitle: 'Regex'
|
||||
inputLabel: 'Regex à tester:'
|
||||
inputPlaceholder: 'Mettez le regex à tester'
|
||||
outputLabel: 'Texte à faire correspondre:'
|
||||
outputPlaceholder: 'Mettez le texte à faire correspondre'
|
||||
|
||||
helpTip: 'Voir la feuille de triche des expressions régulières'
|
||||
globalTitle: 'Recherche globale'
|
||||
globalLabel: 'Recherche globale.'
|
||||
ignoreCaseTitle: 'Recherche insensible à la casse'
|
||||
ignoreCaseLabel: 'Recherche insensible à la casse.'
|
||||
multilineTitle: 'Permet à ^ et $ de correspondre aux caractères de nouvelle ligne.'
|
||||
multilineLabel: 'Multiligne'
|
||||
dotAllTitle: 'Permet à . de correspondre aux caractères de nouvelle ligne.'
|
||||
dotAllLabel: 'Monoligne'
|
||||
unicodeTitle: 'Unicode ; traiter un modèle comme une séquence de points de code Unicode.'
|
||||
unicodeLabel: 'Unicode'
|
||||
unicodeSetsTitle: 'Une mise à niveau du mode u avec plus de fonctionnalités Unicode.'
|
||||
unicodeSetsLabel: 'Ensembles Unicode'
|
||||
|
||||
matches: 'Correspondances'
|
||||
index: 'Index dans le texte'
|
||||
value: 'Valeur'
|
||||
captures: 'Captures'
|
||||
groups: 'Groupes'
|
||||
noMatch: 'Aucune correspondance'
|
||||
|
||||
sampleMatchingText: "Texte de correspondance d'exemple"
|
||||
regexDiagram: 'Schéma Regex'
|
||||
|
||||
invalidRegex: 'Regex invalide: {0}'
|
36
src/tools/regex-tester/locales/zh.yml
Normal file
36
src/tools/regex-tester/locales/zh.yml
Normal file
|
@ -0,0 +1,36 @@
|
|||
tools:
|
||||
regex-tester:
|
||||
title: 正则表达式测试工具
|
||||
description: 使用示例文本测试您的正则表达式。
|
||||
|
||||
inputTitle: '正则表达式'
|
||||
inputLabel: '要测试的正则表达式:'
|
||||
inputPlaceholder: '输入要测试的正则表达式'
|
||||
outputLabel: '匹配的文本:'
|
||||
outputPlaceholder: '输入要匹配的文本'
|
||||
|
||||
helpTip: '查看正则表达式速查表'
|
||||
globalTitle: '全局搜索'
|
||||
globalLabel: '全局搜索。'
|
||||
ignoreCaseTitle: '不区分大小写搜索'
|
||||
ignoreCaseLabel: '不区分大小写搜索。'
|
||||
multilineTitle: '允许^和$匹配换行符旁边的字符。'
|
||||
multilineLabel: '多行'
|
||||
dotAllTitle: '允许.匹配换行符。'
|
||||
dotAllLabel: '单行'
|
||||
unicodeTitle: 'Unicode; 将模式视为 Unicode 代码点序列。'
|
||||
unicodeLabel: 'Unicode'
|
||||
unicodeSetsTitle: '具有更多 Unicode 功能的 u 模式升级版。'
|
||||
unicodeSetsLabel: 'Unicode 集'
|
||||
|
||||
matches: '匹配项'
|
||||
index: '文本中的索引'
|
||||
value: '值'
|
||||
captures: '捕获'
|
||||
groups: '分组'
|
||||
noMatch: '无匹配项'
|
||||
|
||||
sampleMatchingText: '示例匹配文本'
|
||||
regexDiagram: '正则表达式图解'
|
||||
|
||||
invalidRegex: '无效的正则表达式:{0}'
|
106
src/tools/regex-tester/regex-tester.service.test.ts
Normal file
106
src/tools/regex-tester/regex-tester.service.test.ts
Normal file
|
@ -0,0 +1,106 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { matchRegex } from './regex-tester.service';
|
||||
|
||||
const regexesData = [
|
||||
{
|
||||
regex: '',
|
||||
text: '',
|
||||
flags: '',
|
||||
result: [],
|
||||
},
|
||||
{
|
||||
regex: '.*',
|
||||
text: '',
|
||||
flags: '',
|
||||
result: [],
|
||||
},
|
||||
{
|
||||
regex: '',
|
||||
text: 'aaa',
|
||||
flags: '',
|
||||
result: [],
|
||||
},
|
||||
{
|
||||
regex: 'a',
|
||||
text: 'baaa',
|
||||
flags: '',
|
||||
result: [
|
||||
{
|
||||
captures: [],
|
||||
groups: [],
|
||||
index: 1,
|
||||
value: 'a',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
regex: '(.)(?<g>r)',
|
||||
text: 'azertyr',
|
||||
flags: 'g',
|
||||
result: [
|
||||
{
|
||||
captures: [
|
||||
{
|
||||
end: 3,
|
||||
name: '1',
|
||||
start: 2,
|
||||
value: 'e',
|
||||
},
|
||||
{
|
||||
end: 4,
|
||||
name: '2',
|
||||
start: 3,
|
||||
value: 'r',
|
||||
},
|
||||
],
|
||||
groups: [
|
||||
{
|
||||
end: 4,
|
||||
name: 'g',
|
||||
start: 3,
|
||||
value: 'r',
|
||||
},
|
||||
],
|
||||
index: 2,
|
||||
value: 'er',
|
||||
},
|
||||
{
|
||||
captures: [
|
||||
{
|
||||
end: 6,
|
||||
name: '1',
|
||||
start: 5,
|
||||
value: 'y',
|
||||
},
|
||||
{
|
||||
end: 7,
|
||||
name: '2',
|
||||
start: 6,
|
||||
value: 'r',
|
||||
},
|
||||
],
|
||||
groups: [
|
||||
{
|
||||
end: 7,
|
||||
name: 'g',
|
||||
start: 6,
|
||||
value: 'r',
|
||||
},
|
||||
],
|
||||
index: 5,
|
||||
value: 'yr',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
describe('regex-tester', () => {
|
||||
for (const reg of regexesData) {
|
||||
const { regex, text, flags, result: expected_result } = reg;
|
||||
it(`Should matchRegex("${regex}","${text}","${flags}") return correct result`, async () => {
|
||||
const result = matchRegex(regex, text, `${flags}d`);
|
||||
|
||||
expect(result).to.deep.equal(expected_result);
|
||||
});
|
||||
}
|
||||
});
|
61
src/tools/regex-tester/regex-tester.service.ts
Normal file
61
src/tools/regex-tester/regex-tester.service.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
interface RegExpGroupIndices {
|
||||
[name: string]: [number, number]
|
||||
}
|
||||
interface RegExpIndices extends Array<[number, number]> {
|
||||
groups: RegExpGroupIndices
|
||||
}
|
||||
interface RegExpExecArrayWithIndices extends RegExpExecArray {
|
||||
indices: RegExpIndices
|
||||
}
|
||||
interface GroupCapture {
|
||||
name: string
|
||||
value: string
|
||||
start: number
|
||||
end: number
|
||||
};
|
||||
|
||||
export function matchRegex(regex: string, text: string, flags: string) {
|
||||
// if (regex === '' || text === '') {
|
||||
// return [];
|
||||
// }
|
||||
|
||||
let lastIndex = -1;
|
||||
const re = new RegExp(regex, flags);
|
||||
const results = [];
|
||||
let match = re.exec(text) as RegExpExecArrayWithIndices;
|
||||
while (match !== null) {
|
||||
if (re.lastIndex === lastIndex || match[0] === '') {
|
||||
break;
|
||||
}
|
||||
const indices = match.indices;
|
||||
const captures: Array<GroupCapture> = [];
|
||||
Object.entries(match).forEach(([captureName, captureValue]) => {
|
||||
if (captureName !== '0' && captureName.match(/\d+/)) {
|
||||
captures.push({
|
||||
name: captureName,
|
||||
value: captureValue,
|
||||
start: indices[Number(captureName)][0],
|
||||
end: indices[Number(captureName)][1],
|
||||
});
|
||||
}
|
||||
});
|
||||
const groups: Array<GroupCapture> = [];
|
||||
Object.entries(match.groups || {}).forEach(([groupName, groupValue]) => {
|
||||
groups.push({
|
||||
name: groupName,
|
||||
value: groupValue,
|
||||
start: indices.groups[groupName][0],
|
||||
end: indices.groups[groupName][1],
|
||||
});
|
||||
});
|
||||
results.push({
|
||||
index: match.index,
|
||||
value: match[0],
|
||||
captures,
|
||||
groups,
|
||||
});
|
||||
lastIndex = re.lastIndex;
|
||||
match = re.exec(text) as RegExpExecArrayWithIndices;
|
||||
}
|
||||
return results;
|
||||
}
|
194
src/tools/regex-tester/regex-tester.vue
Normal file
194
src/tools/regex-tester/regex-tester.vue
Normal file
|
@ -0,0 +1,194 @@
|
|||
<script setup lang="ts">
|
||||
import RandExp from 'randexp';
|
||||
import { render } from '@regexper/render';
|
||||
import type { ShadowRootExpose } from 'vue-shadow-dom';
|
||||
import { matchRegex } from './regex-tester.service';
|
||||
import { useValidation } from '@/composable/validation';
|
||||
import { useQueryParamOrStorage } from '@/composable/queryParams';
|
||||
|
||||
const { t } = useI18n();
|
||||
const regex = useQueryParamOrStorage({ name: 'regex', storageName: 'regex-tester:regex', defaultValue: '' });
|
||||
const text = ref('');
|
||||
const global = ref(true);
|
||||
const ignoreCase = ref(false);
|
||||
const multiline = ref(false);
|
||||
const dotAll = ref(true);
|
||||
const unicode = ref(true);
|
||||
const unicodeSets = ref(false);
|
||||
const visualizerSVG = ref<ShadowRootExpose>();
|
||||
|
||||
const regexValidation = useValidation({
|
||||
source: regex,
|
||||
rules: [
|
||||
{
|
||||
message: t('tools.regex-tester.invalidRegex'),
|
||||
validator: value => new RegExp(value),
|
||||
getErrorMessage: (value) => {
|
||||
const _ = new RegExp(value);
|
||||
return '';
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
const results = computed(() => {
|
||||
let flags = 'd';
|
||||
if (global.value) {
|
||||
flags += 'g';
|
||||
}
|
||||
if (ignoreCase.value) {
|
||||
flags += 'i';
|
||||
}
|
||||
if (multiline.value) {
|
||||
flags += 'm';
|
||||
}
|
||||
if (dotAll.value) {
|
||||
flags += 's';
|
||||
}
|
||||
if (unicode.value) {
|
||||
flags += 'u';
|
||||
}
|
||||
else if (unicodeSets.value) {
|
||||
flags += 'v';
|
||||
}
|
||||
|
||||
try {
|
||||
return matchRegex(regex.value, text.value, flags);
|
||||
}
|
||||
catch (_) {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
const sample = computed(() => {
|
||||
try {
|
||||
const randexp = new RandExp(new RegExp(regex.value.replace(/\(\?\<[^\>]*\>/g, '(?:')));
|
||||
return randexp.gen();
|
||||
}
|
||||
catch (_) {
|
||||
return '';
|
||||
}
|
||||
});
|
||||
|
||||
watchEffect(
|
||||
async () => {
|
||||
const regexValue = regex.value;
|
||||
// shadow root is required:
|
||||
// @regexper/render append a <defs><style> that broke svg transparency of icons in the whole site
|
||||
const visualizer = visualizerSVG.value?.shadow_root;
|
||||
if (visualizer) {
|
||||
while (visualizer.lastChild) {
|
||||
visualizer.removeChild(visualizer.lastChild);
|
||||
}
|
||||
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||
try {
|
||||
await render(regexValue, svg);
|
||||
}
|
||||
catch (_) {
|
||||
}
|
||||
visualizer.appendChild(svg);
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div max-w-600px>
|
||||
<c-card :title="t('tools.regex-tester.inputTitle')" mb-1>
|
||||
<c-input-text
|
||||
v-model:value="regex"
|
||||
:label="t('tools.regex-tester.inputLabel')"
|
||||
:placeholder="t('tools.regex-tester.inputPlaceholder')"
|
||||
multiline
|
||||
rows="3"
|
||||
:validation="regexValidation"
|
||||
/>
|
||||
<router-link target="_blank" to="/regex-memo" mb-1 mt-1>
|
||||
{{ t('tools.regex-tester.helpTip') }}
|
||||
</router-link>
|
||||
<n-space>
|
||||
<n-checkbox v-model:checked="global">
|
||||
<span :title="t('tools.regex-tester.globalTitle')">{{ t('tools.regex-tester.globalLabel') }} (<code>g</code>)</span>
|
||||
</n-checkbox>
|
||||
<n-checkbox v-model:checked="ignoreCase">
|
||||
<span :title="t('tools.regex-tester.ignoreCaseTitle')">{{ t('tools.regex-tester.ignoreCaseLabel') }} (<code>i</code>)</span>
|
||||
</n-checkbox>
|
||||
<n-checkbox v-model:checked="multiline">
|
||||
<span :title="t('tools.regex-tester.multilineTitle')">{{ t('tools.regex-tester.multilineLabel') }}(<code>m</code>)</span>
|
||||
</n-checkbox>
|
||||
<n-checkbox v-model:checked="dotAll">
|
||||
<span :title="t('tools.regex-tester.dotAllTitle')">{{ t('tools.regex-tester.dotAllLabel') }}(<code>s</code>)</span>
|
||||
</n-checkbox>
|
||||
<n-checkbox v-model:checked="unicode">
|
||||
<span :title="t('tools.regex-tester.unicodeTitle')">{{ t('tools.regex-tester.unicodeLabel') }}(<code>u</code>)</span>
|
||||
</n-checkbox>
|
||||
<n-checkbox v-model:checked="unicodeSets">
|
||||
<span :title="t('tools.regex-tester.unicodeSetsTitle')">{{ t('tools.regex-tester.unicodeSetsLabel') }} (<code>v</code>)</span>
|
||||
</n-checkbox>
|
||||
</n-space>
|
||||
|
||||
<n-divider />
|
||||
|
||||
<c-input-text
|
||||
v-model:value="text"
|
||||
:label="t('tools.regex-tester.outputLabel')"
|
||||
:placeholder="t('tools.regex-tester.outputPlaceholder')"
|
||||
multiline
|
||||
rows="5"
|
||||
/>
|
||||
</c-card>
|
||||
|
||||
<c-card :title="t('tools.regex-tester.groups')" mb-1 mt-3>
|
||||
<n-table v-if="results?.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">
|
||||
{{ t('tools.regex-tester.index') }}
|
||||
</th>
|
||||
<th scope="col">
|
||||
{{ t('tools.regex-tester.value') }}
|
||||
</th>
|
||||
<th scope="col">
|
||||
{{ t('tools.regex-tester.captures') }}
|
||||
</th>
|
||||
<th scope="col">
|
||||
{{ t('tools.regex-tester.groups') }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="match of results" :key="match.index">
|
||||
<td>{{ match.index }}</td>
|
||||
<td>{{ match.value }}</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li v-for="capture in match.captures" :key="capture.name">
|
||||
"{{ capture.name }}" = {{ capture.value }} [{{ capture.start }} - {{ capture.end }}]
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li v-for="group in match.groups" :key="group.name">
|
||||
"{{ group.name }}" = {{ group.value }} [{{ group.start }} - {{ group.end }}]
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</n-table>
|
||||
<c-alert v-else>
|
||||
{{ t('tools.regex-tester.noMatch') }}
|
||||
</c-alert>
|
||||
</c-card>
|
||||
|
||||
<c-card :title="t('tools.regex-tester.sampleMatchingText')" mt-3>
|
||||
<pre style="white-space: pre-wrap; word-break: break-all;">{{ sample }}</pre>
|
||||
</c-card>
|
||||
|
||||
<c-card :title="t('tools.regex-tester.regexDiagram')" style="overflow-x: scroll;" mt-3>
|
||||
<shadow-root ref="visualizerSVG">
|
||||
 
|
||||
</shadow-root>
|
||||
</c-card>
|
||||
</div>
|
||||
</template>
|
|
@ -20,7 +20,7 @@ export function createToken({
|
|||
withLowercase ? 'abcdefghijklmopqrstuvwxyz' : '',
|
||||
withNumbers ? '0123456789' : '',
|
||||
withSymbols ? '.,;:!?./-"\'#{([-|\\@)]=}*+' : '',
|
||||
].join(''); ;
|
||||
].join('');
|
||||
|
||||
return shuffleString(allAlphabet.repeat(length)).substring(0, length);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ const decodeInput = ref('Hello%20world%20%3A)');
|
|||
const decodeOutput = computed(() => withDefaultOnError(() => decodeURIComponent(decodeInput.value), ''));
|
||||
|
||||
const decodeValidation = useValidation({
|
||||
source: encodeInput,
|
||||
source: decodeInput,
|
||||
rules: [
|
||||
{
|
||||
validator: value => isNotThrowing(() => decodeURIComponent(value)),
|
||||
|
|
13
src/tools/xml-to-json/index.ts
Normal file
13
src/tools/xml-to-json/index.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { Braces } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: t('tools.xml-to-json.title'),
|
||||
path: '/xml-to-json',
|
||||
description: t('tools.xml-to-json.description'),
|
||||
keywords: ['xml', 'json'],
|
||||
component: () => import('./xml-to-json.vue'),
|
||||
icon: Braces,
|
||||
createdAt: new Date('2024-08-09'),
|
||||
});
|
10
src/tools/xml-to-json/locales/en.yml
Normal file
10
src/tools/xml-to-json/locales/en.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
tools:
|
||||
xml-to-json:
|
||||
title: XML to JSON
|
||||
description: Convert XML to JSON.
|
||||
|
||||
inputLabel: Your XML content
|
||||
inputPlaceholder: Paste your XML content here...
|
||||
outputLabel: Converted JSON
|
||||
|
||||
invalidMessage: Provided XML is not valid.
|
10
src/tools/xml-to-json/locales/fr.yml
Normal file
10
src/tools/xml-to-json/locales/fr.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
tools:
|
||||
xml-to-json:
|
||||
title: XML vers JSON
|
||||
description: Convertir XML en JSON.
|
||||
|
||||
inputLabel: Votre contenu XML
|
||||
inputPlaceholder: Collez votre contenu XML ici...
|
||||
outputLabel: JSON converti
|
||||
|
||||
invalidMessage: Le XML fourni n'est pas valide.
|
10
src/tools/xml-to-json/locales/zh.yml
Normal file
10
src/tools/xml-to-json/locales/zh.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
tools:
|
||||
xml-to-json:
|
||||
title: XML 转 JSON
|
||||
description: 将 XML 转换为 JSON。
|
||||
|
||||
inputLabel: 您的 XML 内容
|
||||
inputPlaceholder: 在此粘贴您的 XML 内容...
|
||||
outputLabel: 转换后的 JSON
|
||||
|
||||
invalidMessage: 提供的 XML 不是有效的。
|
33
src/tools/xml-to-json/xml-to-json.vue
Normal file
33
src/tools/xml-to-json/xml-to-json.vue
Normal file
|
@ -0,0 +1,33 @@
|
|||
<script setup lang="ts">
|
||||
import convert from 'xml-js';
|
||||
import { isValidXML } from '../xml-formatter/xml-formatter.service';
|
||||
import { withDefaultOnError } from '@/utils/defaults';
|
||||
import type { UseValidationRule } from '@/composable/validation';
|
||||
|
||||
const { t } = useI18n();
|
||||
const defaultValue = '<a x="1.234" y="It\'s"/>';
|
||||
function transformer(value: string) {
|
||||
return withDefaultOnError(() => {
|
||||
return JSON.stringify(convert.xml2js(value, { compact: true }), null, 2);
|
||||
}, '');
|
||||
}
|
||||
|
||||
const rules: UseValidationRule<string>[] = [
|
||||
{
|
||||
validator: isValidXML,
|
||||
message: t('tools.xml-to-json.invalidMessage'),
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<format-transformer
|
||||
input-label="t('tools.xml-to-json.inputLabel')"
|
||||
:input-default="defaultValue"
|
||||
input-placeholder="t('tools.xml-to-json.inputPlaceholder')"
|
||||
output-label="t('tools.xml-to-json.outputLabel')"
|
||||
output-language="json"
|
||||
:transformer="transformer"
|
||||
:input-validation-rules="rules"
|
||||
/>
|
||||
</template>
|
|
@ -38,7 +38,8 @@ describe('base64 utils', () => {
|
|||
|
||||
it('should throw for incorrect base64 string', () => {
|
||||
expect(() => base64ToText('a')).to.throw('Incorrect base64 string');
|
||||
expect(() => base64ToText(' ')).to.throw('Incorrect base64 string');
|
||||
// should not really be false because trimming of space is now implied
|
||||
// expect(() => base64ToText(' ')).to.throw('Incorrect base64 string');
|
||||
expect(() => base64ToText('é')).to.throw('Incorrect base64 string');
|
||||
// missing final '='
|
||||
expect(() => base64ToText('bG9yZW0gaXBzdW0')).to.throw('Incorrect base64 string');
|
||||
|
@ -56,17 +57,17 @@ describe('base64 utils', () => {
|
|||
|
||||
it('should return false for incorrect base64 string', () => {
|
||||
expect(isValidBase64('a')).to.eql(false);
|
||||
expect(isValidBase64(' ')).to.eql(false);
|
||||
expect(isValidBase64('é')).to.eql(false);
|
||||
expect(isValidBase64('data:text/plain;notbase64,YQ==')).to.eql(false);
|
||||
// missing final '='
|
||||
expect(isValidBase64('bG9yZW0gaXBzdW0')).to.eql(false);
|
||||
});
|
||||
|
||||
it('should return false for untrimmed correct base64 string', () => {
|
||||
expect(isValidBase64('bG9yZW0gaXBzdW0= ')).to.eql(false);
|
||||
expect(isValidBase64(' LTE=')).to.eql(false);
|
||||
expect(isValidBase64(' YQ== ')).to.eql(false);
|
||||
it('should return true for untrimmed correct base64 string', () => {
|
||||
expect(isValidBase64('bG9yZW0gaXBzdW0= ')).to.eql(true);
|
||||
expect(isValidBase64(' LTE=')).to.eql(true);
|
||||
expect(isValidBase64(' YQ== ')).to.eql(true);
|
||||
expect(isValidBase64(' ')).to.eql(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { Base64 } from 'js-base64';
|
||||
|
||||
export { textToBase64, base64ToText, isValidBase64, removePotentialDataAndMimePrefix };
|
||||
|
||||
function textToBase64(str: string, { makeUrlSafe = false }: { makeUrlSafe?: boolean } = {}) {
|
||||
const encoded = window.btoa(str);
|
||||
const encoded = Base64.encode(str);
|
||||
return makeUrlSafe ? makeUriSafe(encoded) : encoded;
|
||||
}
|
||||
|
||||
|
@ -16,7 +18,7 @@ function base64ToText(str: string, { makeUrlSafe = false }: { makeUrlSafe?: bool
|
|||
}
|
||||
|
||||
try {
|
||||
return window.atob(cleanStr);
|
||||
return Base64.decode(cleanStr);
|
||||
}
|
||||
catch (_) {
|
||||
throw new Error('Incorrect base64 string');
|
||||
|
@ -34,10 +36,11 @@ function isValidBase64(str: string, { makeUrlSafe = false }: { makeUrlSafe?: boo
|
|||
}
|
||||
|
||||
try {
|
||||
const reEncodedBase64 = Base64.fromUint8Array(Base64.toUint8Array(cleanStr));
|
||||
if (makeUrlSafe) {
|
||||
return removePotentialPadding(window.btoa(window.atob(cleanStr))) === cleanStr;
|
||||
return removePotentialPadding(reEncodedBase64) === cleanStr;
|
||||
}
|
||||
return window.btoa(window.atob(cleanStr)) === cleanStr;
|
||||
return reEncodedBase64 === cleanStr.replace(/\s/g, '');
|
||||
}
|
||||
catch (err) {
|
||||
return false;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue