Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
3ff7727
Modify the comments and translations of the slugify-string tool
stevenlee87 Jun 3, 2026
9ddb92c
Modify the comments and translations of the slugify-string tool
stevenlee87 Jun 3, 2026
be9d705
add new funtion
stevenlee87 Jun 4, 2026
70d0b20
fix: replace ReDoS-vulnerable regex in CSS/JS minify functions
stevenlee87 Jun 4, 2026
e2e7d39
fix: replace remaining ReDoS-vulnerable regex in JS minify
stevenlee87 Jun 4, 2026
83fd1f3
fix: add vite alias for @vueuse/shared to fix build compatibility
stevenlee87 Jun 4, 2026
7dcc575
fix: update pnpm-lock.yaml with new dependencies
stevenlee87 Jun 4, 2026
23d9e89
Add new tool:SSL Certificate Parser
stevenlee87 Jun 5, 2026
22f9a78
Add new tool: DNS 查询工具 — 在线查 A/AAAA/CNAME/MX/TXT 记录
stevenlee87 Jun 12, 2026
148867e
Add new tool: DNS 查询工具 — 在线查 A/AAAA/CNAME/MX/TXT 记录
stevenlee87 Jun 12, 2026
3ca1fea
Add new tool: DNS 查询工具 — 在线查 A/AAAA/CNAME/MX/TXT 记录
stevenlee87 Jun 12, 2026
f7eef65
Adjustment of tool classification
stevenlee87 Jun 12, 2026
cb327a5
Add new tool: DNS 查询工具 — 在线查 A/AAAA/CNAME/MX/TXT 记录
stevenlee87 Jun 12, 2026
b2204aa
Edit tool: DNS Query, Add WHOIS information
stevenlee87 Jun 12, 2026
07fecf0
Enable PWA skipWaiting and clientsClaim for instant updates
stevenlee87 Jun 12, 2026
fb4f9bb
Add new tool: 日期计算器 — 日期加减与两个日期间隔天数计算
stevenlee87 Jun 16, 2026
e52e33a
Order newest tools by createdAt so the latest tool shows first
stevenlee87 Jun 16, 2026
dc07fd4
Reload on service-worker takeover (controllerchange) for reliable PWA…
stevenlee87 Jun 16, 2026
30384f2
Fix SonarCloud warnings: replaceAll, th scope, globalThis
stevenlee87 Jun 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion .eslintrc-auto-import.json
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,20 @@
"watchTriggerable": true,
"watchWithFilter": true,
"whenever": true,
"toValue": true
"toValue": true,
"DirectiveBinding": true,
"ExtractDefaultPropTypes": true,
"ExtractPropTypes": true,
"ExtractPublicPropTypes": true,
"MaybeRef": true,
"MaybeRefOrGetter": true,
"WritableComputedRef": true,
"injectLocal": true,
"onWatcherCleanup": true,
"provideLocal": true,
"useClipboardItems": true,
"useId": true,
"useModel": true,
"useTemplateRef": true
}
}
13 changes: 12 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,19 @@ coverage
*.sw?

.env
.env.*
/test-results/
/playwright-report/
/playwright/.cache/
# Webkit with playwright creates a salt file
salt
salt

# Cloudflare / Wrangler
.wrangler/
wrangler.toml

# Claude Code
.claude/

# Lock files (choose one to keep; delete this line if you want to commit yours)
package-lock.json
Empty file.
574 changes: 574 additions & 0 deletions .playwright-mcp/page-2026-06-12T07-24-10-708Z.yml

Large diffs are not rendered by default.

616 changes: 616 additions & 0 deletions .playwright-mcp/page-2026-06-12T07-24-44-587Z.yml

Large diffs are not rendered by default.

596 changes: 596 additions & 0 deletions .playwright-mcp/page-2026-06-12T07-24-51-311Z.yml

Large diffs are not rendered by default.

616 changes: 616 additions & 0 deletions .playwright-mcp/page-2026-06-12T07-25-13-336Z.yml

Large diffs are not rendered by default.

596 changes: 596 additions & 0 deletions .playwright-mcp/page-2026-06-12T07-25-19-177Z.yml

Large diffs are not rendered by default.

