Support turbo edits (pro) (#166)
This commit is contained in:
@@ -20,6 +20,13 @@ export function ProModeSelector() {
|
||||
const toggleSaverMode = () => {
|
||||
updateSettings({ enableProSaverMode: !settings?.enableProSaverMode });
|
||||
};
|
||||
|
||||
const toggleLazyEdits = () => {
|
||||
updateSettings({
|
||||
enableProLazyEditsMode: !settings?.enableProLazyEditsMode,
|
||||
});
|
||||
};
|
||||
|
||||
if (!settings?.enableDyadPro) {
|
||||
return null;
|
||||
}
|
||||
@@ -75,6 +82,29 @@ export function ProModeSelector() {
|
||||
onCheckedChange={toggleSaverMode}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="lazy-edits">Turbo Edits</Label>
|
||||
<div className="flex items-center gap-1">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Info className="h-4 w-4 text-muted-foreground cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right" className="max-w-72">
|
||||
Edits files faster.
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<p className="text-xs text-muted-foreground max-w-55">
|
||||
Makes editing files faster and cheaper.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
id="lazy-edits"
|
||||
checked={Boolean(settings?.enableProLazyEditsMode)}
|
||||
onCheckedChange={toggleLazyEdits}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
||||
110
src/components/chat/DyadEdit.tsx
Normal file
110
src/components/chat/DyadEdit.tsx
Normal file
@@ -0,0 +1,110 @@
|
||||
import type React from "react";
|
||||
import type { ReactNode } from "react";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
ChevronsDownUp,
|
||||
ChevronsUpDown,
|
||||
Loader,
|
||||
CircleX,
|
||||
Rabbit,
|
||||
} from "lucide-react";
|
||||
import { CodeHighlight } from "./CodeHighlight";
|
||||
import { CustomTagState } from "./stateTypes";
|
||||
|
||||
interface DyadEditProps {
|
||||
children?: ReactNode;
|
||||
node?: any;
|
||||
path?: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export const DyadEdit: React.FC<DyadEditProps> = ({
|
||||
children,
|
||||
node,
|
||||
path: pathProp,
|
||||
description: descriptionProp,
|
||||
}) => {
|
||||
const [isContentVisible, setIsContentVisible] = useState(false);
|
||||
|
||||
// Use props directly if provided, otherwise extract from node
|
||||
const path = pathProp || node?.properties?.path || "";
|
||||
const description = descriptionProp || node?.properties?.description || "";
|
||||
const state = node?.properties?.state as CustomTagState;
|
||||
const inProgress = state === "pending";
|
||||
const aborted = state === "aborted";
|
||||
|
||||
// Extract filename from path
|
||||
const fileName = path ? path.split("/").pop() : "";
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`bg-(--background-lightest) hover:bg-(--background-lighter) rounded-lg px-4 py-2 border my-2 cursor-pointer ${
|
||||
inProgress
|
||||
? "border-amber-500"
|
||||
: aborted
|
||||
? "border-red-500"
|
||||
: "border-border"
|
||||
}`}
|
||||
onClick={() => setIsContentVisible(!isContentVisible)}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex items-center">
|
||||
<Rabbit size={16} />
|
||||
<span className="bg-blue-500 text-white text-xs px-1.5 py-0.5 rounded ml-1 font-medium">
|
||||
Turbo Edit
|
||||
</span>
|
||||
</div>
|
||||
{fileName && (
|
||||
<span className="text-gray-700 dark:text-gray-300 font-medium text-sm">
|
||||
{fileName}
|
||||
</span>
|
||||
)}
|
||||
{inProgress && (
|
||||
<div className="flex items-center text-amber-600 text-xs">
|
||||
<Loader size={14} className="mr-1 animate-spin" />
|
||||
<span>Editing...</span>
|
||||
</div>
|
||||
)}
|
||||
{aborted && (
|
||||
<div className="flex items-center text-red-600 text-xs">
|
||||
<CircleX size={14} className="mr-1" />
|
||||
<span>Did not finish</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
{isContentVisible ? (
|
||||
<ChevronsDownUp
|
||||
size={20}
|
||||
className="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
|
||||
/>
|
||||
) : (
|
||||
<ChevronsUpDown
|
||||
size={20}
|
||||
className="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{path && (
|
||||
<div className="text-xs text-gray-500 dark:text-gray-400 font-medium mb-1">
|
||||
{path}
|
||||
</div>
|
||||
)}
|
||||
{description && (
|
||||
<div className="text-sm text-gray-600 dark:text-gray-300">
|
||||
<span className="font-medium">Summary: </span>
|
||||
{description}
|
||||
</div>
|
||||
)}
|
||||
{isContentVisible && (
|
||||
<div className="text-xs">
|
||||
<CodeHighlight className="language-typescript">
|
||||
{children}
|
||||
</CodeHighlight>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -7,6 +7,7 @@ import { DyadDelete } from "./DyadDelete";
|
||||
import { DyadAddDependency } from "./DyadAddDependency";
|
||||
import { DyadExecuteSql } from "./DyadExecuteSql";
|
||||
import { DyadAddIntegration } from "./DyadAddIntegration";
|
||||
import { DyadEdit } from "./DyadEdit";
|
||||
import { CodeHighlight } from "./CodeHighlight";
|
||||
import { useAtomValue } from "jotai";
|
||||
import { isStreamingAtom } from "@/atoms/chatAtoms";
|
||||
@@ -115,6 +116,7 @@ function preprocessUnclosedTags(content: string): {
|
||||
"dyad-add-integration",
|
||||
"dyad-output",
|
||||
"dyad-chat-summary",
|
||||
"dyad-edit",
|
||||
];
|
||||
|
||||
let processedContent = content;
|
||||
@@ -177,6 +179,7 @@ function parseCustomTags(content: string): ContentPiece[] {
|
||||
"dyad-add-integration",
|
||||
"dyad-output",
|
||||
"dyad-chat-summary",
|
||||
"dyad-edit",
|
||||
];
|
||||
|
||||
const tagPattern = new RegExp(
|
||||
@@ -344,6 +347,21 @@ function renderCustomTag(
|
||||
</DyadAddIntegration>
|
||||
);
|
||||
|
||||
case "dyad-edit":
|
||||
return (
|
||||
<DyadEdit
|
||||
node={{
|
||||
properties: {
|
||||
path: attributes.path || "",
|
||||
description: attributes.description || "",
|
||||
state: getState({ isStreaming, inProgress }),
|
||||
},
|
||||
}}
|
||||
>
|
||||
{content}
|
||||
</DyadEdit>
|
||||
);
|
||||
|
||||
case "dyad-output":
|
||||
return (
|
||||
<DyadOutput
|
||||
|
||||
Reference in New Issue
Block a user