Files
yaak-mountain-loop/apps/yaak-client/components/MarkdownEditor.tsx
T
Gregory SchierandClaude Opus 5.5 7ece5fa5df Add a shared actions bar and a Pretty/Raw switch for Yaak Proxy's bodies
The actions row moves out of the code editor into ActionsBar, a plain
component a wrapper places over its content. FormatAction reformats an
editor through its ref, and BodyViewModeSwitch names its first state for
the body's format (Pretty, Table, Parts, Preview, Form) next to Raw.

Yaak Proxy's request and response body tabs now share one viewer
choice, with the switch in each tab's bar beside the text viewer's
filter. The choice is remembered for both panes; bodies over the large
size open raw. "Response (Raw)" leaves the proxy's tab menu, while
Yaak's response pane keeps it until the remaining sites move.

SegmentedControl moves from the client into packages/ui.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 10:52:36 -07:00

84 lines
2.3 KiB
TypeScript

import { SegmentedControl } from "@yaakapp-internal/ui";
import classNames from "classnames";
import { useRef, useState } from "react";
import type { EditorProps } from "./core/Editor/Editor";
import { Editor } from "./core/Editor/LazyEditor";
import { Markdown } from "./Markdown";
type ViewMode = "edit" | "preview";
interface Props extends Pick<EditorProps, "heightMode" | "stateKey" | "forceUpdateKey"> {
placeholder: string;
className?: string;
editorClassName?: string;
defaultValue: string;
onChange: (value: string) => void;
name: string;
}
export function MarkdownEditor({
className,
editorClassName,
defaultValue,
onChange,
name,
forceUpdateKey,
...editorProps
}: Props) {
const [viewMode, setViewMode] = useState<ViewMode>(defaultValue ? "preview" : "edit");
const containerRef = useRef<HTMLDivElement>(null);
const editor = (
<Editor
hideGutter
wrapLines
className={classNames(editorClassName, "[&_.cm-line]:max-w-lg! max-h-full")}
language="markdown"
defaultValue={defaultValue}
onChange={onChange}
forceUpdateKey={forceUpdateKey}
{...editorProps}
/>
);
const preview =
defaultValue.length === 0 ? (
<p className="text-text-subtlest">No description</p>
) : (
<div className="pr-1.5 overflow-y-auto max-h-full **:cursor-auto **:select-auto">
<Markdown className="max-w-lg select-auto cursor-auto">{defaultValue}</Markdown>
</div>
);
const contents = viewMode === "preview" ? preview : editor;
return (
<div
ref={containerRef}
className={classNames(
"group/markdown",
"relative w-full h-full pt-1.5 rounded-md gap-x-1.5",
"min-w-0", // Not sure why this is needed
className,
)}
>
<div className="h-full w-full">{contents}</div>
<div className="absolute top-0 right-0 pt-1.5 pr-1.5">
<SegmentedControl
name={name}
label="View mode"
hideLabel
onChange={setViewMode}
value={viewMode}
className="opacity-0 group-focus-within/markdown:opacity-100 group-hover/markdown:opacity-100"
options={[
{ icon: "eye", label: "Preview mode", value: "preview" },
{ icon: "pencil", label: "Edit mode", value: "edit" },
]}
/>
</div>
</div>
);
}