From 94fdcaef0d34761917e387e62573f62e2c9d1834 Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Fri, 18 Jul 2025 17:25:45 +0200 Subject: [PATCH] feat (string): url decode --- src/pages/tools/string/url-decode/index.tsx | 69 ++++++++++++++++++++ src/pages/tools/string/url-decode/meta.ts | 16 +++++ src/pages/tools/string/url-decode/service.ts | 20 ++++++ 3 files changed, 105 insertions(+) create mode 100644 src/pages/tools/string/url-decode/index.tsx create mode 100644 src/pages/tools/string/url-decode/meta.ts create mode 100644 src/pages/tools/string/url-decode/service.ts diff --git a/src/pages/tools/string/url-decode/index.tsx b/src/pages/tools/string/url-decode/index.tsx new file mode 100644 index 0000000..49d4a29 --- /dev/null +++ b/src/pages/tools/string/url-decode/index.tsx @@ -0,0 +1,69 @@ +import { useState } from 'react'; +import ToolTextResult from '@components/result/ToolTextResult'; +import { decodeString } from './service'; +import ToolTextInput from '@components/input/ToolTextInput'; +import ToolContent from '@components/ToolContent'; +import { CardExampleType } from '@components/examples/ToolExamples'; +import { ToolComponentProps } from '@tools/defineTool'; +import { useTranslation } from 'react-i18next'; + +const initialValues = {}; + +const exampleCards: CardExampleType[] = [ + { + title: 'Decode an actual URL', + description: + 'This example decodes a URL-encoded string back to its readable URL form.', + sampleText: 'https%3A%2F%2Fomnitools.app%2F', + sampleResult: 'https://omnitools.app/', + sampleOptions: initialValues + }, + { + title: 'Decode All Characters', + description: + 'This example decodes a string where every character has been URL-encoded, restoring the original readable text.', + sampleText: + '%49%20%63%61%6E%27%74%20%62%65%6C%69%65%76%65%20%69%74%27%73%20%6E%6F%74%20%62%75%74%74%65%72%21', + sampleResult: "I can't believe it's not butter!", + sampleOptions: initialValues + } +]; + +export default function DecodeString({ + title, + longDescription +}: ToolComponentProps) { + const { t } = useTranslation('string'); + const [input, setInput] = useState(''); + const [result, setResult] = useState(''); + + function compute(_initialValues: typeof initialValues, input: string) { + setResult(decodeString(input)); + } + + return ( + + } + resultComponent={ + + } + toolInfo={{ + title: t('urlDecode.toolInfo.title', { title }), + description: longDescription + }} + exampleCards={exampleCards} + /> + ); +} diff --git a/src/pages/tools/string/url-decode/meta.ts b/src/pages/tools/string/url-decode/meta.ts new file mode 100644 index 0000000..986a396 --- /dev/null +++ b/src/pages/tools/string/url-decode/meta.ts @@ -0,0 +1,16 @@ +import { defineTool } from '@tools/defineTool'; +import { lazy } from 'react'; + +export const tool = defineTool('string', { + path: 'url-decode-string', + icon: 'codicon:symbol-string', + + keywords: ['uppercase'], + component: lazy(() => import('./index')), + i18n: { + name: 'string:urlDecode.toolInfo.title', + description: 'string:urlDecode.toolInfo.description', + shortDescription: 'string:urlDecode.toolInfo.shortDescription', + longDescription: 'string:urlDecode.toolInfo.longDescription' + } +}); diff --git a/src/pages/tools/string/url-decode/service.ts b/src/pages/tools/string/url-decode/service.ts new file mode 100644 index 0000000..5a5b622 --- /dev/null +++ b/src/pages/tools/string/url-decode/service.ts @@ -0,0 +1,20 @@ +export function decodeString(input: string): string { + if (!input) return ''; + + let result = ''; + let i = 0; + + while (i < input.length) { + if (input[i] === '%' && i + 2 < input.length) { + const hex = input.substring(i + 1, i + 3); + const code = parseInt(hex, 16); + result += String.fromCodePoint(code); + i += 3; + } else { + result += input[i]; + i++; + } + } + + return result; +}