mirror of
https://github.com/ershisan99/DevToysWeb.git
synced 2025-12-16 20:49:23 +00:00
refactor: make some states grouped
This commit is contained in:
@@ -31,50 +31,52 @@ const two = " ";
|
|||||||
const four = " ";
|
const four = " ";
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const [indentation, setIndentation] = useState(two);
|
const [form, setForm] = useState({
|
||||||
const [json, setJson] = useState('{\n "foo": "bar"\n}');
|
indentation: two,
|
||||||
const [yaml, setYaml] = useState("foo: bar");
|
json: '{\n "foo": "bar"\n}',
|
||||||
|
yaml: "foo: bar",
|
||||||
|
});
|
||||||
|
|
||||||
const setJsonReactively = useCallback(
|
const setJsonReactively = useCallback((text: string) => {
|
||||||
(text: string) => {
|
const parsed = safeJsonParse(text);
|
||||||
const parsed = safeJsonParse(text);
|
|
||||||
|
|
||||||
setJson(text);
|
setForm(prev => ({
|
||||||
setYaml(
|
...prev,
|
||||||
O.isNone(parsed)
|
json: text,
|
||||||
? ""
|
yaml: O.isNone(parsed)
|
||||||
: YAML.stringify(parsed.value, { indent: indentation.length, simpleKeys: true })
|
? ""
|
||||||
);
|
: YAML.stringify(parsed.value, { indent: prev.indentation.length, simpleKeys: true }),
|
||||||
},
|
}));
|
||||||
[indentation.length]
|
}, []);
|
||||||
);
|
|
||||||
|
|
||||||
const setYamlReactively = useCallback(
|
const setYamlReactively = useCallback((text: string) => {
|
||||||
(text: string) => {
|
const parsed = safeYamlParse(text, (_, v) => v, { merge: true });
|
||||||
const parsed = safeYamlParse(text, (_, v) => v, { merge: true });
|
|
||||||
|
|
||||||
setYaml(text);
|
setForm(prev => ({
|
||||||
setJson(O.isNone(parsed) ? "" : JSON.stringify(parsed.value, null, indentation));
|
...prev,
|
||||||
},
|
yaml: text,
|
||||||
[indentation]
|
json: O.isNone(parsed) ? "" : JSON.stringify(parsed.value, null, prev.indentation),
|
||||||
);
|
}));
|
||||||
|
}, []);
|
||||||
|
|
||||||
const clearBoth = useCallback(() => {
|
const clearBoth = useCallback(() => {
|
||||||
setJson("");
|
setForm(prev => ({ ...prev, json: "", yaml: "" }));
|
||||||
setYaml("");
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onIndentationChange: SelectProps["onValueChange"] = value => {
|
const onIndentationChange: SelectProps["onValueChange"] = value => {
|
||||||
setIndentation(value);
|
const parsed = safeJsonParse(form.json);
|
||||||
|
|
||||||
const parsed = safeJsonParse(json);
|
const jsonYaml = O.isNone(parsed)
|
||||||
|
? { json: "", yaml: "" }
|
||||||
|
: {
|
||||||
|
json: JSON.stringify(parsed.value, null, value),
|
||||||
|
yaml: YAML.stringify(parsed.value, { indent: value.length, simpleKeys: true }),
|
||||||
|
};
|
||||||
|
|
||||||
if (O.isNone(parsed)) {
|
setForm({
|
||||||
clearBoth();
|
indentation: value,
|
||||||
} else {
|
...jsonYaml,
|
||||||
setJson(JSON.stringify(parsed.value, null, value));
|
});
|
||||||
setYaml(YAML.stringify(parsed.value, { indent: value.length, simpleKeys: true }));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onJsonChange: EditorProps["onChange"] = value => setJsonReactively(value ?? "");
|
const onJsonChange: EditorProps["onChange"] = value => setJsonReactively(value ?? "");
|
||||||
@@ -87,12 +89,12 @@ export default function Page() {
|
|||||||
icon={indentationIcon}
|
icon={indentationIcon}
|
||||||
title="Indentation"
|
title="Indentation"
|
||||||
control={
|
control={
|
||||||
<Select value={indentation} onValueChange={onIndentationChange}>
|
<Select value={form.indentation} onValueChange={onIndentationChange}>
|
||||||
<SelectTrigger
|
<SelectTrigger
|
||||||
className="w-28"
|
className="w-28"
|
||||||
aria-label="toggle open/close state of indentation selection"
|
aria-label="toggle open/close state of indentation selection"
|
||||||
>
|
>
|
||||||
<SelectValue placeholder={indentation} />
|
<SelectValue placeholder={form.indentation} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value={two}>2 spaces</SelectItem>
|
<SelectItem value={two}>2 spaces</SelectItem>
|
||||||
@@ -137,8 +139,8 @@ export default function Page() {
|
|||||||
[setYamlReactively]
|
[setYamlReactively]
|
||||||
);
|
);
|
||||||
|
|
||||||
const jsonCopyButton = <CopyButton text={json} />;
|
const jsonCopyButton = <CopyButton text={form.json} />;
|
||||||
const yamlCopyButton = <CopyButton text={yaml} />;
|
const yamlCopyButton = <CopyButton text={form.yaml} />;
|
||||||
|
|
||||||
const clearButton = useMemo(
|
const clearButton = useMemo(
|
||||||
() => <ClearButton onClick={clearBoth} iconOnly aria-label="clear json and yaml" />,
|
() => <ClearButton onClick={clearBoth} iconOnly aria-label="clear json and yaml" />,
|
||||||
@@ -163,10 +165,10 @@ export default function Page() {
|
|||||||
</PageSection>
|
</PageSection>
|
||||||
<div className="flex flex-1 flex-col gap-x-4 gap-y-5 lg:flex-row">
|
<div className="flex flex-1 flex-col gap-x-4 gap-y-5 lg:flex-row">
|
||||||
<PageSection className="mt-0 min-h-[200px] flex-1" title="Json" control={jsonControl}>
|
<PageSection className="mt-0 min-h-[200px] flex-1" title="Json" control={jsonControl}>
|
||||||
<Editor language="json" value={json} onChange={onJsonChange} />
|
<Editor language="json" value={form.json} onChange={onJsonChange} />
|
||||||
</PageSection>
|
</PageSection>
|
||||||
<PageSection className="mt-0 min-h-[200px] flex-1" title="Yaml" control={yamlControl}>
|
<PageSection className="mt-0 min-h-[200px] flex-1" title="Yaml" control={yamlControl}>
|
||||||
<Editor language="yaml" value={yaml} onChange={onYamlChange} />
|
<Editor language="yaml" value={form.yaml} onChange={onYamlChange} />
|
||||||
</PageSection>
|
</PageSection>
|
||||||
</div>
|
</div>
|
||||||
</PageRootSection>
|
</PageRootSection>
|
||||||
|
|||||||
@@ -14,29 +14,32 @@ import { PageRootSection } from "@/components/page-root-section";
|
|||||||
import { PageSection } from "@/components/page-section";
|
import { PageSection } from "@/components/page-section";
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const [decoded, setDecoded] = useState("😀😂🤣");
|
const [form, setForm] = useState({
|
||||||
const [encoded, setEncoded] = useState("8J+YgPCfmILwn6Sj");
|
decoded: "😀😂🤣",
|
||||||
|
encoded: "8J+YgPCfmILwn6Sj",
|
||||||
|
});
|
||||||
|
|
||||||
const setDecodedReactively = useCallback((text: string) => {
|
const setDecodedReactively = useCallback((text: string) => {
|
||||||
setDecoded(text);
|
setForm({
|
||||||
setEncoded(encode(text));
|
decoded: text,
|
||||||
|
encoded: encode(text),
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const setEncodedReactively = useCallback((text: string) => {
|
const setEncodedReactively = useCallback((text: string) => {
|
||||||
setEncoded(text);
|
|
||||||
|
|
||||||
const newDecoded = decode(text);
|
const newDecoded = decode(text);
|
||||||
|
|
||||||
if (isValid(text) && !newDecoded.includes("<22>")) {
|
setForm({
|
||||||
setDecoded(newDecoded);
|
encoded: text,
|
||||||
} else {
|
decoded: isValid(text) && !newDecoded.includes("<22>") ? newDecoded : "",
|
||||||
setDecoded("");
|
});
|
||||||
}
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const clearBoth = useCallback(() => {
|
const clearBoth = useCallback(() => {
|
||||||
setDecoded("");
|
setForm({
|
||||||
setEncoded("");
|
decoded: "",
|
||||||
|
encoded: "",
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onDecodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
|
const onDecodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
|
||||||
@@ -69,8 +72,8 @@ export default function Page() {
|
|||||||
[setEncodedReactively]
|
[setEncodedReactively]
|
||||||
);
|
);
|
||||||
|
|
||||||
const decodedCopyButton = useMemo(() => <CopyButton text={decoded} />, [decoded]);
|
const decodedCopyButton = useMemo(() => <CopyButton text={form.decoded} />, [form.decoded]);
|
||||||
const encodedCopyButton = useMemo(() => <CopyButton text={encoded} />, [encoded]);
|
const encodedCopyButton = useMemo(() => <CopyButton text={form.encoded} />, [form.encoded]);
|
||||||
|
|
||||||
const clearButton = useMemo(
|
const clearButton = useMemo(
|
||||||
() => <ClearButton onClick={clearBoth} iconOnly aria-label="clear decoded and encoded" />,
|
() => <ClearButton onClick={clearBoth} iconOnly aria-label="clear decoded and encoded" />,
|
||||||
@@ -88,10 +91,10 @@ export default function Page() {
|
|||||||
return (
|
return (
|
||||||
<PageRootSection title={toolGroups.encodersDecoders.tools.base64.longTitle}>
|
<PageRootSection title={toolGroups.encodersDecoders.tools.base64.longTitle}>
|
||||||
<PageSection title="Decoded" control={decodedControl}>
|
<PageSection title="Decoded" control={decodedControl}>
|
||||||
<Textarea value={decoded} onChange={onDecodedChange} rows={10} />
|
<Textarea value={form.decoded} onChange={onDecodedChange} rows={10} />
|
||||||
</PageSection>
|
</PageSection>
|
||||||
<PageSection title="Encoded" control={encodedControl}>
|
<PageSection title="Encoded" control={encodedControl}>
|
||||||
<Textarea value={encoded} onChange={onEncodedChange} rows={10} />
|
<Textarea value={form.encoded} onChange={onEncodedChange} rows={10} />
|
||||||
</PageSection>
|
</PageSection>
|
||||||
</PageRootSection>
|
</PageRootSection>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,22 +14,30 @@ import { PageRootSection } from "@/components/page-root-section";
|
|||||||
import { PageSection } from "@/components/page-section";
|
import { PageSection } from "@/components/page-section";
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const [decoded, setDecoded] = useState('> It\'s "HTML escaping".');
|
const [form, setForm] = useState({
|
||||||
const [encoded, setEncoded] = useState("> It's "HTML escaping".");
|
decoded: '> It\'s "HTML escaping".',
|
||||||
|
encoded: "> It's "HTML escaping".",
|
||||||
|
});
|
||||||
|
|
||||||
const setDecodedReactively = useCallback((text: string) => {
|
const setDecodedReactively = useCallback((text: string) => {
|
||||||
setDecoded(text);
|
setForm({
|
||||||
setEncoded(encode(text));
|
decoded: text,
|
||||||
|
encoded: encode(text),
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const setEncodedReactively = useCallback((text: string) => {
|
const setEncodedReactively = useCallback((text: string) => {
|
||||||
setEncoded(text);
|
setForm({
|
||||||
setDecoded(decode(text));
|
encoded: text,
|
||||||
|
decoded: decode(text),
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const clearBoth = useCallback(() => {
|
const clearBoth = useCallback(() => {
|
||||||
setDecoded("");
|
setForm({
|
||||||
setEncoded("");
|
decoded: "",
|
||||||
|
encoded: "",
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onDecodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
|
const onDecodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
|
||||||
@@ -62,8 +70,8 @@ export default function Page() {
|
|||||||
[setEncodedReactively]
|
[setEncodedReactively]
|
||||||
);
|
);
|
||||||
|
|
||||||
const decodedCopyButton = useMemo(() => <CopyButton text={decoded} />, [decoded]);
|
const decodedCopyButton = useMemo(() => <CopyButton text={form.decoded} />, [form.decoded]);
|
||||||
const encodedCopyButton = useMemo(() => <CopyButton text={encoded} />, [encoded]);
|
const encodedCopyButton = useMemo(() => <CopyButton text={form.encoded} />, [form.encoded]);
|
||||||
|
|
||||||
const clearButton = useMemo(
|
const clearButton = useMemo(
|
||||||
() => <ClearButton onClick={clearBoth} iconOnly aria-label="clear decoded and encoded" />,
|
() => <ClearButton onClick={clearBoth} iconOnly aria-label="clear decoded and encoded" />,
|
||||||
@@ -81,10 +89,10 @@ export default function Page() {
|
|||||||
return (
|
return (
|
||||||
<PageRootSection title={toolGroups.encodersDecoders.tools.html.longTitle}>
|
<PageRootSection title={toolGroups.encodersDecoders.tools.html.longTitle}>
|
||||||
<PageSection title="Decoded" control={decodedControl}>
|
<PageSection title="Decoded" control={decodedControl}>
|
||||||
<Textarea value={decoded} onChange={onDecodedChange} rows={10} />
|
<Textarea value={form.decoded} onChange={onDecodedChange} rows={10} />
|
||||||
</PageSection>
|
</PageSection>
|
||||||
<PageSection title="Encoded" control={encodedControl}>
|
<PageSection title="Encoded" control={encodedControl}>
|
||||||
<Textarea value={encoded} onChange={onEncodedChange} rows={10} />
|
<Textarea value={form.encoded} onChange={onEncodedChange} rows={10} />
|
||||||
</PageSection>
|
</PageSection>
|
||||||
</PageRootSection>
|
</PageRootSection>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -16,22 +16,30 @@ import { PageRootSection } from "@/components/page-root-section";
|
|||||||
import { PageSection } from "@/components/page-section";
|
import { PageSection } from "@/components/page-section";
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const [decoded, setDecoded] = useState('> It\'s "URL encoding"?');
|
const [form, setForm] = useState({
|
||||||
const [encoded, setEncoded] = useState("%3E%20It's%20%22URL%20encoding%22%3F");
|
decoded: '> It\'s "URL encoding"?',
|
||||||
|
encoded: "%3E%20It's%20%22URL%20encoding%22%3F",
|
||||||
|
});
|
||||||
|
|
||||||
const setDecodedReactively = useCallback((text: string) => {
|
const setDecodedReactively = useCallback((text: string) => {
|
||||||
setDecoded(text);
|
setForm({
|
||||||
setEncoded(O.getOrElse(constant(""))(safeEncodeURIComponent(text)));
|
decoded: text,
|
||||||
|
encoded: O.getOrElse(constant(""))(safeEncodeURIComponent(text)),
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const setEncodedReactively = useCallback((text: string) => {
|
const setEncodedReactively = useCallback((text: string) => {
|
||||||
setEncoded(text);
|
setForm({
|
||||||
setDecoded(O.getOrElse(constant(""))(safeDecodeURIComponent(text)));
|
encoded: text,
|
||||||
|
decoded: O.getOrElse(constant(""))(safeDecodeURIComponent(text)),
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const clearBoth = useCallback(() => {
|
const clearBoth = useCallback(() => {
|
||||||
setDecoded("");
|
setForm({
|
||||||
setEncoded("");
|
decoded: "",
|
||||||
|
encoded: "",
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onDecodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
|
const onDecodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
|
||||||
@@ -64,8 +72,8 @@ export default function Page() {
|
|||||||
[setEncodedReactively]
|
[setEncodedReactively]
|
||||||
);
|
);
|
||||||
|
|
||||||
const decodedCopyButton = useMemo(() => <CopyButton text={decoded} />, [decoded]);
|
const decodedCopyButton = useMemo(() => <CopyButton text={form.decoded} />, [form.decoded]);
|
||||||
const encodedCopyButton = useMemo(() => <CopyButton text={encoded} />, [encoded]);
|
const encodedCopyButton = useMemo(() => <CopyButton text={form.encoded} />, [form.encoded]);
|
||||||
|
|
||||||
const clearButton = useMemo(
|
const clearButton = useMemo(
|
||||||
() => <ClearButton onClick={clearBoth} iconOnly aria-label="clear decoded and encoded" />,
|
() => <ClearButton onClick={clearBoth} iconOnly aria-label="clear decoded and encoded" />,
|
||||||
@@ -83,10 +91,10 @@ export default function Page() {
|
|||||||
return (
|
return (
|
||||||
<PageRootSection title={toolGroups.encodersDecoders.tools.url.longTitle}>
|
<PageRootSection title={toolGroups.encodersDecoders.tools.url.longTitle}>
|
||||||
<PageSection title="Decoded" control={decodedControl}>
|
<PageSection title="Decoded" control={decodedControl}>
|
||||||
<Textarea value={decoded} onChange={onDecodedChange} rows={10} />
|
<Textarea value={form.decoded} onChange={onDecodedChange} rows={10} />
|
||||||
</PageSection>
|
</PageSection>
|
||||||
<PageSection title="Encoded" control={encodedControl}>
|
<PageSection title="Encoded" control={encodedControl}>
|
||||||
<Textarea value={encoded} onChange={onEncodedChange} rows={10} />
|
<Textarea value={form.encoded} onChange={onEncodedChange} rows={10} />
|
||||||
</PageSection>
|
</PageSection>
|
||||||
</PageRootSection>
|
</PageRootSection>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user