Files
DevToysWeb/app/text/diff/page.tsx
2024-05-14 22:26:00 +02:00

141 lines
5.0 KiB
TypeScript

"use client";
import { useCallback, useMemo, useState } from "react";
import { Panel, PanelGroup } from "react-resizable-panels";
import { PERSISTENCE_KEY } from "@/config/persistence-keys";
import { toolGroups } from "@/config/tools";
import { cn } from "@/lib/style";
import { DiffEditor } from "@/components/ui/diff-editor";
import { Editor } from "@/components/ui/editor";
import * as Button from "@/components/buttons";
import { Configuration } from "@/components/configuration";
import { Configurations } from "@/components/configurations";
import { ControlMenu } from "@/components/control-menu";
import * as Icon from "@/components/icons";
import * as icons from "@/components/icons";
import { Rows } from "@/components/icons";
import { LabeledSwitch } from "@/components/labeled-switch";
import { PageRootSection } from "@/components/page-root-section";
import { PageSection } from "@/components/page-section";
import { PanelResizeHandle } from "@/components/panel-resize-handler";
/** No particular reason for these sizes, just feels like a good balance */
const VERTICAL_PANEL_MAX_SIZE = 80;
const HORIZONTAL_PANEL_MAX_SIZE = 90;
const PANEL_FULL_SIZE = 100;
export default function Page() {
const [input1, setInput1] = useState<string | undefined>("Hello world");
const [input2, setInput2] = useState<string | undefined>("Hello, World!");
const [diffFullHeight, setDiffFullHeight] = useState(false);
const [inlineMode, setInlineMode] = useState(false);
const diffPanelMaxSize = useMemo(
() => (diffFullHeight ? PANEL_FULL_SIZE : VERTICAL_PANEL_MAX_SIZE),
[diffFullHeight]
);
const clearInput1 = useCallback(() => setInput1(""), [setInput1]);
const clearInput2 = useCallback(() => setInput2(""), [setInput2]);
const toggleFullHeight = useCallback(() => setDiffFullHeight(prev => !prev), [setDiffFullHeight]);
const inlineModeConfig = useMemo(
() => (
<Configuration
icon={<icons.Rows size={24} />}
title="Inline mode"
control={
<LabeledSwitch
id="uppercase-switch"
label={inlineMode ? "On" : "Off"}
checked={inlineMode}
onCheckedChange={setInlineMode}
aria-label="toggle whether to show diff in inline mode"
/>
}
/>
),
[inlineMode, setInlineMode]
);
const input1Control = useMemo(
() => (
<ControlMenu
list={[
<Button.Paste onClipboardRead={setInput1} />,
<Button.File onFileRead={setInput1} iconOnly aria-label="load a file with old text" />,
<Button.Clear onClick={clearInput1} iconOnly aria-label="clear old text input" />,
]}
/>
),
[setInput1, clearInput1]
);
const input2Control = useMemo(
() => (
<ControlMenu
list={[
<Button.Paste onClipboardRead={setInput2} />,
<Button.File onFileRead={setInput2} iconOnly aria-label="load a file with new text" />,
<Button.Clear onClick={clearInput2} iconOnly aria-label="clear new text input" />,
]}
/>
),
[setInput2, clearInput2]
);
const diffControl = useMemo(
() => (
<ControlMenu
list={[
<Button.ToggleFullSize iconOnly onClick={toggleFullHeight} expanded={diffFullHeight} />,
]}
/>
),
[diffFullHeight, toggleFullHeight]
);
return (
<PageRootSection
className="h-full"
title={toolGroups.text.tools.inspector_and_case_converter.longTitle}
>
<PageSection title="Configuration" className={cn(diffFullHeight && "hidden")}>
<Configurations list={[inlineModeConfig]} />
</PageSection>
<PanelGroup direction="vertical" autoSaveId={PERSISTENCE_KEY.panels.textDiff.vertical}>
<Panel maxSize={VERTICAL_PANEL_MAX_SIZE} className={cn(diffFullHeight && "hidden")}>
<PanelGroup
direction="horizontal"
autoSaveId={PERSISTENCE_KEY.panels.textDiff.horizontal}
>
<Panel maxSize={HORIZONTAL_PANEL_MAX_SIZE}>
<PageSection className="h-full" title="Old text" control={input1Control}>
<Editor value={input1} onChange={setInput1} />
</PageSection>
</Panel>
<PanelResizeHandle direction="vertical" className="mt-[42px]" />
<Panel maxSize={HORIZONTAL_PANEL_MAX_SIZE}>
<PageSection className="h-full" title="New text" control={input2Control}>
<Editor value={input2} onChange={setInput2} />
</PageSection>
</Panel>
</PanelGroup>
</Panel>
<PanelResizeHandle direction="horizontal" className={cn(diffFullHeight && "hidden")} />
<Panel maxSize={diffPanelMaxSize}>
<PageSection className="h-full" title="Difference" control={diffControl}>
<DiffEditor
original={input1}
modified={input2}
options={{
readOnly: true,
renderSideBySide: !inlineMode,
}}
/>
</PageSection>
</Panel>
</PanelGroup>
</PageRootSection>
);
}