From c31a128d7abec590e0624faaa3944b12bf1a670d Mon Sep 17 00:00:00 2001 From: rusconn Date: Wed, 30 Mar 2022 11:27:43 +0900 Subject: [PATCH] feat: add url encoder / decoder --- .../pages/encoders-decoders/url/Content.tsx | 55 +++++++++++++++++++ .../pages/encoders-decoders/url/index.ts | 3 + src/data/tools.tsx | 4 +- src/libs/$path.ts | 6 ++ src/pages/encoders-decoders/url.tsx | 7 +++ 5 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 src/components/pages/encoders-decoders/url/Content.tsx create mode 100644 src/components/pages/encoders-decoders/url/index.ts create mode 100644 src/pages/encoders-decoders/url.tsx diff --git a/src/components/pages/encoders-decoders/url/Content.tsx b/src/components/pages/encoders-decoders/url/Content.tsx new file mode 100644 index 0000000..20c2403 --- /dev/null +++ b/src/components/pages/encoders-decoders/url/Content.tsx @@ -0,0 +1,55 @@ +import { ComponentPropsWithoutRef, memo, useCallback, useState } from "react"; + +import { Main, MainItem, TextField } from "@/components/common"; + +type TextFieldValue = ComponentPropsWithoutRef["value"]; +type OnTextFieldChange = NonNullable["onChange"]>; + +type Props = { + decoded: TextFieldValue; + encoded: TextFieldValue; + onDecodedChange: OnTextFieldChange; + onEncodedChange: OnTextFieldChange; +}; + +const StyledComponent = ({ decoded, encoded, onDecodedChange, onEncodedChange }: Props) => ( +
+ + + + + + +
+); + +export const Component = memo(StyledComponent); + +const Container = () => { + const [decoded, setDecoded] = useState("http://example.com?q=foo bar"); + const [encoded, setEncoded] = useState("http://example.com?q=foo%20bar"); + + const onDecodedChange: Props["onDecodedChange"] = useCallback(({ currentTarget: { value } }) => { + setDecoded(value); + + try { + setEncoded(encodeURI(value)); + } catch { + setEncoded(""); + } + }, []); + + const onEncodedChange: Props["onEncodedChange"] = useCallback(({ currentTarget: { value } }) => { + setEncoded(value); + + try { + setDecoded(decodeURI(value)); + } catch { + setDecoded(""); + } + }, []); + + return ; +}; + +export default Container; diff --git a/src/components/pages/encoders-decoders/url/index.ts b/src/components/pages/encoders-decoders/url/index.ts new file mode 100644 index 0000000..ae1b8af --- /dev/null +++ b/src/components/pages/encoders-decoders/url/index.ts @@ -0,0 +1,3 @@ +import Content from "./Content"; + +export { Content }; diff --git a/src/data/tools.tsx b/src/data/tools.tsx index 7c08a17..239e4eb 100644 --- a/src/data/tools.tsx +++ b/src/data/tools.tsx @@ -64,8 +64,8 @@ const toolGroups = [ description: "Encode or decode all the applicable characters to their corresponding URL entities", keywords: "url encoder escaper decocder unescaper", - href: pagesPath.$url(), - disabled: true, + href: pagesPath.encoders_decoders.url.$url(), + disabled: false, }, { icon: , diff --git a/src/libs/$path.ts b/src/libs/$path.ts index 2bbcc86..8fe4fff 100644 --- a/src/libs/$path.ts +++ b/src/libs/$path.ts @@ -20,6 +20,12 @@ export const pagesPath = { hash: url?.hash, }), }, + url: { + $url: (url?: { hash?: string }) => ({ + pathname: "/encoders-decoders/url" as const, + hash: url?.hash, + }), + }, }, search: { $url: (url?: { hash?: string }) => ({ pathname: "/search" as const, hash: url?.hash }), diff --git a/src/pages/encoders-decoders/url.tsx b/src/pages/encoders-decoders/url.tsx new file mode 100644 index 0000000..9d92c24 --- /dev/null +++ b/src/pages/encoders-decoders/url.tsx @@ -0,0 +1,7 @@ +import type { NextPage } from "next"; + +import { Content } from "@/components/pages/encoders-decoders/url"; + +const Page: NextPage = Content; + +export default Page;