Skip to content

Commit 8fb833c

Browse files
authored
Add console, theme and screenshot to views (rebased) (#1738)
* feat: implement theme-aware views with real-time updates and AI integration - Added a new `THEMED_VIEWS_IMPLEMENTATION.md` document summarizing the feature. - Enhanced `view-template.ts` to inject theme variables into generated HTML. - Updated `view-detail.tsx` to listen for theme changes and regenerate views accordingly. - Introduced comprehensive AI prompts in `api.ts` to guide theme token usage. - Created `view-console.tsx` for logging and debugging within views. - Added new example and documentation files to demonstrate theme token usage. - Updated package dependencies to include `html2canvas` for improved functionality. * refactor(ChatInput): replace hardcoded focus delay with constant - Introduced a constant `EDITOR_FOCUS_DELAY` for the focus delay in ChatInput, improving code readability and maintainability. - Updated focus handling to use the new constant instead of a hardcoded value. - Removed unused `handleSendMessage` function from AgenticChatProvider to streamline event handling. - Simplified log formatting in SendLogsButton by utilizing the `formatLogEntry` utility function. * feat(ChatInput): enhance screenshot and logs handling with custom events - Introduced `ChatTemplates` for standardized message formatting in chat input. - Replaced direct event handling with custom event listeners for screenshots and logs, improving code clarity and maintainability. - Updated error handling to provide user feedback via toast notifications when adding screenshots fails. * refactor(ChatMessages): simplify message handling by removing deduplication logic - Removed the deduplication of messages by ID, streamlining the message rendering process. - Updated related logic to directly use the `messages` array from the chat context, improving clarity and performance.
1 parent cbae991 commit 8fb833c

File tree

16 files changed

+3342
-270
lines changed

16 files changed

+3342
-270
lines changed

THEMED_VIEWS_IMPLEMENTATION.md

Lines changed: 455 additions & 0 deletions
Large diffs are not rendered by default.

apps/web/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"cronstrue": "^2.59.0",
5151
"date-fns": "^4.1.0",
5252
"gsap": "^3.12.7",
53+
"html2canvas": "^1.4.1",
5354
"json-schema": "^0.4.0",
5455
"lucide-react": "^0.545.0",
5556
"marked": "^15.0.7",

apps/web/src/components/chat/chat-input.tsx

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,21 @@ import {
1919
type KeyboardEvent,
2020
type ReactNode,
2121
} from "react";
22+
import { toast } from "sonner";
2223
import { useAgentSettingsToolsSet } from "../../hooks/use-agent-settings-tools-set.ts";
2324
import { useFileUpload } from "../../hooks/use-file-upload.ts";
2425
import { useUserPreferences } from "../../hooks/use-user-preferences.ts";
2526
import { ContextResources } from "../chat/context-resources.tsx";
2627
import { useThreadContext } from "../decopilot/thread-context-provider.tsx";
2728
import { SelectConnectionDialog } from "../integrations/select-connection-dialog.tsx";
2829
import { AudioButton } from "./audio-button.tsx";
30+
import { ChatTemplates } from "./chat-templates.ts";
2931
import { ErrorBanner } from "./error-banner.tsx";
3032
import { ModelSelector } from "./model-selector.tsx";
3133
import { useAgenticChat } from "./provider.tsx";
3234
import { RichTextArea, type RichTextAreaHandle } from "./rich-text.tsx";
3335
import type { ToolsetContextItem } from "./types.ts";
36+
import { onLogsAdded, onScreenshotAdded } from "../../utils/custom-events.ts";
3437

3538
export function ChatInput({
3639
disabled,
@@ -61,6 +64,7 @@ export function ChatInput({
6164

6265
const {
6366
uploadedFiles,
67+
setUploadedFiles,
6468
isDragging,
6569
fileInputRef,
6670
handleFileChange,
@@ -74,6 +78,9 @@ export function ChatInput({
7478
// Read from ThreadContextProvider
7579
const { contextItems, addContextItem } = useThreadContext();
7680

81+
// Delay for editor focus to ensure DOM is ready
82+
const EDITOR_FOCUS_DELAY = 100;
83+
7784
// Check if there are any context resources to display
7885
const hasContextResources = useMemo(() => {
7986
const hasFiles = uploadedFiles.length > 0;
@@ -112,6 +119,65 @@ export function ChatInput({
112119
}
113120
}, [isLoading]);
114121

122+
// Listen for screenshot events from view detail
123+
useEffect(() => {
124+
return onScreenshotAdded(({ blob, filename, url }) => {
125+
try {
126+
// Create File object from the blob (no re-fetch needed!)
127+
const file = new File([blob], filename, {
128+
type: "image/png",
129+
});
130+
131+
// Add to uploaded files
132+
setUploadedFiles((prev) => [
133+
...prev,
134+
{
135+
file,
136+
status: "done",
137+
url,
138+
},
139+
]);
140+
141+
// Add default screenshot text to input
142+
setTimeout(() => {
143+
const currentInput = input || "";
144+
const newText = currentInput
145+
? `${ChatTemplates.screenshot}${currentInput}`
146+
: ChatTemplates.screenshot;
147+
148+
setInput(newText);
149+
150+
// Focus the editor
151+
if (richTextRef.current) {
152+
richTextRef.current.focus();
153+
}
154+
}, EDITOR_FOCUS_DELAY);
155+
} catch (error) {
156+
console.error("Failed to add screenshot:", error);
157+
toast.error("Failed to add screenshot to chat");
158+
}
159+
});
160+
}, [setUploadedFiles, input, setInput]);
161+
162+
// Listen for logs events from view detail
163+
useEffect(() => {
164+
return onLogsAdded(({ logs }) => {
165+
// Add logs to the input
166+
setTimeout(() => {
167+
const currentInput = input || "";
168+
const logsText = ChatTemplates.logs(logs);
169+
const newText = currentInput ? `${logsText}${currentInput}` : logsText;
170+
171+
setInput(newText);
172+
173+
// Focus the editor
174+
if (richTextRef.current) {
175+
richTextRef.current.focus();
176+
}
177+
}, EDITOR_FOCUS_DELAY);
178+
});
179+
}, [input, setInput]);
180+
115181
const isMobile =
116182
typeof window !== "undefined" &&
117183
("ontouchstart" in window ||
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* Text templates for chat input messages
3+
*/
4+
5+
export const ChatTemplates = {
6+
screenshot: "Here's a screenshot of the current view:\n\n",
7+
logs: (logs: string) =>
8+
`Here are the console logs:\n\n\`\`\`\n${logs}\n\`\`\`\n\n`,
9+
} as const;

apps/web/src/components/chat/tool-message.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ const ToolStatus = memo(function ToolStatus({
215215
tabIndex={0}
216216
onClick={onClick}
217217
className={cn(
218-
"w-full flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors",
218+
"w-full flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors cursor-pointer",
219219
!isSingle && "hover:bg-accent rounded-lg p-2",
220220
)}
221221
>
@@ -230,19 +230,22 @@ const ToolStatus = memo(function ToolStatus({
230230
<div className="size-5 rounded-full bg-muted/30 shrink-0" />
231231
)}
232232
<div className="flex-1 min-w-0">
233-
<div className="flex items-center gap-2">
234-
<div className="flex items-center gap-2">
233+
<div className="flex items-center gap-2 min-w-0">
234+
<div className="flex items-center gap-2 min-w-0 flex-1">
235235
<div
236236
className={cn(
237-
"font-medium truncate max-w-[60vw] md:max-w-full",
237+
"font-medium truncate",
238238
isLoading &&
239239
"bg-linear-to-r from-foreground via-foreground/50 to-foreground bg-size-[200%_100%] animate-shimmer bg-clip-text text-transparent",
240240
)}
241241
>
242242
{toolName}
243243
</div>
244244
<div
245-
className={cn("text-xs opacity-70", statusConfig.className)}
245+
className={cn(
246+
"text-xs opacity-70 shrink-0",
247+
statusConfig.className,
248+
)}
246249
>
247250
{statusText}
248251
</div>

0 commit comments

Comments
 (0)