diff --git a/app/converters/json-yaml/page.tsx b/app/converters/json-yaml/page.tsx
index 0e58ccd..b4ba77b 100644
--- a/app/converters/json-yaml/page.tsx
+++ b/app/converters/json-yaml/page.tsx
@@ -7,18 +7,8 @@ import { toolGroups } from "@/config/tools";
import { safeJsonParse } from "@/lib/json";
import { safeYamlParse } from "@/lib/yaml";
import { Editor, EditorProps } from "@/components/ui/editor";
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectProps,
- SelectTrigger,
- SelectValue,
-} from "@/components/ui/select";
-import { ClearButton } from "@/components/buttons/clear";
-import { CopyButton } from "@/components/buttons/copy";
-import { FileButton } from "@/components/buttons/file";
-import { PasteButton } from "@/components/buttons/paste";
+import * as Select from "@/components/ui/select";
+import * as Button from "@/components/buttons";
import { Configuration } from "@/components/configuration";
import { Configurations } from "@/components/configurations";
import { ControlMenu } from "@/components/control-menu";
@@ -38,41 +28,44 @@ export default function Page() {
yaml: "foo: bar",
});
- const setJsonReactively = useCallback((text: string) => {
- const parsed = safeJsonParse(text);
-
+ const setFormByJson = useCallback((text: string) => {
setForm(prev => ({
...prev,
json: text,
- yaml: parsed.isErr()
- ? ""
- : yaml.dump(parsed.value, { indent: prev.indentation.length, quotingType: '"' }),
+ yaml: safeJsonParse(text)
+ .map(x => yaml.dump(x, { indent: prev.indentation.length, quotingType: '"' }))
+ .unwrapOr(""),
}));
}, []);
- const setYamlReactively = useCallback((text: string) => {
- const parsed = safeYamlParse(text);
-
+ const setFormByYaml = useCallback((text: string) => {
setForm(prev => ({
...prev,
+ json: safeYamlParse(text)
+ .map(x => JSON.stringify(x, null, prev.indentation))
+ .unwrapOr(""),
yaml: text,
- json: parsed.isErr() ? "" : JSON.stringify(parsed.value, null, prev.indentation),
}));
}, []);
const clearBoth = useCallback(() => {
- setForm(prev => ({ ...prev, json: "", yaml: "" }));
+ setForm(prev => ({
+ ...prev,
+ json: "",
+ yaml: "",
+ }));
}, []);
- const onIndentationChange: SelectProps["onValueChange"] = value => {
- const parsed = safeJsonParse(form.json);
-
- const jsonYaml = parsed.isErr()
- ? { json: "", yaml: "" }
- : {
- json: JSON.stringify(parsed.value, null, value),
- yaml: yaml.dump(parsed.value, { indent: value.length, quotingType: '"' }),
- };
+ const onIndentationChange: Select.Props["onValueChange"] = value => {
+ const jsonYaml = safeJsonParse(form.json)
+ .map(x => ({
+ json: JSON.stringify(x, null, value),
+ yaml: yaml.dump(x, { indent: value.length, quotingType: '"' }),
+ }))
+ .unwrapOr({
+ json: "",
+ yaml: "",
+ });
setForm({
indentation: value,
@@ -80,59 +73,55 @@ export default function Page() {
});
};
- const onJsonChange: EditorProps["onChange"] = value => setJsonReactively(value ?? "");
- const onYamlChange: EditorProps["onChange"] = value => setYamlReactively(value ?? "");
+ const onJsonChange: EditorProps["onChange"] = value => setFormByJson(value ?? "");
+ const onYamlChange: EditorProps["onChange"] = value => setFormByYaml(value ?? "");
const indentationConfig = (
}
title="Indentation"
control={
-
+
+
+
+ 2 spaces
+ 4 spaces
+
+
}
/>
);
- const jsonPasteButton = ;
- const yamlPasteButton = ;
+ const jsonPasteButton = ;
+ const yamlPasteButton = ;
const jsonFileButton = (
-
+
);
const yamlFileButton = (
-
);
- const jsonCopyButton = ;
- const yamlCopyButton = ;
+ const jsonCopyButton = ;
+ const yamlCopyButton = ;
- const clearButton = ;
+ const clearButton = (
+
+ );
const jsonControl = (
);
-
const yamlControl = (
);
diff --git a/app/converters/number-base/page.tsx b/app/converters/number-base/page.tsx
index b2df0c9..04be9a9 100644
--- a/app/converters/number-base/page.tsx
+++ b/app/converters/number-base/page.tsx
@@ -5,7 +5,7 @@ import { useCallback, useState } from "react";
import { toolGroups } from "@/config/tools";
import * as baselib from "@/lib/base";
import { Input, InputProps } from "@/components/ui/input";
-import { PasteButton } from "@/components/buttons/paste";
+import * as Button from "@/components/buttons";
import { Configuration } from "@/components/configuration";
import { Configurations } from "@/components/configurations";
import { ControlMenu } from "@/components/control-menu";
@@ -53,10 +53,10 @@ export default function Page() {
const trySetOct = useCallback((value: string) => trySetInt(8)(value), []);
const trySetBin = useCallback((value: string) => trySetInt(2)(value), []);
- const onDecChange: InputProps["onChange"] = ({ currentTarget: { value } }) => trySetDec(value);
- const onHexChange: InputProps["onChange"] = ({ currentTarget: { value } }) => trySetHex(value);
- const onOctChange: InputProps["onChange"] = ({ currentTarget: { value } }) => trySetOct(value);
- const onBinChange: InputProps["onChange"] = ({ currentTarget: { value } }) => trySetBin(value);
+ const onDecChange: InputProps["onChange"] = e => trySetDec(e.currentTarget.value);
+ const onHexChange: InputProps["onChange"] = e => trySetHex(e.currentTarget.value);
+ const onOctChange: InputProps["onChange"] = e => trySetOct(e.currentTarget.value);
+ const onBinChange: InputProps["onChange"] = e => trySetBin(e.currentTarget.value);
const formatNumberConfig = (
);
- const decPasteButton = ;
- const hexPasteButton = ;
- const octPasteButton = ;
- const binPasteButton = ;
+ const decPasteButton = ;
+ const hexPasteButton = ;
+ const octPasteButton = ;
+ const binPasteButton = ;
const decControl = ;
const hexControl = ;
diff --git a/app/encoders-decoders/base64/page.tsx b/app/encoders-decoders/base64/page.tsx
index 29db4fa..04d3376 100644
--- a/app/encoders-decoders/base64/page.tsx
+++ b/app/encoders-decoders/base64/page.tsx
@@ -5,10 +5,7 @@ import { decode, encode, isValid } from "js-base64";
import { toolGroups } from "@/config/tools";
import { Textarea, TextareaProps } from "@/components/ui/textarea";
-import { ClearButton } from "@/components/buttons/clear";
-import { CopyButton } from "@/components/buttons/copy";
-import { FileButton } from "@/components/buttons/file";
-import { PasteButton } from "@/components/buttons/paste";
+import * as Button from "@/components/buttons";
import { ControlMenu } from "@/components/control-menu";
import { PageRootSection } from "@/components/page-root-section";
import { PageSection } from "@/components/page-section";
@@ -19,19 +16,19 @@ export default function Page() {
encoded: "8J+YgPCfmILwn6Sj",
});
- const setDecodedReactively = useCallback((text: string) => {
+ const setFormByDecoded = useCallback((text: string) => {
setForm({
decoded: text,
encoded: encode(text),
});
}, []);
- const setEncodedReactively = useCallback((text: string) => {
+ const setFormByEncoded = useCallback((text: string) => {
const newDecoded = decode(text);
setForm({
- encoded: text,
decoded: isValid(text) && !newDecoded.includes("�") ? newDecoded : "",
+ encoded: text,
});
}, []);
@@ -42,33 +39,29 @@ export default function Page() {
});
}, []);
- const onDecodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
- setDecodedReactively(value);
+ const onDecodedChange: TextareaProps["onChange"] = e => setFormByDecoded(e.currentTarget.value);
+ const onEncodedChange: TextareaProps["onChange"] = e => setFormByEncoded(e.currentTarget.value);
- const onEncodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
- setEncodedReactively(value);
-
- const decodedPasteButton = ;
- const encodedPasteButton = ;
+ const decodedPasteButton = ;
+ const encodedPasteButton = ;
const decodedFileButton = (
-
+
);
const encodedFileButton = (
-
+
);
- const decodedCopyButton = ;
- const encodedCopyButton = ;
+ const decodedCopyButton = ;
+ const encodedCopyButton = ;
const clearButton = (
-
+
);
const decodedControl = (
);
-
const encodedControl = (
);
diff --git a/app/encoders-decoders/html/page.tsx b/app/encoders-decoders/html/page.tsx
index 977709f..c4defff 100644
--- a/app/encoders-decoders/html/page.tsx
+++ b/app/encoders-decoders/html/page.tsx
@@ -5,10 +5,7 @@ import { escape, unescape } from "html-escaper";
import { toolGroups } from "@/config/tools";
import { Textarea, TextareaProps } from "@/components/ui/textarea";
-import { ClearButton } from "@/components/buttons/clear";
-import { CopyButton } from "@/components/buttons/copy";
-import { FileButton } from "@/components/buttons/file";
-import { PasteButton } from "@/components/buttons/paste";
+import * as Button from "@/components/buttons";
import { ControlMenu } from "@/components/control-menu";
import { PageRootSection } from "@/components/page-root-section";
import { PageSection } from "@/components/page-section";
@@ -19,17 +16,17 @@ export default function Page() {
encoded: "> It's "HTML escaping".",
});
- const setDecodedReactively = useCallback((text: string) => {
+ const setFormByDecoded = useCallback((text: string) => {
setForm({
decoded: text,
encoded: escape(text),
});
}, []);
- const setEncodedReactively = useCallback((text: string) => {
+ const setFormByEncoded = useCallback((text: string) => {
setForm({
- encoded: text,
decoded: unescape(text),
+ encoded: text,
});
}, []);
@@ -40,33 +37,29 @@ export default function Page() {
});
}, []);
- const onDecodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
- setDecodedReactively(value);
+ const onDecodedChange: TextareaProps["onChange"] = e => setFormByDecoded(e.currentTarget.value);
+ const onEncodedChange: TextareaProps["onChange"] = e => setFormByEncoded(e.currentTarget.value);
- const onEncodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
- setEncodedReactively(value);
-
- const decodedPasteButton = ;
- const encodedPasteButton = ;
+ const decodedPasteButton = ;
+ const encodedPasteButton = ;
const decodedFileButton = (
-
+
);
const encodedFileButton = (
-
+
);
- const decodedCopyButton = ;
- const encodedCopyButton = ;
+ const decodedCopyButton = ;
+ const encodedCopyButton = ;
const clearButton = (
-
+
);
const decodedControl = (
);
-
const encodedControl = (
);
diff --git a/app/encoders-decoders/jwt/page.tsx b/app/encoders-decoders/jwt/page.tsx
index cd88d42..014aba9 100644
--- a/app/encoders-decoders/jwt/page.tsx
+++ b/app/encoders-decoders/jwt/page.tsx
@@ -6,10 +6,7 @@ import { toolGroups } from "@/config/tools";
import { decode } from "@/lib/jwt";
import { Editor } from "@/components/ui/editor";
import { Textarea, TextareaProps } from "@/components/ui/textarea";
-import { ClearButton } from "@/components/buttons/clear";
-import { CopyButton } from "@/components/buttons/copy";
-import { FileButton } from "@/components/buttons/file";
-import { PasteButton } from "@/components/buttons/paste";
+import * as Button from "@/components/buttons";
import { ControlMenu } from "@/components/control-menu";
import { PageRootSection } from "@/components/page-root-section";
import { PageSection } from "@/components/page-section";
@@ -20,23 +17,23 @@ export default function Page() {
);
const { header: h, payload: p } = decode(jwt);
- const header = h.isErr() ? "" : JSON.stringify(h.value, null, 2);
- const payload = p.isErr() ? "" : JSON.stringify(p.value, null, 2);
+ const header = h.map(x => JSON.stringify(x, null, 2)).unwrapOr("");
+ const payload = p.map(x => JSON.stringify(x, null, 2)).unwrapOr("");
const clearJwt = useCallback(() => setJwt(""), []);
- const onJwtChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) => setJwt(value);
+ const onJwtChange: TextareaProps["onChange"] = e => setJwt(e.currentTarget.value);
- const jwtTokenPasteButton = ;
+ const jwtTokenPasteButton = ;
const jwtTokenFileButton = (
-
+
);
- const jwtTokenClearButton = ;
+ const jwtTokenClearButton = ;
- const heaederCopyButton = ;
- const payloadCopyButton = ;
+ const heaederCopyButton = ;
+ const payloadCopyButton = ;
const jwtTokenControl = (
diff --git a/app/encoders-decoders/url/page.tsx b/app/encoders-decoders/url/page.tsx
index 6fa8ca0..1fb2c38 100644
--- a/app/encoders-decoders/url/page.tsx
+++ b/app/encoders-decoders/url/page.tsx
@@ -5,10 +5,7 @@ import { useCallback, useState } from "react";
import { toolGroups } from "@/config/tools";
import { safeDecodeURIComponent, safeEncodeURIComponent } from "@/lib/uri";
import { Textarea, TextareaProps } from "@/components/ui/textarea";
-import { ClearButton } from "@/components/buttons/clear";
-import { CopyButton } from "@/components/buttons/copy";
-import { FileButton } from "@/components/buttons/file";
-import { PasteButton } from "@/components/buttons/paste";
+import * as Button from "@/components/buttons";
import { ControlMenu } from "@/components/control-menu";
import { PageRootSection } from "@/components/page-root-section";
import { PageSection } from "@/components/page-section";
@@ -19,17 +16,17 @@ export default function Page() {
encoded: "%3E%20It's%20%22URL%20encoding%22%3F",
});
- const setDecodedReactively = useCallback((text: string) => {
+ const setFormByDecoded = useCallback((text: string) => {
setForm({
decoded: text,
encoded: safeEncodeURIComponent(text).unwrapOr(""),
});
}, []);
- const setEncodedReactively = useCallback((text: string) => {
+ const setFormByEncoded = useCallback((text: string) => {
setForm({
- encoded: text,
decoded: safeDecodeURIComponent(text).unwrapOr(""),
+ encoded: text,
});
}, []);
@@ -40,33 +37,29 @@ export default function Page() {
});
}, []);
- const onDecodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
- setDecodedReactively(value);
+ const onDecodedChange: TextareaProps["onChange"] = e => setFormByDecoded(e.currentTarget.value);
+ const onEncodedChange: TextareaProps["onChange"] = e => setFormByEncoded(e.currentTarget.value);
- const onEncodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
- setEncodedReactively(value);
-
- const decodedPasteButton = ;
- const encodedPasteButton = ;
+ const decodedPasteButton = ;
+ const encodedPasteButton = ;
const decodedFileButton = (
-
+
);
const encodedFileButton = (
-
+
);
- const decodedCopyButton = ;
- const encodedCopyButton = ;
+ const decodedCopyButton = ;
+ const encodedCopyButton = ;
const clearButton = (
-
+
);
const decodedControl = (
);
-
const encodedControl = (
);
diff --git a/app/formatters/json/page.tsx b/app/formatters/json/page.tsx
index 5d39291..e4d0d99 100644
--- a/app/formatters/json/page.tsx
+++ b/app/formatters/json/page.tsx
@@ -5,17 +5,8 @@ import { useCallback, useState } from "react";
import { toolGroups } from "@/config/tools";
import { safeJsonParse } from "@/lib/json";
import { Editor, EditorProps } from "@/components/ui/editor";
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "@/components/ui/select";
-import { ClearButton } from "@/components/buttons/clear";
-import { CopyButton } from "@/components/buttons/copy";
-import { FileButton } from "@/components/buttons/file";
-import { PasteButton } from "@/components/buttons/paste";
+import * as Select from "@/components/ui/select";
+import * as Button from "@/components/buttons";
import { Configuration } from "@/components/configuration";
import { Configurations } from "@/components/configurations";
import { ControlMenu } from "@/components/control-menu";
@@ -35,7 +26,7 @@ export default function Page() {
const [input, setInput] = useState('{\n"foo":"bar"\n}');
const parsed = safeJsonParse(input);
- const output = parsed.isErr() ? "" : JSON.stringify(parsed.value, null, indentation);
+ const output = parsed.map(x => JSON.stringify(x, null, indentation)).unwrapOr("");
const clearInput = useCallback(() => setInput(""), []);
@@ -46,33 +37,33 @@ export default function Page() {
icon={}
title="Indentation"
control={
-
+
+
+
+ 2 spaces
+ 4 spaces
+ 1 tab
+ minified
+
+
}
/>
);
- const inputPasteButton = ;
+ const inputPasteButton = ;
const inputFileButton = (
-
+
);
- const inputClearButton = ;
+ const inputClearButton = ;
- const outputCopyButton = ;
+ const outputCopyButton = ;
const inputControl = ;
const outputControl = ;
diff --git a/app/generators/hash/page.tsx b/app/generators/hash/page.tsx
index ce2ce47..44bd38b 100644
--- a/app/generators/hash/page.tsx
+++ b/app/generators/hash/page.tsx
@@ -6,10 +6,7 @@ import createHash from "create-hash";
import { toolGroups } from "@/config/tools";
import { Input } from "@/components/ui/input";
import { Textarea, TextareaProps } from "@/components/ui/textarea";
-import { ClearButton } from "@/components/buttons/clear";
-import { CopyButton } from "@/components/buttons/copy";
-import { FileButton } from "@/components/buttons/file";
-import { PasteButton } from "@/components/buttons/paste";
+import * as Button from "@/components/buttons";
import { Configuration } from "@/components/configuration";
import { Configurations } from "@/components/configurations";
import { ControlMenu } from "@/components/control-menu";
@@ -34,8 +31,7 @@ export default function Page() {
const clearInput = useCallback(() => setInput(""), []);
- const onInputChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
- setInput(value);
+ const onInputChange: TextareaProps["onChange"] = e => setInput(e.currentTarget.value);
const uppercaseConfig = (
);
- const inputPasteButton = ;
- const inputFileButton = ;
- const inputClearButton = ;
+ const inputPasteButton = ;
+ const inputFileButton = ;
+ const inputClearButton = ;
const inputControl = ;
- const md5CopyButton = ;
- const sha1CopyButton = ;
- const sha256CopyButton = ;
- const sha512CopyButton = ;
+ const md5CopyButton = ;
+ const sha1CopyButton = ;
+ const sha256CopyButton = (
+
+ );
+ const sha512CopyButton = (
+
+ );
return (
diff --git a/app/generators/uuid/page.tsx b/app/generators/uuid/page.tsx
index a725a02..cec2c1a 100644
--- a/app/generators/uuid/page.tsx
+++ b/app/generators/uuid/page.tsx
@@ -9,17 +9,10 @@ import { uuid } from "@/lib/uuid";
import { useScrollFollow } from "@/hooks/useScrollFollow";
import { Button } from "@/components/ui/button";
import { Input, InputProps } from "@/components/ui/input";
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectProps,
- SelectTrigger,
- SelectValue,
-} from "@/components/ui/select";
+import * as Select from "@/components/ui/select";
import { Textarea } from "@/components/ui/textarea";
-import { ClearButton } from "@/components/buttons/clear";
-import { CopyButton } from "@/components/buttons/copy";
+import { Clear } from "@/components/buttons/clear";
+import { Copy } from "@/components/buttons/copy";
import { Configuration } from "@/components/configuration";
import { Configurations } from "@/components/configurations";
import { ControlMenu } from "@/components/control-menu";
@@ -48,22 +41,19 @@ export default function Page() {
const clearUuids = useCallback(() => setUuids([]), []);
- const onUuidVersionChange: NonNullable = useCallback(value => {
+ const onUuidVersionChange: NonNullable = useCallback(value => {
if (uuidVersions.is(value)) {
setUuidVersion(value);
}
}, []);
- const onGeneratesChange: NonNullable = useCallback(
- ({ currentTarget: { value } }) => {
- const newGenerates = Number(value);
+ const onGeneratesChange: NonNullable = useCallback(e => {
+ const newGenerates = Number(e.currentTarget.value);
- if (newGenerates >= 1 && newGenerates <= 1000) {
- setGenerates(newGenerates);
- }
- },
- []
- );
+ if (newGenerates >= 1 && newGenerates <= 1000) {
+ setGenerates(newGenerates);
+ }
+ }, []);
const onGenerateClick = () => {
const newUuids = range(1, generates).map(_ => uuid(uuidVersion, hyphens, uppercase));
@@ -108,24 +98,24 @@ export default function Page() {
title="UUID version"
description="Choose the version of UUID to generate"
control={
-
+
+
+
+ 1
+ 4 (GUID)
+
+
}
/>
);
- const uuidsCopyButton = ;
- const uuidsClearButton = ;
+ const uuidsCopyButton = ;
+ const uuidsClearButton = ;
const uuidsControl = ;
diff --git a/app/settings/page.tsx b/app/settings/page.tsx
index a9d3d77..71afcf0 100644
--- a/app/settings/page.tsx
+++ b/app/settings/page.tsx
@@ -3,13 +3,7 @@
import { useTheme } from "next-themes";
import { singleTools } from "@/config/tools";
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "@/components/ui/select";
+import * as Select from "@/components/ui/select";
import { Configuration } from "@/components/configuration";
import { Configurations } from "@/components/configurations";
import { icons } from "@/components/icons";
@@ -25,19 +19,19 @@ export default function Page() {
title="App theme"
description="Select which app theme to display"
control={
-
+
+
+
+ Light
+ Dark
+ System
+
+
}
/>
);
diff --git a/components/buttons/base.tsx b/components/buttons/base.tsx
index fdfec9e..a1fb85d 100644
--- a/components/buttons/base.tsx
+++ b/components/buttons/base.tsx
@@ -1,13 +1,13 @@
import { Button, ButtonProps } from "@/components/ui/button";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
-export type BaseButtonProps = ButtonProps & {
+export type BaseProps = ButtonProps & {
icon: React.ReactNode;
iconOnly?: true;
labelText: string;
};
-export function BaseButton({ icon, iconOnly, labelText, ...props }: BaseButtonProps) {
+export function Base({ icon, iconOnly, labelText, ...props }: BaseProps) {
const button = (