616 changes: 616 additions & 0 deletions .playwright-mcp/page-2026-06-12T07-29-28-690Z.yml

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions auto-imports.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ declare global {
const h: typeof import('vue')['h']
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
const inject: typeof import('vue')['inject']
const injectLocal: typeof import('@vueuse/core')['injectLocal']
const isDefined: typeof import('@vueuse/core')['isDefined']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
Expand Down Expand Up @@ -63,8 +64,10 @@ declare global {
const onStartTyping: typeof import('@vueuse/core')['onStartTyping']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
const provide: typeof import('vue')['provide']
const provideLocal: typeof import('@vueuse/core')['provideLocal']
const reactify: typeof import('@vueuse/core')['reactify']
const reactifyObject: typeof import('@vueuse/core')['reactifyObject']
const reactive: typeof import('vue')['reactive']
Expand Down Expand Up @@ -128,6 +131,7 @@ declare global {
const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation']
const useCached: typeof import('@vueuse/core')['useCached']
const useClipboard: typeof import('@vueuse/core')['useClipboard']
const useClipboardItems: typeof import('@vueuse/core')['useClipboardItems']
const useCloned: typeof import('@vueuse/core')['useCloned']
const useColorMode: typeof import('@vueuse/core')['useColorMode']
const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog']
Expand Down Expand Up @@ -171,6 +175,7 @@ declare global {
const useGamepad: typeof import('@vueuse/core')['useGamepad']
const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
const useI18n: typeof import('vue-i18n')['useI18n']
const useId: typeof import('vue')['useId']
const useIdle: typeof import('@vueuse/core')['useIdle']
const useImage: typeof import('@vueuse/core')['useImage']
const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll']
Expand All @@ -189,6 +194,7 @@ declare global {
const useMemoize: typeof import('@vueuse/core')['useMemoize']
const useMemory: typeof import('@vueuse/core')['useMemory']
const useMessage: typeof import('naive-ui')['useMessage']
const useModel: typeof import('vue')['useModel']
const useMounted: typeof import('@vueuse/core')['useMounted']
const useMouse: typeof import('@vueuse/core')['useMouse']
const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement']
Expand Down Expand Up @@ -237,6 +243,7 @@ declare global {
const useStyleTag: typeof import('@vueuse/core')['useStyleTag']
const useSupported: typeof import('@vueuse/core')['useSupported']
const useSwipe: typeof import('@vueuse/core')['useSwipe']
const useTemplateRef: typeof import('vue')['useTemplateRef']
const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList']
const useTextDirection: typeof import('@vueuse/core')['useTextDirection']
const useTextSelection: typeof import('@vueuse/core')['useTextSelection']
Expand Down
47 changes: 47 additions & 0 deletions components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ declare module '@vue/runtime-core' {
Bcrypt: typeof import('./src/tools/bcrypt/bcrypt.vue')['default']
BenchmarkBuilder: typeof import('./src/tools/benchmark-builder/benchmark-builder.vue')['default']
Bip39Generator: typeof import('./src/tools/bip39-generator/bip39-generator.vue')['default']
ByteUnitConverter: typeof import('./src/tools/byte-unit-converter/byte-unit-converter.vue')['default']
CAlert: typeof import('./src/ui/c-alert/c-alert.vue')['default']
'CAlert.demo': typeof import('./src/ui/c-alert/c-alert.demo.vue')['default']
CameraRecorder: typeof import('./src/tools/camera-recorder/camera-recorder.vue')['default']
Expand Down Expand Up @@ -58,17 +59,21 @@ declare module '@vue/runtime-core' {
CrontabGenerator: typeof import('./src/tools/crontab-generator/crontab-generator.vue')['default']
CSelect: typeof import('./src/ui/c-select/c-select.vue')['default']
'CSelect.demo': typeof import('./src/ui/c-select/c-select.demo.vue')['default']
CssJsPrettifyMinify: typeof import('./src/tools/css-js-prettify-minify/css-js-prettify-minify.vue')['default']
CTable: typeof import('./src/ui/c-table/c-table.vue')['default']
'CTable.demo': typeof import('./src/ui/c-table/c-table.demo.vue')['default']
CTextCopyable: typeof import('./src/ui/c-text-copyable/c-text-copyable.vue')['default']
'CTextCopyable.demo': typeof import('./src/ui/c-text-copyable/c-text-copyable.demo.vue')['default']
CTooltip: typeof import('./src/ui/c-tooltip/c-tooltip.vue')['default']
'CTooltip.demo': typeof import('./src/ui/c-tooltip/c-tooltip.demo.vue')['default']
CurlToCode: typeof import('./src/tools/curl-to-code/curl-to-code.vue')['default']
DateCalculator: typeof import('./src/tools/date-calculator/date-calculator.vue')['default']
DateTimeConverter: typeof import('./src/tools/date-time-converter/date-time-converter.vue')['default']
'DemoHome.page': typeof import('./src/ui/demo/demo-home.page.vue')['default']
DemoWrapper: typeof import('./src/ui/demo/demo-wrapper.vue')['default']
DeviceInformation: typeof import('./src/tools/device-information/device-information.vue')['default']
DiffViewer: typeof import('./src/tools/json-diff/diff-viewer/diff-viewer.vue')['default']
DnsQuery: typeof import('./src/tools/dns-query/dns-query.vue')['default']
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']
Expand All @@ -86,21 +91,33 @@ declare module '@vue/runtime-core' {
HmacGenerator: typeof import('./src/tools/hmac-generator/hmac-generator.vue')['default']
'Home.page': typeof import('./src/pages/Home.page.vue')['default']
HtmlEntities: typeof import('./src/tools/html-entities/html-entities.vue')['default']
HtmlToMarkdown: typeof import('./src/tools/html-to-markdown/html-to-markdown.vue')['default']
HtmlWysiwygEditor: typeof import('./src/tools/html-wysiwyg-editor/html-wysiwyg-editor.vue')['default']
HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default']
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:contentCopy': typeof import('~icons/mdi/content-copy')['default']
'IconMdi:kettleSteamOutline': typeof import('~icons/mdi/kettle-steam-outline')['default']
IconMdiArrowDown: typeof import('~icons/mdi/arrow-down')['default']
IconMdiArrowRightBottom: typeof import('~icons/mdi/arrow-right-bottom')['default']
IconMdiCamera: typeof import('~icons/mdi/camera')['default']
IconMdiChevronDown: typeof import('~icons/mdi/chevron-down')['default']
IconMdiChevronRight: typeof import('~icons/mdi/chevron-right')['default']
IconMdiClose: typeof import('~icons/mdi/close')['default']
IconMdiContentCopy: typeof import('~icons/mdi/content-copy')['default']
IconMdiDeleteOutline: typeof import('~icons/mdi/delete-outline')['default']
IconMdiDownload: typeof import('~icons/mdi/download')['default']
IconMdiEye: typeof import('~icons/mdi/eye')['default']
IconMdiEyeOff: typeof import('~icons/mdi/eye-off')['default']
IconMdiHeart: typeof import('~icons/mdi/heart')['default']
IconMdiPause: typeof import('~icons/mdi/pause')['default']
IconMdiPlay: typeof import('~icons/mdi/play')['default']
IconMdiRecord: typeof import('~icons/mdi/record')['default']
IconMdiRefresh: typeof import('~icons/mdi/refresh')['default']
IconMdiSearch: typeof import('~icons/mdi/search')['default']
IconMdiTranslate: typeof import('~icons/mdi/translate')['default']
IconMdiTriangleDown: typeof import('~icons/mdi/triangle-down')['default']
IconMdiVideo: typeof import('~icons/mdi/video')['default']
InputCopyable: typeof import('./src/components/InputCopyable.vue')['default']
IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default']
Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default']
Expand All @@ -111,6 +128,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']
JsonToTypes: typeof import('./src/tools/json-to-types/json-to-types.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']
Expand All @@ -129,20 +147,48 @@ declare module '@vue/runtime-core' {
MenuLayout: typeof import('./src/components/MenuLayout.vue')['default']
MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default']
MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default']
NAlert: typeof import('naive-ui')['NAlert']
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']
NCollapse: typeof import('naive-ui')['NCollapse']
NCollapseItem: typeof import('naive-ui')['NCollapseItem']
NCollapseTransition: typeof import('naive-ui')['NCollapseTransition']
NColorPicker: typeof import('naive-ui')['NColorPicker']
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
NDatePicker: typeof import('naive-ui')['NDatePicker']
NDivider: typeof import('naive-ui')['NDivider']
NDynamicInput: typeof import('naive-ui')['NDynamicInput']
NEllipsis: typeof import('naive-ui')['NEllipsis']
NForm: typeof import('naive-ui')['NForm']
NFormItem: typeof import('naive-ui')['NFormItem']
NGi: typeof import('naive-ui')['NGi']
NGrid: typeof import('naive-ui')['NGrid']
NH1: typeof import('naive-ui')['NH1']
NH2: typeof import('naive-ui')['NH2']
NH3: typeof import('naive-ui')['NH3']
NH4: typeof import('naive-ui')['NH4']
NIcon: typeof import('naive-ui')['NIcon']
NImage: typeof import('naive-ui')['NImage']
NInputGroup: typeof import('naive-ui')['NInputGroup']
NInputGroupLabel: typeof import('naive-ui')['NInputGroupLabel']
NInputNumber: typeof import('naive-ui')['NInputNumber']
NLayout: typeof import('naive-ui')['NLayout']
NLayoutSider: typeof import('naive-ui')['NLayoutSider']
NLi: typeof import('naive-ui')['NLi']
NMenu: typeof import('naive-ui')['NMenu']
NP: typeof import('naive-ui')['NP']
NProgress: typeof import('naive-ui')['NProgress']
NScrollbar: typeof import('naive-ui')['NScrollbar']
NSlider: typeof import('naive-ui')['NSlider']
NSpace: typeof import('naive-ui')['NSpace']
NSpin: typeof import('naive-ui')['NSpin']
NStatistic: typeof import('naive-ui')['NStatistic']
NSwitch: typeof import('naive-ui')['NSwitch']
NTable: typeof import('naive-ui')['NTable']
NTag: typeof import('naive-ui')['NTag']
NUl: typeof import('naive-ui')['NUl']
NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default']
OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default']
PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default']
Expand All @@ -164,6 +210,7 @@ declare module '@vue/runtime-core' {
SlugifyString: typeof import('./src/tools/slugify-string/slugify-string.vue')['default']
SpanCopyable: typeof import('./src/components/SpanCopyable.vue')['default']
SqlPrettify: typeof import('./src/tools/sql-prettify/sql-prettify.vue')['default']
SslCertificateParser: typeof import('./src/tools/ssl-certificate-parser/ssl-certificate-parser.vue')['default']
StringObfuscator: typeof import('./src/tools/string-obfuscator/string-obfuscator.vue')['default']
SvgPlaceholderGenerator: typeof import('./src/tools/svg-placeholder-generator/svg-placeholder-generator.vue')['default']
TemperatureConverter: typeof import('./src/tools/temperature-converter/temperature-converter.vue')['default']
Expand Down
81 changes: 81 additions & 0 deletions locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ tools:
title: SVG placeholder generator
description: Generate svg images to use as a placeholder in your applications.

dns-query:
title: DNS Query
description: Query DNS records (A, AAAA, CNAME, MX, TXT, NS, SOA, ...) for any domain name online using Cloudflare DNS.

json-to-csv:
title: JSON to CSV
description: Convert JSON to CSV with automatic header detection.
Expand Down Expand Up @@ -293,6 +297,25 @@ tools:
title: JWT parser
description: Parse and decode your JSON Web Token (jwt) and display its content.

date-calculator:
title: Date calculator
description: Add or subtract days from a date, or calculate the number of days between two dates.
offset:
sectionTitle: Date after / before N days
baseDate: Start date
days: Days offset
daysHint: Use a negative number to go backwards
resultLabel: Result date
diff:
sectionTitle: Days between two dates
startDate: Start date
targetDate: Target date
resultLabel: Difference
dayUnit: days
directionAfter: Target date is after the start date
directionBefore: Target date is before the start date
directionSame: Same date

date-converter:
title: Date-time converter
description: Convert date and time into the various different formats
Expand Down Expand Up @@ -392,3 +415,61 @@ tools:
text-to-binary:
title: Text to ASCII binary
description: Convert text to its ASCII binary representation and vice-versa.

html-to-markdown:
title: HTML to Markdown
description: Convert HTML to Markdown with this online converter.

byte-unit-converter:
title: Byte unit converter
description: Convert between data size units (bytes, KB, MB, GB, TB) in both decimal (SI) and binary (IEC) systems.

json-to-types:
title: JSON to TypeScript/Go
description: Generate TypeScript interfaces or Go structs from a JSON sample.

css-js-prettify-minify:
title: CSS/JS Prettify & Minify
description: Prettify or minify your CSS and JavaScript code online.

curl-to-code:
title: cURL to Code
description: Convert cURL commands to code in various programming languages.

ssl-certificate-parser:
title: SSL Certificate Parser
description: Parse and decode PEM certificates to view expiry date, domain, issuer and other details.
inputLabel: PEM certificate
inputPlaceholder: 'Paste your PEM certificate here (-----BEGIN CERTIFICATE-----...)'
invalidPem: Invalid PEM certificate
validity: Validity
status: Status
valid: Valid
expired: Expired
expiredAgo: '(expired {days} days ago)'
daysRemaining: '({days} days remaining)'
validFrom: Valid From
validTo: Valid To
subject: Subject
san: Subject Alternative Names (SAN)
issuer: Issuer
details: Details
version: Version
serialNumber: Serial Number
signatureAlgorithm: Signature Algorithm
publicKey: Public Key
fingerprint: Public Key Fingerprint (SHA-256)
keyUsage: Key Usage
basicConstraints: Basic Constraints
help:
title: How to get a PEM certificate?
section1Title: 1. Export from a website
section1Desc: 'This outputs content from -----BEGIN CERTIFICATE----- to -----END CERTIFICATE-----, which is the PEM certificate.'
section2Title: 2. Export from browser
section2Step1: 'Chrome/Edge: Click the lock icon in the address bar → Connection is secure → Certificate is valid → Details → Export'
section2Step2: Choose Base-64 encoded (.pem/.crt) format when exporting
section3Title: 3. From server files
section3Nginx: 'Nginx: Check the file pointed to by ssl_certificate (usually .pem or .crt)'
section3Apache: 'Apache: Check SSLCertificateFile'
section3Paths: 'Common paths: /etc/ssl/certs/, /etc/letsencrypt/live/<domain>/fullchain.pem'
section4Title: 4. PEM format example
Loading
Loading